Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 18 +++++++++++++----- dlls/ws2_32/ws2_32_private.h | 1 + 2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 2ba1982b1d9..94f3f139c9c 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1280,6 +1280,8 @@ static void free_per_thread_data(void)
if (!ptb) return;
+ CloseHandle( ptb->sync_event ); + /* delete scratch buffers */ HeapFree( GetProcessHeap(), 0, ptb->he_buffer ); HeapFree( GetProcessHeap(), 0, ptb->se_buffer ); @@ -1290,6 +1292,16 @@ static void free_per_thread_data(void) NtCurrentTeb()->WinSockData = NULL; }
+static HANDLE get_sync_event(void) +{ + struct per_thread_data *data; + + if (!(data = get_per_thread_data())) return NULL; + if (!data->sync_event) + data->sync_event = CreateEventW( NULL, TRUE, FALSE, NULL ); + return data->sync_event; +} + /*********************************************************************** * DllMain (WS2_32.init) */ @@ -2339,19 +2351,15 @@ SOCKET WINAPI WS_accept( SOCKET s, struct WS_sockaddr *addr, int *len )
TRACE("%#lx\n", s);
- if (!(sync_event = CreateEventW( NULL, TRUE, FALSE, NULL ))) return INVALID_SOCKET; + if (!(sync_event = get_sync_event())) return INVALID_SOCKET; status = NtDeviceIoControlFile( SOCKET2HANDLE(s), (HANDLE)((ULONG_PTR)sync_event | 0), NULL, NULL, &io, IOCTL_AFD_WINE_ACCEPT, NULL, 0, &accept_handle, sizeof(accept_handle) ); if (status == STATUS_PENDING) { if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED) - { - CloseHandle( sync_event ); return SOCKET_ERROR; - } status = io.u.Status; } - CloseHandle( sync_event ); if (status) { WARN("failed; status %#x\n", status); diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h index e86a3569510..527dbe903b4 100644 --- a/dlls/ws2_32/ws2_32_private.h +++ b/dlls/ws2_32/ws2_32_private.h @@ -181,6 +181,7 @@ UINT sock_get_error( int err ) DECLSPEC_HIDDEN;
struct per_thread_data { + HANDLE sync_event; /* event to wait on for synchronous ioctls */ int opentype; struct WS_hostent *he_buffer; struct WS_servent *se_buffer;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 94f3f139c9c..0c1ba594825 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -2352,8 +2352,8 @@ SOCKET WINAPI WS_accept( SOCKET s, struct WS_sockaddr *addr, int *len ) TRACE("%#lx\n", s);
if (!(sync_event = get_sync_event())) return INVALID_SOCKET; - status = NtDeviceIoControlFile( SOCKET2HANDLE(s), (HANDLE)((ULONG_PTR)sync_event | 0), NULL, NULL, &io, - IOCTL_AFD_WINE_ACCEPT, NULL, 0, &accept_handle, sizeof(accept_handle) ); + status = NtDeviceIoControlFile( (HANDLE)s, sync_event, NULL, NULL, &io, IOCTL_AFD_WINE_ACCEPT, + NULL, 0, &accept_handle, sizeof(accept_handle) ); if (status == STATUS_PENDING) { if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED)
In particular, so that we can wait for POLLOUT on a connecting socket multiple times, in case the first connection fails, without polling on it while it is unconnected.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- v2: Patch added; no other patches in the series were modified.
server/fd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/server/fd.c b/server/fd.c index 481e9a88f0f..e7253ec8f51 100644 --- a/server/fd.c +++ b/server/fd.c @@ -549,7 +549,6 @@ static inline void set_fd_epoll_events( struct fd *fd, int user, int events ) } else if (pollfd[user].fd == -1) { - if (pollfd[user].events) return; /* stopped waiting on it, don't restart */ ctl = EPOLL_CTL_ADD; } else @@ -658,7 +657,6 @@ static inline void set_fd_epoll_events( struct fd *fd, int user, int events ) } else if (pollfd[user].fd == -1) { - if (pollfd[user].events) return; /* stopped waiting on it, don't restart */ ev[0].flags |= EV_ADD | ((events & POLLIN) ? EV_ENABLE : EV_DISABLE); ev[1].flags |= EV_ADD | ((events & POLLOUT) ? EV_ENABLE : EV_DISABLE); } @@ -767,7 +765,6 @@ static inline void set_fd_epoll_events( struct fd *fd, int user, int events ) } else if (pollfd[user].fd == -1) { - if (pollfd[user].events) return; /* stopped waiting on it, don't restart */ ret = port_associate( port_fd, PORT_SOURCE_FD, fd->unix_fd, events, (void *)user ); } else @@ -1647,7 +1644,7 @@ void set_fd_events( struct fd *fd, int events ) pollfd[user].events = POLLERR; pollfd[user].revents = 0; } - else if (pollfd[user].fd != -1 || !pollfd[user].events) + else { pollfd[user].fd = fd->unix_fd; pollfd[user].events = events;
I was able to reverse-engineer a native CONNECT ioctl, with code 0x801; but I was not able to find a valid set of parameters which would allow us to implement either connect() or ConnectEx(). In particular, I could not find a way to make the ioctl respect nonblocking mode, and I could not find a way to specify an initial buffer to be sent.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- include/wine/afd.h | 9 +++ server/sock.c | 152 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+)
diff --git a/include/wine/afd.h b/include/wine/afd.h index e890020ca88..b085981b6c0 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -36,6 +36,7 @@ struct afd_listen_params #define IOCTL_AFD_WINE_CREATE CTL_CODE(FILE_DEVICE_NETWORK, 200, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_ACCEPT CTL_CODE(FILE_DEVICE_NETWORK, 201, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_ACCEPT_INTO CTL_CODE(FILE_DEVICE_NETWORK, 202, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_CONNECT CTL_CODE(FILE_DEVICE_NETWORK, 203, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_AFD_WINE_ADDRESS_LIST_CHANGE CTL_CODE(FILE_DEVICE_NETWORK, 323, METHOD_BUFFERED, FILE_ANY_ACCESS)
@@ -51,4 +52,12 @@ struct afd_accept_into_params unsigned int recv_len, local_len; };
+struct afd_connect_params +{ + int addr_len; + int synchronous; + /* VARARG(addr, struct sockaddr, addr_len); */ + /* VARARG(data, bytes); */ +}; + #endif diff --git a/server/sock.c b/server/sock.c index 565fb4c5a2c..9896810def1 100644 --- a/server/sock.c +++ b/server/sock.c @@ -106,6 +106,14 @@ struct accept_req unsigned int recv_len, local_len; };
+struct connect_req +{ + struct async *async; + struct iosb *iosb; + struct sock *sock; + unsigned int addr_len, send_len, send_cursor; +}; + struct sock { struct object obj; /* object header */ @@ -141,10 +149,12 @@ struct sock struct async_queue write_q; /* queue for asynchronous writes */ struct async_queue ifchange_q; /* queue for interface change notifications */ struct async_queue accept_q; /* queue for asynchronous accepts */ + struct async_queue connect_q; /* queue for asynchronous connects */ struct object *ifchange_obj; /* the interface change notification object */ struct list ifchange_entry; /* entry in ifchange notification list */ struct list accept_list; /* list of pending accept requests */ struct accept_req *accept_recv_req; /* pending accept-into request which will recv on this socket */ + struct connect_req *connect_req; /* pending connection request */ };
static void sock_dump( struct object *obj, int verbose ); @@ -558,6 +568,58 @@ static void complete_async_accept_recv( struct accept_req *req ) fill_accept_output( req ); }
+static void free_connect_req( void *private ) +{ + struct connect_req *req = private; + + req->sock->connect_req = NULL; + release_object( req->async ); + release_object( req->iosb ); + release_object( req->sock ); + free( req ); +} + +static void complete_async_connect( struct sock *sock ) +{ + struct connect_req *req = sock->connect_req; + const char *in_buffer; + struct iosb *iosb; + size_t len; + int ret; + + if (debug_level) fprintf( stderr, "completing connect request for socket %p\n", sock ); + + sock->pending_events &= ~(FD_CONNECT | FD_READ | FD_WRITE); + sock->reported_events &= ~(FD_CONNECT | FD_READ | FD_WRITE); + sock->state |= FD_WINE_CONNECTED; + sock->state &= ~(FD_CONNECT | FD_WINE_LISTENING); + + if (!req->send_len) + { + set_error( STATUS_SUCCESS ); + return; + } + + iosb = req->iosb; + in_buffer = (const char *)iosb->in_data + sizeof(struct afd_connect_params) + req->addr_len; + len = req->send_len - req->send_cursor; + + ret = send( get_unix_fd( sock->fd ), in_buffer + req->send_cursor, len, 0 ); + if (ret < 0 && errno != EWOULDBLOCK) + set_error( sock_get_ntstatus( errno ) ); + else if (ret == len) + { + iosb->result = req->send_len; + iosb->status = STATUS_SUCCESS; + set_error( STATUS_ALERTED ); + } + else + { + req->send_cursor += ret; + set_error( STATUS_PENDING ); + } +} + static int sock_dispatch_asyncs( struct sock *sock, int event, int error ) { if (event & (POLLIN | POLLPRI)) @@ -583,6 +645,13 @@ static int sock_dispatch_asyncs( struct sock *sock, int event, int error ) } }
+ if ((event & POLLOUT) && sock->connect_req && sock->connect_req->iosb->status == STATUS_PENDING) + { + complete_async_connect( sock ); + if (get_error() != STATUS_PENDING) + async_terminate( sock->connect_req->async, get_error() ); + } + if (is_fd_overlapped( sock->fd )) { if (event & (POLLIN|POLLPRI) && async_waiting( &sock->read_q )) @@ -617,6 +686,9 @@ static int sock_dispatch_asyncs( struct sock *sock, int event, int error )
if (sock->accept_recv_req && sock->accept_recv_req->iosb->status == STATUS_PENDING) async_terminate( sock->accept_recv_req->async, status ); + + if (sock->connect_req) + async_terminate( sock->connect_req->async, status ); }
return event; @@ -865,6 +937,9 @@ static int sock_close_handle( struct object *obj, struct process *process, obj_h
LIST_FOR_EACH_ENTRY_SAFE( req, next, &sock->accept_list, struct accept_req, entry ) async_terminate( req->async, STATUS_CANCELLED ); + + if (sock->connect_req) + async_terminate( sock->connect_req->async, STATUS_CANCELLED ); }
return 1; @@ -887,6 +962,7 @@ static void sock_destroy( struct object *obj ) free_async_queue( &sock->write_q ); free_async_queue( &sock->ifchange_q ); free_async_queue( &sock->accept_q ); + free_async_queue( &sock->connect_q ); if (sock->event) release_object( sock->event ); if (sock->fd) { @@ -919,10 +995,12 @@ static struct sock *create_socket(void) sock->deferred = NULL; sock->ifchange_obj = NULL; sock->accept_recv_req = NULL; + sock->connect_req = NULL; init_async_queue( &sock->read_q ); init_async_queue( &sock->write_q ); init_async_queue( &sock->ifchange_q ); init_async_queue( &sock->accept_q ); + init_async_queue( &sock->connect_q ); memset( sock->errors, 0, sizeof(sock->errors) ); list_init( &sock->accept_list ); return sock; @@ -1318,6 +1396,7 @@ static int sock_get_ntstatus( int err ) case EPIPE: case ECONNRESET: return STATUS_CONNECTION_RESET; case ECONNABORTED: return STATUS_CONNECTION_ABORTED; + case EISCONN: return STATUS_CONNECTION_ACTIVE;
case 0: return STATUS_SUCCESS; default: @@ -1486,6 +1565,79 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return 0; }
+ case IOCTL_AFD_WINE_CONNECT: + { + const struct afd_connect_params *params = get_req_data(); + const struct sockaddr *addr; + struct connect_req *req; + int send_len, ret; + + if (get_req_data_size() < sizeof(*params) || + get_req_data_size() - sizeof(*params) < params->addr_len) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + send_len = get_req_data_size() - sizeof(*params) - params->addr_len; + addr = (const struct sockaddr *)(params + 1); + + if (sock->accept_recv_req) + { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + + if (sock->connect_req) + { + set_error( params->synchronous ? STATUS_INVALID_PARAMETER : STATUS_CONNECTION_ACTIVE ); + return 0; + } + + ret = connect( unix_fd, addr, params->addr_len ); + if (ret < 0 && errno != EINPROGRESS) + { + set_error( sock_get_ntstatus( errno ) ); + return 0; + } + + sock->pending_events &= ~(FD_CONNECT | FD_READ | FD_WRITE); + sock->reported_events &= ~(FD_CONNECT | FD_READ | FD_WRITE); + + if (!ret) + { + sock->state |= FD_WINE_CONNECTED | FD_READ | FD_WRITE; + sock->state &= ~FD_CONNECT; + + if (!send_len) return 1; + } + + if (!(req = mem_alloc( sizeof(*req) ))) + return 0; + + sock->state |= FD_CONNECT; + + if (params->synchronous && (sock->state & FD_WINE_NONBLOCKING)) + { + sock_reselect( sock ); + set_error( STATUS_DEVICE_NOT_READY ); + return 0; + } + + req->async = (struct async *)grab_object( async ); + req->iosb = async_get_iosb( async ); + req->sock = (struct sock *)grab_object( sock ); + req->addr_len = params->addr_len; + req->send_len = send_len; + req->send_cursor = 0; + + async_set_completion_callback( async, free_connect_req, req ); + sock->connect_req = req; + queue_async( &sock->connect_q, async ); + sock_reselect( sock ); + set_error( STATUS_PENDING ); + return 1; + } + case IOCTL_AFD_WINE_ADDRESS_LIST_CHANGE: if ((sock->state & FD_WINE_NONBLOCKING) && async_is_blocking( async )) {
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 140 +++++++++++++++---------------------------- 1 file changed, 49 insertions(+), 91 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 0c1ba594825..3a39493bc3b 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -3064,116 +3064,74 @@ int WINAPI WSAConnect( SOCKET s, const struct WS_sockaddr* name, int namelen, return WS_connect( s, name, namelen ); }
-/*********************************************************************** - * ConnectEx - */ -static BOOL WINAPI WS2_ConnectEx(SOCKET s, const struct WS_sockaddr* name, int namelen, - PVOID sendBuf, DWORD sendBufLen, LPDWORD sent, LPOVERLAPPED ov) + +static BOOL WINAPI WS2_ConnectEx( SOCKET s, const struct WS_sockaddr *name, int namelen, + void *send_buffer, DWORD send_len, DWORD *ret_len, OVERLAPPED *overlapped ) { - int fd, ret, status; + union generic_unix_sockaddr uaddr; + unsigned int uaddrlen = ws_sockaddr_ws2u(name, namelen, &uaddr); + struct afd_connect_params *params; + void *cvalue = NULL; + NTSTATUS status; + int fd, ret;
- if (!ov) - { - SetLastError( ERROR_INVALID_PARAMETER ); + TRACE( "socket %#lx, ptr %p %s, length %d, send_buffer %p, send_len %u, overlapped %p\n", + s, name, debugstr_sockaddr(name), namelen, send_buffer, send_len, overlapped ); + + if ((fd = get_sock_fd( s, FILE_READ_DATA, NULL )) == -1) return FALSE; - }
- fd = get_sock_fd( s, FILE_READ_DATA, NULL ); - if (fd == -1) return FALSE; - - TRACE("socket %04lx, ptr %p %s, length %d, sendptr %p, len %d, ov %p\n", - s, name, debugstr_sockaddr(name), namelen, sendBuf, sendBufLen, ov); - - ret = is_fd_bound(fd, NULL, NULL); - if (ret <= 0) + if ((ret = is_fd_bound( fd, NULL, NULL )) <= 0) { - SetLastError(ret == -1 ? wsaErrno() : WSAEINVAL); + SetLastError( ret ? wsaErrno() : WSAEINVAL ); release_sock_fd( s, fd ); return FALSE; } + release_sock_fd( s, fd );
- ret = do_connect(fd, name, namelen); - if (ret == 0) + if (!overlapped) { - WSABUF wsabuf; - - _enable_event(SOCKET2HANDLE(s), FD_CONNECT|FD_READ|FD_WRITE, - FD_WINE_CONNECTED|FD_READ|FD_WRITE, - FD_CONNECT|FD_WINE_LISTENING); - - wsabuf.len = sendBufLen; - wsabuf.buf = (char*) sendBuf; - - /* WSASend takes care of completion if need be */ - if (WSASend(s, &wsabuf, sendBuf ? 1 : 0, sent, 0, ov, NULL) != SOCKET_ERROR) - goto connection_success; + SetLastError( WSA_INVALID_PARAMETER ); + return FALSE; } - else if (ret == WSAEWOULDBLOCK) + + if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped; + overlapped->Internal = STATUS_PENDING; + overlapped->InternalHigh = 0; + + if (!uaddrlen) { - struct ws2_async *wsa; - DWORD size; + SetLastError( WSAEFAULT ); + return SOCKET_ERROR; + }
- ULONG_PTR cvalue = (((ULONG_PTR)ov->hEvent & 1) == 0) ? (ULONG_PTR)ov : 0; - - _enable_event(SOCKET2HANDLE(s), FD_CONNECT|FD_READ|FD_WRITE, - FD_CONNECT, - FD_WINE_CONNECTED|FD_WINE_LISTENING); - - size = offsetof( struct ws2_async, iovec[1] ) + sendBufLen; - - /* Indirectly call WSASend */ - if (!(wsa = (struct ws2_async *)alloc_async_io( size, WS2_async_send ))) + if (name->sa_family == WS_AF_INET) + { + struct sockaddr_in *in4 = (struct sockaddr_in *)&uaddr; + if (!memcmp( &in4->sin_addr, magic_loopback_addr, sizeof(magic_loopback_addr) )) { - SetLastError(WSAEFAULT); - } - else - { - IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)ov; - iosb->u.Status = STATUS_PENDING; - iosb->Information = 0; - - wsa->hSocket = SOCKET2HANDLE(s); - wsa->addr = NULL; - wsa->addrlen.val = 0; - wsa->flags = 0; - wsa->lpFlags = &wsa->flags; - wsa->control = NULL; - wsa->n_iovecs = sendBuf ? 1 : 0; - wsa->first_iovec = 0; - wsa->completion_func = NULL; - wsa->iovec[0].iov_base = &wsa->iovec[1]; - wsa->iovec[0].iov_len = sendBufLen; - - if (sendBufLen) - memcpy( wsa->iovec[0].iov_base, sendBuf, sendBufLen ); - - status = register_async( ASYNC_TYPE_WRITE, wsa->hSocket, &wsa->io, ov->hEvent, - NULL, (void *)cvalue, iosb ); - if (status != STATUS_PENDING) HeapFree(GetProcessHeap(), 0, wsa); - - /* If the connect already failed */ - if (status == STATUS_PIPE_DISCONNECTED) - { - ov->Internal = sock_error_to_ntstatus( get_sock_error( s, FD_CONNECT_BIT )); - ov->InternalHigh = 0; - if (cvalue) WS_AddCompletion( s, cvalue, ov->Internal, ov->InternalHigh, TRUE ); - if (ov->hEvent) NtSetEvent( ov->hEvent, NULL ); - status = STATUS_PENDING; - } - SetLastError( NtStatusToWSAError(status) ); + TRACE("Replacing magic address 127.12.34.56 with INADDR_LOOPBACK.\n"); + in4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); } } - else + + if (!(params = HeapAlloc( GetProcessHeap(), 0, sizeof(*params) + uaddrlen + send_len ))) { - SetLastError(ret); + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return SOCKET_ERROR; } + params->addr_len = uaddrlen; + params->synchronous = FALSE; + memcpy( params + 1, &uaddr, uaddrlen ); + memcpy( (char *)(params + 1) + uaddrlen, send_buffer, send_len );
- release_sock_fd( s, fd ); - return FALSE; - -connection_success: - release_sock_fd( s, fd ); - return TRUE; + status = NtDeviceIoControlFile( SOCKET2HANDLE(s), overlapped->hEvent, NULL, cvalue, + (IO_STATUS_BLOCK *)overlapped, IOCTL_AFD_WINE_CONNECT, + params, sizeof(*params) + uaddrlen + send_len, NULL, 0 ); + HeapFree( GetProcessHeap(), 0, params ); + if (ret_len) *ret_len = overlapped->InternalHigh; + SetLastError( NtStatusToWSAError( status ) ); + return !status; }
/***********************************************************************
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 108 +++++++++++++++------------------------ dlls/ws2_32/tests/sock.c | 21 +------- 2 files changed, 44 insertions(+), 85 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 3a39493bc3b..889f0327baf 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1145,13 +1145,6 @@ static void _get_sock_errors(SOCKET s, int *events) SERVER_END_REQ; }
-static int get_sock_error(SOCKET s, unsigned int bit) -{ - int events[FD_MAX_EVENTS]; - _get_sock_errors(s, events); - return events[bit]; -} - static int _get_fd_type(int fd) { int sock_type = -1; @@ -2976,82 +2969,65 @@ int WINAPI WS_closesocket(SOCKET s) return res; }
-static int do_connect(int fd, const struct WS_sockaddr* name, int namelen) + +/*********************************************************************** + * connect (ws2_32.4) + */ +int WINAPI WS_connect( SOCKET s, const struct WS_sockaddr *addr, int len ) { union generic_unix_sockaddr uaddr; - unsigned int uaddrlen = ws_sockaddr_ws2u(name, namelen, &uaddr); + unsigned int uaddrlen = ws_sockaddr_ws2u( addr, len, &uaddr ); + struct afd_connect_params *params; + IO_STATUS_BLOCK io; + HANDLE sync_event; + NTSTATUS status; + + TRACE( "socket %#lx, addr %s, len %d\n", s, debugstr_sockaddr(addr), len );
if (!uaddrlen) - return WSAEFAULT; - - if (name->sa_family == WS_AF_INET) { - struct sockaddr_in *in4 = (struct sockaddr_in*) &uaddr; - if (memcmp(&in4->sin_addr, magic_loopback_addr, 4) == 0) + SetLastError( WSAEFAULT ); + return -1; + } + + if (addr->sa_family == WS_AF_INET) + { + struct sockaddr_in *in4 = (struct sockaddr_in *)&uaddr; + if (!memcmp(&in4->sin_addr, magic_loopback_addr, sizeof(magic_loopback_addr))) { - /* Trying to connect to magic replace-loopback address, - * assuming we really want to connect to localhost */ - TRACE("Trying to connect to magic IP address, using " - "INADDR_LOOPBACK instead.\n"); + TRACE("Replacing magic address 127.12.34.56 with INADDR_LOOPBACK.\n"); in4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); } }
- if (connect(fd, &uaddr.addr, uaddrlen) == 0) - return 0; + if (!(sync_event = get_sync_event())) return -1;
- return wsaErrno(); -} - -/*********************************************************************** - * connect (WS2_32.4) - */ -int WINAPI WS_connect(SOCKET s, const struct WS_sockaddr* name, int namelen) -{ - int fd = get_sock_fd( s, FILE_READ_DATA, NULL ); - - TRACE("socket %04lx, ptr %p %s, length %d\n", s, name, debugstr_sockaddr(name), namelen); - - if (fd != -1) + if (!(params = HeapAlloc( GetProcessHeap(), 0, sizeof(*params) + uaddrlen ))) { - BOOL is_blocking; - int ret = do_connect(fd, name, namelen); - if (ret == 0) - goto connect_success; - - if (ret == WSAEWOULDBLOCK) - { - /* tell wineserver that a connection is in progress */ - _enable_event(SOCKET2HANDLE(s), FD_CONNECT|FD_READ|FD_WRITE, - FD_CONNECT, - FD_WINE_CONNECTED|FD_WINE_LISTENING); - ret = sock_is_blocking( s, &is_blocking ); - if (!ret) - { - if (is_blocking) - { - do_block(fd, POLLIN | POLLOUT, -1); - _sync_sock_state(s); /* let wineserver notice connection */ - /* retrieve any error codes from it */ - if (!(ret = get_sock_error(s, FD_CONNECT_BIT))) goto connect_success; - } - else ret = WSAEWOULDBLOCK; - } - } - release_sock_fd( s, fd ); - SetLastError(ret); + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return -1; } - return SOCKET_ERROR; + params->addr_len = uaddrlen; + params->synchronous = TRUE; + memcpy(params + 1, &uaddr, uaddrlen);
-connect_success: - release_sock_fd( s, fd ); - _enable_event(SOCKET2HANDLE(s), FD_CONNECT|FD_READ|FD_WRITE, - FD_WINE_CONNECTED|FD_READ|FD_WRITE, - FD_CONNECT|FD_WINE_LISTENING); - TRACE("\tconnected %04lx\n", s); + status = NtDeviceIoControlFile( (HANDLE)s, sync_event, NULL, NULL, &io, IOCTL_AFD_WINE_CONNECT, + params, sizeof(*params) + uaddrlen, NULL, 0); + HeapFree( GetProcessHeap(), 0, params ); + if (status == STATUS_PENDING) + { + if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED) return -1; + status = io.u.Status; + } + if (status) + { + SetLastError( NtStatusToWSAError( status ) ); + return -1; + } return 0; }
+ /*********************************************************************** * WSAConnect (WS2_32.30) */ diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 33cdd5d6d15..5028a4e749e 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -4159,7 +4159,7 @@ static void test_connect_events(struct event_test_ctx *ctx) if (ctx->is_message) check_events(ctx, FD_WRITE, 0, 200); else - check_events_todo(ctx, FD_CONNECT, FD_WRITE, 200); + check_events(ctx, FD_CONNECT, FD_WRITE, 200);
closesocket(client); closesocket(server); @@ -6117,25 +6117,8 @@ todo_wine
/* try to connect a socket that's being accepted into */ iret = connect(acceptor, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); - todo_wine ok(iret == SOCKET_ERROR && WSAGetLastError() == WSAEINVAL, + ok(iret == SOCKET_ERROR && WSAGetLastError() == WSAEINVAL, "connecting to acceptex acceptor succeeded? return %d + errno %d\n", iret, WSAGetLastError()); - if (!iret || (iret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)) { - /* We need to cancel this call, otherwise things fail */ - closesocket(acceptor); - acceptor = socket(AF_INET, SOCK_STREAM, 0); - ok(acceptor != INVALID_SOCKET, "failed to create socket, error %u\n", GetLastError()); - - bret = CancelIo((HANDLE) listener); - ok(bret, "Failed to cancel failed test. Bailing...\n"); - if (!bret) return; - - overlapped.Internal = 0xdeadbeef; - bret = pAcceptEx(listener, acceptor, buffer, 0, - sizeof(struct sockaddr_in) + 16, sizeof(struct sockaddr_in) + 16, - &bytesReturned, &overlapped); - ok(bret == FALSE && WSAGetLastError() == ERROR_IO_PENDING, "AcceptEx returned %d + errno %d\n", bret, WSAGetLastError()); - ok(overlapped.Internal == STATUS_PENDING, "got %08x\n", (ULONG)overlapped.Internal); - }
bret = pConnectEx(acceptor, (struct sockaddr *)&bindAddress, sizeof(bindAddress), NULL, 0, &bytesReturned, &overlapped2);