udpsrv.c 16 KB

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