Aufgabe 9

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

Aufgabe 9
Ich hoffe ich hab die b) implementier. Es wirft aber einen Fehler bei gethostbyname: Connection timed out. Was kann an dieser Implementierung falsch sein char name[strlen(argv[3])]; struct hostent *host; strcpy(name,argv[3]); host = gethostbyname(name); ?


Dazu kann ich jetzt spontan nichts sagen, das sieht mir möglicherweise nach einem Netzwerkproblem aus.
Was den temporären String angeht, muss ich dir allerdings eine Gardinenpredigt halten - inzwischen sollte es allmählich durchgesickert sein, dass man für Strings immer ein Byte mehr allokieren muss, damit das terminierende [m]\0[/m] reinpasst. :finger:
Wobei das so eh nicht funktionieren kann, dass man beim Anlegen eines statischen Arrays den Rückgabewert eines Funktionsaufrufs als Größe angibt. Das geht nur mit konstanten Werten (oder eventuell noch in Nicht-ANSI-C).


Könnte mal jemand die Übung online stellen auf der Sos Übung Seite??

Thx


faui01 [src]> cp /proj/i4sos/pub/aufgabe9/* ./
cp: cannot open `/proj/i4sos/pub/aufgabe9/connbroker.c’ for reading: Permission denied


Die gibt es natuerlich erst nach dem Abgabetermin der timed, das Objectfile liegt aber ja schon drin :wink:


ich verstehe nicht ganz die aufgabenstellung:

Ich dachte eigentlich die Connbroker baut den Socket und ruft dann - wie bei der timed - das modul port_forward auf. Irgendwie wird port_forward aber doch mit kommandozeilen parametern aufgerufen? Ist das ein Fehler bei der a) oder versteh ich wirklich nicht ganz den Sinn dahinter? Andererseits warum stimmt die Signatur von client_handler nicht mit port_forward.c überein? Ich komm nicht dahinter

Kann mir mal bitte jemand erklären wie hier der zusammenhang lautet zwischen den einzelnen Modulen?

Ist es außerdem port_forward wie in der Aufgabenstellung oder port-forward wie die Datei im pub Verzeichniss/Aufgabenstellung?


Genau das ist der Grund, warum die Schnittstelle wie sie im timed war, für den port-forward nicht zu gebrauchen ist und entsprechend um Kommandozeilen Parameter erweitert wurde. Der angepasste Header
findet sich im pub mit einem ebenfalls angepassten connbroker.o. Nach dem Abgabetermin der Aufgabe8
wird es dann auch den connbroker.c Quellcode geben. Teilaufgabe a) ist also wie in der Aufgabenstellung erwähnt optional und muss nicht von euch programmiert werden. Jetzt kann new_client also noch ein argc
und argv wie üblicherweise die Mainfunktion bekommen. Damit der Connbroker unterscheiden kann, welche Parameter für ihn und welche für das Servicemodul bestimmt sind, werden connbroker Parameter und Modulparameter durch – voneinander getrennt (falls der connbroker irgendwann noch auf mehrere
Parameter erweitert werden sollte, kann man dann diese Aufrufsemantik beibehalten). Ruft man dann
port-forward wie im Beispiel auf

port-forward 5678 -- wwwproxy 8080

dann parst der vorgegebene connbroker die Kommandozeile, verwertet seinen eigenen Parameter (5678)
und gibt der new_client Funktion dann ein entsprechend angepasstes argc und argv mit:

argc = 2;
argv[0] = "wwwproxy";
argv[1] = "8080";
argv[2] = NULL;

Damit kann new_client im port-forward.c dann die Verbindung zum Zielrechner aufbauen.

Das Abgabeskript verlangt port-forward.c.


Der connbroker tut das gleiche wie in Aufgabe 8, enthält die main()-Funktion, nimmt Verbindungen am eingestellten Port an, erzeugt für jede angenommene Verbindung ein Kind und ruft im Kind dann new_client() auf. Nach der Rückkehr aus new_client() schliesst das Kind den socket und terminiert sich. Der Vater nimmt sofort nach dem Erzeugen des Kinds weitere Verbindungen an.

Die new_client()-Funktion bearbeitet jeweils eine Verbindung. Im port-forward bedeutet das, sie baut eine Verbindung zum Ziel (Server) der Weiterleitung auf (Kommandozeilenparameter) und ruft dann forward() auf, welches Daten zwischen dem Socket zum Peer- und zum Serversocket in beide Richtungen weiterleitet.
Nach der Rückkehr von forward() kehrt auch new_client() zurück.

Die forward()-Funktion steckt im dritten Modul und bekommt als Parameter zwei Filedeskriptoren, zwischen denen die Daten dann in beide Richtungen weitergeleitet werden. Hierzu werden zwei Threads erzeugt, von denen jeder die Daten in eine Richtung weiterleitet. Die forward()-Funktion wartet dann auf das Ende beider Threads und kehrt anschliessend zurück.


ah alles klar, vielen dank


Ne Frage zu SIGPIPE blockt euer CONNBROKER dieses Signal oder sollen wir dies per Hand in unserem newclient übernehmen? Wie ist das gedacht?

Und wenn jetzt ein pthread_join fehlschlägt sollen wir dann den anderen thread killen mit pthread_kill oder mit pthread_join auch auf den 2ten thread warten?

Thx,
red


Nein, bei unserem Connbroker sind zum Zeitpunkt des new_client() Aufrufs alle Signalbehandlungen auf
SIG_DFL. Ein ignorieren des Signals muss also im new_client() erfolgen.

Korrekt wäre Fehlermeldung, Warten auf den anderen Thread, return -1.


Mal gugn, wer noch so am Arbeiten sitzt, und hier so reinschaut :wink:

Problem: Ich bekomme dieses struct hostent von gethostbyname.
Entweder hab ich nen Denkfehler, oder wie bekomme ich “sin.sin_addr.s_addr = hostEintrag->h_addr_list[0];” Das so hin, dass es geht? (hostEintrag ist der struct hostent Pointer, sin ein struct sockaddr_in)…
Wenn ich mir “hostEintrag->h_addr_list[0]” printen lasse, kommt nur Schmarrn raus, was aber an der Byteorder liegen sollte? Die ist ja bereits Network.

Weil laut Folie U8.15 brauch ich das ja dann für das connect…

Danke an alle Helfer :wink:

€: Ein “*” vorm hostEintrag->… hilft Wunder… nerv

€²: connect failed bei mir, perror meint: “No Route to Host”. Ich probiere es mit dem wwwproxy… usw. Das ging auch eigentlich immer, und gethostbyname geht ja auch. Kann ich nicht einfach die Erste Adresse aus der Liste nehmen?


So kannst Du die Adresse nicht kopieren. Du mußt ein memcpy() darauf machen, über die Länge (hostEintrag->h_length).
Sonst schreibst Du nur den Inhalt des ersten Bytes rein.


Hab mir die Stelle zeigen lassen in den Übugnsfolien, wo mans 1:1 abschreiben kann :wink:

Jetzt gehts auch, ich schreibe eben diesen Beitrag über meinen Forwarder.

Allerdings erkennt der die Beendigung von Verbindungen noch nicht: Wie habt ihr das gemacht? Ich hatte mir gedacht, SIG_PIPE mal wieder zu ignorieren, und dann read/write auf Fehler abzufragen. Wenn Fehler, dann halt “return 0;” damit beendet sich der Thread. Wenn beide Threads fertig sind, returnt die forward.c automatisch, und dann returnt port-forward.c und am Ende beendet sich das Geforkte Kind in aller Ruhe.
Soweit zur Threorie, gehn tuts gar nicht :stuck_out_tongue:
Das Write erkennt ein Broken Pipe mal alle Jubeljahre, und das read gar nicht. Also so kanns nicht klappen, wie habt ihr das gelöst?


Ich hab ein aenliches Problem. Ich will das Programm mit dem Timedeamon testen wie es auf dem Blatt steht. Das Problem ist, dass nur in eine Richtung Daten geschrieben werden, die Uhrzeit + Datum halt.
Der Thread der die Zeit liest und dann schreibt funktioniert, der andere nicht.
Ich hab read und danach write in eine Schleife gepackt. Wenn ein EPIPE auftritt verlasse ich die Schleife nach dem writeAufruf.
Der andere Thread der in Richtung Timedeamon schreiben sollte bekommt ja keinen Input und read gibt also immer 0 zurueck, dann tut aber write nichts laut man Page:
“Wenn count 0 ist, dann wird 0 zurückgegeben und sonst geschieht nichts.”
write bemerkt wohl auch nicht den EPIPE und bleibt schoen in seiner Schleife.
Jetzt steh ich halt grad auf dem Schlauch wie ich da wieder rauskomme?


In dem Thread, der von nc liest und an den timed schreibt, sollte der read einfach hängen bleiben. Wenn read mit 0 zurückkehrt, bedeutet das EOF. In diesem Fall ist ein shutdown(SHUT_WR) auf dem anderen socket zu machen und der Thread zu beenden. Du solltest write nicht mit 0 Bytes aufrufen.

Auszug aus der Linux Manpage write(2):
If count is zero and fd refers to a file other than a regular file, the results are not specified.


Gibt dass dann nicht auch Probleme bei dem Thread der die Zeit liest?
Der schreibt ja nur jede Sekunde und mach ansonsten sleep? Da muesste read ja auch oefter mit 0 zurueckkommen weil ich das in einer Schleife hab. Und damit wuerde ich dann nicht mehr jede Sekunde die Zeit auslesen koennen?


Nein der read blockiert dann bis Daten vorhanden sind. EOF (also Rückgabe 0) kommt nur dann, wenn die andere Seite den socket ganz geschlossen hat oder zumindest mit shutdown den socket für sich zum Schreiben geschlossen hat und nur noch davon liest. Wenn read also einmal 0 zurückgibt, werden keine Daten mehr von diesem Socket kommen.


Jep, hat funktioniert. Danke.