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/. */
6 /*******************************************************************
7 ** udpsrc.c -- Test basic function of UDP server
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.
13 ** The test is designed to assist developers in porting/debugging
14 ** the UDP socket functions of NSPR.
16 ** This test is not a stress test.
18 ** main() starts two threads: UDP_Server() and UDP_Client();
19 ** main() uses PR_JoinThread() to wait for the threads to complete.
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().
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.
31 ** The test issues a pass/fail message at end.
34 ** The variable "_debug_on" can be set to 1 to cause diagnostic
35 ** messages related to client/server synchronization. Useful when
38 ** Error messages are written to stdout.
40 ********************************************************************
42 /* --- include files --- */
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
68 #define UDP_TIMEOUT 400000
69 /* #define UDP_TIMEOUT PR_INTERVAL_NO_TIMEOUT */
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;
78 /* --- static function declarations --- */
79 #define DPRINTF(arg) if (_debug_on) PR_fprintf(output, arg)
83 /*******************************************************************
84 ** ListNetAddr() -- Display the Net Address on stdout
86 ** Description: displays the component parts of a PRNetAddr struct
88 ** Arguments: address of PRNetAddr structure to display
94 ********************************************************************
96 void ListNetAddr( char *msg, PRNetAddr *na )
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) );
105 } /* --- end ListNetAddr() --- */
107 /********************************************************************
108 ** UDP_Server() -- Test a UDP server application
110 ** Description: The Server side of a UDP Client/Server application.
119 ********************************************************************
121 static void PR_CALLBACK UDP_Server( void *arg )
123 static char svrBuf[UDP_BUF_SIZE];
127 PRBool bound = PR_FALSE;
128 PRBool endOfInput = PR_FALSE;
129 PRInt32 numBytes = UDP_DGRAM_SIZE;
131 DPRINTF("udpsrv: UDP_Server(): starting\n" );
133 /* --- Create the socket --- */
134 DPRINTF("udpsrv: UDP_Server(): Creating UDP Socket\n" );
135 svrSock = PR_NewUDPSocket();
136 if ( svrSock == NULL )
141 "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" );
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 );
151 /* --- Bind the socket --- */
154 DPRINTF("udpsrv: UDP_Server(): Binding socket\n" );
155 rv = PR_Bind( svrSock, &netaddr );
158 if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR )
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 ));
168 if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \
169 PR_Bind(): failed: %ld with error: %ld\n",
178 ListNetAddr( "UDP_Server: after bind", &netaddr );
180 /* --- Recv the socket --- */
183 DPRINTF("udpsrv: UDP_Server(): RecvFrom() socket\n" );
184 rv = PR_RecvFrom( svrSock, svrBuf, numBytes, 0, &netaddr, UDP_TIMEOUT );
190 "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n",
195 ListNetAddr( "UDP_Server after RecvFrom", &netaddr );
199 if ( svrBuf[0] == 'E' )
201 DPRINTF("udpsrv: UDP_Server(): EOF on input detected\n" );
202 endOfInput = PR_TRUE;
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 );
213 "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n",
218 ListNetAddr( "UDP_Server after SendTo", &netaddr );
221 /* --- Close the socket --- */
222 DPRINTF("udpsrv: UDP_Server(): Closing socket\n" );
223 rv = PR_Close( svrSock );
224 if ( rv != PR_SUCCESS )
229 "udpsrv: UDP_Server(): PR_Close(): failed to close socket\n" );
233 DPRINTF("udpsrv: UDP_Server(): Normal end\n" );
234 } /* --- end UDP_Server() --- */
237 static char cltBuf[UDP_BUF_SIZE];
238 static char cltBufin[UDP_BUF_SIZE];
239 /********************************************************************
240 ** UDP_Client() -- Test a UDP client application
248 ** 0 -- Successful execution
254 ********************************************************************
256 static void PR_CALLBACK UDP_Client( void *arg )
260 PRBool bound = PR_FALSE;
263 PRBool endOfInput = PR_FALSE;
264 PRInt32 numBytes = UDP_DGRAM_SIZE;
265 PRInt32 writeThisMany = UDP_AMOUNT_TO_WRITE;
269 DPRINTF("udpsrv: UDP_Client(): starting\n" );
271 /* --- Create the socket --- */
272 cltSock = PR_NewUDPSocket();
273 if ( cltSock == NULL )
278 "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" );
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 );
288 /* --- Initialize the write buffer --- */
289 for ( i = 0; i < UDP_BUF_SIZE ; i++ )
292 /* --- Bind the socket --- */
295 DPRINTF("udpsrv: UDP_Client(): Binding socket\n" );
296 rv = PR_Bind( cltSock, &netaddr );
299 if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR )
303 "udpsrv: UDP_Client(): PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n");
304 PR_Sleep( PR_MillisecondsToInterval( 2000 ));
312 "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n",
321 ListNetAddr( "UDP_Client after Bind", &netaddr );
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 );
329 /* --- send and receive packets until no more data left */
333 ** Signal EOF in the data stream on the last packet
335 if ( writeThisMany <= UDP_DGRAM_SIZE )
337 DPRINTF("udpsrv: UDP_Client(): Send EOF packet\n" );
339 endOfInput = PR_TRUE;
342 /* --- SendTo the socket --- */
343 if ( writeThisMany > UDP_DGRAM_SIZE )
344 numBytes = UDP_DGRAM_SIZE;
346 numBytes = writeThisMany;
347 writeThisMany -= numBytes;
350 sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n",
351 writeThisMany, numBytes );
355 DPRINTF("udpsrv: UDP_Client(): SendTo(): socket\n" );
356 rv = PR_SendTo( cltSock, cltBuf, numBytes, 0, &netaddr, UDP_TIMEOUT );
362 "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n",
367 ListNetAddr( "UDP_Client after SendTo", &netaddr );
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 );
376 if (debug_mode) PR_fprintf(output,
377 "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n",
382 ListNetAddr( "UDP_Client after RecvFrom()", &netaddr );
385 /* --- verify buffer --- */
386 for ( i = 0; i < rv ; i++ )
388 if ( cltBufin[i] != i )
390 /* --- special case, end of input --- */
391 if ( endOfInput && i == 0 && cltBufin[0] == 'E' )
394 if (debug_mode) PR_fprintf(output,
395 "udpsrv: UDP_Client(): return data mismatch\n" );
400 if (debug_mode) PR_fprintf(output, ".");
403 /* --- Close the socket --- */
404 DPRINTF("udpsrv: UDP_Server(): Closing socket\n" );
405 rv = PR_Close( cltSock );
406 if ( rv != PR_SUCCESS )
409 if (debug_mode) PR_fprintf(output,
410 "udpsrv: UDP_Client(): PR_Close(): failed to close socket\n" );
413 DPRINTF("udpsrv: UDP_Client(): ending\n" );
414 } /* --- end UDP_Client() --- */
416 /********************************************************************
422 ** 0 -- Successful execution
427 ** Standard test case setup.
429 ** Calls the function UDP_Server()
431 ********************************************************************
434 int main(int argc, char **argv)
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)
441 Usage: test_name -d -v
444 PLOptState *opt = PL_CreateOptState(argc, argv, "dv");
445 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
447 if (PL_OPT_BAD == os) continue;
450 case 'd': /* debug mode */
453 case 'v': /* verbose mode */
460 PL_DestroyOptState(opt);
462 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
466 PR_SetConcurrency(4);
469 ** Create the Server thread
471 DPRINTF( "udpsrv: Creating Server Thread\n" );
472 srv = PR_CreateThread( PR_USER_THREAD,
481 if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" );
486 ** Give the Server time to Start
488 DPRINTF( "udpsrv: Pausing to allow Server to start\n" );
489 PR_Sleep( PR_MillisecondsToInterval(200) );
492 ** Create the Client thread
494 DPRINTF( "udpsrv: Creating Client Thread\n" );
495 clt = PR_CreateThread( PR_USER_THREAD,
504 if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" );
511 DPRINTF("udpsrv: Waiting to join Server & Client Threads\n" );
512 PR_JoinThread( srv );
513 PR_JoinThread( clt );
516 ** Evaluate test results
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 )
530 } /* --- end main() --- */