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"
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) \
41 if ( !(cond tmp) ) err = WSAGetLastError(); \
42 ok ( cond tmp, msg, GetCurrentThreadId(), err); \
46 /**************** Structs and typedefs ***************/
48 typedef struct thread_info
54 /* Information in the server about open client connections */
55 typedef struct sock_info
58 struct sockaddr_in addr
;
59 struct sockaddr_in peer
;
64 /* Test parameters for both server & client */
65 typedef struct test_params
76 /* server-specific test parameters */
77 typedef struct server_params
84 /* client-specific test parameters */
85 typedef struct client_params
92 /* This type combines all information for setting up a test scenario */
93 typedef struct test_setup
97 server_params srv_params
;
99 client_params clt_params
;
102 /* Thread local storage for server */
103 typedef struct server_memory
106 struct sockaddr_in addr
;
107 sock_info sock
[MAX_CLIENTS
];
110 /* Thread local storage for client */
111 typedef struct client_memory
114 struct sockaddr_in addr
;
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
)
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
)
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
;
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
)
176 while ( ( tmp
= recv ( s
, buf
, 256, 0 ) ) > 0 )
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
;
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" );
191 static int do_synchronous_recv ( SOCKET s
, char *buf
, int buflen
, int recvlen
)
193 char* last
= buf
+ buflen
, *p
;
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:" );
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)
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
&&
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
)
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)
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
);
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
;
323 int n_recvd
, n_sent
, n_expected
= gen
->n_chunks
* gen
->chunk_size
, tmp
, i
,
324 id
= GetCurrentThreadId();
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
);
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
);
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
);
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
;
382 int n_sent
, n_recvd
, n_expected
= gen
->n_chunks
* gen
->chunk_size
, id
;
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
);
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
);
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
);
421 read_zero_bytes ( mem
->s
);
422 trace ( "simple_client (%x) exiting\n", id
);
427 * event_client: An event-driven client
429 static void WINAPI
event_client ( client_params
*par
)
431 test_params
*gen
= par
->general
;
433 int id
= GetCurrentThreadId(), n_expected
= gen
->n_chunks
* gen
->chunk_size
,
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
);
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
;
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
);
487 n
= send ( mem
->s
, send_p
, min ( send_last
- send_p
, par
->buflen
), 0 );
490 err
= WSAGetLastError ();
491 ok ( err
== WSAEWOULDBLOCK
, "event_client (%x): send error: %d\n", id
, err
);
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
);
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 )
517 ok ( 0, "event_client (%x): empty receive", id
);
522 if ( recv_p
== recv_last
)
524 trace ( "event_client (%x): all data received\n", id
);
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
);
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
);
548 WSACloseEvent ( event
);
549 trace ( "event_client (%x) exiting\n", id
);
553 /**************** Main program utility functions ***************/
555 static void Init (void)
557 WORD ver
= MAKEWORD (2, 2);
560 ok ( WSAStartup ( ver
, &data
) == 0, "WSAStartup failed" );
564 static void Exit (void)
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
)
582 par
->general
= general
;
583 for ( i
= 1; i
<= min ( general
->n_clients
, MAX_CLIENTS
); i
++ )
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
);
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 \
631 static test_setup tests
[NUM_TESTS
] =
633 /* Test 0: synchronous client and server */
654 /* Test 1: event-driven client, synchronous server */
677 /**************** Main program ***************/
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
);