- From: Yovav Meydad <yovavm@contact.com>
- Date: Thu, 25 May 2000 17:30:01 +0200
- To: <www-lib@w3.org>
- Cc: "Arkady Kasianski \(E-mail\)" <arikka@amdocs.com>
Hi, I have found 2 bugs; Here they are with a fix: 1. Bug in the implementation of the TCP state machine: HTDoConnect (HTNet * net) (in HTTCP.c) Bug Details -------------- When calling connect() in the second time, after the first call to connect() returned WSAEWOULDBLOCK (10035), an error of WSAEINVAL (10022) is returned. It happens often on WinNT & Win95, and rarely on Win2K & Win98, where in most cases the second call to connect() returns WSAEISCON (10056). I have no idea what is the behavior of connect() on UNIX. The current implementation, consider WSAEINVAL as an error and set the host->tcpstate to TCP_ERROR, which cause, in the layers above, cleanup to be done (request unregister, HTTPCleanup etc. ), without retrying again. The Microsoft docs regarding connect() says: "... Until the connection attempt completes on a nonblocking socket, all subsequent calls to connect on the same socket will fail with the error code WSAEALREADY, and WSAEISCONN when the connection completes successfully. Due to ambiguities in version 1.1 of the Windows Sockets specification, error codes returned from connect while a connection is already pending may vary among implementations. As a result, it is not recommended that applications use multiple calls to connect to detect connection completion. If they do, they must be prepared to handle WSAEINVAL and WSAEWOULDBLOCK error values the same way that they handle WSAEALREADY, to assure robust execution ..." And here is another good one .... This is the description for error WSAEALREADY: "A nonblocking connect call is in progress on the specified socket. Note In order to preserve backward compatibility, this error is reported as WSAEINVAL to Windows Sockets 1.1 applications that link to either Winsock.dll or Wsock32.dll." The Fix ---------- The bug fix is done in HTTCP.c: 1. At the WINSOCKAPI specific macros (line 47), define another macro to handle an error of WSAEINVAL: Note: The Unix part was not tested. /* imperical study in socket call error codes */ #ifdef _WINSOCKAPI_ /* windows */ #define NETCALL_ERROR(ret) (ret == SOCKET_ERROR) #define NETCALL_DEADSOCKET(err) (err == WSAEBADF) #define NETCALL_WOULDBLOCK(err) (err == WSAEWOULDBLOCK) #define NETCALL_INVAL(err) (err == WSAEINVAL) /* yovavm@contact.com */ #else /* _WINSOCKAPI_ unix */ #define NETCALL_ERROR(ret) (ret < 0) #define NETCALL_DEADSOCKET(err) (err == EBADF) #define NETCALL_INVAL(err) (err == EINVAL) /* yovavm@contact.com - Check if this is error code exist on on UNIX machines */ 2. To the HTDoConnect (HTNet * net) function, under the TCP_NEED_CONNECT case of the state machine (line 294), add a condition to handle an error of WSAEINVAL: case TCP_NEED_CONNECT: status = connect(HTChannel_socket(host->channel), (struct sockaddr *) &host->sock_addr, sizeof(host->sock_addr)); if (NETCALL_ERROR(status)) { if (NETCALL_WOULDBLOCK(socerrno)) { HTTRACE(PROT_TRACE, "HTDoConnect. WOULD BLOCK `%s'\n" _ hostname); HTHost_register(host, net, HTEvent_CONNECT); return HT_WOULD_BLOCK; } /* * yovavm@contact.com * * According to Microsoft docs, the error code WSAEALREADY is described as: * "A nonblocking connect call is in progress on the specified socket. * Note In order to preserve backward compatibility, this error is reported as WSAEINVAL to * Windows Sockets 1.1 applications that link to either Winsock.dll or Wsock32.dll." * */ if (NETCALL_INVAL(socerrno)) { host->tcpstate = TCP_CONNECTED; HTTRACE(PROT_TRACE, "Connection to HTHost %p is already in progress.\n" _ host); break; } / * ... */ } 2. Bug in HTEvtLst.c See the comment for bug description and solution This code is in function HTEventList_loop (HTRequest * theRequest) at HTEvtLst.c line 715. #ifdef __hpux active_sockets = select(maxfds+1, (int *)&treadset, (int *)&twriteset, (int *)&texceptset, wt); #else /* * yovavm@contact.com * * On some WINSOCK versions select() with 3 empty sets and NULL timeout * returns 0 and in some it returns -1. * If 0 is returned in such situation, we will go into an infinite loop (cause the sets will stay empty forever ...), * so make sure to set the active_sockets = -1 which will take us out of the loop. */ if (( treadset.fd_count || twriteset.fd_count || texceptset.fd_count) && wt) active_sockets = select(maxfds+1, &treadset, &twriteset, &texceptset, wt); else active_sockets = -1; #endif Enjoy, Yovav ~~~~~~~~~~~~~~~~~~~~~~~~~ Yovav Meydad Software Engineer www.contact.com We Invite You to make Contact ! ~~~~~~~~~~~~~~~~~~~~~~~~~
Received on Thursday, 25 May 2000 10:32:58 UTC