PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : GNU ReadLine & Sockets



7.e.Q
12-05-2005, 05:51
Hi Leute,

auf einen Tip hin, eines Forenkollegen hier, bin ich nun zu dem Ergebnis gekommen, daß ein Einsatz von der GNU Readline Bibliothek meinen Wünschen für das Bediener-Terminal meines Programms am ehesten entspricht. Daher würde ich nun gern folgendes wissen:

- ist es möglich, Readline nicht blockierend einzusetzen, damit andere Kommunikationskanäle auch bearbeitet werden und das Programm nicht an der Stelle des readline() Aufrufs stehen bleibt?

- wie sage ich Readline, daß es auf einem Netzwerk Socket auf Eingaben horchen soll, wenn die eigentliche Standard-Ein/Ausgabe des gesamten Programms bereis für NCurses Fensterdarstellungen auf einer anderen Konsole liegt?

Ums nochmal kurz zu sagen, was meine Probleme sind:
- Einsatz von Readline NICHT-BLOCKIEREND
- Verknüpfen von Readline mit Eingaben von einem Socket (Putty-/Telnet-Client auf anderem Rechner)


Ich wäre für schnelle und kompetente Antworten sehr dankbar!


Gruß,
Hendrik

Joghurt
12-05-2005, 10:09
Müsste eigentlich so gehen:

mit fdopen einen FILE* aus dem Socket bekommen
rl_instream und rl_outstream entsprechend setzen
rl_terminal_name auf "VT100" oder so was stellen.

7.e.Q
12-05-2005, 10:10
Mal ausprobieren...

7.e.Q
12-05-2005, 10:57
Okay, das funktioniert soweit ganz gut... aber was noch nicht funktioniert, sind die Cursor rauf/runter für Befehls-History, die Autokomplettierung von Befehlen und so. Letzteres ist noch zu implementieren, aber ich kann auch auf dem Terminal noch nicht durch die Kommandozeile laufen. Es erscheinen beim Druck auf die Cursor-Tasten immer "^[[D" oder solche Sachen...


Was noch problematisch ist, ist die Tatsache, daß Readline die Daten erst bekommt, wenn der Socket sie empfangen hat. Logisch. Wie bieg ich dem Socket jetzt bei, daß er jedes Zeichen einzeln überträgt, also nach jedem eingegebenen Zeichen readline benachrichtigt wird?

7.e.Q
12-05-2005, 11:28
Autokomplettierung funktioniert auch schon, aber nur so: nach Druck auf TAB erscheint am Prompt ^I. Ein weiterer Druck auf TAB lässt noch ein ^I erscheinen. Erst nach einem Druck auf ENTER löst dann die Autokomplettierung aus und zeigt mir die passenden Dateinamen (da eine programmspezifische Komplettierung noch nicht implementiert ist).

Ich möchte aber, daß das Programm sofort auf das TAB Drücken reagiert, nicht erst nach ENTER (wie auch in einem anderen Thread hier angefragt, sorry für's Doppel Posting, aber mehrere Probleme in einem Thread vereint finden immer so wenige Antworten).

Ich danke euch für eure Hilfe.

7.e.Q
12-05-2005, 12:25
Langsam regt mich das echt auf. Nein, nicht daß hier keiner antwortet, das kann ich nach so kurzer Zeit ja auch nicht erwarten. Viel mehr, daß ich darüber nix finde! Daß ich offenbar zu blöde zum Googlen bin.

Ich möchte doch nur, daß wenn ich mich mit Putty auf den besagten Socket verbunden habe und beispielsweise in Putty dann auf "a" drücke, selbiges "a" gleich in meinem Programm auf der anderen Seite (dem Server, wo ich mich mit Putty drauf connected hab) ankommt, select darauf reagiert (also sage "Ah da sind Daten auf dem Filedeskriptor von dem Socket") und mein Programm dieses "a" dann lesen kann. Und nicht erst, wenn ich nach dem "a" noch Enter drücke. Ich möcht doch nur, daß jedes Zeichen sofort übertragen und auslesbar wird. Nicht erst nach Druck auf Enter. *rumflenn*

Ich bin hier voll am Verzweifeln. :( :( :(

klewan
12-05-2005, 13:15
ssh und so machen das über psydo terminals

google mal nach pty.h

7.e.Q
12-05-2005, 13:18
Das hab ich auch schon irgendwo in meinem Recherche-Wust gelesen. Wirklich weitergeholfen hat's mir nicht. Auch nicht das Googeln nach pty.h.

Wie bindet man denn einen Socket an ein Pseudo-Terminal?

klewan
12-05-2005, 14:15
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <pty.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>


#define PORT 2000

int prepare()
{

struct termios term;
tcgetattr(0,&term);
term.c_lflag &= ~(ECHO|ICANON);
term.c_cc[VMIN] = 0;
tcsetattr(0,TCSANOW,&term);
execl("/bin/bash","su", NULL);
return 0;
}


int main()
{
struct sockaddr_in so, os;
int s, n;
int i;
int pty; // deskryptor pseudoterminala
int tak=1;
char temp[1024]; // Bufor posredni
fd_set rfd;
pid_t pidek;
int len=sizeof(struct sockaddr);


pidek=forkpty(&pty, NULL, NULL, NULL);

switch (pidek)
{
case -1:
{
perror ("forkpty()");
exit (1);
}
case 0:
prepare();
}

s=socket(PF_INET, SOCK_STREAM, 0);
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &tak, sizeof(tak));


so.sin_port = htons(PORT);
so.sin_addr.s_addr = INADDR_ANY;
so.sin_family = PF_INET;
bind(s, (struct sockaddr*)&so, len);
listen(s, 10);


n=accept(s, (struct sockaddr*)&os, &len);
dup2(n, 0);
dup2(n, 1);
dup2(n, 2);

fcntl (0, F_SETFL, O_NONBLOCK);
fcntl (pty, F_SETFL, O_NONBLOCK);

FD_ZERO (&rfd);
FD_SET (0, &rfd);
FD_SET (pty, &rfd);

while (1)
{
FD_SET (0, &rfd);
FD_SET (pty, &rfd);
i = select (pty + 1, &rfd, NULL, NULL, NULL);
if (i > 0)
{
if (FD_ISSET (0, &rfd))
{
bzero (temp, sizeof (temp));
if(read (0, temp, sizeof (temp))<=0)
exit(0);
write (pty, temp, strlen (temp));
}

if (FD_ISSET (pty, &rfd))
{
bzero (temp, sizeof (temp));
if(read (pty, temp, sizeof (temp))<=0)
exit(0);
write (0, temp, strlen (temp));
}
}
}
return 0;
}


google! :-)
gcc -lutil 1.c
./a.out
telnet localhost 2000 (oder putty RAW)

aber die blöden steuerzeichen ^L ..... hab ich auch noch
shit das wurmt mich jetzt

7.e.Q
12-05-2005, 14:20
Hinzu kommt noch, daß ich unter dem Socket dann keine Shell haben möchte, sondern einen eigenen ins Programm integrierten Kommando-Interpreter.

Wird in deinem Programm denn jetzt jedes Zeichen einzeln übertragen?

Ich hab eben mal eine reine Telnet-Verbindung auf den NetKit TelnetD mitgesnifft. Da wird wirklich jedes einzelne Zeichen unmittelbar nach dem Druck auf eine Taste übermittelt. Irgendwie muss TelnetD dem Putty Client diese Option ja mitteilen. Und genau das will ich meinem Programm jetzt auch beibiegen.


Gut, daß dich das wurmt! Dann finden wir sicher gemeinsam 'ne Lösung. :D

klewan
12-05-2005, 15:02
ja die daten sollten char by char versandt werden

dein program sollt nur von stdin lesen und stdout schreiben

ob das jetzt /bin/bash oder /sbin/deins ist is egal

hmmmm diese doofen ^

7.e.Q
12-05-2005, 15:06
StdOut ist leider bereits von einer ncurses Oberfläche belegt. Was mach ich nun?

7.e.Q
13-05-2005, 11:04
Ich hab das jetzt so gemacht:

Es wird per Select auf dem Socket gehorcht. Schreibt Putty dort etwas hinein, liest mein Programm es per read() aus und schreibt es per write() weiter auf die Slave Seite des von mir eingerichteten Pseudo-Terminals. Auf der Master Seite des Pseudo Terminals sitzt meine rl_callback Funktion (bzw. rl_callback_read_char) und liest fleißig meine eingegebenen Bytes ein.

Problem:

es liest brav alles ein. Nur sobald da ein Character 0x0A rein kommt, kann rl_callback_read_char den nicht mehr lesen.

Wie muss ich denn das Pseudo Terminal jetzt per tcsetattr konfigurieren, daß es mit readline 100% zusammen funktioniert?

7.e.Q
17-05-2005, 11:11
Keiner 'ne Idee??? Wischtisch! Ich komm einfach nich voran damit. Scheiß mangelnde Doku...