Let's fix this thing. Attached is a patch that does discard_client_input () without using any memory (2 words of stack+stdio overhead), alerts us if we're seeing bare LF, and alerts us separately if we see a stdio- driven EOF.
We also clear the error status beforehand. This generally make stdio behave better (esp. on SUN) I also do error checking [on the socket]. This'll work on UNIX systems, but quite obviously, not on others. Someone will have to test to see if fileno() can actually return -1 when feof() doesn't go off. This is 80/90%... Can't test it right now... On Mon, 2005-05-09 at 17:36 +0000, Aaron Stone wrote: > OK -- so read discard_client_input() in pipe.c and tell me if you think > that it's hanging there waiting for ".\r\n" and nothing else can get out > of that loop. AFAICT, that's got to be what's happening after the error in > lmtp.c: > > mime_readheader()... > "main(): fatal error from mime_readheader()"); > > Aaron > > > On Mon, May 9, 2005, Geo Carncross <[EMAIL PROTECTED]> > said: > > > On Mon, 2005-05-09 at 17:12 +0000, Aaron Stone wrote: > >> I wonder if the bug reporter's LMTP is sitting in a loop waiting for > >> feof() on the socket and not reading anything. That would certainly cause > >> LMTP to hang following the last error message he reported. I thought that > >> sockets do report EOF when they are open, but no more data to be read. > >> Right? > > > > Saying EOF is confusing. EOF is a concept of POSIX.1 and not unix. > > > > This is all confusing. > > > > In an attempt to clarify: > > > > * read() returns 0 bytes when a pipe has no writers > > > > * read() returns 0 bytes from a tty when VEOF was sent to the tty driver > > > > * read() returns 0 bytes when at the end of a ifile (not a FILE*) > > > > * read/recv() returns 0 bytes from a STREAM SOCKET when SHUT_WR occurs > > on far end. > > > > > > the "eof" flag of a FILE* is set, _ON_UNIX_ when the underlying read() > > returned 0. Obviously, this can happen for lots of reasons, none of > > which (except maybe the kernel ifile) mean no more data is coming... > > > > feof() is true on POSIX.1 when the next fread() or fgets() will be > > unable to return any bytes. Some C libraries will anticipate this with a > > fstat() or similar, but quite obviously, with sockets, it can't be done > > this way. > > > > The difference is critical, because feof() won't fire until after fread > > () or fgets() fails when the FILE* is actually on a socket. This is in > > direct opposition to what POSIX.1 says should happen. > > > > Unless the far side is deliberately doing a shutdown(fileno(f),SHUT_WR) > > you simply are never going to get your "EOF report" on a socket. > > > > .... whether it's in the UNIX domain or in another domain... > > > > And to make matters worse, NOBODY uses shutdown()*. Not that'd matter if > > they did... > > > > > > * I mean, _I_ do, but I'm a pedantic bastard :) > > > > -- > > Internet Connection High Quality Web Hosting > > http://www.internetconnection.net/ > > > > _______________________________________________ > > Dbmail-dev mailing list > > Dbmail-dev@dbmail.org > > http://twister.fastxs.net/mailman/listinfo/dbmail-dev > > -- Internet Connection High Quality Web Hosting http://www.internetconnection.net/
Index: pipe.c =================================================================== --- pipe.c (revision 1772) +++ pipe.c (working copy) @@ -328,25 +328,45 @@ /* read from instream, but simply discard all input! */ int discard_client_input(FILE * instream) { - char *tmpline; + int ch, ns, l; - tmpline = (char *) dm_malloc(MAX_LINE_SIZE + 1); - if (tmpline == NULL) { - trace(TRACE_ERROR, "%s,%s: unable to allocate memory.", - __FILE__, __func__); - return -1; + clearerr(instream); + for (ns = 0; (ch = fgetc(instream)) != EOF;) { + if (ch == '\r') { + if (ns == 4) { + /* \r\n.\r */ + ns = 5; + } else { + /* \r */ + ns = 1; + } + } else if (ch == '\n') { + if (ns == 1) { + /* \r\n */ + ns = 2; + } else if (ns == 5) { + /* complete: \r\n.\r\n */ + return 0; + } else { + /* .\n ? */ + trace(TRACE_ERROR, "%s,%s: bare LF.", + __FILE__, __func__); + } + } else if (ch == '.' && ns == 3) { + /* \r\n. */ + ns = 4; + } + if ((ch = fileno(instream)) != -1) { + /* okay, look for error slippage */ + l = 0; + if (getpeername(ns,(struct sockaddr *)"",&l) == -1 && errno != ENOTSOCK) { + trace(TRACE_ERROR, "%s,%s: unexpected failure from socket layer (client hangup?)", + __FILE__, __func__); + } + } } - - while (!feof(instream)) { - if (fgets(tmpline, MAX_LINE_SIZE, instream) == NULL) - break; - - trace(TRACE_DEBUG, "%s,%s: tmpline = [%s]", __FILE__, - __func__, tmpline); - if (strcmp(tmpline, ".\r\n") == 0) - break; - } - dm_free(tmpline); + trace(TRACE_ERROR, "%s,%s: unexpected EOF from stdio (client hangup?)", + __FILE__, __func__); return 0; }