Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
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
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"
46 #include "plgetopt.h"
47 #include "prttools.h"
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <errno.h>
54 #ifdef XP_PC
55 #define mode_t int
56 #endif
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
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];
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() --- */
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;
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 )
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 }
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 --- */
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 );
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 );
197 srvBytesRead += rv;
199 if ( svrBuf[0] == 'E' )
200 {
201 DPRINTF("udpsrv: UDP_Server(): EOF on input detected\n" );
202 endOfInput = PR_TRUE;
203 }
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 }
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 }
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
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;
269 DPRINTF("udpsrv: UDP_Client(): starting\n" );
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 }
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++ )
290 cltBuf[i] = i;
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 );
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 */
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 }
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 }
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 );
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;
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 }
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() --- */
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 */
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);
462 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
463 PR_STDIO_INIT();
464 output = PR_STDERR;
466 PR_SetConcurrency(4);
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 }
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) );
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 }
508 /*
509 **
510 */
511 DPRINTF("udpsrv: Waiting to join Server & Client Threads\n" );
512 PR_JoinThread( srv );
513 PR_JoinThread( clt );
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() --- */