Winsock rewrite. Sockets are now proper win32 handles.
Internal structures are now really internal.
diff --git a/if1632/winsock.spec b/if1632/winsock.spec
index 58e91e1..46f89f6 100644
--- a/if1632/winsock.spec
+++ b/if1632/winsock.spec
@@ -59,3 +59,5 @@
115 pascal WSAStartup(word ptr) WSAStartup16
116 pascal WSACleanup() WSACleanup
151 pascal16 __WSAFDIsSet(word ptr) __WSAFDIsSet16
+
+1999 pascal DllEntryPoint(long word word word long word) WINSOCK_LibMain
diff --git a/include/task.h b/include/task.h
index c0e75e6..eac2302 100644
--- a/include/task.h
+++ b/include/task.h
@@ -93,8 +93,7 @@
DWORD compat_flags WINE_PACKED; /* 4e Compatibility flags */
BYTE unused4[2]; /* 52 */
struct _TEB *teb; /* 54 Pointer to thread database */
- struct _WSINFO *pwsi; /* 58 Socket control struct */
- BYTE unused5[4]; /* 5B */
+ BYTE unused5[8]; /* 58 */
HANDLE16 hPDB; /* 60 Selector of PDB (i.e. PSP) */
SEGPTR dta WINE_PACKED; /* 62 Current DTA */
BYTE curdrive; /* 66 Current drive */
diff --git a/include/winsock.h b/include/winsock.h
index 84b1d2c..74c4bb1 100644
--- a/include/winsock.h
+++ b/include/winsock.h
@@ -279,10 +279,10 @@
#define WS_FD_CLOSE 0x0020
#define WS_FD_LISTENING 0x10000000 /* internal per-socket flags */
-#define WS_FD_INACTIVE 0x20000000
+#define WS_FD_NONBLOCKING 0x20000000
#define WS_FD_CONNECTED 0x40000000
#define WS_FD_RAW 0x80000000
-#define WS_FD_NONBLOCKING 0x01000000
+#define WS_FD_SERVEVENT 0x01000000
#define WS_FD_INTERNAL 0xFFFF0000
/*
@@ -534,73 +534,6 @@
*/
#define WSAGETSELECTERROR(lParam) HIWORD(lParam)
-/* ----------------------------------- internal structures */
-
-/* ws_... struct conversion flags */
-
-#define WS_DUP_LINEAR 0x0001
-#define WS_DUP_NATIVE 0x0000 /* not used anymore */
-#define WS_DUP_OFFSET 0x0002 /* internal pointers are offsets */
-#define WS_DUP_SEGPTR 0x0004 /* internal pointers are SEGPTRs */
- /* by default, internal pointers are linear */
-
-typedef struct __sop /* WSAAsyncSelect() control struct */
-{
- struct __sop *next, *prev;
-
- struct __ws* pws;
- HWND hWnd;
- UINT uMsg;
-} ws_select_op;
-
-typedef struct __ws /* socket */
-{
- int fd;
- unsigned flags;
- ws_select_op* psop;
-} ws_socket;
-
-#define WS_MAX_SOCKETS_PER_PROCESS 16
-#define WS_MAX_UDP_DATAGRAM 1024
-
-#define WSI_BLOCKINGCALL 0x00000001 /* per-thread info flags */
-#define WSI_BLOCKINGHOOK 0x00000002 /* 32-bit callback */
-
-typedef struct _WSINFO
-{
- struct _WSINFO* prev,*next;
-
- unsigned flags;
- INT16 num_startup; /* reference counter */
- INT16 num_async_rq;
- INT16 last_free; /* entry in the socket table */
- UINT16 buflen;
- char* buffer; /* allocated from SEGPTR heap */
- struct ws_hostent *he;
- int helen;
- struct ws_servent *se;
- int selen;
- struct ws_protoent *pe;
- int pelen;
- char* dbuffer; /* buffer for dummies (32 bytes) */
-
- ws_socket sock[WS_MAX_SOCKETS_PER_PROCESS];
- DWORD blocking_hook;
- HTASK16 tid; /* owning task id - process might be better */
-} WSINFO, *LPWSINFO;
-
-/* function prototypes */
-int WS_dup_he(LPWSINFO pwsi, struct hostent* p_he, int flag);
-int WS_dup_pe(LPWSINFO pwsi, struct protoent* p_pe, int flag);
-int WS_dup_se(LPWSINFO pwsi, struct servent* p_se, int flag);
-
-BOOL WINSOCK_Init(void);
-void WINSOCK_Shutdown(void);
-UINT16 wsaErrno(void);
-UINT16 wsaHerrno(void);
-
-extern INT WINSOCK_DeleteTaskWSI( TDB* pTask, struct _WSINFO* );
-
#ifdef __cplusplus
} /* extern "C" */
#endif /* defined(__cplusplus) */
diff --git a/loader/main.c b/loader/main.c
index a1c3115..3eb4356 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -89,9 +89,6 @@
/* Initialize event handling */
if (!EVENT_Init()) return FALSE;
- /* Initialise WINSOCK handling */
- if (!WINSOCK_Init()) return FALSE;
-
/* Initialize communications */
COMM_Init();
diff --git a/loader/task.c b/loader/task.c
index 5ae567c..d3f90a5 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -451,11 +451,6 @@
TRACE_(task)("Killing task %04x\n", hTask );
- /* Delete active sockets */
-
- if( pTask->pwsi )
- WINSOCK_DeleteTaskWSI( pTask, pTask->pwsi );
-
#ifdef MZ_SUPPORTED
{
/* Kill DOS VM task */
diff --git a/misc/main.c b/misc/main.c
index c3e913b..9ec3198 100644
--- a/misc/main.c
+++ b/misc/main.c
@@ -770,7 +770,6 @@
if (USER_Driver)
USER_Driver->pFinalize();
- WINSOCK_Shutdown();
CONSOLE_Close();
}
diff --git a/misc/winsock.c b/misc/winsock.c
index 2d5fcb2..8818940 100644
--- a/misc/winsock.c
+++ b/misc/winsock.c
@@ -55,12 +55,14 @@
#endif
#include "wine/winbase16.h"
-#include "winsock.h"
+#include "winsock2.h"
#include "winnt.h"
#include "heap.h"
#include "task.h"
#include "message.h"
#include "miscemu.h"
+#include "services.h"
+#include "server.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(winsock)
@@ -74,24 +76,63 @@
/* ----------------------------------- internal data */
+/* ws_... struct conversion flags */
+
+#define WS_DUP_LINEAR 0x0001
+#define WS_DUP_NATIVE 0x0000 /* not used anymore */
+#define WS_DUP_OFFSET 0x0002 /* internal pointers are offsets */
+#define WS_DUP_SEGPTR 0x0004 /* internal pointers are SEGPTRs */
+ /* by default, internal pointers are linear */
+typedef struct /* WSAAsyncSelect() control struct */
+{
+ HANDLE service, event, sock;
+ HWND hWnd;
+ UINT uMsg;
+} ws_select_info;
+
+#define WS_MAX_SOCKETS_PER_PROCESS 128 /* reasonable guess */
+#define WS_MAX_UDP_DATAGRAM 1024
+
+#define WSI_BLOCKINGCALL 0x00000001 /* per-thread info flags */
+#define WSI_BLOCKINGHOOK 0x00000002 /* 32-bit callback */
+
+typedef struct _WSINFO
+{
+ DWORD dwThisProcess;
+ struct _WSINFO *lpNextIData;
+
+ unsigned flags;
+ INT16 num_startup; /* reference counter */
+ INT16 num_async_rq;
+ INT16 last_free; /* entry in the socket table */
+ UINT16 buflen;
+ char* buffer; /* allocated from SEGPTR heap */
+ struct ws_hostent *he;
+ int helen;
+ struct ws_servent *se;
+ int selen;
+ struct ws_protoent *pe;
+ int pelen;
+ char* dbuffer; /* buffer for dummies (32 bytes) */
+
+ DWORD blocking_hook;
+} WSINFO, *LPWSINFO;
+
+/* function prototypes */
+int WS_dup_he(LPWSINFO pwsi, struct hostent* p_he, int flag);
+int WS_dup_pe(LPWSINFO pwsi, struct protoent* p_pe, int flag);
+int WS_dup_se(LPWSINFO pwsi, struct servent* p_se, int flag);
+
+UINT16 wsaErrno(void);
+UINT16 wsaHerrno(void);
+
static HANDLE _WSHeap = 0;
-static unsigned char* _ws_stub = NULL;
-static LPWSINFO _wsi_list = NULL;
#define WS_ALLOC(size) \
HeapAlloc(_WSHeap, HEAP_ZERO_MEMORY, (size) )
#define WS_FREE(ptr) \
HeapFree(_WSHeap, 0, (ptr) )
-#define WS_PTR2HANDLE(ptr) \
- ((short)((int)(ptr) - (int)_ws_stub))
-#define WS_HANDLE2PTR(handle) \
- ((unsigned)((int)_ws_stub + (int)(handle)))
-
-#define WSI_CHECK_RANGE(pwsi, pws) \
- ( ((unsigned)(pws) > (unsigned)(pwsi)) && \
- ((unsigned)(pws) < ((unsigned)(pwsi) + sizeof(WSINFO))) )
-
static INT _ws_sock_ops[] =
{ WS_SO_DEBUG, WS_SO_REUSEADDR, WS_SO_KEEPALIVE, WS_SO_DONTROUTE,
WS_SO_BROADCAST, WS_SO_LINGER, WS_SO_OOBINLINE, WS_SO_SNDBUF,
@@ -122,21 +163,147 @@
0
};
-static int _check_ws(LPWSINFO pwsi, ws_socket* pws);
+static int _check_ws(LPWSINFO pwsi, SOCKET s);
static char* _check_buffer(LPWSINFO pwsi, int size);
-/* ----------------------------------- non-blocking I/O */
-
-static int WINSOCK_unblock_io(int fd, int noblock)
+static int _get_sock_fd(SOCKET s)
{
- int fd_flags;
-
- fd_flags = fcntl(fd, F_GETFL, 0);
- if (fcntl(fd, F_SETFL, (noblock)? fd_flags | O_NONBLOCK
- : fd_flags & ~O_NONBLOCK ) != -1) return 0;
- return -1;
+ struct get_read_fd_request *req = get_req_buffer();
+ int fd;
+
+ req->handle = s;
+ server_call_fd( REQ_GET_READ_FD, -1, &fd );
+ if (fd == -1)
+ FIXME("handle %d is not a socket (GLE %ld)\n",s,GetLastError());
+ return fd;
}
+static void _enable_event(SOCKET s, unsigned int event,
+ unsigned int sstate, unsigned int cstate)
+{
+ struct enable_socket_event_request *req = get_req_buffer();
+
+ req->handle = s;
+ req->mask = event;
+ req->sstate = sstate;
+ req->cstate = cstate;
+ server_call( REQ_ENABLE_SOCKET_EVENT );
+}
+
+static int _is_blocking(SOCKET s)
+{
+ struct get_socket_event_request *req = get_req_buffer();
+
+ req->handle = s;
+ req->service = FALSE;
+ req->s_event = 0;
+ server_call( REQ_GET_SOCKET_EVENT );
+ return (req->state & WS_FD_NONBLOCKING) == 0;
+}
+
+static unsigned int _get_sock_mask(SOCKET s)
+{
+ struct get_socket_event_request *req = get_req_buffer();
+
+ req->handle = s;
+ req->service = FALSE;
+ req->s_event = 0;
+ server_call( REQ_GET_SOCKET_EVENT );
+ return req->mask;
+}
+
+static void _sync_sock_state(SOCKET s)
+{
+ /* do a dummy wineserver request in order to let
+ the wineserver run through its select loop once */
+ (void)_is_blocking(s);
+}
+
+static int _get_sock_error(SOCKET s, unsigned int bit)
+{
+ struct get_socket_event_request *req = get_req_buffer();
+
+ req->handle = s;
+ req->service = FALSE;
+ req->s_event = 0;
+ server_call( REQ_GET_SOCKET_EVENT );
+ return req->errors[bit];
+}
+
+static LPWSINFO lpFirstIData = NULL;
+
+static LPWSINFO WINSOCK_GetIData(void)
+{
+ DWORD pid = GetCurrentProcessId();
+ LPWSINFO iData;
+
+ for (iData = lpFirstIData; iData; iData = iData->lpNextIData) {
+ if (iData->dwThisProcess == pid)
+ break;
+ }
+ return iData;
+}
+
+static BOOL WINSOCK_CreateIData(void)
+{
+ LPWSINFO iData;
+
+ iData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WSINFO));
+ if (!iData)
+ return FALSE;
+ iData->dwThisProcess = GetCurrentProcessId();
+ iData->lpNextIData = lpFirstIData;
+ lpFirstIData = iData;
+ return TRUE;
+}
+
+static void WINSOCK_DeleteIData(void)
+{
+ LPWSINFO iData = WINSOCK_GetIData();
+ LPWSINFO* ppid;
+ if (iData) {
+ for (ppid = &lpFirstIData; *ppid; ppid = &(*ppid)->lpNextIData) {
+ if (*ppid == iData) {
+ *ppid = iData->lpNextIData;
+ break;
+ }
+ }
+
+ if( iData->flags & WSI_BLOCKINGCALL )
+ TRACE("\tinside blocking call!\n");
+
+ /* delete scratch buffers */
+
+ if( iData->buffer ) SEGPTR_FREE(iData->buffer);
+ if( iData->dbuffer ) SEGPTR_FREE(iData->dbuffer);
+
+ HeapFree(GetProcessHeap(), 0, iData);
+ }
+}
+
+BOOL WINAPI WSOCK32_LibMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
+{
+ TRACE("0x%x 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
+ switch (fdwReason) {
+ case DLL_PROCESS_DETACH:
+ WINSOCK_DeleteIData();
+ break;
+ }
+ return TRUE;
+}
+
+BOOL WINAPI WINSOCK_LibMain(DWORD fdwReason, HINSTANCE hInstDLL, WORD ds,
+ WORD wHeapSize, DWORD dwReserved1, WORD wReserved2)
+{
+ TRACE("0x%x 0x%lx\n", hInstDLL, fdwReason);
+ switch (fdwReason) {
+ case DLL_PROCESS_DETACH:
+ WINSOCK_DeleteIData();
+ break;
+ }
+ return TRUE;
+}
+
/***********************************************************************
* convert_sockopt()
*
@@ -166,41 +333,6 @@
/* ----------------------------------- Per-thread info (or per-process?) */
-static LPWSINFO wsi_find(HTASK16 hTask)
-{
- TDB* pTask = (TDB*)GlobalLock16(hTask);
- if( pTask )
- {
- if( pTask->pwsi ) return pTask->pwsi;
- else
- {
- LPWSINFO pwsi = _wsi_list;
- while( pwsi && pwsi->tid != hTask ) pwsi = pwsi->next;
- if( pwsi )
- WARN("(pwsi=0x%08x,task=0x%04x):Loose wsi struct! \n",
- (unsigned)pwsi, hTask );
- return pwsi;
- }
- }
- return NULL;
-}
-
-static ws_socket* wsi_alloc_socket(LPWSINFO pwsi, int fd)
-{
- /* Initialize a new entry in the socket table */
-
- if( pwsi->last_free >= 0 )
- {
- int i = pwsi->last_free;
-
- pwsi->last_free = pwsi->sock[i].flags; /* free list */
- pwsi->sock[i].fd = fd;
- pwsi->sock[i].flags = 0;
- return &pwsi->sock[i];
- }
- return NULL;
-}
-
static int wsi_strtolo(LPWSINFO pwsi, const char* name, const char* opt)
{
/* Stuff a lowercase copy of the string into the local buffer */
@@ -218,7 +350,7 @@
return 0;
}
-static fd_set* fd_set_import( fd_set* fds, LPWSINFO pwsi, void* wsfds, int* highfd, BOOL b32 )
+static fd_set* fd_set_import( fd_set* fds, LPWSINFO pwsi, void* wsfds, int* highfd, int lfd[], BOOL b32 )
{
/* translate Winsock fd set into local fd set */
@@ -226,7 +358,6 @@
{
#define wsfds16 ((ws_fd_set16*)wsfds)
#define wsfds32 ((ws_fd_set32*)wsfds)
- ws_socket* pws;
int i, count;
FD_ZERO(fds);
@@ -234,13 +365,16 @@
for( i = 0; i < count; i++ )
{
- pws = (b32) ? (ws_socket*)WS_HANDLE2PTR(wsfds32->fd_array[i])
- : (ws_socket*)WS_HANDLE2PTR(wsfds16->fd_array[i]);
- if( _check_ws(pwsi, pws) )
+ int s = (b32) ? wsfds32->fd_array[i]
+ : wsfds16->fd_array[i];
+ if( _check_ws(pwsi, s) )
{
- if( pws->fd > *highfd ) *highfd = pws->fd;
- FD_SET(pws->fd, fds);
+ int fd = _get_sock_fd(s);
+ lfd[ i ] = fd;
+ if( fd > *highfd ) *highfd = fd;
+ FD_SET(fd, fds);
}
+ else lfd[ i ] = -1;
}
#undef wsfds32
#undef wsfds16
@@ -259,7 +393,7 @@
return optval != 0;
}
-static int fd_set_export( LPWSINFO pwsi, fd_set* fds, fd_set* exceptfds, void* wsfds, BOOL b32 )
+static int fd_set_export( LPWSINFO pwsi, fd_set* fds, fd_set* exceptfds, void* wsfds, int lfd[], BOOL b32 )
{
int num_err = 0;
@@ -274,12 +408,9 @@
for( i = 0, j = 0; i < count; i++ )
{
- ws_socket *pws = (b32) ? (ws_socket*)WS_HANDLE2PTR(wsfds32->fd_array[i])
- : (ws_socket*)WS_HANDLE2PTR(wsfds16->fd_array[i]);
- if( _check_ws(pwsi, pws) )
+ if( lfd[i] >= 0 )
{
- int fd = pws->fd;
-
+ int fd = lfd[i];
if( FD_ISSET(fd, fds) )
{
if ( exceptfds && sock_error_p(fd) )
@@ -292,6 +423,8 @@
else
wsfds16->fd_array[j++] = wsfds16->fd_array[i];
}
+ close(fd);
+ lfd[i] = -1;
}
}
@@ -305,9 +438,42 @@
return num_err;
}
-HANDLE16 __ws_gethandle( void* ptr )
+static void fd_set_unimport( void* wsfds, int lfd[], BOOL b32 )
{
- return (HANDLE16)WS_PTR2HANDLE(ptr);
+ if ( wsfds )
+ {
+#define wsfds16 ((ws_fd_set16*)wsfds)
+#define wsfds32 ((ws_fd_set32*)wsfds)
+ int i, count = (b32) ? wsfds32->fd_count : wsfds16->fd_count;
+
+ for( i = 0; i < count; i++ )
+ if ( lfd[i] >= 0 )
+ close(lfd[i]);
+
+ TRACE("\n");
+#undef wsfds32
+#undef wsfds16
+ }
+}
+
+static int do_block( int fd, int mask )
+{
+ fd_set fds[3];
+ int i, r;
+
+ FD_ZERO(&fds[0]);
+ FD_ZERO(&fds[1]);
+ FD_ZERO(&fds[2]);
+ for (i=0; i<3; i++)
+ if (mask & (1<<i))
+ FD_SET(fd, &fds[i]);
+ i = select( fd+1, &fds[0], &fds[1], &fds[2], NULL );
+ if (i <= 0) return -1;
+ r = 0;
+ for (i=0; i<3; i++)
+ if (FD_ISSET(fd, &fds[i]))
+ r |= 1<<i;
+ return r;
}
void* __ws_memalloc( int size )
@@ -320,157 +486,6 @@
WS_FREE(ptr);
}
-/*
- * Event handling helper routines
- *
- * FIXME: This is all a hack; winsock event handling should be moved
- * to the services thread ...
- */
-
-#define EVENT_IO_READ 0
-#define EVENT_IO_WRITE 1
-#define EVENT_IO_EXCEPT 2
-
-static fd_set __winsock_io_set[3];
-static int __winsock_max_fd = 0;
-static int __wakeup_pipe[2];
-
-static CRITICAL_SECTION __winsock_crst;
-static HANDLE __winsock_thread = INVALID_HANDLE_VALUE;
-
-BOOL WINSOCK_HandleIO( int* max_fd, int num_pending,
- fd_set pending_set[3], fd_set event_set[3] );
-
-/***********************************************************************
- * WINSOCK_Init
- *
- * Initialize network IO.
- */
-BOOL WINSOCK_Init(void)
-{
- int i;
- for( i = 0; i < 3; i++ )
- FD_ZERO( __winsock_io_set + i );
-
- /* pipe used to wake up the winsock thread */
- pipe(__wakeup_pipe);
-
- /* make the pipe non-blocking */
- fcntl(__wakeup_pipe[0], F_SETFL, O_NONBLOCK);
- fcntl(__wakeup_pipe[1], F_SETFL, O_NONBLOCK);
-
- FD_SET( __wakeup_pipe[0], &__winsock_io_set[EVENT_IO_READ] );
- __winsock_max_fd = __wakeup_pipe[0];
- __winsock_max_fd++;
-
- /* Inititalize critical section */
- InitializeCriticalSection( &__winsock_crst );
- MakeCriticalSectionGlobal( &__winsock_crst );
-
- return TRUE;
-}
-
-/***********************************************************************
- * WINSOCK_Shutdown
- */
-void WINSOCK_Shutdown()
-{
- /* Called on exit(), has to remove all outstanding async DNS processes. */
-
- if ( __winsock_thread != INVALID_HANDLE_VALUE )
- {
- TerminateThread( __winsock_thread, 0 );
- __winsock_thread = INVALID_HANDLE_VALUE;
- }
-}
-
-/***********************************************************************
- * WINSOCK_Thread
- */
-static DWORD CALLBACK WINSOCK_Thread( LPVOID arg )
-{
- while ( TRUE )
- {
- int num_pending, max_fd;
- fd_set io_set[3];
-
- EnterCriticalSection( &__winsock_crst );
- memcpy( io_set, __winsock_io_set, sizeof(io_set) );
- max_fd = __winsock_max_fd;
- LeaveCriticalSection( &__winsock_crst );
-
- num_pending = select( max_fd, &io_set[EVENT_IO_READ],
- &io_set[EVENT_IO_WRITE],
- &io_set[EVENT_IO_EXCEPT], NULL );
-
- if ( num_pending == -1 )
- {
- /* Error - signal, invalid arguments, out of memory */
- continue;
- }
-
- /* Flush the wake-up pipe */
- if ( FD_ISSET( __wakeup_pipe[0], &io_set[EVENT_IO_READ] ) )
- {
- char tmpBuf[10];
- ssize_t ret;
-
- while ( (ret = read(__wakeup_pipe[0], &tmpBuf, 10)) == 10 );
- num_pending--;
- }
-
- /* Handle actual IO */
- if ( num_pending > 0 )
- {
- EnterCriticalSection( &__winsock_crst );
- WINSOCK_HandleIO( &__winsock_max_fd, num_pending, io_set, __winsock_io_set );
- LeaveCriticalSection( &__winsock_crst );
- }
- }
-}
-
-/***********************************************************************
- * WINSOCK_WakeUp
- *
- * Wake up the winsock thread.
- */
-static void WINSOCK_WakeUp(void)
-{
- if ( __winsock_thread == INVALID_HANDLE_VALUE )
- {
- __winsock_thread = CreateThread( NULL, 0, WINSOCK_Thread, NULL, 0, NULL );
- __winsock_thread = ConvertToGlobalHandle( __winsock_thread );
- }
-
- if (write (__wakeup_pipe[1], "A", 1) != 1)
- ERR("unable to write in wakeup_pipe\n");
-}
-
-/***********************************************************************
- * EVENT_AddIO
- */
-static void EVENT_AddIO(int fd, unsigned io_type)
-{
- EnterCriticalSection( &__winsock_crst );
- FD_SET( fd, &__winsock_io_set[io_type] );
- if( __winsock_max_fd <= fd ) __winsock_max_fd = fd + 1;
- LeaveCriticalSection( &__winsock_crst );
-
- WINSOCK_WakeUp();
-}
-
-/***********************************************************************
- * EVENT_DeleteIO
- */
-static void EVENT_DeleteIO(int fd, unsigned io_type)
-{
- EnterCriticalSection( &__winsock_crst );
- FD_CLR( fd, &__winsock_io_set[io_type] );
- LeaveCriticalSection( &__winsock_crst );
-
- WINSOCK_WakeUp();
-}
-
/* ----------------------------------- API -----
*
@@ -502,7 +517,6 @@
#endif
WS_MAX_SOCKETS_PER_PROCESS,
WS_MAX_UDP_DATAGRAM, (SEGPTR)NULL };
- HTASK16 tid = GetCurrentTask();
LPWSINFO pwsi;
TRACE("verReq=%x\n", wVersionRequested);
@@ -514,10 +528,10 @@
/* initialize socket heap */
- if( !_ws_stub )
+ if( !_WSHeap )
{
_WSHeap = HeapCreate(HEAP_ZERO_MEMORY, 8120, 32768);
- if( !(_ws_stub = WS_ALLOC(0x10)) )
+ if( !_WSHeap )
{
ERR("Fatal: failed to create WinSock heap\n");
return 0;
@@ -525,34 +539,12 @@
}
if( _WSHeap == 0 ) return WSASYSNOTREADY;
- /* create socket array for this task */
-
- pwsi = wsi_find(GetCurrentTask());
+ pwsi = WINSOCK_GetIData();
if( pwsi == NULL )
{
- TDB* pTask = (TDB*)GlobalLock16( tid );
-
- if( (pwsi = (LPWSINFO)WS_ALLOC( sizeof(WSINFO))) )
- {
- int i = 0;
- pwsi->tid = tid;
- for( i = 0; i < WS_MAX_SOCKETS_PER_PROCESS; i++ )
- {
- pwsi->sock[i].fd = -1;
- pwsi->sock[i].flags = i + 1;
- }
- pwsi->sock[WS_MAX_SOCKETS_PER_PROCESS - 1].flags = -1;
- }
- else return WSASYSNOTREADY;
-
- /* add this control struct to the global list */
-
- pwsi->prev = NULL;
- if( _wsi_list )
- _wsi_list->prev = pwsi;
- pwsi->next = _wsi_list;
- _wsi_list = pwsi;
- pTask->pwsi = pwsi;
+ WINSOCK_CreateIData();
+ pwsi = WINSOCK_GetIData();
+ if (!pwsi) return WSASYSNOTREADY;
}
pwsi->num_startup++;
@@ -574,82 +566,17 @@
/***********************************************************************
* WSACleanup() (WINSOCK.116)
- *
- * Cleanup functions of varying impact.
*/
-
-INT WINSOCK_DeleteTaskWSI( TDB* pTask, LPWSINFO pwsi )
-{
- /* WSACleanup() backend, called on task termination as well.
- * Real DLL would have registered its own signal handler with
- * TaskSetSignalHandler() and waited until USIG_TERMINATION/USIG_GPF
- * but this scheme is much more straightforward.
- */
-
- int i, j, n;
-
- if( --pwsi->num_startup > 0 ) return 0;
-
- /* unlink socket control struct */
-
- if( pwsi == _wsi_list )
- _wsi_list = pwsi->next;
- else
- pwsi->prev->next = pwsi->next;
- if( pwsi->next ) pwsi->next->prev = pwsi->prev;
-
- if( _wsi_list == NULL )
- WINSOCK_Shutdown(); /* just in case */
-
- if( pwsi->flags & WSI_BLOCKINGCALL )
- TRACE("\tinside blocking call!\n");
-
-/* FIXME: aop_control() doesn't decrement pwsi->num_async_rq
- *
- * if( pwsi->num_async_rq )
- * WARN(winsock,"\thave %i outstanding async ops!\n", pwsi->num_async_rq );
- */
-
- for(i = 0, j = 0, n = 0; i < WS_MAX_SOCKETS_PER_PROCESS; i++)
- if( pwsi->sock[i].fd != -1 )
- {
- if( pwsi->sock[i].psop )
- {
- n++;
- WSAAsyncSelect( (SOCKET16)WS_PTR2HANDLE(pwsi->sock + i), 0, 0, 0 );
- }
- close(pwsi->sock[i].fd); j++;
- }
- if( j )
- TRACE("\tclosed %i sockets, killed %i async selects!\n", j, n);
-
- /* delete scratch buffers */
-
- if( pwsi->buffer ) SEGPTR_FREE(pwsi->buffer);
- if( pwsi->dbuffer ) SEGPTR_FREE(pwsi->dbuffer);
-
- if( pTask )
- pTask->pwsi = NULL;
- memset( pwsi, 0, sizeof(WSINFO) );
- WS_FREE(pwsi);
- return 0;
-}
-
INT WINAPI WSACleanup(void)
{
- HTASK16 hTask = GetCurrentTask();
+ LPWSINFO pwsi = WINSOCK_GetIData();
+ if( pwsi ) {
+ if( --pwsi->num_startup > 0 ) return 0;
- TRACE("(%04x)\n", hTask );
- if( hTask )
- {
- LPWSINFO pwsi = wsi_find(hTask);
- if( pwsi )
- return WINSOCK_DeleteTaskWSI( (TDB*)GlobalLock16(hTask), pwsi );
- return SOCKET_ERROR;
+ WINSOCK_DeleteIData();
+ return 0;
}
- else
- WINSOCK_Shutdown(); /* remove all outstanding DNS requests */
- return 0;
+ return SOCKET_ERROR;
}
@@ -676,13 +603,19 @@
WSASetLastError(iError);
}
-int _check_ws(LPWSINFO pwsi, ws_socket* pws)
+int _check_ws(LPWSINFO pwsi, SOCKET s)
{
if( pwsi )
{
+ int fd;
if( pwsi->flags & WSI_BLOCKINGCALL ) SetLastError(WSAEINPROGRESS);
- else if( WSI_CHECK_RANGE(pwsi, pws) ) return 1;
- else SetLastError(WSAENOTSOCK);
+ if ( (fd = _get_sock_fd(s)) < 0 ) {
+ SetLastError(WSAENOTSOCK);
+ return 0;
+ }
+ /* FIXME: maybe check whether fd is really a socket? */
+ close( fd );
+ return 1;
}
return 0;
}
@@ -731,34 +664,36 @@
SOCKET WINAPI WINSOCK_accept(SOCKET s, struct sockaddr *addr,
INT *addrlen32)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR((SOCKET16)s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
#ifdef HAVE_IPX
struct ws_sockaddr_ipx* addr2 = (struct ws_sockaddr_ipx *)addr;
#endif
+ struct accept_socket_request *req = get_req_buffer();
TRACE("(%08x): socket %04x\n",
(unsigned)pwsi, (UINT16)s );
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
- int sock, fd_flags;
-
- fd_flags = fcntl(pws->fd, F_GETFL, 0);
-
- if( (sock = accept(pws->fd, addr, addrlen32)) >= 0 )
+ if (_is_blocking(s))
{
- ws_socket* pnew = wsi_alloc_socket(pwsi, sock);
- if( pnew )
+ /* block here */
+ int fd = _get_sock_fd(s);
+ do_block(fd, 5);
+ close(fd);
+ _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? */
+ }
+ req->lhandle = s;
+ req->access = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE;
+ req->inherit = TRUE;
+ server_call( REQ_ACCEPT_SOCKET );
+ if( req->handle >= 0 )
+ {
+ int fd = _get_sock_fd( s = req->handle );
+ if( getpeername(fd, addr, addrlen32) != -1 )
{
- s = (SOCKET)WS_PTR2HANDLE(pnew);
- if( pws->psop && pws->flags & WS_FD_ACCEPT )
- {
- EVENT_AddIO( pws->fd, EVENT_IO_READ ); /* reenabler */
-
- /* async select the accept()'ed socket */
- WSAAsyncSelect( s, pws->psop->hWnd, pws->psop->uMsg,
- pws->flags & ~WS_FD_ACCEPT );
- }
#ifdef HAVE_IPX
if (addr && ((struct sockaddr_ipx *)addr)->sipx_family == AF_IPX) {
addr = (struct sockaddr *)
@@ -773,24 +708,11 @@
free(addr);
}
#endif
- return s;
- }
- else SetLastError(WSAENOBUFS);
- } else SetLastError(wsaErrno());
+ } else SetLastError(wsaErrno());
+ close(fd);
+ return s;
+ }
}
-#ifdef HAVE_IPX
- if (addr && ((struct sockaddr_ipx *)addr)->sipx_family == AF_IPX) {
- addr = (struct sockaddr *)
- malloc(addrlen32 ? *addrlen32 : sizeof(*addr2));
- memcpy(addr, addr2, addrlen32 ? *addrlen32 : sizeof(*addr2));
- addr2->sipx_family = WS_AF_IPX;
- addr2->sipx_network = ((struct sockaddr_ipx *)addr)->sipx_network;
- addr2->sipx_port = ((struct sockaddr_ipx *)addr)->sipx_port;
- memcpy(addr2->sipx_node,
- ((struct sockaddr_ipx *)addr)->sipx_node, IPX_NODE_LEN);
- free(addr);
- }
-#endif
return INVALID_SOCKET;
}
@@ -811,8 +733,7 @@
*/
INT WINAPI WINSOCK_bind(SOCKET s, struct sockaddr *name, INT namelen)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
#ifdef HAVE_IPX
struct ws_sockaddr_ipx* name2 = (struct ws_sockaddr_ipx *)name;
#endif
@@ -823,8 +744,9 @@
dump_sockaddr(name);
#endif
- if ( _check_ws(pwsi, pws) )
+ if ( _check_ws(pwsi, s) )
{
+ int fd = _get_sock_fd(s);
/* FIXME: what family does this really map to on the Unix side? */
if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_PUP)
((struct ws_sockaddr_ipx *)name)->sipx_family = AF_UNSPEC;
@@ -850,7 +772,7 @@
#endif
))
{
- if ( bind(pws->fd, name, namelen) < 0 )
+ if ( bind(fd, name, namelen) < 0 )
{
int loc_errno = errno;
WARN("\tfailure - errno = %i\n", errno);
@@ -867,6 +789,7 @@
if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
free(name);
#endif
+ close(fd);
return 0; /* success */
}
} else SetLastError(WSAEAFNOSUPPORT);
@@ -875,6 +798,7 @@
if (name && ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
free(name);
#endif
+ close(fd);
}
return SOCKET_ERROR;
}
@@ -892,24 +816,14 @@
*/
INT WINAPI WINSOCK_closesocket(SOCKET s)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): socket %08x\n", (unsigned)pwsi, s);
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
- int fd = pws->fd;
-
- if( pws->psop ) WSAAsyncSelect( s, 0, 0, 0 );
-
- pws->fd = -1;
- pws->flags = (unsigned)pwsi->last_free;
- pwsi->last_free = pws - &pwsi->sock[0]; /* add to free list */
-
- if( close(fd) == 0 )
+ if( CloseHandle(s) )
return 0;
- SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
}
return SOCKET_ERROR;
}
@@ -927,8 +841,7 @@
*/
INT WINAPI WINSOCK_connect(SOCKET s, struct sockaddr *name, INT namelen)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
#ifdef HAVE_IPX
struct ws_sockaddr_ipx* name2 = (struct ws_sockaddr_ipx *)name;
#endif
@@ -939,8 +852,9 @@
dump_sockaddr(name);
#endif
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
+ int fd = _get_sock_fd(s);
if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_PUP)
((struct ws_sockaddr_ipx *)name)->sipx_family = AF_UNSPEC;
#ifdef HAVE_IPX
@@ -956,45 +870,54 @@
namelen = sizeof(struct sockaddr_ipx);
}
#endif
- if (connect(pws->fd, name, namelen) == 0)
- {
- if( pws->psop && (pws->flags & WS_FD_CONNECT) )
+ if (connect(fd, name, namelen) == 0) {
+ close(fd);
+ goto connect_success;
+ }
+ if (errno == EINPROGRESS)
+ {
+ /* tell wineserver that a connection is in progress */
+ _enable_event(s, FD_CONNECT|FD_READ|FD_WRITE,
+ WS_FD_CONNECT|WS_FD_READ|WS_FD_WRITE,
+ WS_FD_CONNECTED|WS_FD_LISTENING);
+ if (_is_blocking(s))
{
- /* application did AsyncSelect() but then went
- * ahead and called connect() without waiting for
- * notification.
- *
- * FIXME: Do we have to post a notification message
- * in this case?
- */
-
- if( !(pws->flags & WS_FD_CONNECTED) )
- {
- if( pws->flags & (WS_FD_READ | WS_FD_CLOSE) )
- EVENT_AddIO( pws->fd, EVENT_IO_READ );
- else
- EVENT_DeleteIO( pws->fd, EVENT_IO_READ );
- if( pws->flags & WS_FD_WRITE )
- EVENT_AddIO( pws->fd, EVENT_IO_WRITE );
- else
- EVENT_DeleteIO( pws->fd, EVENT_IO_WRITE );
+ int result;
+ /* block here */
+ do_block(fd, 6);
+ _sync_sock_state(s); /* let wineserver notice connection */
+ /* retrieve any error codes from it */
+ result = _get_sock_error(s, FD_CONNECT_BIT);
+ if (result)
+ SetLastError(result);
+ else {
+ close(fd);
+ goto connect_success;
}
}
- pws->flags |= WS_FD_CONNECTED;
- pws->flags &= ~(WS_FD_INACTIVE | WS_FD_CONNECT | WS_FD_LISTENING);
-#ifdef HAVE_IPX
- if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
- free(name);
-#endif
- return 0;
+ else SetLastError(WSAEWOULDBLOCK);
+ close(fd);
}
- SetLastError((errno == EINPROGRESS) ? WSAEWOULDBLOCK : wsaErrno());
+ else
+ {
+ SetLastError(wsaErrno());
+ close(fd);
+ }
}
#ifdef HAVE_IPX
if (name && ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
free(name);
#endif
return SOCKET_ERROR;
+connect_success:
+#ifdef HAVE_IPX
+ if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
+ free(name);
+#endif
+ _enable_event(s, FD_CONNECT|FD_READ|FD_WRITE,
+ WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE,
+ WS_FD_CONNECT|WS_FD_LISTENING);
+ return 0;
}
/***********************************************************************
@@ -1011,17 +934,17 @@
INT WINAPI WINSOCK_getpeername(SOCKET s, struct sockaddr *name,
INT *namelen)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
#ifdef HAVE_IPX
struct ws_sockaddr_ipx* name2 = (struct ws_sockaddr_ipx *)name;
#endif
TRACE("(%08x): socket: %04x, ptr %8x, ptr %8x\n",
(unsigned)pwsi, s, (int) name, *namelen);
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
- if (getpeername(pws->fd, name, namelen) == 0) {
+ int fd = _get_sock_fd(s);
+ if (getpeername(fd, name, namelen) == 0) {
#ifdef HAVE_IPX
if (((struct ws_sockaddr_ipx *)name)->sipx_family == AF_IPX) {
name = (struct sockaddr *)
@@ -1035,22 +958,12 @@
free(name);
}
#endif
+ close(fd);
return 0;
}
SetLastError(wsaErrno());
+ close(fd);
}
-#ifdef HAVE_IPX
- if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == AF_IPX) {
- name = (struct sockaddr *) malloc(namelen ? *namelen : sizeof(*name2));
- memcpy(name, name2, namelen ? *namelen : sizeof(*name2));
- name2->sipx_family = WS_AF_IPX;
- name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network;
- name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port;
- memcpy(name2->sipx_node,
- ((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN);
- free(name);
- }
-#endif
return SOCKET_ERROR;
}
@@ -1077,17 +990,17 @@
INT WINAPI WINSOCK_getsockname(SOCKET s, struct sockaddr *name,
INT *namelen)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
#ifdef HAVE_IPX
struct ws_sockaddr_ipx* name2 = (struct ws_sockaddr_ipx *)name;
#endif
TRACE("(%08x): socket: %04x, ptr %8x, ptr %8x\n",
(unsigned)pwsi, s, (int) name, (int) *namelen);
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
- if (getsockname(pws->fd, name, namelen) == 0) {
+ int fd = _get_sock_fd(s);
+ if (getsockname(fd, name, namelen) == 0) {
#ifdef HAVE_IPX
if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX) {
name = (struct sockaddr *)
@@ -1101,22 +1014,12 @@
free(name);
}
#endif
+ close(fd);
return 0;
}
SetLastError(wsaErrno());
+ close(fd);
}
-#ifdef HAVE_IPX
- if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == AF_IPX) {
- name = (struct sockaddr *) malloc(namelen ? *namelen : sizeof(*name2));
- memcpy(name, name2, namelen ? *namelen : sizeof(*name2));
- name2->sipx_family = WS_AF_IPX;
- name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network;
- name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port;
- memcpy(name2->sipx_node,
- ((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN);
- free(name);
- }
-#endif
return SOCKET_ERROR;
}
@@ -1150,17 +1053,21 @@
INT WINAPI WINSOCK_getsockopt(SOCKET s, INT level,
INT optname, char *optval, INT *optlen)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): socket: %04x, opt %d, ptr %8x, ptr %8x\n",
(unsigned)pwsi, s, level, (int) optval, (int) *optlen);
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
+ int fd = _get_sock_fd(s);
convert_sockopt(&level, &optname);
- if (getsockopt(pws->fd, (int) level, optname, optval, optlen) == 0 )
+ if (getsockopt(fd, (int) level, optname, optval, optlen) == 0 )
+ {
+ close(fd);
return 0;
+ }
SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
+ close(fd);
}
return SOCKET_ERROR;
}
@@ -1211,7 +1118,7 @@
* saving them first...
*/
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
@@ -1243,13 +1150,13 @@
*/
INT WINAPI WINSOCK_ioctlsocket(SOCKET s, LONG cmd, ULONG *argp)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): socket %04x, cmd %08lx, ptr %8x\n",
(unsigned)pwsi, s, cmd, (unsigned) argp);
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
+ int fd = _get_sock_fd(s);
long newcmd = cmd;
switch( cmd )
@@ -1260,13 +1167,19 @@
case WS_FIONBIO:
newcmd=FIONBIO;
- if( pws->psop && *argp == 0 )
+ if( _get_sock_mask(s) )
{
/* AsyncSelect()'ed sockets are always nonblocking */
SetLastError(WSAEINVAL);
+ close(fd);
return SOCKET_ERROR;
}
- break;
+ close(fd);
+ if (*argp)
+ _enable_event(s, 0, WS_FD_NONBLOCKING, 0);
+ else
+ _enable_event(s, 0, 0, WS_FD_NONBLOCKING);
+ return 0;
case WS_SIOCATMARK:
newcmd=SIOCATMARK;
@@ -1281,8 +1194,13 @@
/* Netscape tries hard to use bogus ioctl 0x667e */
WARN("\tunknown WS_IOCTL cmd (%08lx)\n", cmd);
}
- if( ioctl(pws->fd, newcmd, (char*)argp ) == 0 ) return 0;
+ if( ioctl(fd, newcmd, (char*)argp ) == 0 )
+ {
+ close(fd);
+ return 0;
+ }
SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
+ close(fd);
}
return SOCKET_ERROR;
}
@@ -1301,22 +1219,19 @@
*/
INT WINAPI WINSOCK_listen(SOCKET s, INT backlog)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): socket %04x, backlog %d\n",
(unsigned)pwsi, s, backlog);
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
- if (listen(pws->fd, backlog) == 0)
+ int fd = _get_sock_fd(s);
+ if (listen(fd, backlog) == 0)
{
- if( !pws->psop )
- {
- int fd_flags = fcntl(pws->fd, F_GETFL, 0);
- if( !(fd_flags & O_NONBLOCK) ) pws->flags |= WS_FD_ACCEPT;
- }
- pws->flags |= WS_FD_LISTENING;
- pws->flags &= ~(WS_FD_INACTIVE | WS_FD_CONNECT | WS_FD_CONNECTED); /* just in case */
+ close(fd);
+ _enable_event(s, FD_ACCEPT,
+ WS_FD_LISTENING,
+ WS_FD_CONNECT|WS_FD_CONNECTED);
return 0;
}
SetLastError(wsaErrno());
@@ -1339,25 +1254,32 @@
*/
INT WINAPI WINSOCK_recv(SOCKET s, char *buf, INT len, INT flags)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): socket %04x, buf %8x, len %d, "
"flags %d\n", (unsigned)pwsi, s, (unsigned)buf,
len, flags);
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
+ int fd = _get_sock_fd(s);
INT length;
- if ((length = recv(pws->fd, buf, len, flags)) >= 0)
+
+ if (_is_blocking(s))
+ {
+ /* block here */
+ /* FIXME: OOB and exceptfds? */
+ do_block(fd, 1);
+ }
+ if ((length = recv(fd, buf, len, flags)) >= 0)
{
TRACE(" -> %i bytes\n", length);
- if( pws->psop && (pws->flags & (WS_FD_READ | WS_FD_CLOSE)) )
- EVENT_AddIO( pws->fd, EVENT_IO_READ ); /* reenabler */
-
+ close(fd);
+ _enable_event(s, FD_READ, 0, 0);
return length;
}
SetLastError(wsaErrno());
+ close(fd);
}
else SetLastError(WSAENOTSOCK);
WARN(" -> ERROR\n");
@@ -1379,8 +1301,7 @@
INT WINAPI WINSOCK_recvfrom(SOCKET s, char *buf, INT len, INT flags,
struct sockaddr *from, INT *fromlen32)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
#ifdef HAVE_IPX
struct ws_sockaddr_ipx* from2 = (struct ws_sockaddr_ipx *)from;
#endif
@@ -1393,17 +1314,21 @@
else DPRINTF("from = NULL\n");
#endif
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
+ int fd = _get_sock_fd(s);
int length;
- if ((length = recvfrom(pws->fd, buf, len, flags, from, fromlen32)) >= 0)
+ if (_is_blocking(s))
+ {
+ /* block here */
+ /* FIXME: OOB and exceptfds */
+ do_block(fd, 1);
+ }
+ if ((length = recvfrom(fd, buf, len, flags, from, fromlen32)) >= 0)
{
TRACE(" -> %i bytes\n", length);
- if( pws->psop && (pws->flags & (WS_FD_READ | WS_FD_CLOSE)) )
- EVENT_AddIO( pws->fd, EVENT_IO_READ ); /* reenabler */
-
#ifdef HAVE_IPX
if (from && ((struct sockaddr_ipx *)from)->sipx_family == AF_IPX) {
from = (struct sockaddr *)
@@ -1417,9 +1342,12 @@
free(from);
}
#endif
+ close(fd);
+ _enable_event(s, FD_READ, 0, 0);
return (INT16)length;
}
SetLastError(wsaErrno());
+ close(fd);
}
else SetLastError(WSAENOTSOCK);
WARN(" -> ERROR\n");
@@ -1461,7 +1389,7 @@
static INT __ws_select( BOOL b32, void *ws_readfds, void *ws_writefds, void *ws_exceptfds,
struct timeval *timeout )
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): read %8x, write %8x, excp %8x\n",
(unsigned) pwsi, (unsigned) ws_readfds, (unsigned) ws_writefds, (unsigned) ws_exceptfds);
@@ -1471,15 +1399,16 @@
int highfd = 0;
fd_set readfds, writefds, exceptfds;
fd_set *p_read, *p_write, *p_except;
+ int readfd[FD_SETSIZE], writefd[FD_SETSIZE], exceptfd[FD_SETSIZE];
- p_read = fd_set_import(&readfds, pwsi, ws_readfds, &highfd, b32);
- p_write = fd_set_import(&writefds, pwsi, ws_writefds, &highfd, b32);
- p_except = fd_set_import(&exceptfds, pwsi, ws_exceptfds, &highfd, b32);
+ p_read = fd_set_import(&readfds, pwsi, ws_readfds, &highfd, readfd, b32);
+ p_write = fd_set_import(&writefds, pwsi, ws_writefds, &highfd, writefd, b32);
+ p_except = fd_set_import(&exceptfds, pwsi, ws_exceptfds, &highfd, exceptfd, b32);
if( (highfd = select(highfd + 1, p_read, p_write, p_except, timeout)) > 0 )
{
- fd_set_export(pwsi, &readfds, p_except, ws_readfds, b32);
- fd_set_export(pwsi, &writefds, p_except, ws_writefds, b32);
+ fd_set_export(pwsi, &readfds, p_except, ws_readfds, readfd, b32);
+ fd_set_export(pwsi, &writefds, p_except, ws_writefds, writefd, b32);
if (p_except && ws_exceptfds)
{
@@ -1489,15 +1418,16 @@
for (i = j = 0; i < count; i++)
{
- ws_socket *pws = (b32) ? (ws_socket *)WS_HANDLE2PTR(wsfds32->fd_array[i])
- : (ws_socket *)WS_HANDLE2PTR(wsfds16->fd_array[i]);
- if( _check_ws(pwsi, pws) && FD_ISSET(pws->fd, &exceptfds) )
+ int fd = exceptfd[i];
+ if( fd >= 0 && FD_ISSET(fd, &exceptfds) )
{
if( b32 )
wsfds32->fd_array[j++] = wsfds32->fd_array[i];
else
wsfds16->fd_array[j++] = wsfds16->fd_array[i];
}
+ if( fd >= 0 ) close(fd);
+ exceptfd[i] = -1;
}
if( b32 )
wsfds32->fd_count = j;
@@ -1508,6 +1438,9 @@
}
return highfd;
}
+ fd_set_unimport(ws_readfds, readfd, b32);
+ fd_set_unimport(ws_writefds, writefd, b32);
+ fd_set_unimport(ws_exceptfds, exceptfd, b32);
if( ws_readfds ) ((ws_fd_set32*)ws_readfds)->fd_count = 0;
if( ws_writefds ) ((ws_fd_set32*)ws_writefds)->fd_count = 0;
if( ws_exceptfds ) ((ws_fd_set32*)ws_exceptfds)->fd_count = 0;
@@ -1539,23 +1472,33 @@
*/
INT WINAPI WINSOCK_send(SOCKET s, char *buf, INT len, INT flags)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): socket %04x, ptr %08x, length %d, flags %d\n",
(unsigned)pwsi, s, (unsigned) buf, len, flags);
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
+ int fd = _get_sock_fd(s);
int length;
- if ((length = send(pws->fd, buf, len, flags)) < 0 )
+ if (_is_blocking(s))
+ {
+ /* block here */
+ /* FIXME: exceptfds */
+ do_block(fd, 2);
+ }
+ if ((length = send(fd, buf, len, flags)) < 0 )
{
SetLastError(wsaErrno());
- if( GetLastError() == WSAEWOULDBLOCK &&
- pws->psop && pws->flags & WS_FD_WRITE )
- EVENT_AddIO( pws->fd, EVENT_IO_WRITE ); /* reenabler */
+ if( GetLastError() == WSAEWOULDBLOCK )
+ _enable_event(s, FD_WRITE, 0, 0);
}
- else return (INT16)length;
+ else
+ {
+ close(fd);
+ return (INT16)length;
+ }
+ close(fd);
}
else SetLastError(WSAENOTSOCK);
return SOCKET_ERROR;
@@ -1575,16 +1518,16 @@
INT WINAPI WINSOCK_sendto(SOCKET s, char *buf, INT len, INT flags,
struct sockaddr *to, INT tolen)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
#ifdef HAVE_IPX
struct ws_sockaddr_ipx* to2 = (struct ws_sockaddr_ipx *)to;
#endif
TRACE("(%08x): socket %04x, ptr %08x, length %d, flags %d\n",
(unsigned)pwsi, s, (unsigned) buf, len, flags);
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
+ int fd = _get_sock_fd(s);
INT length;
if (to && ((struct ws_sockaddr_ipx *)to)->sipx_family == WS_AF_PUP)
@@ -1603,12 +1546,17 @@
tolen = sizeof(struct sockaddr_ipx);
}
#endif
- if ((length = sendto(pws->fd, buf, len, flags, to, tolen)) < 0 )
+ if (_is_blocking(s))
+ {
+ /* block here */
+ /* FIXME: exceptfds */
+ do_block(fd, 2);
+ }
+ if ((length = sendto(fd, buf, len, flags, to, tolen)) < 0 )
{
SetLastError(wsaErrno());
- if( GetLastError() == WSAEWOULDBLOCK &&
- pws->psop && pws->flags & WS_FD_WRITE )
- EVENT_AddIO( pws->fd, EVENT_IO_WRITE ); /* reenabler */
+ if( GetLastError() == WSAEWOULDBLOCK )
+ _enable_event(s, FD_WRITE, 0, 0);
}
else {
#ifdef HAVE_IPX
@@ -1616,8 +1564,10 @@
free(to);
}
#endif
- return length;
+ close(fd);
+ return length;
}
+ close(fd);
}
else SetLastError(WSAENOTSOCK);
#ifdef HAVE_IPX
@@ -1643,14 +1593,14 @@
INT WINAPI WINSOCK_setsockopt(SOCKET16 s, INT level, INT optname,
char *optval, INT optlen)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): socket %04x, lev %d, opt %d, ptr %08x, len %d\n",
(unsigned)pwsi, s, level, optname, (int) optval, optlen);
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
struct linger linger;
+ int fd = _get_sock_fd(s);
convert_sockopt(&level, &optname);
if (optname == SO_LINGER && optval) {
@@ -1662,8 +1612,13 @@
optval = (char*)&linger;
optlen = sizeof(struct linger);
}
- if (setsockopt(pws->fd, level, optname, optval, optlen) == 0) return 0;
+ if (setsockopt(fd, level, optname, optval, optlen) == 0)
+ {
+ close(fd);
+ return 0;
+ }
SetLastError(wsaErrno());
+ close(fd);
}
else SetLastError(WSAENOTSOCK);
return SOCKET_ERROR;
@@ -1685,29 +1640,24 @@
*/
INT WINAPI WINSOCK_shutdown(SOCKET s, INT how)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): socket %04x, how %i\n",
(unsigned)pwsi, s, how );
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
- if( pws->psop )
+ int fd = _get_sock_fd(s);
switch( how )
{
case 0: /* drop receives */
- if( pws->flags & (WS_FD_READ | WS_FD_CLOSE) )
- EVENT_DeleteIO( pws->fd, EVENT_IO_READ );
- pws->flags &= ~(WS_FD_READ | WS_FD_CLOSE);
+ _enable_event(s, 0, 0, WS_FD_READ);
#ifdef SHUT_RD
how = SHUT_RD;
#endif
break;
case 1: /* drop sends */
- if( pws->flags & WS_FD_WRITE )
- EVENT_DeleteIO( pws->fd, EVENT_IO_WRITE );
- pws->flags &= ~WS_FD_WRITE;
+ _enable_event(s, 0, 0, WS_FD_WRITE);
#ifdef SHUT_WR
how = SHUT_WR;
#endif
@@ -1722,16 +1672,17 @@
break;
}
- if (shutdown(pws->fd, how) == 0)
+ if (shutdown(fd, how) == 0)
{
if( how > 1 )
{
- pws->flags &= ~(WS_FD_CONNECTED | WS_FD_LISTENING);
- pws->flags |= WS_FD_INACTIVE;
+ _enable_event(s, 0, 0, WS_FD_CONNECTED|WS_FD_LISTENING);
}
+ close(fd);
return 0;
}
SetLastError(wsaErrno());
+ close(fd);
}
else SetLastError(WSAENOTSOCK);
return SOCKET_ERROR;
@@ -1751,15 +1702,14 @@
*/
SOCKET WINAPI WINSOCK_socket(INT af, INT type, INT protocol)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
+ struct create_socket_request *req = get_req_buffer();
TRACE("(%08x): af=%d type=%d protocol=%d\n",
(unsigned)pwsi, af, type, protocol);
if( pwsi )
{
- int sock;
-
/* check the socket family */
switch(af)
{
@@ -1796,31 +1746,27 @@
default: SetLastError(WSAEPROTOTYPE); return INVALID_SOCKET;
}
- if ((sock = socket(af, type, protocol)) >= 0)
+ req->family = af;
+ req->type = type;
+ req->protocol = protocol;
+ req->access = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE;
+ req->inherit = TRUE;
+ server_call( REQ_CREATE_SOCKET );
+ if ( req->handle >= 0)
{
- ws_socket* pnew = wsi_alloc_socket(pwsi, sock);
+ TRACE("\tcreated %04x\n", req->handle);
- TRACE("\tcreated %i (handle %04x)\n", sock, (UINT16)WS_PTR2HANDLE(pnew));
-
- if( pnew )
- {
- pnew->flags |= WS_FD_INACTIVE;
- return (SOCKET16)WS_PTR2HANDLE(pnew);
- }
-
- close(sock);
- SetLastError(WSAENOBUFS);
- return INVALID_SOCKET;
+ return req->handle;
}
- if (errno == EPERM) /* raw socket denied */
+ if (GetLastError() == WSAEACCES) /* raw socket denied */
{
if (type == SOCK_RAW)
MESSAGE("WARNING: Trying to create a socket of type SOCK_RAW, will fail unless running as root\n");
else
MESSAGE("WS_SOCKET: not enough privileges to create socket, try running as root\n");
SetLastError(WSAESOCKTNOSUPPORT);
- } else SetLastError(wsaErrno());
+ }
}
WARN("\t\tfailed!\n");
@@ -1851,7 +1797,7 @@
*/
static struct WIN_hostent* __ws_gethostbyaddr(const char *addr, int len, int type, int dup_flag)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
@@ -1889,7 +1835,7 @@
*/
static struct WIN_hostent * __ws_gethostbyname(const char *name, int dup_flag)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
@@ -1923,7 +1869,7 @@
*/
static struct WIN_protoent* __ws_getprotobyname(const char *name, int dup_flag)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
@@ -1957,7 +1903,7 @@
*/
static struct WIN_protoent* __ws_getprotobynumber(int number, int dup_flag)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
@@ -1991,7 +1937,7 @@
*/
struct WIN_servent* __ws_getservbyname(const char *name, const char *proto, int dup_flag)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
@@ -2031,7 +1977,7 @@
*/
static struct WIN_servent* __ws_getservbyport(int port, const char* proto, int dup_flag)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
@@ -2071,7 +2017,7 @@
*/
INT WINAPI WINSOCK_gethostname(char *name, INT namelen)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): name %s, len %d\n",
(unsigned)pwsi, (name)?name:NULL_STRING, namelen);
@@ -2095,267 +2041,123 @@
/* ------------------------------------- Windows sockets extensions -- *
* *
* ------------------------------------------------------------------- */
+
+int WINAPI WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEvent, LPWSANETWORKEVENTS lpEvent)
+{
+ LPWSINFO pwsi = WINSOCK_GetIData();
+ struct get_socket_event_request *req = get_req_buffer();
+
+ TRACE("(%08x): %08x, hEvent %08x, lpEvent %08x\n",
+ (unsigned)pwsi, s, hEvent, (unsigned)lpEvent );
+ if( _check_ws(pwsi, s) )
+ {
+ req->handle = s;
+ req->service = TRUE;
+ req->s_event = 0;
+ server_call( REQ_GET_SOCKET_EVENT );
+ lpEvent->lNetworkEvents = req->pmask;
+ memcpy(lpEvent->iErrorCode, req->errors, sizeof(lpEvent->iErrorCode));
+ if (hEvent)
+ ResetEvent(hEvent);
+ return 0;
+ }
+ else SetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+}
+
+int WINAPI WSAEventSelect(SOCKET s, WSAEVENT hEvent, LONG lEvent)
+{
+ LPWSINFO pwsi = WINSOCK_GetIData();
+ struct set_socket_event_request *req = get_req_buffer();
+
+ TRACE("(%08x): %08x, hEvent %08x, event %08x\n",
+ (unsigned)pwsi, s, hEvent, (unsigned)lEvent );
+ if( _check_ws(pwsi, s) )
+ {
+ req->handle = s;
+ req->mask = lEvent;
+ req->event = hEvent;
+ server_call( REQ_SET_SOCKET_EVENT );
+ return 0;
+ }
+ else SetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+}
+
/***********************************************************************
* WSAAsyncSelect() (WINSOCK.101)(WSOCK32.101)
*/
-static ws_select_op* __ws_select_list = NULL;
-
-BOOL WINSOCK_HandleIO( int* max_fd, int num_pending,
- fd_set pending_set[3], fd_set event_set[3] )
+VOID CALLBACK WINSOCK_DoAsyncEvent( ULONG_PTR ptr )
{
- /* This function is called by the event dispatcher
- * with the pending_set[] containing the result of select() and
- * the event_set[] containing all fd that are being watched */
+ /* FIXME: accepted socket uses same event object as listening socket by default
+ * (at least before a new WSAAsyncSelect is issued), must handle it somehow */
+ ws_select_info *info = (ws_select_info*)ptr;
+ struct get_socket_event_request *req = get_req_buffer();
+ unsigned int i, pmask;
- ws_select_op* psop = __ws_select_list;
- BOOL bPost = FALSE;
- DWORD dwEvent, dwErrBytes;
- int num_posted;
-
- TRACE("%i pending descriptors\n", num_pending );
-
- for( num_posted = dwEvent = 0 ; psop; psop = psop->next )
+ TRACE("socket %08x, event %08x\n", info->sock, info->event);
+ SetLastError(0);
+ req->handle = info->sock;
+ req->service = TRUE;
+ req->s_event = info->event; /* <== avoid race conditions */
+ server_call( REQ_GET_SOCKET_EVENT );
+ if ( GetLastError() == WSAEINVAL )
{
- unsigned flags = psop->pws->flags;
- int fd = psop->pws->fd;
- int r, w, e;
-
- w = 0;
- if( (r = FD_ISSET( fd, &pending_set[EVENT_IO_READ] )) ||
- (w = FD_ISSET( fd, &pending_set[EVENT_IO_WRITE] )) ||
- (e = FD_ISSET( fd, &pending_set[EVENT_IO_EXCEPT] )) )
- {
- /* This code removes WS_FD flags on one-shot events (WS_FD_CLOSE,
- * WS_FD_CONNECT), otherwise it clears descriptors in the io_set.
- * Reenabling calls turn them back on.
- */
-
- TRACE("\tchecking psop = 0x%08x\n", (unsigned) psop );
-
- num_pending--;
-
- /* Now figure out what kind of event we've got. The worst problem
- * we have to contend with is that some out of control applications
- * really want to use mutually exclusive AsyncSelect() flags all at
- * the same time.
- */
-
- if((flags & WS_FD_ACCEPT) && (flags & WS_FD_LISTENING))
- {
- /* WS_FD_ACCEPT is valid only if the socket is in the
- * listening state */
-
- FD_CLR( fd, &event_set[EVENT_IO_WRITE] );
- if( r )
- {
- FD_CLR( fd, &event_set[EVENT_IO_READ] ); /* reenabled by the next accept() */
- dwEvent = WSAMAKESELECTREPLY( WS_FD_ACCEPT, 0 );
- bPost = TRUE;
- }
- else continue;
- }
- else if( flags & WS_FD_CONNECT )
- {
- /* connecting socket */
-
- if( w || (w = FD_ISSET( fd, &pending_set[EVENT_IO_WRITE] )) )
- {
- /* ready to write means that socket is connected
- *
- * FIXME: Netscape calls AsyncSelect( s, ... WS_FD_CONNECT .. )
- * right after s = socket() and somehow "s" becomes writeable
- * before it goes through connect()!?!?
- */
-
- psop->pws->flags |= WS_FD_CONNECTED;
- psop->pws->flags &= ~(WS_FD_CONNECT | WS_FD_INACTIVE);
- dwEvent = WSAMAKESELECTREPLY( WS_FD_CONNECT, 0 );
-
- if( flags & (WS_FD_READ | WS_FD_CLOSE))
- FD_SET( fd, &event_set[EVENT_IO_READ] );
- else
- FD_CLR( fd, &event_set[EVENT_IO_READ] );
- if( flags & WS_FD_WRITE )
- FD_SET( fd, &event_set[EVENT_IO_WRITE] );
- else
- FD_CLR( fd, &event_set[EVENT_IO_WRITE] );
- bPost = TRUE;
- }
- else if( r )
- {
- /* failure - do read() to get correct errno */
-
- if( read( fd, &dwErrBytes, sizeof(dwErrBytes) ) == -1 )
- {
- dwEvent = WSAMAKESELECTREPLY( WS_FD_CONNECT, wsaErrno() );
- bPost = TRUE;
- }
- }
- /* otherwise bPost stays FALSE, should probably clear event_set */
- }
- else
- {
- /* connected socket, no WS_FD_OOB code for now. */
-
- if( flags & WS_FD_WRITE &&
- (w || (w = FD_ISSET( fd, &pending_set[EVENT_IO_WRITE] ))) )
- {
- /* this will be reenabled when send() or sendto() fail with
- * WSAEWOULDBLOCK */
-
- if( PostMessageA( psop->hWnd, psop->uMsg, (WPARAM)WS_PTR2HANDLE(psop->pws),
- (LPARAM)WSAMAKESELECTREPLY( WS_FD_WRITE, 0 ) ) )
- {
- TRACE("\t hwnd %04x - %04x, %08x\n",
- psop->hWnd, psop->uMsg, (unsigned)MAKELONG(WS_FD_WRITE, 0) );
- FD_CLR( fd, &event_set[EVENT_IO_WRITE] );
- num_posted++;
- }
- }
-
- if( r && (flags & (WS_FD_READ | WS_FD_CLOSE)) )
- {
- int val = (flags & WS_FD_RAW);
-
- /* WS_FD_RAW is set by the WSAAsyncSelect() init */
-
- bPost = TRUE;
- if( !val && ioctl( fd, FIONREAD, (char*)&dwErrBytes) == -1 )
- {
- /* weirdness */
-
- dwEvent = WSAMAKESELECTREPLY( WS_FD_READ, wsaErrno() );
- }
- else if( val || dwErrBytes )
- {
- /* got pending data, will be reenabled by recv() or recvfrom() */
-
- FD_CLR( fd, &event_set[EVENT_IO_READ] );
- dwEvent = WSAMAKESELECTREPLY( WS_FD_READ, 0 );
- }
- else
- {
- /* 0 bytes to read - connection reset by peer? */
-
- do
- val = read( fd, (char*)&dwErrBytes, sizeof(dwErrBytes));
- while( errno == EINTR );
- if( errno != EWOULDBLOCK )
- {
- switch( val )
- {
- case 0: errno = ENETDOWN; /* soft reset, fall through */
- case -1: /* hard reset */
- dwEvent = WSAMAKESELECTREPLY( WS_FD_CLOSE, wsaErrno() );
- break;
-
- default: bPost = FALSE;
- continue; /* FIXME: this is real bad */
- }
- }
- else { bPost = FALSE; continue; } /* more weirdness */
-
- /* this is it, this socket is closed */
-
- psop->pws->flags &= ~(WS_FD_READ | WS_FD_CLOSE | WS_FD_WRITE);
- FD_CLR( fd, &event_set[EVENT_IO_READ] );
- FD_CLR( fd, &event_set[EVENT_IO_WRITE] );
-
- if( *max_fd == (fd + 1) ) (*max_fd)--;
- }
- }
- }
-
- if( bPost )
- {
- TRACE("\t hwnd %04x - %04x, %08x\n",
- psop->hWnd, psop->uMsg, (unsigned)dwEvent );
- PostMessageA( psop->hWnd, psop->uMsg,
- (WPARAM)WS_PTR2HANDLE(psop->pws), (LPARAM)dwEvent );
- bPost = FALSE;
- num_posted++;
- }
- }
- if( num_pending <= 0 ) break;
+ /* orphaned event (socket closed or something) */
+ TRACE("orphaned event, self-destructing\n");
+ SERVICE_Delete( info->service );
+ WS_FREE(info);
+ return;
}
-
- TRACE("\tdone, %i posted events\n", num_posted );
- return ( num_posted ) ? TRUE : FALSE;
+ /* dispatch network events */
+ pmask = req->pmask;
+ for (i=0; i<FD_MAX_EVENTS; i++)
+ if (pmask & (1<<i)) {
+ TRACE("post: event bit %d, error %d\n", i, req->errors[i]);
+ PostMessageA(info->hWnd, info->uMsg, info->sock,
+ WSAMAKESELECTREPLY(1<<i, req->errors[i]));
+ }
}
INT WINAPI WSAAsyncSelect(SOCKET s, HWND hWnd, UINT uMsg, LONG lEvent)
{
- ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s);
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): %04x, hWnd %04x, uMsg %08x, event %08x\n",
(unsigned)pwsi, (SOCKET16)s, (HWND16)hWnd, uMsg, (unsigned)lEvent );
- if( _check_ws(pwsi, pws) )
+ if( _check_ws(pwsi, s) )
{
- ws_select_op* psop;
-
- if( (psop = pws->psop) )
- {
- /* delete previous control struct */
-
- if( psop == __ws_select_list )
- __ws_select_list = psop->next;
- else
- psop->prev->next = psop->next;
- if( psop->next ) psop->next->prev = psop->prev;
-
- if( pws->flags & (WS_FD_ACCEPT | WS_FD_CONNECT | WS_FD_READ | WS_FD_CLOSE) )
- EVENT_DeleteIO( pws->fd, EVENT_IO_READ );
- if( pws->flags & (WS_FD_CONNECT | WS_FD_WRITE) )
- EVENT_DeleteIO( pws->fd, EVENT_IO_WRITE );
-
- TRACE("\tremoving psop = 0x%08x\n", (unsigned) psop );
-
- WS_FREE( pws->psop );
- pws->flags &= ~(WS_FD_RAW | WS_FD_ACCEPT | WS_FD_CONNECT |
- WS_FD_READ | WS_FD_WRITE | WS_FD_CLOSE);
- pws->psop = NULL;
- }
-
if( lEvent )
{
- psop = (ws_select_op*)WS_ALLOC(sizeof(ws_select_op));
- if( psop )
+ ws_select_info *info = (ws_select_info*)WS_ALLOC(sizeof(ws_select_info));
+ if( info )
{
- int sock_type, bytes = sizeof(int);
-
- WINSOCK_unblock_io( pws->fd, TRUE );
-
- psop->prev = NULL;
- psop->next = __ws_select_list;
- if( __ws_select_list )
- __ws_select_list->prev = psop;
- __ws_select_list = psop;
+ HANDLE hObj = CreateEventA( NULL, FALSE, FALSE, NULL );
+ INT err;
- psop->pws = pws;
- psop->hWnd = hWnd;
- psop->uMsg = uMsg;
+ info->sock = s;
+ info->event = hObj;
+ info->hWnd = hWnd;
+ info->uMsg = uMsg;
+ info->service = SERVICE_AddObject( hObj, WINSOCK_DoAsyncEvent, (ULONG_PTR)info );
- pws->psop = psop;
- pws->flags |= (0x0000FFFF & lEvent);
- getsockopt(pws->fd, SOL_SOCKET, SO_TYPE, (void *) &sock_type, &bytes);
- if( sock_type == SOCK_RAW ) pws->flags |= WS_FD_RAW;
-
- if( lEvent & (WS_FD_ACCEPT | WS_FD_CONNECT | WS_FD_READ | WS_FD_CLOSE) )
- EVENT_AddIO( pws->fd, EVENT_IO_READ );
- if( lEvent & (WS_FD_CONNECT | WS_FD_WRITE) )
- EVENT_AddIO( pws->fd, EVENT_IO_WRITE );
-
- /* TODO: handle WS_FD_ACCEPT right away if the socket is readable */
-
- TRACE("\tcreating psop = 0x%08x\n", (unsigned)psop );
+ err = WSAEventSelect( s, hObj, lEvent | WS_FD_SERVEVENT );
+ if (err) {
+ SERVICE_Delete( info->service );
+ WS_FREE(info);
+ return err;
+ }
return 0; /* success */
}
else SetLastError(WSAENOBUFS);
}
- else return 0;
+ else
+ {
+ WSAEventSelect(s, 0, 0);
+ return 0;
+ }
}
else SetLastError(WSAEINVAL);
return SOCKET_ERROR;
@@ -2417,7 +2219,7 @@
*/
INT WINAPI WSACancelBlockingCall(void)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x)\n", (unsigned)pwsi);
@@ -2432,7 +2234,7 @@
FARPROC16 WINAPI WSASetBlockingHook16(FARPROC16 lpBlockFunc)
{
FARPROC16 prev;
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): hook %08x\n",
(unsigned)pwsi, (unsigned) lpBlockFunc);
@@ -2453,7 +2255,7 @@
FARPROC WINAPI WSASetBlockingHook(FARPROC lpBlockFunc)
{
FARPROC prev;
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x): hook %08x\n",
(unsigned)pwsi, (unsigned) lpBlockFunc);
@@ -2472,7 +2274,7 @@
*/
INT16 WINAPI WSAUnhookBlockingHook16(void)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x)\n", (unsigned)pwsi);
if( pwsi ) return (INT16)(pwsi->blocking_hook = 0);
@@ -2485,7 +2287,7 @@
*/
INT WINAPI WSAUnhookBlockingHook(void)
{
- LPWSINFO pwsi = wsi_find(GetCurrentTask());
+ LPWSINFO pwsi = WINSOCK_GetIData();
TRACE("(%08x)\n", (unsigned)pwsi);
if( pwsi )
@@ -2743,6 +2545,7 @@
{
case EINTR: return WSAEINTR;
case EBADF: return WSAEBADF;
+ case EPERM:
case EACCES: return WSAEACCES;
case EFAULT: return WSAEFAULT;
case EINVAL: return WSAEINVAL;
diff --git a/relay32/wsock32.spec b/relay32/wsock32.spec
index 9e642a2..f533bde 100644
--- a/relay32/wsock32.spec
+++ b/relay32/wsock32.spec
@@ -1,5 +1,6 @@
name wsock32
type win32
+init WSOCK32_LibMain
001 stdcall accept(long ptr ptr) WINSOCK_accept
002 stdcall bind(long ptr long) WINSOCK_bind
diff --git a/server/object.h b/server/object.h
index 2ff0f71..c678933 100644
--- a/server/object.h
+++ b/server/object.h
@@ -91,7 +91,7 @@
#define READ_EVENT 1
#define WRITE_EVENT 2
-#define EXCEPT_EVENT 3
+#define EXCEPT_EVENT 4
struct select_user
{
diff --git a/server/sock.c b/server/sock.c
index a385c52..9005d65 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -84,7 +84,10 @@
static void sock_reselect( struct sock *sock )
{
- set_select_events( &sock->select, sock_event( sock ) );
+ int ev = sock_event( sock );
+ if (debug_level)
+ fprintf(stderr,"sock_reselect(%d): new mask %x\n", sock->select.fd, ev);
+ set_select_events( &sock->select, ev );
}
inline static int sock_error(int s)
@@ -101,6 +104,8 @@
struct sock *sock = (struct sock *)private;
unsigned int emask;
assert( sock->obj.ops == &sock_ops );
+ if (debug_level)
+ fprintf(stderr, "socket %d select event: %x\n", sock->select.fd, event);
if (sock->state & WS_FD_CONNECT)
{
/* connecting */
@@ -111,6 +116,8 @@
sock->state &= ~WS_FD_CONNECT;
sock->pmask |= FD_CONNECT;
sock->errors[FD_CONNECT_BIT] = 0;
+ if (debug_level)
+ fprintf(stderr, "socket %d connection success\n", sock->select.fd);
}
else if (event & EXCEPT_EVENT)
{
@@ -118,6 +125,8 @@
sock->state &= ~WS_FD_CONNECT;
sock->pmask |= FD_CONNECT;
sock->errors[FD_CONNECT_BIT] = sock_error( sock->select.fd );
+ if (debug_level)
+ fprintf(stderr, "socket %d connection failure\n", sock->select.fd);
}
} else
if (sock->state & WS_FD_LISTENING)
@@ -151,6 +160,8 @@
sock->pmask |= FD_READ;
sock->hmask |= FD_READ;
sock->errors[FD_READ_BIT] = 0;
+ if (debug_level)
+ fprintf(stderr, "socket %d has %d bytes\n", sock->select.fd, bytes);
}
else
{
@@ -158,6 +169,8 @@
sock->state &= ~(WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE);
sock->pmask |= FD_CLOSE;
sock->errors[FD_CLOSE_BIT] = 0;
+ if (debug_level)
+ fprintf(stderr, "socket %d is closing\n", sock->select.fd);
}
}
if (event & WRITE_EVENT)
@@ -165,6 +178,8 @@
sock->pmask |= FD_WRITE;
sock->hmask |= FD_WRITE;
sock->errors[FD_WRITE_BIT] = 0;
+ if (debug_level)
+ fprintf(stderr, "socket %d is writable\n", sock->select.fd);
}
if (event & EXCEPT_EVENT)
{
@@ -174,12 +189,16 @@
/* we got an error, socket closing? */
sock->state &= ~(WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE);
sock->pmask |= FD_CLOSE;
+ if (debug_level)
+ fprintf(stderr, "socket %d aborted by error %d\n", sock->select.fd, sock->errors[FD_CLOSE_BIT]);
}
else
{
/* no error, OOB data? */
sock->pmask |= FD_OOB;
sock->hmask |= FD_OOB;
+ if (debug_level)
+ fprintf(stderr, "socket %d got OOB data\n", sock->select.fd);
}
}
}
@@ -187,8 +206,12 @@
sock_reselect( sock );
/* wake up anyone waiting for whatever just happened */
emask = sock->pmask & sock->mask;
- if (emask && sock->event)
+ if (debug_level && emask)
+ fprintf(stderr, "socket %d pending events: %x\n", sock->select.fd, emask);
+ if (emask && sock->event) {
+ if (debug_level) fprintf(stderr, "signalling event ptr %p\n", sock->event);
set_event(sock->event);
+ }
/* if anyone is stupid enough to wait on the socket object itself,
* maybe we should wake them up too, just in case? */
@@ -199,7 +222,9 @@
{
struct sock *sock = (struct sock *)obj;
assert( obj->ops == &sock_ops );
- printf( "Socket fd=%d\n", sock->select.fd );
+ printf( "Socket fd=%d, state=%x, mask=%x, pending=%x, held=%x\n",
+ sock->select.fd, sock->state,
+ sock->mask, sock->pmask, sock->hmask );
}
static int sock_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -217,7 +242,7 @@
assert( obj->ops == &sock_ops );
remove_queue( obj, entry );
- release_object( obj );
+/* release_object( obj ); */
}
static int sock_signaled( struct object *obj, struct thread *thread )
@@ -252,11 +277,11 @@
/* if the service thread was waiting for the event object,
* we should now signal it, to let the service thread
* object detect that it is now orphaned... */
- set_event( sock->event );
+ if (sock->mask & WS_FD_SERVEVENT)
+ set_event( sock->event );
/* we're through with it */
release_object( sock->event );
}
- free( sock );
}
/* create a new and unconnected socket */
@@ -274,9 +299,11 @@
sock->hmask = 0;
sock->pmask = 0;
sock->event = NULL;
- fprintf(stderr,"socket(%d,%d,%d)=%d\n",family,type,protocol,sock->select.fd);
+ if (debug_level)
+ fprintf(stderr,"socket(%d,%d,%d)=%d\n",family,type,protocol,sock->select.fd);
fcntl(sock->select.fd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
register_select_user( &sock->select );
+ sock_reselect( sock );
clear_error();
return &sock->obj;
}
@@ -313,13 +340,14 @@
acceptsock->select.fd = acceptfd;
acceptsock->select.func = sock_select_event;
- acceptsock->select.private = sock;
+ acceptsock->select.private = acceptsock;
acceptsock->state = WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE;
acceptsock->mask = sock->mask;
acceptsock->hmask = 0;
acceptsock->pmask = 0;
acceptsock->event = (struct event *)grab_object( sock->event );
register_select_user( &acceptsock->select );
+ sock_reselect( acceptsock );
clear_error();
sock->pmask &= ~FD_ACCEPT;
sock->hmask &= ~FD_ACCEPT;
@@ -424,19 +452,22 @@
{
struct sock *sock;
struct event *oevent;
+ unsigned int omask;
sock=(struct sock*)get_handle_obj(current->process,req->handle,GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops);
if (!sock)
return;
oevent = sock->event;
+ omask = sock->mask;
sock->mask = req->mask;
- sock->event = get_event_obj( current->process, req->event, GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE );
+ sock->event = get_event_obj( current->process, req->event, EVENT_MODIFY_STATE );
+ if (debug_level && sock->event) fprintf(stderr, "event ptr: %p\n", sock->event);
sock_reselect( sock );
if (sock->mask)
sock->state |= WS_FD_NONBLOCKING;
if (oevent)
{
- if (oevent != sock->event)
+ if ((oevent != sock->event) && (omask & WS_FD_SERVEVENT))
/* if the service thread was waiting for the old event object,
* we should now signal it, to let the service thread
* object detect that it is now orphaned... */
@@ -470,7 +501,7 @@
{
if (req->s_event)
{
- struct event *sevent = get_event_obj(current->process, req->s_event, GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE);
+ struct event *sevent = get_event_obj(current->process, req->s_event, 0);
if (sevent == sock->event)
req->s_event = 0;
release_object( sevent );