Forum: PC-Programmierung Linux, accept() file handle


von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Servus,

Problem: ich baue mir gerade einen einfachen Webserver, er funktioniert
soweit. Ich hab da einen merkwürdigen Effekt:

Schleife {
  fd = accept( ...);
  tu was damit
  sende HTTP 200
}

Beim ersten Aufruf erhalte ich als fd ein 5 oder 6, bei einer
bestimmten Suchfunktion kommt aber nach den 2ten Aufruf als
fd eine 0 zurück und es feuert 7 Anfragen hintereinander.
Also eine Macke in meiner Suchfunktion. Nur welche ?

fd 0 ist eigentlich stdin, Linux übernimmt bei der Generierung
eines fd immer die kleinste freie Zahl, das würde darauf hindeuten
daß ich irgendwo stdin geschlossen habe (habe ich nicht).

Hilfreich wäre irgendeine Funktion die mir aus dem Programm
heraus die belegten Handles mit Dateinamen ausgäbe. Die
Suchfunktion besteht aus > 2200 Zeilen, das ist sonst sehr
mühselig ;)

von IT-Abteilung (Gast)


Lesenswert?

Joachim D. schrieb:
> Also eine Macke in meiner Suchfunktion. Nur welche ?

Oh magische Miesmuschel, welche Macke hat Joachims Suchfunktion.

Magische Miesmuschel: Weiß ich nicht, weil ich keinen Code habe...

von foobar (Gast)


Lesenswert?

Im proc-Filesystem kannst du die offenen Filehandles sehen 
"/proc/<pid>/fd" insb auch "/proc/self/fd".

Ansonsten das Programm einfach mal unter strace starten, insb "strace -e 
trace=desc <program>".

Generell: wenn accept 0 zurück liefer, muss fd 0 vorher geschlossen 
worden sein.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

foobar schrieb:
> Generell: wenn accept 0 zurück liefer, muss fd 0 vorher geschlossen
> worden sein.

Das ist mir klar ;)

Kann ich irgendwie über den fd herausfinden ob dahinter etwas
steckt ? Wenn ja, wie ?

von Rolf M. (rmagnus)


Lesenswert?

Joachim D. schrieb:
> Kann ich irgendwie über den fd herausfinden ob dahinter etwas
> steckt ? Wenn ja, wie ?

So:

foobar schrieb:
> Im proc-Filesystem kannst du die offenen Filehandles sehen
> "/proc/<pid>/fd" insb auch "/proc/self/fd".

von Hmmm (Gast)


Lesenswert?

Joachim D. schrieb:
> Kann ich irgendwie über den fd herausfinden ob dahinter etwas
> steckt ?

Hier mal ein Beispiel für einen Prozess mit Socket und Pipe:
1
# ls -l /proc/1297/fd
2
total 0
3
lrwx------ 1 root root 64 Apr 10 14:38 0 -> /dev/null
4
lrwx------ 1 root root 64 Apr 10 14:38 1 -> /dev/null
5
lrwx------ 1 root root 64 Apr 10 14:38 2 -> /dev/null
6
lrwx------ 1 root root 64 Apr 10 14:38 3 -> socket:[1791]
7
lr-x------ 1 root root 64 Apr 10 14:38 4 -> pipe:[8985]

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Bei mir:

insgesamt 0insgesamt 0
lrwx------ 1 jd jd 64 Apr 10 14:46 0 -> /dev/pts/1
lrwx------ 1 jd jd 64 Apr 10 14:46 1 -> /dev/pts/1
lrwx------ 1 jd jd 64 Apr 10 14:46 2 -> /dev/pts/1
l-wx------ 1 jd jd 64 Apr 10 14:46 3 -> /home/jd/web/bin/prt/uquery.prt
lrwx------ 1 jd jd 64 Apr 10 14:46 4 -> socket:[121536]

und nach dem Fehler:

insgesamt 0
lrwx------ 1 jd jd 64 Apr 10 14:46 1 -> /dev/pts/1
lrwx------ 1 jd jd 64 Apr 10 14:46 2 -> /dev/pts/1
l-wx------ 1 jd jd 64 Apr 10 14:46 3 -> /home/jd/web/bin/prt/uquery.prt
lrwx------ 1 jd jd 64 Apr 10 14:46 4 -> socket:[121536]

Das eine /dev/pts/1 (was immer das ist) fehlt.

von foobar (Gast)


Lesenswert?

Programmatisch:
1
static void
2
show_fd0()
3
{
4
    char buf[256];
5
    ssize_t n;
6
7
    n = readlink("/proc/self/fd/0", buf, sizeof(buf)-1);
8
    if (n >= 0)
9
    {
10
        buf[n] = 0;
11
        puts(buf);
12
    }
13
    else
14
        perror("readlink");
15
}

von foobar (Gast)


Lesenswert?

Zeigt doch ganz klar, dass fd0 geschlossen wurde.  Als nächstes mal 
strace benutzen - das gibt evtl einen Hinweis, zu welchem 
Zeitpunk/Zusammenhang der geschlossen wurde.

von foobar (Gast)


Lesenswert?

Ich vermute ja, dass du in deiner Schleife
> Schleife {
>   fd = accept( ...);
>   tu was damit
>   sende HTTP 200
> }

den falschen Filehandle schließt, statt close(fd) also close(0) bzw 
irgendwo fd auf 0 gesetzt wird oder das ursprüngliche fd verdeckt wird 
(shadowed var) oder so was.

von Rolf M. (rmagnus)


Lesenswert?

Joachim D. schrieb:
> Das eine /dev/pts/1 (was immer das ist) fehlt.

Das ist ein Pseudoterminal.
Aber es sollte doch nicht so schwer zu finden sein, wo du fd 0 schließt. 
Meine Vermutung: Du übergibst irgendwo eine Variable an close(), von der 
du denkst, dass sie irgendeinen fd enthält, den du dir gemerkt hast, 
aber in Wirklichkeit hat sie noch ihren vorinitialisierten Wert von 0. 
Deshalb initialisiere ich alle Variablen, die fds enthalten sollen, mit 
-1.

von foobar (Gast)


Lesenswert?

Ich schrieb:
> Ich vermute ja, dass du in deiner Schleife ...

Ne, kann nicht sein, dann wäre der acceptete Socket noch offen - ist er 
aber nicht.  Also irgendwo anders ein falscher close.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

foobar schrieb:
> den falschen Filehandle schließt, statt close(fd) also close(0) bzw
> irgendwo fd auf 0 gesetzt wird oder das ursprüngliche fd verdeckt wird
> (shadowed var) oder so was.

Irgendwo ... Die fragliche Suchfunktion ist seit ca 15 Jahren
organisch gewachsen und arbeite als CGI-Programm (das Programm
wird auch immer beenden, da fallen solche Macken nicht auf).

Ich portiere das alles gerade nach Linux und lassen das im
Rahmen eines kleinen Webservers laufen (wird also nicht komplett
beendet).

Ich habe mir gerade mal ein kleines Prüfprogrännchen eingebaut
das mit readlink() die fd's anzeigt. Es schießt mir die 0.

Rolf M. schrieb:
> Deshalb initialisiere ich alle Variablen, die fds enthalten sollen, mit
> -1.

Mache ich mittlerweile auch ...

Zumindest ist mir jetzt klarer nach was ich suchen muß ;)

Vielen Dank !

(bin noch ziemlich neu in Linux)

von Hmmm (Gast)


Lesenswert?

Evtl. hast Du irgendwo einen Buffer Overflow fabriziert und 
überschreibst dabei einen auf dem Stack liegenden FD-Parameter mit 0.

Kann z.B. bei einem memset() oder bzero() passieren, wenn man nicht 
sizeof benutzt.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Da tippe ich auch drauf. Ich habe in der Suchroutine nur
2 mal close(), dabei keins das zuschlägt. Wird halt mühsam ;)

von foobar (Gast)


Lesenswert?

Zum debuggen kann man auch mal etwas pfuschen:
1
#define close(fd) ((fd)==0 ? abort(),-1 : (close)(fd))

generiert dir dann, zumindest in den mit diesem define übersetzten 
Teilen, einen Core-dump den du dir mit dem gdb anschauen kannst.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Der Übeltäter (überflüssiges close()) ist gefunden und alles
funktioniert wunderbar. Vielen Dank nochmal !

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.