tor-browser

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

socket.c (64731B)


      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 **
      8 ** Name: socket.c
      9 **
     10 ** Description: Test socket functionality.
     11 **
     12 ** Modification History:
     13 */
     14 #include "primpl.h"
     15 
     16 #include "plgetopt.h"
     17 
     18 #include <stdio.h>
     19 #include <string.h>
     20 #include <errno.h>
     21 #ifdef XP_UNIX
     22 #  include <sys/mman.h>
     23 #endif
     24 #if defined(_PR_PTHREADS)
     25 #  include <pthread.h>
     26 #endif
     27 
     28 #ifdef WIN32
     29 #  include <process.h>
     30 #endif
     31 
     32 static int _debug_on = 0;
     33 static int test_cancelio = 0;
     34 
     35 #include "obsolete/prsem.h"
     36 
     37 #ifdef XP_PC
     38 #  define mode_t int
     39 #endif
     40 
     41 #define DPRINTF(arg) \
     42  if (_debug_on) printf arg
     43 
     44 #ifdef XP_PC
     45 char* TEST_DIR = "prdir";
     46 char* SMALL_FILE_NAME = "prsmallf";
     47 char* LARGE_FILE_NAME = "prlargef";
     48 #else
     49 char* TEST_DIR = "./tmp-prsocket_test_dir";
     50 char* SMALL_FILE_NAME = "./tmp-prsocket_test_dir/small_file";
     51 char* LARGE_FILE_NAME = "./tmp-prsocket_test_dir/large_file";
     52 #endif
     53 #define SMALL_FILE_SIZE (3 * 1024) /* 3 KB        */
     54 #define SMALL_FILE_OFFSET_1 (512)
     55 #define SMALL_FILE_LEN_1 (1 * 1024) /* 1 KB        */
     56 #define SMALL_FILE_OFFSET_2 (75)
     57 #define SMALL_FILE_LEN_2 (758)
     58 #define SMALL_FILE_OFFSET_3 (1024)
     59 #define SMALL_FILE_LEN_3 (SMALL_FILE_SIZE - SMALL_FILE_OFFSET_3)
     60 #define SMALL_FILE_HEADER_SIZE (64)   /* 64 bytes    */
     61 #define SMALL_FILE_TRAILER_SIZE (128) /* 128 bytes    */
     62 
     63 #define LARGE_FILE_SIZE (3 * 1024 * 1024) /* 3 MB        */
     64 #define LARGE_FILE_OFFSET_1 (0)
     65 #define LARGE_FILE_LEN_1 (2 * 1024 * 1024) /* 2 MB        */
     66 #define LARGE_FILE_OFFSET_2 (64)
     67 #define LARGE_FILE_LEN_2 (1 * 1024 * 1024 + 75)
     68 #define LARGE_FILE_OFFSET_3 (2 * 1024 * 1024 - 128)
     69 #define LARGE_FILE_LEN_3 (LARGE_FILE_SIZE - LARGE_FILE_OFFSET_3)
     70 #define LARGE_FILE_OFFSET_4 PR_GetPageSize()
     71 #define LARGE_FILE_LEN_4 769
     72 #define LARGE_FILE_HEADER_SIZE (512)
     73 #define LARGE_FILE_TRAILER_SIZE (64)
     74 
     75 #define BUF_DATA_SIZE (2 * 1024)
     76 #define TCP_MESG_SIZE 1024
     77 /*
     78 * set UDP datagram size small enough that datagrams sent to a port on the
     79 * local host will not be lost
     80 */
     81 #define UDP_DGRAM_SIZE 128
     82 #define NUM_TCP_CLIENTS 5 /* for a listen queue depth of 5 */
     83 #define NUM_UDP_CLIENTS 10
     84 
     85 #define NUM_TRANSMITFILE_CLIENTS 4
     86 
     87 #define NUM_TCP_CONNECTIONS_PER_CLIENT 5
     88 #define NUM_TCP_MESGS_PER_CONNECTION 10
     89 #define NUM_UDP_DATAGRAMS_PER_CLIENT 5
     90 #define TCP_SERVER_PORT 10000
     91 #define UDP_SERVER_PORT TCP_SERVER_PORT
     92 #define SERVER_MAX_BIND_COUNT 100
     93 
     94 #ifdef WINCE
     95 #  define perror(s)
     96 #endif
     97 
     98 static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS;
     99 static PRInt32 num_udp_clients = NUM_UDP_CLIENTS;
    100 static PRInt32 num_transmitfile_clients = NUM_TRANSMITFILE_CLIENTS;
    101 static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT;
    102 static PRInt32 tcp_mesg_size = TCP_MESG_SIZE;
    103 static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION;
    104 static PRInt32 num_udp_datagrams_per_client = NUM_UDP_DATAGRAMS_PER_CLIENT;
    105 static PRInt32 udp_datagram_size = UDP_DGRAM_SIZE;
    106 
    107 static PRInt32 thread_count;
    108 PRUint16 server_domain = PR_AF_INET, client_domain = PR_AF_INET;
    109 
    110 /* an I/O layer that uses the emulated senfile method */
    111 static PRDescIdentity emuSendFileIdentity;
    112 static PRIOMethods emuSendFileMethods;
    113 
    114 int failed_already = 0;
    115 typedef struct buffer {
    116  char data[BUF_DATA_SIZE];
    117 } buffer;
    118 
    119 PRNetAddr tcp_server_addr, udp_server_addr;
    120 
    121 typedef struct Serve_Client_Param {
    122  PRFileDesc* sockfd; /* socket to read from/write to    */
    123  PRInt32 datalen;    /* bytes of data transfered in each read/write */
    124 } Serve_Client_Param;
    125 
    126 typedef struct Server_Param {
    127  PRSemaphore* addr_sem; /* sem to post on, after setting up the address */
    128  PRMonitor* exit_mon;   /* monitor to signal on exit            */
    129  PRInt32* exit_counter; /* counter to decrement, before exit        */
    130  PRInt32 datalen;       /* bytes of data transfered in each read/write    */
    131 } Server_Param;
    132 
    133 typedef struct Client_Param {
    134  PRNetAddr server_addr;
    135  PRMonitor* exit_mon;   /* monitor to signal on exit */
    136  PRInt32* exit_counter; /* counter to decrement, before exit */
    137  PRInt32 datalen;
    138  PRInt32 udp_connect; /* if set clients connect udp sockets */
    139 } Client_Param;
    140 
    141 /* the sendfile method in emuSendFileMethods */
    142 static PRInt32 PR_CALLBACK emu_SendFile(PRFileDesc* sd, PRSendFileData* sfd,
    143                                        PRTransmitFileFlags flags,
    144                                        PRIntervalTime timeout) {
    145  return PR_EmulateSendFile(sd, sfd, flags, timeout);
    146 }
    147 
    148 /* the transmitfile method in emuSendFileMethods */
    149 static PRInt32 PR_CALLBACK emu_TransmitFile(PRFileDesc* sd, PRFileDesc* fd,
    150                                            const void* headers, PRInt32 hlen,
    151                                            PRTransmitFileFlags flags,
    152                                            PRIntervalTime timeout) {
    153  PRSendFileData sfd;
    154 
    155  sfd.fd = fd;
    156  sfd.file_offset = 0;
    157  sfd.file_nbytes = 0;
    158  sfd.header = headers;
    159  sfd.hlen = hlen;
    160  sfd.trailer = NULL;
    161  sfd.tlen = 0;
    162  return emu_SendFile(sd, &sfd, flags, timeout);
    163 }
    164 
    165 /*
    166 * readn
    167 *    read data from sockfd into buf
    168 */
    169 static PRInt32 readn(PRFileDesc* sockfd, char* buf, int len) {
    170  int rem;
    171  int bytes;
    172  int offset = 0;
    173  int err;
    174  PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
    175 
    176  if (test_cancelio) {
    177    timeout = PR_SecondsToInterval(2);
    178  }
    179 
    180  for (rem = len; rem; offset += bytes, rem -= bytes) {
    181    DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n",
    182             PR_GetCurrentThread(), rem));
    183  retry:
    184    bytes = PR_Recv(sockfd, buf + offset, rem, 0, timeout);
    185    DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n",
    186             PR_GetCurrentThread(), bytes));
    187    if (bytes < 0) {
    188 #ifdef WINNT
    189      printf("PR_Recv: error = %d oserr = %d\n", (err = PR_GetError()),
    190             PR_GetOSError());
    191      if ((test_cancelio) && (err == PR_IO_TIMEOUT_ERROR)) {
    192        if (PR_NT_CancelIo(sockfd) != PR_SUCCESS) {
    193          printf("PR_NT_CancelIO: error = %d\n", PR_GetError());
    194        }
    195        timeout = PR_INTERVAL_NO_TIMEOUT;
    196        goto retry;
    197      }
    198 #endif
    199      return -1;
    200    }
    201  }
    202  return len;
    203 }
    204 
    205 /*
    206 * writen
    207 *    write data from buf to sockfd
    208 */
    209 static PRInt32 writen(PRFileDesc* sockfd, char* buf, int len) {
    210  int rem;
    211  int bytes;
    212  int offset = 0;
    213 
    214  for (rem = len; rem; offset += bytes, rem -= bytes) {
    215    DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n",
    216             PR_GetCurrentThread(), rem));
    217    bytes = PR_Send(sockfd, buf + offset, rem, 0, PR_INTERVAL_NO_TIMEOUT);
    218    DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n",
    219             PR_GetCurrentThread(), bytes));
    220    if (bytes <= 0) {
    221      return -1;
    222    }
    223  }
    224  return len;
    225 }
    226 
    227 /*
    228 * Serve_Client
    229 *    Thread, started by the server, for serving a client connection.
    230 *    Reads data from socket and writes it back, unmodified, and
    231 *    closes the socket
    232 */
    233 static void PR_CALLBACK Serve_Client(void* arg) {
    234  Serve_Client_Param* scp = (Serve_Client_Param*)arg;
    235  PRFileDesc* sockfd;
    236  buffer* in_buf;
    237  PRInt32 bytes, j;
    238 
    239  sockfd = scp->sockfd;
    240  bytes = scp->datalen;
    241  in_buf = PR_NEW(buffer);
    242  if (in_buf == NULL) {
    243    fprintf(stderr, "prsocket_test: failed to alloc buffer struct\n");
    244    failed_already = 1;
    245    goto exit;
    246  }
    247 
    248  for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
    249    /*
    250     * Read data from client and send it back to the client unmodified
    251     */
    252    if (readn(sockfd, in_buf->data, bytes) < bytes) {
    253      fprintf(stderr, "prsocket_test: ERROR - Serve_Client:readn\n");
    254      failed_already = 1;
    255      goto exit;
    256    }
    257    /* Shutdown only RCV will cause error on Symbian OS */
    258    /*
    259     * shutdown reads, after the last read
    260     */
    261    if (j == num_tcp_mesgs_per_connection - 1)
    262      if (PR_Shutdown(sockfd, PR_SHUTDOWN_RCV) < 0) {
    263        fprintf(stderr, "prsocket_test: ERROR - PR_Shutdown\n");
    264      }
    265    DPRINTF(("Serve_Client [0x%lx]: inbuf[0] = 0x%lx\n", PR_GetCurrentThread(),
    266             (*((int*)in_buf->data))));
    267    if (writen(sockfd, in_buf->data, bytes) < bytes) {
    268      fprintf(stderr, "prsocket_test: ERROR - Serve_Client:writen\n");
    269      failed_already = 1;
    270      goto exit;
    271    }
    272  }
    273  /*
    274   * shutdown reads and writes
    275   */
    276  if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
    277    fprintf(stderr, "prsocket_test: ERROR - PR_Shutdown\n");
    278    failed_already = 1;
    279  }
    280 
    281 exit:
    282  PR_Close(sockfd);
    283  if (in_buf) {
    284    PR_DELETE(in_buf);
    285  }
    286 }
    287 
    288 PRThread* create_new_thread(PRThreadType type, void (*start)(void* arg),
    289                            void* arg, PRThreadPriority priority,
    290                            PRThreadScope scope, PRThreadState state,
    291                            PRUint32 stackSize, PRInt32 index) {
    292  PRInt32 native_thread = 0;
    293 
    294  PR_ASSERT(state == PR_UNJOINABLE_THREAD);
    295 #if defined(_PR_PTHREADS) || defined(WIN32)
    296  switch (index % 4) {
    297    case 0:
    298      scope = (PR_LOCAL_THREAD);
    299      break;
    300    case 1:
    301      scope = (PR_GLOBAL_THREAD);
    302      break;
    303    case 2:
    304      scope = (PR_GLOBAL_BOUND_THREAD);
    305      break;
    306    case 3:
    307      native_thread = 1;
    308      break;
    309    default:
    310      PR_NOT_REACHED("Invalid scope");
    311      break;
    312  }
    313  if (native_thread) {
    314 #  if defined(_PR_PTHREADS)
    315    pthread_t tid;
    316    if (!pthread_create(&tid, NULL, (void* (*)(void*))start, arg)) {
    317      return ((PRThread*)tid);
    318    } else {
    319      return (NULL);
    320    }
    321 #  else
    322    HANDLE thandle;
    323    unsigned tid;
    324 
    325    thandle = (HANDLE)_beginthreadex(NULL, stackSize,
    326                                     (unsigned(__stdcall*)(void*))start, arg,
    327                                     STACK_SIZE_PARAM_IS_A_RESERVATION, &tid);
    328    return ((PRThread*)thandle);
    329 #  endif
    330  } else {
    331    return (
    332        PR_CreateThread(type, start, arg, priority, scope, state, stackSize));
    333  }
    334 #else
    335  return (PR_CreateThread(type, start, arg, priority, scope, state, stackSize));
    336 #endif
    337 }
    338 
    339 /*
    340 * TCP Server
    341 *    Server Thread
    342 *    Bind an address to a socket and listen for incoming connections
    343 *    Start a Serve_Client thread for each incoming connection.
    344 */
    345 static void PR_CALLBACK TCP_Server(void* arg) {
    346  PRThread* t;
    347  Server_Param* sp = (Server_Param*)arg;
    348  Serve_Client_Param* scp;
    349  PRFileDesc *sockfd, *newsockfd;
    350  PRNetAddr netaddr;
    351  PRInt32 i;
    352  /*
    353   * Create a tcp socket
    354   */
    355  if ((sockfd = PR_OpenTCPSocket(server_domain)) == NULL) {
    356    fprintf(stderr, "prsocket_test: PR_NewTCPSocket failed\n");
    357    goto exit;
    358  }
    359  memset(&netaddr, 0, sizeof(netaddr));
    360 
    361  if (PR_SetNetAddr(PR_IpAddrAny, server_domain, TCP_SERVER_PORT, &netaddr) ==
    362      PR_FAILURE) {
    363    fprintf(stderr, "prsocket_test: PR_SetNetAddr failed\n");
    364    goto exit;
    365  }
    366  /*
    367   * try a few times to bind server's address, if addresses are in
    368   * use
    369   */
    370  i = 0;
    371 
    372  while (PR_Bind(sockfd, &netaddr) < 0) {
    373    if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
    374      netaddr.inet.port += 2;
    375      if (i++ < SERVER_MAX_BIND_COUNT) {
    376        continue;
    377      }
    378    }
    379    fprintf(stderr, "prsocket_test: ERROR - PR_Bind failed\n");
    380    perror("PR_Bind");
    381    failed_already = 1;
    382    goto exit;
    383  }
    384 
    385  if (PR_Listen(sockfd, 32) < 0) {
    386    fprintf(stderr, "prsocket_test: ERROR - PR_Listen failed\n");
    387    failed_already = 1;
    388    goto exit;
    389  }
    390 
    391  if (PR_GetSockName(sockfd, &netaddr) < 0) {
    392    fprintf(stderr, "prsocket_test: ERROR - PR_GetSockName failed\n");
    393    failed_already = 1;
    394    goto exit;
    395  }
    396 
    397  DPRINTF(
    398      ("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
    399       netaddr.inet.ip, netaddr.inet.port));
    400  if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain,
    401                    PR_ntohs(PR_NetAddrInetPort(&netaddr)),
    402                    &tcp_server_addr) == PR_FAILURE) {
    403    fprintf(stderr, "prsocket_test: PR_SetNetAddr failed\n");
    404    goto exit;
    405  }
    406  if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET))
    407    PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK),
    408                             &tcp_server_addr.ipv6.ip);
    409 
    410  /*
    411   * Wake up parent thread because server address is bound and made
    412   * available in the global variable 'tcp_server_addr'
    413   */
    414  PR_PostSem(sp->addr_sem);
    415 
    416  for (i = 0; i < (num_tcp_clients * num_tcp_connections_per_client); i++) {
    417    /* test both null and non-null 'addr' argument to PR_Accept */
    418    PRNetAddr* addrp = (i % 2 ? &netaddr : NULL);
    419 
    420    DPRINTF(("TCP_Server: Accepting connection\n"));
    421    if ((newsockfd = PR_Accept(sockfd, addrp, PR_INTERVAL_NO_TIMEOUT)) ==
    422        NULL) {
    423      fprintf(stderr, "prsocket_test: ERROR - PR_Accept failed\n");
    424      goto exit;
    425    }
    426    DPRINTF(("TCP_Server: Accepted connection\n"));
    427    scp = PR_NEW(Serve_Client_Param);
    428    if (scp == NULL) {
    429      fprintf(stderr, "prsocket_test: PR_NEW failed\n");
    430      goto exit;
    431    }
    432 
    433    /*
    434     * Start a Serve_Client thread for each incoming connection
    435     */
    436    scp->sockfd = newsockfd;
    437    scp->datalen = sp->datalen;
    438 
    439    t = create_new_thread(PR_USER_THREAD, Serve_Client, (void*)scp,
    440                          PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
    441                          PR_UNJOINABLE_THREAD, 0, i);
    442    if (t == NULL) {
    443      fprintf(stderr, "prsocket_test: PR_CreateThread failed\n");
    444      failed_already = 1;
    445      goto exit;
    446    }
    447    DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", t));
    448  }
    449 
    450 exit:
    451  if (sockfd) {
    452    PR_Close(sockfd);
    453  }
    454 
    455  /*
    456   * Decrement exit_counter and notify parent thread
    457   */
    458 
    459  PR_EnterMonitor(sp->exit_mon);
    460  --(*sp->exit_counter);
    461  PR_Notify(sp->exit_mon);
    462  PR_ExitMonitor(sp->exit_mon);
    463  DPRINTF(("TCP_Server [0x%lx] exiting\n", PR_GetCurrentThread()));
    464 }
    465 
    466 /*
    467 * UDP Server
    468 *    Server Thread
    469 *    Bind an address to a socket, read data from clients and send data
    470 *    back to clients
    471 */
    472 static void PR_CALLBACK UDP_Server(void* arg) {
    473  Server_Param* sp = (Server_Param*)arg;
    474  PRFileDesc* sockfd;
    475  buffer* in_buf;
    476  PRNetAddr netaddr;
    477  PRInt32 bytes, i, rv = 0;
    478 
    479  bytes = sp->datalen;
    480  /*
    481   * Create a udp socket
    482   */
    483  if ((sockfd = PR_OpenUDPSocket(server_domain)) == NULL) {
    484    fprintf(stderr, "prsocket_test: PR_NewUDPSocket failed\n");
    485    failed_already = 1;
    486    return;
    487  }
    488  memset(&netaddr, 0, sizeof(netaddr));
    489  if (PR_SetNetAddr(PR_IpAddrAny, server_domain, UDP_SERVER_PORT, &netaddr) ==
    490      PR_FAILURE) {
    491    fprintf(stderr, "prsocket_test: PR_SetNetAddr failed\n");
    492    failed_already = 1;
    493    return;
    494  }
    495  /*
    496   * try a few times to bind server's address, if addresses are in
    497   * use
    498   */
    499  i = 0;
    500  while (PR_Bind(sockfd, &netaddr) < 0) {
    501    if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
    502      netaddr.inet.port += 2;
    503      if (i++ < SERVER_MAX_BIND_COUNT) {
    504        continue;
    505      }
    506    }
    507    fprintf(stderr, "prsocket_test: ERROR - PR_Bind failed\n");
    508    perror("PR_Bind");
    509    failed_already = 1;
    510    return;
    511  }
    512 
    513  if (PR_GetSockName(sockfd, &netaddr) < 0) {
    514    fprintf(stderr, "prsocket_test: ERROR - PR_GetSockName failed\n");
    515    failed_already = 1;
    516    return;
    517  }
    518 
    519  DPRINTF(
    520      ("PR_Bind: UDP Server netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
    521       netaddr.inet.ip, netaddr.inet.port));
    522  /*
    523   * We can't use the IP address returned by PR_GetSockName in
    524   * netaddr.inet.ip because netaddr.inet.ip is returned
    525   * as 0 (= PR_INADDR_ANY).
    526   */
    527 
    528  if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain,
    529                    PR_ntohs(PR_NetAddrInetPort(&netaddr)),
    530                    &udp_server_addr) == PR_FAILURE) {
    531    fprintf(stderr, "prsocket_test: PR_SetNetAddr failed\n");
    532    failed_already = 1;
    533    return;
    534  }
    535  if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET))
    536    PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK),
    537                             &udp_server_addr.ipv6.ip);
    538 
    539  /*
    540   * Wake up parent thread because server address is bound and made
    541   * available in the global variable 'udp_server_addr'
    542   */
    543  PR_PostSem(sp->addr_sem);
    544 
    545  bytes = sp->datalen;
    546  in_buf = PR_NEW(buffer);
    547  if (in_buf == NULL) {
    548    fprintf(stderr, "prsocket_test: failed to alloc buffer struct\n");
    549    failed_already = 1;
    550    return;
    551  }
    552  /*
    553   * Receive datagrams from clients and send them back, unmodified, to the
    554   * clients
    555   */
    556  memset(&netaddr, 0, sizeof(netaddr));
    557  for (i = 0; i < (num_udp_clients * num_udp_datagrams_per_client); i++) {
    558    DPRINTF(
    559        ("UDP_Server: calling PR_RecvFrom client  - ip = 0x%lx, port = %d "
    560         "bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n",
    561         netaddr.inet.ip, netaddr.inet.port, bytes, in_buf->data,
    562         in_buf->data[0]));
    563 
    564    rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr,
    565                     PR_INTERVAL_NO_TIMEOUT);
    566    DPRINTF((
    567        "UDP_Server: PR_RecvFrom client  - ip = 0x%lx, port = %d bytes = %d "
    568        "inbuf = 0x%lx, inbuf[0] = 0x%lx\n",
    569        netaddr.inet.ip, netaddr.inet.port, rv, in_buf->data, in_buf->data[0]));
    570    if (rv != bytes) {
    571      return;
    572    }
    573    rv = PR_SendTo(sockfd, in_buf->data, bytes, 0, &netaddr,
    574                   PR_INTERVAL_NO_TIMEOUT);
    575    if (rv != bytes) {
    576      return;
    577    }
    578  }
    579 
    580  PR_DELETE(in_buf);
    581  PR_Close(sockfd);
    582 
    583  /*
    584   * Decrement exit_counter and notify parent thread
    585   */
    586  PR_EnterMonitor(sp->exit_mon);
    587  --(*sp->exit_counter);
    588  PR_Notify(sp->exit_mon);
    589  PR_ExitMonitor(sp->exit_mon);
    590  DPRINTF(("UDP_Server [0x%x] exiting\n", PR_GetCurrentThread()));
    591 }
    592 
    593 /*
    594 * TCP_Client
    595 *    Client Thread
    596 *    Connect to the server at the address specified in the argument.
    597 *    Fill in a buffer, write data to server, read it back and check
    598 *    for data corruption.
    599 *    Close the socket for server connection
    600 */
    601 static void PR_CALLBACK TCP_Client(void* arg) {
    602  Client_Param* cp = (Client_Param*)arg;
    603  PRFileDesc* sockfd;
    604  buffer *in_buf, *out_buf;
    605  union PRNetAddr netaddr;
    606  PRInt32 bytes, i, j;
    607 
    608  bytes = cp->datalen;
    609  out_buf = PR_NEW(buffer);
    610  if (out_buf == NULL) {
    611    fprintf(stderr, "prsocket_test: failed to alloc buffer struct\n");
    612    failed_already = 1;
    613    return;
    614  }
    615  in_buf = PR_NEW(buffer);
    616  if (in_buf == NULL) {
    617    fprintf(stderr, "prsocket_test: failed to alloc buffer struct\n");
    618    failed_already = 1;
    619    return;
    620  }
    621  netaddr = cp->server_addr;
    622 
    623  for (i = 0; i < num_tcp_connections_per_client; i++) {
    624    if ((sockfd = PR_OpenTCPSocket(client_domain)) == NULL) {
    625      fprintf(stderr, "prsocket_test: PR_OpenTCPSocket failed\n");
    626      failed_already = 1;
    627      return;
    628    }
    629    if (PR_Connect(sockfd, &netaddr, PR_INTERVAL_NO_TIMEOUT) < 0) {
    630      fprintf(stderr, "PR_Connect failed: (%ld, %ld)\n", PR_GetError(),
    631              PR_GetOSError());
    632      failed_already = 1;
    633      return;
    634    }
    635    for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
    636      /*
    637       * fill in random data
    638       */
    639      memset(out_buf->data, ((PRInt32)(&netaddr)) + i + j, bytes);
    640      /*
    641       * write to server
    642       */
    643 #ifdef WINNT
    644      if (test_cancelio && (j == 0)) {
    645        PR_Sleep(PR_SecondsToInterval(12));
    646      }
    647 #endif
    648      if (writen(sockfd, out_buf->data, bytes) < bytes) {
    649        fprintf(stderr, "prsocket_test: ERROR - TCP_Client:writen\n");
    650        failed_already = 1;
    651        return;
    652      }
    653      DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
    654               PR_GetCurrentThread(), out_buf, (*((int*)out_buf->data))));
    655      if (readn(sockfd, in_buf->data, bytes) < bytes) {
    656        fprintf(stderr, "prsocket_test: ERROR - TCP_Client:readn\n");
    657        failed_already = 1;
    658        return;
    659      }
    660      /*
    661       * verify the data read
    662       */
    663      if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
    664        fprintf(stderr, "prsocket_test: ERROR - data corruption\n");
    665        failed_already = 1;
    666        return;
    667      }
    668    }
    669    /*
    670     * shutdown reads and writes
    671     */
    672    if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
    673      fprintf(stderr, "prsocket_test: ERROR - PR_Shutdown\n");
    674      failed_already = 1;
    675    }
    676    PR_Close(sockfd);
    677  }
    678 
    679  PR_DELETE(out_buf);
    680  PR_DELETE(in_buf);
    681 
    682  /*
    683   * Decrement exit_counter and notify parent thread
    684   */
    685 
    686  PR_EnterMonitor(cp->exit_mon);
    687  --(*cp->exit_counter);
    688  PR_Notify(cp->exit_mon);
    689  PR_ExitMonitor(cp->exit_mon);
    690  DPRINTF(("TCP_Client [0x%x] exiting\n", PR_GetCurrentThread()));
    691 }
    692 
    693 /*
    694 * UDP_Client
    695 *    Client Thread
    696 *    Create a socket and bind an address
    697 *    Communicate with the server at the address specified in the argument.
    698 *    Fill in a buffer, write data to server, read it back and check
    699 *    for data corruption.
    700 *    Close the socket
    701 */
    702 static void PR_CALLBACK UDP_Client(void* arg) {
    703  Client_Param* cp = (Client_Param*)arg;
    704  PRFileDesc* sockfd;
    705  buffer *in_buf, *out_buf;
    706  union PRNetAddr netaddr;
    707  PRInt32 bytes, i, rv;
    708 
    709  bytes = cp->datalen;
    710  out_buf = PR_NEW(buffer);
    711  if (out_buf == NULL) {
    712    fprintf(stderr, "prsocket_test: failed to alloc buffer struct\n");
    713    failed_already = 1;
    714    return;
    715  }
    716  in_buf = PR_NEW(buffer);
    717  if (in_buf == NULL) {
    718    fprintf(stderr, "prsocket_test: failed to alloc buffer struct\n");
    719    failed_already = 1;
    720    return;
    721  }
    722  if ((sockfd = PR_OpenUDPSocket(client_domain)) == NULL) {
    723    fprintf(stderr, "prsocket_test: PR_OpenUDPSocket failed\n");
    724    failed_already = 1;
    725    return;
    726  }
    727 
    728  /*
    729   * bind an address for the client, let the system chose the port
    730   * number
    731   */
    732  memset(&netaddr, 0, sizeof(netaddr));
    733  if (PR_SetNetAddr(PR_IpAddrAny, client_domain, 0, &netaddr) == PR_FAILURE) {
    734    fprintf(stderr, "prsocket_test: PR_SetNetAddr failed\n");
    735    failed_already = 1;
    736    return;
    737  }
    738  if (PR_Bind(sockfd, &netaddr) < 0) {
    739    fprintf(stderr, "prsocket_test: ERROR - PR_Bind failed\n");
    740    perror("PR_Bind");
    741    return;
    742  }
    743 
    744  if (PR_GetSockName(sockfd, &netaddr) < 0) {
    745    fprintf(stderr, "prsocket_test: ERROR - PR_GetSockName failed\n");
    746    failed_already = 1;
    747    return;
    748  }
    749 
    750  DPRINTF(
    751      ("PR_Bind: UDP Client netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
    752       netaddr.inet.ip, netaddr.inet.port));
    753 
    754  netaddr = cp->server_addr;
    755 
    756  if (cp->udp_connect) {
    757    if (PR_Connect(sockfd, &netaddr, PR_INTERVAL_NO_TIMEOUT) < 0) {
    758      fprintf(stderr, "prsocket_test: PR_Connect failed\n");
    759      failed_already = 1;
    760      return;
    761    }
    762  }
    763 
    764  for (i = 0; i < num_udp_datagrams_per_client; i++) {
    765    /*
    766     * fill in random data
    767     */
    768    DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx bytes = 0x%lx\n",
    769             PR_GetCurrentThread(), out_buf->data, bytes));
    770    memset(out_buf->data, ((PRInt32)(&netaddr)) + i, bytes);
    771    /*
    772     * write to server
    773     */
    774    if (cp->udp_connect)
    775      rv = PR_Send(sockfd, out_buf->data, bytes, 0, PR_INTERVAL_NO_TIMEOUT);
    776    else
    777      rv = PR_SendTo(sockfd, out_buf->data, bytes, 0, &netaddr,
    778                     PR_INTERVAL_NO_TIMEOUT);
    779    if (rv != bytes) {
    780      return;
    781    }
    782    DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
    783             PR_GetCurrentThread(), out_buf, (*((int*)out_buf->data))));
    784    if (cp->udp_connect)
    785      rv = PR_Recv(sockfd, in_buf->data, bytes, 0, PR_INTERVAL_NO_TIMEOUT);
    786    else
    787      rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr,
    788                       PR_INTERVAL_NO_TIMEOUT);
    789    if (rv != bytes) {
    790      return;
    791    }
    792    DPRINTF(("UDP_Client [0x%lx]: in_buf = 0x%lx in_buf[0] = 0x%lx\n",
    793             PR_GetCurrentThread(), in_buf, (*((int*)in_buf->data))));
    794    /*
    795     * verify the data read
    796     */
    797    if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
    798      fprintf(stderr, "prsocket_test: ERROR - UDP data corruption\n");
    799      failed_already = 1;
    800      return;
    801    }
    802  }
    803  PR_Close(sockfd);
    804 
    805  PR_DELETE(in_buf);
    806  PR_DELETE(out_buf);
    807 
    808  /*
    809   * Decrement exit_counter and notify parent thread
    810   */
    811 
    812  PR_EnterMonitor(cp->exit_mon);
    813  --(*cp->exit_counter);
    814  PR_Notify(cp->exit_mon);
    815  PR_ExitMonitor(cp->exit_mon);
    816  PR_DELETE(cp);
    817  DPRINTF(("UDP_Client [0x%x] exiting\n", PR_GetCurrentThread()));
    818 }
    819 
    820 /*
    821 * TCP_Socket_Client_Server_Test    - concurrent server test
    822 *
    823 *    One server and several clients are started
    824 *    Each client connects to the server and sends a chunk of data
    825 *    For each connection, server starts another thread to read the data
    826 *    from the client and send it back to the client, unmodified.
    827 *    Each client checks that data received from server is same as the
    828 *    data it sent to the server.
    829 *
    830 */
    831 
    832 static PRInt32 TCP_Socket_Client_Server_Test(void) {
    833  int i;
    834  PRThread* t;
    835  PRSemaphore* server_sem;
    836  Server_Param* sparamp;
    837  Client_Param* cparamp;
    838  PRMonitor* mon2;
    839  PRInt32 datalen;
    840 
    841  datalen = tcp_mesg_size;
    842  thread_count = 0;
    843  /*
    844   * start the server thread
    845   */
    846  sparamp = PR_NEW(Server_Param);
    847  if (sparamp == NULL) {
    848    fprintf(stderr, "prsocket_test: PR_NEW failed\n");
    849    failed_already = 1;
    850    return -1;
    851  }
    852  server_sem = PR_NewSem(0);
    853  if (server_sem == NULL) {
    854    fprintf(stderr, "prsocket_test: PR_NewSem failed\n");
    855    failed_already = 1;
    856    return -1;
    857  }
    858  mon2 = PR_NewMonitor();
    859  if (mon2 == NULL) {
    860    fprintf(stderr, "prsocket_test: PR_NewMonitor failed\n");
    861    failed_already = 1;
    862    return -1;
    863  }
    864  PR_EnterMonitor(mon2);
    865 
    866  sparamp->addr_sem = server_sem;
    867  sparamp->exit_mon = mon2;
    868  sparamp->exit_counter = &thread_count;
    869  sparamp->datalen = datalen;
    870  t = PR_CreateThread(PR_USER_THREAD, TCP_Server, (void*)sparamp,
    871                      PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD,
    872                      0);
    873  if (t == NULL) {
    874    fprintf(stderr, "prsocket_test: PR_CreateThread failed\n");
    875    failed_already = 1;
    876    return -1;
    877  }
    878  DPRINTF(("Created TCP server = 0x%lx\n", t));
    879  thread_count++;
    880 
    881  /*
    882   * wait till the server address is setup
    883   */
    884  PR_WaitSem(server_sem);
    885 
    886  /*
    887   * Now start a bunch of client threads
    888   */
    889 
    890  cparamp = PR_NEW(Client_Param);
    891  if (cparamp == NULL) {
    892    fprintf(stderr, "prsocket_test: PR_NEW failed\n");
    893    failed_already = 1;
    894    return -1;
    895  }
    896  cparamp->server_addr = tcp_server_addr;
    897  cparamp->exit_mon = mon2;
    898  cparamp->exit_counter = &thread_count;
    899  cparamp->datalen = datalen;
    900  for (i = 0; i < num_tcp_clients; i++) {
    901    t = create_new_thread(PR_USER_THREAD, TCP_Client, (void*)cparamp,
    902                          PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
    903                          PR_UNJOINABLE_THREAD, 0, i);
    904    if (t == NULL) {
    905      fprintf(stderr, "prsocket_test: PR_CreateThread failed\n");
    906      failed_already = 1;
    907      return -1;
    908    }
    909    DPRINTF(("Created TCP client = 0x%lx\n", t));
    910    thread_count++;
    911  }
    912  /* Wait for server and client threads to exit */
    913  while (thread_count) {
    914    PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
    915    DPRINTF(("TCP Server - thread_count  = %d\n", thread_count));
    916  }
    917  PR_ExitMonitor(mon2);
    918  printf("%30s", "TCP_Socket_Client_Server_Test:");
    919  printf("%2ld Server %2ld Clients %2ld connections_per_client\n", 1l,
    920         num_tcp_clients, num_tcp_connections_per_client);
    921  printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n", ":",
    922         num_tcp_mesgs_per_connection, tcp_mesg_size);
    923 
    924  return 0;
    925 }
    926 
    927 /*
    928 * UDP_Socket_Client_Server_Test    - iterative server test
    929 *
    930 *    One server and several clients are started
    931 *    Each client connects to the server and sends a chunk of data
    932 *    For each connection, server starts another thread to read the data
    933 *    from the client and send it back to the client, unmodified.
    934 *    Each client checks that data received from server is same as the
    935 *    data it sent to the server.
    936 *
    937 */
    938 
    939 static PRInt32 UDP_Socket_Client_Server_Test(void) {
    940  int i;
    941  PRThread* t;
    942  PRSemaphore* server_sem;
    943  Server_Param* sparamp;
    944  Client_Param* cparamp;
    945  PRMonitor* mon2;
    946  PRInt32 datalen;
    947  PRInt32 udp_connect = 1;
    948 
    949  datalen = udp_datagram_size;
    950  thread_count = 0;
    951  /*
    952   * start the server thread
    953   */
    954  sparamp = PR_NEW(Server_Param);
    955  if (sparamp == NULL) {
    956    fprintf(stderr, "prsocket_test: PR_NEW failed\n");
    957    failed_already = 1;
    958    return -1;
    959  }
    960  server_sem = PR_NewSem(0);
    961  if (server_sem == NULL) {
    962    fprintf(stderr, "prsocket_test: PR_NewSem failed\n");
    963    failed_already = 1;
    964    return -1;
    965  }
    966  mon2 = PR_NewMonitor();
    967  if (mon2 == NULL) {
    968    fprintf(stderr, "prsocket_test: PR_NewMonitor failed\n");
    969    failed_already = 1;
    970    return -1;
    971  }
    972  PR_EnterMonitor(mon2);
    973 
    974  sparamp->addr_sem = server_sem;
    975  sparamp->exit_mon = mon2;
    976  sparamp->exit_counter = &thread_count;
    977  sparamp->datalen = datalen;
    978  DPRINTF(("Creating UDP server"));
    979  t = PR_CreateThread(PR_USER_THREAD, UDP_Server, (void*)sparamp,
    980                      PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD,
    981                      0);
    982  if (t == NULL) {
    983    fprintf(stderr, "prsocket_test: PR_CreateThread failed\n");
    984    failed_already = 1;
    985    return -1;
    986  }
    987  thread_count++;
    988 
    989  /*
    990   * wait till the server address is setup
    991   */
    992  PR_WaitSem(server_sem);
    993 
    994  /*
    995   * Now start a bunch of client threads
    996   */
    997 
    998  for (i = 0; i < num_udp_clients; i++) {
    999    cparamp = PR_NEW(Client_Param);
   1000    if (cparamp == NULL) {
   1001      fprintf(stderr, "prsocket_test: PR_NEW failed\n");
   1002      failed_already = 1;
   1003      return -1;
   1004    }
   1005    cparamp->server_addr = udp_server_addr;
   1006    cparamp->exit_mon = mon2;
   1007    cparamp->exit_counter = &thread_count;
   1008    cparamp->datalen = datalen;
   1009    /*
   1010     * Cause every other client thread to connect udp sockets
   1011     */
   1012    cparamp->udp_connect = udp_connect;
   1013    if (udp_connect) {
   1014      udp_connect = 0;
   1015    } else {
   1016      udp_connect = 1;
   1017    }
   1018    DPRINTF(("Creating UDP client %d\n", i));
   1019    t = PR_CreateThread(PR_USER_THREAD, UDP_Client, (void*)cparamp,
   1020                        PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
   1021                        PR_UNJOINABLE_THREAD, 0);
   1022    if (t == NULL) {
   1023      fprintf(stderr, "prsocket_test: PR_CreateThread failed\n");
   1024      failed_already = 1;
   1025      return -1;
   1026    }
   1027    thread_count++;
   1028  }
   1029  /* Wait for server and client threads to exit */
   1030  while (thread_count) {
   1031    PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
   1032    DPRINTF(("UDP Server - thread_count  = %d\n", thread_count));
   1033  }
   1034  PR_ExitMonitor(mon2);
   1035  printf("%30s", "UDP_Socket_Client_Server_Test: ");
   1036  printf("%2ld Server %2ld Clients\n", 1l, num_udp_clients);
   1037  printf("%30s %2ld datagrams_per_client %4ld bytes_per_datagram\n", ":",
   1038         num_udp_datagrams_per_client, udp_datagram_size);
   1039 
   1040  return 0;
   1041 }
   1042 
   1043 static PRFileDesc *small_file_fd, *large_file_fd;
   1044 static void *small_file_addr, *small_file_header, *large_file_addr;
   1045 static void *small_file_trailer, *large_file_header, *large_file_trailer;
   1046 /*
   1047 * TransmitFile_Client
   1048 *    Client Thread
   1049 */
   1050 static void TransmitFile_Client(void* arg) {
   1051  PRFileDesc* sockfd;
   1052  union PRNetAddr netaddr;
   1053  char *small_buf, *large_buf;
   1054  Client_Param* cp = (Client_Param*)arg;
   1055  PRInt32 rlen;
   1056 
   1057  small_buf = (char*)PR_Malloc(SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE +
   1058                               SMALL_FILE_TRAILER_SIZE);
   1059  if (small_buf == NULL) {
   1060    fprintf(stderr, "prsocket_test: failed to alloc buffer\n");
   1061    failed_already = 1;
   1062    return;
   1063  }
   1064  large_buf = (char*)PR_Malloc(LARGE_FILE_SIZE + LARGE_FILE_HEADER_SIZE +
   1065                               LARGE_FILE_TRAILER_SIZE);
   1066  if (large_buf == NULL) {
   1067    fprintf(stderr, "prsocket_test: failed to alloc buffer\n");
   1068    failed_already = 1;
   1069    return;
   1070  }
   1071  netaddr.inet.family = cp->server_addr.inet.family;
   1072  netaddr.inet.port = cp->server_addr.inet.port;
   1073  netaddr.inet.ip = cp->server_addr.inet.ip;
   1074 
   1075  if ((sockfd = PR_NewTCPSocket()) == NULL) {
   1076    fprintf(stderr, "prsocket_test: PR_NewTCPSocket failed\n");
   1077    failed_already = 1;
   1078    return;
   1079  }
   1080 
   1081  if (PR_Connect(sockfd, &netaddr, PR_INTERVAL_NO_TIMEOUT) < 0) {
   1082    fprintf(stderr, "prsocket_test: PR_Connect failed\n");
   1083    failed_already = 1;
   1084    return;
   1085  }
   1086  /*
   1087   * read the small file and verify the data
   1088   */
   1089  if (readn(sockfd, small_buf, SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE) !=
   1090      (SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)) {
   1091    fprintf(stderr,
   1092            "prsocket_test: TransmitFile_Client failed to receive file\n");
   1093    failed_already = 1;
   1094    return;
   1095  }
   1096 #if defined(XP_UNIX)
   1097  /* File transmission test can not be done because of large file's size */
   1098  if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0) {
   1099    fprintf(stderr,
   1100            "prsocket_test: TransmitFile_Client ERROR - small file header data "
   1101            "corruption\n");
   1102    failed_already = 1;
   1103    return;
   1104  }
   1105  if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE,
   1106             SMALL_FILE_SIZE) != 0) {
   1107    fprintf(stderr,
   1108            "prsocket_test: TransmitFile_Client ERROR - small file data "
   1109            "corruption\n");
   1110    failed_already = 1;
   1111    return;
   1112  }
   1113 #endif
   1114  /*
   1115   * read the large file and verify the data
   1116   */
   1117  if (readn(sockfd, large_buf, LARGE_FILE_SIZE) != LARGE_FILE_SIZE) {
   1118    fprintf(stderr,
   1119            "prsocket_test: TransmitFile_Client failed to receive file\n");
   1120    failed_already = 1;
   1121    return;
   1122  }
   1123 #if defined(XP_UNIX)
   1124  if (memcmp(large_file_addr, large_buf, LARGE_FILE_SIZE) != 0) {
   1125    fprintf(stderr,
   1126            "prsocket_test: TransmitFile_Client ERROR - large file data "
   1127            "corruption\n");
   1128    failed_already = 1;
   1129  }
   1130 #endif
   1131 
   1132  /*
   1133   * receive data from PR_SendFile
   1134   */
   1135  /*
   1136   * case 1: small file with header and trailer
   1137   */
   1138  rlen = SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE + SMALL_FILE_TRAILER_SIZE;
   1139  if (readn(sockfd, small_buf, rlen) != rlen) {
   1140    fprintf(stderr, "prsocket_test: SendFile_Client failed to receive file\n");
   1141    failed_already = 1;
   1142    return;
   1143  }
   1144 #if defined(XP_UNIX)
   1145  if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0) {
   1146    fprintf(stderr, "SendFile 1. ERROR - small file header corruption\n");
   1147    failed_already = 1;
   1148    return;
   1149  }
   1150  if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE,
   1151             SMALL_FILE_SIZE) != 0) {
   1152    fprintf(stderr, "SendFile 1. ERROR - small file data corruption\n");
   1153    failed_already = 1;
   1154    return;
   1155  }
   1156  if (memcmp(small_file_trailer,
   1157             small_buf + SMALL_FILE_HEADER_SIZE + SMALL_FILE_SIZE,
   1158             SMALL_FILE_TRAILER_SIZE) != 0) {
   1159    fprintf(stderr, "SendFile 1. ERROR - small file trailer corruption\n");
   1160    failed_already = 1;
   1161    return;
   1162  }
   1163 #endif
   1164  /*
   1165   * case 2: partial large file at zero offset, file with header and trailer
   1166   */
   1167  rlen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE + LARGE_FILE_TRAILER_SIZE;
   1168  if (readn(sockfd, large_buf, rlen) != rlen) {
   1169    fprintf(stderr, "prsocket_test: SendFile_Client failed to receive file\n");
   1170    failed_already = 1;
   1171    return;
   1172  }
   1173 #if defined(XP_UNIX)
   1174  if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0) {
   1175    fprintf(stderr, "SendFile 2. ERROR - large file header corruption\n");
   1176    failed_already = 1;
   1177    return;
   1178  }
   1179  if (memcmp(large_file_addr, large_buf + LARGE_FILE_HEADER_SIZE,
   1180             LARGE_FILE_LEN_1) != 0) {
   1181    fprintf(stderr, "SendFile 2. ERROR - large file data corruption\n");
   1182    failed_already = 1;
   1183    return;
   1184  }
   1185  if (memcmp(large_file_trailer,
   1186             large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_1,
   1187             LARGE_FILE_TRAILER_SIZE) != 0) {
   1188    fprintf(stderr, "SendFile 2. ERROR - large file trailer corruption\n");
   1189    failed_already = 1;
   1190    return;
   1191  }
   1192 #endif
   1193  /*
   1194   * case 3: partial small file at non-zero offset, with header
   1195   */
   1196  rlen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE;
   1197  if (readn(sockfd, small_buf, rlen) != rlen) {
   1198    fprintf(stderr, "prsocket_test: SendFile_Client failed to receive file\n");
   1199    failed_already = 1;
   1200    return;
   1201  }
   1202 #if defined(XP_UNIX)
   1203  if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0) {
   1204    fprintf(stderr, "SendFile 3. ERROR - small file header corruption\n");
   1205    failed_already = 1;
   1206    return;
   1207  }
   1208  if (memcmp((char*)small_file_addr + SMALL_FILE_OFFSET_1,
   1209             small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_1) != 0) {
   1210    fprintf(stderr, "SendFile 3. ERROR - small file data corruption\n");
   1211    failed_already = 1;
   1212    return;
   1213  }
   1214 #endif
   1215  /*
   1216   * case 4: partial small file at non-zero offset, with trailer
   1217   */
   1218  rlen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE;
   1219  if (readn(sockfd, small_buf, rlen) != rlen) {
   1220    fprintf(stderr, "prsocket_test: SendFile_Client failed to receive file\n");
   1221    failed_already = 1;
   1222    return;
   1223  }
   1224 #if defined(XP_UNIX)
   1225  if (memcmp((char*)small_file_addr + SMALL_FILE_OFFSET_2, small_buf,
   1226             SMALL_FILE_LEN_2) != 0) {
   1227    fprintf(stderr, "SendFile 4. ERROR - small file data corruption\n");
   1228    failed_already = 1;
   1229    return;
   1230  }
   1231  if (memcmp(small_file_trailer, small_buf + SMALL_FILE_LEN_2,
   1232             SMALL_FILE_TRAILER_SIZE) != 0) {
   1233    fprintf(stderr, "SendFile 4. ERROR - small file trailer corruption\n");
   1234    failed_already = 1;
   1235    return;
   1236  }
   1237 #endif
   1238  /*
   1239   * case 5: partial large file at non-zero offset, file with header
   1240   */
   1241  rlen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE;
   1242  if (readn(sockfd, large_buf, rlen) != rlen) {
   1243    fprintf(stderr, "prsocket_test: SendFile_Client failed to receive file\n");
   1244    failed_already = 1;
   1245    return;
   1246  }
   1247 #if defined(XP_UNIX)
   1248  if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0) {
   1249    fprintf(stderr, "SendFile 5. ERROR - large file header corruption\n");
   1250    failed_already = 1;
   1251    return;
   1252  }
   1253  if (memcmp((char*)large_file_addr + LARGE_FILE_OFFSET_2,
   1254             large_buf + LARGE_FILE_HEADER_SIZE, LARGE_FILE_LEN_2) != 0) {
   1255    fprintf(stderr, "SendFile 5. ERROR - large file data corruption\n");
   1256    failed_already = 1;
   1257    return;
   1258  }
   1259 #endif
   1260  /*
   1261   * case 6: partial small file at non-zero offset, with header
   1262   */
   1263  rlen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE;
   1264  if (readn(sockfd, small_buf, rlen) != rlen) {
   1265    fprintf(stderr, "prsocket_test: SendFile_Client failed to receive file\n");
   1266    failed_already = 1;
   1267    return;
   1268  }
   1269 #if defined(XP_UNIX)
   1270  if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0) {
   1271    fprintf(stderr, "SendFile 6. ERROR - small file header corruption\n");
   1272    return;
   1273  }
   1274  if (memcmp((char*)small_file_addr + SMALL_FILE_OFFSET_3,
   1275             small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_3) != 0) {
   1276 #  if 0
   1277        char *i, *j;
   1278        int k;
   1279 
   1280        i = (char *) small_file_addr + SMALL_FILE_OFFSET_3;
   1281        j = small_buf + SMALL_FILE_HEADER_SIZE;
   1282        k = SMALL_FILE_LEN_3;
   1283        while (k-- > 0) {
   1284            if (*i++ != *j++)
   1285                printf("i = %d j = %d\n",
   1286                       (int) (i - ((char *) small_file_addr + SMALL_FILE_OFFSET_3)),
   1287                       (int) (j - (small_buf + SMALL_FILE_HEADER_SIZE)));
   1288        }
   1289 #  endif
   1290    fprintf(stderr, "SendFile 6. ERROR - small file data corruption\n");
   1291    failed_already = 1;
   1292    return;
   1293  }
   1294 #endif
   1295  /*
   1296   * case 7: partial large file at non-zero offset, with header
   1297   */
   1298  rlen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE;
   1299  if (readn(sockfd, large_buf, rlen) != rlen) {
   1300    fprintf(stderr, "prsocket_test: SendFile_Client failed to receive file\n");
   1301    failed_already = 1;
   1302    return;
   1303  }
   1304 #if defined(XP_UNIX)
   1305  if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0) {
   1306    fprintf(stderr, "SendFile 7. ERROR - large file header corruption\n");
   1307    failed_already = 1;
   1308    return;
   1309  }
   1310  if (memcmp((char*)large_file_addr + LARGE_FILE_OFFSET_3,
   1311             large_buf + LARGE_FILE_HEADER_SIZE, LARGE_FILE_LEN_3) != 0) {
   1312    fprintf(stderr, "SendFile 7. ERROR - large file data corruption\n");
   1313    failed_already = 1;
   1314    return;
   1315  }
   1316 #endif
   1317  /*
   1318   * case 8: partial large file at non-zero, page-aligned offset, with
   1319   * header and trailer
   1320   */
   1321  rlen = LARGE_FILE_LEN_4 + LARGE_FILE_HEADER_SIZE + LARGE_FILE_TRAILER_SIZE;
   1322  if (readn(sockfd, large_buf, rlen) != rlen) {
   1323    fprintf(stderr, "prsocket_test: SendFile_Client failed to receive file\n");
   1324    failed_already = 1;
   1325    return;
   1326  }
   1327 #if defined(XP_UNIX)
   1328  if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0) {
   1329    fprintf(stderr, "SendFile 2. ERROR - large file header corruption\n");
   1330    failed_already = 1;
   1331    return;
   1332  }
   1333  if (memcmp((char*)large_file_addr + LARGE_FILE_OFFSET_4,
   1334             large_buf + LARGE_FILE_HEADER_SIZE, LARGE_FILE_LEN_4) != 0) {
   1335    fprintf(stderr, "SendFile 2. ERROR - large file data corruption\n");
   1336    failed_already = 1;
   1337    return;
   1338  }
   1339  if (memcmp(large_file_trailer,
   1340             large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_4,
   1341             LARGE_FILE_TRAILER_SIZE) != 0) {
   1342    fprintf(stderr, "SendFile 2. ERROR - large file trailer corruption\n");
   1343    failed_already = 1;
   1344    return;
   1345  }
   1346 #endif
   1347  PR_DELETE(small_buf);
   1348  PR_DELETE(large_buf);
   1349  PR_Close(sockfd);
   1350 
   1351  /*
   1352   * Decrement exit_counter and notify parent thread
   1353   */
   1354 
   1355  PR_EnterMonitor(cp->exit_mon);
   1356  --(*cp->exit_counter);
   1357  PR_Notify(cp->exit_mon);
   1358  PR_ExitMonitor(cp->exit_mon);
   1359  DPRINTF(("TransmitFile_Client [0x%lx] exiting\n", PR_GetCurrentThread()));
   1360 }
   1361 
   1362 /*
   1363 * Serve_TransmitFile_Client
   1364 *    Thread, started by the server, for serving a client connection.
   1365 *    Trasmits a small file, with a header, and a large file, without
   1366 *    a header
   1367 */
   1368 static void Serve_TransmitFile_Client(void* arg) {
   1369  Serve_Client_Param* scp = (Serve_Client_Param*)arg;
   1370  PRFileDesc* sockfd;
   1371  PRInt32 bytes;
   1372  PRFileDesc* local_small_file_fd = NULL;
   1373  PRFileDesc* local_large_file_fd = NULL;
   1374  PRSendFileData sfd;
   1375  PRInt32 slen;
   1376 
   1377  sockfd = scp->sockfd;
   1378  local_small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDONLY, 0);
   1379 
   1380  if (local_small_file_fd == NULL) {
   1381    fprintf(stderr, "prsocket_test failed to open file for transmitting %s\n",
   1382            SMALL_FILE_NAME);
   1383    failed_already = 1;
   1384    goto done;
   1385  }
   1386  local_large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDONLY, 0);
   1387 
   1388  if (local_large_file_fd == NULL) {
   1389    fprintf(stderr, "prsocket_test failed to open file for transmitting %s\n",
   1390            LARGE_FILE_NAME);
   1391    failed_already = 1;
   1392    goto done;
   1393  }
   1394  bytes = PR_TransmitFile(sockfd, local_small_file_fd, small_file_header,
   1395                          SMALL_FILE_HEADER_SIZE, PR_TRANSMITFILE_KEEP_OPEN,
   1396                          PR_INTERVAL_NO_TIMEOUT);
   1397  if (bytes != (SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)) {
   1398    fprintf(stderr, "prsocet_test: PR_TransmitFile failed: (%ld, %ld)\n",
   1399            PR_GetError(), PR_GetOSError());
   1400    failed_already = 1;
   1401  }
   1402  bytes = PR_TransmitFile(sockfd, local_large_file_fd, NULL, 0,
   1403                          PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT);
   1404  if (bytes != LARGE_FILE_SIZE) {
   1405    fprintf(stderr, "prsocket_test: PR_TransmitFile failed: (%ld, %ld)\n",
   1406            PR_GetError(), PR_GetOSError());
   1407    failed_already = 1;
   1408  }
   1409 
   1410  /*
   1411   * PR_SendFile test cases
   1412   */
   1413 
   1414  /*
   1415   * case 1: small file with header and trailer
   1416   */
   1417  sfd.fd = local_small_file_fd;
   1418  sfd.file_offset = 0;
   1419  sfd.file_nbytes = 0;
   1420  sfd.header = small_file_header;
   1421  sfd.hlen = SMALL_FILE_HEADER_SIZE;
   1422  sfd.trailer = small_file_trailer;
   1423  sfd.tlen = SMALL_FILE_TRAILER_SIZE;
   1424  bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
   1425                      PR_INTERVAL_NO_TIMEOUT);
   1426  slen = SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE + SMALL_FILE_TRAILER_SIZE;
   1427  if (bytes != slen) {
   1428    fprintf(stderr,
   1429            "socket: Error - 1. PR_SendFile  send_size = %d, bytes sent = %d\n",
   1430            slen, bytes);
   1431    fprintf(stderr, "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
   1432            PR_GetError(), PR_GetOSError());
   1433    failed_already = 1;
   1434  }
   1435 
   1436  /*
   1437   * case 2: partial large file at zero offset, file with header and trailer
   1438   */
   1439  sfd.fd = local_large_file_fd;
   1440  sfd.file_offset = 0;
   1441  sfd.file_nbytes = LARGE_FILE_LEN_1;
   1442  sfd.header = large_file_header;
   1443  sfd.hlen = LARGE_FILE_HEADER_SIZE;
   1444  sfd.trailer = large_file_trailer;
   1445  sfd.tlen = LARGE_FILE_TRAILER_SIZE;
   1446  bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
   1447                      PR_INTERVAL_NO_TIMEOUT);
   1448  slen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE + LARGE_FILE_TRAILER_SIZE;
   1449  if (bytes != slen) {
   1450    fprintf(stderr,
   1451            "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n",
   1452            slen, bytes);
   1453    fprintf(stderr, "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
   1454            PR_GetError(), PR_GetOSError());
   1455    failed_already = 1;
   1456  }
   1457  /*
   1458   * case 3: partial small file at non-zero offset, with header
   1459   */
   1460  sfd.fd = local_small_file_fd;
   1461  sfd.file_offset = SMALL_FILE_OFFSET_1;
   1462  sfd.file_nbytes = SMALL_FILE_LEN_1;
   1463  sfd.header = small_file_header;
   1464  sfd.hlen = SMALL_FILE_HEADER_SIZE;
   1465  sfd.trailer = NULL;
   1466  sfd.tlen = 0;
   1467  bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
   1468                      PR_INTERVAL_NO_TIMEOUT);
   1469  slen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE;
   1470  if (bytes != slen) {
   1471    fprintf(stderr,
   1472            "socket: Error - 3. PR_SendFile send_size = %d, bytes sent = %d\n",
   1473            slen, bytes);
   1474    fprintf(stderr, "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
   1475            PR_GetError(), PR_GetOSError());
   1476    failed_already = 1;
   1477  }
   1478  /*
   1479   * case 4: partial small file at non-zero offset, with trailer
   1480   */
   1481  sfd.fd = local_small_file_fd;
   1482  sfd.file_offset = SMALL_FILE_OFFSET_2;
   1483  sfd.file_nbytes = SMALL_FILE_LEN_2;
   1484  sfd.header = NULL;
   1485  sfd.hlen = 0;
   1486  sfd.trailer = small_file_trailer;
   1487  sfd.tlen = SMALL_FILE_TRAILER_SIZE;
   1488  bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
   1489                      PR_INTERVAL_NO_TIMEOUT);
   1490  slen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE;
   1491  if (bytes != slen) {
   1492    fprintf(stderr,
   1493            "socket: Error - 4. PR_SendFile send_size = %d, bytes sent = %d\n",
   1494            slen, bytes);
   1495    fprintf(stderr, "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
   1496            PR_GetError(), PR_GetOSError());
   1497    failed_already = 1;
   1498  }
   1499  /*
   1500   * case 5: partial large file at non-zero offset, file with header
   1501   */
   1502  sfd.fd = local_large_file_fd;
   1503  sfd.file_offset = LARGE_FILE_OFFSET_2;
   1504  sfd.file_nbytes = LARGE_FILE_LEN_2;
   1505  sfd.header = large_file_header;
   1506  sfd.hlen = LARGE_FILE_HEADER_SIZE;
   1507  sfd.trailer = NULL;
   1508  sfd.tlen = 0;
   1509  bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
   1510                      PR_INTERVAL_NO_TIMEOUT);
   1511  slen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE;
   1512  if (bytes != slen) {
   1513    fprintf(stderr,
   1514            "socket: Error - 5. PR_SendFile send_size = %d, bytes sent = %d\n",
   1515            slen, bytes);
   1516    fprintf(stderr, "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
   1517            PR_GetError(), PR_GetOSError());
   1518    failed_already = 1;
   1519  }
   1520  /*
   1521   * case 6: partial small file from non-zero offset till end of file, with
   1522   * header
   1523   */
   1524  sfd.fd = local_small_file_fd;
   1525  sfd.file_offset = SMALL_FILE_OFFSET_3;
   1526  sfd.file_nbytes = 0; /* data from offset to end-of-file */
   1527  sfd.header = small_file_header;
   1528  sfd.hlen = SMALL_FILE_HEADER_SIZE;
   1529  sfd.trailer = NULL;
   1530  sfd.tlen = 0;
   1531  bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
   1532                      PR_INTERVAL_NO_TIMEOUT);
   1533  slen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE;
   1534  if (bytes != slen) {
   1535    fprintf(stderr,
   1536            "socket: Error - 6. PR_SendFile send_size = %d, bytes sent = %d\n",
   1537            slen, bytes);
   1538    fprintf(stderr, "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
   1539            PR_GetError(), PR_GetOSError());
   1540    failed_already = 1;
   1541  }
   1542  /*
   1543   * case 7: partial large file at non-zero offset till end-of-file, with header
   1544   */
   1545  sfd.fd = local_large_file_fd;
   1546  sfd.file_offset = LARGE_FILE_OFFSET_3;
   1547  sfd.file_nbytes = 0; /* data until end-of-file */
   1548  sfd.header = large_file_header;
   1549  sfd.hlen = LARGE_FILE_HEADER_SIZE;
   1550  sfd.trailer = NULL;
   1551  sfd.tlen = 0;
   1552  bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
   1553                      PR_INTERVAL_NO_TIMEOUT);
   1554  slen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE;
   1555  if (bytes != slen) {
   1556    fprintf(stderr,
   1557            "socket: Error - 7. PR_SendFile send_size = %d, bytes sent = %d\n",
   1558            slen, bytes);
   1559    fprintf(stderr, "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
   1560            PR_GetError(), PR_GetOSError());
   1561    failed_already = 1;
   1562  }
   1563  /*
   1564   * case 8: partial large file at non-zero page-aligned offset,
   1565   * with header and trailer
   1566   */
   1567  sfd.fd = local_large_file_fd;
   1568  sfd.file_offset = LARGE_FILE_OFFSET_4;
   1569  sfd.file_nbytes = LARGE_FILE_LEN_4;
   1570  sfd.header = large_file_header;
   1571  sfd.hlen = LARGE_FILE_HEADER_SIZE;
   1572  sfd.trailer = large_file_trailer;
   1573  sfd.tlen = LARGE_FILE_TRAILER_SIZE;
   1574  bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_CLOSE_SOCKET,
   1575                      PR_INTERVAL_NO_TIMEOUT);
   1576  slen = LARGE_FILE_LEN_4 + LARGE_FILE_HEADER_SIZE + LARGE_FILE_TRAILER_SIZE;
   1577  if (bytes != slen) {
   1578    fprintf(stderr,
   1579            "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n",
   1580            slen, bytes);
   1581    fprintf(stderr, "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
   1582            PR_GetError(), PR_GetOSError());
   1583    failed_already = 1;
   1584  }
   1585 done:
   1586  if (local_small_file_fd != NULL) {
   1587    PR_Close(local_small_file_fd);
   1588  }
   1589  if (local_large_file_fd != NULL) {
   1590    PR_Close(local_large_file_fd);
   1591  }
   1592 }
   1593 
   1594 /*
   1595 * TransmitFile Server
   1596 *    Server Thread
   1597 *    Bind an address to a socket and listen for incoming connections
   1598 *    Create worker threads to service clients
   1599 */
   1600 static void TransmitFile_Server(void* arg) {
   1601  PRThread** t = NULL; /* an array of PRThread pointers */
   1602  Server_Param* sp = (Server_Param*)arg;
   1603  Serve_Client_Param* scp;
   1604  PRFileDesc *sockfd = NULL, *newsockfd;
   1605  PRNetAddr netaddr;
   1606  PRInt32 i;
   1607 
   1608  t = (PRThread**)PR_MALLOC(num_transmitfile_clients * sizeof(PRThread*));
   1609  if (t == NULL) {
   1610    fprintf(stderr, "prsocket_test: run out of memory\n");
   1611    failed_already = 1;
   1612    goto exit;
   1613  }
   1614  /*
   1615   * Create a tcp socket
   1616   */
   1617  if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) {
   1618    fprintf(stderr, "prsocket_test: PR_OpenTCPSocket failed\n");
   1619    failed_already = 1;
   1620    goto exit;
   1621  }
   1622  memset(&netaddr, 0, sizeof(netaddr));
   1623  netaddr.inet.family = PR_AF_INET;
   1624  netaddr.inet.port = PR_htons(TCP_SERVER_PORT);
   1625  netaddr.inet.ip = PR_htonl(PR_INADDR_ANY);
   1626  /*
   1627   * try a few times to bind server's address, if addresses are in
   1628   * use
   1629   */
   1630  i = 0;
   1631  while (PR_Bind(sockfd, &netaddr) < 0) {
   1632    if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
   1633      netaddr.inet.port += 2;
   1634      if (i++ < SERVER_MAX_BIND_COUNT) {
   1635        continue;
   1636      }
   1637    }
   1638    fprintf(stderr, "prsocket_test: ERROR - PR_Bind failed\n");
   1639    failed_already = 1;
   1640    perror("PR_Bind");
   1641    goto exit;
   1642  }
   1643 
   1644  if (PR_Listen(sockfd, 32) < 0) {
   1645    fprintf(stderr, "prsocket_test: ERROR - PR_Listen failed\n");
   1646    failed_already = 1;
   1647    goto exit;
   1648  }
   1649 
   1650  if (PR_GetSockName(sockfd, &netaddr) < 0) {
   1651    fprintf(stderr, "prsocket_test: ERROR - PR_GetSockName failed\n");
   1652    failed_already = 1;
   1653    goto exit;
   1654  }
   1655 
   1656  DPRINTF(
   1657      ("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
   1658       netaddr.inet.ip, netaddr.inet.port));
   1659  tcp_server_addr.inet.family = netaddr.inet.family;
   1660  tcp_server_addr.inet.port = netaddr.inet.port;
   1661  tcp_server_addr.inet.ip = netaddr.inet.ip;
   1662 
   1663  /*
   1664   * Wake up parent thread because server address is bound and made
   1665   * available in the global variable 'tcp_server_addr'
   1666   */
   1667  PR_PostSem(sp->addr_sem);
   1668 
   1669  for (i = 0; i < num_transmitfile_clients; i++) {
   1670    /* test both null and non-null 'addr' argument to PR_Accept */
   1671    PRNetAddr* addrp = (i % 2 ? &netaddr : NULL);
   1672 
   1673    if ((newsockfd = PR_Accept(sockfd, addrp, PR_INTERVAL_NO_TIMEOUT)) ==
   1674        NULL) {
   1675      fprintf(stderr, "prsocket_test: ERROR - PR_Accept failed\n");
   1676      failed_already = 1;
   1677      goto exit;
   1678    }
   1679    /* test both regular and emulated PR_SendFile */
   1680    if (i % 2) {
   1681      PRFileDesc* layer =
   1682          PR_CreateIOLayerStub(emuSendFileIdentity, &emuSendFileMethods);
   1683      if (layer == NULL) {
   1684        fprintf(stderr, "prsocket_test: ERROR - PR_CreateIOLayerStub failed\n");
   1685        failed_already = 1;
   1686        goto exit;
   1687      }
   1688      if (PR_PushIOLayer(newsockfd, PR_TOP_IO_LAYER, layer) == PR_FAILURE) {
   1689        fprintf(stderr, "prsocket_test: ERROR - PR_PushIOLayer failed\n");
   1690        failed_already = 1;
   1691        goto exit;
   1692      }
   1693    }
   1694    scp = PR_NEW(Serve_Client_Param);
   1695    if (scp == NULL) {
   1696      fprintf(stderr, "prsocket_test: PR_NEW failed\n");
   1697      failed_already = 1;
   1698      goto exit;
   1699    }
   1700 
   1701    /*
   1702     * Start a Serve_Client thread for each incoming connection
   1703     */
   1704    scp->sockfd = newsockfd;
   1705    scp->datalen = sp->datalen;
   1706 
   1707    t[i] = PR_CreateThread(PR_USER_THREAD, Serve_TransmitFile_Client,
   1708                           (void*)scp, PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
   1709                           PR_JOINABLE_THREAD, 0);
   1710    if (t[i] == NULL) {
   1711      fprintf(stderr, "prsocket_test: PR_CreateThread failed\n");
   1712      failed_already = 1;
   1713      goto exit;
   1714    }
   1715    DPRINTF(("TransmitFile_Server: Created Serve_TransmitFile_Client = 0x%lx\n",
   1716             t));
   1717  }
   1718 
   1719  /*
   1720   * Wait for all the worker threads to end, so that we know
   1721   * they are no longer using the small and large file fd's.
   1722   */
   1723 
   1724  for (i = 0; i < num_transmitfile_clients; i++) {
   1725    PR_JoinThread(t[i]);
   1726  }
   1727 
   1728 exit:
   1729  if (t) {
   1730    PR_DELETE(t);
   1731  }
   1732  if (sockfd) {
   1733    PR_Close(sockfd);
   1734  }
   1735 
   1736  /*
   1737   * Decrement exit_counter and notify parent thread
   1738   */
   1739 
   1740  PR_EnterMonitor(sp->exit_mon);
   1741  --(*sp->exit_counter);
   1742  PR_Notify(sp->exit_mon);
   1743  PR_ExitMonitor(sp->exit_mon);
   1744  DPRINTF(("TransmitFile_Server [0x%lx] exiting\n", PR_GetCurrentThread()));
   1745 }
   1746 
   1747 /*
   1748 * Socket_Misc_Test    - test miscellaneous functions
   1749 *
   1750 */
   1751 static PRInt32 Socket_Misc_Test(void) {
   1752  PRIntn i, rv = 0, bytes, count, len;
   1753  PRThread* t;
   1754  PRSemaphore* server_sem;
   1755  Server_Param* sparamp;
   1756  Client_Param* cparamp;
   1757  PRMonitor* mon2;
   1758  PRInt32 datalen;
   1759 
   1760  /*
   1761   * We deliberately pick a buffer size that is not a nice multiple
   1762   * of 1024.
   1763   */
   1764 #define TRANSMITFILE_BUF_SIZE (4 * 1024 - 11)
   1765 
   1766  typedef struct {
   1767    char data[TRANSMITFILE_BUF_SIZE];
   1768  } file_buf;
   1769  file_buf* buf = NULL;
   1770 
   1771  /*
   1772   * create file(s) to be transmitted
   1773   */
   1774  if ((PR_MkDir(TEST_DIR, 0777)) < 0) {
   1775    printf("prsocket_test failed to create dir %s\n", TEST_DIR);
   1776    failed_already = 1;
   1777    return -1;
   1778  }
   1779 
   1780  small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDWR | PR_CREATE_FILE, 0777);
   1781 
   1782  if (small_file_fd == NULL) {
   1783    fprintf(stderr, "prsocket_test failed to create/open file %s\n",
   1784            SMALL_FILE_NAME);
   1785    failed_already = 1;
   1786    rv = -1;
   1787    goto done;
   1788  }
   1789  buf = PR_NEW(file_buf);
   1790  if (buf == NULL) {
   1791    fprintf(stderr, "prsocket_test failed to allocate buffer\n");
   1792    failed_already = 1;
   1793    rv = -1;
   1794    goto done;
   1795  }
   1796  /*
   1797   * fill in random data
   1798   */
   1799  for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) {
   1800    buf->data[i] = i;
   1801  }
   1802  count = 0;
   1803  do {
   1804    len = (SMALL_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE
   1805              ? TRANSMITFILE_BUF_SIZE
   1806              : (SMALL_FILE_SIZE - count);
   1807    bytes = PR_Write(small_file_fd, buf->data, len);
   1808    if (bytes <= 0) {
   1809      fprintf(stderr, "prsocket_test failed to write to file %s\n",
   1810              SMALL_FILE_NAME);
   1811      failed_already = 1;
   1812      rv = -1;
   1813      goto done;
   1814    }
   1815    count += bytes;
   1816  } while (count < SMALL_FILE_SIZE);
   1817 #ifdef XP_UNIX
   1818  /*
   1819   * map the small file; used in checking for data corruption
   1820   */
   1821  small_file_addr = mmap(0, SMALL_FILE_SIZE, PROT_READ, MAP_SHARED,
   1822                         small_file_fd->secret->md.osfd, 0);
   1823  if (small_file_addr == (void*)-1) {
   1824    fprintf(stderr, "prsocket_test failed to mmap file %s\n", SMALL_FILE_NAME);
   1825    failed_already = 1;
   1826    rv = -1;
   1827    goto done;
   1828  }
   1829 #endif
   1830  /*
   1831   * header for small file
   1832   */
   1833  small_file_header = PR_MALLOC(SMALL_FILE_HEADER_SIZE);
   1834  if (small_file_header == NULL) {
   1835    fprintf(stderr, "prsocket_test failed to malloc header file\n");
   1836    failed_already = 1;
   1837    rv = -1;
   1838    goto done;
   1839  }
   1840  memset(small_file_header, (int)PR_IntervalNow(), SMALL_FILE_HEADER_SIZE);
   1841  /*
   1842   * trailer for small file
   1843   */
   1844  small_file_trailer = PR_MALLOC(SMALL_FILE_TRAILER_SIZE);
   1845  if (small_file_trailer == NULL) {
   1846    fprintf(stderr, "prsocket_test failed to malloc header trailer\n");
   1847    failed_already = 1;
   1848    rv = -1;
   1849    goto done;
   1850  }
   1851  memset(small_file_trailer, (int)PR_IntervalNow(), SMALL_FILE_TRAILER_SIZE);
   1852  /*
   1853   * setup large file
   1854   */
   1855  large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDWR | PR_CREATE_FILE, 0777);
   1856 
   1857  if (large_file_fd == NULL) {
   1858    fprintf(stderr, "prsocket_test failed to create/open file %s\n",
   1859            LARGE_FILE_NAME);
   1860    failed_already = 1;
   1861    rv = -1;
   1862    goto done;
   1863  }
   1864  /*
   1865   * fill in random data
   1866   */
   1867  for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) {
   1868    buf->data[i] = i;
   1869  }
   1870  count = 0;
   1871  do {
   1872    len = (LARGE_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE
   1873              ? TRANSMITFILE_BUF_SIZE
   1874              : (LARGE_FILE_SIZE - count);
   1875    bytes = PR_Write(large_file_fd, buf->data, len);
   1876    if (bytes <= 0) {
   1877      fprintf(stderr, "prsocket_test failed to write to file %s: (%ld, %ld)\n",
   1878              LARGE_FILE_NAME, PR_GetError(), PR_GetOSError());
   1879      failed_already = 1;
   1880      rv = -1;
   1881      goto done;
   1882    }
   1883    count += bytes;
   1884  } while (count < LARGE_FILE_SIZE);
   1885 #if defined(XP_UNIX)
   1886  /*
   1887   * map the large file; used in checking for data corruption
   1888   */
   1889  large_file_addr = mmap(0, LARGE_FILE_SIZE, PROT_READ, MAP_SHARED,
   1890                         large_file_fd->secret->md.osfd, 0);
   1891  if (large_file_addr == (void*)-1) {
   1892    fprintf(stderr, "prsocket_test failed to mmap file %s\n", LARGE_FILE_NAME);
   1893    failed_already = 1;
   1894    rv = -1;
   1895    goto done;
   1896  }
   1897 #endif
   1898  /*
   1899   * header for large file
   1900   */
   1901  large_file_header = PR_MALLOC(LARGE_FILE_HEADER_SIZE);
   1902  if (large_file_header == NULL) {
   1903    fprintf(stderr, "prsocket_test failed to malloc header file\n");
   1904    failed_already = 1;
   1905    rv = -1;
   1906    goto done;
   1907  }
   1908  memset(large_file_header, (int)PR_IntervalNow(), LARGE_FILE_HEADER_SIZE);
   1909  /*
   1910   * trailer for large file
   1911   */
   1912  large_file_trailer = PR_MALLOC(LARGE_FILE_TRAILER_SIZE);
   1913  if (large_file_trailer == NULL) {
   1914    fprintf(stderr, "prsocket_test failed to malloc header trailer\n");
   1915    failed_already = 1;
   1916    rv = -1;
   1917    goto done;
   1918  }
   1919  memset(large_file_trailer, (int)PR_IntervalNow(), LARGE_FILE_TRAILER_SIZE);
   1920 
   1921  datalen = tcp_mesg_size;
   1922  thread_count = 0;
   1923  /*
   1924   * start the server thread
   1925   */
   1926  sparamp = PR_NEW(Server_Param);
   1927  if (sparamp == NULL) {
   1928    fprintf(stderr, "prsocket_test: PR_NEW failed\n");
   1929    failed_already = 1;
   1930    rv = -1;
   1931    goto done;
   1932  }
   1933  server_sem = PR_NewSem(0);
   1934  if (server_sem == NULL) {
   1935    fprintf(stderr, "prsocket_test: PR_NewSem failed\n");
   1936    failed_already = 1;
   1937    rv = -1;
   1938    goto done;
   1939  }
   1940  mon2 = PR_NewMonitor();
   1941  if (mon2 == NULL) {
   1942    fprintf(stderr, "prsocket_test: PR_NewMonitor failed\n");
   1943    failed_already = 1;
   1944    rv = -1;
   1945    goto done;
   1946  }
   1947  PR_EnterMonitor(mon2);
   1948 
   1949  sparamp->addr_sem = server_sem;
   1950  sparamp->exit_mon = mon2;
   1951  sparamp->exit_counter = &thread_count;
   1952  sparamp->datalen = datalen;
   1953  t = PR_CreateThread(PR_USER_THREAD, TransmitFile_Server, (void*)sparamp,
   1954                      PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD,
   1955                      0);
   1956  if (t == NULL) {
   1957    fprintf(stderr, "prsocket_test: PR_CreateThread failed\n");
   1958    failed_already = 1;
   1959    rv = -1;
   1960    goto done;
   1961  }
   1962  DPRINTF(("Created TCP server = 0x%x\n", t));
   1963  thread_count++;
   1964 
   1965  /*
   1966   * wait till the server address is setup
   1967   */
   1968  PR_WaitSem(server_sem);
   1969 
   1970  /*
   1971   * Now start a bunch of client threads
   1972   */
   1973 
   1974  cparamp = PR_NEW(Client_Param);
   1975  if (cparamp == NULL) {
   1976    fprintf(stderr, "prsocket_test: PR_NEW failed\n");
   1977    failed_already = 1;
   1978    rv = -1;
   1979    goto done;
   1980  }
   1981  cparamp->server_addr = tcp_server_addr;
   1982  cparamp->server_addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
   1983  cparamp->exit_mon = mon2;
   1984  cparamp->exit_counter = &thread_count;
   1985  cparamp->datalen = datalen;
   1986  for (i = 0; i < num_transmitfile_clients; i++) {
   1987    t = create_new_thread(PR_USER_THREAD, TransmitFile_Client, (void*)cparamp,
   1988                          PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
   1989                          PR_UNJOINABLE_THREAD, 0, i);
   1990    if (t == NULL) {
   1991      fprintf(stderr, "prsocket_test: PR_CreateThread failed\n");
   1992      rv = -1;
   1993      failed_already = 1;
   1994      goto done;
   1995    }
   1996    DPRINTF(("Created TransmitFile client = 0x%lx\n", t));
   1997    thread_count++;
   1998  }
   1999  /* Wait for server and client threads to exit */
   2000  while (thread_count) {
   2001    PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
   2002    DPRINTF(("Socket_Misc_Test - thread_count  = %d\n", thread_count));
   2003  }
   2004  PR_ExitMonitor(mon2);
   2005 done:
   2006  if (buf) {
   2007    PR_DELETE(buf);
   2008  }
   2009 #if defined(XP_UNIX)
   2010  munmap((char*)small_file_addr, SMALL_FILE_SIZE);
   2011  munmap((char*)large_file_addr, LARGE_FILE_SIZE);
   2012 #endif
   2013  PR_Close(small_file_fd);
   2014  PR_Close(large_file_fd);
   2015  if ((PR_Delete(SMALL_FILE_NAME)) == PR_FAILURE) {
   2016    fprintf(stderr, "prsocket_test: failed to unlink file %s\n",
   2017            SMALL_FILE_NAME);
   2018    failed_already = 1;
   2019  }
   2020  if ((PR_Delete(LARGE_FILE_NAME)) == PR_FAILURE) {
   2021    fprintf(stderr, "prsocket_test: failed to unlink file %s\n",
   2022            LARGE_FILE_NAME);
   2023    failed_already = 1;
   2024  }
   2025  if ((PR_RmDir(TEST_DIR)) == PR_FAILURE) {
   2026    fprintf(stderr, "prsocket_test failed to rmdir %s: (%ld, %ld)\n", TEST_DIR,
   2027            PR_GetError(), PR_GetOSError());
   2028    failed_already = 1;
   2029  }
   2030 
   2031  printf("%-29s%s", "Socket_Misc_Test", ":");
   2032  printf("%2d Server %2d Clients\n", 1, num_transmitfile_clients);
   2033  printf("%30s Sizes of Transmitted Files  - %4d KB, %2d MB \n", ":",
   2034         SMALL_FILE_SIZE / 1024, LARGE_FILE_SIZE / (1024 * 1024));
   2035 
   2036  return rv;
   2037 }
   2038 /************************************************************************/
   2039 
   2040 /*
   2041 * Test Socket NSPR APIs
   2042 */
   2043 
   2044 int main(int argc, char** argv) {
   2045  /*
   2046   * -d           debug mode
   2047   */
   2048 
   2049  PLOptStatus os;
   2050  PLOptState* opt = PL_CreateOptState(argc, argv, "d");
   2051  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
   2052    if (PL_OPT_BAD == os) {
   2053      continue;
   2054    }
   2055    switch (opt->option) {
   2056      case 'd': /* debug mode */
   2057        _debug_on = 1;
   2058        break;
   2059      default:
   2060        break;
   2061    }
   2062  }
   2063  PL_DestroyOptState(opt);
   2064 
   2065  PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
   2066 
   2067  PR_SetConcurrency(4);
   2068 
   2069  emuSendFileIdentity = PR_GetUniqueIdentity("Emulated SendFile");
   2070  emuSendFileMethods = *PR_GetDefaultIOMethods();
   2071  emuSendFileMethods.transmitfile = emu_TransmitFile;
   2072  emuSendFileMethods.sendfile = emu_SendFile;
   2073 
   2074  /*
   2075   * run client-server test with TCP, Ipv4-Ipv4
   2076   */
   2077  printf("TCP Client/Server Test - IPv4/Ipv4\n");
   2078  if (TCP_Socket_Client_Server_Test() < 0) {
   2079    printf("TCP_Socket_Client_Server_Test failed\n");
   2080    goto done;
   2081  } else {
   2082    printf("TCP_Socket_Client_Server_Test Passed\n");
   2083  }
   2084  /*
   2085   * client-server test, Ipv6-Ipv4
   2086   */
   2087  client_domain = PR_AF_INET6;
   2088  printf("TCP Client/Server Test - IPv6/Ipv4\n");
   2089  if (TCP_Socket_Client_Server_Test() < 0) {
   2090    printf("TCP_Socket_Client_Server_Test failed\n");
   2091    goto done;
   2092  } else {
   2093    printf("TCP_Socket_Client_Server_Test Passed\n");
   2094  }
   2095  /*
   2096   * client-server test, Ipv4-Ipv6
   2097   */
   2098  client_domain = PR_AF_INET;
   2099  server_domain = PR_AF_INET6;
   2100  printf("TCP Client/Server Test - IPv4/Ipv6\n");
   2101  if (TCP_Socket_Client_Server_Test() < 0) {
   2102    printf("TCP_Socket_Client_Server_Test failed\n");
   2103    goto done;
   2104  } else {
   2105    printf("TCP_Socket_Client_Server_Test Passed\n");
   2106  }
   2107  /*
   2108   * client-server test, Ipv6-Ipv6
   2109   */
   2110  client_domain = PR_AF_INET6;
   2111  server_domain = PR_AF_INET6;
   2112  printf("TCP Client/Server Test - IPv6/Ipv6\n");
   2113  if (TCP_Socket_Client_Server_Test() < 0) {
   2114    printf("TCP_Socket_Client_Server_Test failed\n");
   2115    goto done;
   2116  } else {
   2117    printf("TCP_Socket_Client_Server_Test Passed\n");
   2118  }
   2119  test_cancelio = 0;
   2120 
   2121  /*
   2122   * Misc socket tests - including transmitfile, etc.
   2123   */
   2124 
   2125  /* File transmission test can not be done in Symbian OS because of
   2126   * large file's size and the incomplete mmap() implementation. */
   2127  /*
   2128  ** The 'transmit file' test does not run because
   2129  ** transmit file is not implemented in NSPR yet.
   2130  **
   2131  */
   2132  if (Socket_Misc_Test() < 0) {
   2133    printf("Socket_Misc_Test failed\n");
   2134    failed_already = 1;
   2135    goto done;
   2136  } else {
   2137    printf("Socket_Misc_Test passed\n");
   2138  }
   2139 
   2140  /*
   2141   * run client-server test with TCP again to test
   2142   * recycling used sockets from PR_TransmitFile().
   2143   */
   2144  if (TCP_Socket_Client_Server_Test() < 0) {
   2145    printf("TCP_Socket_Client_Server_Test failed\n");
   2146    goto done;
   2147  } else {
   2148    printf("TCP_Socket_Client_Server_Test Passed\n");
   2149  }
   2150 
   2151 done:
   2152  PR_Cleanup();
   2153  if (failed_already) {
   2154    return 1;
   2155  } else {
   2156    return 0;
   2157  }
   2158 }