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.
--
Martin Wilck Phone: +49 5251 8 15113
Fujitsu Siemens Computers Fax: +49 5251 8 20409
Heinz-Nixdorf-Ring 1 mailto:Martin.Wilck@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 */
+@REQ(set_socket_flags)
+ handle_t handle; /* handle to the socket */
+ unsigned int flags; /* Winsock2 flags */
+@END
+
+/* Get Winsock2 flags */
+@REQ(get_socket_flags)
+ handle_t handle; /* handle to the socket */
+@REPLY
+ unsigned int flags; /* Winsock2 flags */
+@END
+
+/* Get deferred socket to be accept()ed later, for WSAAccept() */
+@REQ(get_socket_deferred)
+ handle_t handle; /* handle to the socket */
+@REPLY
+ handle_t deferred; /* deferred socket */
+@END
+
+/* Set deferred socket to be accept()ed later, for WSAAccept() */
+@REQ(set_socket_deferred)
+ handle_t handle; /* handle to the socket */
+ handle_t deferred; /* deferred socket */
+@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;
+}
+