winsock2 unit test update

Martin Wilck Martin.Wilck at fujitsu-siemens.com
Fri Apr 26 14:15:06 CDT 2002


A patch for the winsock 2 unit test posted yesterday.
It now has an overlapped client. If you look at the code,
it does pretty nasty things to wine, and still works :-)

BUGS: probably doesn't compile under Windows, I'm using some
gcc extensions. You just get too used to them ...

If somebody was able to port these to Windows and test the outcome I
would be really happy.

Martin

diff -ruNX ignore CVS/wine/dlls/winsock/tests/sock.c TMP/wine/dlls/winsock/tests/sock.c
--- CVS/wine/dlls/winsock/tests/sock.c	Fri Apr 26 20:58:26 2002
+++ TMP/wine/dlls/winsock/tests/sock.c	Fri Apr 26 20:56:53 2002
@@ -26,7 +26,6 @@
 #include <winsock2.h>

 #define MAX_CLIENTS 4      /* Max number of clients */
-#define NUM_TESTS   2      /* Number of tests performed */
 #define FIRST_CHAR 'A'     /* First character in transferred pattern */
 #define BIND_SLEEP 10      /* seconds to wait between attempts to bind() */
 #define BIND_TRIES 6       /* Number of bind() attempts */
@@ -86,6 +85,7 @@
     test_params   *general;
     DWORD          sock_flags;
     int            buflen;
+    int            timeout;
 } client_params;

 /* This type combines all information for setting up a test scenario */
@@ -104,6 +104,7 @@
     SOCKET                  s;
     struct sockaddr_in      addr;
     sock_info               sock[MAX_CLIENTS];
+    int                     id;
 } server_memory;

 /* Thread local storage for client */
@@ -113,6 +114,7 @@
     struct sockaddr_in      addr;
     char                   *send_buf;
     char                   *recv_buf;
+    int                     id;
 } client_memory;

 /**************** Static variables ***************/
@@ -237,6 +239,7 @@
     server_memory *mem = (LPVOID) LocalAlloc ( LPTR, sizeof (server_memory));

     TlsSetValue ( tls, mem );
+    mem->id = GetCurrentThreadId ();
     mem->s = WSASocketA ( AF_INET, gen->sock_type, gen->sock_prot,
                           NULL, 0, par->sock_flags );
     ok ( mem->s != INVALID_SOCKET, "Server: WSASocket failed" );
@@ -267,7 +270,7 @@
         if ( mem->sock[i].s != INVALID_SOCKET )
             closesocket ( mem->sock[i].s );
     }
-    ok ( closesocket ( mem->s ) == 0, "closesocket failed" );
+    ok ( closesocket ( mem->s ) == 0, "server (%x): closesocket failed", mem->id );
     LocalFree ( (HANDLE) mem );
     ExitThread ( GetCurrentThreadId () );
 }
@@ -283,6 +286,7 @@

     WaitForSingleObject ( server_ready, INFINITE );

+    mem->id = GetCurrentThreadId ();
     mem->s = WSASocketA ( AF_INET, gen->sock_type, gen->sock_prot,
                           NULL, 0, par->sock_flags );

@@ -310,6 +314,39 @@
     ExitThread ( GetCurrentThreadId () );
 }

+static SOCKET do_async_connect ( client_memory *mem )
+{
+    HANDLE event;
+    WSANETWORKEVENTS wsa_events;
+    int tmp, err;
+
+    event = WSACreateEvent ();
+
+    WSAEventSelect ( mem->s, event, FD_CONNECT );
+
+    tmp = connect ( mem->s, (struct sockaddr*) &mem->addr, sizeof ( mem->addr ) );
+    if ( tmp != 0 && ( err = WSAGetLastError () ) != WSAEWOULDBLOCK )
+        ok ( 0, "do_async_connect (%x): connect error: %d", mem->id, err );
+
+    tmp = WaitForSingleObject ( event, INFINITE );
+    ok ( tmp == WAIT_OBJECT_0,
+         "do_async_connect (%x): wait for connect event failed: %d", mem->id, tmp );
+    err = WSAEnumNetworkEvents ( mem->s, event, &wsa_events );
+    wsa_ok ( err, 0 ==, "do_async_connect (%x): WSAEnumNetworkEvents error: %d\n" );
+
+    err = wsa_events.iErrorCode[ FD_CONNECT_BIT ];
+    ok ( err == 0, "do_async_connect (%x): connect error: %d", mem->id, err );
+
+    WSAEventSelect ( mem->s, (HANDLE) 0, 0 );
+    WSACloseEvent ( event );
+
+    if ( err )
+        return INVALID_SOCKET;
+
+    trace ( "do_async_connect (%x) connected\n", mem->id );
+    return mem->s;
+}
+
 /**************** Servers ***************/

 /*
@@ -323,11 +360,10 @@
         id = GetCurrentThreadId();
     char *p;

-    trace ( "simple_server (%x) starting\n", id );
-
     set_so_opentype ( FALSE ); /* non-overlapped */
     server_start ( par );
     mem = TlsGetValue ( tls );
+    id = mem->id;

     wsa_ok ( set_blocking ( mem->s, TRUE ), 0 ==, "simple_server (%x): failed to set blocking mode: %d");
     wsa_ok ( listen ( mem->s, SOMAXCONN ), 0 ==, "simple_server (%x): listen failed: %d");
@@ -352,7 +388,8 @@
         ok ( n_recvd == n_expected,
              "simple_server (%x): received less data then expected: %d of %d", id, n_recvd, n_expected );
         p = test_buffer ( mem->sock[0].buf, gen->chunk_size, gen->n_chunks );
-        ok ( p == NULL, "simple_server (%x): test pattern error: %d", p - mem->sock[0].buf);
+        ok ( p == NULL, "simple_server (%x): test pattern error at %d; %c",
+             id, p - mem->sock[0].buf, (p ? *p : '*'));

         /* Echo data back */
         n_sent = do_synchronous_send ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen );
@@ -381,16 +418,15 @@
     int n_sent, n_recvd, n_expected = gen->n_chunks * gen->chunk_size, id;
     char *p;

-    id = GetCurrentThreadId();
-    trace ( "simple_client (%x): starting\n", id );
     /* wait here because we want to call set_so_opentype before creating a socket */
     WaitForSingleObject ( server_ready, INFINITE );
-    trace ( "simple_client (%x): server ready\n", id );

     check_so_opentype ();
     set_so_opentype ( FALSE ); /* non-overlapped */
     client_start ( par );
     mem = TlsGetValue ( tls );
+    id = mem->id;
+    trace ( "simple_client (%x) started\n", id );

     /* Connect */
     wsa_ok ( connect ( mem->s, (struct sockaddr*) &mem->addr, sizeof ( mem->addr ) ),
@@ -414,7 +450,8 @@

     /* check data */
     p = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks );
-    ok ( p == NULL, "simple_client (%x): test pattern error: %d", id, p - mem->recv_buf);
+    ok ( p == NULL, "simple_client (%x): test pattern error at %d: %c",
+         id, p - mem->recv_buf, (p ? *p : '*'));

     /* cleanup */
     read_zero_bytes ( mem->s );
@@ -429,37 +466,21 @@
 {
     test_params *gen = par->general;
     client_memory *mem;
-    int id = GetCurrentThreadId(), n_expected = gen->n_chunks * gen->chunk_size,
-        tmp, err, n;
-    HANDLE event;
+    int n_expected = gen->n_chunks * gen->chunk_size, id, err, n;
+    HANDLE event = 0;
     WSANETWORKEVENTS wsa_events;
     char *send_last, *recv_last, *send_p, *recv_p;
     long mask = FD_READ | FD_WRITE | FD_CLOSE;

-    trace ( "event_client (%x): starting\n", id );
     client_start ( par );
-    trace ( "event_client (%x): server ready\n", id );
-
     mem = TlsGetValue ( tls );
+    id = mem->id;
+    trace ( "event_client (%x) started\n", id );

-    /* Prepare event notification for connect, makes socket nonblocking */
-    event = WSACreateEvent ();
-    WSAEventSelect ( mem->s, event, FD_CONNECT );
-    tmp = connect ( mem->s, (struct sockaddr*) &mem->addr, sizeof ( mem->addr ) );
-    if ( tmp != 0 && ( err = WSAGetLastError () ) != WSAEWOULDBLOCK )
-        ok ( 0, "event_client (%x): connect error: %d", id, err );
-
-    tmp = WaitForSingleObject ( event, INFINITE );
-    ok ( tmp == WAIT_OBJECT_0, "event_client (%x): wait for connect event failed: %d", id, tmp );
-    err = WSAEnumNetworkEvents ( mem->s, event, &wsa_events );
-    wsa_ok ( err, 0 ==, "event_client (%x): WSAEnumNetworkEvents error: %d\n" );
-
-    err = wsa_events.iErrorCode[ FD_CONNECT_BIT ];
-    ok ( err == 0, "event_client (%x): connect error: %d", id, err );
-    if ( err ) goto out;
-
-    trace ( "event_client (%x) connected\n", id );
+    if ( do_async_connect ( mem ) == INVALID_SOCKET )
+        goto out;

+    event = WSACreateEvent ();
     WSAEventSelect ( mem->s, event, mask );

     recv_p = mem->recv_buf;
@@ -470,7 +491,7 @@
     while ( TRUE )
     {
         err = WaitForSingleObject ( event, INFINITE );
-        ok ( err == WAIT_OBJECT_0, "event_client (%x): wait failed", id, tmp );
+        ok ( err == WAIT_OBJECT_0, "event_client (%x): wait failed: %d", id, err );

         err = WSAEnumNetworkEvents ( mem->s, event, &wsa_events );
         wsa_ok ( err, 0 ==, "event_client (%x): WSAEnumNetworkEvents error: %d\n" );
@@ -535,20 +556,183 @@
     }

     ok ( send_p == send_last,
-         "simple_client (%x): sent less data then expected: %d of %d",
+         "event_client (%x): sent less data then expected: %d of %d",
          id, send_p - mem->send_buf, n_expected );
     ok ( recv_p == recv_last,
-         "simple_client (%x): received less data then expected: %d of %d",
+         "event_client (%x): received less data then expected: %d of %d",
          id, recv_p - mem->recv_buf, n_expected );
     recv_p = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks );
-    ok ( recv_p == NULL, "event_client (%x): test pattern error: %d", id, recv_p - mem->recv_buf);
+    ok ( recv_p == NULL, "event_client (%x): test pattern error at %d: %c",
+         id, recv_p - mem->recv_buf, (recv_p ? *recv_p : '*'));

 out:
-    WSACloseEvent ( event );
+    if ( event ) WSACloseEvent ( event );
     trace ( "event_client (%x) exiting\n", id );
     client_stop ();
 }

+/*
+ * ReadFile_client: A client using overlapped IO with ReadFile() / WriteFile()
+ */
+static void WINAPI ReadFile_client ( client_params *par )
+{
+    test_params *gen = par->general;
+    client_memory *mem;
+    int id, n_expected = gen->n_chunks * gen->chunk_size, n_requests;
+    int tmp, err, i, sent_total = 0, recvd_total = 0;
+    char *send_last, *recv_last, *send_p, *recv_p;
+    LPHANDLE event = NULL, send_event, recv_event;
+    LPOVERLAPPED send_over, recv_over;
+    LPDWORD n_sent, n_recvd;
+
+    client_start ( par );
+    mem = TlsGetValue ( tls );
+    id = mem->id;
+    trace ( "ReadFile_client (%x): started\n", id );
+
+    if ( do_async_connect ( mem ) == INVALID_SOCKET )
+        goto out;
+
+    if ( n_expected % par->buflen == 0 )
+        n_requests = n_expected / par->buflen;
+    else
+        n_requests = n_expected / par->buflen + 1;
+
+    event     = (LPVOID) LocalAlloc ( LPTR, ( 1 + 2 * n_requests ) * sizeof ( HANDLE ) );
+    send_over = (LPVOID) LocalAlloc ( LPTR, 2 * n_requests * sizeof ( OVERLAPPED ) );
+    n_sent    = (LPVOID) LocalAlloc ( LPTR, 2 * n_requests * sizeof ( DWORD ) );
+
+    send_event = event + 1;
+    recv_event = send_event + n_requests;
+    recv_over  = send_over + n_requests;
+    n_recvd = n_sent + n_requests;
+
+    event[0] = WSACreateEvent ();
+    WSAEventSelect ( mem->s, event[0], FD_CLOSE );
+
+    for ( i = 0; i < 2 * n_requests; i++ )
+        event[ 1 + i ] = CreateEventA  ( NULL, TRUE, FALSE, NULL );
+
+    /* Brutal: queue all requests right away */
+    send_last = mem->send_buf + n_expected;
+    recv_last = mem->recv_buf + n_expected;
+    for ( i = 0, send_p = mem->send_buf, recv_p = mem->recv_buf;
+          i < n_requests;
+          i++, send_p += par->buflen, recv_p += par->buflen )
+    {
+        tmp = min ( par->buflen, send_last - send_p );
+        send_over[i].hEvent = send_event[i];
+        err = WriteFile ( (HANDLE) mem->s, send_p, tmp, &n_sent[i], &send_over[i] );
+        if ( !err ) tmp = GetLastError ();
+        ok ( err == TRUE || tmp == ERROR_IO_PENDING,
+             "ReadFile_client (%x): WriteFile error: %d", id, tmp );
+
+        tmp = min ( par->buflen, recv_last - recv_p );
+        recv_over[i].hEvent = recv_event[i];
+        err = ReadFile ( (HANDLE) mem->s, recv_p, tmp, &n_recvd[i], &recv_over[i] );
+        if ( !err ) tmp = GetLastError ();
+        ok ( err == TRUE || tmp == ERROR_IO_PENDING,
+             "ReadFile_client (%x): ReadFile error: %d", id, tmp );
+    }
+    trace ( "ReadFile_client (%x): all requests queued\n", id );
+    shutdown ( mem->s, SD_SEND );
+
+    /* Wait for the FD_CLOSE event */
+    err = WaitForSingleObject ( event[0], par->timeout );
+
+    ok ( err == WAIT_OBJECT_0 || err == WAIT_TIMEOUT,
+         "ReadFile_client (%x): error waiting for FD_CLOSE: %d", id, err );
+
+    if ( err == WAIT_OBJECT_0 )
+        trace ( "ReadFile_client (%x): close event\n", id );
+    else if ( err == WAIT_TIMEOUT )
+        trace ( "ReadFile_client (%x): timeout\n", id );
+
+    /* Wait for read results only if TIMEOUT received - indicates not all data could be read */
+    for ( i = 0, recv_p = mem->recv_buf; i < n_requests; i++, recv_p += par->buflen )
+    {
+        err = GetOverlappedResult ( (HANDLE) mem->s, &send_over[i], &n_sent[i], FALSE );
+        ok ( err == TRUE, "ReadFile_client (%x): write request %d error %d",
+             id, i, GetLastError () );
+        sent_total += n_sent[i];
+
+        err = GetOverlappedResult ( (HANDLE) mem->s, &recv_over[i], &n_recvd[i], err == WAIT_TIMEOUT );
+        ok ( err == TRUE, "ReadFile_client (%x): read request %d error %d",
+             id, i, GetLastError () );
+
+        /* If a read did not get all requested bytes, rearrange data */
+        if ( mem->recv_buf + recvd_total < recv_p )
+            memmove ( mem->recv_buf + recvd_total, recv_p, n_recvd[i] );
+        recvd_total += n_recvd[i];
+    }
+
+    /* Try to read remaining data, if any */
+    while ( recvd_total < n_expected )
+    {
+        trace ( "ReadFile_client (%x): %d bytes missing, retrying ...\n", id, n_expected - recvd_total );
+        recv_p = mem->recv_buf + recvd_total;
+        ResetEvent ( recv_over[0].hEvent );
+        err = ReadFile ( (HANDLE) mem->s, recv_p, recv_last - recv_p, &n_recvd[0], &recv_over[0] );
+        if ( err == FALSE )
+        {
+            err = GetLastError ();
+            ok ( err == ERROR_IO_PENDING, "ReadFile_client (%x): ReadFile(2) error: %d", id, err );
+            if ( err != ERROR_IO_PENDING ) break;
+            err = GetOverlappedResult ( (HANDLE) mem->s, &recv_over[0], &n_recvd[0], TRUE );
+            ok ( err == TRUE, "ReadFile_client (%x): read request error %d",
+                 id, GetLastError () );
+            if ( err == FALSE ) break;
+            if ( n_recvd[0] == 0 )
+            {
+                trace ( "ReadFile_client (%x): empty receive (overlapped)\n", id );
+                break;
+            }
+            recvd_total += n_recvd[0];
+        }
+        else
+        {
+            if ( n_recvd[0] == 0 )
+            {
+                trace ( "ReadFile_client (%x): empty receive (immediate)\n", id );
+                break;
+            }
+            recvd_total += n_recvd[0];
+        }
+    }
+
+    /* Wait for the FD_CLOSE event again - it should be signalled now */
+    err = WaitForSingleObject ( event[0], par->timeout );
+
+    ok ( err == WAIT_OBJECT_0,
+         "ReadFile_client (%x): error waiting for FD_CLOSE: %d", id, err );
+    if ( err == WAIT_OBJECT_0 )
+        trace ( "ReadFile_client (%x): close event (2)\n" );
+
+    /* Check IO results */
+    ok ( sent_total == n_expected,
+         "ReadFile_client (%x): sent less data then expected: %d of %d",
+         id, sent_total, n_expected );
+
+    ok ( recvd_total == n_expected,
+         "ReadFile_client (%x): received less data then expected: %d of %d",
+         id, recvd_total, n_expected );
+
+    recv_p = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks );
+    ok ( recv_p == NULL,
+         "ReadFile_client (%x): test pattern error at %d: %c",
+         id, recv_p - mem->recv_buf, (recv_p ? *recv_p : '*'));
+
+    for (i = 0; i < 1 + 2 * n_requests; i++)
+        WSACloseEvent ( event[i] );
+
+    LocalFree ( (HANDLE)event );
+    LocalFree ( (HANDLE)send_over );
+    LocalFree ( (HANDLE)n_sent );
+out:
+    trace ( "ReadFile_client (%x) exiting\n", id );
+    client_stop ();
+}
+
 /**************** Main program utility functions ***************/

 static void Init (void)
@@ -627,7 +811,7 @@
             inet_addr:   "127.0.0.1", \
             inet_port:   9374

-static test_setup tests [NUM_TESTS] =
+static test_setup tests [] =
 {
     /* Test 0: synchronous client and server */
     {
@@ -662,6 +846,25 @@
         clt_params: {
             buflen:      128
         }
+    },
+    /* Test 2: ReadFile() overlapped client, synchronous server */
+    {
+        general: {
+            STD_STREAM_SOCKET,
+            chunk_size: 2084,
+            n_chunks:  16,
+            n_clients: 2
+        },
+        srv: simple_server,
+        srv_params: {
+            buflen:      64
+        },
+        clt: ReadFile_client,
+        clt_params: {
+            sock_flags:  WSA_FLAG_OVERLAPPED,
+            buflen:      128,
+            timeout:     1000
+        }
     }
 };

@@ -670,9 +873,10 @@
 START_TEST( sock )
 {
     int i;
-    Init();
+    int n_tests = sizeof (tests) / sizeof (test_setup);

-    for (i = 0; i < NUM_TESTS; i++)
+    Init();
+    for (i = 0; i < n_tests; i++)
     {
         trace ( " **** STARTING TEST %d **** \n", i );
         do_test (  &tests[i] );







More information about the wine-devel mailing list