diff -r a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c 249a250,262 > typedef struct ws2_accept_async > { > SOCKET s_listen; > SOCKET s_accept; > LPOVERLAPPED user_overlapped; > ULONG_PTR cvalue; > PVOID buf; > int data_len; > int local_len; > int remote_len; > ws2_async *read; > } ws2_accept_async; > 266a280,281 > static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS CompletionStatus, > ULONG Information ); 1523a1539,1655 > * WS2_async_accept_recv (INTERNAL) > * > * This function is used to finish the acceptex read request. It is > * needed to place the completion on the correct socket (listener). > */ > static NTSTATUS WINAPI WS2_async_accept_recv( void *arg, IO_STATUS_BLOCK *iosb, NTSTATUS status ) > { > void *apc; > struct ws2_accept_async *wsa = arg; > > if (!wsa->read) > { > if (!(wsa->read = HeapAlloc( GetProcessHeap(), 0, > FIELD_OFFSET(struct ws2_async, iovec[1]) ))) > { > iosb->u.Status = STATUS_NO_MEMORY; > iosb->Information = 0; > goto finish; > } > > wsa->read->hSocket = SOCKET2HANDLE(wsa->s_accept); > wsa->read->addr = NULL; > wsa->read->addrlen.ptr = NULL; > wsa->read->flags = 0; > wsa->read->n_iovecs = 1; > wsa->read->first_iovec = 0; > > wsa->read->iovec[0].iov_base = wsa->buf; > wsa->read->iovec[0].iov_len = wsa->data_len; > } > > status = WS2_async_recv( wsa->read, iosb, status, &apc); > if (status == STATUS_PENDING) > return status; > > finish: > if (wsa->user_overlapped->hEvent) SetEvent(wsa->user_overlapped->hEvent); > if (wsa->cvalue) WS_AddCompletion( wsa->s_listen, wsa->cvalue, iosb->u.Status, iosb->Information ); > > HeapFree( GetProcessHeap(), 0, wsa->read ); > HeapFree( GetProcessHeap(), 0, wsa ); > return status; > } > > /*********************************************************************** > * WS2_async_accept (INTERNAL) > * > * This is the function called to satisfy the AcceptEx callback > */ > static NTSTATUS WINAPI WS2_async_accept( void *arg, IO_STATUS_BLOCK *iosb, NTSTATUS status ) > { > struct ws2_accept_async *wsa = arg; > char *addr = ((char *) wsa->buf) + wsa->data_len; > int len; > > TRACE("listen: %lx, accept: %lx, status %x\n", wsa->s_listen, wsa->s_accept, status); > > if (status == STATUS_HANDLES_CLOSED) > status = STATUS_CANCELLED; > > if (status != STATUS_ALERTED) > goto error; > > /* WS2 Spec says size param is extra 16 bytes long...what do we put in it? */ > len = wsa->local_len - sizeof(int); > WS_getsockname(wsa->s_accept, (struct WS_sockaddr *)(addr + sizeof(int)),&len); > *(int *)addr = len; > > addr += wsa->local_len; > > len = wsa->remote_len - sizeof(int); > WS_getpeername(wsa->s_accept, (struct WS_sockaddr *)(addr + sizeof(int)),&len); > *(int *)addr = len; > > if (!wsa->data_len) > { > iosb->u.Status = STATUS_SUCCESS; > iosb->Information = 0; > goto finish; > } > > SERVER_START_REQ( register_async ) > { > req->type = ASYNC_TYPE_READ; > req->async.handle = wine_server_obj_handle( SOCKET2HANDLE(wsa->s_accept) ); > req->async.callback = wine_server_client_ptr( WS2_async_accept_recv ); > req->async.iosb = wine_server_client_ptr( iosb ); > req->async.arg = wine_server_client_ptr( wsa ); > status = wine_server_call( req ); > } > SERVER_END_REQ; > > if (status != STATUS_PENDING) > { > ERR("Could not register async read, %x\n", status); > goto error; > } > > iosb->u.Status = STATUS_PENDING; > iosb->Information = 0; > > return STATUS_SUCCESS; > > error: > iosb->u.Status = status; > iosb->Information = 0; > > finish: > if (wsa->user_overlapped->hEvent) SetEvent(wsa->user_overlapped->hEvent); > if (wsa->cvalue) WS_AddCompletion( wsa->s_listen, wsa->cvalue, iosb->u.Status, iosb->Information ); > > HeapFree( GetProcessHeap(), 0, wsa ); > > return status; > } > > /*********************************************************************** 1787a1920,1987 > /*********************************************************************** > * ConnectEx > */ > BOOL WINAPI ConnectEx(SOCKET s, const struct WS_sockaddr* name, int namelen, > PVOID sendBuf, int sendBufLen, LPDWORD sent, LPOVERLAPPED ov) > { > int fd = get_sock_fd( s, FILE_READ_DATA, NULL ); > union generic_unix_sockaddr uaddr; > unsigned int uaddrlen = ws_sockaddr_ws2u(name, namelen, &uaddr); > if (!ov || fd == -1 || !uaddrlen) > { > SetLastError( WSAEFAULT ); > 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); > > 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) > { > /* 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"); > in4->sin_addr.s_addr = htonl(WS_INADDR_LOOPBACK); > } > } > > if (connect(fd, &uaddr.addr, uaddrlen) == 0) > goto connect_success; > > if (errno == EINPROGRESS) > { > int result; > FIXME("unimplemented overlapped connect, blocking\n"); > /* tell wineserver that a connection is in progress */ > _enable_event(SOCKET2HANDLE(s), FD_CONNECT|FD_READ|FD_WRITE, > FD_CONNECT|FD_READ|FD_WRITE, > FD_WINE_CONNECTED|FD_WINE_LISTENING); > /* block here */ > do_block(fd, POLLIN | POLLOUT, -1); > _sync_sock_state(s); /* let wineserver notice connection */ > /* retrieve any error codes from it */ > result = _get_sock_error(s, FD_CONNECT_BIT); > if (result) > SetLastError(result); > else > goto connect_success; > } > else > { > SetLastError(wsaErrno()); > } > > release_sock_fd( s, fd ); > return FALSE; > > 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); > return TRUE; > } > 2599,2601c2799,2826 < FIXME("SIO_GET_EXTENSION_FUNCTION_POINTER %s: stub\n", debugstr_guid(lpvInBuffer)); < WSASetLastError(WSAEOPNOTSUPP); < return SOCKET_ERROR; --- > { > GUID acceptex_guid = WSAID_ACCEPTEX; > GUID getacceptexsockaddrs_guid = WSAID_GETACCEPTEXSOCKADDRS; > GUID connectex_guid = WSAID_CONNECTEX; > > if ( IsEqualGUID(&connectex_guid, lpvInBuffer) ) > { > *(LPFN_CONNECTEX *)lpbOutBuffer = ConnectEx; > return STATUS_SUCCESS; > } > > if ( IsEqualGUID(&acceptex_guid, lpvInBuffer) ) > { > *(LPFN_ACCEPTEX *)lpbOutBuffer = AcceptEx; > WSASetLastError(STATUS_SUCCESS); > return STATUS_SUCCESS; > } > if ( IsEqualGUID(&getacceptexsockaddrs_guid, lpvInBuffer) ) > { > *(LPFN_GETACCEPTEXSOCKADDRS *)lpbOutBuffer = GetAcceptExSockaddrs; > WSASetLastError(STATUS_SUCCESS); > return STATUS_SUCCESS; > } > > FIXME("SIO_GET_EXTENSION_FUNCTION_POINTER %s: stub\n", debugstr_guid(lpvInBuffer)); > WSASetLastError(WSAEOPNOTSUPP); > return SOCKET_ERROR; > } 5003a5229,5344 > * AcceptEx (ws2_32.@) > * > * Accept a new connection, retrieving the connected addresses and initial data. > * > * listener [I] Listening socket > * acceptor [I] Socket to accept on > * dest [O] Destination for inital data > * dest_len [I] Size of dest in bytes > * local_addr_len [I] Number of bytes reserved in dest for local addrress > * rem_addr_len [I] Number of bytes reserved in dest for remote addrress > * received [O] Destination for number of bytes of initial data > * overlapped [I] For asynchronous execution > * > * RETURNS > * Success: TRUE (Does this ever happen on windows?) > * Failure: FALSE. Use WSAGetLastError() for details of the error. > */ > BOOL WINAPI AcceptEx( SOCKET listener, SOCKET acceptor, PVOID dest, DWORD dest_len, DWORD local_addr_len, > DWORD rem_addr_len, LPDWORD received, LPOVERLAPPED overlapped ) > { > DWORD status; > struct ws2_accept_async *wsa; > ULONG_PTR cvalue = (overlapped && ((ULONG_PTR)overlapped->hEvent & 1) == 0) ? (ULONG_PTR)overlapped : 0; > > TRACE("(%lx, %lx, %p, %d, %d, %d, %p, %p)\n", listener, acceptor, dest, dest_len, local_addr_len, > rem_addr_len, received, overlapped); > > if (!dest) > { > set_error(STATUS_INVALID_PARAMETER); > return FALSE; > } > > if (!overlapped) > { > WSASetLastError(WSA_INVALID_PARAMETER); > return FALSE; > } > > wsa = HeapAlloc( GetProcessHeap(), 0, sizeof(*wsa) ); > if(!wsa) > { > set_error(ERROR_NOT_ENOUGH_MEMORY); > return FALSE; > } > > wsa->s_listen = listener; > wsa->s_accept = acceptor; > wsa->user_overlapped = overlapped; > wsa->cvalue = cvalue; > wsa->buf = dest; > wsa->data_len = dest_len; > wsa->local_len = local_addr_len; > wsa->remote_len = rem_addr_len; > wsa->read = NULL; > > SERVER_START_REQ( register_accept_async ) > { > req->data.handle = wine_server_obj_handle( SOCKET2HANDLE(wsa->s_listen) ); > req->ahandle = wine_server_obj_handle( SOCKET2HANDLE(wsa->s_accept) ); > req->data.callback = wine_server_client_ptr( WS2_async_accept ); > req->data.iosb = wine_server_client_ptr( wsa->user_overlapped ); > req->data.arg = wine_server_client_ptr( wsa ); > req->data.cvalue = 0; > status = wine_server_call( req ); > } > SERVER_END_REQ; > > if(status != STATUS_PENDING) > { > FIXME("Failed to query async: %x\n", status); > HeapFree( GetProcessHeap(), 0, wsa ); > set_error(status); > return FALSE; > } > > set_error( STATUS_PENDING ); > return FALSE; > } > > /*********************************************************************** > * GetAcceptExSockaddrs (ws2_32.@) > * > * Get infomation about an accepted socket. > * > * buf [O] Destination for the first block of data from AcceptEx() > * data_size [I] length of data in bytes > * local_size [I] Bytes reserved for local addrinfo > * remote_size [I] Bytes reserved for remote addrinfo > * local_addr [O] Destination for local sockaddr > * local_addr_len [I] Size of local_addr > * remote_addr [O] Destination for remote sockaddr > * remote_addr_len [I] Size of rem_addr > * > * RETURNS > * Nothing. > */ > void WINAPI GetAcceptExSockaddrs( PVOID buf, DWORD data_size, DWORD local_size, DWORD remote_size, > struct sockaddr **local_addr, LPINT local_addr_len, > struct sockaddr **remote_addr, LPINT remote_addr_len ) > { > char *cbuf = buf; > TRACE("(%p, %d, %d, %d, %p, %p, %p, %p)\n", buf, data_size, local_size, remote_size, local_addr, > local_addr_len, remote_addr, remote_addr_len ); > cbuf += data_size; > > *local_addr_len = *(int *) cbuf; > *local_addr = (struct sockaddr *)(cbuf + sizeof(int)); > > cbuf += local_size; > > *remote_addr_len = *(int *) cbuf; > *remote_addr = (struct sockaddr *)(cbuf + sizeof(int)); > } > > /*********************************************************************** Только в b/dlls/ws2_32: socket.c.orig Только в b/dlls/ws2_32: socket.c.rej diff -r a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c 2891c2891 < ok(bret == FALSE && WSAGetLastError() == WSAEINVAL, "AcceptEx on invalid accepting socket " --- > todo_wine ok(bret == FALSE && WSAGetLastError() == WSAEINVAL, "AcceptEx on invalid accepting socket " 2904c2904 < ok(bret == FALSE && WSAGetLastError() == WSAEINVAL, "AcceptEx on too small local address size " --- > todo_wine ok(bret == FALSE && WSAGetLastError() == WSAEINVAL, "AcceptEx on too small local address size " 2909c2909 < ok(bret == FALSE && WSAGetLastError() == WSAEINVAL, "AcceptEx on too small remote address size " --- > todo_wine ok(bret == FALSE && WSAGetLastError() == WSAEINVAL, "AcceptEx on too small remote address size " 2921c2921 < ok(bret == FALSE && WSAGetLastError() == WSAEINVAL, "AcceptEx on a non-listening socket " --- > todo_wine ok(bret == FALSE && WSAGetLastError() == WSAEINVAL, "AcceptEx on a non-listening socket " 2959c2959 < ok((iret == SOCKET_ERROR && WSAGetLastError() == WSAEINVAL) || broken(!iret) /* NT4 */, --- > todo_wine ok((iret == SOCKET_ERROR && WSAGetLastError() == WSAEINVAL) || broken(!iret) /* NT4 */, diff -r a/include/wine/server_protocol.h b/include/wine/server_protocol.h 1334a1335,1349 > struct register_accept_async_request > { > struct request_header __header; > char __pad_12[4]; > async_data_t data; > obj_handle_t ahandle; > char __pad_60[4]; > }; > struct register_accept_async_reply > { > struct reply_header __header; > }; > > > 4703a4719 > REQ_register_accept_async, 4951a4968 > struct register_accept_async_request register_accept_async_request; 5197a5215 > struct register_accept_async_reply register_accept_async_reply; 5397c5415 < #define SERVER_PROTOCOL_VERSION 394 --- > #define SERVER_PROTOCOL_VERSION 396 diff -r a/include/winsock.h b/include/winsock.h 846a847 > #define FD_WINE_ACCEPTING 0x08000000 diff -r a/server/async.c b/server/async.c 104c104 < static inline void async_reselect( struct async *async ) --- > static inline void async_event( struct async *async, int finished ) 106c106 < if (async->queue->fd) fd_reselect_async( async->queue->fd, async->queue ); --- > if (async->queue->fd) fd_async_event( async->queue->fd, async->queue, async, async->status, finished ); 122c122 < async_reselect( async ); --- > async_event( async, TRUE ); 152,161c152,169 < memset( &data, 0, sizeof(data) ); < data.type = APC_ASYNC_IO; < data.async_io.func = async->data.callback; < data.async_io.user = async->data.arg; < data.async_io.sb = async->data.iosb; < data.async_io.status = status; < thread_queue_apc( async->thread, &async->obj, &data ); < async->status = status; < async_reselect( async ); < release_object( async ); /* so that it gets destroyed when the async is done */ --- > if (async->queue->fd) > status = fd_async_terminated(async->queue->fd, async->queue, async, status); > > if (status != STATUS_PENDING) > { > memset( &data, 0, sizeof(data) ); > data.type = APC_ASYNC_IO; > data.async_io.func = async->data.callback; > data.async_io.user = async->data.arg; > data.async_io.sb = async->data.iosb; > data.async_io.status = status; > thread_queue_apc( async->thread, &async->obj, &data ); > async->status = status; > async_event( async, FALSE ); > release_object( async ); /* so that it gets destroyed when the async is done */ > } > else > async_event( async, FALSE ); 254c262 < async_reselect( async ); --- > async_event( async, FALSE ); diff -r a/server/change.c b/server/change.c 201a202 > default_fd_removable, /* removable */ 204c205,206 < default_fd_reselect_async, /* reselect_async */ --- > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ 616a619 > NULL, /* removable */ 619,620c622,624 < NULL, /* reselect_async */ < NULL, /* cancel_async */ --- > NULL, /* async_event */ > NULL, /* async_terminated */ > NULL /* cancel_async */ diff -r a/server/device.c b/server/device.c 155a156 > default_fd_removable, /* removable */ 158c159,160 < default_fd_reselect_async, /* reselect_async */ --- > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ diff -r a/server/fd.c b/server/fd.c 1921,1926d1920 < /* check if fd is on a removable device */ < int is_fd_removable( struct fd *fd ) < { < return (fd->inode && fd->inode->device->removable); < } < 1998a1993,2004 > /* default removable() */ > int default_fd_removable( struct fd *fd ) > { > return (fd->inode && fd->inode->device->removable); > } > > /* check whether an fd can be abruptly removed (ie don't cache it) */ > int is_fd_removable( struct fd *fd ) > { > return fd->fd_ops->removable( fd ); > } > 2051c2057 < void fd_reselect_async( struct fd *fd, struct async_queue *queue ) --- > void fd_async_event( struct fd *fd, struct async_queue *queue, struct async *async, int status, int finished ) 2053c2059,2064 < fd->fd_ops->reselect_async( fd, queue ); --- > fd->fd_ops->async_event( fd, queue, async, status, finished ); > } > > int fd_async_terminated( struct fd *fd, struct async_queue *queue, struct async *async, int status ) > { > return fd->fd_ops->async_terminated( fd, queue, async, status ); 2072,2073c2083,2084 < /* default reselect_async() fd routine */ < void default_fd_reselect_async( struct fd *fd, struct async_queue *queue ) --- > /* default async_event() fd routine */ > void default_fd_async_event( struct fd *fd, struct async_queue *queue, struct async *async, int status, int finished ) 2083a2095,2100 > /* default async_terminated() fd routine */ > int default_fd_async_terminated( struct fd *fd, struct async_queue *queue, struct async *async, int status ) > { > return status; > } > diff -r a/server/file.c b/server/file.c 104a105 > default_fd_removable, /* removable */ 107c108,109 < default_fd_reselect_async, /* reselect_async */ --- > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ diff -r a/server/file.h b/server/file.h 27a28 > struct async; 40a42,43 > /* is this file's fd removable */ > int (*removable)(struct fd *fd); 46,47c49,52 < /* selected events for async i/o need an update */ < void (*reselect_async)( struct fd *, struct async_queue *queue ); --- > /* an async request changed state (or being destroyed) */ > void (*async_event)(struct fd *, struct async_queue *queue, struct async *async, int status, int finished); > /* an async request was terminated, called before user apc */ > int (*async_terminated)(struct fd *, struct async_queue *queue, struct async *async, int status); 76a82 > extern int default_fd_removable( struct fd *fd ); 83c89,90 < extern void fd_reselect_async( struct fd *fd, struct async_queue *queue ); --- > extern void fd_async_event( struct fd *fd, struct async_queue *queue, struct async *async, int status, int finished ); > extern int fd_async_terminated( struct fd *fd, struct async_queue *queue, struct async *async, int status ); 90c97,98 < extern void default_fd_reselect_async( struct fd *fd, struct async_queue *queue ); --- > extern void default_fd_async_event( struct fd *fd, struct async_queue *queue, struct async *async, int status, int finished ); > extern int default_fd_async_terminated( struct fd *fd, struct async_queue *queue, struct async *async, int status ); diff -r a/server/mailslot.c b/server/mailslot.c 98,105c98,107 < default_fd_get_poll_events, /* get_poll_events */ < default_poll_event, /* poll_event */ < no_flush, /* flush */ < mailslot_get_fd_type, /* get_fd_type */ < default_fd_ioctl, /* ioctl */ < mailslot_queue_async, /* queue_async */ < default_fd_reselect_async, /* reselect_async */ < default_fd_cancel_async /* cancel_async */ --- > default_fd_get_poll_events, /* get_poll_events */ > default_poll_event, /* poll_event */ > no_flush, /* flush */ > mailslot_get_fd_type, /* get_fd_type */ > default_fd_removable, /* removable */ > default_fd_ioctl, /* ioctl */ > mailslot_queue_async, /* queue_async */ > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ > default_fd_cancel_async /* cancel_async */ 151a154 > default_fd_removable, /* removable */ 154c157,158 < default_fd_reselect_async, /* reselect_async */ --- > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ 201a206 > default_fd_removable, /* removable */ 204c209,210 < default_fd_reselect_async, /* reselect_async */ --- > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ diff -r a/server/mapping.c b/server/mapping.c 99a100 > default_fd_removable, /* removable */ 102c103,104 < default_fd_reselect_async, /* reselect_async */ --- > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ diff -r a/server/named_pipe.c b/server/named_pipe.c 170a171 > default_fd_removable, /* removable */ 173,174c174,176 < default_fd_reselect_async, /* reselect_async */ < default_fd_cancel_async, /* cancel_async */ --- > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ > default_fd_cancel_async /* cancel_async */ 210a213 > default_fd_removable, /* removable */ 213c216,217 < default_fd_reselect_async, /* reselect_async */ --- > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ 254a259 > default_fd_removable, /* removable */ 257c262,263 < default_fd_reselect_async, /* reselect_async */ --- > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ diff -r a/server/process.c b/server/process.c 93a94 > NULL, /* removable */ 96c97,98 < NULL, /* reselect_async */ --- > NULL, /* async_event */ > NULL, /* async_terminated */ diff -r a/server/protocol.def b/server/protocol.def 1020c1020 < int removable; /* is file removable? */ --- > int removable; /* is this fd removable? */ 1090a1091,1097 > /* Register an accept listener */ > @REQ(register_accept_async) > async_data_t data; /* async I/O parameters for listener */ > obj_handle_t ahandle; /* handle to the future accepting socket */ > @END > > diff -r a/server/queue.c b/server/queue.c 170a171 > NULL, /* removable */ 173c174,175 < NULL, /* reselect_async */ --- > NULL, /* async_event */ > NULL, /* async_terminated */ diff -r a/server/request.c b/server/request.c 112a113 > NULL, /* removable */ 115c116,117 < NULL, /* reselect_async */ --- > NULL, /* async_event */ > NULL, /* async_terminated */ diff -r a/server/request.h b/server/request.h 157a158 > DECL_HANDLER(register_accept_async); 404a406 > (req_handler)req_register_accept_async, 887a890,892 > C_ASSERT( FIELD_OFFSET(struct register_accept_async_request, data) == 16 ); > C_ASSERT( FIELD_OFFSET(struct register_accept_async_request, ahandle) == 56 ); > C_ASSERT( sizeof(struct register_accept_async_request) == 64 ); diff -r a/server/serial.c b/server/serial.c 111a112 > default_fd_removable, /* removable */ 114c115,116 < default_fd_reselect_async, /* reselect_async */ --- > default_fd_async_event, /* async_event */ > default_fd_async_terminated, /* async_terminated */ diff -r a/server/signal.c b/server/signal.c 89a90 > NULL, /* removable */ 92c93,94 < NULL, /* reselect_async */ --- > NULL, /* async_event */ > NULL, /* async_terminated */ diff -r a/server/sock.c b/server/sock.c 85a86,88 > struct async *async; /* pending accept to this socket */ > struct list accentry; /* entry in the list below for the request */ > struct list paccepts; /* pending accepts on this socket */ 97a101 > static int sock_removable( struct fd *fd ); 99c103,104 < static void sock_reselect_async( struct fd *fd, struct async_queue *queue ); --- > static void sock_async_event( struct fd *fd, struct async_queue *queue, struct async *async, int status, int finished ); > static int sock_async_terminated( struct fd *fd, struct async_queue *queue, struct async *async, int status ); 103a109 > static int accept_into_socket( struct sock *sock, struct sock *acceptsock ); 130a137 > sock_removable, /* removable */ 133c140,141 < sock_reselect_async, /* reselect_async */ --- > sock_async_event, /* async_event */ > sock_async_terminated, /* async_terminated */ 223c231 < if (!(sock->state & ~FD_WINE_NONBLOCKING)) return 0; --- > if (!(sock->state & ~(FD_WINE_NONBLOCKING|FD_WINE_ACCEPTING))) return 0; 298a307,313 > static inline void sock_free_accept_async( struct sock *acceptsock ) > { > list_remove( &acceptsock->accentry ); > acceptsock->state &= ~FD_WINE_ACCEPTING; > acceptsock->async = NULL; > } > 477c492 < return (sock->hmask & FD_ACCEPT) ? 0 : POLLIN; --- > return (!(sock->hmask & FD_ACCEPT) || async_waiting( sock->read_q )) ? POLLIN : 0; 492a508,516 > static int sock_removable( struct fd *fd ) > { > struct sock *sock = get_fd_user( fd ); > assert( sock->obj.ops == &sock_ops ); > > /* Don't cache SOCK_STREAM sockets until connected (needed for AcceptEx) */ > return sock->type == SOCK_STREAM && !sock->polling; > } > 534c558 < static void sock_reselect_async( struct fd *fd, struct async_queue *queue ) --- > static void sock_async_event( struct fd *fd, struct async_queue *queue, struct async *async, int status, int finished ) 537c561,578 < int events = sock_reselect( sock ); --- > int events; > struct sock *acceptsock, *next; > assert( sock->obj.ops == &sock_ops ); > > if ( finished ) > { > /* Clear pending accepts */ > LIST_FOR_EACH_ENTRY_SAFE( acceptsock, next, &sock->paccepts, struct sock, accentry ) > { > if ( acceptsock->async == async ) > { > sock_free_accept_async( acceptsock ); > break; > } > } > } > > events = sock_reselect( sock ); 538a580,612 > > } > > static int sock_async_terminated( struct fd *fd, struct async_queue *queue, struct async *async, int status) > { > struct sock *sock = get_fd_user( fd ); > struct sock *acceptsock; > assert( sock->obj.ops == &sock_ops ); > > if (status == STATUS_ALERTED) > { > LIST_FOR_EACH_ENTRY( acceptsock, &sock->paccepts, struct sock, accentry ) > { > if ( acceptsock->async == async ) > { > status = accept_into_socket( sock, acceptsock ); > > if (status != WSAEWOULDBLOCK) > sock_free_accept_async( acceptsock ); > > if (status == STATUS_SUCCESS) > { > sock_reselect( acceptsock ); > status = STATUS_ALERTED; > } > else if (status == WSAEWOULDBLOCK) > status = STATUS_PENDING; > break; > } > } > } > > return status; 561a636 > struct sock *acceptsock, *next; 567a643,652 > if ( sock->async ) > { > async_terminate( sock->async, STATUS_CANCELLED ); > sock_free_accept_async( sock ); > } > LIST_FOR_EACH_ENTRY_SAFE( acceptsock, next, &sock->paccepts, struct sock, accentry ) > { > /* No need to cancel, freeing queues does it */ > sock_free_accept_async( acceptsock ); > } 579a665,691 > static struct sock *alloc_sock(void) > { > struct sock *sock; > if (!(sock = alloc_object( &sock_ops ))) > return NULL; > > sock->state = 0; > sock->mask = 0; > sock->hmask = 0; > sock->pmask = 0; > sock->polling = 0; > sock->flags = 0; > sock->type = 0; > sock->family = 0; > sock->event = NULL; > sock->window = 0; > sock->message = 0; > sock->wparam = 0; > sock->deferred = NULL; > sock->async = NULL; > list_init( &sock->paccepts ); > sock->read_q = NULL; > sock->write_q = NULL; > > return sock; > } > 595c707 < if (!(sock = alloc_object( &sock_ops ))) --- > if (!(sock = alloc_sock())) 601,604d712 < sock->mask = 0; < sock->hmask = 0; < sock->pmask = 0; < sock->polling = 0; 608,614d715 < sock->event = NULL; < sock->window = 0; < sock->message = 0; < sock->wparam = 0; < sock->deferred = NULL; < sock->read_q = NULL; < sock->write_q = NULL; 625a727,799 > /* accepts a socket and inits it */ > static int accept_new_fd( struct sock *sock ) > { > > /* Try to accept(2). We can't be safe that this an already connected socket > * or that accept() is allowed on it. In those cases we will get -1/errno > * return. > */ > int acceptfd; > struct sockaddr saddr; > unsigned int slen = sizeof(saddr); > acceptfd = accept( get_unix_fd(sock->fd), &saddr, &slen); > if (acceptfd == -1) > return acceptfd; > > fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ > return acceptfd; > } > > static int accept_into_socket( struct sock *sock, struct sock *acceptsock ) > { > int acceptfd; > struct fd *oldfd; > if ( sock->deferred ) > { > acceptfd = dup( get_unix_fd(sock->deferred->fd) ); > if ( acceptfd == -1 ) > return sock_get_error(errno); > > /* Make sure we destroy fd first, so shutdown() isn't called */ > oldfd = sock->deferred->fd; > sock->deferred->fd = NULL; > release_object( sock->deferred ); > sock->deferred = NULL; > release_object( oldfd ); > } > else > { > if ((acceptfd = accept_new_fd( sock )) == -1) > return sock_get_error(errno); > } > > /* FIXME: need to copy sockopts from the old fd */ > if ( dup2( acceptfd, get_unix_fd(acceptsock->fd) ) == -1 ) > { > close(acceptfd); > return sock_get_error(errno); > } > close(acceptfd); > > /* FIXME: Move these into SO_UPDATE_ACCEPT_CONTEXT + validation */ > acceptsock->state |= FD_WINE_CONNECTED|FD_READ|FD_WRITE; > acceptsock->mask = sock->mask; > acceptsock->hmask = 0; > acceptsock->pmask = 0; > acceptsock->polling = 0; > acceptsock->type = sock->type; > acceptsock->family = sock->family; > acceptsock->window = sock->window; > acceptsock->message = sock->message; > acceptsock->wparam = 0; > if (acceptsock->event) release_object(acceptsock->event); > acceptsock->event = NULL; > if (sock->event) acceptsock->event = (struct event *)grab_object( sock->event ); > acceptsock->deferred = NULL; > > sock->pmask &= ~FD_ACCEPT; > sock->hmask &= ~FD_ACCEPT; > sock_reselect( sock ); > > return STATUS_SUCCESS; > } > 627c801 < static struct sock *accept_socket( obj_handle_t handle ) --- > static struct sock *accept_socket( struct sock *sock ) 630d803 < struct sock *sock; 632,636d804 < struct sockaddr saddr; < < sock = (struct sock *)get_handle_obj( current->process, handle, FILE_READ_DATA, &sock_ops ); < if (!sock) < return NULL; 645,652c813 < < /* Try to accept(2). We can't be safe that this an already connected socket < * or that accept() is allowed on it. In those cases we will get -1/errno < * return. < */ < unsigned int slen = sizeof(saddr); < acceptfd = accept( get_unix_fd(sock->fd), &saddr, &slen); < if (acceptfd==-1) --- > if ((acceptfd = accept_new_fd( sock )) == -1) 655d815 < release_object( sock ); 658c818,819 < if (!(acceptsock = alloc_object( &sock_ops ))) --- > > if (!(acceptsock = alloc_sock())) 661d821 < release_object( sock ); 666d825 < fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ 671,673d829 < acceptsock->hmask = 0; < acceptsock->pmask = 0; < acceptsock->polling = 0; 676d831 < acceptsock->event = NULL; 679d833 < acceptsock->wparam = 0; 681,684c835 < acceptsock->flags = sock->flags; < acceptsock->deferred = NULL; < acceptsock->read_q = NULL; < acceptsock->write_q = NULL; --- > acceptsock->flags = sock->flags; 689d839 < release_object( sock ); 697d846 < release_object( sock ); 790c939 < struct sock *sock; --- > struct sock *sock, *acceptsock; 793c942,946 < if ((sock = accept_socket( req->lhandle )) != NULL) --- > if (!(sock = (struct sock *)get_handle_obj( current->process, req->lhandle, > FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|FILE_READ_DATA, &sock_ops))) > return; > > if ((acceptsock = accept_socket( sock )) != NULL) 795,798c948,952 < reply->handle = alloc_handle( current->process, &sock->obj, req->access, req->attributes ); < sock->wparam = reply->handle; /* wparam for message is the socket handle */ < sock_reselect( sock ); < release_object( &sock->obj ); --- > reply->handle = alloc_handle( current->process, &acceptsock->obj, req->access, req->attributes ); > acceptsock->wparam = reply->handle; /* wparam for message is the socket handle */ > sock_reselect( acceptsock ); > > release_object( acceptsock ); 799a954 > release_object( sock ); 918a1074,1131 > > DECL_HANDLER(register_accept_async) > { > struct sock *sock, *acceptsock; > int pollev; > > sock = (struct sock *)get_handle_obj( current->process, req->data.handle, > FILE_READ_ATTRIBUTES, &sock_ops ); > if ( !sock ) > { > set_error( STATUS_OBJECT_TYPE_MISMATCH ); > return; > } > if ( !(sock->state & FD_WINE_LISTENING) ) > { > release_object( sock ); > set_error( STATUS_OBJECT_TYPE_MISMATCH ); > return; > } > > acceptsock = (struct sock *)get_handle_obj( current->process, req->ahandle, > FILE_WRITE_ATTRIBUTES, &sock_ops ); > if ( !acceptsock ) > { > release_object( sock ); > set_error( STATUS_INVALID_PARAMETER ); > return; > } > if ( acceptsock->state & ~FD_WINE_NONBLOCKING ) > { > release_object( acceptsock ); > release_object( sock ); > set_error( STATUS_INVALID_PARAMETER ); > return; > } > > if (!sock->read_q && !(sock->read_q = create_async_queue( sock->fd ))) return; > > acceptsock->async = create_async( current, sock->read_q, &req->data ); > if ( !acceptsock->async ) > { > release_object( acceptsock ); > release_object( sock ); > return; > } > > list_add_tail( &sock->paccepts, &acceptsock->accentry ); > acceptsock->state |= FD_WINE_ACCEPTING; > release_object( acceptsock->async ); > > pollev = sock_reselect( sock ); > if ( pollev ) sock_try_event( sock, pollev ); > > set_error( STATUS_PENDING ); > > release_object( acceptsock ); > release_object( sock ); > } diff -r a/server/thread.c b/server/thread.c 157a158 > NULL, /* removable */ 160c161,162 < NULL, /* reselect_async */ --- > NULL, /* async_event */ > NULL, /* async_terminated */ diff -r a/server/trace.c b/server/trace.c 1542a1543,1548 > static void dump_register_accept_async_request( const struct register_accept_async_request *req ) > { > dump_async_data( " data=", &req->data ); > fprintf( stderr, ", ahandle=%04x", req->ahandle ); > } > 3853a3860 > (dump_func)dump_register_accept_async_request, 4098a4106 > NULL, 4341a4350 > "register_accept_async",