From 9f5fb9b8fe1285acac56dcbabff604740823cf37 Mon Sep 17 00:00:00 2001 From: Scott Lindeneau Date: Mon, 4 Aug 2008 16:15:13 +0900 Subject: [PATCH] mswsock: Impelements AcceptEx and GetAcceptExSockaddrs in the ws2_32. --- dlls/mswsock/mswsock.spec | 4 +- dlls/ws2_32/socket.c | 250 ++++++++++++++++++++++++++++++++++++++++ dlls/ws2_32/ws2_32.spec | 2 + include/wine/server_protocol.h | 2 +- 4 files changed, 255 insertions(+), 3 deletions(-) diff --git a/dlls/mswsock/mswsock.spec b/dlls/mswsock/mswsock.spec index 521b3a4..d49f8b2 100644 --- a/dlls/mswsock/mswsock.spec +++ b/dlls/mswsock/mswsock.spec @@ -1,7 +1,7 @@ -@ stdcall AcceptEx(long long ptr long long long ptr ptr) +@ stdcall AcceptEx(long long ptr long long long ptr ptr) ws2_32.AcceptEx @ stdcall EnumProtocolsA(ptr ptr ptr) ws2_32.WSAEnumProtocolsA @ stdcall EnumProtocolsW(ptr ptr ptr) ws2_32.WSAEnumProtocolsW -@ stdcall GetAcceptExSockaddrs(ptr long long long ptr ptr ptr ptr) +@ stdcall GetAcceptExSockaddrs(ptr long long long ptr ptr ptr ptr) ws2_32.GetAcceptExSockaddrs @ stub GetAddressByNameA @ stub GetAddressByNameW @ stub GetNameByTypeA diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 451de49..e86ee88 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -194,6 +194,15 @@ typedef struct ws2_async { int val; /* for send operations */ int *ptr; /* for recv operations */ + struct /* for accept operation */ + { + SOCKET s_accept; /* socket to use as connection socket */ + PVOID buf; /* buffer to write data to */ + int data_len; + int local_len; + int remote_len; + DWORD *recvd; + } acpt; } addrlen; DWORD flags; } ws2_async; @@ -236,6 +245,8 @@ static FARPROC blocking_hook = (FARPROC)WSA_DefaultBlockingHook; static struct WS_hostent *WS_dup_he(const struct hostent* p_he); static struct WS_protoent *WS_dup_pe(const struct protoent* p_pe); static struct WS_servent *WS_dup_se(const struct servent* p_se); +static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS CompletionStatus, ULONG_PTR Information ); + int WSAIOCTL_GetInterfaceCount(void); int WSAIOCTL_GetInterfaceName(int intNumber, char *intName); @@ -1065,6 +1076,245 @@ static void WINAPI ws2_async_apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserv wsa->flags ); HeapFree( GetProcessHeap(), 0, wsa ); } +/*********************************************************************** + * WS2_acceptex_data (INTERNAL) + * + * This function is used to place the ipaddresses in the buffer. + */ +static void WS2_acceptex_data( char* buf, int local_len, int remote_len, int data_len, SOCKET s ) +{ + int len; + buf = buf+data_len; + len = local_len - sizeof(int); + WS_getpeername(s,(struct WS_sockaddr*)(buf+sizeof(int)),&len); + *(int*)buf = len; + buf += local_len; + len = remote_len - sizeof(int); + WS_getsockname(s,(struct WS_sockaddr*)(buf+sizeof(int)),&len); + *(int*)buf = len; +} +/*********************************************************************** + * 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 ) +{ + ws2_async *wsa = arg; + char *buf; + if(status != STATUS_ALERTED){ + if(status != STATUS_HANDLES_CLOSED) + FIXME("Unexpected/Unhandeled status Message= %x \n",status); + } + TRACE("status Message= %x listen: %lx, accept: %lx\n",status, HANDLE2SOCKET(wsa->hSocket),wsa->addrlen.acpt.s_accept); + if(status == STATUS_HANDLES_CLOSED){ + wsa->user_overlapped->Internal = status; + wsa->user_overlapped->InternalHigh = 0; + iosb->u.Status = status; + iosb->Information = 0; + return status; + } + SERVER_START_REQ( accept_socket ) + { + req->lhandle = wsa->hSocket; + req->ahandle = SOCKET2HANDLE(wsa->addrlen.acpt.s_accept); + req->access = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE; + req->attributes = OBJ_INHERIT; + status = wine_server_call( req ); + } + SERVER_END_REQ; + if(status != STATUS_SUCCESS){ + FIXME("error in getting socket. socket: %lx, status: %x\n",wsa->addrlen.acpt.s_accept,status); + wsa->user_overlapped->Internal = status; + wsa->user_overlapped->InternalHigh = 0; + iosb->u.Status = status; + iosb->Information = 0; + return status; + } + /*We now have a connected socket. pull data in/write info to buffer*/ + buf = (char*)wsa->addrlen.acpt.buf; + WS2_acceptex_data( buf, wsa->addrlen.acpt.local_len, wsa->addrlen.acpt.remote_len,wsa->addrlen.acpt.data_len, wsa->addrlen.acpt.s_accept ); + /*socket address information is written. next pull in data.*/ + /*we don't pull in data yet... */ + wsa->addrlen.acpt.recvd = 0; + wsa->user_overlapped->Internal = status; + wsa->user_overlapped->InternalHigh = 0; + iosb->u.Status = status; + iosb->Information = 0; + + HeapFree( GetProcessHeap(), 0, wsa ); + return status; + +} + +/*********************************************************************** + * 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 (We always return false because its simple) + * 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_async *wsa; + IO_STATUS_BLOCK *iosb; + char *buf = (char*) dest; + TRACE("listen: %lx, accept: %lx\n",listener,acceptor); + if(overlapped == NULL){ + set_error(STATUS_INVALID_PARAMETER); + return FALSE; + } + if(dest_len !=0){ + FIXME("AcceptEx does not support reciving data yet\n"); + dest_len = 0; + } + + SERVER_START_REQ( accept_socket ) + { + req->lhandle = SOCKET2HANDLE(listener); + req->ahandle = SOCKET2HANDLE(acceptor); + req->access = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE; + req->attributes = OBJ_INHERIT; + status = wine_server_call( req ); + } + SERVER_END_REQ; + + if (STATUS_SUCCESS == status) + { + buf = buf+dest_len; + WS2_acceptex_data( buf, local_addr_len, rem_addr_len, dest_len, acceptor ); + *received = 0; + overlapped->Internal = status; + overlapped->InternalHigh = 0; + WS_AddCompletion( listener , (ULONG_PTR)overlapped, STATUS_SUCCESS, 0); + set_error(STATUS_PENDING); + return FALSE; + } + + wsa = HeapAlloc( GetProcessHeap(), 0, sizeof(*wsa) ); + iosb = HeapAlloc( GetProcessHeap(), 0, sizeof(*iosb) ); + if(!wsa || !iosb){ + set_error(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + + /*Setup the internal data structures!*/ + overlapped->Internal = STATUS_PENDING; + overlapped->InternalHigh = 0; + /*Do we need the following? Maybe...*/ + iosb = &wsa->local_iosb; + iosb->u.Status = STATUS_PENDING; + iosb->Information = 0; + + + wsa->hSocket = SOCKET2HANDLE(listener); + wsa->flags = 0; + wsa->user_overlapped = overlapped; + wsa->addrlen.acpt.s_accept = acceptor; + wsa->addrlen.acpt.buf = dest; + wsa->addrlen.acpt.data_len = dest_len; + wsa->addrlen.acpt.local_len = local_addr_len; + wsa->addrlen.acpt.remote_len = rem_addr_len; + wsa->addrlen.acpt.recvd = received; + + SERVER_START_REQ( set_socket_listener ) + { + req->handle = SOCKET2HANDLE(acceptor); + req->hListen = SOCKET2HANDLE(listener); + status = wine_server_call( req ); + } + SERVER_END_REQ; + if(status != STATUS_SUCCESS){ + FIXME("error setting socket listener\n"); + } + + SERVER_START_REQ( register_async_l ) + { + req->handle = wsa->hSocket; + req->type = ASYNC_TYPE_READ; + req->locator = SOCKET2HANDLE(acceptor); + req->async.callback = WS2_async_accept; + req->async.iosb = iosb; + req->async.arg = wsa; + req->async.apc = NULL; + req->async.event = overlapped->hEvent; + req->async.cvalue = (ULONG_PTR)overlapped; + status = wine_server_call( req ); + } + SERVER_END_REQ; + + if(status != STATUS_PENDING){ + HeapFree( GetProcessHeap(), 0, wsa ); + HeapFree( GetProcessHeap(), 0, iosb ); + 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) +{ + int len; + char *buf = _buf; + + TRACE("buf=%p, data_size=%d, local_size=%d, remote_size=%d, local_addr=%p (%p), remote_addr=%p (%p)\n", buf, data_size, local_size, remote_size, + local_addr, local_addr_len, remote_addr, remote_addr_len ); + + buf += data_size; + if (local_size) + { + len = *(int*)buf; + *local_addr_len = len; + *local_addr = (struct sockaddr*)(buf+sizeof(int)); + buf += local_size; + TRACE("local %d bytes to %p\n", len, local_addr); + } + else + *local_addr_len = 0; + if (remote_size) + { + len = *(int*)buf; + *remote_addr_len = len; + *remote_addr = (struct sockaddr*)(buf+sizeof(int)); + TRACE("remote %d bytes to %p\n", len, remote_addr); + } + else + *remote_addr_len = 0; +} /*********************************************************************** * WS2_recv (INTERNAL) diff --git a/dlls/ws2_32/ws2_32.spec b/dlls/ws2_32/ws2_32.spec index bbcafc0..5a0a3cf 100644 --- a/dlls/ws2_32/ws2_32.spec +++ b/dlls/ws2_32/ws2_32.spec @@ -117,3 +117,5 @@ @ stdcall freeaddrinfo(ptr) WS_freeaddrinfo @ stdcall getaddrinfo(str str ptr ptr) WS_getaddrinfo @ stdcall getnameinfo(ptr long ptr long ptr long long) WS_getnameinfo +@ stdcall AcceptEx(long long ptr long long long ptr ptr) +@ stdcall GetAcceptExSockaddrs(ptr long long long ptr ptr ptr ptr) diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index c23a3f4..7c43862 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -5011,6 +5011,6 @@ union generic_reply struct add_fd_completion_reply add_fd_completion_reply; }; -#define SERVER_PROTOCOL_VERSION 349 +#define SERVER_PROTOCOL_VERSION 350 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ -- 1.5.4.3