Back to index

lightning-sunbird  0.9+nobinonly
udpsrv.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*******************************************************************
00039 ** udpsrc.c -- Test basic function of UDP server
00040 **
00041 ** udpsrv operates on the same machine with program udpclt.
00042 ** udpsrv is the server side of a udp sockets application.
00043 ** udpclt is the client side of a udp sockets application.
00044 **
00045 ** The test is designed to assist developers in porting/debugging
00046 ** the UDP socket functions of NSPR.
00047 **
00048 ** This test is not a stress test.
00049 **
00050 ** main() starts two threads: UDP_Server() and UDP_Client();
00051 ** main() uses PR_JoinThread() to wait for the threads to complete.
00052 **
00053 ** UDP_Server() does repeated recvfrom()s from a socket.
00054 ** He detects an EOF condition set by UDP_Client(). For each
00055 ** packet received by UDP_Server(), he checks its content for
00056 ** expected content, then sends the packet back to UDP_Client().
00057 ** 
00058 ** UDP_Client() sends packets to UDP_Server() using sendto()
00059 ** he recieves packets back from the server via recvfrom().
00060 ** After he sends enough packets containing UDP_AMOUNT_TO_WRITE
00061 ** bytes of data, he sends an EOF message.
00062 ** 
00063 ** The test issues a pass/fail message at end.
00064 ** 
00065 ** Notes:
00066 ** The variable "_debug_on" can be set to 1 to cause diagnostic
00067 ** messages related to client/server synchronization. Useful when
00068 ** the test hangs.
00069 ** 
00070 ** Error messages are written to stdout.
00071 ** 
00072 ********************************************************************
00073 */
00074 /* --- include files --- */
00075 #include "nspr.h"
00076 #include "prpriv.h"
00077 
00078 #include "plgetopt.h"
00079 #include "prttools.h"
00080 
00081 #include <stdio.h>
00082 #include <stdlib.h>
00083 #include <string.h>
00084 #include <errno.h>
00085 
00086 #ifdef XP_PC
00087 #define mode_t int
00088 #endif
00089 
00090 #define UDP_BUF_SIZE            4096
00091 #define UDP_DGRAM_SIZE          128
00092 #define UDP_AMOUNT_TO_WRITE     (PRInt32)((UDP_DGRAM_SIZE * 1000l) +1)
00093 #define NUM_UDP_CLIENTS         1
00094 #define NUM_UDP_DATAGRAMS_PER_CLIENT    5
00095 #define UDP_SERVER_PORT         9050
00096 #define UDP_CLIENT_PORT         9053
00097 #define MY_INADDR               PR_INADDR_ANY
00098 #define PEER_INADDR             PR_INADDR_LOOPBACK
00099 
00100 #define UDP_TIMEOUT             400000
00101 /* #define UDP_TIMEOUT             PR_INTERVAL_NO_TIMEOUT */
00102 
00103 /* --- static data --- */
00104 static PRIntn _debug_on      = 0;
00105 static PRBool passed         = PR_TRUE;
00106 static PRUint32 cltBytesRead = 0;
00107 static PRUint32 srvBytesRead = 0;
00108 static PRFileDesc *output    = NULL;
00109 
00110 /* --- static function declarations --- */
00111 #define DPRINTF(arg) if (_debug_on) PR_fprintf(output, arg)
00112 
00113 
00114 
00115 /*******************************************************************
00116 ** ListNetAddr() -- Display the Net Address on stdout
00117 **
00118 ** Description: displays the component parts of a PRNetAddr struct
00119 **
00120 ** Arguments:   address of PRNetAddr structure to display
00121 **
00122 ** Returns: void
00123 **
00124 ** Notes:
00125 **
00126 ********************************************************************
00127 */
00128 void ListNetAddr( char *msg, PRNetAddr *na )
00129 {
00130     char    mbuf[256];
00131     
00132     sprintf( mbuf, "ListNetAddr: %s family: %d, port: %d, ip: %8.8X\n",
00133             msg, na->inet.family, PR_ntohs( na->inet.port), PR_ntohl(na->inet.ip) );
00134 #if 0            
00135     DPRINTF( mbuf );            
00136 #endif
00137 } /* --- end ListNetAddr() --- */
00138 
00139 /********************************************************************
00140 ** UDP_Server() -- Test a UDP server application
00141 **
00142 ** Description: The Server side of a UDP Client/Server application.
00143 **
00144 ** Arguments: none
00145 **
00146 ** Returns: void
00147 **
00148 ** Notes:
00149 **
00150 **
00151 ********************************************************************
00152 */
00153 static void PR_CALLBACK UDP_Server( void *arg )
00154 {
00155     static char     svrBuf[UDP_BUF_SIZE];
00156     PRFileDesc      *svrSock;
00157     PRInt32         rv;
00158     PRNetAddr       netaddr;
00159     PRBool          bound = PR_FALSE;
00160     PRBool          endOfInput = PR_FALSE;
00161     PRInt32         numBytes = UDP_DGRAM_SIZE;
00162     
00163     DPRINTF("udpsrv: UDP_Server(): starting\n" );
00164 
00165     /* --- Create the socket --- */
00166     DPRINTF("udpsrv: UDP_Server(): Creating UDP Socket\n" );
00167     svrSock = PR_NewUDPSocket();
00168     if ( svrSock == NULL )
00169     {
00170         passed = PR_FALSE;
00171         if (debug_mode)
00172             PR_fprintf(output,
00173                 "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" );
00174         return;
00175     }
00176     
00177     /* --- Initialize the sockaddr_in structure --- */
00178     memset( &netaddr, 0, sizeof( netaddr )); 
00179     netaddr.inet.family = PR_AF_INET;
00180     netaddr.inet.port   = PR_htons( UDP_SERVER_PORT );
00181     netaddr.inet.ip     = PR_htonl( MY_INADDR );
00182     
00183     /* --- Bind the socket --- */
00184     while ( !bound )
00185     {
00186         DPRINTF("udpsrv: UDP_Server(): Binding socket\n" );
00187         rv = PR_Bind( svrSock, &netaddr );
00188         if ( rv < 0 )
00189         {
00190             if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR )
00191             {
00192                 if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \
00193                                           PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n");
00194                 PR_Sleep( PR_MillisecondsToInterval( 2000 ));
00195                 continue;
00196             }
00197             else
00198             {
00199                 passed = PR_FALSE;
00200                 if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \
00201                                           PR_Bind(): failed: %ld with error: %ld\n",
00202                         rv, PR_GetError() );
00203                 PR_Close( svrSock );
00204                 return;
00205             }
00206         }
00207         else
00208             bound = PR_TRUE;
00209     }
00210     ListNetAddr( "UDP_Server: after bind", &netaddr );
00211     
00212     /* --- Recv the socket --- */
00213     while( !endOfInput )
00214     {
00215         DPRINTF("udpsrv: UDP_Server(): RecvFrom() socket\n" );
00216         rv = PR_RecvFrom( svrSock, svrBuf, numBytes, 0, &netaddr, UDP_TIMEOUT );
00217         if ( rv == -1 )
00218         {
00219             passed = PR_FALSE;
00220             if (debug_mode)
00221                 PR_fprintf(output,
00222                     "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n",
00223                     PR_GetError() );
00224             PR_Close( svrSock );
00225             return;
00226         }
00227         ListNetAddr( "UDP_Server after RecvFrom", &netaddr );
00228         
00229         srvBytesRead += rv;
00230         
00231         if ( svrBuf[0] == 'E' )
00232         {
00233             DPRINTF("udpsrv: UDP_Server(): EOF on input detected\n" );
00234             endOfInput = PR_TRUE;
00235         }
00236             
00237         /* --- Send the socket --- */
00238         DPRINTF("udpsrv: UDP_Server(): SendTo(): socket\n" );
00239         rv = PR_SendTo( svrSock, svrBuf, rv, 0, &netaddr, PR_INTERVAL_NO_TIMEOUT );
00240         if ( rv == -1 )
00241         {
00242             passed = PR_FALSE;
00243             if (debug_mode)
00244                 PR_fprintf(output,
00245                     "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n",
00246                     PR_GetError() );
00247             PR_Close( svrSock );
00248             return;
00249         }
00250         ListNetAddr( "UDP_Server after SendTo", &netaddr );
00251     }
00252     
00253     /* --- Close the socket --- */
00254     DPRINTF("udpsrv: UDP_Server(): Closing socket\n" );
00255     rv = PR_Close( svrSock );
00256     if ( rv != PR_SUCCESS )
00257     {
00258         passed = PR_FALSE;
00259         if (debug_mode)
00260             PR_fprintf(output,
00261                 "udpsrv: UDP_Server(): PR_Close(): failed to close socket\n" );
00262         return;
00263     }
00264     
00265     DPRINTF("udpsrv: UDP_Server(): Normal end\n" );
00266 } /* --- end UDP_Server() --- */
00267 
00268 
00269 static char         cltBuf[UDP_BUF_SIZE];
00270 static char         cltBufin[UDP_BUF_SIZE];
00271 /********************************************************************
00272 ** UDP_Client() -- Test a UDP client application
00273 **
00274 ** Description:
00275 **
00276 ** Arguments:
00277 **
00278 **
00279 ** Returns:
00280 ** 0 -- Successful execution
00281 ** 1 -- Test failed.
00282 **
00283 ** Notes:
00284 **
00285 **
00286 ********************************************************************
00287 */
00288 static void PR_CALLBACK UDP_Client( void *arg )
00289 {
00290     PRFileDesc   *cltSock;
00291     PRInt32      rv;
00292     PRBool       bound = PR_FALSE;
00293     PRNetAddr    netaddr;
00294     PRNetAddr    netaddrx;
00295     PRBool       endOfInput = PR_FALSE;
00296     PRInt32      numBytes = UDP_DGRAM_SIZE;
00297     PRInt32      writeThisMany = UDP_AMOUNT_TO_WRITE;
00298     int          i;
00299     
00300     
00301     DPRINTF("udpsrv: UDP_Client(): starting\n" );
00302     
00303     /* --- Create the socket --- */
00304     cltSock = PR_NewUDPSocket();
00305     if ( cltSock == NULL )
00306     {
00307         passed = PR_FALSE;
00308         if (debug_mode)
00309             PR_fprintf(output,
00310                 "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" );
00311         return;
00312     }
00313     
00314     /* --- Initialize the sockaddr_in structure --- */
00315     memset( &netaddr, 0, sizeof( netaddr )); 
00316     netaddr.inet.family = PR_AF_INET;
00317     netaddr.inet.ip     = PR_htonl( MY_INADDR );
00318     netaddr.inet.port   = PR_htons( UDP_CLIENT_PORT );
00319     
00320     /* --- Initialize the write buffer --- */    
00321     for ( i = 0; i < UDP_BUF_SIZE ; i++ )
00322         cltBuf[i] = i;
00323     
00324     /* --- Bind the socket --- */
00325     while ( !bound )
00326     {
00327         DPRINTF("udpsrv: UDP_Client(): Binding socket\n" );
00328         rv = PR_Bind( cltSock, &netaddr );
00329         if ( rv < 0 )
00330         {
00331             if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR )
00332             {
00333                 if (debug_mode)
00334                     PR_fprintf(output,
00335                         "udpsrv: UDP_Client(): PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n");
00336                 PR_Sleep( PR_MillisecondsToInterval( 2000 ));
00337                 continue;
00338             }
00339             else
00340             {
00341                 passed = PR_FALSE;
00342                 if (debug_mode)
00343                     PR_fprintf(output,
00344                         "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n",
00345                         rv, PR_GetError() );
00346                 PR_Close( cltSock );
00347                 return;
00348             }
00349         }
00350         else
00351             bound = PR_TRUE;
00352     }
00353     ListNetAddr( "UDP_Client after Bind", &netaddr );
00354     
00355     /* --- Initialize the sockaddr_in structure --- */
00356     memset( &netaddr, 0, sizeof( netaddr )); 
00357     netaddr.inet.family = PR_AF_INET;
00358     netaddr.inet.ip     = PR_htonl( PEER_INADDR );
00359     netaddr.inet.port   = PR_htons( UDP_SERVER_PORT );
00360     
00361     /* --- send and receive packets until no more data left */    
00362     while( !endOfInput )
00363     {
00364         /*
00365         ** Signal EOF in the data stream on the last packet
00366         */        
00367         if ( writeThisMany <= UDP_DGRAM_SIZE )
00368         {
00369             DPRINTF("udpsrv: UDP_Client(): Send EOF packet\n" );
00370             cltBuf[0] = 'E';
00371             endOfInput = PR_TRUE;
00372         }
00373         
00374         /* --- SendTo the socket --- */
00375         if ( writeThisMany > UDP_DGRAM_SIZE )
00376             numBytes = UDP_DGRAM_SIZE;
00377         else
00378             numBytes = writeThisMany;
00379         writeThisMany -= numBytes;
00380         {
00381             char   mbuf[256];
00382             sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n", 
00383                 writeThisMany, numBytes );
00384             DPRINTF( mbuf );
00385         }
00386         
00387         DPRINTF("udpsrv: UDP_Client(): SendTo(): socket\n" );
00388         rv = PR_SendTo( cltSock, cltBuf, numBytes, 0, &netaddr, UDP_TIMEOUT );
00389         if ( rv == -1 )
00390         {
00391             passed = PR_FALSE;
00392             if (debug_mode)
00393                 PR_fprintf(output,
00394                     "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n",
00395                         PR_GetError() );
00396             PR_Close( cltSock );
00397             return;
00398         }
00399         ListNetAddr( "UDP_Client after SendTo", &netaddr );
00400 
00401         /* --- RecvFrom the socket --- */
00402         memset( cltBufin, 0, UDP_BUF_SIZE );
00403         DPRINTF("udpsrv: UDP_Client(): RecvFrom(): socket\n" );
00404         rv = PR_RecvFrom( cltSock, cltBufin, numBytes, 0, &netaddrx, UDP_TIMEOUT );
00405         if ( rv == -1 )
00406         {
00407             passed = PR_FALSE;
00408             if (debug_mode) PR_fprintf(output,
00409                 "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n",
00410                    PR_GetError() );
00411             PR_Close( cltSock );
00412             return;
00413         }
00414         ListNetAddr( "UDP_Client after RecvFrom()", &netaddr );
00415         cltBytesRead += rv;
00416         
00417         /* --- verify buffer --- */
00418         for ( i = 0; i < rv ; i++ )
00419         {
00420             if ( cltBufin[i] != i )
00421             {
00422                 /* --- special case, end of input --- */
00423                 if ( endOfInput && i == 0 && cltBufin[0] == 'E' )
00424                     continue;
00425                 passed = PR_FALSE;
00426                 if (debug_mode) PR_fprintf(output,
00427                     "udpsrv: UDP_Client(): return data mismatch\n" );
00428                 PR_Close( cltSock );
00429                 return;
00430             }
00431         }
00432         if (debug_mode) PR_fprintf(output, ".");
00433     }
00434     
00435     /* --- Close the socket --- */
00436     DPRINTF("udpsrv: UDP_Server(): Closing socket\n" );
00437     rv = PR_Close( cltSock );
00438     if ( rv != PR_SUCCESS )
00439     {
00440         passed = PR_FALSE;
00441         if (debug_mode) PR_fprintf(output,
00442             "udpsrv: UDP_Client(): PR_Close(): failed to close socket\n" );
00443         return;
00444     }
00445     DPRINTF("udpsrv: UDP_Client(): ending\n" );
00446 } /* --- end UDP_Client() --- */
00447 
00448 /********************************************************************
00449 ** main() -- udpsrv
00450 **
00451 ** arguments:
00452 **
00453 ** Returns:
00454 ** 0 -- Successful execution
00455 ** 1 -- Test failed.
00456 **
00457 ** Description:
00458 **
00459 ** Standard test case setup.
00460 **
00461 ** Calls the function UDP_Server()
00462 **
00463 ********************************************************************
00464 */
00465 
00466 int main(int argc, char **argv)
00467 {
00468     PRThread    *srv, *clt;
00469 /* The command line argument: -d is used to determine if the test is being run
00470        in debug mode. The regress tool requires only one line output:PASS or FAIL.
00471        All of the printfs associated with this test has been handled with a if (debug_mode)
00472        test.
00473        Usage: test_name -d -v
00474        */
00475        PLOptStatus os;
00476        PLOptState *opt = PL_CreateOptState(argc, argv, "dv");
00477        while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00478     {
00479               if (PL_OPT_BAD == os) continue;
00480         switch (opt->option)
00481         {
00482         case 'd':  /* debug mode */
00483                      debug_mode = 1;
00484             break;
00485         case 'v':  /* verbose mode */
00486                      _debug_on = 1;
00487             break;
00488          default:
00489             break;
00490         }
00491     }
00492        PL_DestroyOptState(opt);
00493               
00494     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
00495     PR_STDIO_INIT();
00496     output = PR_STDERR;
00497 
00498 #ifdef XP_MAC
00499     SetupMacPrintfLog("udpsrv.log");
00500 #endif
00501 
00502     PR_SetConcurrency(4);
00503     
00504     /*
00505     ** Create the Server thread
00506     */    
00507     DPRINTF( "udpsrv: Creating Server Thread\n" );
00508     srv =  PR_CreateThread( PR_USER_THREAD,
00509             UDP_Server,
00510             (void *) 0,
00511             PR_PRIORITY_LOW,
00512             PR_LOCAL_THREAD,
00513             PR_JOINABLE_THREAD,
00514             0 );
00515     if ( srv == NULL )
00516     {
00517         if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" );
00518         passed = PR_FALSE;
00519     }
00520     
00521     /*
00522     ** Give the Server time to Start
00523     */    
00524     DPRINTF( "udpsrv: Pausing to allow Server to start\n" );
00525     PR_Sleep( PR_MillisecondsToInterval(200) );
00526     
00527     /*
00528     ** Create the Client thread
00529     */    
00530     DPRINTF( "udpsrv: Creating Client Thread\n" );
00531     clt = PR_CreateThread( PR_USER_THREAD,
00532             UDP_Client,
00533             (void *) 0,
00534             PR_PRIORITY_LOW,
00535             PR_LOCAL_THREAD,
00536             PR_JOINABLE_THREAD,
00537             0 );
00538     if ( clt == NULL )
00539     {
00540         if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" );
00541         passed = PR_FALSE;
00542     }
00543     
00544     /*
00545     **
00546     */
00547     DPRINTF("udpsrv: Waiting to join Server & Client Threads\n" );
00548     PR_JoinThread( srv );
00549     PR_JoinThread( clt );    
00550     
00551     /*
00552     ** Evaluate test results
00553     */
00554     if (debug_mode) PR_fprintf(output, "\n\nudpsrv: main(): cltBytesRead(%ld), \
00555               srvBytesRead(%ld), expected(%ld)\n",
00556          cltBytesRead, srvBytesRead, UDP_AMOUNT_TO_WRITE );
00557     if ( cltBytesRead != srvBytesRead || cltBytesRead != UDP_AMOUNT_TO_WRITE )
00558     {
00559         passed = PR_FALSE;
00560     }
00561     PR_Cleanup();
00562     if ( passed )
00563         return 0;
00564     else
00565               return 1;
00566 } /* --- end main() --- */