From 6ae74f9b7a1ec9170efa53cab74e889eb1697a50 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Mon, 31 Jan 2000 22:16:23 +0000 Subject: Graceful socket closing. svn path=/trunk/; revision=2726 --- NEWS | 14 +++++++++++++- driver.c | 2 +- fetchmail-FAQ.html | 7 +++++-- fetchmail.c | 2 +- interface.c | 2 +- sink.c | 2 +- socket.c | 37 +++++++++++++++++++++++++++++-------- 7 files changed, 51 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index 8dc6f564..05f9204d 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,11 @@ Things to do: +Scrollbars on fetchmailconf help windows (Debian bug #51770). + +Log bounced messages via syslog (Debian bug #50184). + +Notify user by mail when pop server nonexistent (Debian bug #47143). + In the SSL support, we need to add server certificate validation (In other words, does the certificate match the system we are trying to contact?). Also, add authentication of Certifying Authority (Is this @@ -15,12 +21,18 @@ package will have two security verifications instead of one... (The `lines' figures total .c, .h, .l, and .y files under version control.) +* Close down sockets using shutdown(2) and discarding read data until we + get a TCP FIN. With any luck this will squash our socket leak. +* Added Martijn Lievaart's sendmail hacks for multidrop to the contrib + directory. +* Debian buglist cleanup. + fetchmail-5.2.5 (Mon Jan 31 02:02:48 EST 2000), 18445 lines: * Fixed bugs in BSMTP generation reported by Jaap Lutz. * Make fetchmailconf better at handling backslashes in usernames and passwords. -* Jochen Hayeek's patch to handle spaces in UID usernames. +* Jochen Hayek's patch to handle spaces in UID usernames. There are 279 people on fetchmail-friends and 497 on fetchmail-announce. diff --git a/driver.c b/driver.c index 655bf4d3..f627d2cb 100644 --- a/driver.c +++ b/driver.c @@ -1537,7 +1537,7 @@ const int maxfetch; /* maximum number of messages to fetch */ /* try to clean up all streams */ release_sink(ctl); if (ctl->smtp_socket != -1) - close(ctl->smtp_socket); + SockClose(ctl->smtp_socket); if (mailserver_socket != -1) SockClose(mailserver_socket); } diff --git a/fetchmail-FAQ.html b/fetchmail-FAQ.html index 6107b829..256406c3 100644 --- a/fetchmail-FAQ.html +++ b/fetchmail-FAQ.html @@ -10,7 +10,7 @@
Back to Fetchmail Home Page To Site Map -$Date: 2000/01/31 04:07:30 $ +$Date: 2000/01/31 22:16:21 $

Frequently Asked Questions About Fetchmail

@@ -1042,6 +1042,9 @@ reliably even when the Received header omits the envelope address (which will typically be the case when the message has multiple recipients).

+Martijn Lievart has a more detailed recipe in the contrib subdirectory +of the fetchmail source distribution. +


T2. How can I use fetchmail with qmail?

@@ -2578,7 +2581,7 @@ terminate it.

Back to Fetchmail Home Page To Site Map -$Date: 2000/01/31 04:07:30 $ +$Date: 2000/01/31 22:16:21 $

Eric S. Raymond <esr@snark.thyrsus.com>
diff --git a/fetchmail.c b/fetchmail.c index bbd6bfab..c6b2e72f 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -1322,7 +1322,7 @@ static void terminate_poll(int sig) if (ctl->smtp_socket != -1) { SMTP_quit(ctl->smtp_socket); - close(ctl->smtp_socket); + SockClose(ctl->smtp_socket); ctl->smtp_socket = -1; } } diff --git a/interface.c b/interface.c index 6ddbbbbf..7a485e78 100644 --- a/interface.c +++ b/interface.c @@ -174,7 +174,7 @@ static int get_ifinfo(const char *ifname, ifinfo_t *ifinfo) *sp = '/'; } if (socket_fd >= 0) - close(socket_fd); /* not checking should be safe, mode was "r" */ + SockClose(close(socket_fd)); if (stats_file) fclose(stats_file); /* not checking should be safe, mode was "r" */ return(result); diff --git a/sink.c b/sink.c index 3a001f7a..d6e25d89 100644 --- a/sink.c +++ b/sink.c @@ -51,7 +51,7 @@ static int smtp_open(struct query *ctl) /* maybe it's time to close the socket in order to force delivery */ if (NUM_NONZERO(ctl->batchlimit) && (ctl->smtp_socket != -1) && ++batchcount == ctl->batchlimit) { - close(ctl->smtp_socket); + SockClose(ctl->smtp_socket); ctl->smtp_socket = -1; batchcount = 0; } diff --git a/socket.c b/socket.c index 4dde2048..f8e40c34 100644 --- a/socket.c +++ b/socket.c @@ -163,7 +163,7 @@ int SockOpen(const char *host, const char *service, const char *options, } if (connect(i, (struct sockaddr *) ai->ai_addr, ai->ai_addrlen) < 0) { freeaddrinfo(ai); - close(i); + SockClose(i); return -1; } #endif @@ -226,7 +226,7 @@ int SockOpen(const char *host, int clientPort, const char *options, if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0) { int olderr = errno; - close(sock); + SockClose(sock); h_errno = 0; errno = olderr; return -1; @@ -272,14 +272,14 @@ int SockOpen(const char *host, int clientPort, const char *options, memcpy(&ad.sin_addr, *pptr, sizeof(struct in_addr)); if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) == 0) break; /* success */ - close(sock); + SockClose(sock); memset(&ad, 0, sizeof(ad)); ad.sin_family = AF_INET; } if(*pptr == NULL) { int olderr = errno; - close(sock); + SockClose(sock); h_errno = 0; errno = olderr; return -1; @@ -651,8 +651,9 @@ int SSLOpen(int sock, char *mycert, char *mykey, char *servercname ) #endif int SockClose(int sock) -/* close a socket (someday we may do other cleanup here) */ +/* close a socket gracefully */ { + char ch; #ifdef SSL_ENABLE SSL *ssl; @@ -662,15 +663,35 @@ int SockClose(int sock) _ssl_context[sock] = NULL; } #endif - return(close(sock)); + + /* Half-close the connection first so the other end gets notified. + * + * This stops sends but allows receives (effectively, it sends a + * TCP ). We ignore the return from this function because + * some older BSD-based implementations fail shutdown() if a TCP + * reset has been recieved. In any case, if it fails it means the + * connection is already closed anyway, so it doesn't matter. + */ + shutdown(sock, 1); + + /* If there is any data still waiting in the queue, discard it. + * Call recv() until either it returns 0 (meaning we received a FIN) + * or any error occurs. This makes sure all data sent by the other + * side is acknowledged at the TCP level. + */ + if (recv(sock, &ch, 1, MSG_PEEK) > 0) + while (recv(sock, &ch, 1, MSG_NOSIGNAL) > 0) + continue; + + /* if there's an error closing at this point, not much we can do */ + return(close(sock)); /* this is guarded */ } #ifdef MAIN /* * Use the chargen service to test input buffering directly. * You may have to uncomment the `chargen' service description in your - * inetd.conf (and then SIGHUP inetd) for this to work. - */ + * inetd.conf (and then SIGHUP inetd) for this to work. */ main() { int sock = SockOpen("localhost", 19, NULL); -- cgit v1.2.3