stoddard 00/01/31 11:21:44
Modified: src/main http_protocol.c src/lib/apr/network_io/win32 sendrecv.c Log: Set timeouts to sendfile operation in http_protocol.c. Fix bugs in Win32 sendfile implementation. Revision Changes Path 1.53 +20 -10 apache-2.0/src/main/http_protocol.c Index: http_protocol.c =================================================================== RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v retrieving revision 1.52 retrieving revision 1.53 diff -u -r1.52 -r1.53 --- http_protocol.c 2000/01/28 18:01:16 1.52 +++ http_protocol.c 2000/01/31 19:21:37 1.53 @@ -963,9 +963,9 @@ #endif ap_bsetopt(conn->client, BO_TIMEOUT, - conn->keptalive - ? &r->server->keep_alive_timeout - : &r->server->timeout); + conn->keptalive + ? &r->server->keep_alive_timeout + : &r->server->timeout); /* Get the request... */ if (!read_request_line(r)) { @@ -2015,18 +2015,28 @@ */ API_EXPORT(long) ap_send_fd(ap_file_t *fd, request_rec *r) { + ap_status_t rv; long len = r->finfo.size; #ifdef HAVE_SENDFILE if (!r->chunked) { + ap_bsetopt(r->connection->client, BO_TIMEOUT, + r->connection->keptalive + ? &r->server->keep_alive_timeout + : &r->server->timeout); ap_bflush(r->connection->client); - if (iol_sendfile(r->connection->client->iol, - fd, /* The file to send */ - NULL, /* header and trailer iovecs */ - 0, /* Offset in file to begin sending from */ - &len, - 0) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, + rv = iol_sendfile(r->connection->client->iol, + fd, /* The file to send */ + NULL, /* header and trailer iovecs */ + 0, /* Offset in file to begin sending from */ + &len, + 0); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "ap_send_fd: iol_sendfile failed."); + } + if (r->connection->keptalive) { + ap_bsetopt(r->connection->client, BO_TIMEOUT, + &r->server->timeout); } } else { 1.7 +42 -60 apache-2.0/src/lib/apr/network_io/win32/sendrecv.c Index: sendrecv.c =================================================================== RCS file: /home/cvs/apache-2.0/src/lib/apr/network_io/win32/sendrecv.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- sendrecv.c 2000/01/27 05:57:34 1.6 +++ sendrecv.c 2000/01/31 19:21:41 1.7 @@ -69,26 +69,13 @@ WSABUF wsaData; int lasterror; DWORD dwBytes = 0; - int timeout = sock->timeout * 1000; /* Need timeout in milliseconds */ wsaData.len = *len; wsaData.buf = (char*) buf; - rv = setsockopt(sock->sock, SOL_SOCKET, SO_SNDTIMEO, (char*) &timeout, - sizeof(timeout)); - if (rv == SOCKET_ERROR) { - return WSAGetLastError(); - } - rv = WSASend(sock->sock, &wsaData, 1, &dwBytes, 0, NULL, NULL); if (rv == SOCKET_ERROR) { lasterror = WSAGetLastError(); - /* Test code: Remove before release */ - if (lasterror == WSAETIMEDOUT) - printf("wsasend: Connection timed out\n"); - else - printf("wsasend: connection failed. lasterror = %d\n", lasterror); - return lasterror; } @@ -104,25 +91,13 @@ int lasterror; DWORD dwBytes = 0; DWORD flags = 0; - int timeout = sock->timeout * 1000; /* Need timeout in milliseconds */ wsaData.len = *len; wsaData.buf = (char*) buf; - rv = setsockopt(sock->sock, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, - sizeof(timeout)); - if (rv == SOCKET_ERROR) { - return WSAGetLastError(); - } - rv = WSARecv(sock->sock, &wsaData, 1, &dwBytes, &flags, NULL, NULL); if (rv == SOCKET_ERROR) { lasterror = WSAGetLastError(); - /* Test code: remove before release */ - if (lasterror == WSAETIMEDOUT) - printf("wsarecv: Connection timed out\n"); - else - printf("wsarecv: connection failed. lasterror = %d\n", lasterror); return lasterror; } @@ -137,7 +112,6 @@ int i; int lasterror; DWORD dwBytes = 0; - int timeout = sock->timeout * 1000; /* Need timeout in milliseconds */ LPWSABUF pWsaData = (LPWSABUF) malloc(sizeof(WSABUF) * nvec); @@ -149,25 +123,9 @@ pWsaData[i].len = vec[i].iov_len; } - rv = setsockopt(sock->sock, SOL_SOCKET, SO_SNDTIMEO, (char*) &timeout, - sizeof(timeout)); - if (rv == SOCKET_ERROR) { - lasterror = WSAGetLastError(); - /* Test code: remove before release */ - printf("win32_writev: setsockopt failed. errno = %d\n", lasterror); - free(pWsaData); - return lasterror; - } - rv = WSASend(sock->sock, pWsaData, nvec, &dwBytes, 0, NULL, NULL); if (rv == SOCKET_ERROR) { lasterror = WSAGetLastError(); - /* Test code: remove before release */ - if (lasterror == WSAETIMEDOUT) - printf("wsasend: Connection timed out\n"); - else - printf("wsasend: connection failed. lasterror = %d\n", lasterror); - free(pWsaData); return lasterror; } @@ -194,17 +152,24 @@ ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len, ap_int32_t flags) { +/* + *#define WAIT_FOR_EVENT + * Note: Waiting for the socket directly is much faster than creating a seperate + * wait event. There are a couple of dangerous aspects to waiting directly + * for the socket. First, we should not wait on the socket if concurrent threads + * can wait-on/signal the same socket. This shouldn't be happening with Apache since + * a socket is uniquely tied to a thread. This will change when we begin using + * async I/O with completion ports on the socket. Second, I am not sure how the + * socket timeout code will work. I am hoping the socket will be signaled if the + * setsockopt timeout expires. Need to verify this... + */ ap_ssize_t rv; -#ifdef OVERLAPPED OVERLAPPED overlapped; -#endif TRANSMIT_FILE_BUFFERS tfb, *ptfb = NULL; - int i, lasterror, ptr = 0; + int i, ptr = 0; + int lasterror = APR_SUCCESS; DWORD dwFlags = 0; - int timeout = sock->timeout * 1000; /* Need timeout in milliseconds */ - rv = setsockopt(sock->sock, SOL_SOCKET, SO_SNDTIMEO, - (char*) &timeout, sizeof(timeout)); #if 0 if (flags | APR_SENDFILE_KEEP_SOCKET) dwFlags |= TF_REUSE_SOCKET; @@ -215,7 +180,7 @@ #endif /* TransmitFile can only send one header and one footer */ - memset(&tfb, '0', sizeof (tfb)); + memset(&tfb, '\0', sizeof (tfb)); if (hdtr && hdtr->numheaders) { ptfb = &tfb; for (i = 0; i < hdtr->numheaders; i++) { @@ -243,27 +208,44 @@ hdtr->trailers[i].iov_len); ptr += hdtr->trailers[i].iov_len; } + } + /* Initialize the overlapped structure */ + memset(&overlapped,'\0', sizeof(overlapped)); + if (offset && *offset) { + overlapped.Offset = *offset; } -#ifdef OVERLAPPED - memset(&overlapped,'0', sizeof(overlapped)); +#ifdef WAIT_FOR_EVENT + overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); #endif + rv = TransmitFile(sock->sock, /* socket */ file->filehand, /* open file descriptor of the file to be sent */ *len, /* number of bytes to send. 0=send all */ 0, /* Number of bytes per send. 0=use default */ -#ifdef OVERLAPPED - &overlapped, -#else - NULL, /* OVERLAPPED structure */ -#endif + &overlapped, /* OVERLAPPED structure */ ptfb, /* header and trailer buffers */ dwFlags); /* flags to control various aspects of TransmitFile */ if (!rv) { lasterror = WSAGetLastError(); - printf("TransmitFile failed with error %d\n", lasterror); - return lasterror; + if (lasterror == ERROR_IO_PENDING) { +#ifdef WAIT_FOR_EVENT + rv = WaitForSingleObject(overlapped.hEvent, sock->timeout * 1000); +#else + rv = WaitForSingleObject((HANDLE) sock->sock, sock->timeout * 1000); +#endif + if (rv == WAIT_OBJECT_0) + lasterror = APR_SUCCESS; + else if (rv == WAIT_TIMEOUT) + lasterror = WAIT_TIMEOUT; + else if (rv == WAIT_ABANDONED) + lasterror = WAIT_ABANDONED; + else + lasterror = GetLastError(); + } } - - return APR_SUCCESS; +#ifdef WAIT_FOR_EVENT + CloseHandle(overlapped.hEvent); +#endif + return lasterror; } #endif