Hi, this patch tries to implement a small part of the extended Winsock 2 functionality in Wine. It is very experimental, I have only made sure everything compiles. It is _NOT_ intended for people to try and run. I am submitting this patch because I am pretty new to Wine hacking and I'd appreciate some Wine gurus to audit this for obvious stupidity, style incompatiblities, etc. Features implemented: - WSAAccept(), including callback functionality. - WSASocket(): support for dwFlags parameter. The real difficult stuff will follow when I start looking into WSARecv(), WSASend(), and WSAGetOverlappedResults(). Thus it'd be nice if someone pointed out my misconceptions before I put real work into the latter. Thanks & regards, Martin -- Martin Wilck Phone: +49 5251 8 15113 Fujitsu Siemens Computers Fax: +49 5251 8 20409 Heinz-Nixdorf-Ring 1 mailto:Martin.Wilck(a)Fujitsu-Siemens.com D-33106 Paderborn http://www.fujitsu-siemens.com/primergy Index: dlls/winsock/socket.c =================================================================== RCS file: /home/wine/wine/dlls/winsock/socket.c,v retrieving revision 1.65 diff -u -r1.65 socket.c --- dlls/winsock/socket.c 2001/10/14 16:25:47 1.65 +++ dlls/winsock/socket.c 2001/11/07 16:36:53 @@ -154,6 +154,7 @@ int WS_dup_pe(struct protoent* p_pe, int flag); int WS_dup_se(struct servent* p_se, int flag); int WINAPI WSOCK32_getpeername(SOCKET s, ws_sockaddr *name, int *namelen); +int WINAPI WSOCK32_getsockname(SOCKET s, ws_sockaddr *name, int *namelen); typedef void WIN_hostent; typedef void WIN_protoent; @@ -938,6 +939,131 @@ } /*********************************************************************** + * WSAAccept (WS2_32.26) + */ +SOCKET WINAPI WSAAccept(SOCKET s, + ws_sockaddr* addr, + LPINT addrlen32, + LPCONDITIONPROC cond_cb, + DWORD cb_data ) +{ + + /* Code copied largely from WSOCK32_accept() */ + /* FIXME: Can we simply call WSOCK32_accept() instead ? */ + /* I wasn't sure because of the AsyncSelect stuff at the end, + which presumably should only be called if the connection is accepted */ + + SOCKET as; + int fd = _get_sock_fd(s); + unsigned omask; + + TRACE("%04x cond=%08x data=%08x\n", (UINT16) s, (UINT) cond_cb, (UINT) cb_data); + + if (fd == -1) + { + SetLastError(WSAENOTSOCK); + return INVALID_SOCKET; + } + + if (_is_blocking(s)) + { + /* block here */ + do_block(fd, 5); + _sync_sock_state(s); /* let wineserver notice connection */ + /* retrieve any error codes from it */ + SetLastError(_get_sock_error(s, FD_ACCEPT_BIT)); + /* FIXME: care about the error? */ + } + + close(fd); + + SERVER_START_REQ( accept_socket ) + { + req->lhandle = s; + req->access = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE; + req->inherit = TRUE; + set_error( SERVER_CALL() ); + as = (SOCKET)req->handle; + } + SERVER_END_REQ; + + if (!as) + { + SetLastError(WSAENOTSOCK); + return INVALID_SOCKET; + } + + if (cond_cb) + { + /* We need our own buffers for Caller and Callee addresses. */ + /* FIXME: large enough / too large ? */ + const int SOCKADDR_LEN=128; + INT caller_len = SOCKADDR_LEN, callee_len = SOCKADDR_LEN; + char _caller_addr[SOCKADDR_LEN], _callee_addr[SOCKADDR_LEN]; + ws_sockaddr *caller_addr = (ws_sockaddr*) _caller_addr; + ws_sockaddr *callee_addr = (ws_sockaddr*) _callee_addr; + WSABUF caller_buf = { 0, _caller_addr }; + WSABUF callee_buf = { 0, _callee_addr }; + WSABUF callee_data_buf = { 0, NULL }; + GROUP group = 0; + int cb_result; + + WSOCK32_getpeername (as, caller_addr, &caller_len); + WSOCK32_getsockname (as, callee_addr, &callee_len); + caller_buf.len = caller_len; + callee_buf.len = callee_len; + + TRACE ("Calling callback\n"); + cb_result = cond_cb (&caller_buf, /* Caller ID */ + NULL, /* Caller data unsupported */ + NULL, NULL, /* QOS unsupported */ + &callee_buf, /* Callee id */ + &callee_data_buf, /* Callee data unsupported */ + &group, /* Group unsupported */ + cb_data); + + switch (cb_result) + { + case CF_ACCEPT: + TRACE ("Connection accepted\n"); + break; + case CF_REJECT: + closesocket (as); + TRACE ("Connection refused\n"); + SetLastError (WSAECONNREFUSED); + return INVALID_SOCKET; + case CF_DEFER: + TRACE ("Connection deferred\n"); + SERVER_START_REQ (set_socket_deferred) + { + req->handle = s; + req->deferred = as; + SERVER_CALL (); + } + SERVER_END_REQ; + SetLastError (WSATRY_AGAIN); + return INVALID_SOCKET; + default: + WARN ("Invalid return value\n"); + SetLastError (WSAEINVAL); + return INVALID_SOCKET; + } + + if (addrlen32 && addr && *addrlen32 >= caller_len) + memcpy (addr, caller_addr, caller_len); + + } else + WSOCK32_getpeername (as, addr, addrlen32); + + omask = _get_sock_mask( s ); + if (omask & FD_WINE_SERVEVENT) + ws2_async_accept(s, as); + + return as; +} + + +/*********************************************************************** * bind (WS2_32.2) */ int WINAPI WSOCK32_bind(SOCKET s, const ws_sockaddr* name, int namelen) @@ -1016,7 +1142,21 @@ */ INT WINAPI WSOCK32_closesocket(SOCKET s) { + SOCKET deferred; TRACE("socket %08x\n", s); + + /* Close a deferred socket if present */ + SERVER_START_REQ ( get_socket_deferred ) + { + req->handle = s; + SERVER_CALL (); + deferred = req->deferred; + } + SERVER_END_REQ; + + if (deferred) + WSOCK32_closesocket (deferred); + if (CloseHandle(s)) return 0; return SOCKET_ERROR; } @@ -2898,10 +3038,24 @@ g, dwFlags) are ignored. */ - TRACE("af=%d type=%d protocol=%d protocol_info=%p group=%d flags=0x%lx\n", + SOCKET s; + + TRACE("af=%d type=%d protocol=%d protocol_info=%p group=%d flags=0x%lx\n", af, type, protocol, lpProtocolInfo, g, dwFlags ); - return ( WSOCK32_socket (af, type, protocol) ); + s = WSOCK32_socket (af, type, protocol); + + if (dwFlags && s != INVALID_SOCKET) + { + SERVER_START_REQ ( set_socket_flags ) + { + req->handle = s; + req->flags = dwFlags; + SERVER_CALL(); + } + SERVER_END_REQ; + } + return s; } Index: dlls/winsock/ws2_32.spec =================================================================== RCS file: /home/wine/wine/dlls/winsock/ws2_32.spec,v retrieving revision 1.13 diff -u -r1.13 ws2_32.spec --- dlls/winsock/ws2_32.spec 2001/10/02 17:46:59 1.13 +++ dlls/winsock/ws2_32.spec 2001/11/07 16:36:53 @@ -38,7 +38,7 @@ 23 stdcall socket(long long long) WSOCK32_socket 24 stdcall WSApSetPostRoutine(ptr) WSApSetPostRoutine 25 stub WPUCompleteOverlappedRequest -26 stub WSAAccept +26 stdcall WSAAccept(long ptr ptr ptr long) WSAAccept 27 stub WSAAddressToStringA 28 stub WSAAddressToStringW 29 stdcall WSACloseEvent(long) WSACloseEvent Index: include/winsock2.h =================================================================== RCS file: /home/wine/wine/include/winsock2.h,v retrieving revision 1.10 diff -u -r1.10 winsock2.h --- include/winsock2.h 2001/10/02 17:46:59 1.10 +++ include/winsock2.h 2001/11/07 16:36:54 @@ -225,10 +225,44 @@ CHAR* buf; } WSABUF, *LPWSABUF; -typedef struct _OVERLAPPED * LPWSAOVERLAPPED; typedef HANDLE WSAEVENT; + +typedef struct _WSAOVERLAPPED { + DWORD Internal; + DWORD InternalHigh; + DWORD Offset; + DWORD OffsetHigh; + WSAEVENT hEvent; +} WSAOVERLAPPED, *LPWSAOVERLAPPED; + +#define WSA_IO_PENDING (WSAEWOULDBLOCK) +#define WSA_IO_INCOMPLETE (WSAEWOULDBLOCK) +#define WSA_INVALID_HANDLE (WSAENOTSOCK) +#define WSA_INVALID_PARAMETER (WSAEINVAL) +#define WSA_NOT_ENOUGH_MEMORY (WSAENOBUFS) +#define WSA_OPERATION_ABORTED (WSAEINTR) + +#define WSA_INVALID_EVENT ((WSAEVENT)NULL) +#define WSA_MAXIMUM_WAIT_EVENTS (MAXIMUM_WAIT_OBJECTS) +#define WSA_WAIT_FAILED ((DWORD)-1L) +#define WSA_WAIT_EVENT_0 ((DWORD)0) +#define WSA_WAIT_TIMEOUT ((DWORD)0x102L) +#define WSA_INFINITE ((DWORD)-1L) + +/* + * WinSock 2 extension -- manifest constants for WSASocket() + */ +#define WSA_FLAG_OVERLAPPED 0x01 +#define WSA_FLAG_MULTIPOINT_C_ROOT 0x02 +#define WSA_FLAG_MULTIPOINT_C_LEAF 0x04 +#define WSA_FLAG_MULTIPOINT_D_ROOT 0x08 +#define WSA_FLAG_MULTIPOINT_D_LEAF 0x10 + typedef unsigned int GROUP; +/* FIXME: We don't support QOS */ +typedef DWORD QOS, *LPQOS; + typedef void CALLBACK (*LPWSAOVERLAPPED_COMPLETION_ROUTINE) ( DWORD dwError, @@ -237,7 +271,27 @@ DWORD dwFlags ); +/* + * WinSock 2 extension -- manifest constants for return values of the condition function + */ +#define CF_ACCEPT 0x0000 +#define CF_REJECT 0x0001 +#define CF_DEFER 0x0002 +/* FIXME: The lpCallerData / lpCalleeData arguments are unsupported */ +typedef int CALLBACK (*LPCONDITIONPROC) +( + LPWSABUF lpCallerId, + LPWSABUF lpCallerData, + LPQOS lpSQOS, + LPQOS lpGQOS, + LPWSABUF lpCalleeId, + LPWSABUF lpCalleeData, + GROUP *g, + DWORD dwCallbackData +); + + /* Function declarations */ int WINAPI WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEventObject, LPWSANETWORKEVENTS lpNetworkEvents); int WINAPI WSAEventSelect(SOCKET s, WSAEVENT hEventObject, long lNetworkEvents); @@ -251,6 +305,9 @@ LPWSAPROTOCOL_INFOA lpProtocolInfo, GROUP g, DWORD dwFlags); INT WINAPI ioctlsocket(SOCKET s, LONG cmd, ULONG *argp); + +/* FIXME: omitted the deviating WIN64 declaration */ +SOCKET WINAPI WSAAccept(SOCKET,ws_sockaddr*,LPINT,LPCONDITIONPROC,DWORD); #include "poppack.h" Index: server/protocol.def =================================================================== RCS file: /home/wine/wine/server/protocol.def,v retrieving revision 1.16 diff -u -r1.16 protocol.def --- server/protocol.def 2001/10/24 00:23:26 1.16 +++ server/protocol.def 2001/11/07 16:36:55 @@ -661,6 +661,31 @@ handle_t event; /* event object */ @END +/* Set Winsock2 flags */ +(a)REQ(set_socket_flags) + handle_t handle; /* handle to the socket */ + unsigned int flags; /* Winsock2 flags */ +(a)END + +/* Get Winsock2 flags */ +(a)REQ(get_socket_flags) + handle_t handle; /* handle to the socket */ +(a)REPLY + unsigned int flags; /* Winsock2 flags */ +(a)END + +/* Get deferred socket to be accept()ed later, for WSAAccept() */ +(a)REQ(get_socket_deferred) + handle_t handle; /* handle to the socket */ +(a)REPLY + handle_t deferred; /* deferred socket */ +(a)END + +/* Set deferred socket to be accept()ed later, for WSAAccept() */ +(a)REQ(set_socket_deferred) + handle_t handle; /* handle to the socket */ + handle_t deferred; /* deferred socket */ +(a)END /* Get socket event parameters */ @REQ(get_socket_event) Index: server/sock.c =================================================================== RCS file: /home/wine/wine/server/sock.c,v retrieving revision 1.21 diff -u -r1.21 sock.c --- server/sock.c 2001/10/05 19:45:45 1.21 +++ server/sock.c 2001/11/07 16:36:55 @@ -47,6 +47,8 @@ unsigned int pmask; /* pending events */ struct event *event; /* event object */ int errors[FD_MAX_EVENTS]; /* event errors */ + unsigned int flags; /* Winsock 2 socket flags */ + handle_t deferred; /* deferred socket to be accept()ed later */ }; static void sock_dump( struct object *obj, int verbose ); @@ -324,6 +326,8 @@ sock->hmask = 0; sock->pmask = 0; sock->event = NULL; + sock->flags = 0; + sock->deferred = 0; sock_reselect( sock ); clear_error(); return &sock->obj; @@ -342,36 +346,51 @@ GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops); if (!sock) return NULL; - /* 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. - */ - slen = sizeof(saddr); - acceptfd = accept(sock->obj.fd,&saddr,&slen); - if (acceptfd==-1) { - sock_set_error(); - release_object( sock ); - return NULL; - } - if (!(acceptsock = alloc_object( &sock_ops, -1 ))) - { - release_object( sock ); - return NULL; + + if (sock->deferred) { + + /* If a previous WSAAccept() deferred accepting this request, try it again. */ + /* We do this no matter if called through accept() or WSAAccept(), */ + /* because this is the way Windows does it, too. */ + + acceptsock = (struct sock*)get_handle_obj(current->process,sock->deferred, + GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops); + sock->deferred = 0; + } else { + /* 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. + */ + slen = sizeof(saddr); + acceptfd = accept(sock->obj.fd,&saddr,&slen); + if (acceptfd==-1) { + sock_set_error(); + release_object( sock ); + return NULL; + } + if (!(acceptsock = alloc_object( &sock_ops, -1 ))) + { + release_object( sock ); + return NULL; + } + + /* newly created socket gets the same properties of the listening socket */ + fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ + acceptsock->obj.fd = acceptfd; + acceptsock->state = FD_WINE_CONNECTED|FD_READ|FD_WRITE; + if (sock->state & FD_WINE_NONBLOCKING) + acceptsock->state |= FD_WINE_NONBLOCKING; + acceptsock->mask = sock->mask; + acceptsock->hmask = 0; + acceptsock->pmask = 0; + acceptsock->event = NULL; + acceptsock->flags = sock->flags; + acceptsock->deferred = 0; } - /* newly created socket gets the same properties of the listening socket */ - fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ - acceptsock->obj.fd = acceptfd; - acceptsock->state = FD_WINE_CONNECTED|FD_READ|FD_WRITE; - if (sock->state & FD_WINE_NONBLOCKING) - acceptsock->state |= FD_WINE_NONBLOCKING; - acceptsock->mask = sock->mask; - acceptsock->hmask = 0; - acceptsock->pmask = 0; - acceptsock->event = NULL; if (sock->event && !(sock->mask & FD_WINE_SERVEVENT)) - acceptsock->event = (struct event *)grab_object( sock->event ); - + acceptsock->event = (struct event *)grab_object( sock->event ); + sock_reselect( acceptsock ); clear_error(); sock->pmask &= ~FD_ACCEPT; @@ -589,3 +608,37 @@ release_object( &sock->obj ); } +DECL_HANDLER(get_socket_deferred) +{ + struct sock *sock; + + sock=(struct sock*)get_handle_obj(current->process,req->handle,GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops); + req->deferred = sock->deferred; +} + +DECL_HANDLER(set_socket_deferred) +{ + struct sock *sock; + + sock=(struct sock*)get_handle_obj(current->process,req->handle,GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops); + + sock->deferred = req->deferred; + release_object (&sock->obj); +} + +DECL_HANDLER(get_socket_flags) +{ + struct sock *sock; + + sock=(struct sock*)get_handle_obj(current->process,req->handle,GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops); + req->flags = sock->flags; +} + +DECL_HANDLER(set_socket_flags) +{ + struct sock *sock; + + sock=(struct sock*)get_handle_obj(current->process,req->handle,GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops); + sock->flags = req->flags; +} +
On Wed, 7 Nov 2001, Martin Wilck wrote:
Hi,
this patch tries to implement a small part of the extended Winsock 2 functionality in Wine. It is very experimental, I have only made sure everything compiles. It is _NOT_ intended for people to try and run.
I am submitting this patch because I am pretty new to Wine hacking and I'd appreciate some Wine gurus to audit this for obvious stupidity, style incompatiblities, etc.
Features implemented: - WSAAccept(), including callback functionality. - WSASocket(): support for dwFlags parameter.
The real difficult stuff will follow when I start looking into WSARecv(), WSASend(), and WSAGetOverlappedResults().
Thus it'd be nice if someone pointed out my misconceptions before I put real work into the latter.
I will leave it to someone else to comment on the meat of the matter but still, here are a couple of comments: * To answer your question: /* Code copied largely from WSOCK32_accept() */ /* FIXME: Can we simply call WSOCK32_accept() instead ? */ /* I wasn't sure because of the AsyncSelect stuff at the end, which presumably should only be called if the connection is accepted */ Winsock2 should not call the wsock32 library. It should be the opposite. One of the things on my todo list (but whether I will have time to actually do it is another matter) is to reorganize the winsock libraries so that wsock32 and winsock are together in dlls/wsock32. The reason is that they both implement the winsock1 API except one is 16bit and the other 32bits. Then in dlls/winsock we would be left with just ws2_32 which implements the winsock2 API. So having ws2_32 call to wsock32 is not going in the right direction :-) * I am currently working on a big reorganization of the winsock headers (I'm a bit late in resubmitting my patches but I will resubmit them) so there is going to be a clash with 'winsock2.h'. But don't worry about it too much. I will try to integrate all the changes in your current patch in my version before submitting it. Then you will only have to take care of any later additions. * Also, to give you a heads up, the prefix for all functions will switch from 'WSOCK32_' to 'WS_'. Well, it's not that hard to deal with. * I don't think you need to specify which structures/fields are unsupported in the header file. After all they could be unsupported in one function and supported in another. I see that you also put this info in the relevant functions so it should be enough. Looks good to me. Welcome to the Wine project. It's always good to have some new blood. -- Francois Gouget fgouget(a)free.fr http://fgouget.free.fr/ The software said it requires Win95 or better, so I installed Linux.
On Wed, Nov 07, 2001 at 10:54:02AM -0800, Francois Gouget wrote:
* To answer your question: /* Code copied largely from WSOCK32_accept() */ /* FIXME: Can we simply call WSOCK32_accept() instead ? */ /* I wasn't sure because of the AsyncSelect stuff at the end, which presumably should only be called if the connection is accepted */
Winsock2 should not call the wsock32 library. It should be the opposite. One of the things on my todo list (but whether I will have time to actually do it is another matter) is to reorganize the winsock libraries so that wsock32 and winsock are together in dlls/wsock32. The reason is that they both implement the winsock1 API except one is 16bit and the other 32bits. Then in dlls/winsock we would be left with just ws2_32 which implements the winsock2 API. So having ws2_32 call to wsock32 is not going in the right direction :-) Hmm ? Sorry, but this directory stuff sounds rather dainbread to me. IMHO winsock/wsock32 should be in winsock/, and ws2_32 should be in winsock2/ Or, maybe even better, use winsock1/ instead of winsock/.
WTH would you want to do it in a different way ? -- Andreas Mohr Stauferstr. 6, D-71272 Renningen, Germany Tel. +49 7159 800604 http://home.nexgo.de/andi.mohr/
On Wed, 7 Nov 2001, Andreas Mohr wrote:
On Wed, Nov 07, 2001 at 10:54:02AM -0800, Francois Gouget wrote:
* To answer your question: /* Code copied largely from WSOCK32_accept() */ /* FIXME: Can we simply call WSOCK32_accept() instead ? */ /* I wasn't sure because of the AsyncSelect stuff at the end, which presumably should only be called if the connection is accepted */
Winsock2 should not call the wsock32 library. It should be the opposite. One of the things on my todo list (but whether I will have time to actually do it is another matter) is to reorganize the winsock libraries so that wsock32 and winsock are together in dlls/wsock32. The reason is that they both implement the winsock1 API except one is 16bit and the other 32bits. Then in dlls/winsock we would be left with just ws2_32 which implements the winsock2 API. So having ws2_32 call to wsock32 is not going in the right direction :-) Hmm ? Sorry, but this directory stuff sounds rather dainbread to me. IMHO winsock/wsock32 should be in winsock/, and ws2_32 should be in winsock2/ Or, maybe even better, use winsock1/ instead of winsock/.
WTH would you want to do it in a different way ?
I actually don't care about the directories or their names. Here are the goals: * implement the two libraries dealing with version 1 of the API as a dll pair. Currently the 16bit implementation is in dlls/winsock while the 32bit implementation of that API is in dlls/wsock32. That does not seem logical. * remove all the 16bit aspects from the library implementing the version 2 of the API, i.e. ws2_32. ws2_32 does not have a 16bit version so it should not have to bother with 16bit stuff. This would also simplify the code of ws2_32. * make ws2_32 independent from the other winsock implementations, i.e. it should not call wsock32. I believe this is already the case... except that it is mixed up with the 16bit library. * implement the version 1 API by using ws2_32 whenever possible to avoid code duplication. As far as directory names are concerned, libwsock32.so is implemented in a directory called 'dlls/wsock32'. That seems logical to me. The library 'libws2_32.so' is implemented in a directory called 'dlls/winsock'. If we try to name the directories after the name of the 'main' library, 'dlls/ws2_32' may be better. But it is not going to be a huge Wine architectural gain :-) -- Francois Gouget fgouget(a)free.fr http://fgouget.free.fr/ Broadcast message : fin du monde dans cinq minutes, repentez vous !
participants (3)
-
Andreas Mohr -
Francois Gouget -
Martin Wilck