From 3479c59750ee16303d1190a05bf42577a14b4027 Mon Sep 17 00:00:00 2001 From: Scott Lindeneau Date: Thu, 21 Aug 2008 05:30:25 +0900 Subject: [PATCH] Forwards and implements AcceptEx and GetAcceptExaddrs. AcceptEx is only 'partially' implemented to simplify its implementation. It never returns true, but it doesn't need to return true, so we don't have to impelment that functionality. AcceptEx does not impelement dest_length yet. This only affects programs that expect AcceptEx to recieve data. socket.c: implements WS2_async_accept as the callback function for acceptex. This function calls the accept once a connection can be established. --- dlls/mswsock/mswsock.spec | 4 +- dlls/ws2_32/socket.c | 250 +++++++++++++++++++++++++++++++++++++++++++++ dlls/ws2_32/ws2_32.spec | 2 + 3 files changed, 254 insertions(+), 2 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) -- 1.5.4.3