1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/udpsrv.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,530 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/******************************************************************* 1.10 +** udpsrc.c -- Test basic function of UDP server 1.11 +** 1.12 +** udpsrv operates on the same machine with program udpclt. 1.13 +** udpsrv is the server side of a udp sockets application. 1.14 +** udpclt is the client side of a udp sockets application. 1.15 +** 1.16 +** The test is designed to assist developers in porting/debugging 1.17 +** the UDP socket functions of NSPR. 1.18 +** 1.19 +** This test is not a stress test. 1.20 +** 1.21 +** main() starts two threads: UDP_Server() and UDP_Client(); 1.22 +** main() uses PR_JoinThread() to wait for the threads to complete. 1.23 +** 1.24 +** UDP_Server() does repeated recvfrom()s from a socket. 1.25 +** He detects an EOF condition set by UDP_Client(). For each 1.26 +** packet received by UDP_Server(), he checks its content for 1.27 +** expected content, then sends the packet back to UDP_Client(). 1.28 +** 1.29 +** UDP_Client() sends packets to UDP_Server() using sendto() 1.30 +** he recieves packets back from the server via recvfrom(). 1.31 +** After he sends enough packets containing UDP_AMOUNT_TO_WRITE 1.32 +** bytes of data, he sends an EOF message. 1.33 +** 1.34 +** The test issues a pass/fail message at end. 1.35 +** 1.36 +** Notes: 1.37 +** The variable "_debug_on" can be set to 1 to cause diagnostic 1.38 +** messages related to client/server synchronization. Useful when 1.39 +** the test hangs. 1.40 +** 1.41 +** Error messages are written to stdout. 1.42 +** 1.43 +******************************************************************** 1.44 +*/ 1.45 +/* --- include files --- */ 1.46 +#include "nspr.h" 1.47 +#include "prpriv.h" 1.48 + 1.49 +#include "plgetopt.h" 1.50 +#include "prttools.h" 1.51 + 1.52 +#include <stdio.h> 1.53 +#include <stdlib.h> 1.54 +#include <string.h> 1.55 +#include <errno.h> 1.56 + 1.57 +#ifdef XP_PC 1.58 +#define mode_t int 1.59 +#endif 1.60 + 1.61 +#define UDP_BUF_SIZE 4096 1.62 +#define UDP_DGRAM_SIZE 128 1.63 +#define UDP_AMOUNT_TO_WRITE (PRInt32)((UDP_DGRAM_SIZE * 1000l) +1) 1.64 +#define NUM_UDP_CLIENTS 1 1.65 +#define NUM_UDP_DATAGRAMS_PER_CLIENT 5 1.66 +#define UDP_SERVER_PORT 9050 1.67 +#define UDP_CLIENT_PORT 9053 1.68 +#define MY_INADDR PR_INADDR_ANY 1.69 +#define PEER_INADDR PR_INADDR_LOOPBACK 1.70 + 1.71 +#define UDP_TIMEOUT 400000 1.72 +/* #define UDP_TIMEOUT PR_INTERVAL_NO_TIMEOUT */ 1.73 + 1.74 +/* --- static data --- */ 1.75 +static PRIntn _debug_on = 0; 1.76 +static PRBool passed = PR_TRUE; 1.77 +static PRUint32 cltBytesRead = 0; 1.78 +static PRUint32 srvBytesRead = 0; 1.79 +static PRFileDesc *output = NULL; 1.80 + 1.81 +/* --- static function declarations --- */ 1.82 +#define DPRINTF(arg) if (_debug_on) PR_fprintf(output, arg) 1.83 + 1.84 + 1.85 + 1.86 +/******************************************************************* 1.87 +** ListNetAddr() -- Display the Net Address on stdout 1.88 +** 1.89 +** Description: displays the component parts of a PRNetAddr struct 1.90 +** 1.91 +** Arguments: address of PRNetAddr structure to display 1.92 +** 1.93 +** Returns: void 1.94 +** 1.95 +** Notes: 1.96 +** 1.97 +******************************************************************** 1.98 +*/ 1.99 +void ListNetAddr( char *msg, PRNetAddr *na ) 1.100 +{ 1.101 + char mbuf[256]; 1.102 + 1.103 + sprintf( mbuf, "ListNetAddr: %s family: %d, port: %d, ip: %8.8X\n", 1.104 + msg, na->inet.family, PR_ntohs( na->inet.port), PR_ntohl(na->inet.ip) ); 1.105 +#if 0 1.106 + DPRINTF( mbuf ); 1.107 +#endif 1.108 +} /* --- end ListNetAddr() --- */ 1.109 + 1.110 +/******************************************************************** 1.111 +** UDP_Server() -- Test a UDP server application 1.112 +** 1.113 +** Description: The Server side of a UDP Client/Server application. 1.114 +** 1.115 +** Arguments: none 1.116 +** 1.117 +** Returns: void 1.118 +** 1.119 +** Notes: 1.120 +** 1.121 +** 1.122 +******************************************************************** 1.123 +*/ 1.124 +static void PR_CALLBACK UDP_Server( void *arg ) 1.125 +{ 1.126 + static char svrBuf[UDP_BUF_SIZE]; 1.127 + PRFileDesc *svrSock; 1.128 + PRInt32 rv; 1.129 + PRNetAddr netaddr; 1.130 + PRBool bound = PR_FALSE; 1.131 + PRBool endOfInput = PR_FALSE; 1.132 + PRInt32 numBytes = UDP_DGRAM_SIZE; 1.133 + 1.134 + DPRINTF("udpsrv: UDP_Server(): starting\n" ); 1.135 + 1.136 + /* --- Create the socket --- */ 1.137 + DPRINTF("udpsrv: UDP_Server(): Creating UDP Socket\n" ); 1.138 + svrSock = PR_NewUDPSocket(); 1.139 + if ( svrSock == NULL ) 1.140 + { 1.141 + passed = PR_FALSE; 1.142 + if (debug_mode) 1.143 + PR_fprintf(output, 1.144 + "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" ); 1.145 + return; 1.146 + } 1.147 + 1.148 + /* --- Initialize the sockaddr_in structure --- */ 1.149 + memset( &netaddr, 0, sizeof( netaddr )); 1.150 + netaddr.inet.family = PR_AF_INET; 1.151 + netaddr.inet.port = PR_htons( UDP_SERVER_PORT ); 1.152 + netaddr.inet.ip = PR_htonl( MY_INADDR ); 1.153 + 1.154 + /* --- Bind the socket --- */ 1.155 + while ( !bound ) 1.156 + { 1.157 + DPRINTF("udpsrv: UDP_Server(): Binding socket\n" ); 1.158 + rv = PR_Bind( svrSock, &netaddr ); 1.159 + if ( rv < 0 ) 1.160 + { 1.161 + if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR ) 1.162 + { 1.163 + if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \ 1.164 + PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); 1.165 + PR_Sleep( PR_MillisecondsToInterval( 2000 )); 1.166 + continue; 1.167 + } 1.168 + else 1.169 + { 1.170 + passed = PR_FALSE; 1.171 + if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \ 1.172 + PR_Bind(): failed: %ld with error: %ld\n", 1.173 + rv, PR_GetError() ); 1.174 + PR_Close( svrSock ); 1.175 + return; 1.176 + } 1.177 + } 1.178 + else 1.179 + bound = PR_TRUE; 1.180 + } 1.181 + ListNetAddr( "UDP_Server: after bind", &netaddr ); 1.182 + 1.183 + /* --- Recv the socket --- */ 1.184 + while( !endOfInput ) 1.185 + { 1.186 + DPRINTF("udpsrv: UDP_Server(): RecvFrom() socket\n" ); 1.187 + rv = PR_RecvFrom( svrSock, svrBuf, numBytes, 0, &netaddr, UDP_TIMEOUT ); 1.188 + if ( rv == -1 ) 1.189 + { 1.190 + passed = PR_FALSE; 1.191 + if (debug_mode) 1.192 + PR_fprintf(output, 1.193 + "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n", 1.194 + PR_GetError() ); 1.195 + PR_Close( svrSock ); 1.196 + return; 1.197 + } 1.198 + ListNetAddr( "UDP_Server after RecvFrom", &netaddr ); 1.199 + 1.200 + srvBytesRead += rv; 1.201 + 1.202 + if ( svrBuf[0] == 'E' ) 1.203 + { 1.204 + DPRINTF("udpsrv: UDP_Server(): EOF on input detected\n" ); 1.205 + endOfInput = PR_TRUE; 1.206 + } 1.207 + 1.208 + /* --- Send the socket --- */ 1.209 + DPRINTF("udpsrv: UDP_Server(): SendTo(): socket\n" ); 1.210 + rv = PR_SendTo( svrSock, svrBuf, rv, 0, &netaddr, PR_INTERVAL_NO_TIMEOUT ); 1.211 + if ( rv == -1 ) 1.212 + { 1.213 + passed = PR_FALSE; 1.214 + if (debug_mode) 1.215 + PR_fprintf(output, 1.216 + "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n", 1.217 + PR_GetError() ); 1.218 + PR_Close( svrSock ); 1.219 + return; 1.220 + } 1.221 + ListNetAddr( "UDP_Server after SendTo", &netaddr ); 1.222 + } 1.223 + 1.224 + /* --- Close the socket --- */ 1.225 + DPRINTF("udpsrv: UDP_Server(): Closing socket\n" ); 1.226 + rv = PR_Close( svrSock ); 1.227 + if ( rv != PR_SUCCESS ) 1.228 + { 1.229 + passed = PR_FALSE; 1.230 + if (debug_mode) 1.231 + PR_fprintf(output, 1.232 + "udpsrv: UDP_Server(): PR_Close(): failed to close socket\n" ); 1.233 + return; 1.234 + } 1.235 + 1.236 + DPRINTF("udpsrv: UDP_Server(): Normal end\n" ); 1.237 +} /* --- end UDP_Server() --- */ 1.238 + 1.239 + 1.240 +static char cltBuf[UDP_BUF_SIZE]; 1.241 +static char cltBufin[UDP_BUF_SIZE]; 1.242 +/******************************************************************** 1.243 +** UDP_Client() -- Test a UDP client application 1.244 +** 1.245 +** Description: 1.246 +** 1.247 +** Arguments: 1.248 +** 1.249 +** 1.250 +** Returns: 1.251 +** 0 -- Successful execution 1.252 +** 1 -- Test failed. 1.253 +** 1.254 +** Notes: 1.255 +** 1.256 +** 1.257 +******************************************************************** 1.258 +*/ 1.259 +static void PR_CALLBACK UDP_Client( void *arg ) 1.260 +{ 1.261 + PRFileDesc *cltSock; 1.262 + PRInt32 rv; 1.263 + PRBool bound = PR_FALSE; 1.264 + PRNetAddr netaddr; 1.265 + PRNetAddr netaddrx; 1.266 + PRBool endOfInput = PR_FALSE; 1.267 + PRInt32 numBytes = UDP_DGRAM_SIZE; 1.268 + PRInt32 writeThisMany = UDP_AMOUNT_TO_WRITE; 1.269 + int i; 1.270 + 1.271 + 1.272 + DPRINTF("udpsrv: UDP_Client(): starting\n" ); 1.273 + 1.274 + /* --- Create the socket --- */ 1.275 + cltSock = PR_NewUDPSocket(); 1.276 + if ( cltSock == NULL ) 1.277 + { 1.278 + passed = PR_FALSE; 1.279 + if (debug_mode) 1.280 + PR_fprintf(output, 1.281 + "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" ); 1.282 + return; 1.283 + } 1.284 + 1.285 + /* --- Initialize the sockaddr_in structure --- */ 1.286 + memset( &netaddr, 0, sizeof( netaddr )); 1.287 + netaddr.inet.family = PR_AF_INET; 1.288 + netaddr.inet.ip = PR_htonl( MY_INADDR ); 1.289 + netaddr.inet.port = PR_htons( UDP_CLIENT_PORT ); 1.290 + 1.291 + /* --- Initialize the write buffer --- */ 1.292 + for ( i = 0; i < UDP_BUF_SIZE ; i++ ) 1.293 + cltBuf[i] = i; 1.294 + 1.295 + /* --- Bind the socket --- */ 1.296 + while ( !bound ) 1.297 + { 1.298 + DPRINTF("udpsrv: UDP_Client(): Binding socket\n" ); 1.299 + rv = PR_Bind( cltSock, &netaddr ); 1.300 + if ( rv < 0 ) 1.301 + { 1.302 + if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR ) 1.303 + { 1.304 + if (debug_mode) 1.305 + PR_fprintf(output, 1.306 + "udpsrv: UDP_Client(): PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); 1.307 + PR_Sleep( PR_MillisecondsToInterval( 2000 )); 1.308 + continue; 1.309 + } 1.310 + else 1.311 + { 1.312 + passed = PR_FALSE; 1.313 + if (debug_mode) 1.314 + PR_fprintf(output, 1.315 + "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n", 1.316 + rv, PR_GetError() ); 1.317 + PR_Close( cltSock ); 1.318 + return; 1.319 + } 1.320 + } 1.321 + else 1.322 + bound = PR_TRUE; 1.323 + } 1.324 + ListNetAddr( "UDP_Client after Bind", &netaddr ); 1.325 + 1.326 + /* --- Initialize the sockaddr_in structure --- */ 1.327 + memset( &netaddr, 0, sizeof( netaddr )); 1.328 + netaddr.inet.family = PR_AF_INET; 1.329 + netaddr.inet.ip = PR_htonl( PEER_INADDR ); 1.330 + netaddr.inet.port = PR_htons( UDP_SERVER_PORT ); 1.331 + 1.332 + /* --- send and receive packets until no more data left */ 1.333 + while( !endOfInput ) 1.334 + { 1.335 + /* 1.336 + ** Signal EOF in the data stream on the last packet 1.337 + */ 1.338 + if ( writeThisMany <= UDP_DGRAM_SIZE ) 1.339 + { 1.340 + DPRINTF("udpsrv: UDP_Client(): Send EOF packet\n" ); 1.341 + cltBuf[0] = 'E'; 1.342 + endOfInput = PR_TRUE; 1.343 + } 1.344 + 1.345 + /* --- SendTo the socket --- */ 1.346 + if ( writeThisMany > UDP_DGRAM_SIZE ) 1.347 + numBytes = UDP_DGRAM_SIZE; 1.348 + else 1.349 + numBytes = writeThisMany; 1.350 + writeThisMany -= numBytes; 1.351 + { 1.352 + char mbuf[256]; 1.353 + sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n", 1.354 + writeThisMany, numBytes ); 1.355 + DPRINTF( mbuf ); 1.356 + } 1.357 + 1.358 + DPRINTF("udpsrv: UDP_Client(): SendTo(): socket\n" ); 1.359 + rv = PR_SendTo( cltSock, cltBuf, numBytes, 0, &netaddr, UDP_TIMEOUT ); 1.360 + if ( rv == -1 ) 1.361 + { 1.362 + passed = PR_FALSE; 1.363 + if (debug_mode) 1.364 + PR_fprintf(output, 1.365 + "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n", 1.366 + PR_GetError() ); 1.367 + PR_Close( cltSock ); 1.368 + return; 1.369 + } 1.370 + ListNetAddr( "UDP_Client after SendTo", &netaddr ); 1.371 + 1.372 + /* --- RecvFrom the socket --- */ 1.373 + memset( cltBufin, 0, UDP_BUF_SIZE ); 1.374 + DPRINTF("udpsrv: UDP_Client(): RecvFrom(): socket\n" ); 1.375 + rv = PR_RecvFrom( cltSock, cltBufin, numBytes, 0, &netaddrx, UDP_TIMEOUT ); 1.376 + if ( rv == -1 ) 1.377 + { 1.378 + passed = PR_FALSE; 1.379 + if (debug_mode) PR_fprintf(output, 1.380 + "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n", 1.381 + PR_GetError() ); 1.382 + PR_Close( cltSock ); 1.383 + return; 1.384 + } 1.385 + ListNetAddr( "UDP_Client after RecvFrom()", &netaddr ); 1.386 + cltBytesRead += rv; 1.387 + 1.388 + /* --- verify buffer --- */ 1.389 + for ( i = 0; i < rv ; i++ ) 1.390 + { 1.391 + if ( cltBufin[i] != i ) 1.392 + { 1.393 + /* --- special case, end of input --- */ 1.394 + if ( endOfInput && i == 0 && cltBufin[0] == 'E' ) 1.395 + continue; 1.396 + passed = PR_FALSE; 1.397 + if (debug_mode) PR_fprintf(output, 1.398 + "udpsrv: UDP_Client(): return data mismatch\n" ); 1.399 + PR_Close( cltSock ); 1.400 + return; 1.401 + } 1.402 + } 1.403 + if (debug_mode) PR_fprintf(output, "."); 1.404 + } 1.405 + 1.406 + /* --- Close the socket --- */ 1.407 + DPRINTF("udpsrv: UDP_Server(): Closing socket\n" ); 1.408 + rv = PR_Close( cltSock ); 1.409 + if ( rv != PR_SUCCESS ) 1.410 + { 1.411 + passed = PR_FALSE; 1.412 + if (debug_mode) PR_fprintf(output, 1.413 + "udpsrv: UDP_Client(): PR_Close(): failed to close socket\n" ); 1.414 + return; 1.415 + } 1.416 + DPRINTF("udpsrv: UDP_Client(): ending\n" ); 1.417 +} /* --- end UDP_Client() --- */ 1.418 + 1.419 +/******************************************************************** 1.420 +** main() -- udpsrv 1.421 +** 1.422 +** arguments: 1.423 +** 1.424 +** Returns: 1.425 +** 0 -- Successful execution 1.426 +** 1 -- Test failed. 1.427 +** 1.428 +** Description: 1.429 +** 1.430 +** Standard test case setup. 1.431 +** 1.432 +** Calls the function UDP_Server() 1.433 +** 1.434 +******************************************************************** 1.435 +*/ 1.436 + 1.437 +int main(int argc, char **argv) 1.438 +{ 1.439 + PRThread *srv, *clt; 1.440 +/* The command line argument: -d is used to determine if the test is being run 1.441 + in debug mode. The regress tool requires only one line output:PASS or FAIL. 1.442 + All of the printfs associated with this test has been handled with a if (debug_mode) 1.443 + test. 1.444 + Usage: test_name -d -v 1.445 + */ 1.446 + PLOptStatus os; 1.447 + PLOptState *opt = PL_CreateOptState(argc, argv, "dv"); 1.448 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.449 + { 1.450 + if (PL_OPT_BAD == os) continue; 1.451 + switch (opt->option) 1.452 + { 1.453 + case 'd': /* debug mode */ 1.454 + debug_mode = 1; 1.455 + break; 1.456 + case 'v': /* verbose mode */ 1.457 + _debug_on = 1; 1.458 + break; 1.459 + default: 1.460 + break; 1.461 + } 1.462 + } 1.463 + PL_DestroyOptState(opt); 1.464 + 1.465 + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 1.466 + PR_STDIO_INIT(); 1.467 + output = PR_STDERR; 1.468 + 1.469 + PR_SetConcurrency(4); 1.470 + 1.471 + /* 1.472 + ** Create the Server thread 1.473 + */ 1.474 + DPRINTF( "udpsrv: Creating Server Thread\n" ); 1.475 + srv = PR_CreateThread( PR_USER_THREAD, 1.476 + UDP_Server, 1.477 + (void *) 0, 1.478 + PR_PRIORITY_LOW, 1.479 + PR_LOCAL_THREAD, 1.480 + PR_JOINABLE_THREAD, 1.481 + 0 ); 1.482 + if ( srv == NULL ) 1.483 + { 1.484 + if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" ); 1.485 + passed = PR_FALSE; 1.486 + } 1.487 + 1.488 + /* 1.489 + ** Give the Server time to Start 1.490 + */ 1.491 + DPRINTF( "udpsrv: Pausing to allow Server to start\n" ); 1.492 + PR_Sleep( PR_MillisecondsToInterval(200) ); 1.493 + 1.494 + /* 1.495 + ** Create the Client thread 1.496 + */ 1.497 + DPRINTF( "udpsrv: Creating Client Thread\n" ); 1.498 + clt = PR_CreateThread( PR_USER_THREAD, 1.499 + UDP_Client, 1.500 + (void *) 0, 1.501 + PR_PRIORITY_LOW, 1.502 + PR_LOCAL_THREAD, 1.503 + PR_JOINABLE_THREAD, 1.504 + 0 ); 1.505 + if ( clt == NULL ) 1.506 + { 1.507 + if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" ); 1.508 + passed = PR_FALSE; 1.509 + } 1.510 + 1.511 + /* 1.512 + ** 1.513 + */ 1.514 + DPRINTF("udpsrv: Waiting to join Server & Client Threads\n" ); 1.515 + PR_JoinThread( srv ); 1.516 + PR_JoinThread( clt ); 1.517 + 1.518 + /* 1.519 + ** Evaluate test results 1.520 + */ 1.521 + if (debug_mode) PR_fprintf(output, "\n\nudpsrv: main(): cltBytesRead(%ld), \ 1.522 + srvBytesRead(%ld), expected(%ld)\n", 1.523 + cltBytesRead, srvBytesRead, UDP_AMOUNT_TO_WRITE ); 1.524 + if ( cltBytesRead != srvBytesRead || cltBytesRead != UDP_AMOUNT_TO_WRITE ) 1.525 + { 1.526 + passed = PR_FALSE; 1.527 + } 1.528 + PR_Cleanup(); 1.529 + if ( passed ) 1.530 + return 0; 1.531 + else 1.532 + return 1; 1.533 +} /* --- end main() --- */