summaryrefslogtreecommitdiffstats
path: root/nsprpub/pr/tests/udpsrv.c
diff options
context:
space:
mode:
Diffstat (limited to 'nsprpub/pr/tests/udpsrv.c')
-rw-r--r--nsprpub/pr/tests/udpsrv.c546
1 files changed, 546 insertions, 0 deletions
diff --git a/nsprpub/pr/tests/udpsrv.c b/nsprpub/pr/tests/udpsrv.c
new file mode 100644
index 0000000000..39a919c606
--- /dev/null
+++ b/nsprpub/pr/tests/udpsrv.c
@@ -0,0 +1,546 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*******************************************************************
+** udpsrc.c -- Test basic function of UDP server
+**
+** udpsrv operates on the same machine with program udpclt.
+** udpsrv is the server side of a udp sockets application.
+** udpclt is the client side of a udp sockets application.
+**
+** The test is designed to assist developers in porting/debugging
+** the UDP socket functions of NSPR.
+**
+** This test is not a stress test.
+**
+** main() starts two threads: UDP_Server() and UDP_Client();
+** main() uses PR_JoinThread() to wait for the threads to complete.
+**
+** UDP_Server() does repeated recvfrom()s from a socket.
+** He detects an EOF condition set by UDP_Client(). For each
+** packet received by UDP_Server(), he checks its content for
+** expected content, then sends the packet back to UDP_Client().
+**
+** UDP_Client() sends packets to UDP_Server() using sendto()
+** he recieves packets back from the server via recvfrom().
+** After he sends enough packets containing UDP_AMOUNT_TO_WRITE
+** bytes of data, he sends an EOF message.
+**
+** The test issues a pass/fail message at end.
+**
+** Notes:
+** The variable "_debug_on" can be set to 1 to cause diagnostic
+** messages related to client/server synchronization. Useful when
+** the test hangs.
+**
+** Error messages are written to stdout.
+**
+********************************************************************
+*/
+/* --- include files --- */
+#include "nspr.h"
+#include "prpriv.h"
+
+#include "plgetopt.h"
+#include "prttools.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef XP_PC
+#define mode_t int
+#endif
+
+#define UDP_BUF_SIZE 4096
+#define UDP_DGRAM_SIZE 128
+#define UDP_AMOUNT_TO_WRITE (PRInt32)((UDP_DGRAM_SIZE * 1000l) +1)
+#define NUM_UDP_CLIENTS 1
+#define NUM_UDP_DATAGRAMS_PER_CLIENT 5
+#define UDP_SERVER_PORT 9050
+#define UDP_CLIENT_PORT 9053
+#define MY_INADDR PR_INADDR_ANY
+#define PEER_INADDR PR_INADDR_LOOPBACK
+
+#define UDP_TIMEOUT 400000
+/* #define UDP_TIMEOUT PR_INTERVAL_NO_TIMEOUT */
+
+/* --- static data --- */
+static PRIntn _debug_on = 0;
+static PRBool passed = PR_TRUE;
+static PRUint32 cltBytesRead = 0;
+static PRUint32 srvBytesRead = 0;
+static PRFileDesc *output = NULL;
+
+/* --- static function declarations --- */
+#define DPRINTF(arg) if (_debug_on) PR_fprintf(output, arg)
+
+
+
+/*******************************************************************
+** ListNetAddr() -- Display the Net Address on stdout
+**
+** Description: displays the component parts of a PRNetAddr struct
+**
+** Arguments: address of PRNetAddr structure to display
+**
+** Returns: void
+**
+** Notes:
+**
+********************************************************************
+*/
+void ListNetAddr( char *msg, PRNetAddr *na )
+{
+ char mbuf[256];
+
+ sprintf( mbuf, "ListNetAddr: %s family: %d, port: %d, ip: %8.8X\n",
+ msg, na->inet.family, PR_ntohs( na->inet.port), PR_ntohl(na->inet.ip) );
+#if 0
+ DPRINTF( mbuf );
+#endif
+} /* --- end ListNetAddr() --- */
+
+/********************************************************************
+** UDP_Server() -- Test a UDP server application
+**
+** Description: The Server side of a UDP Client/Server application.
+**
+** Arguments: none
+**
+** Returns: void
+**
+** Notes:
+**
+**
+********************************************************************
+*/
+static void PR_CALLBACK UDP_Server( void *arg )
+{
+ static char svrBuf[UDP_BUF_SIZE];
+ PRFileDesc *svrSock;
+ PRInt32 rv;
+ PRNetAddr netaddr;
+ PRBool bound = PR_FALSE;
+ PRBool endOfInput = PR_FALSE;
+ PRInt32 numBytes = UDP_DGRAM_SIZE;
+
+ DPRINTF("udpsrv: UDP_Server(): starting\n" );
+
+ /* --- Create the socket --- */
+ DPRINTF("udpsrv: UDP_Server(): Creating UDP Socket\n" );
+ svrSock = PR_NewUDPSocket();
+ if ( svrSock == NULL )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" );
+ return;
+ }
+
+ /* --- Initialize the sockaddr_in structure --- */
+ memset( &netaddr, 0, sizeof( netaddr ));
+ netaddr.inet.family = PR_AF_INET;
+ netaddr.inet.port = PR_htons( UDP_SERVER_PORT );
+ netaddr.inet.ip = PR_htonl( MY_INADDR );
+
+ /* --- Bind the socket --- */
+ while ( !bound )
+ {
+ DPRINTF("udpsrv: UDP_Server(): Binding socket\n" );
+ rv = PR_Bind( svrSock, &netaddr );
+ if ( rv < 0 )
+ {
+ if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR )
+ {
+ if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \
+ PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n");
+ PR_Sleep( PR_MillisecondsToInterval( 2000 ));
+ continue;
+ }
+ else
+ {
+ passed = PR_FALSE;
+ if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \
+ PR_Bind(): failed: %ld with error: %ld\n",
+ rv, PR_GetError() );
+ PR_Close( svrSock );
+ return;
+ }
+ }
+ else {
+ bound = PR_TRUE;
+ }
+ }
+ ListNetAddr( "UDP_Server: after bind", &netaddr );
+
+ /* --- Recv the socket --- */
+ while( !endOfInput )
+ {
+ DPRINTF("udpsrv: UDP_Server(): RecvFrom() socket\n" );
+ rv = PR_RecvFrom( svrSock, svrBuf, numBytes, 0, &netaddr, UDP_TIMEOUT );
+ if ( rv == -1 )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n",
+ PR_GetError() );
+ PR_Close( svrSock );
+ return;
+ }
+ ListNetAddr( "UDP_Server after RecvFrom", &netaddr );
+
+ srvBytesRead += rv;
+
+ if ( svrBuf[0] == 'E' )
+ {
+ DPRINTF("udpsrv: UDP_Server(): EOF on input detected\n" );
+ endOfInput = PR_TRUE;
+ }
+
+ /* --- Send the socket --- */
+ DPRINTF("udpsrv: UDP_Server(): SendTo(): socket\n" );
+ rv = PR_SendTo( svrSock, svrBuf, rv, 0, &netaddr, PR_INTERVAL_NO_TIMEOUT );
+ if ( rv == -1 )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n",
+ PR_GetError() );
+ PR_Close( svrSock );
+ return;
+ }
+ ListNetAddr( "UDP_Server after SendTo", &netaddr );
+ }
+
+ /* --- Close the socket --- */
+ DPRINTF("udpsrv: UDP_Server(): Closing socket\n" );
+ rv = PR_Close( svrSock );
+ if ( rv != PR_SUCCESS )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Server(): PR_Close(): failed to close socket\n" );
+ return;
+ }
+
+ DPRINTF("udpsrv: UDP_Server(): Normal end\n" );
+} /* --- end UDP_Server() --- */
+
+
+static char cltBuf[UDP_BUF_SIZE];
+static char cltBufin[UDP_BUF_SIZE];
+/********************************************************************
+** UDP_Client() -- Test a UDP client application
+**
+** Description:
+**
+** Arguments:
+**
+**
+** Returns:
+** 0 -- Successful execution
+** 1 -- Test failed.
+**
+** Notes:
+**
+**
+********************************************************************
+*/
+static void PR_CALLBACK UDP_Client( void *arg )
+{
+ PRFileDesc *cltSock;
+ PRInt32 rv;
+ PRBool bound = PR_FALSE;
+ PRNetAddr netaddr;
+ PRNetAddr netaddrx;
+ PRBool endOfInput = PR_FALSE;
+ PRInt32 numBytes = UDP_DGRAM_SIZE;
+ PRInt32 writeThisMany = UDP_AMOUNT_TO_WRITE;
+ int i;
+
+
+ DPRINTF("udpsrv: UDP_Client(): starting\n" );
+
+ /* --- Create the socket --- */
+ cltSock = PR_NewUDPSocket();
+ if ( cltSock == NULL )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" );
+ return;
+ }
+
+ /* --- Initialize the sockaddr_in structure --- */
+ memset( &netaddr, 0, sizeof( netaddr ));
+ netaddr.inet.family = PR_AF_INET;
+ netaddr.inet.ip = PR_htonl( MY_INADDR );
+ netaddr.inet.port = PR_htons( UDP_CLIENT_PORT );
+
+ /* --- Initialize the write buffer --- */
+ for ( i = 0; i < UDP_BUF_SIZE ; i++ ) {
+ cltBuf[i] = i;
+ }
+
+ /* --- Bind the socket --- */
+ while ( !bound )
+ {
+ DPRINTF("udpsrv: UDP_Client(): Binding socket\n" );
+ rv = PR_Bind( cltSock, &netaddr );
+ if ( rv < 0 )
+ {
+ if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR )
+ {
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n");
+ PR_Sleep( PR_MillisecondsToInterval( 2000 ));
+ continue;
+ }
+ else
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n",
+ rv, PR_GetError() );
+ PR_Close( cltSock );
+ return;
+ }
+ }
+ else {
+ bound = PR_TRUE;
+ }
+ }
+ ListNetAddr( "UDP_Client after Bind", &netaddr );
+
+ /* --- Initialize the sockaddr_in structure --- */
+ memset( &netaddr, 0, sizeof( netaddr ));
+ netaddr.inet.family = PR_AF_INET;
+ netaddr.inet.ip = PR_htonl( PEER_INADDR );
+ netaddr.inet.port = PR_htons( UDP_SERVER_PORT );
+
+ /* --- send and receive packets until no more data left */
+ while( !endOfInput )
+ {
+ /*
+ ** Signal EOF in the data stream on the last packet
+ */
+ if ( writeThisMany <= UDP_DGRAM_SIZE )
+ {
+ DPRINTF("udpsrv: UDP_Client(): Send EOF packet\n" );
+ cltBuf[0] = 'E';
+ endOfInput = PR_TRUE;
+ }
+
+ /* --- SendTo the socket --- */
+ if ( writeThisMany > UDP_DGRAM_SIZE ) {
+ numBytes = UDP_DGRAM_SIZE;
+ }
+ else {
+ numBytes = writeThisMany;
+ }
+ writeThisMany -= numBytes;
+ {
+ char mbuf[256];
+ sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n",
+ writeThisMany, numBytes );
+ DPRINTF( mbuf );
+ }
+
+ DPRINTF("udpsrv: UDP_Client(): SendTo(): socket\n" );
+ rv = PR_SendTo( cltSock, cltBuf, numBytes, 0, &netaddr, UDP_TIMEOUT );
+ if ( rv == -1 )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n",
+ PR_GetError() );
+ PR_Close( cltSock );
+ return;
+ }
+ ListNetAddr( "UDP_Client after SendTo", &netaddr );
+
+ /* --- RecvFrom the socket --- */
+ memset( cltBufin, 0, UDP_BUF_SIZE );
+ DPRINTF("udpsrv: UDP_Client(): RecvFrom(): socket\n" );
+ rv = PR_RecvFrom( cltSock, cltBufin, numBytes, 0, &netaddrx, UDP_TIMEOUT );
+ if ( rv == -1 )
+ {
+ passed = PR_FALSE;
+ if (debug_mode) PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n",
+ PR_GetError() );
+ PR_Close( cltSock );
+ return;
+ }
+ ListNetAddr( "UDP_Client after RecvFrom()", &netaddr );
+ cltBytesRead += rv;
+
+ /* --- verify buffer --- */
+ for ( i = 0; i < rv ; i++ )
+ {
+ if ( cltBufin[i] != i )
+ {
+ /* --- special case, end of input --- */
+ if ( endOfInput && i == 0 && cltBufin[0] == 'E' ) {
+ continue;
+ }
+ passed = PR_FALSE;
+ if (debug_mode) PR_fprintf(output,
+ "udpsrv: UDP_Client(): return data mismatch\n" );
+ PR_Close( cltSock );
+ return;
+ }
+ }
+ if (debug_mode) {
+ PR_fprintf(output, ".");
+ }
+ }
+
+ /* --- Close the socket --- */
+ DPRINTF("udpsrv: UDP_Server(): Closing socket\n" );
+ rv = PR_Close( cltSock );
+ if ( rv != PR_SUCCESS )
+ {
+ passed = PR_FALSE;
+ if (debug_mode) PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_Close(): failed to close socket\n" );
+ return;
+ }
+ DPRINTF("udpsrv: UDP_Client(): ending\n" );
+} /* --- end UDP_Client() --- */
+
+/********************************************************************
+** main() -- udpsrv
+**
+** arguments:
+**
+** Returns:
+** 0 -- Successful execution
+** 1 -- Test failed.
+**
+** Description:
+**
+** Standard test case setup.
+**
+** Calls the function UDP_Server()
+**
+********************************************************************
+*/
+
+int main(int argc, char **argv)
+{
+ PRThread *srv, *clt;
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d -v
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dv");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 'v': /* verbose mode */
+ _debug_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+ output = PR_STDERR;
+
+ PR_SetConcurrency(4);
+
+ /*
+ ** Create the Server thread
+ */
+ DPRINTF( "udpsrv: Creating Server Thread\n" );
+ srv = PR_CreateThread( PR_USER_THREAD,
+ UDP_Server,
+ (void *) 0,
+ PR_PRIORITY_LOW,
+ PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0 );
+ if ( srv == NULL )
+ {
+ if (debug_mode) {
+ PR_fprintf(output, "udpsrv: Cannot create server thread\n" );
+ }
+ passed = PR_FALSE;
+ }
+
+ /*
+ ** Give the Server time to Start
+ */
+ DPRINTF( "udpsrv: Pausing to allow Server to start\n" );
+ PR_Sleep( PR_MillisecondsToInterval(200) );
+
+ /*
+ ** Create the Client thread
+ */
+ DPRINTF( "udpsrv: Creating Client Thread\n" );
+ clt = PR_CreateThread( PR_USER_THREAD,
+ UDP_Client,
+ (void *) 0,
+ PR_PRIORITY_LOW,
+ PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0 );
+ if ( clt == NULL )
+ {
+ if (debug_mode) {
+ PR_fprintf(output, "udpsrv: Cannot create server thread\n" );
+ }
+ passed = PR_FALSE;
+ }
+
+ /*
+ **
+ */
+ DPRINTF("udpsrv: Waiting to join Server & Client Threads\n" );
+ PR_JoinThread( srv );
+ PR_JoinThread( clt );
+
+ /*
+ ** Evaluate test results
+ */
+ if (debug_mode) PR_fprintf(output, "\n\nudpsrv: main(): cltBytesRead(%ld), \
+ srvBytesRead(%ld), expected(%ld)\n",
+ cltBytesRead, srvBytesRead, UDP_AMOUNT_TO_WRITE );
+ if ( cltBytesRead != srvBytesRead || cltBytesRead != UDP_AMOUNT_TO_WRITE )
+ {
+ passed = PR_FALSE;
+ }
+ PR_Cleanup();
+ if ( passed ) {
+ return 0;
+ }
+ else {
+ return 1;
+ }
+} /* --- end main() --- */