[EXPERIMENTAL PATCH]: Winsock2

Martin Wilck Martin.Wilck at fujitsu-siemens.com
Wed Nov 7 12:17:02 CST 2001


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 at 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 */
+ at REQ(set_socket_flags)
+    handle_t     handle;        /* handle to the socket */
+    unsigned int flags;         /* Winsock2 flags */
+ at END
+
+/* Get Winsock2 flags */
+ at REQ(get_socket_flags)
+    handle_t     handle;        /* handle to the socket */
+ at REPLY
+    unsigned int flags;         /* Winsock2 flags */
+ at END
+
+/* Get deferred socket to be accept()ed later, for WSAAccept() */
+ at REQ(get_socket_deferred)
+    handle_t     handle;        /* handle to the socket */
+ at REPLY
+    handle_t     deferred;      /* deferred socket */
+ at END
+
+/* Set deferred socket to be accept()ed later, for WSAAccept() */
+ at REQ(set_socket_deferred)
+    handle_t     handle;        /* handle to the socket */
+    handle_t     deferred;      /* deferred socket */
+ at 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;
+}
+







More information about the wine-devel mailing list