805bccbbb3a9b98044e54982b1e5a8d364486b30
[platform/upstream/nspr.git] / nspr / pr / tests / udpsrv.c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 /*******************************************************************
7 ** udpsrc.c -- Test basic function of UDP server
8 **
9 ** udpsrv operates on the same machine with program udpclt.
10 ** udpsrv is the server side of a udp sockets application.
11 ** udpclt is the client side of a udp sockets application.
12 **
13 ** The test is designed to assist developers in porting/debugging
14 ** the UDP socket functions of NSPR.
15 **
16 ** This test is not a stress test.
17 **
18 ** main() starts two threads: UDP_Server() and UDP_Client();
19 ** main() uses PR_JoinThread() to wait for the threads to complete.
20 **
21 ** UDP_Server() does repeated recvfrom()s from a socket.
22 ** He detects an EOF condition set by UDP_Client(). For each
23 ** packet received by UDP_Server(), he checks its content for
24 ** expected content, then sends the packet back to UDP_Client().
25 ** 
26 ** UDP_Client() sends packets to UDP_Server() using sendto()
27 ** he recieves packets back from the server via recvfrom().
28 ** After he sends enough packets containing UDP_AMOUNT_TO_WRITE
29 ** bytes of data, he sends an EOF message.
30 ** 
31 ** The test issues a pass/fail message at end.
32 ** 
33 ** Notes:
34 ** The variable "_debug_on" can be set to 1 to cause diagnostic
35 ** messages related to client/server synchronization. Useful when
36 ** the test hangs.
37 ** 
38 ** Error messages are written to stdout.
39 ** 
40 ********************************************************************
41 */
42 /* --- include files --- */
43 #include "nspr.h"
44 #include "prpriv.h"
45
46 #include "plgetopt.h"
47 #include "prttools.h"
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <errno.h>
53
54 #ifdef XP_PC
55 #define mode_t int
56 #endif
57
58 #define UDP_BUF_SIZE            4096
59 #define UDP_DGRAM_SIZE          128
60 #define UDP_AMOUNT_TO_WRITE     (PRInt32)((UDP_DGRAM_SIZE * 1000l) +1)
61 #define NUM_UDP_CLIENTS         1
62 #define NUM_UDP_DATAGRAMS_PER_CLIENT    5
63 #define UDP_SERVER_PORT         9050
64 #define UDP_CLIENT_PORT         9053
65 #define MY_INADDR               PR_INADDR_ANY
66 #define PEER_INADDR             PR_INADDR_LOOPBACK
67
68 #define UDP_TIMEOUT             400000
69 /* #define UDP_TIMEOUT             PR_INTERVAL_NO_TIMEOUT */
70
71 /* --- static data --- */
72 static PRIntn _debug_on      = 0;
73 static PRBool passed         = PR_TRUE;
74 static PRUint32 cltBytesRead = 0;
75 static PRUint32 srvBytesRead = 0;
76 static PRFileDesc *output    = NULL;
77
78 /* --- static function declarations --- */
79 #define DPRINTF(arg) if (_debug_on) PR_fprintf(output, arg)
80
81
82
83 /*******************************************************************
84 ** ListNetAddr() -- Display the Net Address on stdout
85 **
86 ** Description: displays the component parts of a PRNetAddr struct
87 **
88 ** Arguments:   address of PRNetAddr structure to display
89 **
90 ** Returns: void
91 **
92 ** Notes:
93 **
94 ********************************************************************
95 */
96 void ListNetAddr( char *msg, PRNetAddr *na )
97 {
98     char    mbuf[256];
99     
100     sprintf( mbuf, "ListNetAddr: %s family: %d, port: %d, ip: %8.8X\n",
101             msg, na->inet.family, PR_ntohs( na->inet.port), PR_ntohl(na->inet.ip) );
102 #if 0            
103     DPRINTF( mbuf );            
104 #endif
105 } /* --- end ListNetAddr() --- */
106
107 /********************************************************************
108 ** UDP_Server() -- Test a UDP server application
109 **
110 ** Description: The Server side of a UDP Client/Server application.
111 **
112 ** Arguments: none
113 **
114 ** Returns: void
115 **
116 ** Notes:
117 **
118 **
119 ********************************************************************
120 */
121 static void PR_CALLBACK UDP_Server( void *arg )
122 {
123     static char     svrBuf[UDP_BUF_SIZE];
124     PRFileDesc      *svrSock;
125     PRInt32         rv;
126     PRNetAddr       netaddr;
127     PRBool          bound = PR_FALSE;
128     PRBool          endOfInput = PR_FALSE;
129     PRInt32         numBytes = UDP_DGRAM_SIZE;
130     
131     DPRINTF("udpsrv: UDP_Server(): starting\n" );
132
133     /* --- Create the socket --- */
134     DPRINTF("udpsrv: UDP_Server(): Creating UDP Socket\n" );
135     svrSock = PR_NewUDPSocket();
136     if ( svrSock == NULL )
137     {
138         passed = PR_FALSE;
139         if (debug_mode)
140             PR_fprintf(output,
141                 "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" );
142         return;
143     }
144     
145     /* --- Initialize the sockaddr_in structure --- */
146     memset( &netaddr, 0, sizeof( netaddr )); 
147     netaddr.inet.family = PR_AF_INET;
148     netaddr.inet.port   = PR_htons( UDP_SERVER_PORT );
149     netaddr.inet.ip     = PR_htonl( MY_INADDR );
150     
151     /* --- Bind the socket --- */
152     while ( !bound )
153     {
154         DPRINTF("udpsrv: UDP_Server(): Binding socket\n" );
155         rv = PR_Bind( svrSock, &netaddr );
156         if ( rv < 0 )
157         {
158             if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR )
159             {
160                 if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \
161                                                 PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n");
162                 PR_Sleep( PR_MillisecondsToInterval( 2000 ));
163                 continue;
164             }
165             else
166             {
167                 passed = PR_FALSE;
168                 if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \
169                                                 PR_Bind(): failed: %ld with error: %ld\n",
170                         rv, PR_GetError() );
171                 PR_Close( svrSock );
172                 return;
173             }
174         }
175         else
176             bound = PR_TRUE;
177     }
178     ListNetAddr( "UDP_Server: after bind", &netaddr );
179     
180     /* --- Recv the socket --- */
181     while( !endOfInput )
182     {
183         DPRINTF("udpsrv: UDP_Server(): RecvFrom() socket\n" );
184         rv = PR_RecvFrom( svrSock, svrBuf, numBytes, 0, &netaddr, UDP_TIMEOUT );
185         if ( rv == -1 )
186         {
187             passed = PR_FALSE;
188             if (debug_mode)
189                 PR_fprintf(output,
190                     "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n",
191                     PR_GetError() );
192             PR_Close( svrSock );
193             return;
194         }
195         ListNetAddr( "UDP_Server after RecvFrom", &netaddr );
196         
197         srvBytesRead += rv;
198         
199         if ( svrBuf[0] == 'E' )
200         {
201             DPRINTF("udpsrv: UDP_Server(): EOF on input detected\n" );
202             endOfInput = PR_TRUE;
203         }
204             
205         /* --- Send the socket --- */
206         DPRINTF("udpsrv: UDP_Server(): SendTo(): socket\n" );
207         rv = PR_SendTo( svrSock, svrBuf, rv, 0, &netaddr, PR_INTERVAL_NO_TIMEOUT );
208         if ( rv == -1 )
209         {
210             passed = PR_FALSE;
211             if (debug_mode)
212                 PR_fprintf(output,
213                     "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n",
214                     PR_GetError() );
215             PR_Close( svrSock );
216             return;
217         }
218         ListNetAddr( "UDP_Server after SendTo", &netaddr );
219     }
220     
221     /* --- Close the socket --- */
222     DPRINTF("udpsrv: UDP_Server(): Closing socket\n" );
223     rv = PR_Close( svrSock );
224     if ( rv != PR_SUCCESS )
225     {
226         passed = PR_FALSE;
227         if (debug_mode)
228             PR_fprintf(output,
229                 "udpsrv: UDP_Server(): PR_Close(): failed to close socket\n" );
230         return;
231     }
232     
233     DPRINTF("udpsrv: UDP_Server(): Normal end\n" );
234 } /* --- end UDP_Server() --- */
235
236
237 static char         cltBuf[UDP_BUF_SIZE];
238 static char         cltBufin[UDP_BUF_SIZE];
239 /********************************************************************
240 ** UDP_Client() -- Test a UDP client application
241 **
242 ** Description:
243 **
244 ** Arguments:
245 **
246 **
247 ** Returns:
248 ** 0 -- Successful execution
249 ** 1 -- Test failed.
250 **
251 ** Notes:
252 **
253 **
254 ********************************************************************
255 */
256 static void PR_CALLBACK UDP_Client( void *arg )
257 {
258     PRFileDesc   *cltSock;
259     PRInt32      rv;
260     PRBool       bound = PR_FALSE;
261     PRNetAddr    netaddr;
262     PRNetAddr    netaddrx;
263     PRBool       endOfInput = PR_FALSE;
264     PRInt32      numBytes = UDP_DGRAM_SIZE;
265     PRInt32      writeThisMany = UDP_AMOUNT_TO_WRITE;
266     int          i;
267     
268     
269     DPRINTF("udpsrv: UDP_Client(): starting\n" );
270     
271     /* --- Create the socket --- */
272     cltSock = PR_NewUDPSocket();
273     if ( cltSock == NULL )
274     {
275         passed = PR_FALSE;
276         if (debug_mode)
277             PR_fprintf(output,
278                 "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" );
279         return;
280     }
281     
282     /* --- Initialize the sockaddr_in structure --- */
283     memset( &netaddr, 0, sizeof( netaddr )); 
284     netaddr.inet.family = PR_AF_INET;
285     netaddr.inet.ip     = PR_htonl( MY_INADDR );
286     netaddr.inet.port   = PR_htons( UDP_CLIENT_PORT );
287     
288     /* --- Initialize the write buffer --- */    
289     for ( i = 0; i < UDP_BUF_SIZE ; i++ )
290         cltBuf[i] = i;
291     
292     /* --- Bind the socket --- */
293     while ( !bound )
294     {
295         DPRINTF("udpsrv: UDP_Client(): Binding socket\n" );
296         rv = PR_Bind( cltSock, &netaddr );
297         if ( rv < 0 )
298         {
299             if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR )
300             {
301                 if (debug_mode)
302                     PR_fprintf(output,
303                         "udpsrv: UDP_Client(): PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n");
304                 PR_Sleep( PR_MillisecondsToInterval( 2000 ));
305                 continue;
306             }
307             else
308             {
309                 passed = PR_FALSE;
310                 if (debug_mode)
311                     PR_fprintf(output,
312                         "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n",
313                         rv, PR_GetError() );
314                 PR_Close( cltSock );
315                 return;
316             }
317         }
318         else
319             bound = PR_TRUE;
320     }
321     ListNetAddr( "UDP_Client after Bind", &netaddr );
322     
323     /* --- Initialize the sockaddr_in structure --- */
324     memset( &netaddr, 0, sizeof( netaddr )); 
325     netaddr.inet.family = PR_AF_INET;
326     netaddr.inet.ip     = PR_htonl( PEER_INADDR );
327     netaddr.inet.port   = PR_htons( UDP_SERVER_PORT );
328     
329     /* --- send and receive packets until no more data left */    
330     while( !endOfInput )
331     {
332         /*
333         ** Signal EOF in the data stream on the last packet
334         */        
335         if ( writeThisMany <= UDP_DGRAM_SIZE )
336         {
337             DPRINTF("udpsrv: UDP_Client(): Send EOF packet\n" );
338             cltBuf[0] = 'E';
339             endOfInput = PR_TRUE;
340         }
341         
342         /* --- SendTo the socket --- */
343         if ( writeThisMany > UDP_DGRAM_SIZE )
344             numBytes = UDP_DGRAM_SIZE;
345         else
346             numBytes = writeThisMany;
347         writeThisMany -= numBytes;
348         {
349             char   mbuf[256];
350             sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n", 
351                 writeThisMany, numBytes );
352             DPRINTF( mbuf );
353         }
354         
355         DPRINTF("udpsrv: UDP_Client(): SendTo(): socket\n" );
356         rv = PR_SendTo( cltSock, cltBuf, numBytes, 0, &netaddr, UDP_TIMEOUT );
357         if ( rv == -1 )
358         {
359             passed = PR_FALSE;
360             if (debug_mode)
361                 PR_fprintf(output,
362                     "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n",
363                         PR_GetError() );
364             PR_Close( cltSock );
365             return;
366         }
367         ListNetAddr( "UDP_Client after SendTo", &netaddr );
368
369         /* --- RecvFrom the socket --- */
370         memset( cltBufin, 0, UDP_BUF_SIZE );
371         DPRINTF("udpsrv: UDP_Client(): RecvFrom(): socket\n" );
372         rv = PR_RecvFrom( cltSock, cltBufin, numBytes, 0, &netaddrx, UDP_TIMEOUT );
373         if ( rv == -1 )
374         {
375             passed = PR_FALSE;
376             if (debug_mode) PR_fprintf(output,
377                 "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n",
378                    PR_GetError() );
379             PR_Close( cltSock );
380             return;
381         }
382         ListNetAddr( "UDP_Client after RecvFrom()", &netaddr );
383         cltBytesRead += rv;
384         
385         /* --- verify buffer --- */
386         for ( i = 0; i < rv ; i++ )
387         {
388             if ( cltBufin[i] != i )
389             {
390                 /* --- special case, end of input --- */
391                 if ( endOfInput && i == 0 && cltBufin[0] == 'E' )
392                     continue;
393                 passed = PR_FALSE;
394                 if (debug_mode) PR_fprintf(output,
395                     "udpsrv: UDP_Client(): return data mismatch\n" );
396                 PR_Close( cltSock );
397                 return;
398             }
399         }
400         if (debug_mode) PR_fprintf(output, ".");
401     }
402     
403     /* --- Close the socket --- */
404     DPRINTF("udpsrv: UDP_Server(): Closing socket\n" );
405     rv = PR_Close( cltSock );
406     if ( rv != PR_SUCCESS )
407     {
408         passed = PR_FALSE;
409         if (debug_mode) PR_fprintf(output,
410             "udpsrv: UDP_Client(): PR_Close(): failed to close socket\n" );
411         return;
412     }
413     DPRINTF("udpsrv: UDP_Client(): ending\n" );
414 } /* --- end UDP_Client() --- */
415
416 /********************************************************************
417 ** main() -- udpsrv
418 **
419 ** arguments:
420 **
421 ** Returns:
422 ** 0 -- Successful execution
423 ** 1 -- Test failed.
424 **
425 ** Description:
426 **
427 ** Standard test case setup.
428 **
429 ** Calls the function UDP_Server()
430 **
431 ********************************************************************
432 */
433
434 int main(int argc, char **argv)
435 {
436     PRThread    *srv, *clt;
437 /* The command line argument: -d is used to determine if the test is being run
438         in debug mode. The regress tool requires only one line output:PASS or FAIL.
439         All of the printfs associated with this test has been handled with a if (debug_mode)
440         test.
441         Usage: test_name -d -v
442         */
443         PLOptStatus os;
444         PLOptState *opt = PL_CreateOptState(argc, argv, "dv");
445         while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
446     {
447                 if (PL_OPT_BAD == os) continue;
448         switch (opt->option)
449         {
450         case 'd':  /* debug mode */
451                         debug_mode = 1;
452             break;
453         case 'v':  /* verbose mode */
454                         _debug_on = 1;
455             break;
456          default:
457             break;
458         }
459     }
460         PL_DestroyOptState(opt);
461                 
462     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
463     PR_STDIO_INIT();
464     output = PR_STDERR;
465
466     PR_SetConcurrency(4);
467     
468     /*
469     ** Create the Server thread
470     */    
471     DPRINTF( "udpsrv: Creating Server Thread\n" );
472     srv =  PR_CreateThread( PR_USER_THREAD,
473             UDP_Server,
474             (void *) 0,
475             PR_PRIORITY_LOW,
476             PR_LOCAL_THREAD,
477             PR_JOINABLE_THREAD,
478             0 );
479     if ( srv == NULL )
480     {
481         if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" );
482         passed = PR_FALSE;
483     }
484     
485     /*
486     ** Give the Server time to Start
487     */    
488     DPRINTF( "udpsrv: Pausing to allow Server to start\n" );
489     PR_Sleep( PR_MillisecondsToInterval(200) );
490     
491     /*
492     ** Create the Client thread
493     */    
494     DPRINTF( "udpsrv: Creating Client Thread\n" );
495     clt = PR_CreateThread( PR_USER_THREAD,
496             UDP_Client,
497             (void *) 0,
498             PR_PRIORITY_LOW,
499             PR_LOCAL_THREAD,
500             PR_JOINABLE_THREAD,
501             0 );
502     if ( clt == NULL )
503     {
504         if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" );
505         passed = PR_FALSE;
506     }
507     
508     /*
509     **
510     */
511     DPRINTF("udpsrv: Waiting to join Server & Client Threads\n" );
512     PR_JoinThread( srv );
513     PR_JoinThread( clt );    
514     
515     /*
516     ** Evaluate test results
517     */
518     if (debug_mode) PR_fprintf(output, "\n\nudpsrv: main(): cltBytesRead(%ld), \
519                 srvBytesRead(%ld), expected(%ld)\n",
520          cltBytesRead, srvBytesRead, UDP_AMOUNT_TO_WRITE );
521     if ( cltBytesRead != srvBytesRead || cltBytesRead != UDP_AMOUNT_TO_WRITE )
522     {
523         passed = PR_FALSE;
524     }
525     PR_Cleanup();
526     if ( passed )
527         return 0;
528     else
529                 return 1;
530 } /* --- end main() --- */