home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / socket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  48.3 KB  |  1,635 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /***********************************************************************
  20. **
  21. ** Name: socket.c
  22. **
  23. ** Description: Test socket functionality.
  24. **
  25. ** Modification History:
  26. */
  27. #include "primpl.h"
  28.  
  29. #include "plgetopt.h"
  30.  
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <errno.h>
  34. #ifdef XP_UNIX
  35. #include <sys/mman.h>
  36. #endif
  37.  
  38. static int _debug_on = 0;
  39.  
  40. #ifdef XP_MAC
  41. #include "prlog.h"
  42. #include "prsem.h"
  43. int fprintf(FILE *stream, const char *fmt, ...)
  44. {
  45.     PR_LogPrint(fmt);
  46.     return 0;
  47. }
  48. #define printf PR_LogPrint
  49. extern void SetupMacPrintfLog(char *logFile);
  50. #else
  51. #include "obsolete/prsem.h"
  52. #endif
  53.  
  54. #ifdef XP_PC
  55. #define mode_t int
  56. #endif
  57.  
  58. #define DPRINTF(arg) if (_debug_on) printf arg
  59.  
  60. #ifdef XP_PC
  61. char *TEST_DIR = "C:\\tmp\\prdir";
  62. char *SMALL_FILE_NAME = "prsmallf";
  63. char *LARGE_FILE_NAME = "prlargef";
  64. #else
  65. char *TEST_DIR = "/tmp/prsocket_test_dir";
  66. char *SMALL_FILE_NAME = "/tmp/prsocket_test_dir/small_file";
  67. char *LARGE_FILE_NAME = "/tmp/prsocket_test_dir/large_file";
  68. #endif
  69. #define SMALL_FILE_SIZE        (8 * 1024)        /* 8 KB        */
  70. #define SMALL_FILE_HEADER_SIZE    (64)            /* 64 bytes    */
  71. #define LARGE_FILE_SIZE        (3 * 1024 * 1024)    /* 3 MB        */
  72.  
  73. #define    BUF_DATA_SIZE    (2 * 1024)
  74. #define TCP_MESG_SIZE    1024
  75. /*
  76.  * set UDP datagram size small enough that datagrams sent to a port on the
  77.  * local host will not be lost
  78.  */
  79. #define UDP_DGRAM_SIZE            128
  80. #define NUM_TCP_CLIENTS            10
  81. #define NUM_UDP_CLIENTS            10
  82.  
  83. #ifndef XP_MAC
  84. #define NUM_TRANSMITFILE_CLIENTS    4
  85. #else
  86. /* Mac can't handle more than 2* (3Mb) allocations for large file size buffers */
  87. #define NUM_TRANSMITFILE_CLIENTS    2
  88. #endif
  89.  
  90. #define NUM_TCP_CONNECTIONS_PER_CLIENT    5
  91. #define NUM_TCP_MESGS_PER_CONNECTION    10
  92. #define NUM_UDP_DATAGRAMS_PER_CLIENT    5
  93. #define TCP_SERVER_PORT            10000
  94. #define UDP_SERVER_PORT            TCP_SERVER_PORT
  95. #define SERVER_MAX_BIND_COUNT        100
  96.  
  97. static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS;
  98. static PRInt32 num_udp_clients = NUM_UDP_CLIENTS;
  99. static PRInt32 num_transmitfile_clients = NUM_TRANSMITFILE_CLIENTS;
  100. static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT;
  101. static PRInt32 tcp_mesg_size = TCP_MESG_SIZE;
  102. static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION;
  103. static PRInt32 num_udp_datagrams_per_client = NUM_UDP_DATAGRAMS_PER_CLIENT;
  104. static PRInt32 udp_datagram_size = UDP_DGRAM_SIZE;
  105.  
  106. static PRInt32 thread_count;
  107.  
  108. int failed_already=0;
  109. typedef struct buffer {
  110.     char    data[BUF_DATA_SIZE];
  111. } buffer;
  112.  
  113. PRNetAddr tcp_server_addr, udp_server_addr;
  114.  
  115. typedef struct Serve_Client_Param {
  116.     PRFileDesc *sockfd;    /* socket to read from/write to    */
  117.     PRInt32    datalen;    /* bytes of data transfered in each read/write */
  118. } Serve_Client_Param;
  119.  
  120. typedef struct Server_Param {
  121.     PRSemaphore *addr_sem;    /* sem to post on, after setting up the address */
  122.     PRMonitor *exit_mon;    /* monitor to signal on exit            */
  123.     PRInt32 *exit_counter;    /* counter to decrement, before exit        */
  124.     PRInt32    datalen;    /* bytes of data transfered in each read/write    */
  125. } Server_Param;
  126.  
  127.  
  128. typedef struct Client_Param {
  129.     PRNetAddr server_addr;
  130.     PRMonitor *exit_mon;    /* monitor to signal on exit */
  131.     PRInt32 *exit_counter;    /* counter to decrement, before exit */
  132.     PRInt32    datalen;
  133.     PRInt32    udp_connect;    /* if set clients connect udp sockets */
  134. } Client_Param;
  135.  
  136. /*
  137.  * readn
  138.  *    read data from sockfd into buf
  139.  */
  140. static PRInt32
  141. readn(PRFileDesc *sockfd, char *buf, int len)
  142. {
  143.     int rem;
  144.     int bytes;
  145.     int offset = 0;
  146.  
  147.     for (rem=len; rem; offset += bytes, rem -= bytes) {
  148.         DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n",
  149.             PR_GetCurrentThread(), rem));
  150.         bytes = PR_Recv(sockfd, buf + offset, rem, 0,
  151.             PR_INTERVAL_NO_TIMEOUT);
  152.         DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n",
  153.             PR_GetCurrentThread(), bytes));
  154.         if (bytes <= 0)
  155.             return -1;
  156.     }
  157.     return len;
  158. }
  159.  
  160. /*
  161.  * writen
  162.  *    write data from buf to sockfd
  163.  */
  164. static PRInt32
  165. writen(PRFileDesc *sockfd, char *buf, int len)
  166. {
  167.     int rem;
  168.     int bytes;
  169.     int offset = 0;
  170.  
  171.     for (rem=len; rem; offset += bytes, rem -= bytes) {
  172.         DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n",
  173.             PR_GetCurrentThread(), rem));
  174.         bytes = PR_Send(sockfd, buf + offset, rem, 0,
  175.             PR_INTERVAL_NO_TIMEOUT);
  176.         DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n",
  177.             PR_GetCurrentThread(), bytes));
  178.         if (bytes <= 0)
  179.             return -1;
  180.     }
  181.     return len;
  182. }
  183.  
  184. /*
  185.  * Serve_Client
  186.  *    Thread, started by the server, for serving a client connection.
  187.  *    Reads data from socket and writes it back, unmodified, and
  188.  *    closes the socket
  189.  */
  190. static void PR_CALLBACK
  191. Serve_Client(void *arg)
  192. {
  193.     Serve_Client_Param *scp = (Serve_Client_Param *) arg;
  194.     PRFileDesc *sockfd;
  195.     buffer *in_buf;
  196.     PRInt32 bytes, j;
  197.  
  198.     sockfd = scp->sockfd;
  199.     bytes = scp->datalen;
  200.     in_buf = PR_NEW(buffer);
  201.     if (in_buf == NULL) {
  202.         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
  203.         failed_already=1;
  204.         goto exit;
  205.     }
  206.  
  207.  
  208.     for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
  209.         /*
  210.          * Read data from client and send it back to the client unmodified
  211.          */
  212.         if (readn(sockfd, in_buf->data, bytes) < bytes) {
  213.             fprintf(stderr,"prsocket_test: ERROR - Serve_Client:readn\n");
  214.             failed_already=1;
  215.             goto exit;
  216.         }
  217.         /*
  218.          * shutdown reads, after the last read
  219.          */
  220.         if (j == num_tcp_mesgs_per_connection - 1)
  221.             if (PR_Shutdown(sockfd, PR_SHUTDOWN_RCV) < 0) {
  222.                 fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
  223.             }
  224.         DPRINTF(("Serve_Client [0x%lx]: inbuf[0] = 0x%lx\n",PR_GetCurrentThread(),
  225.             (*((int *) in_buf->data))));
  226.         if (writen(sockfd, in_buf->data, bytes) < bytes) {
  227.             fprintf(stderr,"prsocket_test: ERROR - Serve_Client:writen\n");
  228.             failed_already=1;
  229.             goto exit;
  230.         }
  231.     }
  232.     /*
  233.      * shutdown reads and writes
  234.      */
  235.     if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
  236.         fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
  237.         failed_already=1;
  238.     }
  239.  
  240. exit:
  241.     PR_Close(sockfd);
  242.     if (in_buf) {
  243.         PR_DELETE(in_buf);
  244.     }
  245. }
  246.  
  247. /*
  248.  * TCP Server
  249.  *    Server Thread
  250.  *    Bind an address to a socket and listen for incoming connections
  251.  *    Start a Serve_Client thread for each incoming connection.
  252.  */
  253. static void PR_CALLBACK
  254. TCP_Server(void *arg)
  255. {
  256.     PRThread *t;
  257.     Server_Param *sp = (Server_Param *) arg;
  258.     Serve_Client_Param *scp;
  259.     PRFileDesc *sockfd, *newsockfd;
  260.     PRNetAddr netaddr;
  261.     PRInt32 i;
  262.     /*
  263.      * Create a tcp socket
  264.      */
  265.     if ((sockfd = PR_NewTCPSocket()) == NULL) {
  266.         fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
  267.         goto exit;
  268.     }
  269.     memset(&netaddr, 0 , sizeof(netaddr));
  270.     netaddr.inet.family = AF_INET;
  271.     netaddr.inet.port = PR_htons(TCP_SERVER_PORT);
  272.     netaddr.inet.ip = PR_htonl(INADDR_ANY);
  273.     /*
  274.      * try a few times to bind server's address, if addresses are in
  275.      * use
  276.      */
  277.     i = 0;
  278.     while (PR_Bind(sockfd, &netaddr) < 0) {
  279.         if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
  280.             netaddr.inet.port += 2;
  281.             if (i++ < SERVER_MAX_BIND_COUNT)
  282.                 continue;
  283.         }
  284.         fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
  285.         perror("PR_Bind");
  286.         failed_already=1;
  287.         goto exit;
  288.     }
  289.  
  290.     if (PR_Listen(sockfd, 32) < 0) {
  291.         fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n");
  292.         failed_already=1;
  293.         goto exit;
  294.     }
  295.  
  296.     if (PR_GetSockName(sockfd, &netaddr) < 0) {
  297.         fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
  298.         failed_already=1;
  299.         goto exit;
  300.     }
  301.  
  302.     DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
  303.         netaddr.inet.ip, netaddr.inet.port));
  304.     tcp_server_addr.inet.family = netaddr.inet.family;
  305.     tcp_server_addr.inet.port = netaddr.inet.port;
  306.     tcp_server_addr.inet.ip = netaddr.inet.ip;
  307.  
  308.     /*
  309.      * Wake up parent thread because server address is bound and made
  310.      * available in the global variable 'tcp_server_addr'
  311.      */
  312.     PR_PostSem(sp->addr_sem);
  313.  
  314.     for (i = 0; i < (num_tcp_clients * num_tcp_connections_per_client); i++) {
  315.  
  316.         if ((newsockfd = PR_Accept(sockfd, &netaddr,
  317.             PR_INTERVAL_NO_TIMEOUT)) == NULL) {
  318.             fprintf(stderr,"prsocket_test: ERROR - PR_Accept failed\n");
  319.             goto exit;
  320.         }
  321.         scp = PR_NEW(Serve_Client_Param);
  322.         if (scp == NULL) {
  323.             fprintf(stderr,"prsocket_test: PR_NEW failed\n");
  324.             goto exit;
  325.         }
  326.  
  327.         /*
  328.          * Start a Serve_Client thread for each incoming connection
  329.          */
  330.         scp->sockfd = newsockfd;
  331.         scp->datalen = sp->datalen;
  332.  
  333.         t = PR_CreateThread(PR_USER_THREAD,
  334.             Serve_Client, (void *)scp, 
  335.             PR_PRIORITY_NORMAL,
  336.             PR_LOCAL_THREAD,
  337.             PR_UNJOINABLE_THREAD,
  338.             0);
  339.         if (t == NULL) {
  340.             fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
  341.             failed_already=1;
  342.             goto exit;
  343.         }
  344.         DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", t));
  345.     }
  346.  
  347. exit:
  348.     if (sockfd) {
  349.         PR_Close(sockfd);
  350.     }
  351.  
  352.     /*
  353.      * Decrement exit_counter and notify parent thread
  354.      */
  355.  
  356.     PR_EnterMonitor(sp->exit_mon);
  357.     --(*sp->exit_counter);
  358.     PR_Notify(sp->exit_mon);
  359.     PR_ExitMonitor(sp->exit_mon);
  360.     DPRINTF(("TCP_Server [0x%lx] exiting\n", PR_GetCurrentThread()));
  361. }
  362.  
  363. /*
  364.  * UDP Server
  365.  *    Server Thread
  366.  *    Bind an address to a socket, read data from clients and send data
  367.  *    back to clients
  368.  */
  369. static void PR_CALLBACK
  370. UDP_Server(void *arg)
  371. {
  372.     Server_Param *sp = (Server_Param *) arg;
  373.     PRFileDesc *sockfd;
  374.     buffer *in_buf;
  375.     PRNetAddr netaddr;
  376.     PRInt32 bytes, i, rv;
  377.  
  378.  
  379.     bytes = sp->datalen;
  380.     /*
  381.      * Create a udp socket
  382.      */
  383.     if ((sockfd = PR_NewUDPSocket()) == NULL) {
  384.         fprintf(stderr,"prsocket_test: PR_NewUDPSocket failed\n");
  385.         failed_already=1;
  386.         return;
  387.     }
  388.     memset(&netaddr, 0 , sizeof(netaddr));
  389.     netaddr.inet.family = AF_INET;
  390.     netaddr.inet.port = PR_htons(UDP_SERVER_PORT);
  391.     netaddr.inet.ip = PR_htonl(INADDR_ANY);
  392.     /*
  393.      * try a few times to bind server's address, if addresses are in
  394.      * use
  395.      */
  396.     i = 0;
  397.     while (PR_Bind(sockfd, &netaddr) < 0) {
  398.         if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
  399.             netaddr.inet.port += 2;
  400.             if (i++ < SERVER_MAX_BIND_COUNT)
  401.                 continue;
  402.         }
  403.         fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
  404.         perror("PR_Bind");
  405.         failed_already=1;
  406.         return;
  407.     }
  408.  
  409.     if (PR_GetSockName(sockfd, &netaddr) < 0) {
  410.         fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
  411.         failed_already=1;
  412.         return;
  413.     }
  414.     if (netaddr.inet.port != PR_htons(UDP_SERVER_PORT)) {
  415.         fprintf(stderr,"prsocket_test: ERROR - tried to bind to UDP "
  416.             "port %hu, but was bound to port %hu\n",
  417.             UDP_SERVER_PORT, PR_ntohs(netaddr.inet.port));
  418.         failed_already=1;
  419.         return;
  420.     }
  421.  
  422.     DPRINTF(("PR_Bind: UDP Server netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
  423.         netaddr.inet.ip, netaddr.inet.port));
  424.     udp_server_addr = netaddr;
  425.  
  426.     /*
  427.      * We can't use the IP address returned by PR_GetSockName in
  428.          * netaddr.inet.ip because netaddr.inet.ip is returned
  429.          * as 0 (= INADDR_ANY).
  430.      */
  431.  
  432.     udp_server_addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
  433.  
  434.     /*
  435.      * Wake up parent thread because server address is bound and made
  436.      * available in the global variable 'udp_server_addr'
  437.      */
  438.     PR_PostSem(sp->addr_sem);
  439.  
  440.     bytes = sp->datalen;
  441.     in_buf = PR_NEW(buffer);
  442.     if (in_buf == NULL) {
  443.         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
  444.         failed_already=1;
  445.         return;
  446.     }
  447.     /*
  448.      * Receive datagrams from clients and send them back, unmodified, to the
  449.      * clients
  450.      */
  451.     memset(&netaddr, 0 , sizeof(netaddr));
  452.     for (i = 0; i < (num_udp_clients * num_udp_datagrams_per_client); i++) {
  453.         DPRINTF(("UDP_Server: calling PR_RecvFrom client  - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n",
  454.             netaddr.inet.ip, netaddr.inet.port, rv, in_buf->data,
  455.             in_buf->data[0]));
  456.  
  457.         rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr,
  458.             PR_INTERVAL_NO_TIMEOUT);
  459.         DPRINTF(("UDP_Server: PR_RecvFrom client  - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n",
  460.             netaddr.inet.ip, netaddr.inet.port, rv, in_buf->data,
  461.             in_buf->data[0]));
  462.         if (rv != bytes) {
  463.             return;
  464.         }
  465.         rv = PR_SendTo(sockfd, in_buf->data, bytes, 0, &netaddr,
  466.             PR_INTERVAL_NO_TIMEOUT);
  467.         if (rv != bytes) {
  468.             return;
  469.         }
  470.     }
  471.  
  472.     PR_DELETE(in_buf);
  473.  
  474.     /*
  475.      * Decrement exit_counter and notify parent thread
  476.      */
  477.     PR_EnterMonitor(sp->exit_mon);
  478.     --(*sp->exit_counter);
  479.     PR_Notify(sp->exit_mon);
  480.     PR_ExitMonitor(sp->exit_mon);
  481.     DPRINTF(("UDP_Server [0x%x] exiting\n", PR_GetCurrentThread()));
  482. }
  483.  
  484. /*
  485.  * TCP_Client
  486.  *    Client Thread
  487.  *    Connect to the server at the address specified in the argument.
  488.  *    Fill in a buffer, write data to server, read it back and check
  489.  *    for data corruption.
  490.  *    Close the socket for server connection
  491.  */
  492. static void PR_CALLBACK
  493. TCP_Client(void *arg)
  494. {
  495.     Client_Param *cp = (Client_Param *) arg;
  496.     PRFileDesc *sockfd;
  497.     buffer *in_buf, *out_buf;
  498.     union PRNetAddr netaddr;
  499.     PRInt32 bytes, i, j;
  500.  
  501.  
  502.     bytes = cp->datalen;
  503.     out_buf = PR_NEW(buffer);
  504.     if (out_buf == NULL) {
  505.         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
  506.         failed_already=1;
  507.         return;
  508.     }
  509.     in_buf = PR_NEW(buffer);
  510.     if (in_buf == NULL) {
  511.         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
  512.         failed_already=1;
  513.         return;
  514.     }
  515.     netaddr.inet.family = cp->server_addr.inet.family;
  516.     netaddr.inet.port = cp->server_addr.inet.port;
  517.     netaddr.inet.ip = cp->server_addr.inet.ip;
  518.  
  519.     for (i = 0; i < num_tcp_connections_per_client; i++) {
  520.         if ((sockfd = PR_NewTCPSocket()) == NULL) {
  521.             fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
  522.             failed_already=1;
  523.             return;
  524.         }
  525.  
  526.         if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){
  527.             fprintf(stderr,"prsocket_test: PR_Connect failed\n");
  528.             failed_already=1;
  529.             return;
  530.         }
  531.         for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
  532.             /*
  533.              * fill in random data
  534.              */
  535.             memset(out_buf->data, ((PRInt32) (&netaddr)) + i + j, bytes);
  536.             /*
  537.              * write to server
  538.              */
  539.             if (writen(sockfd, out_buf->data, bytes) < bytes) {
  540.                 fprintf(stderr,"prsocket_test: ERROR - TCP_Client:writen\n");
  541.                 failed_already=1;
  542.                 return;
  543.             }
  544.             DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
  545.                 PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data))));
  546.             if (readn(sockfd, in_buf->data, bytes) < bytes) {
  547.                 fprintf(stderr,"prsocket_test: ERROR - TCP_Client:readn\n");
  548.                 failed_already=1;
  549.                 return;
  550.             }
  551.             /*
  552.              * verify the data read
  553.              */
  554.             if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
  555.                 fprintf(stderr,"prsocket_test: ERROR - data corruption\n");
  556.                 failed_already=1;
  557.                 return;
  558.             }
  559.         }
  560.         /*
  561.          * shutdown reads and writes
  562.          */
  563.         if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
  564.             fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
  565.             failed_already=1;
  566.         }
  567.         PR_Close(sockfd);
  568.     }
  569.  
  570.     PR_DELETE(out_buf);
  571.     PR_DELETE(in_buf);
  572.  
  573.     /*
  574.      * Decrement exit_counter and notify parent thread
  575.      */
  576.  
  577.     PR_EnterMonitor(cp->exit_mon);
  578.     --(*cp->exit_counter);
  579.     PR_Notify(cp->exit_mon);
  580.     PR_ExitMonitor(cp->exit_mon);
  581.     DPRINTF(("TCP_Client [0x%x] exiting\n", PR_GetCurrentThread()));
  582. }
  583.  
  584. /*
  585.  * UDP_Client
  586.  *    Client Thread
  587.  *    Create a socket and bind an address 
  588.  *    Communicate with the server at the address specified in the argument.
  589.  *    Fill in a buffer, write data to server, read it back and check
  590.  *    for data corruption.
  591.  *    Close the socket
  592.  */
  593. static void PR_CALLBACK
  594. UDP_Client(void *arg)
  595. {
  596.     Client_Param *cp = (Client_Param *) arg;
  597.     PRFileDesc *sockfd;
  598.     buffer *in_buf, *out_buf;
  599.     union PRNetAddr netaddr;
  600.     PRInt32 bytes, i, rv;
  601.  
  602.  
  603.     bytes = cp->datalen;
  604.     out_buf = PR_NEW(buffer);
  605.     if (out_buf == NULL) {
  606.         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
  607.         failed_already=1;
  608.         return;
  609.     }
  610.     in_buf = PR_NEW(buffer);
  611.     if (in_buf == NULL) {
  612.         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
  613.         failed_already=1;
  614.         return;
  615.     }
  616.     if ((sockfd = PR_NewUDPSocket()) == NULL) {
  617.         fprintf(stderr,"prsocket_test: PR_NewUDPSocket failed\n");
  618.         failed_already=1;
  619.         return;
  620.     }
  621.  
  622.     /*
  623.      * bind an address for the client, let the system chose the port
  624.      * number
  625.      */
  626.     memset(&netaddr, 0 , sizeof(netaddr));
  627.     netaddr.inet.family = AF_INET;
  628.     netaddr.inet.ip = PR_htonl(INADDR_ANY);
  629.     netaddr.inet.port = PR_htons(0);
  630.     if (PR_Bind(sockfd, &netaddr) < 0) {
  631.         fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
  632.         perror("PR_Bind");
  633.         return;
  634.     }
  635.  
  636.     if (PR_GetSockName(sockfd, &netaddr) < 0) {
  637.         fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
  638.         failed_already=1;
  639.         return;
  640.     }
  641.  
  642.     DPRINTF(("PR_Bind: UDP Client netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
  643.         netaddr.inet.ip, netaddr.inet.port));
  644.  
  645.     netaddr.inet.family = cp->server_addr.inet.family;
  646.     netaddr.inet.port = cp->server_addr.inet.port;
  647.     netaddr.inet.ip = cp->server_addr.inet.ip;
  648.  
  649.     if (cp->udp_connect) {
  650.         if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){
  651.             fprintf(stderr,"prsocket_test: PR_Connect failed\n");
  652.             failed_already=1;
  653.             return;
  654.         }
  655.     }
  656.  
  657.     for (i = 0; i < num_udp_datagrams_per_client; i++) {
  658.         /*
  659.          * fill in random data
  660.          */
  661.         DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx bytes = 0x%lx\n",
  662.             PR_GetCurrentThread(), out_buf->data, bytes));
  663.         memset(out_buf->data, ((PRInt32) (&netaddr)) + i, bytes);
  664.         /*
  665.          * write to server
  666.          */
  667.         if (cp->udp_connect)
  668.             rv = PR_Send(sockfd, out_buf->data, bytes, 0,
  669.                 PR_INTERVAL_NO_TIMEOUT);
  670.         else
  671.             rv = PR_SendTo(sockfd, out_buf->data, bytes, 0, &netaddr,
  672.                 PR_INTERVAL_NO_TIMEOUT);
  673.         if (rv != bytes) {
  674.             return;
  675.         }
  676.         DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
  677.             PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data))));
  678.         if (cp->udp_connect)
  679.             rv = PR_Recv(sockfd, in_buf->data, bytes, 0,
  680.                 PR_INTERVAL_NO_TIMEOUT);
  681.         else
  682.             rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr,
  683.                 PR_INTERVAL_NO_TIMEOUT);
  684.         if (rv != bytes) {
  685.             return;
  686.         }
  687.         DPRINTF(("UDP_Client [0x%lx]: in_buf = 0x%lx in_buf[0] = 0x%lx\n",
  688.             PR_GetCurrentThread(), in_buf, (*((int *) in_buf->data))));
  689.         /*
  690.          * verify the data read
  691.          */
  692.         if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
  693.             fprintf(stderr,"prsocket_test: ERROR - UDP data corruption\n");
  694.             failed_already=1;
  695.             return;
  696.         }
  697.     }
  698.     PR_Close(sockfd);
  699.  
  700.     PR_DELETE(in_buf);
  701.     PR_DELETE(out_buf);
  702.  
  703.     /*
  704.      * Decrement exit_counter and notify parent thread
  705.      */
  706.  
  707.     PR_EnterMonitor(cp->exit_mon);
  708.     --(*cp->exit_counter);
  709.     PR_Notify(cp->exit_mon);
  710.     PR_ExitMonitor(cp->exit_mon);
  711.     PR_DELETE(cp);
  712.     DPRINTF(("UDP_Client [0x%x] exiting\n", PR_GetCurrentThread()));
  713. }
  714.  
  715. /*
  716.  * TCP_Socket_Client_Server_Test    - concurrent server test
  717.  *    
  718.  *    One server and several clients are started
  719.  *    Each client connects to the server and sends a chunk of data
  720.  *    For each connection, server starts another thread to read the data
  721.  *    from the client and send it back to the client, unmodified.
  722.  *    Each client checks that data received from server is same as the
  723.  *    data it sent to the server.
  724.  *
  725.  */
  726.  
  727. static PRInt32
  728. TCP_Socket_Client_Server_Test(void)
  729. {
  730.     int i;
  731.     PRThread *t;
  732.     PRThreadScope scope;
  733.     PRSemaphore *server_sem;
  734.     Server_Param *sparamp;
  735.     Client_Param *cparamp;
  736.     PRMonitor *mon2;
  737.     PRInt32    datalen;
  738.  
  739.  
  740.     datalen = tcp_mesg_size;
  741.     thread_count = 0;
  742.     /*
  743.      * start the server thread
  744.      */
  745.     sparamp = PR_NEW(Server_Param);
  746.     if (sparamp == NULL) {
  747.         fprintf(stderr,"prsocket_test: PR_NEW failed\n");
  748.         failed_already=1;
  749.         return -1;
  750.     }
  751.     server_sem = PR_NewSem(0);
  752.     if (server_sem == NULL) {
  753.         fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
  754.         failed_already=1;
  755.         return -1;
  756.     }
  757.     mon2 = PR_NewMonitor();
  758.     if (mon2 == NULL) {
  759.         fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
  760.         failed_already=1;
  761.         return -1;
  762.     }
  763.     PR_EnterMonitor(mon2);
  764.  
  765.     sparamp->addr_sem = server_sem;
  766.     sparamp->exit_mon = mon2;
  767.     sparamp->exit_counter = &thread_count;
  768.     sparamp->datalen = datalen;
  769.     t = PR_CreateThread(PR_USER_THREAD,
  770.         TCP_Server, (void *)sparamp, 
  771.         PR_PRIORITY_NORMAL,
  772.         PR_LOCAL_THREAD,
  773.         PR_UNJOINABLE_THREAD,
  774.         0);
  775.     if (t == NULL) {
  776.         fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
  777.         failed_already=1;
  778.         return -1;
  779.     }
  780.     DPRINTF(("Created TCP server = 0x%lx\n", t));
  781.     thread_count++;
  782.  
  783.     /*
  784.      * wait till the server address is setup
  785.      */
  786.     PR_WaitSem(server_sem);
  787.  
  788.     /*
  789.      * Now start a bunch of client threads
  790.      */
  791.  
  792.     cparamp = PR_NEW(Client_Param);
  793.     if (cparamp == NULL) {
  794.         fprintf(stderr,"prsocket_test: PR_NEW failed\n");
  795.         failed_already=1;
  796.         return -1;
  797.     }
  798.     cparamp->server_addr = tcp_server_addr;
  799.     cparamp->server_addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
  800.     cparamp->exit_mon = mon2;
  801.     cparamp->exit_counter = &thread_count;
  802.     cparamp->datalen = datalen;
  803.     for (i = 0; i < num_tcp_clients; i++) {
  804.         /*
  805.          * Every other thread is a LOCAL/GLOBAL thread
  806.          */
  807.         if (i & 1)
  808.             scope = PR_LOCAL_THREAD;
  809.         else
  810.             scope = PR_GLOBAL_THREAD;
  811.         t = PR_CreateThread(PR_USER_THREAD,
  812.             TCP_Client, (void *) cparamp,
  813.             PR_PRIORITY_NORMAL,
  814.             scope,
  815.             PR_UNJOINABLE_THREAD,
  816.             0);
  817.         if (t == NULL) {
  818.             fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
  819.             failed_already=1;
  820.             return -1;
  821.         }
  822.         DPRINTF(("Created TCP client = 0x%lx\n", t));
  823.         thread_count++;
  824.     }
  825.     /* Wait for server and client threads to exit */
  826.     while (thread_count) {
  827.         PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
  828.         DPRINTF(("TCP Server - thread_count  = %d\n", thread_count));
  829.     }
  830.     PR_ExitMonitor(mon2);
  831.     printf("%30s","TCP_Socket_Client_Server_Test:");
  832.     printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l,
  833.         num_tcp_clients, num_tcp_connections_per_client);
  834.     printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":",
  835.         num_tcp_mesgs_per_connection, tcp_mesg_size);
  836.  
  837.     return 0;
  838. }
  839.  
  840. /*
  841.  * UDP_Socket_Client_Server_Test    - iterative server test
  842.  *    
  843.  *    One server and several clients are started
  844.  *    Each client connects to the server and sends a chunk of data
  845.  *    For each connection, server starts another thread to read the data
  846.  *    from the client and send it back to the client, unmodified.
  847.  *    Each client checks that data received from server is same as the
  848.  *    data it sent to the server.
  849.  *
  850.  */
  851.  
  852. static PRInt32
  853. UDP_Socket_Client_Server_Test(void)
  854. {
  855.     int i;
  856.     PRThread *t;
  857.     PRSemaphore *server_sem;
  858.     Server_Param *sparamp;
  859.     Client_Param *cparamp;
  860.     PRMonitor *mon2;
  861.     PRInt32    datalen;
  862.     PRInt32    udp_connect = 1;
  863.  
  864.  
  865.     datalen = udp_datagram_size;
  866.     thread_count = 0;
  867.     /*
  868.      * start the server thread
  869.      */
  870.     sparamp = PR_NEW(Server_Param);
  871.     if (sparamp == NULL) {
  872.         fprintf(stderr,"prsocket_test: PR_NEW failed\n");
  873.         failed_already=1;
  874.         return -1;
  875.     }
  876.     server_sem = PR_NewSem(0);
  877.     if (server_sem == NULL) {
  878.         fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
  879.         failed_already=1;
  880.         return -1;
  881.     }
  882.     mon2 = PR_NewMonitor();
  883.     if (mon2 == NULL) {
  884.         fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
  885.         failed_already=1;
  886.         return -1;
  887.     }
  888.     PR_EnterMonitor(mon2);
  889.  
  890.     sparamp->addr_sem = server_sem;
  891.     sparamp->exit_mon = mon2;
  892.     sparamp->exit_counter = &thread_count;
  893.     sparamp->datalen = datalen;
  894.     DPRINTF(("Creating UDP server"));
  895.     t = PR_CreateThread(PR_USER_THREAD,
  896.         UDP_Server, (void *)sparamp, 
  897.         PR_PRIORITY_NORMAL,
  898.         PR_LOCAL_THREAD,
  899.         PR_UNJOINABLE_THREAD,
  900.         0);
  901.     if (t == NULL) {
  902.         fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
  903.         failed_already=1;
  904.         return -1;
  905.     }
  906.     thread_count++;
  907.  
  908.     /*
  909.      * wait till the server address is setup
  910.      */
  911.     PR_WaitSem(server_sem);
  912.  
  913.     /*
  914.      * Now start a bunch of client threads
  915.      */
  916.  
  917.     for (i = 0; i < num_udp_clients; i++) {
  918.         cparamp = PR_NEW(Client_Param);
  919.         if (cparamp == NULL) {
  920.             fprintf(stderr,"prsocket_test: PR_NEW failed\n");
  921.             failed_already=1;
  922.             return -1;
  923.         }
  924.         cparamp->server_addr = udp_server_addr;
  925.         cparamp->exit_mon = mon2;
  926.         cparamp->exit_counter = &thread_count;
  927.         cparamp->datalen = datalen;
  928.         /*
  929.          * Cause every other client thread to connect udp sockets
  930.          */
  931. #ifndef XP_MAC
  932.         cparamp->udp_connect = udp_connect;
  933. #else
  934.         /* No support for UDP connects on Mac */
  935.         cparamp->udp_connect = 0;
  936. #endif
  937.         if (udp_connect)
  938.             udp_connect = 0;
  939.         else
  940.             udp_connect = 1;
  941.         DPRINTF(("Creating UDP client %d\n", i));
  942.         t = PR_CreateThread(PR_USER_THREAD,
  943.             UDP_Client, (void *) cparamp,
  944.             PR_PRIORITY_NORMAL,
  945.             PR_LOCAL_THREAD,
  946.             PR_UNJOINABLE_THREAD,
  947.             0);
  948.         if (t == NULL) {
  949.             fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
  950.             failed_already=1;
  951.             return -1;
  952.         }
  953.         thread_count++;
  954.     }
  955.     /* Wait for server and client threads to exit */
  956.     while (thread_count) {
  957.         PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
  958.         DPRINTF(("UDP Server - thread_count  = %d\n", thread_count));
  959.     }
  960.     PR_ExitMonitor(mon2);
  961.     printf("%30s","UDP_Socket_Client_Server_Test: ");
  962.     printf("%2ld Server %2ld Clients\n",1l, num_udp_clients);
  963.     printf("%30s %2ld datagrams_per_client %4ld bytes_per_datagram\n",":",
  964.         num_udp_datagrams_per_client, udp_datagram_size);
  965.  
  966.     return 0;
  967. }
  968.  
  969. static PRFileDesc *small_file_fd, *large_file_fd;
  970. static void *small_file_addr, *small_file_header, *large_file_addr;
  971. /*
  972.  * TransmitFile_Client
  973.  *    Client Thread
  974.  */
  975. static void
  976. TransmitFile_Client(void *arg)
  977. {
  978.     PRFileDesc *sockfd;
  979.     union PRNetAddr netaddr;
  980.     char *small_buf, *large_buf;
  981.     Client_Param *cp = (Client_Param *) arg;
  982.  
  983.     small_buf = (char*)PR_Malloc(SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE);
  984.     if (small_buf == NULL) {
  985.         fprintf(stderr,"prsocket_test: failed to alloc buffer\n");
  986.         failed_already=1;
  987.         return;
  988.     }
  989.     large_buf = (char*)PR_Malloc(LARGE_FILE_SIZE);
  990.     if (large_buf == NULL) {
  991.         fprintf(stderr,"prsocket_test: failed to alloc buffer\n");
  992.         failed_already=1;
  993.         return;
  994.     }
  995.     netaddr.inet.family = cp->server_addr.inet.family;
  996.     netaddr.inet.port = cp->server_addr.inet.port;
  997.     netaddr.inet.ip = cp->server_addr.inet.ip;
  998.  
  999.     if ((sockfd = PR_NewTCPSocket()) == NULL) {
  1000.         fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
  1001.         failed_already=1;
  1002.         return;
  1003.     }
  1004.  
  1005.     if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){
  1006.         fprintf(stderr,"prsocket_test: PR_Connect failed\n");
  1007.         failed_already=1;
  1008.         return;
  1009.     }
  1010.     /*
  1011.      * read the small file and verify the data
  1012.      */
  1013.     if (readn(sockfd, small_buf, SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)
  1014.         != (SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)) {
  1015.         fprintf(stderr,
  1016.             "prsocket_test: TransmitFile_Client failed to receive file\n");
  1017.         failed_already=1;
  1018.         return;
  1019.     }
  1020. #ifdef XP_UNIX
  1021.     if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){
  1022.         fprintf(stderr,
  1023.             "prsocket_test: TransmitFile_Client ERROR - small file header data corruption\n");
  1024.         failed_already=1;
  1025.         return;
  1026.     }
  1027.     if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE,
  1028.         SMALL_FILE_SIZE) != 0) {
  1029.         fprintf(stderr,
  1030.             "prsocket_test: TransmitFile_Client ERROR - small file data corruption\n");
  1031.         failed_already=1;
  1032.         return;
  1033.     }
  1034. #endif
  1035.     /*
  1036.      * read the large file and verify the data
  1037.      */
  1038.     if (readn(sockfd, large_buf, LARGE_FILE_SIZE) != LARGE_FILE_SIZE) {
  1039.         fprintf(stderr,
  1040.             "prsocket_test: TransmitFile_Client failed to receive file\n");
  1041.         failed_already=1;
  1042.         return;
  1043.     }
  1044. #ifdef XP_UNIX
  1045.     if (memcmp(large_file_addr, large_buf, LARGE_FILE_SIZE) != 0) {
  1046.         fprintf(stderr,
  1047.             "prsocket_test: TransmitFile_Client ERROR - large file data corruption\n");
  1048.         failed_already=1;
  1049.         return;
  1050.     }
  1051. #endif
  1052.     PR_DELETE(small_buf);
  1053.     PR_DELETE(large_buf);
  1054.     PR_Close(sockfd);
  1055.  
  1056.     /*
  1057.      * Decrement exit_counter and notify parent thread
  1058.      */
  1059.  
  1060.     PR_EnterMonitor(cp->exit_mon);
  1061.     --(*cp->exit_counter);
  1062.     PR_Notify(cp->exit_mon);
  1063.     PR_ExitMonitor(cp->exit_mon);
  1064.     DPRINTF(("TransmitFile_Client [0x%lx] exiting\n", PR_GetCurrentThread()));
  1065. }
  1066.  
  1067. /*
  1068.  * Serve_TransmitFile_Client
  1069.  *    Thread, started by the server, for serving a client connection.
  1070.  *    Trasmits a small file, with a header, and a large file, without
  1071.  *    a header
  1072.  */
  1073. static void
  1074. Serve_TransmitFile_Client(void *arg)
  1075. {
  1076.     Serve_Client_Param *scp = (Serve_Client_Param *) arg;
  1077.     PRFileDesc *sockfd;
  1078.     PRInt32 bytes;
  1079.     PRFileDesc *local_small_file_fd=NULL;
  1080.     PRFileDesc *local_large_file_fd=NULL;
  1081.  
  1082.     sockfd = scp->sockfd;
  1083.     local_small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDONLY,0);
  1084.  
  1085.     if (local_small_file_fd == NULL) {
  1086.         fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n",
  1087.             SMALL_FILE_NAME);
  1088.         failed_already=1;
  1089.         goto done;
  1090.     }
  1091.     local_large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDONLY,0);
  1092.  
  1093.     if (local_large_file_fd == NULL) {
  1094.         fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n",
  1095.             LARGE_FILE_NAME);
  1096.         failed_already=1;
  1097.         goto done;
  1098.     }
  1099.     bytes = PR_TransmitFile(sockfd, local_small_file_fd, small_file_header,
  1100.         SMALL_FILE_HEADER_SIZE, PR_TRANSMITFILE_KEEP_OPEN,
  1101.         PR_INTERVAL_NO_TIMEOUT);
  1102.     if (bytes != (SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE)) {
  1103.         fprintf(stderr,
  1104.             "prsocet_test: PR_TransmitFile failed: (%ld, %ld)\n",
  1105.             PR_GetError(), PR_GetOSError());
  1106.         failed_already=1;
  1107.     }
  1108.     bytes = PR_TransmitFile(sockfd, local_large_file_fd, NULL, 0,
  1109.         PR_TRANSMITFILE_CLOSE_SOCKET, PR_INTERVAL_NO_TIMEOUT);
  1110.     if (bytes != LARGE_FILE_SIZE) {
  1111.         fprintf(stderr,
  1112.             "prsocket_test: PR_TransmitFile failed: (%ld, %ld)\n",
  1113.             PR_GetError(), PR_GetOSError());
  1114.         failed_already=1;
  1115.     }
  1116. done:
  1117.     if (local_small_file_fd != NULL)
  1118.         PR_Close(local_small_file_fd);
  1119.     if (local_large_file_fd != NULL)
  1120.         PR_Close(local_large_file_fd);
  1121. }
  1122.  
  1123. /*
  1124.  * TransmitFile Server
  1125.  *    Server Thread
  1126.  *    Bind an address to a socket and listen for incoming connections
  1127.  *    Create worker threads to service clients
  1128.  */
  1129. static void
  1130. TransmitFile_Server(void *arg)
  1131. {
  1132.     PRThread **t = NULL;  /* an array of PRThread pointers */
  1133.     Server_Param *sp = (Server_Param *) arg;
  1134.     Serve_Client_Param *scp;
  1135.     PRFileDesc *sockfd = NULL, *newsockfd;
  1136.     PRNetAddr netaddr;
  1137.     PRInt32 i;
  1138.     PRThreadScope scope;
  1139.  
  1140.     t = (PRThread**)PR_MALLOC(num_transmitfile_clients * sizeof(PRThread *));
  1141.     if (t == NULL) {
  1142.         fprintf(stderr, "prsocket_test: run out of memory\n");
  1143.         failed_already=1;
  1144.         goto exit;
  1145.     }
  1146.     /*
  1147.      * Create a tcp socket
  1148.      */
  1149.     if ((sockfd = PR_NewTCPSocket()) == NULL) {
  1150.         fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
  1151.         failed_already=1;
  1152.         goto exit;
  1153.     }
  1154.     memset(&netaddr, 0 , sizeof(netaddr));
  1155.     netaddr.inet.family = AF_INET;
  1156.     netaddr.inet.port = PR_htons(TCP_SERVER_PORT);
  1157.     netaddr.inet.ip = PR_htonl(INADDR_ANY);
  1158.     /*
  1159.      * try a few times to bind server's address, if addresses are in
  1160.      * use
  1161.      */
  1162.     i = 0;
  1163.     while (PR_Bind(sockfd, &netaddr) < 0) {
  1164.         if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
  1165.             netaddr.inet.port += 2;
  1166.             if (i++ < SERVER_MAX_BIND_COUNT)
  1167.                 continue;
  1168.         }
  1169.         fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
  1170.         failed_already=1;
  1171.         perror("PR_Bind");
  1172.         goto exit;
  1173.     }
  1174.  
  1175.     if (PR_Listen(sockfd, 32) < 0) {
  1176.         fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n");
  1177.         failed_already=1;
  1178.         goto exit;
  1179.     }
  1180.  
  1181.     if (PR_GetSockName(sockfd, &netaddr) < 0) {
  1182.         fprintf(stderr,
  1183.             "prsocket_test: ERROR - PR_GetSockName failed\n");
  1184.         failed_already=1;
  1185.         goto exit;
  1186.     }
  1187.  
  1188.     DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
  1189.         netaddr.inet.ip, netaddr.inet.port));
  1190.     tcp_server_addr.inet.family = netaddr.inet.family;
  1191.     tcp_server_addr.inet.port = netaddr.inet.port;
  1192.     tcp_server_addr.inet.ip = netaddr.inet.ip;
  1193.  
  1194.     /*
  1195.      * Wake up parent thread because server address is bound and made
  1196.      * available in the global variable 'tcp_server_addr'
  1197.      */
  1198.     PR_PostSem(sp->addr_sem);
  1199.  
  1200.     for (i = 0; i < num_transmitfile_clients ; i++) {
  1201.  
  1202.         if ((newsockfd = PR_Accept(sockfd, &netaddr,
  1203.             PR_INTERVAL_NO_TIMEOUT)) == NULL) {
  1204.             fprintf(stderr,
  1205.                 "prsocket_test: ERROR - PR_Accept failed\n");
  1206.             failed_already=1;
  1207.             goto exit;
  1208.         }
  1209.         scp = PR_NEW(Serve_Client_Param);
  1210.         if (scp == NULL) {
  1211.             fprintf(stderr,"prsocket_test: PR_NEW failed\n");
  1212.             failed_already=1;
  1213.             goto exit;
  1214.         }
  1215.  
  1216.         /*
  1217.          * Start a Serve_Client thread for each incoming connection
  1218.          */
  1219.         scp->sockfd = newsockfd;
  1220.         scp->datalen = sp->datalen;
  1221.  
  1222.         /*
  1223.          * create LOCAL and GLOBAL threads alternately
  1224.          */
  1225.         if (i & 1)
  1226.             scope = PR_LOCAL_THREAD;
  1227.         else
  1228.             scope = PR_GLOBAL_THREAD;
  1229.         t[i] = PR_CreateThread(PR_USER_THREAD,
  1230.             Serve_TransmitFile_Client, (void *)scp, 
  1231.             PR_PRIORITY_NORMAL,
  1232.             scope,
  1233.             PR_JOINABLE_THREAD,
  1234.             0);
  1235.         if (t[i] == NULL) {
  1236.             fprintf(stderr,
  1237.                 "prsocket_test: PR_CreateThread failed\n");
  1238.             failed_already=1;
  1239.             goto exit;
  1240.         }
  1241.         DPRINTF(("TransmitFile_Server: Created Serve_TransmitFile_Client = 0x%lx\n", t));
  1242.     }
  1243.  
  1244.     /*
  1245.      * Wait for all the worker threads to end, so that we know
  1246.      * they are no longer using the small and large file fd's.
  1247.      */
  1248.  
  1249.     for (i = 0; i < num_transmitfile_clients; i++) {
  1250.         PR_JoinThread(t[i]);
  1251.     }
  1252.  
  1253. exit:
  1254.     if (t) {
  1255.         PR_DELETE(t);
  1256.     }
  1257.     if (sockfd) {
  1258.         PR_Close(sockfd);
  1259.     }
  1260.  
  1261.     /*
  1262.      * Decrement exit_counter and notify parent thread
  1263.      */
  1264.  
  1265.     PR_EnterMonitor(sp->exit_mon);
  1266.     --(*sp->exit_counter);
  1267.     PR_Notify(sp->exit_mon);
  1268.     PR_ExitMonitor(sp->exit_mon);
  1269.     DPRINTF(("TransmitFile_Server [0x%lx] exiting\n", PR_GetCurrentThread()));
  1270. }
  1271.  
  1272. /*
  1273.  * Socket_Misc_Test    - test miscellaneous functions 
  1274.  *    
  1275.  */
  1276. static PRInt32
  1277. Socket_Misc_Test(void)
  1278. {
  1279.     PRIntn i, rv = 0, bytes, count, len;
  1280.     PRThread *t;
  1281.     PRThreadScope scope;
  1282.     PRSemaphore *server_sem;
  1283.     Server_Param *sparamp;
  1284.     Client_Param *cparamp;
  1285.     PRMonitor *mon2;
  1286.     PRInt32    datalen;
  1287.  
  1288.     /*
  1289.  * We deliberately pick a buffer size that is not a nice multiple
  1290.  * of 1024.
  1291.  */
  1292. #define TRANSMITFILE_BUF_SIZE    (4 * 1024 - 11)
  1293.  
  1294.     typedef struct {
  1295.         char    data[TRANSMITFILE_BUF_SIZE];
  1296.     } file_buf;
  1297.     file_buf *buf = NULL;
  1298.  
  1299.     /*
  1300.      * create file(s) to be transmitted
  1301.      */
  1302.     if ((PR_MkDir(TEST_DIR, 0777)) < 0) {
  1303.         printf("prsocket_test failed to create dir %s\n",TEST_DIR);
  1304.         failed_already=1;
  1305.         return -1;
  1306.     }
  1307.  
  1308.     small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777);
  1309.  
  1310.     if (small_file_fd == NULL) {
  1311.         fprintf(stderr,"prsocket_test failed to create/open file %s\n",
  1312.             SMALL_FILE_NAME);
  1313.         failed_already=1;
  1314.         rv = -1;
  1315.         goto done;
  1316.     }
  1317.     buf = PR_NEW(file_buf);
  1318.     if (buf == NULL) {
  1319.         fprintf(stderr,"prsocket_test failed to allocate buffer\n");
  1320.         failed_already=1;
  1321.         rv = -1;
  1322.         goto done;
  1323.     }
  1324.     /*
  1325.      * fill in random data
  1326.      */
  1327.     for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) {
  1328.         buf->data[i] = i;
  1329.     }
  1330.     count = 0;
  1331.     do {
  1332.         len = (SMALL_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ?
  1333.             TRANSMITFILE_BUF_SIZE : (SMALL_FILE_SIZE - count);
  1334.         bytes = PR_Write(small_file_fd, buf->data, len);
  1335.         if (bytes <= 0) {
  1336.             fprintf(stderr,
  1337.                 "prsocket_test failed to write to file %s\n",
  1338.                 SMALL_FILE_NAME);
  1339.             failed_already=1;
  1340.             rv = -1;
  1341.             goto done;
  1342.         }
  1343.         count += bytes;
  1344.     } while (count < SMALL_FILE_SIZE);
  1345. #ifdef XP_UNIX
  1346.     /*
  1347.      * map the small file; used in checking for data corruption
  1348.      */
  1349.     small_file_addr = mmap(0, SMALL_FILE_SIZE, PROT_READ,
  1350.         MAP_PRIVATE, small_file_fd->secret->md.osfd, 0);
  1351.     if (small_file_addr == (void *) -1) {
  1352.         fprintf(stderr,"prsocket_test failed to mmap file %s\n",
  1353.             SMALL_FILE_NAME);
  1354.         failed_already=1;
  1355.         rv = -1;
  1356.         goto done;
  1357.     }
  1358. #endif
  1359.     /*
  1360.      * header for small file
  1361.      */
  1362.     small_file_header = PR_MALLOC(SMALL_FILE_HEADER_SIZE);
  1363.     if (small_file_header == NULL) {
  1364.         fprintf(stderr,"prsocket_test failed to malloc header file\n");
  1365.         failed_already=1;
  1366.         rv = -1;
  1367.         goto done;
  1368.     }
  1369.     memset(small_file_header, (int) PR_IntervalNow(),
  1370.         SMALL_FILE_HEADER_SIZE);
  1371.     /*
  1372.      * setup large file
  1373.      */
  1374.     large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777);
  1375.  
  1376.     if (large_file_fd == NULL) {
  1377.         fprintf(stderr,"prsocket_test failed to create/open file %s\n",
  1378.             LARGE_FILE_NAME);
  1379.         failed_already=1;
  1380.         rv = -1;
  1381.         goto done;
  1382.     }
  1383.     /*
  1384.      * fill in random data
  1385.      */
  1386.     for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) {
  1387.         buf->data[i] = i;
  1388.     }
  1389.     count = 0;
  1390.     do {
  1391.         len = (LARGE_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ?
  1392.             TRANSMITFILE_BUF_SIZE : (LARGE_FILE_SIZE - count);
  1393.         bytes = PR_Write(large_file_fd, buf->data, len);
  1394.         if (bytes <= 0) {
  1395.             fprintf(stderr,
  1396.                 "prsocket_test failed to write to file %s: (%ld, %ld)\n",
  1397.                 LARGE_FILE_NAME,
  1398.                 PR_GetError(), PR_GetOSError());
  1399.             failed_already=1;
  1400.             rv = -1;
  1401.             goto done;
  1402.         }
  1403.         count += bytes;
  1404.     } while (count < LARGE_FILE_SIZE);
  1405. #ifdef XP_UNIX
  1406.     /*
  1407.      * map the large file; used in checking for data corruption
  1408.      */
  1409.     large_file_addr = mmap(0, LARGE_FILE_SIZE, PROT_READ,
  1410.         MAP_PRIVATE, large_file_fd->secret->md.osfd, 0);
  1411.     if (large_file_addr == (void *) -1) {
  1412.         fprintf(stderr,"prsocket_test failed to mmap file %s\n",
  1413.             LARGE_FILE_NAME);
  1414.         failed_already=1;
  1415.         rv = -1;
  1416.         goto done;
  1417.     }
  1418. #endif
  1419.     datalen = tcp_mesg_size;
  1420.     thread_count = 0;
  1421.     /*
  1422.      * start the server thread
  1423.      */
  1424.     sparamp = PR_NEW(Server_Param);
  1425.     if (sparamp == NULL) {
  1426.         fprintf(stderr,"prsocket_test: PR_NEW failed\n");
  1427.         failed_already=1;
  1428.         rv = -1;
  1429.         goto done;
  1430.     }
  1431.     server_sem = PR_NewSem(0);
  1432.     if (server_sem == NULL) {
  1433.         fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
  1434.         failed_already=1;
  1435.         rv = -1;
  1436.         goto done;
  1437.     }
  1438.     mon2 = PR_NewMonitor();
  1439.     if (mon2 == NULL) {
  1440.         fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
  1441.         failed_already=1;
  1442.         rv = -1;
  1443.         goto done;
  1444.     }
  1445.     PR_EnterMonitor(mon2);
  1446.  
  1447.     sparamp->addr_sem = server_sem;
  1448.     sparamp->exit_mon = mon2;
  1449.     sparamp->exit_counter = &thread_count;
  1450.     sparamp->datalen = datalen;
  1451.     t = PR_CreateThread(PR_USER_THREAD,
  1452.         TransmitFile_Server, (void *)sparamp, 
  1453.         PR_PRIORITY_NORMAL,
  1454.         PR_LOCAL_THREAD,
  1455.         PR_UNJOINABLE_THREAD,
  1456.         0);
  1457.     if (t == NULL) {
  1458.         fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
  1459.         failed_already=1;
  1460.         rv = -1;
  1461.         goto done;
  1462.     }
  1463.     DPRINTF(("Created TCP server = 0x%x\n", t));
  1464.     thread_count++;
  1465.  
  1466.     /*
  1467.      * wait till the server address is setup
  1468.      */
  1469.     PR_WaitSem(server_sem);
  1470.  
  1471.     /*
  1472.      * Now start a bunch of client threads
  1473.      */
  1474.  
  1475.     cparamp = PR_NEW(Client_Param);
  1476.     if (cparamp == NULL) {
  1477.         fprintf(stderr,"prsocket_test: PR_NEW failed\n");
  1478.         failed_already=1;
  1479.         rv = -1;
  1480.         goto done;
  1481.     }
  1482.     cparamp->server_addr = tcp_server_addr;
  1483.     cparamp->server_addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
  1484.     cparamp->exit_mon = mon2;
  1485.     cparamp->exit_counter = &thread_count;
  1486.     cparamp->datalen = datalen;
  1487.     for (i = 0; i < num_transmitfile_clients; i++) {
  1488.         /*
  1489.          * Every other thread is a LOCAL/GLOBAL thread
  1490.          */
  1491.         if (i & 1)
  1492.             scope = PR_GLOBAL_THREAD;
  1493.         else
  1494.             scope = PR_LOCAL_THREAD;
  1495.         t = PR_CreateThread(PR_USER_THREAD,
  1496.             TransmitFile_Client, (void *) cparamp,
  1497.             PR_PRIORITY_NORMAL,
  1498.             scope,
  1499.             PR_UNJOINABLE_THREAD,
  1500.             0);
  1501.         if (t == NULL) {
  1502.             fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
  1503.             rv = -1;
  1504.             failed_already=1;
  1505.             goto done;
  1506.         }
  1507.         DPRINTF(("Created TransmitFile client = 0x%lx\n", t));
  1508.         thread_count++;
  1509.     }
  1510.     /* Wait for server and client threads to exit */
  1511.     while (thread_count) {
  1512.         PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
  1513.         DPRINTF(("Socket_Misc_Test - thread_count  = %d\n", thread_count));
  1514.     }
  1515.     PR_ExitMonitor(mon2);
  1516. done:
  1517.     if (buf) {
  1518.         PR_DELETE(buf);
  1519.     }
  1520. #ifdef XP_UNIX
  1521.     munmap(small_file_addr, SMALL_FILE_SIZE);
  1522.     munmap(large_file_addr, LARGE_FILE_SIZE);
  1523. #endif
  1524.     PR_Close(small_file_fd);
  1525.     PR_Close(large_file_fd);
  1526.     if ((PR_Delete(SMALL_FILE_NAME)) == PR_FAILURE) {
  1527.         fprintf(stderr,"prsocket_test: failed to unlink file %s\n",
  1528.             SMALL_FILE_NAME);
  1529.         failed_already=1;
  1530.     }
  1531.     if ((PR_Delete(LARGE_FILE_NAME)) == PR_FAILURE) {
  1532.         fprintf(stderr,"prsocket_test: failed to unlink file %s\n",
  1533.             LARGE_FILE_NAME);
  1534.         failed_already=1;
  1535.     }
  1536.     if ((PR_RmDir(TEST_DIR)) == PR_FAILURE) {
  1537.         fprintf(stderr,"prsocket_test failed to rmdir %s: (%ld, %ld)\n",
  1538.             TEST_DIR, PR_GetError(), PR_GetOSError());
  1539.         failed_already=1;
  1540.     }
  1541.  
  1542.     printf("%-29s%s","Socket_Misc_Test",":");
  1543.     printf("%2d Server %2d Clients\n",1, num_transmitfile_clients);
  1544.     printf("%30s Sizes of Transmitted Files  - %4d KB, %2d MB \n",":",
  1545.         SMALL_FILE_SIZE/1024, LARGE_FILE_SIZE/(1024 * 1024));
  1546.  
  1547.  
  1548.     return rv;
  1549. }
  1550. /************************************************************************/
  1551.  
  1552. /*
  1553.  * Test Socket NSPR APIs
  1554.  */
  1555.  
  1556. int
  1557. main(int argc, char **argv)
  1558. {
  1559.     /*
  1560.      * -d           debug mode
  1561.      */
  1562.  
  1563.     PLOptStatus os;
  1564.     PLOptState *opt = PL_CreateOptState(argc, argv, "d");
  1565.     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  1566.     {
  1567.         if (PL_OPT_BAD == os) continue;
  1568.         switch (opt->option)
  1569.         {
  1570.         case 'd':  /* debug mode */
  1571.             _debug_on = 1;
  1572.             break;
  1573.         default:
  1574.             break;
  1575.         }
  1576.     }
  1577.     PL_DestroyOptState(opt);
  1578.  
  1579.     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
  1580.     PR_STDIO_INIT();
  1581.  
  1582. #ifdef XP_MAC
  1583.     SetupMacPrintfLog("socket.log");
  1584. #endif
  1585.     PR_SetConcurrency(4);
  1586.     /*
  1587.      * run client-server test with TCP
  1588.      */
  1589.     if (TCP_Socket_Client_Server_Test() < 0) {
  1590.         printf("TCP_Socket_Client_Server_Test failed\n");
  1591.         goto done;
  1592.     } else
  1593.         printf("TCP_Socket_Client_Server_Test Passed\n");
  1594.     /*
  1595.      * run client-server test with UDP
  1596.      */
  1597.     if (UDP_Socket_Client_Server_Test() < 0) {
  1598.         printf("UDP_Socket_Client_Server_Test failed\n");
  1599.         goto done;
  1600.     } else
  1601.         printf("UDP_Socket_Client_Server_Test Passed\n");
  1602.     /*
  1603.      * Misc socket tests - including transmitfile, etc.
  1604.      */
  1605.  
  1606. #if !defined(WIN16)
  1607.     /*
  1608. ** The 'transmit file' test does not run because
  1609. ** transmit file is not implemented in NSPR yet.
  1610. **
  1611. */
  1612.     if (Socket_Misc_Test() < 0) {
  1613.         printf("Socket_Misc_Test failed\n");
  1614.         failed_already=1;
  1615.         goto done;
  1616.     } else
  1617.         printf("Socket_Misc_Test passed\n");
  1618.  
  1619.     /*
  1620.      * run client-server test with TCP again to test
  1621.      * recycling used sockets from PR_TransmitFile().
  1622.      */
  1623.     if (TCP_Socket_Client_Server_Test() < 0) {
  1624.         printf("TCP_Socket_Client_Server_Test failed\n");
  1625.         goto done;
  1626.     } else
  1627.         printf("TCP_Socket_Client_Server_Test Passed\n");
  1628. #endif
  1629.  
  1630. done:
  1631.     PR_Cleanup();
  1632.     if (failed_already) return 1;
  1633.     else return 0;
  1634. }
  1635.