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