2 * Unit test suite for winsock functions
4 * Copyright 2002 Martin Wilck
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/test.h"
26 #include "wine/test.h"
34 #define MAX_CLIENTS 4 /* Max number of clients */
35 #define NUM_TESTS 2 /* Number of tests performed */
36 #define FIRST_CHAR 'A' /* First character in transferred pattern */
37 #define BIND_SLEEP 10 /* seconds to wait between attempts to bind() */
38 #define BIND_TRIES 6 /* Number of bind() attempts */
39 #define TEST_TIMEOUT 30 /* seconds to wait before killing child threads
40 after server initialization, if something hangs */
42 #define wsa_ok(op, cond, msg) \
46 if ( !(cond tmp) ) err = WSAGetLastError(); \
47 ok ( cond tmp, msg, GetCurrentThreadId(), err); \
51 /**************** Structs and typedefs ***************/
53 typedef struct thread_info
59 /* Information in the server about open client connections */
60 typedef struct sock_info
63 struct sockaddr_in addr;
64 struct sockaddr_in peer;
69 /* Test parameters for both server & client */
70 typedef struct test_params
81 /* server-specific test parameters */
82 typedef struct server_params
89 /* client-specific test parameters */
90 typedef struct client_params
97 /* This type combines all information for setting up a test scenario */
98 typedef struct test_setup
102 server_params srv_params;
104 client_params clt_params;
107 /* Thread local storage for server */
108 typedef struct server_memory
111 struct sockaddr_in addr;
112 sock_info sock[MAX_CLIENTS];
115 /* Thread local storage for client */
116 typedef struct client_memory
119 struct sockaddr_in addr;
124 /**************** Static variables ***************/
126 static DWORD tls; /* Thread local storage index */
127 static HANDLE thread[1+MAX_CLIENTS];
128 static DWORD thread_id[1+MAX_CLIENTS];
129 static HANDLE server_ready;
130 static HANDLE client_ready[MAX_CLIENTS];
131 static int client_id;
133 /**************** General utility functions ***************/
135 static void set_so_opentype ( BOOL overlapped )
137 int optval = !overlapped, newval, len = sizeof (int);
139 ok ( setsockopt ( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
140 (LPVOID) &optval, sizeof (optval) ) == 0,
141 "setting SO_OPENTYPE failed" );
142 ok ( getsockopt ( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
143 (LPVOID) &newval, &len ) == 0,
144 "getting SO_OPENTYPE failed" );
145 ok ( optval == newval, "failed to set SO_OPENTYPE" );
148 static int set_blocking ( SOCKET s, BOOL blocking )
150 u_long val = !blocking;
151 return ioctlsocket ( s, FIONBIO, &val );
154 static void fill_buffer ( char *buf, int chunk_size, int n_chunks )
157 for ( c = FIRST_CHAR, p = buf; c < FIRST_CHAR + n_chunks; c++, p += chunk_size )
158 memset ( p, c, chunk_size );
161 static char* test_buffer ( char *buf, int chunk_size, int n_chunks )
165 for ( c = FIRST_CHAR, p = buf; c < FIRST_CHAR + n_chunks; c++, p += chunk_size )
167 for ( i = 0; i < chunk_size; i++ )
168 if ( p[i] != c ) return p + i;
174 * This routine is called when a client / server does not expect any more data,
175 * but needs to acknowedge the closing of the connection (by reasing 0 bytes).
177 static void read_zero_bytes ( SOCKET s )
181 while ( ( tmp = recv ( s, buf, 256, 0 ) ) > 0 )
183 ok ( n <= 0, "garbage data received: %d bytes\n", n );
186 static int do_synchronous_send ( SOCKET s, char *buf, int buflen, int sendlen )
188 char* last = buf + buflen, *p;
190 for ( p = buf; n > 0 && p < last; p += n )
191 n = send ( s, p, min ( sendlen, last - p ), 0 );
192 wsa_ok ( n, 0 <=, "do_synchronous_send (%lx): error %d" );
196 static int do_synchronous_recv ( SOCKET s, char *buf, int buflen, int recvlen )
198 char* last = buf + buflen, *p;
200 for ( p = buf; n > 0 && p < last; p += n )
201 n = recv ( s, p, min ( recvlen, last - p ), 0 );
202 wsa_ok ( n, 0 <=, "do_synchronous_recv (%lx): error %d:" );
207 * Call this routine right after thread startup.
208 * SO_OPENTYPE must by 0, regardless what the server did.
210 static void check_so_opentype (void)
214 getsockopt ( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (LPVOID) &tmp, &len );
215 ok ( tmp == 0, "check_so_opentype: wrong startup value of SO_OPENTYPE: %d", tmp );
218 /**************** Server utility functions ***************/
221 * Even if we have closed our server socket cleanly,
222 * the OS may mark the address "in use" for some time -
223 * this happens with native Linux apps, too.
225 static void do_bind ( SOCKET s, struct sockaddr* addr, int addrlen )
227 int err, wsaerr = 0, n_try = BIND_TRIES;
229 while ( ( err = bind ( s, addr, addrlen ) ) != 0 &&
230 ( wsaerr = WSAGetLastError () ) == WSAEADDRINUSE &&
233 trace ( "address in use, waiting ...\n" );
234 Sleep ( 1000 * BIND_SLEEP );
236 ok ( err == 0, "failed to bind: %d\n", wsaerr );
239 static void server_start ( server_params *par )
242 test_params *gen = par->general;
243 server_memory *mem = (LPVOID) LocalAlloc ( LPTR, sizeof (server_memory));
245 TlsSetValue ( tls, mem );
246 mem->s = WSASocketA ( AF_INET, gen->sock_type, gen->sock_prot,
247 NULL, 0, par->sock_flags );
248 ok ( mem->s != INVALID_SOCKET, "Server: WSASocket failed" );
250 mem->addr.sin_family = AF_INET;
251 mem->addr.sin_addr.s_addr = inet_addr ( gen->inet_addr );
252 mem->addr.sin_port = htons ( gen->inet_port );
254 for (i = 0; i < MAX_CLIENTS; i++)
256 mem->sock[i].s = INVALID_SOCKET;
257 mem->sock[i].buf = (LPVOID) LocalAlloc ( LPTR, gen->n_chunks * gen->chunk_size );
258 mem->sock[i].nread = 0;
261 if ( gen->sock_type == SOCK_STREAM )
262 do_bind ( mem->s, (struct sockaddr*) &mem->addr, sizeof (mem->addr) );
265 static void server_stop (void)
268 server_memory *mem = TlsGetValue ( tls );
270 for (i = 0; i < MAX_CLIENTS; i++ )
272 LocalFree ( (HANDLE) mem->sock[i].buf );
273 if ( mem->sock[i].s != INVALID_SOCKET )
274 closesocket ( mem->sock[i].s );
276 ok ( closesocket ( mem->s ) == 0, "closesocket failed" );
277 LocalFree ( (HANDLE) mem );
278 ExitThread ( GetCurrentThreadId () );
281 /**************** Client utilitiy functions ***************/
283 static void client_start ( client_params *par )
285 test_params *gen = par->general;
286 client_memory *mem = (LPVOID) LocalAlloc (LPTR, sizeof (client_memory));
288 TlsSetValue ( tls, mem );
290 WaitForSingleObject ( server_ready, INFINITE );
292 mem->s = WSASocketA ( AF_INET, gen->sock_type, gen->sock_prot,
293 NULL, 0, par->sock_flags );
295 mem->addr.sin_family = AF_INET;
296 mem->addr.sin_addr.s_addr = inet_addr ( gen->inet_addr );
297 mem->addr.sin_port = htons ( gen->inet_port );
299 ok ( mem->s != INVALID_SOCKET, "Client: WSASocket failed" );
301 mem->send_buf = (LPVOID) LocalAlloc ( LPTR, 2 * gen->n_chunks * gen->chunk_size );
302 mem->recv_buf = mem->send_buf + gen->n_chunks * gen->chunk_size;
303 fill_buffer ( mem->send_buf, gen->chunk_size, gen->n_chunks );
305 SetEvent ( client_ready[client_id] );
306 /* Wait for the other clients to come up */
307 WaitForMultipleObjects ( min ( gen->n_clients, MAX_CLIENTS ), client_ready, TRUE, INFINITE );
310 static void client_stop (void)
312 client_memory *mem = TlsGetValue ( tls );
313 wsa_ok ( closesocket ( mem->s ), 0 ==, "closesocket error (%lx): %d\n" );
314 LocalFree ( (HANDLE) mem->send_buf );
315 LocalFree ( (HANDLE) mem );
319 /**************** Servers ***************/
322 * simple_server: A very basic server doing synchronous IO.
324 static VOID WINAPI simple_server ( server_params *par )
326 test_params *gen = par->general;
328 int n_recvd, n_sent, n_expected = gen->n_chunks * gen->chunk_size, tmp, i,
329 id = GetCurrentThreadId();
332 trace ( "simple_server (%x) starting\n", id );
334 set_so_opentype ( FALSE ); /* non-overlapped */
335 server_start ( par );
336 mem = TlsGetValue ( tls );
338 wsa_ok ( set_blocking ( mem->s, TRUE ), 0 ==, "simple_server (%lx): failed to set blocking mode: %d");
339 wsa_ok ( listen ( mem->s, SOMAXCONN ), 0 ==, "simple_server (%lx): listen failed: %d");
341 trace ( "simple_server (%x) ready\n", id );
342 SetEvent ( server_ready ); /* notify clients */
344 for ( i = 0; i < min ( gen->n_clients, MAX_CLIENTS ); i++ )
346 trace ( "simple_server (%x): waiting for client\n", id );
348 /* accept a single connection */
349 tmp = sizeof ( mem->sock[0].peer );
350 mem->sock[0].s = accept ( mem->s, (struct sockaddr*) &mem->sock[0].peer, &tmp );
351 wsa_ok ( mem->sock[0].s, INVALID_SOCKET !=, "simple_server (%lx): accept failed: %d" );
353 ok ( mem->sock[0].peer.sin_addr.s_addr == inet_addr ( gen->inet_addr ),
354 "simple_server (%x): strange peer address", id );
356 /* Receive data & check it */
357 n_recvd = do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen );
358 ok ( n_recvd == n_expected,
359 "simple_server (%x): received less data then expected: %d of %d", id, n_recvd, n_expected );
360 p = test_buffer ( mem->sock[0].buf, gen->chunk_size, gen->n_chunks );
361 ok ( p == NULL, "simple_server (%x): test pattern error: %d", id, p - mem->sock[0].buf);
364 n_sent = do_synchronous_send ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen );
365 ok ( n_sent == n_expected,
366 "simple_server (%x): sent less data then expected: %d of %d", id, n_sent, n_expected );
369 read_zero_bytes ( mem->sock[0].s );
370 wsa_ok ( closesocket ( mem->sock[0].s ), 0 ==, "simple_server (%lx): closesocket error: %d" );
371 mem->sock[0].s = INVALID_SOCKET;
374 trace ( "simple_server (%x) exiting\n", id );
378 /**************** Clients ***************/
381 * simple_client: A very basic client doing synchronous IO.
383 static VOID WINAPI simple_client ( client_params *par )
385 test_params *gen = par->general;
387 int n_sent, n_recvd, n_expected = gen->n_chunks * gen->chunk_size, id;
390 id = GetCurrentThreadId();
391 trace ( "simple_client (%x): starting\n", id );
392 /* wait here because we want to call set_so_opentype before creating a socket */
393 WaitForSingleObject ( server_ready, INFINITE );
394 trace ( "simple_client (%x): server ready\n", id );
396 check_so_opentype ();
397 set_so_opentype ( FALSE ); /* non-overlapped */
398 client_start ( par );
399 mem = TlsGetValue ( tls );
402 wsa_ok ( connect ( mem->s, (struct sockaddr*) &mem->addr, sizeof ( mem->addr ) ),
403 0 ==, "simple_client (%lx): connect error: %d" );
404 ok ( set_blocking ( mem->s, TRUE ) == 0,
405 "simple_client (%x): failed to set blocking mode", id );
406 trace ( "simple_client (%x) connected\n", id );
408 /* send data to server */
409 n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, par->buflen );
410 ok ( n_sent == n_expected,
411 "simple_client (%x): sent less data then expected: %d of %d", id, n_sent, n_expected );
413 /* shutdown send direction */
414 wsa_ok ( shutdown ( mem->s, SD_SEND ), 0 ==, "simple_client (%lx): shutdown failed: %d" );
416 /* Receive data echoed back & check it */
417 n_recvd = do_synchronous_recv ( mem->s, mem->recv_buf, n_expected, par->buflen );
418 ok ( n_recvd == n_expected,
419 "simple_client (%x): received less data then expected: %d of %d", id, n_recvd, n_expected );
422 p = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks );
423 ok ( p == NULL, "simple_client (%x): test pattern error: %d", id, p - mem->recv_buf);
426 read_zero_bytes ( mem->s );
427 trace ( "simple_client (%x) exiting\n", id );
432 * event_client: An event-driven client
434 static void WINAPI event_client ( client_params *par )
436 test_params *gen = par->general;
438 int id = GetCurrentThreadId(), n_expected = gen->n_chunks * gen->chunk_size,
441 WSANETWORKEVENTS wsa_events;
442 char *send_last, *recv_last, *send_p, *recv_p;
443 long mask = FD_READ | FD_WRITE | FD_CLOSE;
445 trace ( "event_client (%x): starting\n", id );
446 client_start ( par );
447 trace ( "event_client (%x): server ready\n", id );
449 mem = TlsGetValue ( tls );
451 /* Prepare event notification for connect, makes socket nonblocking */
452 event = WSACreateEvent ();
453 WSAEventSelect ( mem->s, event, FD_CONNECT );
454 tmp = connect ( mem->s, (struct sockaddr*) &mem->addr, sizeof ( mem->addr ) );
455 if ( tmp != 0 && ( err = WSAGetLastError () ) != WSAEWOULDBLOCK )
456 ok ( 0, "event_client (%x): connect error: %d", id, err );
458 tmp = WaitForSingleObject ( event, INFINITE );
459 ok ( tmp == WAIT_OBJECT_0, "event_client (%x): wait for connect event failed: %d", id, tmp );
460 err = WSAEnumNetworkEvents ( mem->s, event, &wsa_events );
461 wsa_ok ( err, 0 ==, "event_client (%lx): WSAEnumNetworkEvents error: %d\n" );
463 err = wsa_events.iErrorCode[ FD_CONNECT_BIT ];
464 ok ( err == 0, "event_client (%x): connect error: %d", id, err );
467 trace ( "event_client (%x) connected\n", id );
469 WSAEventSelect ( mem->s, event, mask );
471 recv_p = mem->recv_buf;
472 recv_last = mem->recv_buf + n_expected;
473 send_p = mem->send_buf;
474 send_last = mem->send_buf + n_expected;
478 err = WaitForSingleObject ( event, INFINITE );
479 ok ( err == WAIT_OBJECT_0, "event_client (%x): wait failed", id );
481 err = WSAEnumNetworkEvents ( mem->s, event, &wsa_events );
482 wsa_ok ( err, 0 ==, "event_client (%lx): WSAEnumNetworkEvents error: %d\n" );
484 if ( wsa_events.lNetworkEvents & FD_WRITE )
486 err = wsa_events.iErrorCode[ FD_WRITE_BIT ];
487 ok ( err == 0, "event_client (%x): FD_WRITE error code: %d\n", id, err );
492 n = send ( mem->s, send_p, min ( send_last - send_p, par->buflen ), 0 );
495 err = WSAGetLastError ();
496 ok ( err == WSAEWOULDBLOCK, "event_client (%x): send error: %d\n", id, err );
501 while ( n >= 0 && send_p < send_last );
503 if ( send_p == send_last )
505 trace ( "event_client (%x): all data sent - shutdown\n", id );
506 shutdown ( mem->s, SD_SEND );
508 WSAEventSelect ( mem->s, event, mask );
511 if ( wsa_events.lNetworkEvents & FD_READ )
513 err = wsa_events.iErrorCode[ FD_READ_BIT ];
514 ok ( err == 0, "event_client (%x): FD_READ error code: %d\n", id, err );
515 if ( err != 0 ) break;
517 /* First read must succeed */
518 n = recv ( mem->s, recv_p, min ( recv_last - recv_p, par->buflen ), 0 );
519 wsa_ok ( n, 0 <=, "event_client (%lx): recv error: %d\n" );
523 if ( recv_p == recv_last )
526 trace ( "event_client (%x): all data received\n", id );
527 WSAEventSelect ( mem->s, event, mask );
530 n = recv ( mem->s, recv_p, min ( recv_last - recv_p, par->buflen ), 0 );
531 if ( n < 0 && ( err = WSAGetLastError()) != WSAEWOULDBLOCK )
532 ok ( 0, "event_client (%x): read error: %d\n", id, err );
536 if ( wsa_events.lNetworkEvents & FD_CLOSE )
538 trace ( "event_client (%x): close event\n", id );
539 err = wsa_events.iErrorCode[ FD_CLOSE_BIT ];
540 ok ( err == 0, "event_client (%x): FD_CLOSE error code: %d\n", id, err );
545 ok ( send_p == send_last,
546 "simple_client (%x): sent less data then expected: %d of %d",
547 id, send_p - mem->send_buf, n_expected );
548 ok ( recv_p == recv_last,
549 "simple_client (%x): received less data then expected: %d of %d",
550 id, recv_p - mem->recv_buf, n_expected );
551 recv_p = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks );
552 ok ( recv_p == NULL, "event_client (%x): test pattern error: %d", id, recv_p - mem->recv_buf);
555 WSACloseEvent ( event );
556 trace ( "event_client (%x) exiting\n", id );
560 /**************** Main program utility functions ***************/
562 static void Init (void)
564 WORD ver = MAKEWORD (2, 2);
567 ok ( WSAStartup ( ver, &data ) == 0, "WSAStartup failed" );
571 static void Exit (void)
574 ok ( WSACleanup() == 0, "WSACleanup failed" );
577 static void StartServer (LPTHREAD_START_ROUTINE routine,
578 test_params *general, server_params *par)
580 par->general = general;
581 thread[0] = CreateThread ( NULL, 0, routine, par, 0, &thread_id[0] );
582 ok ( thread[0] != (HANDLE) NULL, "Failed to create server thread" );
585 static void StartClients (LPTHREAD_START_ROUTINE routine,
586 test_params *general, client_params *par)
589 par->general = general;
590 for ( i = 1; i <= min ( general->n_clients, MAX_CLIENTS ); i++ )
593 thread[i] = CreateThread ( NULL, 0, routine, par, 0, &thread_id[i] );
594 ok ( thread[i] != (HANDLE) NULL, "Failed to create client thread" );
595 /* Make sure the client is up and running */
596 WaitForSingleObject ( client_ready[client_id], INFINITE );
600 static void do_test( test_setup *test )
602 DWORD i, n = min (test->general.n_clients, MAX_CLIENTS);
605 server_ready = CreateEventA ( NULL, TRUE, FALSE, NULL );
606 for (i = 0; i <= n; i++)
607 client_ready[i] = CreateEventA ( NULL, TRUE, FALSE, NULL );
609 StartServer ( test->srv, &test->general, &test->srv_params );
610 StartClients ( test->clt, &test->general, &test->clt_params );
611 WaitForSingleObject ( server_ready, INFINITE );
613 wait = WaitForMultipleObjects ( 1 + n, thread, TRUE, 1000 * TEST_TIMEOUT );
614 ok ( wait >= WAIT_OBJECT_0 && wait <= WAIT_OBJECT_0 + n ,
615 "some threads have not completed: %lx\n", wait );
617 if ( ! ( wait >= WAIT_OBJECT_0 && wait <= WAIT_OBJECT_0 + n ) )
619 for (i = 0; i <= n; i++)
621 trace ("terminating thread %08lx\n", thread_id[i]);
622 if ( WaitForSingleObject ( thread[i], 0 ) != WAIT_OBJECT_0 )
623 TerminateThread ( thread [i], 0 );
626 CloseHandle ( server_ready );
627 for (i = 0; i <= n; i++)
628 CloseHandle ( client_ready[i] );
631 /************* Array containing the tests to run **********/
633 #define STD_STREAM_SOCKET \
639 static test_setup tests [NUM_TESTS] =
641 /* Test 0: synchronous client and server */
662 /* Test 1: event-driven client, synchronous server */
685 /**************** Main program ***************/
692 for (i = 0; i < NUM_TESTS; i++)
694 trace ( " **** STARTING TEST %d **** \n", i );
695 do_test ( &tests[i] );
696 trace ( " **** TEST %d COMPLETE **** \n", i );