tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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() --- */