1 cs130_ryutaro 1.4 #include <stdio.h>
2 #include "winsock2.h"
3 #include "windows.h"
4
5 #include <wine/test.h>
6 #include <winbase.h>
7
8 /* The #pragma directives offer a way for each compiler to offer machine-
9 and operating-system-specific features while retaining overall
10 compatibility with the C and C++ languages.
11 The next line places a library-search record, ws2_32, in the object file. */
12 // #pragma comment ( lib, "ws2_32" )
13
14 /* constants */
15 #define ASYNC_EVENT (WM_USER +5) // the message we'll use for our async notification
16 #define PORT_NUM 27015
17 #define PACKET_SZ 32
18 #define FILE_SZ 100
19 #define SERVER_START_TIME 3000
20 #define MAX_WAIT_TIME 30000 // 30 seconds expressed in milliseconds
21 #define NUM_THREADS_TO_WAIT 2
22 cs130_ryutaro 1.4
23 enum // define all the exit codes for a thread
24 {
25 TH_START_ERROR = 1001,
26 TH_SOCKET_ERROR,
27 TH_SOCKADDR_ERROR,
28 TH_BIND_ERROR,
29 TH_CONNECT_ERROR,
30 TH_LISTEN_ERROR,
31 TH_ACCEPT_ERROR,
32 TH_SELECT_ERROR,
33 TH_RECV_ERROR,
34 TH_SEND_ERROR,
35 TH_WINDOW_ERROR,
36 TH_MSG_ERROR
37
38 } ThreadExitCodes;
39
40 /* static func prototypes */
41 static int WSAStartup_w( WORD wVersionRequired, LPWSADATA lpWSAData );
42 static SOCKET socket_w( int af, int type, int protocol );
43 cs130_ryutaro 1.4 static LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
44 static HWND WineCreateWindow( HINSTANCE hInstance);
45 static void WineThreadCleanUp();
46 static void WineCreateFile();
47 static DWORD WINAPI WineRunServer();
48 static DWORD WINAPI WineRunClient();
49
50 /* struct def */
51 typedef struct
52 {
53 DWORD id;
54 HANDLE handle;
55 int bytesRecvd;
56 int bytesSent;
57 char packet[PACKET_SZ];
58 } thread_t;
59
60 /* global vars */
61 static char FileBuf[FILE_SZ];
62 static thread_t ServerThread;
63 static thread_t ClientThread;
64 cs130_ryutaro 1.4
65 /*
66 Wrapper for WSAStartup().
67 The WSAStartup function must be the first Windows Sockets function
68 called by an application or DLL. It allows an application or DLL to
69 specify the version of Windows Sockets required and retrieve details
70 of the specific Windows Sockets implementation.
71
72 Paremeters:
73 wVersionRequested
74 [in] Highest version of Windows Sockets support that the caller can use.
75 The high-order byte specifies the minor version (revision) number;
76 the low-order byte specifies the major version number.
77 lpWSAData
78 [out] Pointer to the WSADATA data structure that is to receive details of
79 the Windows Sockets implementation.
80
81 Error code | Meaning
82 WSASYSNOTREADY | Indicates that the underlying network subsystem is
83 not ready for network communication.
84 WSAVERNOTSUPPORTED | The version of Windows Sockets support requested is
85 cs130_ryutaro 1.4 not provided by this particular Windows Sockets
86 implementation.
87 WSAEINPROGRESS | A blocking Windows Sockets 1.1 operation is in progress.
88 WSAEPROCLIM | Limit on the number of tasks supported by the Windows
89 Sockets implementation has been reached.
90 WSAEFAULT | The lpWSAData is not a valid pointer.
91 */
92 static int WSAStartup_w( WORD wVersionRequired, LPWSADATA lpWSAData )
93 {
94 int errCode = 0;
95
96 // WSAVERNOTSUPPORTED test
97 WSADATA tmpLpWSAData;
98 errCode = WSAStartup( MAKEWORD( 0, 0 ), &tmpLpWSAData );
99 if( errCode != WSAVERNOTSUPPORTED ) {
100
101 // print out the Error Code to be thorough
102 trace( "WSAVERNOTSUPPORTED test failed with error code: %d\n", errCode );
103 errCode = 0;
104 }
105
106 cs130_ryutaro 1.4 // WSEFAULT test
107 errCode = WSAStartup( wVersionRequired, ( LPWSADATA ) 0 );
108 if( errCode != WSAEFAULT ) {
109
110 // print out the Error Code to be thorough
111 trace( "WSAFAULT test failed with error code: %d\n", errCode );
112 errCode = 0;
113 }
114
115 // lastly regular case - should succeed
116 errCode = WSAStartup( wVersionRequired, lpWSAData );
117 if( errCode != 0 ) {
118
119 // print out the Error Code to be thorough
120 errCode = WSAGetLastError();
121 trace( "WSAStartup() failed with error code: %d\n", errCode );
122 }
123
124 return errCode;
125 }
126
127 cs130_ryutaro 1.4 /*
128 Wrapper for socket().
129 socket() function creates a socket that is bound to a specific service provider.
130
131 Parameters:
132 af
133 [in] Address family specification.
134 type
135 [in] Type specification for the new socket. Types are:
136 SOCK_STREAM - Uses TCP
137 SOCK_DGRAM - Uses UDP
138 protocol
139 [in] Protocol to be used with the socket that is specific to the indicated address
140 family.
141
142 If no error occurs, socket returns a descriptor referencing the new socket. Otherwise,
143 a value of INVALID_SOCKET is returned, and a specific error code can be retrieved by
144 calling WSAGetLastError.
145
146 Error code | Meaning
147 WSANOTINITIALISED | A successful WSAStartup call must occur before using this function.
148 cs130_ryutaro 1.4 WSAENETDOWN | The network subsystem or the associated service provider has failed.
149 WSAEAFNOSUPPORT | The specified address family is not supported.
150 WSAEINPROGRESS | A blocking Windows Sockets 1.1 call is in progress, or the service
151 provider is still processing a callback function.
152 WSAEMFILE | No more socket descriptors are available.
153 WSAENOBUFS | No buffer space is available. The socket cannot be created.
154 WSAEPROTONOSUPPORT | The specified protocol is not supported.
155 WSAEPROTOTYPE | The specified protocol is the wrong type for this socket.
156 WSAESOCKTNOSUPPORT | The specified socket type is not supported in this address family.
157
158 NOTE: WSAEPROTOTYPE tried to do test for this error by specifying type=SOCK_DGRAM and
159 protocol=IPPROTO_TCP but the return error code was WSEPROTONOSUPPORT
160 */
161 static SOCKET socket_w( int af, int type, int protocol )
162 {
163 // Create a socket.
164 SOCKET m_socket;
165
166 // WSAEAFNOSUPPORT test
167 m_socket = socket( -999, SOCK_STREAM, IPPROTO_TCP );
168 if( m_socket != INVALID_SOCKET || WSAGetLastError() != WSAEAFNOSUPPORT ){
169 cs130_ryutaro 1.4 trace( "WSAEAFNOSUPPORT test failed: %d %d\n", m_socket, WSAGetLastError() );
170 }
171
172 // WSAEPROTONOSUPPORT test
173 m_socket = socket( AF_INET, SOCK_STREAM, -999 );
174 if( m_socket != INVALID_SOCKET || WSAGetLastError() != WSAEPROTONOSUPPORT ){
175 trace( "WSAEPROTONOSUPPORT test failed: %d %d\n", m_socket, WSAGetLastError() );
176 }
177
178 // WSAESOCKTNOSUPPORT test
179 m_socket = socket( AF_INET, -999, IPPROTO_TCP );
180 if( m_socket != INVALID_SOCKET || WSAGetLastError() != WSAESOCKTNOSUPPORT ){
181 trace( "WSAEPROTONOSUPPORT test failed: %d %d\n", m_socket, WSAGetLastError() );
182 }
183
184 m_socket = socket( af, type, protocol );
185 if( m_socket == INVALID_SOCKET ){
186 trace( "Error at socket(): %d\n", WSAGetLastError() );
187 }
188
189 return m_socket;
190 cs130_ryutaro 1.4 }
191
192 /*
193 Call back event handler for asynchronous client
194 */
195 static LRESULT CALLBACK WndProcedure( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
196 {
197 int eventCode = 0;
198 switch( msg )
199 {
200 case ASYNC_EVENT:
201 eventCode = WSAGETSELECTEVENT( lParam );
202 SOCKET socket = (SOCKET) wParam;
203 SOCKET acceptSock;
204 int bytesRecv = 0;
205 int i = 0, j = 0;
206 char* buf;
207 if( GetCurrentThreadId() == ServerThread.id )
208 buf = ServerThread.packet;
209 else
210 buf = ClientThread.packet;
211 cs130_ryutaro 1.4
212 switch( eventCode )
213 {
214 case FD_ACCEPT:
215 trace( "%ld accept called\n", GetCurrentThreadId() );
216 acceptSock = accept( socket, NULL, NULL );
217 if( acceptSock == INVALID_SOCKET ){
218 trace( "accept error %d\n", WSAGetLastError() );
219 closesocket( socket );
220 ExitThread( TH_ACCEPT_ERROR );
221 }
222 trace( "%ld: connection accepted\n", GetCurrentThreadId() );
223 break;
224
225 case FD_CONNECT:
226
227 // a call to connect() has completed
228 trace("%ld CONNECTED!\n", GetCurrentThreadId() );
229 break;
230
231 case FD_CLOSE:
232 cs130_ryutaro 1.4
233 // a connection has been closed
234 closesocket( socket );
235 trace( "%ld: Closed socket\n", GetCurrentThreadId());
236 WSACleanup();
237 ExitThread( 0 );
238 break;
239
240 case FD_READ:
241
242 // WinSock has data waiting to be read
243 bytesRecv = recv( socket, buf, PACKET_SZ, 0 );
244
245 trace( "%ld received %d bytes: ", GetCurrentThreadId(), bytesRecv );
246 while( i < PACKET_SZ && buf[i] != (char)EOF ){
247 printf( "%c", buf[i] );
248 i++;
249 }
250 printf( "\n" );
251
252 // Now send it back if you're the server
253 cs130_ryutaro 1.4 if( GetCurrentThreadId() == ServerThread.id ){
254
255 if( send( socket, buf, bytesRecv, 0 ) == SOCKET_ERROR ){
256
257 // check if the network buffer is full and can send no more
258 // data. If so then break from the loop
259 if( WSAGetLastError() == WSAEWOULDBLOCK ){
260 // break from the loop buffer is full
261 trace( "woud block send!\n" );
262 break;
263 }
264 else{ // another error
265 trace(" some send error\n" );
266 return 0;
267 }
268 }
269
270 trace( "%ld sent back %d bytes: ", GetCurrentThreadId(), bytesRecv );
271 j = 0;
272 while( j < bytesRecv ){
273 printf( "%c", buf[j] );
274 cs130_ryutaro 1.4 j++;
275 }
276 printf( "\n" );
277
278 }
279 else{
280
281 // Client: close the connection when it received back FILE_SZ
282 ClientThread.bytesRecvd += bytesRecv;
283 if( ClientThread.bytesRecvd >= FILE_SZ ){
284 trace( "%ld closing socket\n", GetCurrentThreadId() );
285 closesocket( socket );
286 WSACleanup();
287 ExitThread( 0 );
288 }
289 }
290 break;
291
292 case FD_WRITE:
293
294 // don't do anything here for server
295 cs130_ryutaro 1.4 if( GetCurrentThreadId() == ServerThread.id )
296 break;
297
298 // enter an infinite loop
299 BOOL notDone = TRUE;
300 while( notDone ){
301
302 // determine how many bytes to send
303 int bytesToSend = 0;
304 if( sizeof( FileBuf ) - ClientThread.bytesSent < PACKET_SZ ){
305
306 // the bytes remaining to send is smaller than packet size
307 bytesToSend = (int) ( sizeof( FileBuf ) - ClientThread.bytesSent );
308 notDone = FALSE;
309
310 }
311 else{
312
313 // the bytes remaining is greater than or equal to PACKET_SZ
314 bytesToSend = PACKET_SZ;
315
316 cs130_ryutaro 1.4 }
317
318 memcpy( buf, FileBuf + ClientThread.bytesSent, bytesToSend );
319 ClientThread.bytesSent += bytesToSend;
320
321 // send the packet off to the Server if it is filled
322 if( send( socket, buf, bytesToSend, 0 ) == SOCKET_ERROR ){
323
324 // check if the network buffer is full and can send no more
325 // data. If so then break from the loop
326 if( WSAGetLastError() == WSAEWOULDBLOCK ){
327 // break from the loop buffer is full
328 break;
329 }
330 else{ // another error
331 return 0;
332 }
333 }
334
335 trace( "%ld sent: ", GetCurrentThreadId() );
336 j = 0;
337 cs130_ryutaro 1.4 while( j < PACKET_SZ && buf[j] != (char)EOF ){
338 printf( "%c", buf[j] );
339 j++;
340 }
341 printf( "\n" );
342 }
343 break;
344 }
345 }
346 return DefWindowProc( hWnd, msg, wParam, lParam );
347 }
348
349 /*
350 Creates a hidden window object.
351
352 input:
353 none
354 output:
355 window handle
356 */
357 static HWND WineCreateWindow( HINSTANCE hInstance )
358 cs130_ryutaro 1.4 {
359 // initialize the window class attributes.
360 WNDCLASS windowClass;
361 //windowClass = new WNDCLASS;
362 windowClass.lpszClassName = "Hidden_Winsock_Window";
363 windowClass.style = CS_HREDRAW | CS_VREDRAW;
364 windowClass.lpfnWndProc = WndProcedure;
365 windowClass.cbClsExtra = 0;
366 windowClass.cbWndExtra = 0;
367 windowClass.hInstance = hInstance;
368 windowClass.hIcon = NULL;
369 windowClass.hCursor = NULL;
370 windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
371 windowClass.lpszMenuName = NULL;
372 RegisterClass(&windowClass);
373
374 // create window
375 return CreateWindow(
376 "Hidden_Winsock_Window",
377 "Winsock Window",
378 WS_OVERLAPPEDWINDOW,
379 cs130_ryutaro 1.4 CW_USEDEFAULT,
380 CW_USEDEFAULT,
381 CW_USEDEFAULT,
382 CW_USEDEFAULT,
383 NULL,
384 NULL,
385 hInstance,
386 NULL
387 );
388 }
389
390 /* server */
391 static DWORD WINAPI WineRunServer()
392 {
393 // Retrieve an instance
394 HINSTANCE hInstance = GetModuleHandle( NULL );
395
396 // Create a window
397 HWND hwnd = WineCreateWindow( hInstance );
398 if( hwnd == NULL ){
399 trace( "Window could not be created %ld\n", GetLastError() );
400 cs130_ryutaro 1.4 ExitThread( TH_WINDOW_ERROR );
401 }
402
403 // start winsock
404 WSADATA wsaData;
405 if( WSAStartup_w( MAKEWORD( 2, 2 ), &wsaData ) != 0 ){
406
407 // print out the Error Code to be thorough
408 trace( "WSAStartup() failed with error code: %d\n", WSAGetLastError() );
409 ExitThread( TH_START_ERROR );
410 }
411
412 // Create a socket.
413 SOCKET sock = socket_w( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if( sock == INVALID_SOCKET ){
414 trace( "socket error: %d\n", WSAGetLastError() );
415 ExitThread( TH_SOCKET_ERROR );
416 }
417
418 // Bind the socket.
419 SOCKADDR_IN sockAddr;
420 sockAddr.sin_family = AF_INET;
421 cs130_ryutaro 1.4 sockAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" );
422 sockAddr.sin_port = htons( PORT_NUM );
423 if( bind( sock, (SOCKADDR*) &sockAddr, sizeof( sockAddr ) ) == SOCKET_ERROR ){
424 trace( "bind failed weith error code %d\n", WSAGetLastError() );
425 closesocket( sock );
426 ExitThread( TH_BIND_ERROR );
427
428 }
429
430 // Listen on the socket.
431 if ( listen( sock, 1 ) == SOCKET_ERROR ){
432 trace( "listen error with error code %d.\n", WSAGetLastError() );
433 closesocket( sock ); ExitThread( TH_LISTEN_ERROR ); }
434
435 // make the socket asynchronous and notify of read, write, connect and close events
436 if( WSAAsyncSelect( sock, hwnd, ASYNC_EVENT, FD_WRITE | FD_ACCEPT |FD_READ | FD_CLOSE ) == SOCKET_ERROR ){
437
438 trace( "WSAAsyncSelect Failed %d\n", WSAGetLastError() );
439 closesocket( sock );
440 ExitThread( TH_SELECT_ERROR );
441
442 cs130_ryutaro 1.4 }
443
444 trace( "listening and going to loop %ld\n", GetCurrentThreadId() );
445
446 BOOL retVal;
447 MSG msg;
448 while( ( retVal = GetMessage( &msg, NULL, 0, 0 ) ) != 0 ){
449
450 if( retVal == -1 ){
451
452 // handle the error and possibly exit
453 trace( "GetMessage error %ld\n", GetLastError() );
454 closesocket( sock );
455 ExitThread( TH_MSG_ERROR );
456 }
457
458 // Translate and dispatch the message
459 TranslateMessage( &msg );
460 DispatchMessage( &msg );
461
462 }
463 cs130_ryutaro 1.4
464 return 0;
465 }
466
467 /* client */
468 static DWORD WINAPI WineRunClient()
469 {
470 // Retrieve an instance
471 HINSTANCE hInstance = GetModuleHandle( NULL );
472
473 // Create a window
474 HWND hwnd = WineCreateWindow( hInstance );
475 if( hwnd == NULL ){
476 trace( "Window could not be created %ld\n", GetLastError() );
477 ExitThread( TH_WINDOW_ERROR );
478 }
479
480 // start winsock
481 WSADATA wsaData;
482 if( WSAStartup_w( MAKEWORD( 2, 2 ), &wsaData ) != 0 ){
483
484 cs130_ryutaro 1.4 // print out the Error Code to be thorough
485 trace( "WSAStartup() failed with error code: %d\n", WSAGetLastError() );
486 ExitThread( TH_START_ERROR );
487 }
488
489 // Create a socket. -- This is a TCP test
490 SOCKET sock = socket_w( AF_INET, SOCK_STREAM, IPPROTO_TCP );
491 if ( sock == INVALID_SOCKET ) {
492 trace( "socket returned with error code: %d\n", WSAGetLastError() );
493 ExitThread( TH_SOCKET_ERROR );
494 }
495
496 // make the socket asynchronous and notify of read, write, connect and close events
497 // this is the client socket
498 if( WSAAsyncSelect( sock, hwnd, ASYNC_EVENT, FD_WRITE | FD_CONNECT | FD_READ | FD_CLOSE ) == SOCKET_ERROR ){
499 trace( "WSAAsyncSelect Failed %d\n", WSAGetLastError() );
500 closesocket( sock );
501 ExitThread( TH_SELECT_ERROR );
502 }
503
504 /* connect */
505 cs130_ryutaro 1.4 SOCKADDR_IN sockAddr;
506 sockAddr.sin_family = AF_INET;
507 sockAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" );
508 sockAddr.sin_port = htons( PORT_NUM );
509 if( connect( sock, (SOCKADDR*) &sockAddr, sizeof( sockAddr ) ) == SOCKET_ERROR ){
510 if( WSAGetLastError() != WSAEWOULDBLOCK ){
511 trace( "Failed to connect.: %d\n", WSAGetLastError() );
512 closesocket( sock );
513 ExitThread( TH_CONNECT_ERROR );
514 }
515 }
516
517 BOOL retVal;
518 MSG msg;
519 while( ( retVal = GetMessage( &msg, NULL, 0, 0 ) ) != 0 ){
520
521 if( retVal == -1 ){
522
523 // handle the error and possibly exit
524 trace( "GetMessage error %ld\n", GetLastError() );
525 closesocket( sock );
526 cs130_ryutaro 1.4 ExitThread( TH_MSG_ERROR );
527 }
528
529 // Translate and dispatch the message
530 TranslateMessage( &msg );
531 DispatchMessage( &msg );
532
533 }
534 return 0;
535 }
536
537 /* close thread handles and finish up winsock dll */
538 static void WineThreadCleanUp()
539 {
540 if( ServerThread.handle )
541 CloseHandle( ServerThread.handle );
542
543 if( ClientThread.handle )
544 CloseHandle( ClientThread.handle );
545 }
546
547 cs130_ryutaro 1.4 /* creates the buffer that the client sends */
548 static void WineCreateFile()
549 {
550 /* initialize just in case */
551 memset( FileBuf, 0, sizeof( FileBuf ) );
552
553 /* just customize this any way you want */
554 memset( FileBuf, 'W', PACKET_SZ );
555 memset( FileBuf + PACKET_SZ, 'I', PACKET_SZ );
556 memset( FileBuf + ( 2 * PACKET_SZ ), 'N', PACKET_SZ );
557 memset( FileBuf + ( 3 * PACKET_SZ ), 'E', 3 );
558 FileBuf[FILE_SZ - 1] = (char) EOF;
559 }
560
561 START_TEST( WineWinsockAsyncTest )
562 {
563 // Create the file that we are going to send.
564 WineCreateFile();
565
566 // Initialize server and client threads
567 memset( &ServerThread, 0, sizeof( ServerThread ) );
568 cs130_ryutaro 1.4 memset( &ClientThread, 0, sizeof( ClientThread ) );
569
570 // create server thread
571 ServerThread.handle = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)WineRunServer,
572 NULL, 0, &ServerThread.id );
573
574 if( ServerThread.handle == NULL ){
575
576 trace( "CreateThread failed %ld\n", GetLastError() );
577 WineThreadCleanUp();
578 return;
579 }
580
581 trace( "%ld: server thread %ld created\n", GetCurrentThreadId(), ServerThread.id );
582
583 // Wait for three seconds to let server start
584 DWORD waitRet = WaitForSingleObject( ServerThread.handle, SERVER_START_TIME );
585 if( waitRet == WAIT_FAILED ){
586
587 // WaitForSingleObject failed for whatever reason
588 trace( "WaitForSingleObject failed with error code %ld\n", GetLastError() );
589 cs130_ryutaro 1.4 WineThreadCleanUp();
590 return;
591
592 }
593
594 // get the exit code of the server - error if not STILL_ACTIVE
595 DWORD threadStatus = 0;
596 if( GetExitCodeThread( ServerThread.handle, &threadStatus ) == 0 ){
597
598 trace( "GetExitCodeThread failed with error code %ld\n",GetLastError() );
599 WineThreadCleanUp();
600 return;
601
602 }
603
604 trace( "%ld: server started successfully now creating client thread\n", GetCurrentThreadId() );
605
606 // Create client thread in suspended state
607 ClientThread.handle = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)WineRunClient,
608 NULL, 0, &ClientThread.id );
609
610 cs130_ryutaro 1.4 if( ClientThread.handle == NULL ){
611
612 trace( "CreateThread failed %ld\n", GetLastError() );
613 WineThreadCleanUp();
614 return;
615 }
616
617 trace( "%ld: client thread %ld created. Now wait.\n", GetCurrentThreadId(), ClientThread.id );
618
619 // Wait for this server to suspsend itself
620 HANDLE threadHandles[NUM_THREADS_TO_WAIT] = { ServerThread.handle, ClientThread.handle };
621 waitRet = WaitForMultipleObjects( NUM_THREADS_TO_WAIT, threadHandles, TRUE, MAX_WAIT_TIME );
622 if( waitRet == WAIT_FAILED ){
623
624 // WaitForSingleObject failed for whatever reason
625 trace( "WaitForMultipleObjects failed with error code %ld\n", GetLastError() );
626 WineThreadCleanUp();
627 return;
628
629 }
630 else if( waitRet == WAIT_TIMEOUT ){
631 cs130_ryutaro 1.4
632 trace( "Timed out while waiting for threads to finish\n" );
633 WineThreadCleanUp();
634 return;
635
636 }
637
638 // clean up the threads
639 WineThreadCleanUp();
640
641 trace( "%ld: main thread exiting...\n", GetCurrentThreadId() );
642 }
|