diff --git a/src/ipxwrapper.def b/src/ipxwrapper.def index cde5667..c3f10ab 100644 --- a/src/ipxwrapper.def +++ b/src/ipxwrapper.def @@ -20,3 +20,4 @@ EXPORTS getpeername listen accept + WSAAsyncSelect diff --git a/src/ipxwrapper.h b/src/ipxwrapper.h index 05d97a5..05fa88e 100644 --- a/src/ipxwrapper.h +++ b/src/ipxwrapper.h @@ -47,6 +47,7 @@ #define IPX_IS_SPX (int)(1<<10) #define IPX_IS_SPXII (int)(1<<11) #define IPX_LISTENING (int)(1<<12) +#define IPX_CONNECT_OK (int)(1<<13) typedef struct ipx_socket ipx_socket; typedef struct ipx_packet ipx_packet; @@ -152,5 +153,6 @@ int PASCAL r_send(SOCKET fd, const char *buf, int len, int flags); int PASCAL r_getpeername(SOCKET fd, struct sockaddr *addr, int *addrlen); int PASCAL r_listen(SOCKET s, int backlog); SOCKET PASCAL r_accept(SOCKET s, struct sockaddr *addr, int *addrlen); +int PASCAL r_WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent); #endif /* !IPXWRAPPER_H */ diff --git a/src/ipxwrapper_stubs.txt b/src/ipxwrapper_stubs.txt index fa2a0eb..d2b308f 100644 --- a/src/ipxwrapper_stubs.txt +++ b/src/ipxwrapper_stubs.txt @@ -33,3 +33,5 @@ r_connect:4 r_send:4 r_getpeername:4 inet_ntoa:4 +__WSAFDIsSet:4 +r_WSAAsyncSelect:4 diff --git a/src/winsock.c b/src/winsock.c index 311e2de..ad0c7bd 100644 --- a/src/winsock.c +++ b/src/winsock.c @@ -1724,12 +1724,57 @@ static int _connect_spx(ipx_socket *sock, struct sockaddr_ipx *ipxaddr) if(r_connect(sock->fd, (struct sockaddr*)(&in_addr), sizeof(in_addr)) == -1) { + if(WSAGetLastError() == WSAEWOULDBLOCK) + { + /* The socket is in non-blocking mode, so we wait for + * the asynchronous connect call to complete. + * + * Keeping it synchronous until it is proven this breaks + * something for simplicity. + */ + + fd_set w_fdset; + FD_ZERO(&w_fdset); + FD_SET(sock->fd, &w_fdset); + + fd_set e_fdset; + FD_ZERO(&e_fdset); + FD_SET(sock->fd, &e_fdset); + + if(select(1, NULL, &w_fdset, &e_fdset, NULL) == 1 && FD_ISSET(sock->fd, &w_fdset)) + { + goto CONNECTED; + } + + int errnum, len = sizeof(int); + getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, (char*)(&errnum), &len); + + log_printf(LOG_DEBUG, "Connection failed: %s", w32_error(errnum)); + + unlock_sockets(); + + WSASetLastError(WSAEWOULDBLOCK); + return -1; + } + unlock_sockets(); return -1; } + CONNECTED: + log_printf(LOG_DEBUG, "Connection succeeded"); + /* Set the IPX_CONNECT_OK bit which indicates the next WSAAsyncSelect + * call with FD_CONNECT set should send a message indicating the + * connection succeeded and then clear this bit. + * + * This is a hack to make asynchronous connect calls vaguely work as + * they should. + */ + + sock->flags |= IPX_CONNECT_OK; + /* The TCP connection is up! * * Store the remote IPX address in remote_addr and mark the socket as @@ -2145,3 +2190,26 @@ SOCKET PASCAL accept(SOCKET s, struct sockaddr *addr, int *addrlen) return r_accept(s, addr, addrlen); } } + +int PASCAL WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent) +{ + if(lEvent & FD_CONNECT) + { + ipx_socket *sock = get_socket(s); + + if(sock) + { + if(sock->flags & IPX_CONNECT_OK) + { + log_printf(LOG_DEBUG, "Posting message %u for FD_CONNECT on socket %d", wMsg, sock->fd); + + PostMessage(hWnd, wMsg, sock->fd, MAKEWORD(FD_CONNECT, 0)); + sock->flags &= ~IPX_CONNECT_OK; + } + + unlock_sockets(); + } + } + + return r_WSAAsyncSelect(s, hWnd, wMsg, lEvent); +} diff --git a/src/wsock32_stubs.txt b/src/wsock32_stubs.txt index 9596a70..75450c4 100644 --- a/src/wsock32_stubs.txt +++ b/src/wsock32_stubs.txt @@ -29,7 +29,7 @@ getprotobynumber getservbyname getservbyport gethostname -WSAAsyncSelect +WSAAsyncSelect:0 WSAAsyncGetHostByAddr WSAAsyncGetHostByName WSAAsyncGetProtoByNumber