home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / cltsrv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  41.1 KB  |  1,252 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.  * Notes:
  22.  * [1] lth. The call to Sleep() is a hack to get the test case to run
  23.  * on Windows 95. Without it, the test case fails with an error
  24.  * WSAECONNRESET following a recv() call. The error is caused by the
  25.  * server side thread termination without a shutdown() or closesocket()
  26.  * call. Windows docmunentation suggests that this is predicted
  27.  * behavior; that other platforms get away with it is ... serindipity.
  28.  * The test case should shutdown() or closesocket() before
  29.  * thread termination. I didn't have time to figure out where or how
  30.  * to do it. The Sleep() call inserts enough delay to allow the
  31.  * client side to recv() all his data before the server side thread
  32.  * terminates. Whew! ...
  33.  *
  34.  ** Modification History:
  35.  * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  36.  *             The debug mode will print all of the printfs associated with this test.
  37.  *             The regress mode will be the default mode. Since the regress tool limits
  38.  *           the output to a one line status:PASS or FAIL,all of the printf statements
  39.  *             have been handled with an if (debug_mode) statement. 
  40.  */
  41.  
  42. #include "prclist.h"
  43. #include "prcvar.h"
  44. #include "prerror.h"
  45. #include "prinit.h"
  46. #include "prinrval.h"
  47. #include "prio.h"
  48. #include "prlock.h"
  49. #include "prlog.h"
  50. #include "prtime.h"
  51. #include "prmem.h"
  52. #include "prnetdb.h"
  53. #include "prprf.h"
  54. #include "prthread.h"
  55.  
  56. #include "pprio.h"
  57. #include "primpl.h"
  58.  
  59. #include "plstr.h"
  60. #include "plerror.h"
  61. #include "plgetopt.h"
  62.  
  63. #include <stdlib.h>
  64. #include <string.h>
  65.  
  66.  
  67. #if defined(XP_UNIX)
  68. #include <math.h>
  69. #endif
  70.  
  71. #ifdef XP_MAC
  72. #include "prlog.h"
  73. #define printf PR_LogPrint
  74. #endif
  75.  
  76. /*
  77. ** This is the beginning of the test
  78. */
  79.  
  80. #define RECV_FLAGS 0
  81. #define SEND_FLAGS 0
  82. #define BUFFER_SIZE 1024
  83. #define DEFAULT_BACKLOG 5
  84. #define DEFAULT_PORT 12848
  85. #define DEFAULT_CLIENTS 1
  86. #define ALLOWED_IN_ACCEPT 1
  87. #define DEFAULT_CLIPPING 1000
  88. #define DEFAULT_WORKERS_MIN 1
  89. #define DEFAULT_WORKERS_MAX 1
  90. #define DEFAULT_SERVER "localhost"
  91. #define DEFAULT_EXECUTION_TIME 10
  92. #define DEFAULT_CLIENT_TIMEOUT 4000
  93. #define DEFAULT_SERVER_TIMEOUT 4000
  94. #define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGH
  95.  
  96. typedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t;
  97.  
  98. static void PR_CALLBACK Worker(void *arg);
  99. typedef struct CSPool_s CSPool_t;
  100. typedef struct CSWorker_s CSWorker_t;
  101. typedef struct CSServer_s CSServer_t;
  102. typedef enum Verbosity
  103. {
  104.     TEST_LOG_ALWAYS,
  105.     TEST_LOG_ERROR,
  106.     TEST_LOG_WARNING,
  107.     TEST_LOG_NOTICE,
  108.     TEST_LOG_INFO,
  109.     TEST_LOG_STATUS,
  110.     TEST_LOG_VERBOSE
  111. } Verbosity;
  112.  
  113. static PRInt32 domain = AF_INET;
  114. static PRInt32 protocol = 6;  /* TCP */
  115. static PRFileDesc *debug_out = NULL;
  116. static PRBool debug_mode = PR_FALSE;
  117. static PRBool pthread_stats = PR_FALSE;
  118. static Verbosity verbosity = TEST_LOG_ALWAYS;
  119. static PRThreadScope thread_scope = PR_LOCAL_THREAD;
  120.  
  121. struct CSWorker_s
  122. {
  123.     PRCList element;        /* list of the server's workers */
  124.  
  125.     PRThread *thread;       /* this worker objects thread */
  126.     CSServer_t *server;     /* back pointer to server structure */
  127. };
  128.  
  129. struct CSPool_s
  130. {
  131.     PRCondVar *exiting;
  132.     PRCondVar *acceptComplete;
  133.     PRUint32 accepting, active, workers;
  134. };
  135.  
  136. struct CSServer_s
  137. {
  138.     PRCList list;           /* head of worker list */
  139.  
  140.     PRLock *ml;
  141.     PRThread *thread;       /* the main server thread */
  142.     PRCondVar *stateChange;
  143.  
  144.     PRUint16 port;          /* port we're listening on */
  145.     PRUint32 backlog;       /* size of our listener backlog */
  146.     PRFileDesc *listener;   /* the fd accepting connections */
  147.  
  148.     CSPool_t pool;          /* statistics on worker threads */
  149.     CSState_t state;        /* the server's state */
  150.     struct                  /* controlling worker counts */
  151.     {
  152.         PRUint32 minimum, maximum, accepting;
  153.     } workers;
  154.  
  155.     /* statistics */
  156.     PRIntervalTime started, stopped;
  157.     PRUint32 operations, bytesTransferred;
  158. };
  159.  
  160. typedef struct CSDescriptor_s
  161. {
  162.     PRInt32 size;       /* size of transfer */
  163.     char filename[60];  /* filename, null padded */
  164. } CSDescriptor_t;
  165.  
  166. typedef struct CSClient_s
  167. {
  168.     PRLock *ml;
  169.     PRThread *thread;
  170.     PRCondVar *stateChange;
  171.     PRNetAddr serverAddress;
  172.  
  173.     CSState_t state;
  174.  
  175.     /* statistics */
  176.     PRIntervalTime started, stopped;
  177.     PRUint32 operations, bytesTransferred;
  178. } CSClient_t;
  179.  
  180. #define TEST_LOG(l, p, a) \
  181.     do { \
  182.         if (debug_mode || (p <= verbosity)) printf a; \
  183.     } while (0)
  184.  
  185. PRLogModuleInfo *cltsrv_log_file = NULL;
  186.  
  187. #define MY_ASSERT(_expr) \
  188.     ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
  189.  
  190. #define TEST_ASSERT(_expr) \
  191.     ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
  192.  
  193. static void _MY_Assert(const char *s, const char *file, PRIntn ln)
  194. {
  195.     PL_PrintError(NULL);
  196. #if DEBUG
  197.     PR_Assert(s, file, ln);
  198. #endif
  199. }  /* _MW_Assert */
  200.  
  201. static PRBool Aborted(PRStatus rv)
  202. {
  203.     return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ?
  204.         PR_TRUE : PR_FALSE;
  205. }
  206.  
  207. static void Assert(const char *s, const char *file, PRIntn ln)
  208. {
  209.     PRIntn error = PR_GetError(), syserrno = PR_GetOSError();
  210.     TEST_LOG(
  211.         cltsrv_log_file, TEST_LOG_ALWAYS, 
  212.         ("Assertion failed(0x%lx): '%s' in %s[%d]\n",
  213.         PR_CurrentThread(), s, file, ln));
  214.     TEST_LOG(
  215.         cltsrv_log_file, TEST_LOG_ALWAYS, 
  216.         ("**Error information: Error = %d, OSError = %d\n",
  217.     error, syserrno));
  218.     PR_LogFlush();
  219.  
  220.     PR_Abort();
  221. }  /* Assert */
  222.  
  223. static void TimeOfDayMessage(const char *msg, PRThread* me)
  224. {
  225.     char buffer[100];
  226.     PRExplodedTime tod;
  227.     PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod);
  228.     (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
  229.  
  230.     TEST_LOG(
  231.         cltsrv_log_file, TEST_LOG_ALWAYS,
  232.         ("%s(0x%lx): %s\n", msg, me, buffer));
  233. }  /* TimeOfDayMessage */
  234.  
  235.  
  236. static void PR_CALLBACK Client(void *arg)
  237. {
  238.     PRStatus rv;
  239.     PRIntn index;
  240.     char buffer[1024];
  241.     PRFileDesc *fd = NULL;
  242.     PRUintn clipping = DEFAULT_CLIPPING;
  243.     PRThread *me = PR_CurrentThread();
  244.     CSClient_t *client = (CSClient_t*)arg;
  245.     CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
  246.     PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT);
  247.  
  248.  
  249.     for (index = 0; index < sizeof(buffer); ++index)
  250.         buffer[index] = (char)index;
  251.  
  252.     client->started = PR_IntervalNow();
  253.  
  254.     PR_Lock(client->ml);
  255.     client->state = cs_run;
  256.     PR_NotifyCondVar(client->stateChange);
  257.     PR_Unlock(client->ml);
  258.  
  259.     TimeOfDayMessage("Client started at", me);
  260.  
  261.     while (cs_run == client->state)
  262.     {
  263.         PRInt32 bytes, descbytes, filebytes, netbytes;
  264.  
  265.         (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer));
  266.         TEST_LOG(cltsrv_log_file, TEST_LOG_INFO, 
  267.             ("\tClient(0x%lx): connecting to server at %s\n", me, buffer));
  268.  
  269.         fd = PR_Socket(domain, SOCK_STREAM, protocol);
  270.         TEST_ASSERT(NULL != fd);
  271.         rv = PR_Connect(fd, &client->serverAddress, timeout);
  272.         if (PR_FAILURE == rv)
  273.         {
  274.             TEST_LOG(
  275.                 cltsrv_log_file, TEST_LOG_ERROR,
  276.                 ("\tClient(0x%lx): conection failed\n", me));
  277.             goto aborted;
  278.         }
  279.  
  280.         memset(descriptor, 0, sizeof(*descriptor));
  281.         descriptor->size = PR_htonl(descbytes = rand() % clipping);
  282.         PR_snprintf(
  283.             descriptor->filename, sizeof(descriptor->filename),
  284.             "CS%lx%lx-%lx.dat", client->started, me, client->operations);
  285.         TEST_LOG(
  286.             cltsrv_log_file, TEST_LOG_VERBOSE,
  287.             ("\tClient(0x%lx): sending descriptor for %ld bytes\n", me, descbytes));
  288.         bytes = PR_Send(
  289.             fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout);
  290.         if (sizeof(CSDescriptor_t) != bytes)
  291.         {
  292.             if (Aborted(PR_FAILURE)) goto aborted;
  293.             if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  294.             {
  295.                 TEST_LOG(
  296.                     cltsrv_log_file, TEST_LOG_ERROR,
  297.                     ("\tClient(0x%lx): send descriptor timeout\n", me));
  298.                 goto retry;
  299.             }
  300.         }
  301.         TEST_ASSERT(sizeof(*descriptor) == bytes);
  302.  
  303.         netbytes = 0;
  304.         while (netbytes < descbytes)
  305.         {
  306.             filebytes = sizeof(buffer);
  307.             if ((descbytes - netbytes) < filebytes)
  308.                 filebytes = descbytes - netbytes;
  309.             TEST_LOG(
  310.                 cltsrv_log_file, TEST_LOG_VERBOSE,
  311.                 ("\tClient(0x%lx): sending %d bytes\n", me, filebytes));
  312.             bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
  313.             if (filebytes != bytes)
  314.             {
  315.                 if (Aborted(PR_FAILURE)) goto aborted;
  316.                 if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  317.                 {
  318.                     TEST_LOG(
  319.                         cltsrv_log_file, TEST_LOG_ERROR,
  320.                         ("\tClient(0x%lx): send data timeout\n", me));
  321.                     goto retry;
  322.                 }
  323.             }
  324.             TEST_ASSERT(bytes == filebytes);
  325.             netbytes += bytes;
  326.         }
  327.         filebytes = 0;
  328.         while (filebytes < descbytes)
  329.         {
  330.             netbytes = sizeof(buffer);
  331.             if ((descbytes - filebytes) < netbytes)
  332.                 netbytes = descbytes - filebytes;
  333.             TEST_LOG(
  334.                 cltsrv_log_file, TEST_LOG_VERBOSE,
  335.                 ("\tClient(0x%lx): receiving %d bytes\n", me, netbytes));
  336.             bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
  337.             if (-1 == bytes)
  338.             {
  339.                 if (Aborted(PR_FAILURE))
  340.                 {
  341.                     TEST_LOG(
  342.                         cltsrv_log_file, TEST_LOG_ERROR,
  343.                         ("\tClient(0x%lx): receive data aborted\n", me));
  344.                     goto aborted;
  345.                 }
  346.                 else if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  347.                     TEST_LOG(
  348.                         cltsrv_log_file, TEST_LOG_ERROR,
  349.                         ("\tClient(0x%lx): receive data timeout\n", me));
  350.                 else
  351.                     TEST_LOG(
  352.                         cltsrv_log_file, TEST_LOG_ERROR,
  353.                         ("\tClient(0x%lx): receive error (%ld, %ld)\n",
  354.                         me, PR_GetError(), PR_GetOSError()));
  355.                 goto retry;
  356.            }
  357.             if (0 == bytes)
  358.             {
  359.                 TEST_LOG(
  360.                     cltsrv_log_file, TEST_LOG_ERROR,
  361.                     ("\t\tClient(0x%lx): unexpected end of stream\n",
  362.                     PR_CurrentThread()));
  363.                 break;
  364.             }
  365.             filebytes += bytes;
  366.         }
  367.  
  368.         rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
  369.         if (Aborted(rv)) goto aborted;
  370.         TEST_ASSERT(PR_SUCCESS == rv);
  371. retry:
  372.         (void)PR_Close(fd); fd = NULL;
  373.         TEST_LOG(
  374.             cltsrv_log_file, TEST_LOG_INFO,
  375.             ("\tClient(0x%lx): disconnected from server\n", me));
  376.  
  377.         PR_Lock(client->ml);
  378.         client->operations += 1;
  379.         client->bytesTransferred += 2 * descbytes;
  380.         rv = PR_WaitCondVar(client->stateChange, rand() % clipping);
  381.         PR_Unlock(client->ml);
  382.         if (Aborted(rv)) break;
  383.     }
  384.  
  385. aborted:
  386.     client->stopped = PR_IntervalNow();
  387.  
  388.     PR_ClearInterrupt();
  389.     if (NULL != fd) rv = PR_Close(fd);
  390.  
  391.     PR_Lock(client->ml);
  392.     client->state = cs_exit;
  393.     PR_NotifyCondVar(client->stateChange);
  394.     PR_Unlock(client->ml);
  395.     PR_DELETE(descriptor);
  396.     TEST_LOG(
  397.         cltsrv_log_file, TEST_LOG_ALWAYS,
  398.         ("\tClient(0x%lx): stopped after %lu operations and %lu bytes\n",
  399.         PR_CurrentThread(), client->operations, client->bytesTransferred));
  400.  
  401. }  /* Client */
  402.  
  403. static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server)
  404. {
  405.     PRStatus drv, rv;
  406.     char buffer[1024];
  407.     PRFileDesc *file = NULL;
  408.     PRThread * me = PR_CurrentThread();
  409.     PRInt32 bytes, descbytes, netbytes, filebytes = 0;
  410.     CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
  411.     PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT);
  412.  
  413.     TEST_LOG(
  414.         cltsrv_log_file, TEST_LOG_VERBOSE,
  415.         ("\tProcessRequest(0x%lx): receiving desciptor\n", me));
  416.     bytes = PR_Recv(
  417.         fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout);
  418.     if (-1 == bytes)
  419.     {
  420.         rv = PR_FAILURE;
  421.         if (Aborted(rv)) goto exit;
  422.         if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  423.         {
  424.             TEST_LOG(
  425.                 cltsrv_log_file, TEST_LOG_ERROR,
  426.                 ("\tProcessRequest(0x%lx): receive timeout\n", me));
  427.         }
  428.         goto exit;
  429.     }
  430.     if (0 == bytes)
  431.     {
  432.         rv = PR_FAILURE;
  433.         TEST_LOG(
  434.             cltsrv_log_file, TEST_LOG_ERROR,
  435.             ("\tProcessRequest(0x%lx): unexpected end of file\n", me));
  436.         goto exit;
  437.     }
  438.     descbytes = PR_ntohl(descriptor->size);
  439.     TEST_ASSERT(sizeof(*descriptor) == bytes);
  440.  
  441.     TEST_LOG(
  442.         cltsrv_log_file, TEST_LOG_VERBOSE, 
  443.         ("\t\tProcessRequest(0x%lx): read descriptor {%ld, %s}\n",
  444.         me, descbytes, descriptor->filename));
  445.  
  446.     file = PR_Open(
  447.         descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666);
  448.     if (NULL == file)
  449.     {
  450.         rv = PR_FAILURE;
  451.         if (Aborted(rv)) goto aborted;
  452.         if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  453.         {
  454.             TEST_LOG(
  455.                 cltsrv_log_file, TEST_LOG_ERROR,
  456.                 ("\tProcessRequest(0x%lx): open file timeout\n", me));
  457.             goto aborted;
  458.         }
  459.     }
  460.     TEST_ASSERT(NULL != file);
  461.  
  462.     filebytes = 0;
  463.     while (filebytes < descbytes)
  464.     {
  465.         netbytes = sizeof(buffer);
  466.         if ((descbytes - filebytes) < netbytes)
  467.             netbytes = descbytes - filebytes;
  468.         TEST_LOG(
  469.             cltsrv_log_file, TEST_LOG_VERBOSE,
  470.             ("\tProcessRequest(0x%lx): receive %d bytes\n", me, netbytes));
  471.         bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
  472.         if (-1 == bytes)
  473.         {
  474.             rv = PR_FAILURE;
  475.             if (Aborted(rv)) goto aborted;
  476.             if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  477.             {
  478.                 TEST_LOG(
  479.                     cltsrv_log_file, TEST_LOG_ERROR,
  480.                     ("\t\tProcessRequest(0x%lx): receive data timeout\n", me));
  481.                 goto aborted;
  482.             }
  483.             /*
  484.              * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED)
  485.              * on NT here.  This is equivalent to ECONNRESET on Unix.
  486.              *     -wtc
  487.              */
  488.             TEST_LOG(
  489.                 cltsrv_log_file, TEST_LOG_WARNING,
  490.                 ("\t\tProcessRequest(0x%lx): unexpected error (%d, %d)\n",
  491.                 me, PR_GetError(), PR_GetOSError()));
  492.             goto aborted;
  493.         }
  494.         if(0 == bytes)
  495.         {
  496.             TEST_LOG(
  497.                 cltsrv_log_file, TEST_LOG_WARNING,
  498.                 ("\t\tProcessRequest(0x%lx): unexpected end of stream\n", me));
  499.             rv = PR_FAILURE;
  500.             goto aborted;
  501.         }
  502.         filebytes += bytes;
  503.         netbytes = bytes;
  504.         /* The byte count for PR_Write should be positive */
  505.         MY_ASSERT(netbytes > 0);
  506.         TEST_LOG(
  507.             cltsrv_log_file, TEST_LOG_VERBOSE,
  508.             ("\tProcessRequest(0x%lx): write %d bytes to file\n", me, netbytes));
  509.         bytes = PR_Write(file, buffer, netbytes);
  510.         if (netbytes != bytes)
  511.         {
  512.             rv = PR_FAILURE;
  513.             if (Aborted(rv)) goto aborted;
  514.             if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  515.             {
  516.                 TEST_LOG(
  517.                     cltsrv_log_file, TEST_LOG_ERROR,
  518.                     ("\t\tProcessRequest(0x%lx): write file timeout\n", me));
  519.                 goto aborted;
  520.             }
  521.         }
  522.         TEST_ASSERT(bytes > 0);
  523.     }
  524.  
  525.     PR_Lock(server->ml);
  526.     server->operations += 1;
  527.     server->bytesTransferred += filebytes;
  528.     PR_Unlock(server->ml);
  529.  
  530.     rv = PR_Close(file); file = NULL;
  531.     if (Aborted(rv)) goto aborted;
  532.     TEST_ASSERT(PR_SUCCESS == rv);
  533.  
  534.     TEST_LOG(
  535.         cltsrv_log_file, TEST_LOG_VERBOSE,
  536.         ("\t\tProcessRequest(0x%lx): opening %s\n", me, descriptor->filename));
  537.     file = PR_Open(descriptor->filename, PR_RDONLY, 0);
  538.     if (NULL == file)
  539.     {
  540.         rv = PR_FAILURE;
  541.         if (Aborted(rv)) goto aborted;
  542.         if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  543.         {
  544.             TEST_LOG(
  545.                 cltsrv_log_file, TEST_LOG_ERROR,
  546.                 ("\t\tProcessRequest(0x%lx): open file timeout\n",
  547.                 PR_CurrentThread()));
  548.             goto aborted;
  549.         }
  550.         TEST_LOG(
  551.             cltsrv_log_file, TEST_LOG_ERROR,
  552.             ("\t\tProcessRequest(0x%lx): other file open error (%u, %u)\n",
  553.             me, PR_GetError(), PR_GetOSError()));
  554.         goto aborted;
  555.     }
  556.     TEST_ASSERT(NULL != file);
  557.  
  558.     netbytes = 0;
  559.     while (netbytes < descbytes)
  560.     {
  561.         filebytes = sizeof(buffer);
  562.         if ((descbytes - netbytes) < filebytes)
  563.             filebytes = descbytes - netbytes;
  564.         TEST_LOG(
  565.             cltsrv_log_file, TEST_LOG_VERBOSE,
  566.             ("\tProcessRequest(0x%lx): read %d bytes from file\n", me, filebytes));
  567.         bytes = PR_Read(file, buffer, filebytes);
  568.         if (filebytes != bytes)
  569.         {
  570.             rv = PR_FAILURE;
  571.             if (Aborted(rv)) goto aborted;
  572.             if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  573.                 TEST_LOG(
  574.                     cltsrv_log_file, TEST_LOG_ERROR,
  575.                     ("\t\tProcessRequest(0x%lx): read file timeout\n", me));
  576.             else
  577.                 TEST_LOG(
  578.                     cltsrv_log_file, TEST_LOG_ERROR,
  579.                     ("\t\tProcessRequest(0x%lx): other file error (%d, %d)\n",
  580.                     me, PR_GetError(), PR_GetOSError()));
  581.             goto aborted;
  582.         }
  583.         TEST_ASSERT(bytes > 0);
  584.         netbytes += bytes;
  585.         filebytes = bytes;
  586.         TEST_LOG(
  587.             cltsrv_log_file, TEST_LOG_VERBOSE,
  588.             ("\t\tProcessRequest(0x%lx): sending %d bytes\n", me, filebytes));
  589.         bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
  590.         if (filebytes != bytes)
  591.         {
  592.             rv = PR_FAILURE;
  593.             if (Aborted(rv)) goto aborted;
  594.             if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  595.             {
  596.                 TEST_LOG(
  597.                     cltsrv_log_file, TEST_LOG_ERROR,
  598.                     ("\t\tProcessRequest(0x%lx): send data timeout\n", me));
  599.                 goto aborted;
  600.             }
  601.             break;
  602.         }
  603.        TEST_ASSERT(bytes > 0);
  604.     }
  605.     
  606.     PR_Lock(server->ml);
  607.     server->bytesTransferred += filebytes;
  608.     PR_Unlock(server->ml);
  609.  
  610.     rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
  611.     if (Aborted(rv)) goto aborted;
  612.  
  613.     rv = PR_Close(file); file = NULL;
  614.     if (Aborted(rv)) goto aborted;
  615.     TEST_ASSERT(PR_SUCCESS == rv);
  616.  
  617. aborted:
  618.     PR_ClearInterrupt();
  619.     if (NULL != file) PR_Close(file);
  620.     drv = PR_Delete(descriptor->filename);
  621.     TEST_ASSERT(PR_SUCCESS == drv);
  622. exit:
  623.     TEST_LOG(
  624.         cltsrv_log_file, TEST_LOG_VERBOSE,
  625.         ("\t\tProcessRequest(0x%lx): Finished\n", me));
  626.  
  627.     PR_DELETE(descriptor);
  628.  
  629. #if defined(WIN95)
  630.     PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */
  631. #endif
  632.     return rv;
  633. }  /* ProcessRequest */
  634.  
  635. static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool)
  636. {
  637.     CSWorker_t *worker = PR_NEWZAP(CSWorker_t);
  638.     worker->server = server;
  639.     PR_INIT_CLIST(&worker->element);
  640.     worker->thread = PR_CreateThread(
  641.         PR_USER_THREAD, Worker, worker,
  642.         DEFAULT_SERVER_PRIORITY, thread_scope,
  643.         PR_UNJOINABLE_THREAD, 0);
  644.     if (NULL == worker->thread)
  645.     {
  646.         PR_DELETE(worker);
  647.         return PR_FAILURE;
  648.     }
  649.  
  650.     TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, 
  651.         ("\tCreateWorker(0x%lx): create new worker (0x%lx)\n",
  652.         PR_CurrentThread(), worker->thread));
  653.  
  654.     return PR_SUCCESS;
  655. }  /* CreateWorker */
  656.  
  657. static void PR_CALLBACK Worker(void *arg)
  658. {
  659.     PRStatus rv;
  660.     PRNetAddr from;
  661.     PRFileDesc *fd = NULL;
  662.     PRThread *me = PR_CurrentThread();
  663.     CSWorker_t *worker = (CSWorker_t*)arg;
  664.     CSServer_t *server = worker->server;
  665.     CSPool_t *pool = &server->pool;
  666.  
  667.     TEST_LOG(
  668.         cltsrv_log_file, TEST_LOG_NOTICE,
  669.         ("\t\tWorker(0x%lx): started [%lu]\n", me, pool->workers + 1));
  670.  
  671.     PR_Lock(server->ml);
  672.     PR_APPEND_LINK(&worker->element, &server->list);
  673.     pool->workers += 1;  /* define our existance */
  674.  
  675.     while (cs_run == server->state)
  676.     {
  677.         while (pool->accepting >= server->workers.accepting)
  678.         {
  679.             TEST_LOG(
  680.                 cltsrv_log_file, TEST_LOG_VERBOSE,
  681.                 ("\t\tWorker(0x%lx): waiting for accept slot[%d]\n",
  682.                 me, pool->accepting));
  683.             rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT);
  684.             if (Aborted(rv) || (cs_run != server->state))
  685.             {
  686.                 TEST_LOG(
  687.                     cltsrv_log_file, TEST_LOG_NOTICE,
  688.                     ("\tWorker(0x%lx): has been %s\n",
  689.                     me, (Aborted(rv) ? "interrupted" : "stopped")));
  690.                 goto exit;
  691.             }
  692.         } 
  693.         pool->accepting += 1;  /* how many are really in accept */
  694.         PR_Unlock(server->ml);
  695.  
  696.         TEST_LOG(
  697.             cltsrv_log_file, TEST_LOG_VERBOSE,
  698.             ("\t\tWorker(0x%lx): calling accept\n", me));
  699.         fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT);
  700.  
  701.         PR_Lock(server->ml);        
  702.         pool->accepting -= 1;
  703.         PR_NotifyCondVar(pool->acceptComplete);
  704.  
  705.         if ((NULL == fd) && Aborted(PR_FAILURE))
  706.         {
  707.             if (NULL != server->listener)
  708.             {
  709.                 PR_Close(server->listener);
  710.                 server->listener = NULL;
  711.             }
  712.             goto exit;
  713.         }
  714.  
  715.         if (NULL != fd)
  716.         {
  717.             /*
  718.             ** Create another worker of the total number of workers is
  719.             ** less than the minimum specified or we have none left in
  720.             ** accept() AND we're not over the maximum.
  721.             ** This sort of presumes that the number allowed in accept
  722.             ** is at least as many as the minimum. Otherwise we'll keep
  723.             ** creating new threads and deleting them soon after.
  724.             */
  725.             PRBool another =
  726.                 ((pool->workers < server->workers.minimum) ||
  727.                 ((0 == pool->accepting)
  728.                     && (pool->workers < server->workers.maximum))) ?
  729.                     PR_TRUE : PR_FALSE;
  730.             pool->active += 1;
  731.             PR_Unlock(server->ml);
  732.  
  733.             if (another) (void)CreateWorker(server, pool);
  734.  
  735.             rv = ProcessRequest(fd, server);
  736.             if (PR_SUCCESS != rv)
  737.                 TEST_LOG(
  738.                     cltsrv_log_file, TEST_LOG_ERROR,
  739.                     ("\t\tWorker(0x%lx): server process ended abnormally\n", me));
  740.             (void)PR_Close(fd); fd = NULL;
  741.  
  742.             PR_Lock(server->ml);
  743.             pool->active -= 1;
  744.         }
  745.     }
  746.  
  747. exit:
  748.     PR_ClearInterrupt();    
  749.     PR_Unlock(server->ml);
  750.  
  751.     if (NULL != fd)
  752.     {
  753.         (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
  754.         (void)PR_Close(fd);
  755.     }
  756.  
  757.     TEST_LOG(
  758.         cltsrv_log_file, TEST_LOG_NOTICE,
  759.         ("\t\tWorker(0x%lx): exiting [%lu]\n", PR_CurrentThread(), pool->workers));
  760.  
  761.     PR_Lock(server->ml);
  762.     pool->workers -= 1;  /* undefine our existance */
  763.     PR_REMOVE_AND_INIT_LINK(&worker->element);
  764.     PR_NotifyCondVar(pool->exiting);
  765.     PR_Unlock(server->ml);
  766.  
  767.     PR_DELETE(worker);  /* destruction of the "worker" object */
  768.  
  769. }  /* Worker */
  770.  
  771. static void PR_CALLBACK Server(void *arg)
  772. {
  773.     PRStatus rv;
  774.     PRNetAddr serverAddress;
  775.     PRThread *me = PR_CurrentThread();
  776.     CSServer_t *server = (CSServer_t*)arg;
  777.  
  778.     server->listener = PR_Socket(domain, SOCK_STREAM, protocol);
  779.  
  780.     rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress);
  781.  
  782.     rv = PR_Bind(server->listener, &serverAddress);
  783.     TEST_ASSERT(PR_SUCCESS == rv);
  784.  
  785.     rv = PR_Listen(server->listener, server->backlog);
  786.     TEST_ASSERT(PR_SUCCESS == rv);
  787.  
  788.     server->started = PR_IntervalNow();
  789.     TimeOfDayMessage("Server started at", me);
  790.  
  791.     PR_Lock(server->ml);
  792.     server->state = cs_run;
  793.     PR_NotifyCondVar(server->stateChange);
  794.     PR_Unlock(server->ml);
  795.  
  796.     /*
  797.     ** Create the first worker (actually, a thread that accepts
  798.     ** connections and then processes the work load as needed).
  799.     ** From this point on, additional worker threads are created
  800.     ** as they are needed by existing worker threads.
  801.     */
  802.     rv = CreateWorker(server, &server->pool);
  803.     TEST_ASSERT(PR_SUCCESS == rv);
  804.  
  805.     /*
  806.     ** From here on this thread is merely hanging around as the contact
  807.     ** point for the main test driver. It's just waiting for the driver
  808.     ** to declare the test complete.
  809.     */
  810.     TEST_LOG(
  811.         cltsrv_log_file, TEST_LOG_VERBOSE,
  812.         ("\tServer(0x%lx): waiting for state change\n", me));
  813.  
  814.     PR_Lock(server->ml);
  815.     while ((cs_run == server->state) && !Aborted(rv))
  816.     {
  817.         rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  818.     }
  819.     PR_Unlock(server->ml);
  820.     PR_ClearInterrupt();
  821.  
  822.     TEST_LOG(
  823.         cltsrv_log_file, TEST_LOG_INFO,
  824.         ("\tServer(0x%lx): shutting down workers\n", me));
  825.  
  826.     /*
  827.     ** Get all the worker threads to exit. They know how to
  828.     ** clean up after themselves, so this is just a matter of
  829.     ** waiting for clorine in the pool to take effect. During
  830.     ** this stage we're ignoring interrupts.
  831.     */
  832.     server->workers.minimum = server->workers.maximum = 0;
  833.  
  834.     PR_Lock(server->ml);
  835.     while (!PR_CLIST_IS_EMPTY(&server->list))
  836.     {
  837.         PRCList *head = PR_LIST_HEAD(&server->list);
  838.         CSWorker_t *worker = (CSWorker_t*)head;
  839.         TEST_LOG(
  840.             cltsrv_log_file, TEST_LOG_VERBOSE,
  841.             ("\tServer(0x%lx): interrupting worker(0x%lx)\n", me, worker));
  842.         rv = PR_Interrupt(worker->thread);
  843.         TEST_ASSERT(PR_SUCCESS == rv);
  844.         PR_REMOVE_AND_INIT_LINK(head);
  845.     }
  846.  
  847.     while (server->pool.workers > 0)
  848.     {
  849.         TEST_LOG(
  850.             cltsrv_log_file, TEST_LOG_NOTICE,
  851.             ("\tServer(0x%lx): waiting for %lu workers to exit\n",
  852.             me, server->pool.workers));
  853.         (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT);
  854.     }
  855.  
  856.     server->state = cs_exit;
  857.     PR_NotifyCondVar(server->stateChange);
  858.     PR_Unlock(server->ml);
  859.  
  860.     TEST_LOG(
  861.         cltsrv_log_file, TEST_LOG_ALWAYS,
  862.         ("\tServer(0x%lx): stopped after %lu operations and %lu bytes\n",
  863.         me, server->operations, server->bytesTransferred));
  864.  
  865.     if (NULL != server->listener) PR_Close(server->listener);
  866.     server->stopped = PR_IntervalNow();
  867.  
  868. }  /* Server */
  869.  
  870. #if 0 && defined(DEBUG) && defined(_PR_PTHREADS)
  871. static void PrintPthreadStats(void)
  872. {
  873.     char buffer[100];
  874.     PRExplodedTime tod;
  875.     PTDebug stats = PT_GetStats();
  876.     PRInt64 elapsed, aMil;
  877.     PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod);
  878.     (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
  879.  
  880.     LL_SUB(elapsed, PR_Now(), stats.timeStarted);
  881.     LL_I2L(aMil, 1000000);
  882.     LL_DIV(elapsed, elapsed, aMil);
  883.     PR_fprintf(debug_out, "\npthread statistics\n\tstarted: %s[%lld]\n", buffer, elapsed);
  884.     PR_fprintf(debug_out, "\tmissed predictions: %u\n", stats.predictionsFoiled);
  885.     PR_fprintf(debug_out, "\tpollingList max: %u\n", stats.pollingListMax);
  886.     PR_fprintf(debug_out, "\tcontinuations served: %u\n", stats.continuationsServed);
  887.     PR_fprintf(debug_out, "\trecycles needed: %u\n", stats.recyclesNeeded);
  888.     PR_fprintf(debug_out, "\tquiescent IO: %u\n", stats.quiescentIO);
  889. }  /* PrintPthreadStats */
  890. #endif /* defined(DEBUG) && defined(_PR_PTHREADS) */
  891.  
  892. static void WaitForCompletion(PRIntn execution)
  893. {
  894. #if 0 && defined(DEBUG) && defined(_PR_PTHREADS)
  895.     while (execution > 0)
  896.     { 
  897.         PRIntn dally = (execution > 30) ? 30 : execution;
  898.         PR_Sleep(PR_SecondsToInterval(dally));
  899.         if (pthread_stats) PrintPthreadStats();
  900.         execution -= dally;
  901.     }
  902. #else
  903.     PR_Sleep(PR_SecondsToInterval(execution));
  904. #endif /* defined(DEBUG) && defined(_PR_PTHREADS) */
  905. }  /* WaitForCompletion */
  906.  
  907. static void Help(void)
  908. {
  909.     PR_fprintf(debug_out, "cltsrv test program usage:\n");
  910.     PR_fprintf(debug_out, "\t-a <n>       threads allowed in accept        (5)\n");
  911.     PR_fprintf(debug_out, "\t-b <n>       backlock for listen              (5)\n");
  912.     PR_fprintf(debug_out, "\t-c <threads> number of clients to create      (1)\n");
  913.     PR_fprintf(debug_out, "\t-w <threads> minimal number of server threads (1)\n");
  914.     PR_fprintf(debug_out, "\t-W <threads> maximum number of server threads (1)\n");
  915.     PR_fprintf(debug_out, "\t-e <seconds> duration of the test in seconds  (10)\n");
  916.     PR_fprintf(debug_out, "\t-s <string>  dsn name of server               (localhost)\n");
  917.     PR_fprintf(debug_out, "\t-G           use GLOBAL threads               (LOCAL)\n");
  918.     PR_fprintf(debug_out, "\t-X           use XTP as transport             (TCP)\n");
  919. #ifdef _PR_INET6
  920.     PR_fprintf(debug_out, "\t-6           Use IPv6                         (IPv4)\n");
  921. #endif /* _PR_INET6 */
  922.     PR_fprintf(debug_out, "\t-v           verbosity (accumulative)         (0)\n");
  923.     PR_fprintf(debug_out, "\t-p           pthread statistics               (FALSE)\n");
  924.     PR_fprintf(debug_out, "\t-d           debug mode                       (FALSE)\n");
  925.     PR_fprintf(debug_out, "\t-h           this message\n");
  926. }  /* Help */
  927.  
  928. static Verbosity IncrementVerbosity(void)
  929. {
  930.     PRIntn verboge = (PRIntn)verbosity + 1;
  931.     return (Verbosity)verboge;
  932. }  /* IncrementVerbosity */
  933. PRIntn xmain(PRIntn argc, char** argv)
  934. {
  935.     PRUintn index;
  936.     PRBool boolean;
  937.     CSClient_t *client;
  938.     PRStatus rv, joinStatus;
  939.     CSServer_t *server = NULL;
  940.  
  941.     PRUintn backlog = DEFAULT_BACKLOG;
  942.     PRUintn clients = DEFAULT_CLIENTS;
  943.     const char *serverName = DEFAULT_SERVER;
  944.     PRBool serverIsLocal = PR_TRUE;
  945.     PRUintn accepting = ALLOWED_IN_ACCEPT;
  946.     PRUintn workersMin = DEFAULT_WORKERS_MIN;
  947.     PRUintn workersMax = DEFAULT_WORKERS_MAX;
  948.     PRIntn execution = DEFAULT_EXECUTION_TIME;
  949.  
  950.     /*
  951.      * -G           use global threads
  952.      * -a <n>       threads allowed in accept
  953.      * -b <n>       backlock for listen
  954.      * -c <threads> number of clients to create
  955.      * -w <threads> minimal number of server threads
  956.      * -W <threads> maximum number of server threads
  957.      * -e <seconds> duration of the test in seconds
  958.      * -s <string>  dsn name of server (implies no server here)
  959.      * -v           verbosity
  960.      */
  961.  
  962.     PLOptStatus os;
  963.     PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:l:w:W:e:s:vdhp");
  964.  
  965.     debug_out = PR_GetSpecialFD(PR_StandardError);
  966.  
  967.     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  968.     {
  969.         if (PL_OPT_BAD == os) continue;
  970.         switch (opt->option)
  971.         {
  972.         case 'G':  /* use global threads */
  973.             thread_scope = PR_GLOBAL_THREAD;
  974.             break;
  975.         case 'X':  /* use XTP as transport */
  976.             protocol = 36;
  977.             break;
  978. #ifdef _PR_INET6
  979.     case '6':  /* Use IPv6 */
  980.             domain = AF_INET6;
  981.             PR_SetIPv6Enable(PR_TRUE);
  982.             break;
  983. #endif /* _PR_INET6 */
  984.         case 'a':  /* the value for accepting */
  985.             accepting = atoi(opt->value);
  986.             break;
  987.         case 'b':  /* the value for backlock */
  988.             backlog = atoi(opt->value);
  989.             break;
  990.         case 'c':  /* number of client threads */
  991.             clients = atoi(opt->value);
  992.             break;
  993.         case 'l':  /* number of outer loops */
  994.             break;
  995.         case 'w':  /* minimum server worker threads */
  996.             workersMin = atoi(opt->value);
  997.             break;
  998.         case 'W':  /* maximum server worker threads */
  999.             workersMax = atoi(opt->value);
  1000.             break;
  1001.         case 'e':  /* program execution time in seconds */
  1002.             execution = atoi(opt->value);
  1003.             break;
  1004.         case 's':  /* server's address */
  1005.             serverName = opt->value;
  1006.             break;
  1007.         case 'v':  /* verbosity */
  1008.             verbosity = IncrementVerbosity();
  1009.             break;
  1010.         case 'd':  /* debug mode */
  1011.             debug_mode = PR_TRUE;
  1012.             break;
  1013.         case 'p':  /* pthread mode */
  1014.             pthread_stats = PR_TRUE;
  1015.             break;
  1016.         case 'h':
  1017.         default:
  1018.             Help();
  1019.             return 2;
  1020.         }
  1021.     }
  1022.     PL_DestroyOptState(opt);
  1023.  
  1024.     if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) serverIsLocal = PR_FALSE;
  1025.     if (0 == execution) execution = DEFAULT_EXECUTION_TIME;
  1026.     if (0 == workersMax) workersMax = DEFAULT_WORKERS_MAX;
  1027.     if (0 == workersMin) workersMin = DEFAULT_WORKERS_MIN;
  1028.     if (0 == accepting) accepting = ALLOWED_IN_ACCEPT;
  1029.     if (0 == backlog) backlog = DEFAULT_BACKLOG;
  1030.  
  1031.     if (workersMin > accepting) accepting = workersMin;
  1032.  
  1033.     PR_STDIO_INIT();
  1034.     TimeOfDayMessage("Client/Server started at", PR_CurrentThread());
  1035.  
  1036.     cltsrv_log_file = PR_NewLogModule("cltsrv_log");
  1037.     MY_ASSERT(NULL != cltsrv_log_file);
  1038.     boolean = PR_SetLogFile("cltsrv.log");
  1039.     MY_ASSERT(boolean);
  1040.  
  1041. #ifdef XP_MAC
  1042.     debug_mode = PR_TRUE;
  1043. #endif
  1044.  
  1045.     if (serverIsLocal)
  1046.     {
  1047.         /* Establish the server */
  1048.         TEST_LOG(
  1049.             cltsrv_log_file, TEST_LOG_INFO,
  1050.             ("main(0x%lx): starting server\n", PR_CurrentThread()));
  1051.  
  1052.         server = PR_NEWZAP(CSServer_t);
  1053.         PR_INIT_CLIST(&server->list);
  1054.         server->state = cs_init;
  1055.         server->ml = PR_NewLock();
  1056.         server->backlog = backlog;
  1057.         server->port = DEFAULT_PORT;
  1058.         server->workers.minimum = workersMin;
  1059.         server->workers.maximum = workersMax;
  1060.         server->workers.accepting = accepting;
  1061.         server->stateChange = PR_NewCondVar(server->ml);
  1062.         server->pool.exiting = PR_NewCondVar(server->ml);
  1063.         server->pool.acceptComplete = PR_NewCondVar(server->ml);
  1064.  
  1065.         TEST_LOG(
  1066.             cltsrv_log_file, TEST_LOG_NOTICE,
  1067.             ("main(0x%lx): creating server thread\n", PR_CurrentThread()));
  1068.  
  1069.         server->thread = PR_CreateThread(
  1070.             PR_USER_THREAD, Server, server, PR_PRIORITY_HIGH,
  1071.             thread_scope, PR_JOINABLE_THREAD, 0);
  1072.         TEST_ASSERT(NULL != server->thread);
  1073.  
  1074.         TEST_LOG(
  1075.             cltsrv_log_file, TEST_LOG_VERBOSE,
  1076.             ("main(0x%lx): waiting for server init\n", PR_CurrentThread()));
  1077.  
  1078.         PR_Lock(server->ml);
  1079.         while (server->state == cs_init)
  1080.             PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  1081.         PR_Unlock(server->ml);
  1082.  
  1083.         TEST_LOG(
  1084.             cltsrv_log_file, TEST_LOG_VERBOSE,
  1085.             ("main(0x%lx): server init complete (port #%d)\n",
  1086.             PR_CurrentThread(), server->port));
  1087.     }
  1088.  
  1089.     if (clients != 0)
  1090.     {
  1091.         /* Create all of the clients */
  1092.         PRHostEnt host;
  1093.         char buffer[BUFFER_SIZE];
  1094.         client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t));
  1095.  
  1096.         TEST_LOG(
  1097.             cltsrv_log_file, TEST_LOG_VERBOSE,
  1098.             ("main(0x%lx): creating %d client threads\n",
  1099.             PR_CurrentThread(), clients));
  1100.         
  1101.         if (!serverIsLocal)
  1102.         {
  1103.             rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host);
  1104.             if (PR_SUCCESS != rv)
  1105.             {
  1106.                 PL_FPrintError(PR_STDERR, "PR_GetHostByName");
  1107.                 return 2;
  1108.             }
  1109.         }
  1110.  
  1111.         for (index = 0; index < clients; ++index)
  1112.         {
  1113.             client[index].state = cs_init;
  1114.             client[index].ml = PR_NewLock();
  1115.             if (serverIsLocal)
  1116.             {
  1117.                 (void)PR_InitializeNetAddr(
  1118.                     PR_IpAddrLoopback, DEFAULT_PORT,
  1119.                     &client[index].serverAddress);
  1120.             }
  1121.             else
  1122.             {
  1123.                 (void)PR_EnumerateHostEnt(
  1124.                     0, &host, DEFAULT_PORT, &client[index].serverAddress);
  1125.             }
  1126.             client[index].stateChange = PR_NewCondVar(client[index].ml);
  1127.             TEST_LOG(
  1128.                 cltsrv_log_file, TEST_LOG_INFO,
  1129.                 ("main(0x%lx): creating client threads\n", PR_CurrentThread()));
  1130.             client[index].thread = PR_CreateThread(
  1131.                 PR_USER_THREAD, Client, &client[index], PR_PRIORITY_NORMAL,
  1132.                 thread_scope, PR_JOINABLE_THREAD, 0);
  1133.             TEST_ASSERT(NULL != client[index].thread);
  1134.             PR_Lock(client[index].ml);
  1135.             while (cs_init == client[index].state)
  1136.                 PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
  1137.             PR_Unlock(client[index].ml);
  1138.         }
  1139.     }
  1140.  
  1141.     /* Then just let them go at it for a bit */
  1142.     TEST_LOG(
  1143.         cltsrv_log_file, TEST_LOG_ALWAYS,
  1144.         ("main(0x%lx): waiting for execution interval (%d seconds)\n",
  1145.         PR_CurrentThread(), execution));
  1146.  
  1147.     WaitForCompletion(execution);
  1148.  
  1149.     TimeOfDayMessage("Shutting down", PR_CurrentThread());
  1150.  
  1151.     if (clients != 0)
  1152.     {
  1153.         for (index = 0; index < clients; ++index)
  1154.         {
  1155.             TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, 
  1156.                 ("main(0x%lx): notifying client(0x%lx) to stop\n",
  1157.                 PR_CurrentThread(), client[index].thread));
  1158.  
  1159.             PR_Lock(client[index].ml);
  1160.             if (cs_run == client[index].state)
  1161.             {
  1162.                 client[index].state = cs_stop;
  1163.                 PR_Interrupt(client[index].thread);
  1164.                 while (cs_stop == client[index].state)
  1165.                     PR_WaitCondVar(
  1166.                         client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
  1167.             }
  1168.             PR_Unlock(client[index].ml);
  1169.  
  1170.             TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE, 
  1171.                 ("main(0x%lx): joining client(0x%lx)\n",
  1172.                 PR_CurrentThread(), client[index].thread));
  1173.  
  1174.             joinStatus = PR_JoinThread(client[index].thread);
  1175.             TEST_ASSERT(PR_SUCCESS == joinStatus);
  1176.             PR_DestroyCondVar(client[index].stateChange);
  1177.             PR_DestroyLock(client[index].ml);
  1178.         }
  1179.         PR_DELETE(client);
  1180.     }
  1181.  
  1182.     if (NULL != server)
  1183.     {
  1184.         /* All clients joined - retrieve the server */
  1185.         TEST_LOG(
  1186.             cltsrv_log_file, TEST_LOG_NOTICE, 
  1187.             ("main(0x%lx): notifying server(0x%lx) to stop\n",
  1188.             PR_CurrentThread(), server->thread));
  1189.  
  1190.         PR_Lock(server->ml);
  1191.         server->state = cs_stop;
  1192.         PR_Interrupt(server->thread);
  1193.         while (cs_exit != server->state)
  1194.             PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  1195.         PR_Unlock(server->ml);
  1196.  
  1197.         TEST_LOG(
  1198.             cltsrv_log_file, TEST_LOG_NOTICE, 
  1199.             ("main(0x%lx): joining server(0x%lx)\n",
  1200.             PR_CurrentThread(), server->thread));
  1201.         joinStatus = PR_JoinThread(server->thread);
  1202.         TEST_ASSERT(PR_SUCCESS == joinStatus);
  1203.  
  1204.         PR_DestroyCondVar(server->stateChange);
  1205.         PR_DestroyCondVar(server->pool.exiting);
  1206.         PR_DestroyCondVar(server->pool.acceptComplete);
  1207.         PR_DestroyLock(server->ml);
  1208.         PR_DELETE(server);
  1209.     }
  1210.  
  1211.     TEST_LOG(
  1212.         cltsrv_log_file, TEST_LOG_ALWAYS, 
  1213.         ("main(0x%lx): test complete\n", PR_CurrentThread()));
  1214.  
  1215. #if 0 && defined(DEBUG) && defined(_PR_PTHREADS)
  1216.     PrintPthreadStats();
  1217. #endif  /* defined(DEBUG) && defined(_PR_PTHREADS) */
  1218.  
  1219.     TimeOfDayMessage("Test exiting at", PR_CurrentThread());
  1220.     return 0;
  1221. }  /* xmain */
  1222.  
  1223. PRIntn main(PRIntn argc, char **argv)
  1224. {
  1225.     PRIntn loops = 1;
  1226.     PRIntn rv;
  1227.     PLOptStatus os;
  1228.     PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:l:w:W:e:s:vdhp");
  1229.     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  1230.     {
  1231.         if (PL_OPT_BAD == os) continue;
  1232.         switch (opt->option)
  1233.         {
  1234.         case 'l':  /* number of outer loops */
  1235.             loops = atoi(opt->value);
  1236.             break;
  1237.         default:
  1238.             break;
  1239.         }
  1240.     }
  1241.     PL_DestroyOptState(opt);
  1242.     while (loops-- > 0)
  1243.     {
  1244.         rv = xmain(argc, argv);
  1245.         PR_fprintf(debug_out, "*****\n\n");
  1246.         if (0 != rv) break;
  1247.     }
  1248.     return rv;
  1249. }  /* main */
  1250.  
  1251. /* cltsrv.c */
  1252.