From: Arseny S. <am...@ic...> - 2002-05-22 22:49:24
|
Hello Sam, Wednesday, May 22, 2002, 11:24:37 PM, you wrote: >> Joerg-Cyril> Is 30 seconds actually acceptable? Who recommends this value? >> I steal that in Apache sources. I think we can trust them about it. Sam> could you please quote the Apache source file (with the relevant Sam> comments)? Sam> thanks. That's what I meditated on (it's found in http_main.c module). They don't want blocking so the code somethat complicated. ********************************** /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2002 The Apache Software Foundation. All rights * reserved. * skipped... /* * More machine-dependent networking gooo... on some systems, * you've got to be *really* sure that all the packets are acknowledged * before closing the connection, since the client will not be able * to see the last response if their TCP buffer is flushed by a RST * packet from us, which is what the server's TCP stack will send * if it receives any request data after closing the connection. * * In an ideal world, this function would be accomplished by simply * setting the socket option SO_LINGER and handling it within the * server's TCP stack while the process continues on to the next request. * Unfortunately, it seems that most (if not all) operating systems * block the server process on close() when SO_LINGER is used. * For those that don't, see USE_SO_LINGER below. For the rest, * we have created a home-brew lingering_close. * * Many operating systems tend to block, puke, or otherwise mishandle * calls to shutdown only half of the connection. You should define * NO_LINGCLOSE in ap_config.h if such is the case for your system. */ #ifndef MAX_SECS_TO_LINGER #define MAX_SECS_TO_LINGER 30 #endif #ifdef USE_SO_LINGER #define NO_LINGCLOSE /* The two lingering options are exclusive */ static void sock_enable_linger(int s) { struct linger li; li.l_onoff = 1; li.l_linger = MAX_SECS_TO_LINGER; if (setsockopt(s, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) < 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "setsockopt: (SO_LINGER)"); /* not a fatal error */ } } #else #define sock_enable_linger(s) /* NOOP */ #endif /* USE_SO_LINGER */ #ifndef NO_LINGCLOSE /* Special version of timeout for lingering_close */ static void lingerout(int sig) { #ifdef NETWARE get_tsd #endif if (alarms_blocked) { alarm_pending = 1; return; } if (!current_conn) { ap_longjmp(jmpbuffer, 1); } ap_bsetflag(current_conn->client, B_EOUT, 1); current_conn->aborted = 1; } static void linger_timeout(void) { #ifdef NETWARE get_tsd #endif timeout_name = "lingering close"; ap_set_callback_and_alarm(lingerout, MAX_SECS_TO_LINGER); } /* Since many clients will abort a connection instead of closing it, * attempting to log an error message from this routine will only * confuse the webmaster. There doesn't seem to be any portable way to * distinguish between a dropped connection and something that might be * worth logging. */ static void lingering_close(request_rec *r) { char dummybuf[512]; struct timeval tv; fd_set lfds; int select_rv; int lsd; /* Prevent a slow-drip client from holding us here indefinitely */ linger_timeout(); /* Send any leftover data to the client, but never try to again */ if (ap_bflush(r->connection->client) == -1) { ap_kill_timeout(r); ap_bclose(r->connection->client); return; } ap_bsetflag(r->connection->client, B_EOUT, 1); /* Close our half of the connection --- send the client a FIN */ lsd = r->connection->client->fd; if ((shutdown(lsd, 1) != 0) || r->connection->aborted) { ap_kill_timeout(r); ap_bclose(r->connection->client); return; } /* Set up to wait for readable data on socket... */ FD_ZERO(&lfds); /* Wait for readable data or error condition on socket; * slurp up any data that arrives... We exit when we go for an * interval of tv length without getting any more data, get an error * from select(), get an error or EOF on a read, or the timer expires. */ do { /* We use a 2 second timeout because current (Feb 97) browsers * fail to close a connection after the server closes it. Thus, * to avoid keeping the child busy, we are only lingering long enough * for a client that is actively sending data on a connection. * This should be sufficient unless the connection is massively * losing packets, in which case we might have missed the RST anyway. * These parameters are reset on each pass, since they might be * changed by select. */ #ifdef NETWARE ThreadSwitch(); #endif FD_SET(lsd, &lfds); tv.tv_sec = 2; tv.tv_usec = 0; select_rv = ap_select(lsd + 1, &lfds, NULL, NULL, &tv); } while ((select_rv > 0) && #if defined(WIN32) || defined(NETWARE) (recv(lsd, dummybuf, sizeof(dummybuf), 0) > 0)); #else (read(lsd, dummybuf, sizeof(dummybuf)) > 0)); #endif /* Should now have seen final ack. Safe to finally kill socket */ ap_bclose(r->connection->client); ap_kill_timeout(r); } #endif /* ndef NO_LINGCLOSE */ ********************************** >> As about header... Maybe... Nobody finds it there anyway. Sam> changing win32.d requires recompiling _all_ *.d files. Sam> changing socket.d is much cheaper. -- Best regards, Arseny mailto:am...@ic... |