Back to index

lightning-sunbird  0.9+nobinonly
socket.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /***********************************************************************
00039 **
00040 ** Name: socket.c
00041 **
00042 ** Description: Test socket functionality.
00043 **
00044 ** Modification History:
00045 */
00046 #include "primpl.h"
00047 
00048 #include "plgetopt.h"
00049 
00050 #include <stdio.h>
00051 #include <string.h>
00052 #include <errno.h>
00053 #ifdef XP_UNIX
00054 #include <sys/mman.h>
00055 #endif
00056 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
00057 #include <pthread.h>
00058 #endif
00059 
00060 #ifdef WIN32
00061 #include <process.h>
00062 #endif
00063 
00064 static int _debug_on = 0;
00065 static int test_cancelio = 0;
00066 
00067 #ifdef XP_MAC
00068 #include "prlog.h"
00069 #include "prsem.h"
00070 int fprintf(FILE *stream, const char *fmt, ...)
00071 {
00072     PR_LogPrint(fmt);
00073     return 0;
00074 }
00075 #define printf PR_LogPrint
00076 extern void SetupMacPrintfLog(char *logFile);
00077 #else
00078 #include "obsolete/prsem.h"
00079 #endif
00080 
00081 #ifdef XP_PC
00082 #define mode_t int
00083 #endif
00084 
00085 #define DPRINTF(arg) if (_debug_on) printf arg
00086 
00087 #ifdef XP_PC
00088 char *TEST_DIR = "prdir";
00089 char *SMALL_FILE_NAME = "prsmallf";
00090 char *LARGE_FILE_NAME = "prlargef";
00091 #else
00092 char *TEST_DIR = "/tmp/prsocket_test_dir";
00093 char *SMALL_FILE_NAME = "/tmp/prsocket_test_dir/small_file";
00094 char *LARGE_FILE_NAME = "/tmp/prsocket_test_dir/large_file";
00095 #endif
00096 #define SMALL_FILE_SIZE                          (3 * 1024)        /* 3 KB        */
00097 #define SMALL_FILE_OFFSET_1               (512)
00098 #define SMALL_FILE_LEN_1                  (1 * 1024)        /* 1 KB        */
00099 #define SMALL_FILE_OFFSET_2               (75)
00100 #define SMALL_FILE_LEN_2                  (758)
00101 #define SMALL_FILE_OFFSET_3               (1024)
00102 #define SMALL_FILE_LEN_3                  (SMALL_FILE_SIZE - SMALL_FILE_OFFSET_3)
00103 #define SMALL_FILE_HEADER_SIZE     (64)            /* 64 bytes    */
00104 #define SMALL_FILE_TRAILER_SIZE    (128)           /* 128 bytes    */
00105 
00106 #define LARGE_FILE_SIZE                          (3 * 1024 * 1024)    /* 3 MB        */
00107 #define LARGE_FILE_OFFSET_1               (0)
00108 #define LARGE_FILE_LEN_1                  (2 * 1024 * 1024)    /* 2 MB        */
00109 #define LARGE_FILE_OFFSET_2               (64)
00110 #define LARGE_FILE_LEN_2                  (1 * 1024 * 1024 + 75)
00111 #define LARGE_FILE_OFFSET_3               (2 * 1024 * 1024 - 128)
00112 #define LARGE_FILE_LEN_3                  (LARGE_FILE_SIZE - LARGE_FILE_OFFSET_3)
00113 #define LARGE_FILE_OFFSET_4               PR_GetPageSize()
00114 #define LARGE_FILE_LEN_4                  769
00115 #define LARGE_FILE_HEADER_SIZE     (512)
00116 #define LARGE_FILE_TRAILER_SIZE    (64)
00117 
00118 #define    BUF_DATA_SIZE    (2 * 1024)
00119 #define TCP_MESG_SIZE    1024
00120 /*
00121  * set UDP datagram size small enough that datagrams sent to a port on the
00122  * local host will not be lost
00123  */
00124 #define UDP_DGRAM_SIZE            128
00125 #define NUM_TCP_CLIENTS            5      /* for a listen queue depth of 5 */
00126 #define NUM_UDP_CLIENTS            10
00127 
00128 #ifndef XP_MAC
00129 #define NUM_TRANSMITFILE_CLIENTS    4
00130 #else
00131 /* Mac can't handle more than 2* (3Mb) allocations for large file size buffers */
00132 #define NUM_TRANSMITFILE_CLIENTS    2
00133 #endif
00134 
00135 #define NUM_TCP_CONNECTIONS_PER_CLIENT    5
00136 #define NUM_TCP_MESGS_PER_CONNECTION    10
00137 #define NUM_UDP_DATAGRAMS_PER_CLIENT    5
00138 #define TCP_SERVER_PORT            10000
00139 #define UDP_SERVER_PORT            TCP_SERVER_PORT
00140 #define SERVER_MAX_BIND_COUNT        100
00141 
00142 static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS;
00143 static PRInt32 num_udp_clients = NUM_UDP_CLIENTS;
00144 static PRInt32 num_transmitfile_clients = NUM_TRANSMITFILE_CLIENTS;
00145 static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT;
00146 static PRInt32 tcp_mesg_size = TCP_MESG_SIZE;
00147 static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION;
00148 static PRInt32 num_udp_datagrams_per_client = NUM_UDP_DATAGRAMS_PER_CLIENT;
00149 static PRInt32 udp_datagram_size = UDP_DGRAM_SIZE;
00150 
00151 static PRInt32 thread_count;
00152 PRUint16 server_domain = PR_AF_INET, client_domain = PR_AF_INET;
00153 
00154 /* an I/O layer that uses the emulated senfile method */
00155 static PRDescIdentity emuSendFileIdentity;
00156 static PRIOMethods emuSendFileMethods;
00157 
00158 int failed_already=0;
00159 typedef struct buffer {
00160     char    data[BUF_DATA_SIZE];
00161 } buffer;
00162 
00163 PRNetAddr tcp_server_addr, udp_server_addr;
00164 
00165 typedef struct Serve_Client_Param {
00166     PRFileDesc *sockfd;    /* socket to read from/write to    */
00167     PRInt32    datalen;    /* bytes of data transfered in each read/write */
00168 } Serve_Client_Param;
00169 
00170 typedef struct Server_Param {
00171     PRSemaphore *addr_sem;    /* sem to post on, after setting up the address */
00172     PRMonitor *exit_mon;    /* monitor to signal on exit            */
00173     PRInt32 *exit_counter;    /* counter to decrement, before exit        */
00174     PRInt32    datalen;    /* bytes of data transfered in each read/write    */
00175 } Server_Param;
00176 
00177 
00178 typedef struct Client_Param {
00179     PRNetAddr server_addr;
00180     PRMonitor *exit_mon;    /* monitor to signal on exit */
00181     PRInt32 *exit_counter;    /* counter to decrement, before exit */
00182     PRInt32    datalen;
00183     PRInt32    udp_connect;    /* if set clients connect udp sockets */
00184 } Client_Param;
00185 
00186 /* the sendfile method in emuSendFileMethods */
00187 static PRInt32 PR_CALLBACK
00188 emu_SendFile(PRFileDesc *sd, PRSendFileData *sfd,
00189     PRTransmitFileFlags flags, PRIntervalTime timeout)
00190 {
00191     return PR_EmulateSendFile(sd, sfd, flags, timeout);
00192 }
00193 
00194 /* the transmitfile method in emuSendFileMethods */
00195 static PRInt32 PR_CALLBACK
00196 emu_TransmitFile(PRFileDesc *sd, PRFileDesc *fd, const void *headers,
00197     PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
00198 {
00199     PRSendFileData sfd;
00200 
00201     sfd.fd = fd;
00202     sfd.file_offset = 0;
00203     sfd.file_nbytes = 0;
00204     sfd.header = headers;
00205     sfd.hlen = hlen;
00206     sfd.trailer = NULL;
00207     sfd.tlen = 0;
00208     return emu_SendFile(sd, &sfd, flags, timeout);
00209 }
00210 
00211 /*
00212  * readn
00213  *    read data from sockfd into buf
00214  */
00215 static PRInt32
00216 readn(PRFileDesc *sockfd, char *buf, int len)
00217 {
00218     int rem;
00219     int bytes;
00220     int offset = 0;
00221        int err;
00222        PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
00223 
00224        if (test_cancelio)
00225               timeout = PR_SecondsToInterval(2);
00226 
00227     for (rem=len; rem; offset += bytes, rem -= bytes) {
00228         DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n",
00229             PR_GetCurrentThread(), rem));
00230 retry:
00231         bytes = PR_Recv(sockfd, buf + offset, rem, 0,
00232               timeout);
00233         DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n",
00234             PR_GetCurrentThread(), bytes));
00235         if (bytes < 0) {
00236 #ifdef WINNT
00237                      printf("PR_Recv: error = %d oserr = %d\n",(err = PR_GetError()),
00238                                                                PR_GetOSError());
00239                      if ((test_cancelio) && (err == PR_IO_TIMEOUT_ERROR)) {
00240                             if (PR_NT_CancelIo(sockfd) != PR_SUCCESS)
00241                                    printf("PR_NT_CancelIO: error = %d\n",PR_GetError());
00242                             timeout = PR_INTERVAL_NO_TIMEOUT;
00243                             goto retry;
00244                      }
00245 #endif
00246                      return -1;
00247               }      
00248     }
00249     return len;
00250 }
00251 
00252 /*
00253  * writen
00254  *    write data from buf to sockfd
00255  */
00256 static PRInt32
00257 writen(PRFileDesc *sockfd, char *buf, int len)
00258 {
00259     int rem;
00260     int bytes;
00261     int offset = 0;
00262 
00263     for (rem=len; rem; offset += bytes, rem -= bytes) {
00264         DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n",
00265             PR_GetCurrentThread(), rem));
00266         bytes = PR_Send(sockfd, buf + offset, rem, 0,
00267             PR_INTERVAL_NO_TIMEOUT);
00268         DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n",
00269             PR_GetCurrentThread(), bytes));
00270         if (bytes <= 0)
00271             return -1;
00272     }
00273     return len;
00274 }
00275 
00276 /*
00277  * Serve_Client
00278  *    Thread, started by the server, for serving a client connection.
00279  *    Reads data from socket and writes it back, unmodified, and
00280  *    closes the socket
00281  */
00282 static void PR_CALLBACK
00283 Serve_Client(void *arg)
00284 {
00285     Serve_Client_Param *scp = (Serve_Client_Param *) arg;
00286     PRFileDesc *sockfd;
00287     buffer *in_buf;
00288     PRInt32 bytes, j;
00289 
00290     sockfd = scp->sockfd;
00291     bytes = scp->datalen;
00292     in_buf = PR_NEW(buffer);
00293     if (in_buf == NULL) {
00294         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
00295         failed_already=1;
00296         goto exit;
00297     }
00298 
00299 
00300     for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
00301         /*
00302          * Read data from client and send it back to the client unmodified
00303          */
00304         if (readn(sockfd, in_buf->data, bytes) < bytes) {
00305             fprintf(stderr,"prsocket_test: ERROR - Serve_Client:readn\n");
00306             failed_already=1;
00307             goto exit;
00308         }
00309         /*
00310          * shutdown reads, after the last read
00311          */
00312         if (j == num_tcp_mesgs_per_connection - 1)
00313             if (PR_Shutdown(sockfd, PR_SHUTDOWN_RCV) < 0) {
00314                 fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
00315             }
00316         DPRINTF(("Serve_Client [0x%lx]: inbuf[0] = 0x%lx\n",PR_GetCurrentThread(),
00317             (*((int *) in_buf->data))));
00318         if (writen(sockfd, in_buf->data, bytes) < bytes) {
00319             fprintf(stderr,"prsocket_test: ERROR - Serve_Client:writen\n");
00320             failed_already=1;
00321             goto exit;
00322         }
00323     }
00324     /*
00325      * shutdown reads and writes
00326      */
00327     if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
00328         fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
00329         failed_already=1;
00330     }
00331 
00332 exit:
00333     PR_Close(sockfd);
00334     if (in_buf) {
00335         PR_DELETE(in_buf);
00336     }
00337 }
00338 
00339 PRThread* create_new_thread(PRThreadType type,
00340                                                  void (*start)(void *arg),
00341                                                  void *arg,
00342                                                  PRThreadPriority priority,
00343                                                  PRThreadScope scope,
00344                                                  PRThreadState state,
00345                                                  PRUint32 stackSize, PRInt32 index)
00346 {
00347 PRInt32 native_thread = 0;
00348 
00349        PR_ASSERT(state == PR_UNJOINABLE_THREAD);
00350 #if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WIN32)
00351        switch(index %  4) {
00352               case 0:
00353                      scope = (PR_LOCAL_THREAD);
00354                      break;
00355               case 1:
00356                      scope = (PR_GLOBAL_THREAD);
00357                      break;
00358               case 2:
00359                      scope = (PR_GLOBAL_BOUND_THREAD);
00360                      break;
00361               case 3:
00362                      native_thread = 1;
00363                      break;
00364               default:
00365                      PR_ASSERT(!"Invalid scope");
00366                      break;
00367        }
00368        if (native_thread) {
00369 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
00370               pthread_t tid;
00371               if (!pthread_create(&tid, NULL, (void * (*)(void *)) start, arg))
00372                      return((PRThread *) tid);
00373               else
00374                      return (NULL);
00375 #else
00376               HANDLE thandle;
00377               unsigned tid;
00378               
00379               thandle = (HANDLE) _beginthreadex(
00380                                           NULL,
00381                                           stackSize,
00382                                           (unsigned (__stdcall *)(void *))start,
00383                                           arg,
00384                                           0,
00385                                           &tid);        
00386               return((PRThread *) thandle);
00387 #endif
00388        } else {
00389               return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize));
00390        }
00391 #else
00392        return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize));
00393 #endif
00394 }
00395 
00396 /*
00397  * TCP Server
00398  *    Server Thread
00399  *    Bind an address to a socket and listen for incoming connections
00400  *    Start a Serve_Client thread for each incoming connection.
00401  */
00402 static void PR_CALLBACK
00403 TCP_Server(void *arg)
00404 {
00405     PRThread *t;
00406     Server_Param *sp = (Server_Param *) arg;
00407     Serve_Client_Param *scp;
00408     PRFileDesc *sockfd, *newsockfd;
00409     PRNetAddr netaddr;
00410     PRInt32 i;
00411     /*
00412      * Create a tcp socket
00413      */
00414        if ((sockfd = PR_OpenTCPSocket(server_domain)) == NULL) {
00415         fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
00416         goto exit;
00417     }
00418     memset(&netaddr, 0 , sizeof(netaddr));
00419        
00420        if (PR_SetNetAddr(PR_IpAddrAny, server_domain, TCP_SERVER_PORT,
00421                                                                &netaddr) == PR_FAILURE) {
00422         fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
00423         goto exit;
00424        }
00425     /*
00426      * try a few times to bind server's address, if addresses are in
00427      * use
00428      */
00429     i = 0;
00430        
00431     while (PR_Bind(sockfd, &netaddr) < 0) {
00432         if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
00433             netaddr.inet.port += 2;
00434             if (i++ < SERVER_MAX_BIND_COUNT)
00435                 continue;
00436         }
00437         fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
00438         perror("PR_Bind");
00439         failed_already=1;
00440         goto exit;
00441     }
00442 
00443     if (PR_Listen(sockfd, 32) < 0) {
00444         fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n");
00445         failed_already=1;
00446         goto exit;
00447     }
00448 
00449     if (PR_GetSockName(sockfd, &netaddr) < 0) {
00450         fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
00451         failed_already=1;
00452         goto exit;
00453     }
00454 
00455     DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
00456         netaddr.inet.ip, netaddr.inet.port));
00457        if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain,
00458                                                                PR_ntohs(PR_NetAddrInetPort(&netaddr)),
00459                                                                &tcp_server_addr) == PR_FAILURE) {
00460         fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
00461         goto exit;
00462        }
00463        if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET))
00464               PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK),
00465                                                         &tcp_server_addr.ipv6.ip);
00466 
00467     /*
00468      * Wake up parent thread because server address is bound and made
00469      * available in the global variable 'tcp_server_addr'
00470      */
00471     PR_PostSem(sp->addr_sem);
00472 
00473     for (i = 0; i < (num_tcp_clients * num_tcp_connections_per_client); i++) {
00474         /* test both null and non-null 'addr' argument to PR_Accept */
00475         PRNetAddr *addrp = (i%2 ? &netaddr: NULL);
00476 
00477     DPRINTF(("TCP_Server: Accepting connection\n"));
00478         if ((newsockfd = PR_Accept(sockfd, addrp,
00479             PR_INTERVAL_NO_TIMEOUT)) == NULL) {
00480             fprintf(stderr,"prsocket_test: ERROR - PR_Accept failed\n");
00481             goto exit;
00482         }
00483     DPRINTF(("TCP_Server: Accepted connection\n"));
00484         scp = PR_NEW(Serve_Client_Param);
00485         if (scp == NULL) {
00486             fprintf(stderr,"prsocket_test: PR_NEW failed\n");
00487             goto exit;
00488         }
00489 
00490         /*
00491          * Start a Serve_Client thread for each incoming connection
00492          */
00493         scp->sockfd = newsockfd;
00494         scp->datalen = sp->datalen;
00495 
00496         t = create_new_thread(PR_USER_THREAD,
00497             Serve_Client, (void *)scp, 
00498             PR_PRIORITY_NORMAL,
00499             PR_LOCAL_THREAD,
00500             PR_UNJOINABLE_THREAD,
00501             0, i);
00502         if (t == NULL) {
00503             fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
00504             failed_already=1;
00505             goto exit;
00506         }
00507         DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", t));
00508     }
00509 
00510 exit:
00511     if (sockfd) {
00512         PR_Close(sockfd);
00513     }
00514 
00515     /*
00516      * Decrement exit_counter and notify parent thread
00517      */
00518 
00519     PR_EnterMonitor(sp->exit_mon);
00520     --(*sp->exit_counter);
00521     PR_Notify(sp->exit_mon);
00522     PR_ExitMonitor(sp->exit_mon);
00523     DPRINTF(("TCP_Server [0x%lx] exiting\n", PR_GetCurrentThread()));
00524 }
00525 
00526 /*
00527  * UDP Server
00528  *    Server Thread
00529  *    Bind an address to a socket, read data from clients and send data
00530  *    back to clients
00531  */
00532 static void PR_CALLBACK
00533 UDP_Server(void *arg)
00534 {
00535     Server_Param *sp = (Server_Param *) arg;
00536     PRFileDesc *sockfd;
00537     buffer *in_buf;
00538     PRNetAddr netaddr;
00539     PRInt32 bytes, i, rv = 0;
00540 
00541 
00542     bytes = sp->datalen;
00543     /*
00544      * Create a udp socket
00545      */
00546        if ((sockfd = PR_OpenUDPSocket(server_domain)) == NULL) {
00547         fprintf(stderr,"prsocket_test: PR_NewUDPSocket failed\n");
00548         failed_already=1;
00549         return;
00550     }
00551     memset(&netaddr, 0 , sizeof(netaddr));
00552        if (PR_SetNetAddr(PR_IpAddrAny, server_domain, UDP_SERVER_PORT,
00553                                                                &netaddr) == PR_FAILURE) {
00554         fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
00555         failed_already=1;
00556         return;
00557        }
00558     /*
00559      * try a few times to bind server's address, if addresses are in
00560      * use
00561      */
00562     i = 0;
00563     while (PR_Bind(sockfd, &netaddr) < 0) {
00564         if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
00565             netaddr.inet.port += 2;
00566             if (i++ < SERVER_MAX_BIND_COUNT)
00567                 continue;
00568         }
00569         fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
00570         perror("PR_Bind");
00571         failed_already=1;
00572         return;
00573     }
00574 
00575     if (PR_GetSockName(sockfd, &netaddr) < 0) {
00576         fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
00577         failed_already=1;
00578         return;
00579     }
00580 
00581     DPRINTF(("PR_Bind: UDP Server netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
00582         netaddr.inet.ip, netaddr.inet.port));
00583     /*
00584      * We can't use the IP address returned by PR_GetSockName in
00585      * netaddr.inet.ip because netaddr.inet.ip is returned
00586      * as 0 (= PR_INADDR_ANY).
00587      */
00588 
00589        if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain,
00590                                                                PR_ntohs(PR_NetAddrInetPort(&netaddr)),
00591                                                                &udp_server_addr) == PR_FAILURE) {
00592         fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
00593         failed_already=1;
00594         return;
00595        }
00596        if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET))
00597               PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK),
00598                                                         &udp_server_addr.ipv6.ip);
00599               
00600     /*
00601      * Wake up parent thread because server address is bound and made
00602      * available in the global variable 'udp_server_addr'
00603      */
00604     PR_PostSem(sp->addr_sem);
00605 
00606     bytes = sp->datalen;
00607     in_buf = PR_NEW(buffer);
00608     if (in_buf == NULL) {
00609         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
00610         failed_already=1;
00611         return;
00612     }
00613     /*
00614      * Receive datagrams from clients and send them back, unmodified, to the
00615      * clients
00616      */
00617     memset(&netaddr, 0 , sizeof(netaddr));
00618     for (i = 0; i < (num_udp_clients * num_udp_datagrams_per_client); i++) {
00619         DPRINTF(("UDP_Server: calling PR_RecvFrom client  - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n",
00620             netaddr.inet.ip, netaddr.inet.port, bytes, in_buf->data,
00621             in_buf->data[0]));
00622 
00623         rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr,
00624             PR_INTERVAL_NO_TIMEOUT);
00625         DPRINTF(("UDP_Server: PR_RecvFrom client  - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n",
00626             netaddr.inet.ip, netaddr.inet.port, rv, in_buf->data,
00627             in_buf->data[0]));
00628         if (rv != bytes) {
00629             return;
00630         }
00631         rv = PR_SendTo(sockfd, in_buf->data, bytes, 0, &netaddr,
00632             PR_INTERVAL_NO_TIMEOUT);
00633         if (rv != bytes) {
00634             return;
00635         }
00636     }
00637 
00638     PR_DELETE(in_buf);
00639     PR_Close(sockfd);
00640 
00641     /*
00642      * Decrement exit_counter and notify parent thread
00643      */
00644     PR_EnterMonitor(sp->exit_mon);
00645     --(*sp->exit_counter);
00646     PR_Notify(sp->exit_mon);
00647     PR_ExitMonitor(sp->exit_mon);
00648     DPRINTF(("UDP_Server [0x%x] exiting\n", PR_GetCurrentThread()));
00649 }
00650 
00651 /*
00652  * TCP_Client
00653  *    Client Thread
00654  *    Connect to the server at the address specified in the argument.
00655  *    Fill in a buffer, write data to server, read it back and check
00656  *    for data corruption.
00657  *    Close the socket for server connection
00658  */
00659 static void PR_CALLBACK
00660 TCP_Client(void *arg)
00661 {
00662     Client_Param *cp = (Client_Param *) arg;
00663     PRFileDesc *sockfd;
00664     buffer *in_buf, *out_buf;
00665     union PRNetAddr netaddr;
00666     PRInt32 bytes, i, j;
00667 
00668 
00669     bytes = cp->datalen;
00670     out_buf = PR_NEW(buffer);
00671     if (out_buf == NULL) {
00672         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
00673         failed_already=1;
00674         return;
00675     }
00676     in_buf = PR_NEW(buffer);
00677     if (in_buf == NULL) {
00678         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
00679         failed_already=1;
00680         return;
00681     }
00682     netaddr = cp->server_addr;
00683 
00684     for (i = 0; i < num_tcp_connections_per_client; i++) {
00685         if ((sockfd = PR_OpenTCPSocket(client_domain)) == NULL) {
00686             fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n");
00687             failed_already=1;
00688             return;
00689         }
00690         if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){
00691               fprintf(stderr, "PR_Connect failed: (%ld, %ld)\n",
00692                      PR_GetError(), PR_GetOSError());
00693             failed_already=1;
00694             return;
00695         }
00696         for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
00697             /*
00698              * fill in random data
00699              */
00700             memset(out_buf->data, ((PRInt32) (&netaddr)) + i + j, bytes);
00701             /*
00702              * write to server
00703              */
00704 #ifdef WINNT
00705                      if (test_cancelio && (j == 0))
00706                             PR_Sleep(PR_SecondsToInterval(12));
00707 #endif
00708             if (writen(sockfd, out_buf->data, bytes) < bytes) {
00709                 fprintf(stderr,"prsocket_test: ERROR - TCP_Client:writen\n");
00710                 failed_already=1;
00711                 return;
00712             }
00713             DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
00714                 PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data))));
00715             if (readn(sockfd, in_buf->data, bytes) < bytes) {
00716                 fprintf(stderr,"prsocket_test: ERROR - TCP_Client:readn\n");
00717                 failed_already=1;
00718                 return;
00719             }
00720             /*
00721              * verify the data read
00722              */
00723             if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
00724                 fprintf(stderr,"prsocket_test: ERROR - data corruption\n");
00725                 failed_already=1;
00726                 return;
00727             }
00728         }
00729         /*
00730          * shutdown reads and writes
00731          */
00732         if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
00733             fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
00734             failed_already=1;
00735         }
00736         PR_Close(sockfd);
00737     }
00738 
00739     PR_DELETE(out_buf);
00740     PR_DELETE(in_buf);
00741 
00742     /*
00743      * Decrement exit_counter and notify parent thread
00744      */
00745 
00746     PR_EnterMonitor(cp->exit_mon);
00747     --(*cp->exit_counter);
00748     PR_Notify(cp->exit_mon);
00749     PR_ExitMonitor(cp->exit_mon);
00750     DPRINTF(("TCP_Client [0x%x] exiting\n", PR_GetCurrentThread()));
00751 }
00752 
00753 /*
00754  * UDP_Client
00755  *    Client Thread
00756  *    Create a socket and bind an address 
00757  *    Communicate with the server at the address specified in the argument.
00758  *    Fill in a buffer, write data to server, read it back and check
00759  *    for data corruption.
00760  *    Close the socket
00761  */
00762 static void PR_CALLBACK
00763 UDP_Client(void *arg)
00764 {
00765     Client_Param *cp = (Client_Param *) arg;
00766     PRFileDesc *sockfd;
00767     buffer *in_buf, *out_buf;
00768     union PRNetAddr netaddr;
00769     PRInt32 bytes, i, rv;
00770 
00771 
00772     bytes = cp->datalen;
00773     out_buf = PR_NEW(buffer);
00774     if (out_buf == NULL) {
00775         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
00776         failed_already=1;
00777         return;
00778     }
00779     in_buf = PR_NEW(buffer);
00780     if (in_buf == NULL) {
00781         fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
00782         failed_already=1;
00783         return;
00784     }
00785     if ((sockfd = PR_OpenUDPSocket(client_domain)) == NULL) {
00786         fprintf(stderr,"prsocket_test: PR_OpenUDPSocket failed\n");
00787         failed_already=1;
00788         return;
00789     }
00790 
00791     /*
00792      * bind an address for the client, let the system chose the port
00793      * number
00794      */
00795     memset(&netaddr, 0 , sizeof(netaddr));
00796        if (PR_SetNetAddr(PR_IpAddrAny, client_domain, 0,
00797                                                                &netaddr) == PR_FAILURE) {
00798         fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
00799         failed_already=1;
00800         return;
00801        }
00802     if (PR_Bind(sockfd, &netaddr) < 0) {
00803         fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
00804         perror("PR_Bind");
00805         return;
00806     }
00807 
00808     if (PR_GetSockName(sockfd, &netaddr) < 0) {
00809         fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
00810         failed_already=1;
00811         return;
00812     }
00813 
00814     DPRINTF(("PR_Bind: UDP Client netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
00815         netaddr.inet.ip, netaddr.inet.port));
00816 
00817     netaddr = cp->server_addr;
00818 
00819     if (cp->udp_connect) {
00820         if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){
00821             fprintf(stderr,"prsocket_test: PR_Connect failed\n");
00822             failed_already=1;
00823             return;
00824         }
00825     }
00826 
00827     for (i = 0; i < num_udp_datagrams_per_client; i++) {
00828         /*
00829          * fill in random data
00830          */
00831         DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx bytes = 0x%lx\n",
00832             PR_GetCurrentThread(), out_buf->data, bytes));
00833         memset(out_buf->data, ((PRInt32) (&netaddr)) + i, bytes);
00834         /*
00835          * write to server
00836          */
00837         if (cp->udp_connect)
00838             rv = PR_Send(sockfd, out_buf->data, bytes, 0,
00839                 PR_INTERVAL_NO_TIMEOUT);
00840         else
00841             rv = PR_SendTo(sockfd, out_buf->data, bytes, 0, &netaddr,
00842                 PR_INTERVAL_NO_TIMEOUT);
00843         if (rv != bytes) {
00844             return;
00845         }
00846         DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
00847             PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data))));
00848         if (cp->udp_connect)
00849             rv = PR_Recv(sockfd, in_buf->data, bytes, 0,
00850                 PR_INTERVAL_NO_TIMEOUT);
00851         else
00852             rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr,
00853                 PR_INTERVAL_NO_TIMEOUT);
00854         if (rv != bytes) {
00855             return;
00856         }
00857         DPRINTF(("UDP_Client [0x%lx]: in_buf = 0x%lx in_buf[0] = 0x%lx\n",
00858             PR_GetCurrentThread(), in_buf, (*((int *) in_buf->data))));
00859         /*
00860          * verify the data read
00861          */
00862         if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
00863             fprintf(stderr,"prsocket_test: ERROR - UDP data corruption\n");
00864             failed_already=1;
00865             return;
00866         }
00867     }
00868     PR_Close(sockfd);
00869 
00870     PR_DELETE(in_buf);
00871     PR_DELETE(out_buf);
00872 
00873     /*
00874      * Decrement exit_counter and notify parent thread
00875      */
00876 
00877     PR_EnterMonitor(cp->exit_mon);
00878     --(*cp->exit_counter);
00879     PR_Notify(cp->exit_mon);
00880     PR_ExitMonitor(cp->exit_mon);
00881     PR_DELETE(cp);
00882     DPRINTF(("UDP_Client [0x%x] exiting\n", PR_GetCurrentThread()));
00883 }
00884 
00885 /*
00886  * TCP_Socket_Client_Server_Test    - concurrent server test
00887  *    
00888  *    One server and several clients are started
00889  *    Each client connects to the server and sends a chunk of data
00890  *    For each connection, server starts another thread to read the data
00891  *    from the client and send it back to the client, unmodified.
00892  *    Each client checks that data received from server is same as the
00893  *    data it sent to the server.
00894  *
00895  */
00896 
00897 static PRInt32
00898 TCP_Socket_Client_Server_Test(void)
00899 {
00900     int i;
00901     PRThread *t;
00902     PRSemaphore *server_sem;
00903     Server_Param *sparamp;
00904     Client_Param *cparamp;
00905     PRMonitor *mon2;
00906     PRInt32    datalen;
00907 
00908 
00909     datalen = tcp_mesg_size;
00910     thread_count = 0;
00911     /*
00912      * start the server thread
00913      */
00914     sparamp = PR_NEW(Server_Param);
00915     if (sparamp == NULL) {
00916         fprintf(stderr,"prsocket_test: PR_NEW failed\n");
00917         failed_already=1;
00918         return -1;
00919     }
00920     server_sem = PR_NewSem(0);
00921     if (server_sem == NULL) {
00922         fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
00923         failed_already=1;
00924         return -1;
00925     }
00926     mon2 = PR_NewMonitor();
00927     if (mon2 == NULL) {
00928         fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
00929         failed_already=1;
00930         return -1;
00931     }
00932     PR_EnterMonitor(mon2);
00933 
00934     sparamp->addr_sem = server_sem;
00935     sparamp->exit_mon = mon2;
00936     sparamp->exit_counter = &thread_count;
00937     sparamp->datalen = datalen;
00938     t = PR_CreateThread(PR_USER_THREAD,
00939         TCP_Server, (void *)sparamp, 
00940         PR_PRIORITY_NORMAL,
00941         PR_LOCAL_THREAD,
00942         PR_UNJOINABLE_THREAD,
00943         0);
00944     if (t == NULL) {
00945         fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
00946         failed_already=1;
00947         return -1;
00948     }
00949     DPRINTF(("Created TCP server = 0x%lx\n", t));
00950     thread_count++;
00951 
00952     /*
00953      * wait till the server address is setup
00954      */
00955     PR_WaitSem(server_sem);
00956 
00957     /*
00958      * Now start a bunch of client threads
00959      */
00960 
00961     cparamp = PR_NEW(Client_Param);
00962     if (cparamp == NULL) {
00963         fprintf(stderr,"prsocket_test: PR_NEW failed\n");
00964         failed_already=1;
00965         return -1;
00966     }
00967     cparamp->server_addr = tcp_server_addr;
00968     cparamp->exit_mon = mon2;
00969     cparamp->exit_counter = &thread_count;
00970     cparamp->datalen = datalen;
00971     for (i = 0; i < num_tcp_clients; i++) {
00972         t = create_new_thread(PR_USER_THREAD,
00973             TCP_Client, (void *) cparamp,
00974             PR_PRIORITY_NORMAL,
00975             PR_LOCAL_THREAD,
00976             PR_UNJOINABLE_THREAD,
00977             0, i);
00978         if (t == NULL) {
00979             fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
00980             failed_already=1;
00981             return -1;
00982         }
00983         DPRINTF(("Created TCP client = 0x%lx\n", t));
00984         thread_count++;
00985     }
00986     /* Wait for server and client threads to exit */
00987     while (thread_count) {
00988         PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
00989         DPRINTF(("TCP Server - thread_count  = %d\n", thread_count));
00990     }
00991     PR_ExitMonitor(mon2);
00992     printf("%30s","TCP_Socket_Client_Server_Test:");
00993     printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l,
00994         num_tcp_clients, num_tcp_connections_per_client);
00995     printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":",
00996         num_tcp_mesgs_per_connection, tcp_mesg_size);
00997 
00998     return 0;
00999 }
01000 
01001 /*
01002  * UDP_Socket_Client_Server_Test    - iterative server test
01003  *    
01004  *    One server and several clients are started
01005  *    Each client connects to the server and sends a chunk of data
01006  *    For each connection, server starts another thread to read the data
01007  *    from the client and send it back to the client, unmodified.
01008  *    Each client checks that data received from server is same as the
01009  *    data it sent to the server.
01010  *
01011  */
01012 
01013 static PRInt32
01014 UDP_Socket_Client_Server_Test(void)
01015 {
01016     int i;
01017     PRThread *t;
01018     PRSemaphore *server_sem;
01019     Server_Param *sparamp;
01020     Client_Param *cparamp;
01021     PRMonitor *mon2;
01022     PRInt32    datalen;
01023     PRInt32    udp_connect = 1;
01024 
01025 
01026     datalen = udp_datagram_size;
01027     thread_count = 0;
01028     /*
01029      * start the server thread
01030      */
01031     sparamp = PR_NEW(Server_Param);
01032     if (sparamp == NULL) {
01033         fprintf(stderr,"prsocket_test: PR_NEW failed\n");
01034         failed_already=1;
01035         return -1;
01036     }
01037     server_sem = PR_NewSem(0);
01038     if (server_sem == NULL) {
01039         fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
01040         failed_already=1;
01041         return -1;
01042     }
01043     mon2 = PR_NewMonitor();
01044     if (mon2 == NULL) {
01045         fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
01046         failed_already=1;
01047         return -1;
01048     }
01049     PR_EnterMonitor(mon2);
01050 
01051     sparamp->addr_sem = server_sem;
01052     sparamp->exit_mon = mon2;
01053     sparamp->exit_counter = &thread_count;
01054     sparamp->datalen = datalen;
01055     DPRINTF(("Creating UDP server"));
01056     t = PR_CreateThread(PR_USER_THREAD,
01057         UDP_Server, (void *)sparamp, 
01058         PR_PRIORITY_NORMAL,
01059         PR_LOCAL_THREAD,
01060         PR_UNJOINABLE_THREAD,
01061         0);
01062     if (t == NULL) {
01063         fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
01064         failed_already=1;
01065         return -1;
01066     }
01067     thread_count++;
01068 
01069     /*
01070      * wait till the server address is setup
01071      */
01072     PR_WaitSem(server_sem);
01073 
01074     /*
01075      * Now start a bunch of client threads
01076      */
01077 
01078     for (i = 0; i < num_udp_clients; i++) {
01079         cparamp = PR_NEW(Client_Param);
01080         if (cparamp == NULL) {
01081             fprintf(stderr,"prsocket_test: PR_NEW failed\n");
01082             failed_already=1;
01083             return -1;
01084         }
01085         cparamp->server_addr = udp_server_addr;
01086         cparamp->exit_mon = mon2;
01087         cparamp->exit_counter = &thread_count;
01088         cparamp->datalen = datalen;
01089         /*
01090          * Cause every other client thread to connect udp sockets
01091          */
01092 #ifndef XP_MAC
01093         cparamp->udp_connect = udp_connect;
01094 #else
01095         /* No support for UDP connects on Mac */
01096         cparamp->udp_connect = 0;
01097 #endif
01098         if (udp_connect)
01099             udp_connect = 0;
01100         else
01101             udp_connect = 1;
01102         DPRINTF(("Creating UDP client %d\n", i));
01103         t = PR_CreateThread(PR_USER_THREAD,
01104             UDP_Client, (void *) cparamp,
01105             PR_PRIORITY_NORMAL,
01106             PR_LOCAL_THREAD,
01107             PR_UNJOINABLE_THREAD,
01108             0);
01109         if (t == NULL) {
01110             fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
01111             failed_already=1;
01112             return -1;
01113         }
01114         thread_count++;
01115     }
01116     /* Wait for server and client threads to exit */
01117     while (thread_count) {
01118         PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
01119         DPRINTF(("UDP Server - thread_count  = %d\n", thread_count));
01120     }
01121     PR_ExitMonitor(mon2);
01122     printf("%30s","UDP_Socket_Client_Server_Test: ");
01123     printf("%2ld Server %2ld Clients\n",1l, num_udp_clients);
01124     printf("%30s %2ld datagrams_per_client %4ld bytes_per_datagram\n",":",
01125         num_udp_datagrams_per_client, udp_datagram_size);
01126 
01127     return 0;
01128 }
01129 
01130 static PRFileDesc *small_file_fd, *large_file_fd;
01131 static void *small_file_addr, *small_file_header, *large_file_addr;
01132 static void *small_file_trailer, *large_file_header, *large_file_trailer;
01133 /*
01134  * TransmitFile_Client
01135  *    Client Thread
01136  */
01137 static void
01138 TransmitFile_Client(void *arg)
01139 {
01140     PRFileDesc *sockfd;
01141     union PRNetAddr netaddr;
01142     char *small_buf, *large_buf;
01143     Client_Param *cp = (Client_Param *) arg;
01144        PRInt32 rlen;
01145 
01146     small_buf = (char*)PR_Malloc(SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE +
01147                                                                       SMALL_FILE_TRAILER_SIZE);
01148     if (small_buf == NULL) {
01149         fprintf(stderr,"prsocket_test: failed to alloc buffer\n");
01150         failed_already=1;
01151         return;
01152     }
01153     large_buf = (char*)PR_Malloc(LARGE_FILE_SIZE + LARGE_FILE_HEADER_SIZE +
01154                                                                                     LARGE_FILE_TRAILER_SIZE);
01155     if (large_buf == NULL) {
01156         fprintf(stderr,"prsocket_test: failed to alloc buffer\n");
01157         failed_already=1;
01158         return;
01159     }
01160     netaddr.inet.family = cp->server_addr.inet.family;
01161     netaddr.inet.port = cp->server_addr.inet.port;
01162     netaddr.inet.ip = cp->server_addr.inet.ip;
01163 
01164     if ((sockfd = PR_NewTCPSocket()) == NULL) {
01165         fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
01166         failed_already=1;
01167         return;
01168     }
01169 
01170     if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){
01171         fprintf(stderr,"prsocket_test: PR_Connect failed\n");
01172         failed_already=1;
01173         return;
01174     }
01175     /*
01176      * read the small file and verify the data
01177      */
01178     if (readn(sockfd, small_buf, SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)
01179         != (SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)) {
01180         fprintf(stderr,
01181             "prsocket_test: TransmitFile_Client failed to receive file\n");
01182         failed_already=1;
01183         return;
01184     }
01185 #ifdef XP_UNIX
01186     if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){
01187         fprintf(stderr,
01188             "prsocket_test: TransmitFile_Client ERROR - small file header data corruption\n");
01189         failed_already=1;
01190         return;
01191     }
01192     if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE,
01193         SMALL_FILE_SIZE) != 0) {
01194         fprintf(stderr,
01195             "prsocket_test: TransmitFile_Client ERROR - small file data corruption\n");
01196         failed_already=1;
01197         return;
01198     }
01199 #endif
01200     /*
01201      * read the large file and verify the data
01202      */
01203     if (readn(sockfd, large_buf, LARGE_FILE_SIZE) != LARGE_FILE_SIZE) {
01204         fprintf(stderr,
01205             "prsocket_test: TransmitFile_Client failed to receive file\n");
01206         failed_already=1;
01207         return;
01208     }
01209 #ifdef XP_UNIX
01210     if (memcmp(large_file_addr, large_buf, LARGE_FILE_SIZE) != 0) {
01211         fprintf(stderr,
01212             "prsocket_test: TransmitFile_Client ERROR - large file data corruption\n");
01213         failed_already=1;
01214     }
01215 #endif
01216 
01217 
01218        /*
01219         * receive data from PR_SendFile
01220         */
01221        /*
01222         * case 1: small file with header and trailer
01223         */
01224     rlen = SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE +
01225                                                                SMALL_FILE_TRAILER_SIZE;
01226     if (readn(sockfd, small_buf, rlen) != rlen) {
01227         fprintf(stderr,
01228             "prsocket_test: SendFile_Client failed to receive file\n");
01229         failed_already=1;
01230         return;
01231     }
01232 #ifdef XP_UNIX
01233     if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){
01234         fprintf(stderr,
01235             "SendFile 1. ERROR - small file header corruption\n");
01236         failed_already=1;
01237         return;
01238     }
01239     if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE,
01240                                                                SMALL_FILE_SIZE) != 0) {
01241         fprintf(stderr,
01242             "SendFile 1. ERROR - small file data corruption\n");
01243         failed_already=1;
01244         return;
01245     }
01246     if (memcmp(small_file_trailer,
01247                             small_buf + SMALL_FILE_HEADER_SIZE + SMALL_FILE_SIZE,
01248                                    SMALL_FILE_TRAILER_SIZE) != 0) {
01249         fprintf(stderr,
01250             "SendFile 1. ERROR - small file trailer corruption\n");
01251         failed_already=1;
01252         return;
01253     }
01254 #endif
01255        /*
01256         * case 2: partial large file at zero offset, file with header and trailer
01257         */
01258     rlen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE +
01259                                                                LARGE_FILE_TRAILER_SIZE;
01260     if (readn(sockfd, large_buf, rlen) != rlen) {
01261         fprintf(stderr,
01262             "prsocket_test: SendFile_Client failed to receive file\n");
01263         failed_already=1;
01264         return;
01265     }
01266 #ifdef XP_UNIX
01267     if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){
01268         fprintf(stderr,
01269             "SendFile 2. ERROR - large file header corruption\n");
01270         failed_already=1;
01271         return;
01272     }
01273     if (memcmp(large_file_addr, large_buf + LARGE_FILE_HEADER_SIZE,
01274                                                                LARGE_FILE_LEN_1) != 0) {
01275         fprintf(stderr,
01276             "SendFile 2. ERROR - large file data corruption\n");
01277         failed_already=1;
01278         return;
01279     }
01280     if (memcmp(large_file_trailer,
01281                             large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_1,
01282                                    LARGE_FILE_TRAILER_SIZE) != 0) {
01283         fprintf(stderr,
01284             "SendFile 2. ERROR - large file trailer corruption\n");
01285         failed_already=1;
01286         return;
01287     }
01288 #endif
01289        /*
01290         * case 3: partial small file at non-zero offset, with header
01291         */
01292     rlen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE;
01293     if (readn(sockfd, small_buf, rlen) != rlen) {
01294         fprintf(stderr,
01295             "prsocket_test: SendFile_Client failed to receive file\n");
01296         failed_already=1;
01297         return;
01298     }
01299 #ifdef XP_UNIX
01300     if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){
01301         fprintf(stderr,
01302             "SendFile 3. ERROR - small file header corruption\n");
01303         failed_already=1;
01304         return;
01305     }
01306     if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_1,
01307                             small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_1) != 0) {
01308         fprintf(stderr,
01309             "SendFile 3. ERROR - small file data corruption\n");
01310         failed_already=1;
01311         return;
01312     }
01313 #endif
01314        /*
01315         * case 4: partial small file at non-zero offset, with trailer
01316         */
01317     rlen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE;
01318     if (readn(sockfd, small_buf, rlen) != rlen) {
01319         fprintf(stderr,
01320             "prsocket_test: SendFile_Client failed to receive file\n");
01321         failed_already=1;
01322         return;
01323     }
01324 #ifdef XP_UNIX
01325     if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_2, small_buf,
01326                                                                SMALL_FILE_LEN_2) != 0) {
01327         fprintf(stderr,
01328             "SendFile 4. ERROR - small file data corruption\n");
01329         failed_already=1;
01330         return;
01331     }
01332     if (memcmp(small_file_trailer, small_buf + SMALL_FILE_LEN_2,
01333                                    SMALL_FILE_TRAILER_SIZE) != 0) {
01334         fprintf(stderr,
01335             "SendFile 4. ERROR - small file trailer corruption\n");
01336         failed_already=1;
01337         return;
01338     }
01339 #endif
01340        /*
01341         * case 5: partial large file at non-zero offset, file with header
01342         */
01343     rlen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE;
01344     if (readn(sockfd, large_buf, rlen) != rlen) {
01345         fprintf(stderr,
01346             "prsocket_test: SendFile_Client failed to receive file\n");
01347         failed_already=1;
01348         return;
01349     }
01350 #ifdef XP_UNIX
01351     if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){
01352         fprintf(stderr,
01353             "SendFile 5. ERROR - large file header corruption\n");
01354         failed_already=1;
01355         return;
01356     }
01357     if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_2,
01358                                    large_buf + LARGE_FILE_HEADER_SIZE,
01359                                                                LARGE_FILE_LEN_2) != 0) {
01360         fprintf(stderr,
01361             "SendFile 5. ERROR - large file data corruption\n");
01362         failed_already=1;
01363         return;
01364     }
01365 #endif
01366        /*
01367         * case 6: partial small file at non-zero offset, with header
01368         */
01369     rlen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE;
01370     if (readn(sockfd, small_buf, rlen) != rlen) {
01371         fprintf(stderr,
01372             "prsocket_test: SendFile_Client failed to receive file\n");
01373         failed_already=1;
01374         return;
01375     }
01376 #ifdef XP_UNIX
01377     if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){
01378         fprintf(stderr,
01379             "SendFile 6. ERROR - small file header corruption\n");
01380         return;
01381     }
01382     if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_3,
01383                             small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_3) != 0) {
01384 #if 0
01385               char *i, *j;
01386               int k;
01387 
01388               i = (char *) small_file_addr + SMALL_FILE_OFFSET_3;
01389               j = small_buf + SMALL_FILE_HEADER_SIZE;
01390               k = SMALL_FILE_LEN_3;
01391               while (k-- > 0) {
01392                      if (*i++ != *j++)
01393                      printf("i = %d j = %d\n",
01394                             (int) (i - ((char *) small_file_addr + SMALL_FILE_OFFSET_3)),
01395                             (int) (j - (small_buf + SMALL_FILE_HEADER_SIZE)));
01396               }
01397 #endif
01398         fprintf(stderr,
01399             "SendFile 6. ERROR - small file data corruption\n");
01400         failed_already=1;
01401         return;
01402     }
01403 #endif
01404        /*
01405         * case 7: partial large file at non-zero offset, with header
01406         */
01407     rlen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE;
01408     if (readn(sockfd, large_buf, rlen) != rlen) {
01409         fprintf(stderr,
01410             "prsocket_test: SendFile_Client failed to receive file\n");
01411         failed_already=1;
01412         return;
01413     }
01414 #ifdef XP_UNIX
01415     if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){
01416         fprintf(stderr,
01417             "SendFile 7. ERROR - large file header corruption\n");
01418         failed_already=1;
01419         return;
01420     }
01421     if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_3,
01422                                    large_buf + LARGE_FILE_HEADER_SIZE,
01423                                                                LARGE_FILE_LEN_3) != 0) {
01424         fprintf(stderr,
01425             "SendFile 7. ERROR - large file data corruption\n");
01426         failed_already=1;
01427         return;
01428     }
01429 #endif
01430        /*
01431         * case 8: partial large file at non-zero, page-aligned offset, with
01432         * header and trailer
01433         */
01434     rlen = LARGE_FILE_LEN_4 + LARGE_FILE_HEADER_SIZE +
01435                                                                LARGE_FILE_TRAILER_SIZE;
01436     if (readn(sockfd, large_buf, rlen) != rlen) {
01437         fprintf(stderr,
01438             "prsocket_test: SendFile_Client failed to receive file\n");
01439         failed_already=1;
01440         return;
01441     }
01442 #ifdef XP_UNIX
01443     if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){
01444         fprintf(stderr,
01445             "SendFile 2. ERROR - large file header corruption\n");
01446         failed_already=1;
01447         return;
01448     }
01449     if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_4,
01450                             large_buf + LARGE_FILE_HEADER_SIZE,
01451                                                                LARGE_FILE_LEN_4) != 0) {
01452         fprintf(stderr,
01453             "SendFile 2. ERROR - large file data corruption\n");
01454         failed_already=1;
01455         return;
01456     }
01457     if (memcmp(large_file_trailer,
01458                             large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_4,
01459                                    LARGE_FILE_TRAILER_SIZE) != 0) {
01460         fprintf(stderr,
01461             "SendFile 2. ERROR - large file trailer corruption\n");
01462         failed_already=1;
01463         return;
01464     }
01465 #endif
01466     PR_DELETE(small_buf);
01467     PR_DELETE(large_buf);
01468     PR_Close(sockfd);
01469 
01470 
01471     /*
01472      * Decrement exit_counter and notify parent thread
01473      */
01474 
01475     PR_EnterMonitor(cp->exit_mon);
01476     --(*cp->exit_counter);
01477     PR_Notify(cp->exit_mon);
01478     PR_ExitMonitor(cp->exit_mon);
01479     DPRINTF(("TransmitFile_Client [0x%lx] exiting\n", PR_GetCurrentThread()));
01480 }
01481 
01482 /*
01483  * Serve_TransmitFile_Client
01484  *    Thread, started by the server, for serving a client connection.
01485  *    Trasmits a small file, with a header, and a large file, without
01486  *    a header
01487  */
01488 static void
01489 Serve_TransmitFile_Client(void *arg)
01490 {
01491     Serve_Client_Param *scp = (Serve_Client_Param *) arg;
01492     PRFileDesc *sockfd;
01493     PRInt32 bytes;
01494     PRFileDesc *local_small_file_fd=NULL;
01495     PRFileDesc *local_large_file_fd=NULL;
01496        PRSendFileData sfd;
01497        PRInt32 slen;
01498 
01499     sockfd = scp->sockfd;
01500     local_small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDONLY,0);
01501 
01502     if (local_small_file_fd == NULL) {
01503         fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n",
01504             SMALL_FILE_NAME);
01505         failed_already=1;
01506         goto done;
01507     }
01508     local_large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDONLY,0);
01509 
01510     if (local_large_file_fd == NULL) {
01511         fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n",
01512             LARGE_FILE_NAME);
01513         failed_already=1;
01514         goto done;
01515     }
01516     bytes = PR_TransmitFile(sockfd, local_small_file_fd, small_file_header,
01517         SMALL_FILE_HEADER_SIZE, PR_TRANSMITFILE_KEEP_OPEN,
01518         PR_INTERVAL_NO_TIMEOUT);
01519     if (bytes != (SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE)) {
01520         fprintf(stderr,
01521             "prsocet_test: PR_TransmitFile failed: (%ld, %ld)\n",
01522             PR_GetError(), PR_GetOSError());
01523         failed_already=1;
01524     }
01525     bytes = PR_TransmitFile(sockfd, local_large_file_fd, NULL, 0,
01526         PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT);
01527     if (bytes != LARGE_FILE_SIZE) {
01528         fprintf(stderr,
01529             "prsocket_test: PR_TransmitFile failed: (%ld, %ld)\n",
01530             PR_GetError(), PR_GetOSError());
01531         failed_already=1;
01532     }
01533 
01534        /*
01535         * PR_SendFile test cases
01536         */
01537 
01538        /*
01539         * case 1: small file with header and trailer
01540         */
01541        sfd.fd = local_small_file_fd;
01542        sfd.file_offset = 0;
01543        sfd.file_nbytes = 0;
01544        sfd.header = small_file_header;
01545        sfd.hlen = SMALL_FILE_HEADER_SIZE;
01546        sfd.trailer = small_file_trailer;
01547        sfd.tlen = SMALL_FILE_TRAILER_SIZE;
01548     bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
01549                                    PR_INTERVAL_NO_TIMEOUT);
01550     slen = SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE +
01551                                           SMALL_FILE_TRAILER_SIZE;
01552     if (bytes != slen) {
01553         fprintf(stderr,
01554                      "socket: Error - 1. PR_SendFile  send_size = %d, bytes sent = %d\n",
01555                                                                slen, bytes);
01556         fprintf(stderr,
01557             "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
01558             PR_GetError(), PR_GetOSError());
01559         failed_already=1;
01560     }
01561 
01562        /*
01563         * case 2: partial large file at zero offset, file with header and trailer
01564         */
01565        sfd.fd = local_large_file_fd;
01566        sfd.file_offset = 0;
01567        sfd.file_nbytes = LARGE_FILE_LEN_1;
01568        sfd.header = large_file_header;
01569        sfd.hlen = LARGE_FILE_HEADER_SIZE;
01570        sfd.trailer = large_file_trailer;
01571        sfd.tlen = LARGE_FILE_TRAILER_SIZE;
01572     bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
01573                                    PR_INTERVAL_NO_TIMEOUT);
01574     slen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE +
01575                                           LARGE_FILE_TRAILER_SIZE;
01576     if (bytes != slen) {
01577         fprintf(stderr,
01578                      "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n",
01579                                                                slen, bytes);
01580         fprintf(stderr,
01581             "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
01582             PR_GetError(), PR_GetOSError());
01583         failed_already=1;
01584     }
01585        /*
01586         * case 3: partial small file at non-zero offset, with header
01587         */
01588        sfd.fd = local_small_file_fd;
01589        sfd.file_offset = SMALL_FILE_OFFSET_1;
01590        sfd.file_nbytes = SMALL_FILE_LEN_1;
01591        sfd.header = small_file_header;
01592        sfd.hlen = SMALL_FILE_HEADER_SIZE;
01593        sfd.trailer = NULL;
01594        sfd.tlen = 0;
01595     bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
01596                                    PR_INTERVAL_NO_TIMEOUT);
01597     slen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE;
01598     if (bytes != slen) {
01599         fprintf(stderr,
01600                      "socket: Error - 3. PR_SendFile send_size = %d, bytes sent = %d\n",
01601                                                                slen, bytes);
01602         fprintf(stderr,
01603             "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
01604             PR_GetError(), PR_GetOSError());
01605         failed_already=1;
01606     }
01607        /*
01608         * case 4: partial small file at non-zero offset, with trailer
01609         */
01610        sfd.fd = local_small_file_fd;
01611        sfd.file_offset = SMALL_FILE_OFFSET_2;
01612        sfd.file_nbytes = SMALL_FILE_LEN_2;
01613        sfd.header = NULL;
01614        sfd.hlen = 0;
01615        sfd.trailer = small_file_trailer;
01616        sfd.tlen = SMALL_FILE_TRAILER_SIZE;
01617     bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
01618                                    PR_INTERVAL_NO_TIMEOUT);
01619     slen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE;
01620     if (bytes != slen) {
01621         fprintf(stderr,
01622                      "socket: Error - 4. PR_SendFile send_size = %d, bytes sent = %d\n",
01623                                                                slen, bytes);
01624         fprintf(stderr,
01625             "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
01626             PR_GetError(), PR_GetOSError());
01627         failed_already=1;
01628     }
01629        /*
01630         * case 5: partial large file at non-zero offset, file with header
01631         */
01632        sfd.fd = local_large_file_fd;
01633        sfd.file_offset = LARGE_FILE_OFFSET_2;
01634        sfd.file_nbytes = LARGE_FILE_LEN_2;
01635        sfd.header = large_file_header;
01636        sfd.hlen = LARGE_FILE_HEADER_SIZE;
01637        sfd.trailer = NULL;
01638        sfd.tlen = 0;
01639     bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
01640                                    PR_INTERVAL_NO_TIMEOUT);
01641     slen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE;
01642     if (bytes != slen) {
01643         fprintf(stderr,
01644                      "socket: Error - 5. PR_SendFile send_size = %d, bytes sent = %d\n",
01645                                                                slen, bytes);
01646         fprintf(stderr,
01647             "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
01648             PR_GetError(), PR_GetOSError());
01649         failed_already=1;
01650     }
01651        /*
01652         * case 6: partial small file from non-zero offset till end of file, with header
01653         */
01654        sfd.fd = local_small_file_fd;
01655        sfd.file_offset = SMALL_FILE_OFFSET_3;
01656        sfd.file_nbytes = 0;                      /* data from offset to end-of-file */
01657        sfd.header = small_file_header;
01658        sfd.hlen = SMALL_FILE_HEADER_SIZE;
01659        sfd.trailer = NULL;
01660        sfd.tlen = 0;
01661     bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
01662                                    PR_INTERVAL_NO_TIMEOUT);
01663     slen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE;
01664     if (bytes != slen) {
01665         fprintf(stderr,
01666                      "socket: Error - 6. PR_SendFile send_size = %d, bytes sent = %d\n",
01667                                                                slen, bytes);
01668         fprintf(stderr,
01669             "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
01670             PR_GetError(), PR_GetOSError());
01671         failed_already=1;
01672     }
01673        /*
01674         * case 7: partial large file at non-zero offset till end-of-file, with header
01675         */
01676        sfd.fd = local_large_file_fd;
01677        sfd.file_offset = LARGE_FILE_OFFSET_3;
01678        sfd.file_nbytes = 0;                      /* data until end-of-file */
01679        sfd.header = large_file_header;
01680        sfd.hlen = LARGE_FILE_HEADER_SIZE;
01681        sfd.trailer = NULL;
01682        sfd.tlen = 0;
01683     bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
01684                                                                       PR_INTERVAL_NO_TIMEOUT);
01685     slen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE;
01686     if (bytes != slen) {
01687         fprintf(stderr,
01688                      "socket: Error - 7. PR_SendFile send_size = %d, bytes sent = %d\n",
01689                                                                slen, bytes);
01690         fprintf(stderr,
01691             "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
01692             PR_GetError(), PR_GetOSError());
01693         failed_already=1;
01694     }
01695        /*
01696         * case 8: partial large file at non-zero page-aligned offset,
01697         * with header and trailer
01698         */
01699        sfd.fd = local_large_file_fd;
01700        sfd.file_offset = LARGE_FILE_OFFSET_4;
01701        sfd.file_nbytes = LARGE_FILE_LEN_4;
01702        sfd.header = large_file_header;
01703        sfd.hlen = LARGE_FILE_HEADER_SIZE;
01704        sfd.trailer = large_file_trailer;
01705        sfd.tlen = LARGE_FILE_TRAILER_SIZE;
01706     bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_CLOSE_SOCKET,
01707                                    PR_INTERVAL_NO_TIMEOUT);
01708     slen = LARGE_FILE_LEN_4 + LARGE_FILE_HEADER_SIZE +
01709                                           LARGE_FILE_TRAILER_SIZE;
01710     if (bytes != slen) {
01711         fprintf(stderr,
01712                      "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n",
01713                                                                slen, bytes);
01714         fprintf(stderr,
01715             "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
01716             PR_GetError(), PR_GetOSError());
01717         failed_already=1;
01718     }
01719 done:
01720     if (local_small_file_fd != NULL)
01721         PR_Close(local_small_file_fd);
01722     if (local_large_file_fd != NULL)
01723         PR_Close(local_large_file_fd);
01724 }
01725 
01726 /*
01727  * TransmitFile Server
01728  *    Server Thread
01729  *    Bind an address to a socket and listen for incoming connections
01730  *    Create worker threads to service clients
01731  */
01732 static void
01733 TransmitFile_Server(void *arg)
01734 {
01735     PRThread **t = NULL;  /* an array of PRThread pointers */
01736     Server_Param *sp = (Server_Param *) arg;
01737     Serve_Client_Param *scp;
01738     PRFileDesc *sockfd = NULL, *newsockfd;
01739     PRNetAddr netaddr;
01740     PRInt32 i;
01741 
01742     t = (PRThread**)PR_MALLOC(num_transmitfile_clients * sizeof(PRThread *));
01743     if (t == NULL) {
01744         fprintf(stderr, "prsocket_test: run out of memory\n");
01745         failed_already=1;
01746         goto exit;
01747     }
01748     /*
01749      * Create a tcp socket
01750      */
01751     if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) {
01752         fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n");
01753         failed_already=1;
01754         goto exit;
01755     }
01756     memset(&netaddr, 0 , sizeof(netaddr));
01757     netaddr.inet.family = PR_AF_INET;
01758     netaddr.inet.port = PR_htons(TCP_SERVER_PORT);
01759     netaddr.inet.ip = PR_htonl(PR_INADDR_ANY);
01760     /*
01761      * try a few times to bind server's address, if addresses are in
01762      * use
01763      */
01764     i = 0;
01765     while (PR_Bind(sockfd, &netaddr) < 0) {
01766         if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
01767             netaddr.inet.port += 2;
01768             if (i++ < SERVER_MAX_BIND_COUNT)
01769                 continue;
01770         }
01771         fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
01772         failed_already=1;
01773         perror("PR_Bind");
01774         goto exit;
01775     }
01776 
01777     if (PR_Listen(sockfd, 32) < 0) {
01778         fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n");
01779         failed_already=1;
01780         goto exit;
01781     }
01782 
01783     if (PR_GetSockName(sockfd, &netaddr) < 0) {
01784         fprintf(stderr,
01785             "prsocket_test: ERROR - PR_GetSockName failed\n");
01786         failed_already=1;
01787         goto exit;
01788     }
01789 
01790     DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
01791         netaddr.inet.ip, netaddr.inet.port));
01792     tcp_server_addr.inet.family = netaddr.inet.family;
01793     tcp_server_addr.inet.port = netaddr.inet.port;
01794     tcp_server_addr.inet.ip = netaddr.inet.ip;
01795 
01796     /*
01797      * Wake up parent thread because server address is bound and made
01798      * available in the global variable 'tcp_server_addr'
01799      */
01800     PR_PostSem(sp->addr_sem);
01801 
01802     for (i = 0; i < num_transmitfile_clients ; i++) {
01803         /* test both null and non-null 'addr' argument to PR_Accept */
01804         PRNetAddr *addrp = (i%2 ? &netaddr: NULL);
01805 
01806         if ((newsockfd = PR_Accept(sockfd, addrp,
01807             PR_INTERVAL_NO_TIMEOUT)) == NULL) {
01808             fprintf(stderr,
01809                 "prsocket_test: ERROR - PR_Accept failed\n");
01810             failed_already=1;
01811             goto exit;
01812         }
01813         /* test both regular and emulated PR_SendFile */
01814         if (i%2) {
01815             PRFileDesc *layer = PR_CreateIOLayerStub(
01816                 emuSendFileIdentity, &emuSendFileMethods);
01817             if (layer == NULL) {
01818                 fprintf(stderr,
01819                     "prsocket_test: ERROR - PR_CreateIOLayerStub failed\n");
01820                 failed_already=1;
01821                 goto exit;
01822             }
01823             if (PR_PushIOLayer(newsockfd, PR_TOP_IO_LAYER, layer)
01824                     == PR_FAILURE) {
01825                 fprintf(stderr,
01826                     "prsocket_test: ERROR - PR_PushIOLayer failed\n");
01827                 failed_already=1;
01828                 goto exit;
01829             }
01830         }
01831         scp = PR_NEW(Serve_Client_Param);
01832         if (scp == NULL) {
01833             fprintf(stderr,"prsocket_test: PR_NEW failed\n");
01834             failed_already=1;
01835             goto exit;
01836         }
01837 
01838         /*
01839          * Start a Serve_Client thread for each incoming connection
01840          */
01841         scp->sockfd = newsockfd;
01842         scp->datalen = sp->datalen;
01843 
01844         t[i] = PR_CreateThread(PR_USER_THREAD,
01845             Serve_TransmitFile_Client, (void *)scp, 
01846             PR_PRIORITY_NORMAL,
01847             PR_LOCAL_THREAD,
01848             PR_JOINABLE_THREAD,
01849             0);
01850         if (t[i] == NULL) {
01851             fprintf(stderr,
01852                 "prsocket_test: PR_CreateThread failed\n");
01853             failed_already=1;
01854             goto exit;
01855         }
01856         DPRINTF(("TransmitFile_Server: Created Serve_TransmitFile_Client = 0x%lx\n", t));
01857     }
01858 
01859     /*
01860      * Wait for all the worker threads to end, so that we know
01861      * they are no longer using the small and large file fd's.
01862      */
01863 
01864     for (i = 0; i < num_transmitfile_clients; i++) {
01865         PR_JoinThread(t[i]);
01866     }
01867 
01868 exit:
01869     if (t) {
01870         PR_DELETE(t);
01871     }
01872     if (sockfd) {
01873         PR_Close(sockfd);
01874     }
01875 
01876     /*
01877      * Decrement exit_counter and notify parent thread
01878      */
01879 
01880     PR_EnterMonitor(sp->exit_mon);
01881     --(*sp->exit_counter);
01882     PR_Notify(sp->exit_mon);
01883     PR_ExitMonitor(sp->exit_mon);
01884     DPRINTF(("TransmitFile_Server [0x%lx] exiting\n", PR_GetCurrentThread()));
01885 }
01886 
01887 /*
01888  * Socket_Misc_Test    - test miscellaneous functions 
01889  *    
01890  */
01891 static PRInt32
01892 Socket_Misc_Test(void)
01893 {
01894     PRIntn i, rv = 0, bytes, count, len;
01895     PRThread *t;
01896     PRSemaphore *server_sem;
01897     Server_Param *sparamp;
01898     Client_Param *cparamp;
01899     PRMonitor *mon2;
01900     PRInt32    datalen;
01901 
01902     /*
01903  * We deliberately pick a buffer size that is not a nice multiple
01904  * of 1024.
01905  */
01906 #define TRANSMITFILE_BUF_SIZE    (4 * 1024 - 11)
01907 
01908     typedef struct {
01909         char    data[TRANSMITFILE_BUF_SIZE];
01910     } file_buf;
01911     file_buf *buf = NULL;
01912 
01913     /*
01914      * create file(s) to be transmitted
01915      */
01916     if ((PR_MkDir(TEST_DIR, 0777)) < 0) {
01917         printf("prsocket_test failed to create dir %s\n",TEST_DIR);
01918         failed_already=1;
01919         return -1;
01920     }
01921 
01922     small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777);
01923 
01924     if (small_file_fd == NULL) {
01925         fprintf(stderr,"prsocket_test failed to create/open file %s\n",
01926             SMALL_FILE_NAME);
01927         failed_already=1;
01928         rv = -1;
01929         goto done;
01930     }
01931     buf = PR_NEW(file_buf);
01932     if (buf == NULL) {
01933         fprintf(stderr,"prsocket_test failed to allocate buffer\n");
01934         failed_already=1;
01935         rv = -1;
01936         goto done;
01937     }
01938     /*
01939      * fill in random data
01940      */
01941     for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) {
01942         buf->data[i] = i;
01943     }
01944     count = 0;
01945     do {
01946         len = (SMALL_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ?
01947             TRANSMITFILE_BUF_SIZE : (SMALL_FILE_SIZE - count);
01948         bytes = PR_Write(small_file_fd, buf->data, len);
01949         if (bytes <= 0) {
01950             fprintf(stderr,
01951                 "prsocket_test failed to write to file %s\n",
01952                 SMALL_FILE_NAME);
01953             failed_already=1;
01954             rv = -1;
01955             goto done;
01956         }
01957         count += bytes;
01958     } while (count < SMALL_FILE_SIZE);
01959 #ifdef XP_UNIX
01960     /*
01961      * map the small file; used in checking for data corruption
01962      */
01963     small_file_addr = mmap(0, SMALL_FILE_SIZE, PROT_READ,
01964         MAP_SHARED, small_file_fd->secret->md.osfd, 0);
01965     if (small_file_addr == (void *) -1) {
01966         fprintf(stderr,"prsocket_test failed to mmap file %s\n",
01967             SMALL_FILE_NAME);
01968         failed_already=1;
01969         rv = -1;
01970         goto done;
01971     }
01972 #endif
01973     /*
01974      * header for small file
01975      */
01976     small_file_header = PR_MALLOC(SMALL_FILE_HEADER_SIZE);
01977     if (small_file_header == NULL) {
01978         fprintf(stderr,"prsocket_test failed to malloc header file\n");
01979         failed_already=1;
01980         rv = -1;
01981         goto done;
01982     }
01983     memset(small_file_header, (int) PR_IntervalNow(),
01984         SMALL_FILE_HEADER_SIZE);
01985     /*
01986      * trailer for small file
01987      */
01988     small_file_trailer = PR_MALLOC(SMALL_FILE_TRAILER_SIZE);
01989     if (small_file_trailer == NULL) {
01990         fprintf(stderr,"prsocket_test failed to malloc header trailer\n");
01991         failed_already=1;
01992         rv = -1;
01993         goto done;
01994     }
01995     memset(small_file_trailer, (int) PR_IntervalNow(),
01996         SMALL_FILE_TRAILER_SIZE);
01997     /*
01998      * setup large file
01999      */
02000     large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777);
02001 
02002     if (large_file_fd == NULL) {
02003         fprintf(stderr,"prsocket_test failed to create/open file %s\n",
02004             LARGE_FILE_NAME);
02005         failed_already=1;
02006         rv = -1;
02007         goto done;
02008     }
02009     /*
02010      * fill in random data
02011      */
02012     for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) {
02013         buf->data[i] = i;
02014     }
02015     count = 0;
02016     do {
02017         len = (LARGE_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ?
02018             TRANSMITFILE_BUF_SIZE : (LARGE_FILE_SIZE - count);
02019         bytes = PR_Write(large_file_fd, buf->data, len);
02020         if (bytes <= 0) {
02021             fprintf(stderr,
02022                 "prsocket_test failed to write to file %s: (%ld, %ld)\n",
02023                 LARGE_FILE_NAME,
02024                 PR_GetError(), PR_GetOSError());
02025             failed_already=1;
02026             rv = -1;
02027             goto done;
02028         }
02029         count += bytes;
02030     } while (count < LARGE_FILE_SIZE);
02031 #ifdef XP_UNIX
02032     /*
02033      * map the large file; used in checking for data corruption
02034      */
02035     large_file_addr = mmap(0, LARGE_FILE_SIZE, PROT_READ,
02036         MAP_SHARED, large_file_fd->secret->md.osfd, 0);
02037     if (large_file_addr == (void *) -1) {
02038         fprintf(stderr,"prsocket_test failed to mmap file %s\n",
02039             LARGE_FILE_NAME);
02040         failed_already=1;
02041         rv = -1;
02042         goto done;
02043     }
02044 #endif
02045     /*
02046      * header for large file
02047      */
02048     large_file_header = PR_MALLOC(LARGE_FILE_HEADER_SIZE);
02049     if (large_file_header == NULL) {
02050         fprintf(stderr,"prsocket_test failed to malloc header file\n");
02051         failed_already=1;
02052         rv = -1;
02053         goto done;
02054     }
02055     memset(large_file_header, (int) PR_IntervalNow(),
02056         LARGE_FILE_HEADER_SIZE);
02057     /*
02058      * trailer for large file
02059      */
02060     large_file_trailer = PR_MALLOC(LARGE_FILE_TRAILER_SIZE);
02061     if (large_file_trailer == NULL) {
02062         fprintf(stderr,"prsocket_test failed to malloc header trailer\n");
02063         failed_already=1;
02064         rv = -1;
02065         goto done;
02066     }
02067     memset(large_file_trailer, (int) PR_IntervalNow(),
02068         LARGE_FILE_TRAILER_SIZE);
02069 
02070     datalen = tcp_mesg_size;
02071     thread_count = 0;
02072     /*
02073      * start the server thread
02074      */
02075     sparamp = PR_NEW(Server_Param);
02076     if (sparamp == NULL) {
02077         fprintf(stderr,"prsocket_test: PR_NEW failed\n");
02078         failed_already=1;
02079         rv = -1;
02080         goto done;
02081     }
02082     server_sem = PR_NewSem(0);
02083     if (server_sem == NULL) {
02084         fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
02085         failed_already=1;
02086         rv = -1;
02087         goto done;
02088     }
02089     mon2 = PR_NewMonitor();
02090     if (mon2 == NULL) {
02091         fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
02092         failed_already=1;
02093         rv = -1;
02094         goto done;
02095     }
02096     PR_EnterMonitor(mon2);
02097 
02098     sparamp->addr_sem = server_sem;
02099     sparamp->exit_mon = mon2;
02100     sparamp->exit_counter = &thread_count;
02101     sparamp->datalen = datalen;
02102     t = PR_CreateThread(PR_USER_THREAD,
02103         TransmitFile_Server, (void *)sparamp, 
02104         PR_PRIORITY_NORMAL,
02105         PR_LOCAL_THREAD,
02106         PR_UNJOINABLE_THREAD,
02107         0);
02108     if (t == NULL) {
02109         fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
02110         failed_already=1;
02111         rv = -1;
02112         goto done;
02113     }
02114     DPRINTF(("Created TCP server = 0x%x\n", t));
02115     thread_count++;
02116 
02117     /*
02118      * wait till the server address is setup
02119      */
02120     PR_WaitSem(server_sem);
02121 
02122     /*
02123      * Now start a bunch of client threads
02124      */
02125 
02126     cparamp = PR_NEW(Client_Param);
02127     if (cparamp == NULL) {
02128         fprintf(stderr,"prsocket_test: PR_NEW failed\n");
02129         failed_already=1;
02130         rv = -1;
02131         goto done;
02132     }
02133     cparamp->server_addr = tcp_server_addr;
02134     cparamp->server_addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
02135     cparamp->exit_mon = mon2;
02136     cparamp->exit_counter = &thread_count;
02137     cparamp->datalen = datalen;
02138     for (i = 0; i < num_transmitfile_clients; i++) {
02139         t = create_new_thread(PR_USER_THREAD,
02140             TransmitFile_Client, (void *) cparamp,
02141             PR_PRIORITY_NORMAL,
02142             PR_LOCAL_THREAD,
02143             PR_UNJOINABLE_THREAD,
02144             0, i);
02145         if (t == NULL) {
02146             fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
02147             rv = -1;
02148             failed_already=1;
02149             goto done;
02150         }
02151         DPRINTF(("Created TransmitFile client = 0x%lx\n", t));
02152         thread_count++;
02153     }
02154     /* Wait for server and client threads to exit */
02155     while (thread_count) {
02156         PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
02157         DPRINTF(("Socket_Misc_Test - thread_count  = %d\n", thread_count));
02158     }
02159     PR_ExitMonitor(mon2);
02160 done:
02161     if (buf) {
02162         PR_DELETE(buf);
02163     }
02164 #ifdef XP_UNIX
02165     munmap((char*)small_file_addr, SMALL_FILE_SIZE);
02166     munmap((char*)large_file_addr, LARGE_FILE_SIZE);
02167 #endif
02168     PR_Close(small_file_fd);
02169     PR_Close(large_file_fd);
02170     if ((PR_Delete(SMALL_FILE_NAME)) == PR_FAILURE) {
02171         fprintf(stderr,"prsocket_test: failed to unlink file %s\n",
02172             SMALL_FILE_NAME);
02173         failed_already=1;
02174     }
02175     if ((PR_Delete(LARGE_FILE_NAME)) == PR_FAILURE) {
02176         fprintf(stderr,"prsocket_test: failed to unlink file %s\n",
02177             LARGE_FILE_NAME);
02178         failed_already=1;
02179     }
02180     if ((PR_RmDir(TEST_DIR)) == PR_FAILURE) {
02181         fprintf(stderr,"prsocket_test failed to rmdir %s: (%ld, %ld)\n",
02182             TEST_DIR, PR_GetError(), PR_GetOSError());
02183         failed_already=1;
02184     }
02185 
02186     printf("%-29s%s","Socket_Misc_Test",":");
02187     printf("%2d Server %2d Clients\n",1, num_transmitfile_clients);
02188     printf("%30s Sizes of Transmitted Files  - %4d KB, %2d MB \n",":",
02189         SMALL_FILE_SIZE/1024, LARGE_FILE_SIZE/(1024 * 1024));
02190 
02191 
02192     return rv;
02193 }
02194 /************************************************************************/
02195 
02196 /*
02197  * Test Socket NSPR APIs
02198  */
02199 
02200 int
02201 main(int argc, char **argv)
02202 {
02203     /*
02204      * -d           debug mode
02205      */
02206 
02207     PLOptStatus os;
02208     PLOptState *opt = PL_CreateOptState(argc, argv, "d");
02209     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
02210     {
02211         if (PL_OPT_BAD == os) continue;
02212         switch (opt->option)
02213         {
02214         case 'd':  /* debug mode */
02215             _debug_on = 1;
02216             break;
02217         default:
02218             break;
02219         }
02220     }
02221     PL_DestroyOptState(opt);
02222 
02223     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
02224     PR_STDIO_INIT();
02225 
02226 #ifdef XP_MAC
02227     SetupMacPrintfLog("socket.log");
02228 #endif
02229     PR_SetConcurrency(4);
02230 
02231     emuSendFileIdentity = PR_GetUniqueIdentity("Emulated SendFile");
02232     emuSendFileMethods = *PR_GetDefaultIOMethods();
02233     emuSendFileMethods.transmitfile = emu_TransmitFile;
02234     emuSendFileMethods.sendfile = emu_SendFile;
02235 
02236     /*
02237      * run client-server test with TCP, Ipv4-Ipv4
02238      */
02239        printf("TCP Client/Server Test - IPv4/Ipv4\n");
02240     if (TCP_Socket_Client_Server_Test() < 0) {
02241         printf("TCP_Socket_Client_Server_Test failed\n");
02242         goto done;
02243     } else
02244         printf("TCP_Socket_Client_Server_Test Passed\n");
02245     /*
02246      * client-server test, Ipv6-Ipv4
02247      */
02248        client_domain = PR_AF_INET6;
02249        printf("TCP Client/Server Test - IPv6/Ipv4\n");
02250     if (TCP_Socket_Client_Server_Test() < 0) {
02251         printf("TCP_Socket_Client_Server_Test failed\n");
02252         goto done;
02253     } else
02254         printf("TCP_Socket_Client_Server_Test Passed\n");
02255     /*
02256      * client-server test, Ipv4-Ipv6
02257      */
02258        client_domain = PR_AF_INET;
02259        server_domain = PR_AF_INET6;
02260        printf("TCP Client/Server Test - IPv4/Ipv6\n");
02261     if (TCP_Socket_Client_Server_Test() < 0) {
02262         printf("TCP_Socket_Client_Server_Test failed\n");
02263         goto done;
02264     } else
02265         printf("TCP_Socket_Client_Server_Test Passed\n");
02266     /*
02267      * client-server test, Ipv6-Ipv6
02268      */
02269        client_domain = PR_AF_INET6;
02270        server_domain = PR_AF_INET6;
02271        printf("TCP Client/Server Test - IPv6/Ipv6\n");
02272     if (TCP_Socket_Client_Server_Test() < 0) {
02273         printf("TCP_Socket_Client_Server_Test failed\n");
02274         goto done;
02275     } else
02276         printf("TCP_Socket_Client_Server_Test Passed\n");
02277        test_cancelio = 0;
02278     /*
02279      * run client-server test with UDP, IPv4/IPv4
02280      */
02281        printf("UDP Client/Server Test - IPv4/Ipv4\n");
02282        client_domain = PR_AF_INET;
02283        server_domain = PR_AF_INET;
02284     if (UDP_Socket_Client_Server_Test() < 0) {
02285         printf("UDP_Socket_Client_Server_Test failed\n");
02286         goto done;
02287     } else
02288         printf("UDP_Socket_Client_Server_Test Passed\n");
02289     /*
02290      * run client-server test with UDP, IPv6/IPv4
02291      */
02292        printf("UDP Client/Server Test - IPv6/Ipv4\n");
02293        client_domain = PR_AF_INET6;
02294        server_domain = PR_AF_INET;
02295     if (UDP_Socket_Client_Server_Test() < 0) {
02296         printf("UDP_Socket_Client_Server_Test failed\n");
02297         goto done;
02298     } else
02299         printf("UDP_Socket_Client_Server_Test Passed\n");
02300     /*
02301      * run client-server test with UDP,IPv4-IPv6
02302      */
02303        printf("UDP Client/Server Test - IPv4/Ipv6\n");
02304        client_domain = PR_AF_INET;
02305        server_domain = PR_AF_INET6;
02306     if (UDP_Socket_Client_Server_Test() < 0) {
02307         printf("UDP_Socket_Client_Server_Test failed\n");
02308         goto done;
02309     } else
02310         printf("UDP_Socket_Client_Server_Test Passed\n");
02311     /*
02312      * run client-server test with UDP,IPv6-IPv6
02313      */
02314        printf("UDP Client/Server Test - IPv6/Ipv6\n");
02315        client_domain = PR_AF_INET6;
02316        server_domain = PR_AF_INET6;
02317     if (UDP_Socket_Client_Server_Test() < 0) {
02318         printf("UDP_Socket_Client_Server_Test failed\n");
02319         goto done;
02320     } else
02321         printf("UDP_Socket_Client_Server_Test Passed\n");
02322     /*
02323      * Misc socket tests - including transmitfile, etc.
02324      */
02325 
02326 #if !defined(WIN16)
02327     /*
02328 ** The 'transmit file' test does not run because
02329 ** transmit file is not implemented in NSPR yet.
02330 **
02331 */
02332     if (Socket_Misc_Test() < 0) {
02333         printf("Socket_Misc_Test failed\n");
02334         failed_already=1;
02335         goto done;
02336     } else
02337         printf("Socket_Misc_Test passed\n");
02338 
02339     /*
02340      * run client-server test with TCP again to test
02341      * recycling used sockets from PR_TransmitFile().
02342      */
02343     if (TCP_Socket_Client_Server_Test() < 0) {
02344         printf("TCP_Socket_Client_Server_Test failed\n");
02345         goto done;
02346     } else
02347         printf("TCP_Socket_Client_Server_Test Passed\n");
02348 #endif
02349 
02350 done:
02351     PR_Cleanup();
02352     if (failed_already) return 1;
02353     else return 0;
02354 }