udpsrv.c (14284B)
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) \ 80 if (_debug_on) PR_fprintf(output, arg) 81 82 /******************************************************************* 83 ** ListNetAddr() -- Display the Net Address on stdout 84 ** 85 ** Description: displays the component parts of a PRNetAddr struct 86 ** 87 ** Arguments: address of PRNetAddr structure to display 88 ** 89 ** Returns: void 90 ** 91 ** Notes: 92 ** 93 ******************************************************************** 94 */ 95 void ListNetAddr(char* msg, PRNetAddr* na) { 96 char mbuf[256]; 97 98 sprintf(mbuf, "ListNetAddr: %s family: %d, port: %d, ip: %8.8X\n", msg, 99 na->inet.family, PR_ntohs(na->inet.port), PR_ntohl(na->inet.ip)); 100 #if 0 101 DPRINTF( mbuf ); 102 #endif 103 } /* --- end ListNetAddr() --- */ 104 105 /******************************************************************** 106 ** UDP_Server() -- Test a UDP server application 107 ** 108 ** Description: The Server side of a UDP Client/Server application. 109 ** 110 ** Arguments: none 111 ** 112 ** Returns: void 113 ** 114 ** Notes: 115 ** 116 ** 117 ******************************************************************** 118 */ 119 static void PR_CALLBACK UDP_Server(void* arg) { 120 static char svrBuf[UDP_BUF_SIZE]; 121 PRFileDesc* svrSock; 122 PRInt32 rv; 123 PRNetAddr netaddr; 124 PRBool bound = PR_FALSE; 125 PRBool endOfInput = PR_FALSE; 126 PRInt32 numBytes = UDP_DGRAM_SIZE; 127 128 DPRINTF("udpsrv: UDP_Server(): starting\n"); 129 130 /* --- Create the socket --- */ 131 DPRINTF("udpsrv: UDP_Server(): Creating UDP Socket\n"); 132 svrSock = PR_NewUDPSocket(); 133 if (svrSock == NULL) { 134 passed = PR_FALSE; 135 if (debug_mode) 136 PR_fprintf(output, 137 "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n"); 138 return; 139 } 140 141 /* --- Initialize the sockaddr_in structure --- */ 142 memset(&netaddr, 0, sizeof(netaddr)); 143 netaddr.inet.family = PR_AF_INET; 144 netaddr.inet.port = PR_htons(UDP_SERVER_PORT); 145 netaddr.inet.ip = PR_htonl(MY_INADDR); 146 147 /* --- Bind the socket --- */ 148 while (!bound) { 149 DPRINTF("udpsrv: UDP_Server(): Binding socket\n"); 150 rv = PR_Bind(svrSock, &netaddr); 151 if (rv < 0) { 152 if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { 153 if (debug_mode) 154 PR_fprintf(output, 155 "udpsrv: UDP_Server(): \ 156 PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); 157 PR_Sleep(PR_MillisecondsToInterval(2000)); 158 continue; 159 } else { 160 passed = PR_FALSE; 161 if (debug_mode) 162 PR_fprintf(output, 163 "udpsrv: UDP_Server(): \ 164 PR_Bind(): failed: %ld with error: %ld\n", 165 rv, PR_GetError()); 166 PR_Close(svrSock); 167 return; 168 } 169 } else { 170 bound = PR_TRUE; 171 } 172 } 173 ListNetAddr("UDP_Server: after bind", &netaddr); 174 175 /* --- Recv the socket --- */ 176 while (!endOfInput) { 177 DPRINTF("udpsrv: UDP_Server(): RecvFrom() socket\n"); 178 rv = PR_RecvFrom(svrSock, svrBuf, numBytes, 0, &netaddr, UDP_TIMEOUT); 179 if (rv == -1) { 180 passed = PR_FALSE; 181 if (debug_mode) 182 PR_fprintf( 183 output, 184 "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n", 185 PR_GetError()); 186 PR_Close(svrSock); 187 return; 188 } 189 ListNetAddr("UDP_Server after RecvFrom", &netaddr); 190 191 srvBytesRead += rv; 192 193 if (svrBuf[0] == 'E') { 194 DPRINTF("udpsrv: UDP_Server(): EOF on input detected\n"); 195 endOfInput = PR_TRUE; 196 } 197 198 /* --- Send the socket --- */ 199 DPRINTF("udpsrv: UDP_Server(): SendTo(): socket\n"); 200 rv = PR_SendTo(svrSock, svrBuf, rv, 0, &netaddr, PR_INTERVAL_NO_TIMEOUT); 201 if (rv == -1) { 202 passed = PR_FALSE; 203 if (debug_mode) 204 PR_fprintf( 205 output, 206 "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n", 207 PR_GetError()); 208 PR_Close(svrSock); 209 return; 210 } 211 ListNetAddr("UDP_Server after SendTo", &netaddr); 212 } 213 214 /* --- Close the socket --- */ 215 DPRINTF("udpsrv: UDP_Server(): Closing socket\n"); 216 rv = PR_Close(svrSock); 217 if (rv != PR_SUCCESS) { 218 passed = PR_FALSE; 219 if (debug_mode) 220 PR_fprintf(output, 221 "udpsrv: UDP_Server(): PR_Close(): failed to close socket\n"); 222 return; 223 } 224 225 DPRINTF("udpsrv: UDP_Server(): Normal end\n"); 226 } /* --- end UDP_Server() --- */ 227 228 static char cltBuf[UDP_BUF_SIZE]; 229 static char cltBufin[UDP_BUF_SIZE]; 230 /******************************************************************** 231 ** UDP_Client() -- Test a UDP client application 232 ** 233 ** Description: 234 ** 235 ** Arguments: 236 ** 237 ** 238 ** Returns: 239 ** 0 -- Successful execution 240 ** 1 -- Test failed. 241 ** 242 ** Notes: 243 ** 244 ** 245 ******************************************************************** 246 */ 247 static void PR_CALLBACK UDP_Client(void* arg) { 248 PRFileDesc* cltSock; 249 PRInt32 rv; 250 PRBool bound = PR_FALSE; 251 PRNetAddr netaddr; 252 PRNetAddr netaddrx; 253 PRBool endOfInput = PR_FALSE; 254 PRInt32 numBytes = UDP_DGRAM_SIZE; 255 PRInt32 writeThisMany = UDP_AMOUNT_TO_WRITE; 256 int i; 257 258 DPRINTF("udpsrv: UDP_Client(): starting\n"); 259 260 /* --- Create the socket --- */ 261 cltSock = PR_NewUDPSocket(); 262 if (cltSock == NULL) { 263 passed = PR_FALSE; 264 if (debug_mode) 265 PR_fprintf(output, 266 "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n"); 267 return; 268 } 269 270 /* --- Initialize the sockaddr_in structure --- */ 271 memset(&netaddr, 0, sizeof(netaddr)); 272 netaddr.inet.family = PR_AF_INET; 273 netaddr.inet.ip = PR_htonl(MY_INADDR); 274 netaddr.inet.port = PR_htons(UDP_CLIENT_PORT); 275 276 /* --- Initialize the write buffer --- */ 277 for (i = 0; i < UDP_BUF_SIZE; i++) { 278 cltBuf[i] = i; 279 } 280 281 /* --- Bind the socket --- */ 282 while (!bound) { 283 DPRINTF("udpsrv: UDP_Client(): Binding socket\n"); 284 rv = PR_Bind(cltSock, &netaddr); 285 if (rv < 0) { 286 if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { 287 if (debug_mode) 288 PR_fprintf(output, 289 "udpsrv: UDP_Client(): PR_Bind(): reports: " 290 "PR_ADDRESS_IN_USE_ERROR\n"); 291 PR_Sleep(PR_MillisecondsToInterval(2000)); 292 continue; 293 } else { 294 passed = PR_FALSE; 295 if (debug_mode) 296 PR_fprintf( 297 output, 298 "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n", 299 rv, PR_GetError()); 300 PR_Close(cltSock); 301 return; 302 } 303 } else { 304 bound = PR_TRUE; 305 } 306 } 307 ListNetAddr("UDP_Client after Bind", &netaddr); 308 309 /* --- Initialize the sockaddr_in structure --- */ 310 memset(&netaddr, 0, sizeof(netaddr)); 311 netaddr.inet.family = PR_AF_INET; 312 netaddr.inet.ip = PR_htonl(PEER_INADDR); 313 netaddr.inet.port = PR_htons(UDP_SERVER_PORT); 314 315 /* --- send and receive packets until no more data left */ 316 while (!endOfInput) { 317 /* 318 ** Signal EOF in the data stream on the last packet 319 */ 320 if (writeThisMany <= UDP_DGRAM_SIZE) { 321 DPRINTF("udpsrv: UDP_Client(): Send EOF packet\n"); 322 cltBuf[0] = 'E'; 323 endOfInput = PR_TRUE; 324 } 325 326 /* --- SendTo the socket --- */ 327 if (writeThisMany > UDP_DGRAM_SIZE) { 328 numBytes = UDP_DGRAM_SIZE; 329 } else { 330 numBytes = writeThisMany; 331 } 332 writeThisMany -= numBytes; 333 { 334 char mbuf[256]; 335 sprintf(mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n", 336 writeThisMany, numBytes); 337 DPRINTF(mbuf); 338 } 339 340 DPRINTF("udpsrv: UDP_Client(): SendTo(): socket\n"); 341 rv = PR_SendTo(cltSock, cltBuf, numBytes, 0, &netaddr, UDP_TIMEOUT); 342 if (rv == -1) { 343 passed = PR_FALSE; 344 if (debug_mode) 345 PR_fprintf( 346 output, 347 "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n", 348 PR_GetError()); 349 PR_Close(cltSock); 350 return; 351 } 352 ListNetAddr("UDP_Client after SendTo", &netaddr); 353 354 /* --- RecvFrom the socket --- */ 355 memset(cltBufin, 0, UDP_BUF_SIZE); 356 DPRINTF("udpsrv: UDP_Client(): RecvFrom(): socket\n"); 357 rv = PR_RecvFrom(cltSock, cltBufin, numBytes, 0, &netaddrx, UDP_TIMEOUT); 358 if (rv == -1) { 359 passed = PR_FALSE; 360 if (debug_mode) 361 PR_fprintf( 362 output, 363 "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n", 364 PR_GetError()); 365 PR_Close(cltSock); 366 return; 367 } 368 ListNetAddr("UDP_Client after RecvFrom()", &netaddr); 369 cltBytesRead += rv; 370 371 /* --- verify buffer --- */ 372 for (i = 0; i < rv; i++) { 373 if (cltBufin[i] != i) { 374 /* --- special case, end of input --- */ 375 if (endOfInput && i == 0 && cltBufin[0] == 'E') { 376 continue; 377 } 378 passed = PR_FALSE; 379 if (debug_mode) 380 PR_fprintf(output, "udpsrv: UDP_Client(): return data mismatch\n"); 381 PR_Close(cltSock); 382 return; 383 } 384 } 385 if (debug_mode) { 386 PR_fprintf(output, "."); 387 } 388 } 389 390 /* --- Close the socket --- */ 391 DPRINTF("udpsrv: UDP_Server(): Closing socket\n"); 392 rv = PR_Close(cltSock); 393 if (rv != PR_SUCCESS) { 394 passed = PR_FALSE; 395 if (debug_mode) 396 PR_fprintf(output, 397 "udpsrv: UDP_Client(): PR_Close(): failed to close socket\n"); 398 return; 399 } 400 DPRINTF("udpsrv: UDP_Client(): ending\n"); 401 } /* --- end UDP_Client() --- */ 402 403 /******************************************************************** 404 ** main() -- udpsrv 405 ** 406 ** arguments: 407 ** 408 ** Returns: 409 ** 0 -- Successful execution 410 ** 1 -- Test failed. 411 ** 412 ** Description: 413 ** 414 ** Standard test case setup. 415 ** 416 ** Calls the function UDP_Server() 417 ** 418 ******************************************************************** 419 */ 420 421 int main(int argc, char** argv) { 422 PRThread *srv, *clt; 423 /* The command line argument: -d is used to determine if the test is being run 424 in debug mode. The regress tool requires only one line output:PASS or 425 FAIL. All of the printfs associated with this test has been handled with a 426 if (debug_mode) test. Usage: test_name -d -v 427 */ 428 PLOptStatus os; 429 PLOptState* opt = PL_CreateOptState(argc, argv, "dv"); 430 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 431 if (PL_OPT_BAD == os) { 432 continue; 433 } 434 switch (opt->option) { 435 case 'd': /* debug mode */ 436 debug_mode = 1; 437 break; 438 case 'v': /* verbose mode */ 439 _debug_on = 1; 440 break; 441 default: 442 break; 443 } 444 } 445 PL_DestroyOptState(opt); 446 447 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 448 output = PR_STDERR; 449 450 PR_SetConcurrency(4); 451 452 /* 453 ** Create the Server thread 454 */ 455 DPRINTF("udpsrv: Creating Server Thread\n"); 456 srv = PR_CreateThread(PR_USER_THREAD, UDP_Server, (void*)0, PR_PRIORITY_LOW, 457 PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); 458 if (srv == NULL) { 459 if (debug_mode) { 460 PR_fprintf(output, "udpsrv: Cannot create server thread\n"); 461 } 462 passed = PR_FALSE; 463 } 464 465 /* 466 ** Give the Server time to Start 467 */ 468 DPRINTF("udpsrv: Pausing to allow Server to start\n"); 469 PR_Sleep(PR_MillisecondsToInterval(200)); 470 471 /* 472 ** Create the Client thread 473 */ 474 DPRINTF("udpsrv: Creating Client Thread\n"); 475 clt = PR_CreateThread(PR_USER_THREAD, UDP_Client, (void*)0, PR_PRIORITY_LOW, 476 PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); 477 if (clt == NULL) { 478 if (debug_mode) { 479 PR_fprintf(output, "udpsrv: Cannot create server thread\n"); 480 } 481 passed = PR_FALSE; 482 } 483 484 /* 485 ** 486 */ 487 DPRINTF("udpsrv: Waiting to join Server & Client Threads\n"); 488 PR_JoinThread(srv); 489 PR_JoinThread(clt); 490 491 /* 492 ** Evaluate test results 493 */ 494 if (debug_mode) 495 PR_fprintf(output, 496 "\n\nudpsrv: main(): cltBytesRead(%ld), \ 497 srvBytesRead(%ld), expected(%ld)\n", 498 cltBytesRead, srvBytesRead, UDP_AMOUNT_TO_WRITE); 499 if (cltBytesRead != srvBytesRead || cltBytesRead != UDP_AMOUNT_TO_WRITE) { 500 passed = PR_FALSE; 501 } 502 PR_Cleanup(); 503 if (passed) { 504 return 0; 505 } else { 506 return 1; 507 } 508 } /* --- end main() --- */