Moved a large number of 16-bit functions to a separate gdi16.c file.
[wine/hacks.git] / dlls / winsock / tests / sock.c
blobf1dcdd44891d363dc6be0618f7be80c28e5ec28b
1 /*
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
21 #include "wine/test.h"
22 #include <winbase.h>
23 #include <winnt.h>
24 #include <winerror.h>
25 #undef USE_WS_PREFIX
26 #include <winsock2.h>
27 #include <mswsock.h>
29 #define MAX_CLIENTS 4 /* Max number of clients */
30 #define NUM_TESTS 2 /* Number of tests performed */
31 #define FIRST_CHAR 'A' /* First character in transferred pattern */
32 #define BIND_SLEEP 10 /* seconds to wait between attempts to bind() */
33 #define BIND_TRIES 6 /* Number of bind() attempts */
34 #define TEST_TIMEOUT 30 /* seconds to wait before killing child threads
35 after server initialization, if something hangs */
37 #define wsa_ok(op, cond, msg) \
38 do { \
39 int tmp, err = 0; \
40 tmp = op; \
41 if ( !(cond tmp) ) err = WSAGetLastError(); \
42 ok ( cond tmp, msg, GetCurrentThreadId(), err); \
43 } while (0);
46 /**************** Structs and typedefs ***************/
48 typedef struct thread_info
50 HANDLE thread;
51 DWORD id;
52 } thread_info;
54 /* Information in the server about open client connections */
55 typedef struct sock_info
57 SOCKET s;
58 struct sockaddr_in addr;
59 struct sockaddr_in peer;
60 char *buf;
61 int nread;
62 } sock_info;
64 /* Test parameters for both server & client */
65 typedef struct test_params
67 int sock_type;
68 int sock_prot;
69 char *inet_addr;
70 int inet_port;
71 int chunk_size;
72 int n_chunks;
73 int n_clients;
74 } test_params;
76 /* server-specific test parameters */
77 typedef struct server_params
79 test_params *general;
80 DWORD sock_flags;
81 int buflen;
82 } server_params;
84 /* client-specific test parameters */
85 typedef struct client_params
87 test_params *general;
88 DWORD sock_flags;
89 int buflen;
90 } client_params;
92 /* This type combines all information for setting up a test scenario */
93 typedef struct test_setup
95 test_params general;
96 LPVOID srv;
97 server_params srv_params;
98 LPVOID clt;
99 client_params clt_params;
100 } test_setup;
102 /* Thread local storage for server */
103 typedef struct server_memory
105 SOCKET s;
106 struct sockaddr_in addr;
107 sock_info sock[MAX_CLIENTS];
108 } server_memory;
110 /* Thread local storage for client */
111 typedef struct client_memory
113 SOCKET s;
114 struct sockaddr_in addr;
115 char *send_buf;
116 char *recv_buf;
117 } client_memory;
119 /**************** Static variables ***************/
121 static DWORD tls; /* Thread local storage index */
122 static HANDLE thread[1+MAX_CLIENTS];
123 static DWORD thread_id[1+MAX_CLIENTS];
124 static HANDLE server_ready;
125 static HANDLE client_ready[MAX_CLIENTS];
126 static int client_id;
128 /**************** General utility functions ***************/
130 static void set_so_opentype ( BOOL overlapped )
132 int optval = !overlapped, newval, len = sizeof (int);
134 ok ( setsockopt ( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
135 (LPVOID) &optval, sizeof (optval) ) == 0,
136 "setting SO_OPENTYPE failed" );
137 ok ( getsockopt ( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
138 (LPVOID) &newval, &len ) == 0,
139 "getting SO_OPENTYPE failed" );
140 ok ( optval == newval, "failed to set SO_OPENTYPE" );
143 static int set_blocking ( SOCKET s, BOOL blocking )
145 u_long val = !blocking;
146 return ioctlsocket ( s, FIONBIO, &val );
149 static void fill_buffer ( char *buf, int chunk_size, int n_chunks )
151 char c, *p;
152 for ( c = FIRST_CHAR, p = buf; c < FIRST_CHAR + n_chunks; c++, p += chunk_size )
153 memset ( p, c, chunk_size );
156 static char* test_buffer ( char *buf, int chunk_size, int n_chunks )
158 char c, *p;
159 int i;
160 for ( c = FIRST_CHAR, p = buf; c < FIRST_CHAR + n_chunks; c++, p += chunk_size )
162 for ( i = 0; i < chunk_size; i++ )
163 if ( p[i] != c ) return p + i;
165 return NULL;
169 * This routine is called when a client / server does not expect any more data,
170 * but needs to acknowedge the closing of the connection (by reasing 0 bytes).
172 static void read_zero_bytes ( SOCKET s )
174 char buf[256];
175 int tmp, n = 0;
176 while ( ( tmp = recv ( s, buf, 256, 0 ) ) > 0 )
177 n += tmp;
178 ok ( n <= 0, "garbage data received: %d bytes\n", n );
181 static int do_synchronous_send ( SOCKET s, char *buf, int buflen, int sendlen )
183 char* last = buf + buflen, *p;
184 int n = 1;
185 for ( p = buf; n > 0 && p < last; p += n )
186 n = send ( s, p, min ( sendlen, last - p ), 0 );
187 wsa_ok ( n, 0 <=, "do_synchronous_send (%lx): error %d" );
188 return p - buf;
191 static int do_synchronous_recv ( SOCKET s, char *buf, int buflen, int recvlen )
193 char* last = buf + buflen, *p;
194 int n = 1;
195 for ( p = buf; n > 0 && p < last; p += n )
196 n = recv ( s, p, min ( recvlen, last - p ), 0 );
197 wsa_ok ( n, 0 <=, "do_synchronous_recv (%lx): error %d:" );
198 return p - buf;
202 * Call this routine right after thread startup.
203 * SO_OPENTYPE must by 0, regardless what the server did.
205 static void check_so_opentype (void)
207 int tmp = 1, len;
208 len = sizeof (tmp);
209 getsockopt ( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (LPVOID) &tmp, &len );
210 ok ( tmp == 0, "check_so_opentype: wrong startup value of SO_OPENTYPE: %d", tmp );
213 /**************** Server utility functions ***************/
216 * Even if we have closed our server socket cleanly,
217 * the OS may mark the address "in use" for some time -
218 * this happens with native Linux apps, too.
220 static void do_bind ( SOCKET s, struct sockaddr* addr, int addrlen )
222 int err, wsaerr = 0, n_try = BIND_TRIES;
224 while ( ( err = bind ( s, addr, addrlen ) ) != 0 &&
225 ( wsaerr = WSAGetLastError () ) == WSAEADDRINUSE &&
226 n_try-- >= 0)
228 trace ( "address in use, waiting ...\n" );
229 Sleep ( 1000 * BIND_SLEEP );
231 ok ( err == 0, "failed to bind: %d\n", wsaerr );
234 static void server_start ( server_params *par )
236 int i;
237 test_params *gen = par->general;
238 server_memory *mem = (LPVOID) LocalAlloc ( LPTR, sizeof (server_memory));
240 TlsSetValue ( tls, mem );
241 mem->s = WSASocketA ( AF_INET, gen->sock_type, gen->sock_prot,
242 NULL, 0, par->sock_flags );
243 ok ( mem->s != INVALID_SOCKET, "Server: WSASocket failed" );
245 mem->addr.sin_family = AF_INET;
246 mem->addr.sin_addr.s_addr = inet_addr ( gen->inet_addr );
247 mem->addr.sin_port = htons ( gen->inet_port );
249 for (i = 0; i < MAX_CLIENTS; i++)
251 mem->sock[i].s = INVALID_SOCKET;
252 mem->sock[i].buf = (LPVOID) LocalAlloc ( LPTR, gen->n_chunks * gen->chunk_size );
253 mem->sock[i].nread = 0;
256 if ( gen->sock_type == SOCK_STREAM )
257 do_bind ( mem->s, (struct sockaddr*) &mem->addr, sizeof (mem->addr) );
260 static void server_stop (void)
262 int i;
263 server_memory *mem = TlsGetValue ( tls );
265 for (i = 0; i < MAX_CLIENTS; i++ )
267 LocalFree ( (HANDLE) mem->sock[i].buf );
268 if ( mem->sock[i].s != INVALID_SOCKET )
269 closesocket ( mem->sock[i].s );
271 ok ( closesocket ( mem->s ) == 0, "closesocket failed" );
272 LocalFree ( (HANDLE) mem );
273 ExitThread ( GetCurrentThreadId () );
276 /**************** Client utilitiy functions ***************/
278 static void client_start ( client_params *par )
280 test_params *gen = par->general;
281 client_memory *mem = (LPVOID) LocalAlloc (LPTR, sizeof (client_memory));
283 TlsSetValue ( tls, mem );
285 WaitForSingleObject ( server_ready, INFINITE );
287 mem->s = WSASocketA ( AF_INET, gen->sock_type, gen->sock_prot,
288 NULL, 0, par->sock_flags );
290 mem->addr.sin_family = AF_INET;
291 mem->addr.sin_addr.s_addr = inet_addr ( gen->inet_addr );
292 mem->addr.sin_port = htons ( gen->inet_port );
294 ok ( mem->s != INVALID_SOCKET, "Client: WSASocket failed" );
296 mem->send_buf = (LPVOID) LocalAlloc ( LPTR, 2 * gen->n_chunks * gen->chunk_size );
297 mem->recv_buf = mem->send_buf + gen->n_chunks * gen->chunk_size;
298 fill_buffer ( mem->send_buf, gen->chunk_size, gen->n_chunks );
300 SetEvent ( client_ready[client_id] );
301 /* Wait for the other clients to come up */
302 WaitForMultipleObjects ( min ( gen->n_clients, MAX_CLIENTS ), client_ready, TRUE, INFINITE );
305 static void client_stop (void)
307 client_memory *mem = TlsGetValue ( tls );
308 wsa_ok ( closesocket ( mem->s ), 0 ==, "closesocket error (%lx): %d\n" );
309 LocalFree ( (HANDLE) mem->send_buf );
310 LocalFree ( (HANDLE) mem );
311 ExitThread(0);
314 /**************** Servers ***************/
317 * simple_server: A very basic server doing synchronous IO.
319 static VOID WINAPI simple_server ( server_params *par )
321 test_params *gen = par->general;
322 server_memory *mem;
323 int n_recvd, n_sent, n_expected = gen->n_chunks * gen->chunk_size, tmp, i,
324 id = GetCurrentThreadId();
325 char *p;
327 trace ( "simple_server (%x) starting\n", id );
329 set_so_opentype ( FALSE ); /* non-overlapped */
330 server_start ( par );
331 mem = TlsGetValue ( tls );
333 wsa_ok ( set_blocking ( mem->s, TRUE ), 0 ==, "simple_server (%lx): failed to set blocking mode: %d");
334 wsa_ok ( listen ( mem->s, SOMAXCONN ), 0 ==, "simple_server (%lx): listen failed: %d");
336 trace ( "simple_server (%x) ready\n", id );
337 SetEvent ( server_ready ); /* notify clients */
339 for ( i = 0; i < min ( gen->n_clients, MAX_CLIENTS ); i++ )
341 trace ( "simple_server (%x): waiting for client\n", id );
343 /* accept a single connection */
344 tmp = sizeof ( mem->sock[0].peer );
345 mem->sock[0].s = accept ( mem->s, (struct sockaddr*) &mem->sock[0].peer, &tmp );
346 wsa_ok ( mem->sock[0].s, INVALID_SOCKET !=, "simple_server (%lx): accept failed: %d" );
348 ok ( mem->sock[0].peer.sin_addr.s_addr == inet_addr ( gen->inet_addr ),
349 "simple_server (%x): strange peer address", id );
351 /* Receive data & check it */
352 n_recvd = do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen );
353 ok ( n_recvd == n_expected,
354 "simple_server (%x): received less data then expected: %d of %d", id, n_recvd, n_expected );
355 p = test_buffer ( mem->sock[0].buf, gen->chunk_size, gen->n_chunks );
356 ok ( p == NULL, "simple_server (%x): test pattern error: %d", id, p - mem->sock[0].buf);
358 /* Echo data back */
359 n_sent = do_synchronous_send ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen );
360 ok ( n_sent == n_expected,
361 "simple_server (%x): sent less data then expected: %d of %d", id, n_sent, n_expected );
363 /* cleanup */
364 read_zero_bytes ( mem->sock[0].s );
365 wsa_ok ( closesocket ( mem->sock[0].s ), 0 ==, "simple_server (%lx): closesocket error: %d" );
366 mem->sock[0].s = INVALID_SOCKET;
369 trace ( "simple_server (%x) exiting\n", id );
370 server_stop ();
373 /**************** Clients ***************/
376 * simple_client: A very basic client doing synchronous IO.
378 static VOID WINAPI simple_client ( client_params *par )
380 test_params *gen = par->general;
381 client_memory *mem;
382 int n_sent, n_recvd, n_expected = gen->n_chunks * gen->chunk_size, id;
383 char *p;
385 id = GetCurrentThreadId();
386 trace ( "simple_client (%x): starting\n", id );
387 /* wait here because we want to call set_so_opentype before creating a socket */
388 WaitForSingleObject ( server_ready, INFINITE );
389 trace ( "simple_client (%x): server ready\n", id );
391 check_so_opentype ();
392 set_so_opentype ( FALSE ); /* non-overlapped */
393 client_start ( par );
394 mem = TlsGetValue ( tls );
396 /* Connect */
397 wsa_ok ( connect ( mem->s, (struct sockaddr*) &mem->addr, sizeof ( mem->addr ) ),
398 0 ==, "simple_client (%lx): connect error: %d" );
399 ok ( set_blocking ( mem->s, TRUE ) == 0,
400 "simple_client (%x): failed to set blocking mode", id );
401 trace ( "simple_client (%x) connected\n", id );
403 /* send data to server */
404 n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, par->buflen );
405 ok ( n_sent == n_expected,
406 "simple_client (%x): sent less data then expected: %d of %d", id, n_sent, n_expected );
408 /* shutdown send direction */
409 wsa_ok ( shutdown ( mem->s, SD_SEND ), 0 ==, "simple_client (%lx): shutdown failed: %d" );
411 /* Receive data echoed back & check it */
412 n_recvd = do_synchronous_recv ( mem->s, mem->recv_buf, n_expected, par->buflen );
413 ok ( n_recvd == n_expected,
414 "simple_client (%x): received less data then expected: %d of %d", id, n_recvd, n_expected );
416 /* check data */
417 p = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks );
418 ok ( p == NULL, "simple_client (%x): test pattern error: %d", id, p - mem->recv_buf);
420 /* cleanup */
421 read_zero_bytes ( mem->s );
422 trace ( "simple_client (%x) exiting\n", id );
423 client_stop ();
427 * event_client: An event-driven client
429 static void WINAPI event_client ( client_params *par )
431 test_params *gen = par->general;
432 client_memory *mem;
433 int id = GetCurrentThreadId(), n_expected = gen->n_chunks * gen->chunk_size,
434 tmp, err, n;
435 HANDLE event;
436 WSANETWORKEVENTS wsa_events;
437 char *send_last, *recv_last, *send_p, *recv_p;
438 long mask = FD_READ | FD_WRITE | FD_CLOSE;
440 trace ( "event_client (%x): starting\n", id );
441 client_start ( par );
442 trace ( "event_client (%x): server ready\n", id );
444 mem = TlsGetValue ( tls );
446 /* Prepare event notification for connect, makes socket nonblocking */
447 event = WSACreateEvent ();
448 WSAEventSelect ( mem->s, event, FD_CONNECT );
449 tmp = connect ( mem->s, (struct sockaddr*) &mem->addr, sizeof ( mem->addr ) );
450 if ( tmp != 0 && ( err = WSAGetLastError () ) != WSAEWOULDBLOCK )
451 ok ( 0, "event_client (%x): connect error: %d", id, err );
453 tmp = WaitForSingleObject ( event, INFINITE );
454 ok ( tmp == WAIT_OBJECT_0, "event_client (%x): wait for connect event failed: %d", id, tmp );
455 err = WSAEnumNetworkEvents ( mem->s, event, &wsa_events );
456 wsa_ok ( err, 0 ==, "event_client (%lx): WSAEnumNetworkEvents error: %d\n" );
458 err = wsa_events.iErrorCode[ FD_CONNECT_BIT ];
459 ok ( err == 0, "event_client (%x): connect error: %d", id, err );
460 if ( err ) goto out;
462 trace ( "event_client (%x) connected\n", id );
464 WSAEventSelect ( mem->s, event, mask );
466 recv_p = mem->recv_buf;
467 recv_last = mem->recv_buf + n_expected;
468 send_p = mem->send_buf;
469 send_last = mem->send_buf + n_expected;
471 while ( TRUE )
473 err = WaitForSingleObject ( event, INFINITE );
474 ok ( err == WAIT_OBJECT_0, "event_client (%x): wait failed", id );
476 err = WSAEnumNetworkEvents ( mem->s, event, &wsa_events );
477 wsa_ok ( err, 0 ==, "event_client (%lx): WSAEnumNetworkEvents error: %d\n" );
479 if ( wsa_events.lNetworkEvents & FD_WRITE )
481 err = wsa_events.iErrorCode[ FD_WRITE_BIT ];
482 ok ( err == 0, "event_client (%x): FD_WRITE error code: %d\n", id, err );
484 if ( err== 0 )
487 n = send ( mem->s, send_p, min ( send_last - send_p, par->buflen ), 0 );
488 if ( n < 0 )
490 err = WSAGetLastError ();
491 ok ( err == WSAEWOULDBLOCK, "event_client (%x): send error: %d\n", id, err );
493 else
494 send_p += n;
496 while ( n >= 0 && send_p < send_last );
498 if ( send_p == send_last )
500 trace ( "event_client (%x): all data sent - shutdown\n", id );
501 shutdown ( mem->s, SD_SEND );
502 mask &= ~FD_WRITE;
503 WSAEventSelect ( mem->s, event, mask );
506 else if ( wsa_events.lNetworkEvents & FD_READ )
508 err = wsa_events.iErrorCode[ FD_READ_BIT ];
509 ok ( err == 0, "event_client (%x): FD_READ error code: %d\n", id, err );
511 n = recv ( mem->s, recv_p, min ( recv_last - recv_p, par->buflen ), 0 );
512 wsa_ok ( n, 0 <=, "event_client (%lx): recv error: %d\n" );
513 if ( err != 0 || n < 0 )
514 break;
515 else if ( n == 0 )
517 ok ( 0, "event_client (%x): empty receive", id );
518 break;
521 recv_p += n;
522 if ( recv_p == recv_last )
524 trace ( "event_client (%x): all data received\n", id );
525 mask &= ~FD_READ;
526 WSAEventSelect ( mem->s, event, mask );
529 else if ( wsa_events.lNetworkEvents & FD_CLOSE )
531 trace ( "event_client (%x): close event\n", id );
532 err = wsa_events.iErrorCode[ FD_CLOSE_BIT ];
533 ok ( err == 0, "event_client (%x): FD_CLOSE error code: %d\n", id, err );
534 break;
538 ok ( send_p == send_last,
539 "simple_client (%x): sent less data then expected: %d of %d",
540 id, send_p - mem->send_buf, n_expected );
541 ok ( recv_p == recv_last,
542 "simple_client (%x): received less data then expected: %d of %d",
543 id, recv_p - mem->recv_buf, n_expected );
544 recv_p = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks );
545 ok ( recv_p == NULL, "event_client (%x): test pattern error: %d", id, recv_p - mem->recv_buf);
547 out:
548 WSACloseEvent ( event );
549 trace ( "event_client (%x) exiting\n", id );
550 client_stop ();
553 /**************** Main program utility functions ***************/
555 static void Init (void)
557 WORD ver = MAKEWORD (2, 2);
558 WSADATA data;
560 ok ( WSAStartup ( ver, &data ) == 0, "WSAStartup failed" );
561 tls = TlsAlloc();
564 static void Exit (void)
566 TlsFree ( tls );
567 ok ( WSACleanup() == 0, "WSACleanup failed" );
570 static void StartServer (LPTHREAD_START_ROUTINE routine,
571 test_params *general, server_params *par)
573 par->general = general;
574 thread[0] = CreateThread ( NULL, 0, routine, par, 0, &thread_id[0] );
575 ok ( thread[0] != (HANDLE) NULL, "Failed to create server thread" );
578 static void StartClients (LPTHREAD_START_ROUTINE routine,
579 test_params *general, client_params *par)
581 int i;
582 par->general = general;
583 for ( i = 1; i <= min ( general->n_clients, MAX_CLIENTS ); i++ )
585 client_id = i - 1;
586 thread[i] = CreateThread ( NULL, 0, routine, par, 0, &thread_id[i] );
587 ok ( thread[i] != (HANDLE) NULL, "Failed to create client thread" );
588 /* Make sure the client is up and running */
589 WaitForSingleObject ( client_ready[client_id], INFINITE );
593 static void do_test( test_setup *test )
595 int i, n = min (test->general.n_clients, MAX_CLIENTS);
596 int wait;
598 server_ready = CreateEventA ( NULL, TRUE, FALSE, NULL );
599 for (i = 0; i <= n; i++)
600 client_ready[i] = CreateEventA ( NULL, TRUE, FALSE, NULL );
602 StartServer ( test->srv, &test->general, &test->srv_params );
603 StartClients ( test->clt, &test->general, &test->clt_params );
604 WaitForSingleObject ( server_ready, INFINITE );
606 wait = WaitForMultipleObjects ( 1 + n, thread, TRUE, 1000 * TEST_TIMEOUT );
607 ok ( wait == WAIT_OBJECT_0, "some threads have not completed\n" );
609 if ( wait == WAIT_TIMEOUT )
611 for (i = 0; i <= n; i++)
613 trace ("terminating thread %08lx\n", thread_id[i]);
614 if ( WaitForSingleObject ( thread[i], 0 ) != WAIT_OBJECT_0 )
615 TerminateThread ( thread [i], 0 );
618 CloseHandle ( server_ready );
619 for (i = 0; i <= n; i++)
620 CloseHandle ( client_ready[i] );
623 /************* Array containing the tests to run **********/
625 #define STD_STREAM_SOCKET \
626 SOCK_STREAM, \
627 0, \
628 "127.0.0.1", \
629 9374
631 static test_setup tests [NUM_TESTS] =
633 /* Test 0: synchronous client and server */
636 STD_STREAM_SOCKET,
637 2048,
641 simple_server,
643 NULL,
647 simple_client,
649 NULL,
654 /* Test 1: event-driven client, synchronous server */
657 STD_STREAM_SOCKET,
658 2048,
662 simple_server,
664 NULL,
668 event_client,
670 NULL,
677 /**************** Main program ***************/
679 START_TEST( sock )
681 int i;
682 Init();
684 for (i = 0; i < NUM_TESTS; i++)
686 trace ( " **** STARTING TEST %d **** \n", i );
687 do_test ( &tests[i] );
688 trace ( " **** TEST %d COMPLETE **** \n", i );
691 Exit();