nsprpub/pr/tests/cltsrv.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/tests/cltsrv.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1182 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 + *
    1.11 + * Notes:
    1.12 + * [1] lth. The call to Sleep() is a hack to get the test case to run
    1.13 + * on Windows 95. Without it, the test case fails with an error
    1.14 + * WSAECONNRESET following a recv() call. The error is caused by the
    1.15 + * server side thread termination without a shutdown() or closesocket()
    1.16 + * call. Windows docmunentation suggests that this is predicted
    1.17 + * behavior; that other platforms get away with it is ... serindipity.
    1.18 + * The test case should shutdown() or closesocket() before
    1.19 + * thread termination. I didn't have time to figure out where or how
    1.20 + * to do it. The Sleep() call inserts enough delay to allow the
    1.21 + * client side to recv() all his data before the server side thread
    1.22 + * terminates. Whew! ...
    1.23 + *
    1.24 + ** Modification History:
    1.25 + * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
    1.26 + *             The debug mode will print all of the printfs associated with this test.
    1.27 + *             The regress mode will be the default mode. Since the regress tool limits
    1.28 + *           the output to a one line status:PASS or FAIL,all of the printf statements
    1.29 + *             have been handled with an if (debug_mode) statement. 
    1.30 + */
    1.31 +
    1.32 +#include "prclist.h"
    1.33 +#include "prcvar.h"
    1.34 +#include "prerror.h"
    1.35 +#include "prinit.h"
    1.36 +#include "prinrval.h"
    1.37 +#include "prio.h"
    1.38 +#include "prlock.h"
    1.39 +#include "prlog.h"
    1.40 +#include "prtime.h"
    1.41 +#include "prmem.h"
    1.42 +#include "prnetdb.h"
    1.43 +#include "prprf.h"
    1.44 +#include "prthread.h"
    1.45 +
    1.46 +#include "pprio.h"
    1.47 +#include "primpl.h"
    1.48 +
    1.49 +#include "plstr.h"
    1.50 +#include "plerror.h"
    1.51 +#include "plgetopt.h"
    1.52 +
    1.53 +#include <stdlib.h>
    1.54 +#include <string.h>
    1.55 +
    1.56 +#if defined(XP_UNIX)
    1.57 +#include <math.h>
    1.58 +#endif
    1.59 +
    1.60 +/*
    1.61 +** This is the beginning of the test
    1.62 +*/
    1.63 +
    1.64 +#define RECV_FLAGS 0
    1.65 +#define SEND_FLAGS 0
    1.66 +#define DEFAULT_LOW 0
    1.67 +#define DEFAULT_HIGH 0
    1.68 +#define BUFFER_SIZE 1024
    1.69 +#define DEFAULT_BACKLOG 5
    1.70 +#define DEFAULT_PORT 12849
    1.71 +#define DEFAULT_CLIENTS 1
    1.72 +#define ALLOWED_IN_ACCEPT 1
    1.73 +#define DEFAULT_CLIPPING 1000
    1.74 +#define DEFAULT_WORKERS_MIN 1
    1.75 +#define DEFAULT_WORKERS_MAX 1
    1.76 +#define DEFAULT_SERVER "localhost"
    1.77 +#define DEFAULT_EXECUTION_TIME 10
    1.78 +#define DEFAULT_CLIENT_TIMEOUT 4000
    1.79 +#define DEFAULT_SERVER_TIMEOUT 4000
    1.80 +#define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGH
    1.81 +
    1.82 +typedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t;
    1.83 +
    1.84 +static void PR_CALLBACK Worker(void *arg);
    1.85 +typedef struct CSPool_s CSPool_t;
    1.86 +typedef struct CSWorker_s CSWorker_t;
    1.87 +typedef struct CSServer_s CSServer_t;
    1.88 +typedef enum Verbosity
    1.89 +{
    1.90 +    TEST_LOG_ALWAYS,
    1.91 +    TEST_LOG_ERROR,
    1.92 +    TEST_LOG_WARNING,
    1.93 +    TEST_LOG_NOTICE,
    1.94 +    TEST_LOG_INFO,
    1.95 +    TEST_LOG_STATUS,
    1.96 +    TEST_LOG_VERBOSE
    1.97 +} Verbosity;
    1.98 +
    1.99 +static PRInt32 domain = AF_INET;
   1.100 +static PRInt32 protocol = 6;  /* TCP */
   1.101 +static PRFileDesc *debug_out = NULL;
   1.102 +static PRBool debug_mode = PR_FALSE;
   1.103 +static PRBool pthread_stats = PR_FALSE;
   1.104 +static Verbosity verbosity = TEST_LOG_ALWAYS;
   1.105 +static PRThreadScope thread_scope = PR_LOCAL_THREAD;
   1.106 +
   1.107 +struct CSWorker_s
   1.108 +{
   1.109 +    PRCList element;        /* list of the server's workers */
   1.110 +
   1.111 +    PRThread *thread;       /* this worker objects thread */
   1.112 +    CSServer_t *server;     /* back pointer to server structure */
   1.113 +};
   1.114 +
   1.115 +struct CSPool_s
   1.116 +{
   1.117 +    PRCondVar *exiting;
   1.118 +    PRCondVar *acceptComplete;
   1.119 +    PRUint32 accepting, active, workers;
   1.120 +};
   1.121 +
   1.122 +struct CSServer_s
   1.123 +{
   1.124 +    PRCList list;           /* head of worker list */
   1.125 +
   1.126 +    PRLock *ml;
   1.127 +    PRThread *thread;       /* the main server thread */
   1.128 +    PRCondVar *stateChange;
   1.129 +
   1.130 +    PRUint16 port;          /* port we're listening on */
   1.131 +    PRUint32 backlog;       /* size of our listener backlog */
   1.132 +    PRFileDesc *listener;   /* the fd accepting connections */
   1.133 +
   1.134 +    CSPool_t pool;          /* statistics on worker threads */
   1.135 +    CSState_t state;        /* the server's state */
   1.136 +    struct                  /* controlling worker counts */
   1.137 +    {
   1.138 +        PRUint32 minimum, maximum, accepting;
   1.139 +    } workers;
   1.140 +
   1.141 +    /* statistics */
   1.142 +    PRIntervalTime started, stopped;
   1.143 +    PRUint32 operations, bytesTransferred;
   1.144 +};
   1.145 +
   1.146 +typedef struct CSDescriptor_s
   1.147 +{
   1.148 +    PRInt32 size;       /* size of transfer */
   1.149 +    char filename[60];  /* filename, null padded */
   1.150 +} CSDescriptor_t;
   1.151 +
   1.152 +typedef struct CSClient_s
   1.153 +{
   1.154 +    PRLock *ml;
   1.155 +    PRThread *thread;
   1.156 +    PRCondVar *stateChange;
   1.157 +    PRNetAddr serverAddress;
   1.158 +
   1.159 +    CSState_t state;
   1.160 +
   1.161 +    /* statistics */
   1.162 +    PRIntervalTime started, stopped;
   1.163 +    PRUint32 operations, bytesTransferred;
   1.164 +} CSClient_t;
   1.165 +
   1.166 +#define TEST_LOG(l, p, a) \
   1.167 +    do { \
   1.168 +        if (debug_mode || (p <= verbosity)) printf a; \
   1.169 +    } while (0)
   1.170 +
   1.171 +PRLogModuleInfo *cltsrv_log_file = NULL;
   1.172 +
   1.173 +#define MY_ASSERT(_expr) \
   1.174 +    ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
   1.175 +
   1.176 +#define TEST_ASSERT(_expr) \
   1.177 +    ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
   1.178 +
   1.179 +static void _MY_Assert(const char *s, const char *file, PRIntn ln)
   1.180 +{
   1.181 +    PL_PrintError(NULL);
   1.182 +    PR_Assert(s, file, ln);
   1.183 +}  /* _MY_Assert */
   1.184 +
   1.185 +static PRBool Aborted(PRStatus rv)
   1.186 +{
   1.187 +    return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ?
   1.188 +        PR_TRUE : PR_FALSE;
   1.189 +}
   1.190 +
   1.191 +static void TimeOfDayMessage(const char *msg, PRThread* me)
   1.192 +{
   1.193 +    char buffer[100];
   1.194 +    PRExplodedTime tod;
   1.195 +    PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod);
   1.196 +    (void)PR_FormatTime(buffer, sizeof(buffer), "%H:%M:%S", &tod);
   1.197 +
   1.198 +    TEST_LOG(
   1.199 +        cltsrv_log_file, TEST_LOG_ALWAYS,
   1.200 +        ("%s(0x%p): %s\n", msg, me, buffer));
   1.201 +}  /* TimeOfDayMessage */
   1.202 +
   1.203 +
   1.204 +static void PR_CALLBACK Client(void *arg)
   1.205 +{
   1.206 +    PRStatus rv;
   1.207 +    PRIntn index;
   1.208 +    char buffer[1024];
   1.209 +    PRFileDesc *fd = NULL;
   1.210 +    PRUintn clipping = DEFAULT_CLIPPING;
   1.211 +    PRThread *me = PR_GetCurrentThread();
   1.212 +    CSClient_t *client = (CSClient_t*)arg;
   1.213 +    CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
   1.214 +    PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT);
   1.215 +
   1.216 +
   1.217 +    for (index = 0; index < sizeof(buffer); ++index)
   1.218 +        buffer[index] = (char)index;
   1.219 +
   1.220 +    client->started = PR_IntervalNow();
   1.221 +
   1.222 +    PR_Lock(client->ml);
   1.223 +    client->state = cs_run;
   1.224 +    PR_NotifyCondVar(client->stateChange);
   1.225 +    PR_Unlock(client->ml);
   1.226 +
   1.227 +    TimeOfDayMessage("Client started at", me);
   1.228 +
   1.229 +    while (cs_run == client->state)
   1.230 +    {
   1.231 +        PRInt32 bytes, descbytes, filebytes, netbytes;
   1.232 +
   1.233 +        (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer));
   1.234 +        TEST_LOG(cltsrv_log_file, TEST_LOG_INFO, 
   1.235 +            ("\tClient(0x%p): connecting to server at %s\n", me, buffer));
   1.236 +
   1.237 +        fd = PR_Socket(domain, SOCK_STREAM, protocol);
   1.238 +        TEST_ASSERT(NULL != fd);
   1.239 +        rv = PR_Connect(fd, &client->serverAddress, timeout);
   1.240 +        if (PR_FAILURE == rv)
   1.241 +        {
   1.242 +            TEST_LOG(
   1.243 +                cltsrv_log_file, TEST_LOG_ERROR,
   1.244 +                ("\tClient(0x%p): conection failed (%d, %d)\n",
   1.245 +                me, PR_GetError(), PR_GetOSError()));
   1.246 +            goto aborted;
   1.247 +        }
   1.248 +
   1.249 +        memset(descriptor, 0, sizeof(*descriptor));
   1.250 +        descriptor->size = PR_htonl(descbytes = rand() % clipping);
   1.251 +        PR_snprintf(
   1.252 +            descriptor->filename, sizeof(descriptor->filename),
   1.253 +            "CS%p%p-%p.dat", client->started, me, client->operations);
   1.254 +        TEST_LOG(
   1.255 +            cltsrv_log_file, TEST_LOG_VERBOSE,
   1.256 +            ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes));
   1.257 +        bytes = PR_Send(
   1.258 +            fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout);
   1.259 +        if (sizeof(CSDescriptor_t) != bytes)
   1.260 +        {
   1.261 +            if (Aborted(PR_FAILURE)) goto aborted;
   1.262 +            if (PR_IO_TIMEOUT_ERROR == PR_GetError())
   1.263 +            {
   1.264 +                TEST_LOG(
   1.265 +                    cltsrv_log_file, TEST_LOG_ERROR,
   1.266 +                    ("\tClient(0x%p): send descriptor timeout\n", me));
   1.267 +                goto retry;
   1.268 +            }
   1.269 +        }
   1.270 +        TEST_ASSERT(sizeof(*descriptor) == bytes);
   1.271 +
   1.272 +        netbytes = 0;
   1.273 +        while (netbytes < descbytes)
   1.274 +        {
   1.275 +            filebytes = sizeof(buffer);
   1.276 +            if ((descbytes - netbytes) < filebytes)
   1.277 +                filebytes = descbytes - netbytes;
   1.278 +            TEST_LOG(
   1.279 +                cltsrv_log_file, TEST_LOG_VERBOSE,
   1.280 +                ("\tClient(0x%p): sending %d bytes\n", me, filebytes));
   1.281 +            bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
   1.282 +            if (filebytes != bytes)
   1.283 +            {
   1.284 +                if (Aborted(PR_FAILURE)) goto aborted;
   1.285 +                if (PR_IO_TIMEOUT_ERROR == PR_GetError())
   1.286 +                {
   1.287 +                    TEST_LOG(
   1.288 +                        cltsrv_log_file, TEST_LOG_ERROR,
   1.289 +                        ("\tClient(0x%p): send data timeout\n", me));
   1.290 +                    goto retry;
   1.291 +                }
   1.292 +            }
   1.293 +            TEST_ASSERT(bytes == filebytes);
   1.294 +            netbytes += bytes;
   1.295 +        }
   1.296 +        filebytes = 0;
   1.297 +        while (filebytes < descbytes)
   1.298 +        {
   1.299 +            netbytes = sizeof(buffer);
   1.300 +            if ((descbytes - filebytes) < netbytes)
   1.301 +                netbytes = descbytes - filebytes;
   1.302 +            TEST_LOG(
   1.303 +                cltsrv_log_file, TEST_LOG_VERBOSE,
   1.304 +                ("\tClient(0x%p): receiving %d bytes\n", me, netbytes));
   1.305 +            bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
   1.306 +            if (-1 == bytes)
   1.307 +            {
   1.308 +                if (Aborted(PR_FAILURE))
   1.309 +                {
   1.310 +                    TEST_LOG(
   1.311 +                        cltsrv_log_file, TEST_LOG_ERROR,
   1.312 +                        ("\tClient(0x%p): receive data aborted\n", me));
   1.313 +                    goto aborted;
   1.314 +                }
   1.315 +                else if (PR_IO_TIMEOUT_ERROR == PR_GetError())
   1.316 +                    TEST_LOG(
   1.317 +                        cltsrv_log_file, TEST_LOG_ERROR,
   1.318 +                        ("\tClient(0x%p): receive data timeout\n", me));
   1.319 +				else
   1.320 +                    TEST_LOG(
   1.321 +                        cltsrv_log_file, TEST_LOG_ERROR,
   1.322 +                        ("\tClient(0x%p): receive error (%d, %d)\n",
   1.323 +						me, PR_GetError(), PR_GetOSError()));
   1.324 +                goto retry;
   1.325 +           }
   1.326 +            if (0 == bytes)
   1.327 +            {
   1.328 +                TEST_LOG(
   1.329 +                    cltsrv_log_file, TEST_LOG_ERROR,
   1.330 +                    ("\t\tClient(0x%p): unexpected end of stream\n",
   1.331 +                    PR_GetCurrentThread()));
   1.332 +                break;
   1.333 +            }
   1.334 +            filebytes += bytes;
   1.335 +        }
   1.336 +
   1.337 +        rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
   1.338 +        if (Aborted(rv)) goto aborted;
   1.339 +        TEST_ASSERT(PR_SUCCESS == rv);
   1.340 +retry:
   1.341 +        (void)PR_Close(fd); fd = NULL;
   1.342 +        TEST_LOG(
   1.343 +            cltsrv_log_file, TEST_LOG_INFO,
   1.344 +            ("\tClient(0x%p): disconnected from server\n", me));
   1.345 +
   1.346 +        PR_Lock(client->ml);
   1.347 +        client->operations += 1;
   1.348 +        client->bytesTransferred += 2 * descbytes;
   1.349 +        rv = PR_WaitCondVar(client->stateChange, rand() % clipping);
   1.350 +        PR_Unlock(client->ml);
   1.351 +        if (Aborted(rv)) break;
   1.352 +    }
   1.353 +
   1.354 +aborted:
   1.355 +    client->stopped = PR_IntervalNow();
   1.356 +
   1.357 +    PR_ClearInterrupt();
   1.358 +    if (NULL != fd) rv = PR_Close(fd);
   1.359 +
   1.360 +    PR_Lock(client->ml);
   1.361 +    client->state = cs_exit;
   1.362 +    PR_NotifyCondVar(client->stateChange);
   1.363 +    PR_Unlock(client->ml);
   1.364 +    PR_DELETE(descriptor);
   1.365 +    TEST_LOG(
   1.366 +        cltsrv_log_file, TEST_LOG_ALWAYS,
   1.367 +        ("\tClient(0x%p): stopped after %u operations and %u bytes\n",
   1.368 +        PR_GetCurrentThread(), client->operations, client->bytesTransferred));
   1.369 +
   1.370 +}  /* Client */
   1.371 +
   1.372 +static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server)
   1.373 +{
   1.374 +    PRStatus drv, rv;
   1.375 +    char buffer[1024];
   1.376 +    PRFileDesc *file = NULL;
   1.377 +    PRThread * me = PR_GetCurrentThread();
   1.378 +    PRInt32 bytes, descbytes, netbytes, filebytes = 0;
   1.379 +    CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
   1.380 +    PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT);
   1.381 +
   1.382 +    TEST_LOG(
   1.383 +        cltsrv_log_file, TEST_LOG_VERBOSE,
   1.384 +        ("\tProcessRequest(0x%p): receiving desciptor\n", me));
   1.385 +    bytes = PR_Recv(
   1.386 +        fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout);
   1.387 +    if (-1 == bytes)
   1.388 +    {
   1.389 +        rv = PR_FAILURE;
   1.390 +        if (Aborted(rv)) goto exit;
   1.391 +        if (PR_IO_TIMEOUT_ERROR == PR_GetError())
   1.392 +        {
   1.393 +            TEST_LOG(
   1.394 +                cltsrv_log_file, TEST_LOG_ERROR,
   1.395 +                ("\tProcessRequest(0x%p): receive timeout\n", me));
   1.396 +        }
   1.397 +        goto exit;
   1.398 +    }
   1.399 +    if (0 == bytes)
   1.400 +    {
   1.401 +        rv = PR_FAILURE;
   1.402 +        TEST_LOG(
   1.403 +            cltsrv_log_file, TEST_LOG_ERROR,
   1.404 +            ("\tProcessRequest(0x%p): unexpected end of file\n", me));
   1.405 +        goto exit;
   1.406 +    }
   1.407 +    descbytes = PR_ntohl(descriptor->size);
   1.408 +    TEST_ASSERT(sizeof(*descriptor) == bytes);
   1.409 +
   1.410 +    TEST_LOG(
   1.411 +        cltsrv_log_file, TEST_LOG_VERBOSE, 
   1.412 +        ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n",
   1.413 +        me, descbytes, descriptor->filename));
   1.414 +
   1.415 +    file = PR_Open(
   1.416 +        descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666);
   1.417 +    if (NULL == file)
   1.418 +    {
   1.419 +        rv = PR_FAILURE;
   1.420 +        if (Aborted(rv)) goto aborted;
   1.421 +        if (PR_IO_TIMEOUT_ERROR == PR_GetError())
   1.422 +        {
   1.423 +            TEST_LOG(
   1.424 +                cltsrv_log_file, TEST_LOG_ERROR,
   1.425 +                ("\tProcessRequest(0x%p): open file timeout\n", me));
   1.426 +            goto aborted;
   1.427 +        }
   1.428 +    }
   1.429 +    TEST_ASSERT(NULL != file);
   1.430 +
   1.431 +    filebytes = 0;
   1.432 +    while (filebytes < descbytes)
   1.433 +    {
   1.434 +        netbytes = sizeof(buffer);
   1.435 +        if ((descbytes - filebytes) < netbytes)
   1.436 +            netbytes = descbytes - filebytes;
   1.437 +        TEST_LOG(
   1.438 +            cltsrv_log_file, TEST_LOG_VERBOSE,
   1.439 +            ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes));
   1.440 +        bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
   1.441 +        if (-1 == bytes)
   1.442 +        {
   1.443 +            rv = PR_FAILURE;
   1.444 +            if (Aborted(rv)) goto aborted;
   1.445 +            if (PR_IO_TIMEOUT_ERROR == PR_GetError())
   1.446 +            {
   1.447 +                TEST_LOG(
   1.448 +                    cltsrv_log_file, TEST_LOG_ERROR,
   1.449 +                    ("\t\tProcessRequest(0x%p): receive data timeout\n", me));
   1.450 +                goto aborted;
   1.451 +            }
   1.452 +            /*
   1.453 +             * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED)
   1.454 +             * on NT here.  This is equivalent to ECONNRESET on Unix.
   1.455 +             *     -wtc
   1.456 +             */
   1.457 +            TEST_LOG(
   1.458 +                cltsrv_log_file, TEST_LOG_WARNING,
   1.459 +                ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n",
   1.460 +                me, PR_GetError(), PR_GetOSError()));
   1.461 +            goto aborted;
   1.462 +        }
   1.463 +        if(0 == bytes)
   1.464 +        {
   1.465 +            TEST_LOG(
   1.466 +                cltsrv_log_file, TEST_LOG_WARNING,
   1.467 +                ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me));
   1.468 +            rv = PR_FAILURE;
   1.469 +            goto aborted;
   1.470 +        }
   1.471 +        filebytes += bytes;
   1.472 +        netbytes = bytes;
   1.473 +        /* The byte count for PR_Write should be positive */
   1.474 +        MY_ASSERT(netbytes > 0);
   1.475 +        TEST_LOG(
   1.476 +            cltsrv_log_file, TEST_LOG_VERBOSE,
   1.477 +            ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes));
   1.478 +        bytes = PR_Write(file, buffer, netbytes);
   1.479 +        if (netbytes != bytes)
   1.480 +        {
   1.481 +            rv = PR_FAILURE;
   1.482 +            if (Aborted(rv)) goto aborted;
   1.483 +            if (PR_IO_TIMEOUT_ERROR == PR_GetError())
   1.484 +            {
   1.485 +                TEST_LOG(
   1.486 +                    cltsrv_log_file, TEST_LOG_ERROR,
   1.487 +                    ("\t\tProcessRequest(0x%p): write file timeout\n", me));
   1.488 +                goto aborted;
   1.489 +            }
   1.490 +        }
   1.491 +        TEST_ASSERT(bytes > 0);
   1.492 +    }
   1.493 +
   1.494 +    PR_Lock(server->ml);
   1.495 +    server->operations += 1;
   1.496 +    server->bytesTransferred += filebytes;
   1.497 +    PR_Unlock(server->ml);
   1.498 +
   1.499 +    rv = PR_Close(file);
   1.500 +    if (Aborted(rv)) goto aborted;
   1.501 +    TEST_ASSERT(PR_SUCCESS == rv);
   1.502 +    file = NULL;
   1.503 +
   1.504 +    TEST_LOG(
   1.505 +        cltsrv_log_file, TEST_LOG_VERBOSE,
   1.506 +        ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename));
   1.507 +    file = PR_Open(descriptor->filename, PR_RDONLY, 0);
   1.508 +    if (NULL == file)
   1.509 +    {
   1.510 +        rv = PR_FAILURE;
   1.511 +        if (Aborted(rv)) goto aborted;
   1.512 +        if (PR_IO_TIMEOUT_ERROR == PR_GetError())
   1.513 +        {
   1.514 +            TEST_LOG(
   1.515 +                cltsrv_log_file, TEST_LOG_ERROR,
   1.516 +                ("\t\tProcessRequest(0x%p): open file timeout\n",
   1.517 +                PR_GetCurrentThread()));
   1.518 +            goto aborted;
   1.519 +        }
   1.520 +        TEST_LOG(
   1.521 +            cltsrv_log_file, TEST_LOG_ERROR,
   1.522 +            ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n",
   1.523 +            me, PR_GetError(), PR_GetOSError()));
   1.524 +        goto aborted;
   1.525 +    }
   1.526 +    TEST_ASSERT(NULL != file);
   1.527 +
   1.528 +    netbytes = 0;
   1.529 +    while (netbytes < descbytes)
   1.530 +    {
   1.531 +        filebytes = sizeof(buffer);
   1.532 +        if ((descbytes - netbytes) < filebytes)
   1.533 +            filebytes = descbytes - netbytes;
   1.534 +        TEST_LOG(
   1.535 +            cltsrv_log_file, TEST_LOG_VERBOSE,
   1.536 +            ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes));
   1.537 +        bytes = PR_Read(file, buffer, filebytes);
   1.538 +        if (filebytes != bytes)
   1.539 +        {
   1.540 +            rv = PR_FAILURE;
   1.541 +            if (Aborted(rv)) goto aborted;
   1.542 +            if (PR_IO_TIMEOUT_ERROR == PR_GetError())
   1.543 +                TEST_LOG(
   1.544 +                    cltsrv_log_file, TEST_LOG_ERROR,
   1.545 +                    ("\t\tProcessRequest(0x%p): read file timeout\n", me));
   1.546 +            else
   1.547 +                TEST_LOG(
   1.548 +                    cltsrv_log_file, TEST_LOG_ERROR,
   1.549 +                    ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n",
   1.550 +                    me, PR_GetError(), PR_GetOSError()));
   1.551 +            goto aborted;
   1.552 +        }
   1.553 +        TEST_ASSERT(bytes > 0);
   1.554 +        netbytes += bytes;
   1.555 +        filebytes = bytes;
   1.556 +        TEST_LOG(
   1.557 +            cltsrv_log_file, TEST_LOG_VERBOSE,
   1.558 +            ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes));
   1.559 +        bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
   1.560 +        if (filebytes != bytes)
   1.561 +        {
   1.562 +            rv = PR_FAILURE;
   1.563 +            if (Aborted(rv)) goto aborted;
   1.564 +            if (PR_IO_TIMEOUT_ERROR == PR_GetError())
   1.565 +            {
   1.566 +                TEST_LOG(
   1.567 +                    cltsrv_log_file, TEST_LOG_ERROR,
   1.568 +                    ("\t\tProcessRequest(0x%p): send data timeout\n", me));
   1.569 +                goto aborted;
   1.570 +            }
   1.571 +            break;
   1.572 +        }
   1.573 +       TEST_ASSERT(bytes > 0);
   1.574 +    }
   1.575 +    
   1.576 +    PR_Lock(server->ml);
   1.577 +    server->bytesTransferred += filebytes;
   1.578 +    PR_Unlock(server->ml);
   1.579 +
   1.580 +    rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
   1.581 +    if (Aborted(rv)) goto aborted;
   1.582 +
   1.583 +    rv = PR_Close(file);
   1.584 +    if (Aborted(rv)) goto aborted;
   1.585 +    TEST_ASSERT(PR_SUCCESS == rv);
   1.586 +    file = NULL;
   1.587 +
   1.588 +aborted:
   1.589 +    PR_ClearInterrupt();
   1.590 +    if (NULL != file) PR_Close(file);
   1.591 +    drv = PR_Delete(descriptor->filename);
   1.592 +    TEST_ASSERT(PR_SUCCESS == drv);
   1.593 +exit:
   1.594 +    TEST_LOG(
   1.595 +        cltsrv_log_file, TEST_LOG_VERBOSE,
   1.596 +        ("\t\tProcessRequest(0x%p): Finished\n", me));
   1.597 +
   1.598 +    PR_DELETE(descriptor);
   1.599 +
   1.600 +#if defined(WIN95)
   1.601 +    PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */
   1.602 +#endif
   1.603 +    return rv;
   1.604 +}  /* ProcessRequest */
   1.605 +
   1.606 +static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool)
   1.607 +{
   1.608 +    CSWorker_t *worker = PR_NEWZAP(CSWorker_t);
   1.609 +    worker->server = server;
   1.610 +    PR_INIT_CLIST(&worker->element);
   1.611 +    worker->thread = PR_CreateThread(
   1.612 +        PR_USER_THREAD, Worker, worker,
   1.613 +        DEFAULT_SERVER_PRIORITY, thread_scope,
   1.614 +        PR_UNJOINABLE_THREAD, 0);
   1.615 +    if (NULL == worker->thread)
   1.616 +    {
   1.617 +        PR_DELETE(worker);
   1.618 +        return PR_FAILURE;
   1.619 +    }
   1.620 +
   1.621 +    TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, 
   1.622 +        ("\tCreateWorker(0x%p): create new worker (0x%p)\n",
   1.623 +        PR_GetCurrentThread(), worker->thread));
   1.624 +
   1.625 +    return PR_SUCCESS;
   1.626 +}  /* CreateWorker */
   1.627 +
   1.628 +static void PR_CALLBACK Worker(void *arg)
   1.629 +{
   1.630 +    PRStatus rv;
   1.631 +    PRNetAddr from;
   1.632 +    PRFileDesc *fd = NULL;
   1.633 +    PRThread *me = PR_GetCurrentThread();
   1.634 +    CSWorker_t *worker = (CSWorker_t*)arg;
   1.635 +    CSServer_t *server = worker->server;
   1.636 +    CSPool_t *pool = &server->pool;
   1.637 +
   1.638 +    TEST_LOG(
   1.639 +        cltsrv_log_file, TEST_LOG_NOTICE,
   1.640 +        ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1));
   1.641 +
   1.642 +    PR_Lock(server->ml);
   1.643 +    PR_APPEND_LINK(&worker->element, &server->list);
   1.644 +    pool->workers += 1;  /* define our existance */
   1.645 +
   1.646 +    while (cs_run == server->state)
   1.647 +    {
   1.648 +        while (pool->accepting >= server->workers.accepting)
   1.649 +        {
   1.650 +            TEST_LOG(
   1.651 +                cltsrv_log_file, TEST_LOG_VERBOSE,
   1.652 +                ("\t\tWorker(0x%p): waiting for accept slot[%d]\n",
   1.653 +                me, pool->accepting));
   1.654 +            rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT);
   1.655 +            if (Aborted(rv) || (cs_run != server->state))
   1.656 +            {
   1.657 +                TEST_LOG(
   1.658 +                    cltsrv_log_file, TEST_LOG_NOTICE,
   1.659 +                    ("\tWorker(0x%p): has been %s\n",
   1.660 +                    me, (Aborted(rv) ? "interrupted" : "stopped")));
   1.661 +                goto exit;
   1.662 +            }
   1.663 +        } 
   1.664 +        pool->accepting += 1;  /* how many are really in accept */
   1.665 +        PR_Unlock(server->ml);
   1.666 +
   1.667 +        TEST_LOG(
   1.668 +            cltsrv_log_file, TEST_LOG_VERBOSE,
   1.669 +            ("\t\tWorker(0x%p): calling accept\n", me));
   1.670 +        fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT);
   1.671 +
   1.672 +        PR_Lock(server->ml);        
   1.673 +        pool->accepting -= 1;
   1.674 +        PR_NotifyCondVar(pool->acceptComplete);
   1.675 +
   1.676 +        if ((NULL == fd) && Aborted(PR_FAILURE))
   1.677 +        {
   1.678 +            if (NULL != server->listener)
   1.679 +            {
   1.680 +                PR_Close(server->listener);
   1.681 +                server->listener = NULL;
   1.682 +            }
   1.683 +            goto exit;
   1.684 +        }
   1.685 +
   1.686 +        if (NULL != fd)
   1.687 +        {
   1.688 +            /*
   1.689 +            ** Create another worker of the total number of workers is
   1.690 +            ** less than the minimum specified or we have none left in
   1.691 +            ** accept() AND we're not over the maximum.
   1.692 +            ** This sort of presumes that the number allowed in accept
   1.693 +            ** is at least as many as the minimum. Otherwise we'll keep
   1.694 +            ** creating new threads and deleting them soon after.
   1.695 +            */
   1.696 +            PRBool another =
   1.697 +                ((pool->workers < server->workers.minimum) ||
   1.698 +                ((0 == pool->accepting)
   1.699 +                    && (pool->workers < server->workers.maximum))) ?
   1.700 +                    PR_TRUE : PR_FALSE;
   1.701 +            pool->active += 1;
   1.702 +            PR_Unlock(server->ml);
   1.703 +
   1.704 +            if (another) (void)CreateWorker(server, pool);
   1.705 +
   1.706 +            rv = ProcessRequest(fd, server);
   1.707 +            if (PR_SUCCESS != rv)
   1.708 +                TEST_LOG(
   1.709 +                    cltsrv_log_file, TEST_LOG_ERROR,
   1.710 +                    ("\t\tWorker(0x%p): server process ended abnormally\n", me));
   1.711 +            (void)PR_Close(fd); fd = NULL;
   1.712 +
   1.713 +            PR_Lock(server->ml);
   1.714 +            pool->active -= 1;
   1.715 +        }
   1.716 +    }
   1.717 +
   1.718 +exit:
   1.719 +    PR_ClearInterrupt();    
   1.720 +    PR_Unlock(server->ml);
   1.721 +
   1.722 +    if (NULL != fd)
   1.723 +    {
   1.724 +        (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
   1.725 +        (void)PR_Close(fd);
   1.726 +    }
   1.727 +
   1.728 +    TEST_LOG(
   1.729 +        cltsrv_log_file, TEST_LOG_NOTICE,
   1.730 +        ("\t\tWorker(0x%p): exiting [%u]\n", PR_GetCurrentThread(), pool->workers));
   1.731 +
   1.732 +    PR_Lock(server->ml);
   1.733 +    pool->workers -= 1;  /* undefine our existance */
   1.734 +    PR_REMOVE_AND_INIT_LINK(&worker->element);
   1.735 +    PR_NotifyCondVar(pool->exiting);
   1.736 +    PR_Unlock(server->ml);
   1.737 +
   1.738 +    PR_DELETE(worker);  /* destruction of the "worker" object */
   1.739 +
   1.740 +}  /* Worker */
   1.741 +
   1.742 +static void PR_CALLBACK Server(void *arg)
   1.743 +{
   1.744 +    PRStatus rv;
   1.745 +    PRNetAddr serverAddress;
   1.746 +    PRThread *me = PR_GetCurrentThread();
   1.747 +    CSServer_t *server = (CSServer_t*)arg;
   1.748 +    PRSocketOptionData sockOpt;
   1.749 +
   1.750 +    server->listener = PR_Socket(domain, SOCK_STREAM, protocol);
   1.751 +
   1.752 +    sockOpt.option = PR_SockOpt_Reuseaddr;
   1.753 +    sockOpt.value.reuse_addr = PR_TRUE;
   1.754 +    rv = PR_SetSocketOption(server->listener, &sockOpt);
   1.755 +    TEST_ASSERT(PR_SUCCESS == rv);
   1.756 +
   1.757 +    memset(&serverAddress, 0, sizeof(serverAddress));
   1.758 +	if (PR_AF_INET6 != domain)
   1.759 +		rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress);
   1.760 +	else
   1.761 +		rv = PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, DEFAULT_PORT,
   1.762 +													&serverAddress);
   1.763 +    rv = PR_Bind(server->listener, &serverAddress);
   1.764 +    TEST_ASSERT(PR_SUCCESS == rv);
   1.765 +
   1.766 +    rv = PR_Listen(server->listener, server->backlog);
   1.767 +    TEST_ASSERT(PR_SUCCESS == rv);
   1.768 +
   1.769 +    server->started = PR_IntervalNow();
   1.770 +    TimeOfDayMessage("Server started at", me);
   1.771 +
   1.772 +    PR_Lock(server->ml);
   1.773 +    server->state = cs_run;
   1.774 +    PR_NotifyCondVar(server->stateChange);
   1.775 +    PR_Unlock(server->ml);
   1.776 +
   1.777 +    /*
   1.778 +    ** Create the first worker (actually, a thread that accepts
   1.779 +    ** connections and then processes the work load as needed).
   1.780 +    ** From this point on, additional worker threads are created
   1.781 +    ** as they are needed by existing worker threads.
   1.782 +    */
   1.783 +    rv = CreateWorker(server, &server->pool);
   1.784 +    TEST_ASSERT(PR_SUCCESS == rv);
   1.785 +
   1.786 +    /*
   1.787 +    ** From here on this thread is merely hanging around as the contact
   1.788 +    ** point for the main test driver. It's just waiting for the driver
   1.789 +    ** to declare the test complete.
   1.790 +    */
   1.791 +    TEST_LOG(
   1.792 +        cltsrv_log_file, TEST_LOG_VERBOSE,
   1.793 +        ("\tServer(0x%p): waiting for state change\n", me));
   1.794 +
   1.795 +    PR_Lock(server->ml);
   1.796 +    while ((cs_run == server->state) && !Aborted(rv))
   1.797 +    {
   1.798 +        rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
   1.799 +    }
   1.800 +    PR_Unlock(server->ml);
   1.801 +    PR_ClearInterrupt();
   1.802 +
   1.803 +    TEST_LOG(
   1.804 +        cltsrv_log_file, TEST_LOG_INFO,
   1.805 +        ("\tServer(0x%p): shutting down workers\n", me));
   1.806 +
   1.807 +    /*
   1.808 +    ** Get all the worker threads to exit. They know how to
   1.809 +    ** clean up after themselves, so this is just a matter of
   1.810 +    ** waiting for clorine in the pool to take effect. During
   1.811 +    ** this stage we're ignoring interrupts.
   1.812 +    */
   1.813 +    server->workers.minimum = server->workers.maximum = 0;
   1.814 +
   1.815 +    PR_Lock(server->ml);
   1.816 +    while (!PR_CLIST_IS_EMPTY(&server->list))
   1.817 +    {
   1.818 +        PRCList *head = PR_LIST_HEAD(&server->list);
   1.819 +        CSWorker_t *worker = (CSWorker_t*)head;
   1.820 +        TEST_LOG(
   1.821 +            cltsrv_log_file, TEST_LOG_VERBOSE,
   1.822 +            ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker));
   1.823 +        rv = PR_Interrupt(worker->thread);
   1.824 +        TEST_ASSERT(PR_SUCCESS == rv);
   1.825 +        PR_REMOVE_AND_INIT_LINK(head);
   1.826 +    }
   1.827 +
   1.828 +    while (server->pool.workers > 0)
   1.829 +    {
   1.830 +        TEST_LOG(
   1.831 +            cltsrv_log_file, TEST_LOG_NOTICE,
   1.832 +            ("\tServer(0x%p): waiting for %u workers to exit\n",
   1.833 +            me, server->pool.workers));
   1.834 +        (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT);
   1.835 +    }
   1.836 +
   1.837 +    server->state = cs_exit;
   1.838 +    PR_NotifyCondVar(server->stateChange);
   1.839 +    PR_Unlock(server->ml);
   1.840 +
   1.841 +    TEST_LOG(
   1.842 +        cltsrv_log_file, TEST_LOG_ALWAYS,
   1.843 +        ("\tServer(0x%p): stopped after %u operations and %u bytes\n",
   1.844 +        me, server->operations, server->bytesTransferred));
   1.845 +
   1.846 +    if (NULL != server->listener) PR_Close(server->listener);
   1.847 +    server->stopped = PR_IntervalNow();
   1.848 +
   1.849 +}  /* Server */
   1.850 +
   1.851 +static void WaitForCompletion(PRIntn execution)
   1.852 +{
   1.853 +    while (execution > 0)
   1.854 +    { 
   1.855 +        PRIntn dally = (execution > 30) ? 30 : execution;
   1.856 +        PR_Sleep(PR_SecondsToInterval(dally));
   1.857 +        if (pthread_stats) PT_FPrintStats(debug_out, "\nPThread Statistics\n");
   1.858 +        execution -= dally;
   1.859 +    }
   1.860 +}  /* WaitForCompletion */
   1.861 +
   1.862 +static void Help(void)
   1.863 +{
   1.864 +    PR_fprintf(debug_out, "cltsrv test program usage:\n");
   1.865 +    PR_fprintf(debug_out, "\t-a <n>       threads allowed in accept        (5)\n");
   1.866 +    PR_fprintf(debug_out, "\t-b <n>       backlock for listen              (5)\n");
   1.867 +    PR_fprintf(debug_out, "\t-c <threads> number of clients to create      (1)\n");
   1.868 +    PR_fprintf(debug_out, "\t-f <low>     low water mark for fd caching    (0)\n");
   1.869 +    PR_fprintf(debug_out, "\t-F <high>    high water mark for fd caching   (0)\n");
   1.870 +    PR_fprintf(debug_out, "\t-w <threads> minimal number of server threads (1)\n");
   1.871 +    PR_fprintf(debug_out, "\t-W <threads> maximum number of server threads (1)\n");
   1.872 +    PR_fprintf(debug_out, "\t-e <seconds> duration of the test in seconds  (10)\n");
   1.873 +    PR_fprintf(debug_out, "\t-s <string>  dsn name of server               (localhost)\n");
   1.874 +    PR_fprintf(debug_out, "\t-G           use GLOBAL threads               (LOCAL)\n");
   1.875 +    PR_fprintf(debug_out, "\t-X           use XTP as transport             (TCP)\n");
   1.876 +    PR_fprintf(debug_out, "\t-6           Use IPv6                         (IPv4)\n");
   1.877 +    PR_fprintf(debug_out, "\t-v           verbosity (accumulative)         (0)\n");
   1.878 +    PR_fprintf(debug_out, "\t-p           pthread statistics               (FALSE)\n");
   1.879 +    PR_fprintf(debug_out, "\t-d           debug mode                       (FALSE)\n");
   1.880 +    PR_fprintf(debug_out, "\t-h           this message\n");
   1.881 +}  /* Help */
   1.882 +
   1.883 +static Verbosity IncrementVerbosity(void)
   1.884 +{
   1.885 +    PRIntn verboge = (PRIntn)verbosity + 1;
   1.886 +    return (Verbosity)verboge;
   1.887 +}  /* IncrementVerbosity */
   1.888 +
   1.889 +int main(int argc, char** argv)
   1.890 +{
   1.891 +    PRUintn index;
   1.892 +    PRBool boolean;
   1.893 +    CSClient_t *client;
   1.894 +    PRStatus rv, joinStatus;
   1.895 +    CSServer_t *server = NULL;
   1.896 +
   1.897 +    PRUintn backlog = DEFAULT_BACKLOG;
   1.898 +    PRUintn clients = DEFAULT_CLIENTS;
   1.899 +    const char *serverName = DEFAULT_SERVER;
   1.900 +    PRBool serverIsLocal = PR_TRUE;
   1.901 +    PRUintn accepting = ALLOWED_IN_ACCEPT;
   1.902 +    PRUintn workersMin = DEFAULT_WORKERS_MIN;
   1.903 +    PRUintn workersMax = DEFAULT_WORKERS_MAX;
   1.904 +    PRIntn execution = DEFAULT_EXECUTION_TIME;
   1.905 +    PRIntn low = DEFAULT_LOW, high = DEFAULT_HIGH;
   1.906 +
   1.907 +    /*
   1.908 +     * -G           use global threads
   1.909 +     * -a <n>       threads allowed in accept
   1.910 +     * -b <n>       backlock for listen
   1.911 +     * -c <threads> number of clients to create
   1.912 +     * -f <low>     low water mark for caching FDs
   1.913 +     * -F <high>    high water mark for caching FDs
   1.914 +     * -w <threads> minimal number of server threads
   1.915 +     * -W <threads> maximum number of server threads
   1.916 +     * -e <seconds> duration of the test in seconds
   1.917 +     * -s <string>  dsn name of server (implies no server here)
   1.918 +     * -v           verbosity
   1.919 +     */
   1.920 +
   1.921 +    PLOptStatus os;
   1.922 +    PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:f:F:w:W:e:s:vdhp");
   1.923 +
   1.924 +    debug_out = PR_GetSpecialFD(PR_StandardError);
   1.925 +
   1.926 +    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
   1.927 +    {
   1.928 +        if (PL_OPT_BAD == os) continue;
   1.929 +        switch (opt->option)
   1.930 +        {
   1.931 +        case 'G':  /* use global threads */
   1.932 +            thread_scope = PR_GLOBAL_THREAD;
   1.933 +            break;
   1.934 +        case 'X':  /* use XTP as transport */
   1.935 +            protocol = 36;
   1.936 +            break;
   1.937 +        case '6':  /* Use IPv6 */
   1.938 +            domain = PR_AF_INET6;
   1.939 +            break;
   1.940 +        case 'a':  /* the value for accepting */
   1.941 +            accepting = atoi(opt->value);
   1.942 +            break;
   1.943 +        case 'b':  /* the value for backlock */
   1.944 +            backlog = atoi(opt->value);
   1.945 +            break;
   1.946 +        case 'c':  /* number of client threads */
   1.947 +            clients = atoi(opt->value);
   1.948 +            break;
   1.949 +        case 'f':  /* low water fd cache */
   1.950 +            low = atoi(opt->value);
   1.951 +            break;
   1.952 +        case 'F':  /* low water fd cache */
   1.953 +            high = atoi(opt->value);
   1.954 +            break;
   1.955 +        case 'w':  /* minimum server worker threads */
   1.956 +            workersMin = atoi(opt->value);
   1.957 +            break;
   1.958 +        case 'W':  /* maximum server worker threads */
   1.959 +            workersMax = atoi(opt->value);
   1.960 +            break;
   1.961 +        case 'e':  /* program execution time in seconds */
   1.962 +            execution = atoi(opt->value);
   1.963 +            break;
   1.964 +        case 's':  /* server's address */
   1.965 +            serverName = opt->value;
   1.966 +            break;
   1.967 +        case 'v':  /* verbosity */
   1.968 +            verbosity = IncrementVerbosity();
   1.969 +            break;
   1.970 +        case 'd':  /* debug mode */
   1.971 +            debug_mode = PR_TRUE;
   1.972 +            break;
   1.973 +        case 'p':  /* pthread mode */
   1.974 +            pthread_stats = PR_TRUE;
   1.975 +            break;
   1.976 +        case 'h':
   1.977 +        default:
   1.978 +            Help();
   1.979 +            return 2;
   1.980 +        }
   1.981 +    }
   1.982 +    PL_DestroyOptState(opt);
   1.983 +
   1.984 +    if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) serverIsLocal = PR_FALSE;
   1.985 +    if (0 == execution) execution = DEFAULT_EXECUTION_TIME;
   1.986 +    if (0 == workersMax) workersMax = DEFAULT_WORKERS_MAX;
   1.987 +    if (0 == workersMin) workersMin = DEFAULT_WORKERS_MIN;
   1.988 +    if (0 == accepting) accepting = ALLOWED_IN_ACCEPT;
   1.989 +    if (0 == backlog) backlog = DEFAULT_BACKLOG;
   1.990 +
   1.991 +    if (workersMin > accepting) accepting = workersMin;
   1.992 +
   1.993 +    PR_STDIO_INIT();
   1.994 +    TimeOfDayMessage("Client/Server started at", PR_GetCurrentThread());
   1.995 +
   1.996 +    cltsrv_log_file = PR_NewLogModule("cltsrv_log");
   1.997 +    MY_ASSERT(NULL != cltsrv_log_file);
   1.998 +    boolean = PR_SetLogFile("cltsrv.log");
   1.999 +    MY_ASSERT(boolean);
  1.1000 +
  1.1001 +    rv = PR_SetFDCacheSize(low, high);
  1.1002 +    PR_ASSERT(PR_SUCCESS == rv);
  1.1003 +
  1.1004 +    if (serverIsLocal)
  1.1005 +    {
  1.1006 +        /* Establish the server */
  1.1007 +        TEST_LOG(
  1.1008 +            cltsrv_log_file, TEST_LOG_INFO,
  1.1009 +            ("main(0x%p): starting server\n", PR_GetCurrentThread()));
  1.1010 +
  1.1011 +        server = PR_NEWZAP(CSServer_t);
  1.1012 +        PR_INIT_CLIST(&server->list);
  1.1013 +        server->state = cs_init;
  1.1014 +        server->ml = PR_NewLock();
  1.1015 +        server->backlog = backlog;
  1.1016 +        server->port = DEFAULT_PORT;
  1.1017 +        server->workers.minimum = workersMin;
  1.1018 +        server->workers.maximum = workersMax;
  1.1019 +        server->workers.accepting = accepting;
  1.1020 +        server->stateChange = PR_NewCondVar(server->ml);
  1.1021 +        server->pool.exiting = PR_NewCondVar(server->ml);
  1.1022 +        server->pool.acceptComplete = PR_NewCondVar(server->ml);
  1.1023 +
  1.1024 +        TEST_LOG(
  1.1025 +            cltsrv_log_file, TEST_LOG_NOTICE,
  1.1026 +            ("main(0x%p): creating server thread\n", PR_GetCurrentThread()));
  1.1027 +
  1.1028 +        server->thread = PR_CreateThread(
  1.1029 +            PR_USER_THREAD, Server, server, PR_PRIORITY_HIGH,
  1.1030 +            thread_scope, PR_JOINABLE_THREAD, 0);
  1.1031 +        TEST_ASSERT(NULL != server->thread);
  1.1032 +
  1.1033 +        TEST_LOG(
  1.1034 +            cltsrv_log_file, TEST_LOG_VERBOSE,
  1.1035 +            ("main(0x%p): waiting for server init\n", PR_GetCurrentThread()));
  1.1036 +
  1.1037 +        PR_Lock(server->ml);
  1.1038 +        while (server->state == cs_init)
  1.1039 +            PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  1.1040 +        PR_Unlock(server->ml);
  1.1041 +
  1.1042 +        TEST_LOG(
  1.1043 +            cltsrv_log_file, TEST_LOG_VERBOSE,
  1.1044 +            ("main(0x%p): server init complete (port #%d)\n",
  1.1045 +            PR_GetCurrentThread(), server->port));
  1.1046 +    }
  1.1047 +
  1.1048 +    if (clients != 0)
  1.1049 +    {
  1.1050 +        /* Create all of the clients */
  1.1051 +        PRHostEnt host;
  1.1052 +        char buffer[BUFFER_SIZE];
  1.1053 +        client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t));
  1.1054 +
  1.1055 +        TEST_LOG(
  1.1056 +            cltsrv_log_file, TEST_LOG_VERBOSE,
  1.1057 +            ("main(0x%p): creating %d client threads\n",
  1.1058 +            PR_GetCurrentThread(), clients));
  1.1059 +        
  1.1060 +        if (!serverIsLocal)
  1.1061 +        {
  1.1062 +            rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host);
  1.1063 +            if (PR_SUCCESS != rv)
  1.1064 +            {
  1.1065 +                PL_FPrintError(PR_STDERR, "PR_GetHostByName");
  1.1066 +                return 2;
  1.1067 +            }
  1.1068 +        }
  1.1069 +
  1.1070 +        for (index = 0; index < clients; ++index)
  1.1071 +        {
  1.1072 +            client[index].state = cs_init;
  1.1073 +            client[index].ml = PR_NewLock();
  1.1074 +            if (serverIsLocal)
  1.1075 +            {
  1.1076 +				if (PR_AF_INET6 != domain)
  1.1077 +                	(void)PR_InitializeNetAddr(
  1.1078 +                    	PR_IpAddrLoopback, DEFAULT_PORT,
  1.1079 +                    	&client[index].serverAddress);
  1.1080 +				else
  1.1081 +					rv = PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6,
  1.1082 +							DEFAULT_PORT, &client[index].serverAddress);
  1.1083 +            }
  1.1084 +            else
  1.1085 +            {
  1.1086 +                (void)PR_EnumerateHostEnt(
  1.1087 +                    0, &host, DEFAULT_PORT, &client[index].serverAddress);
  1.1088 +            }
  1.1089 +            client[index].stateChange = PR_NewCondVar(client[index].ml);
  1.1090 +            TEST_LOG(
  1.1091 +                cltsrv_log_file, TEST_LOG_INFO,
  1.1092 +                ("main(0x%p): creating client threads\n", PR_GetCurrentThread()));
  1.1093 +            client[index].thread = PR_CreateThread(
  1.1094 +                PR_USER_THREAD, Client, &client[index], PR_PRIORITY_NORMAL,
  1.1095 +                thread_scope, PR_JOINABLE_THREAD, 0);
  1.1096 +            TEST_ASSERT(NULL != client[index].thread);
  1.1097 +            PR_Lock(client[index].ml);
  1.1098 +            while (cs_init == client[index].state)
  1.1099 +                PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
  1.1100 +            PR_Unlock(client[index].ml);
  1.1101 +        }
  1.1102 +    }
  1.1103 +
  1.1104 +    /* Then just let them go at it for a bit */
  1.1105 +    TEST_LOG(
  1.1106 +        cltsrv_log_file, TEST_LOG_ALWAYS,
  1.1107 +        ("main(0x%p): waiting for execution interval (%d seconds)\n",
  1.1108 +        PR_GetCurrentThread(), execution));
  1.1109 +
  1.1110 +    WaitForCompletion(execution);
  1.1111 +
  1.1112 +    TimeOfDayMessage("Shutting down", PR_GetCurrentThread());
  1.1113 +
  1.1114 +    if (clients != 0)
  1.1115 +    {
  1.1116 +        for (index = 0; index < clients; ++index)
  1.1117 +        {
  1.1118 +            TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, 
  1.1119 +                ("main(0x%p): notifying client(0x%p) to stop\n",
  1.1120 +                PR_GetCurrentThread(), client[index].thread));
  1.1121 +
  1.1122 +            PR_Lock(client[index].ml);
  1.1123 +            if (cs_run == client[index].state)
  1.1124 +            {
  1.1125 +                client[index].state = cs_stop;
  1.1126 +                PR_Interrupt(client[index].thread);
  1.1127 +                while (cs_stop == client[index].state)
  1.1128 +                    PR_WaitCondVar(
  1.1129 +                        client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
  1.1130 +            }
  1.1131 +            PR_Unlock(client[index].ml);
  1.1132 +
  1.1133 +            TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE, 
  1.1134 +                ("main(0x%p): joining client(0x%p)\n",
  1.1135 +                PR_GetCurrentThread(), client[index].thread));
  1.1136 +
  1.1137 +		    joinStatus = PR_JoinThread(client[index].thread);
  1.1138 +		    TEST_ASSERT(PR_SUCCESS == joinStatus);
  1.1139 +            PR_DestroyCondVar(client[index].stateChange);
  1.1140 +            PR_DestroyLock(client[index].ml);
  1.1141 +        }
  1.1142 +        PR_DELETE(client);
  1.1143 +    }
  1.1144 +
  1.1145 +    if (NULL != server)
  1.1146 +    {
  1.1147 +        /* All clients joined - retrieve the server */
  1.1148 +        TEST_LOG(
  1.1149 +            cltsrv_log_file, TEST_LOG_NOTICE, 
  1.1150 +            ("main(0x%p): notifying server(0x%p) to stop\n",
  1.1151 +            PR_GetCurrentThread(), server->thread));
  1.1152 +
  1.1153 +        PR_Lock(server->ml);
  1.1154 +        server->state = cs_stop;
  1.1155 +        PR_Interrupt(server->thread);
  1.1156 +        while (cs_exit != server->state)
  1.1157 +            PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  1.1158 +        PR_Unlock(server->ml);
  1.1159 +
  1.1160 +        TEST_LOG(
  1.1161 +            cltsrv_log_file, TEST_LOG_NOTICE, 
  1.1162 +            ("main(0x%p): joining server(0x%p)\n",
  1.1163 +            PR_GetCurrentThread(), server->thread));
  1.1164 +        joinStatus = PR_JoinThread(server->thread);
  1.1165 +        TEST_ASSERT(PR_SUCCESS == joinStatus);
  1.1166 +
  1.1167 +        PR_DestroyCondVar(server->stateChange);
  1.1168 +        PR_DestroyCondVar(server->pool.exiting);
  1.1169 +        PR_DestroyCondVar(server->pool.acceptComplete);
  1.1170 +        PR_DestroyLock(server->ml);
  1.1171 +        PR_DELETE(server);
  1.1172 +    }
  1.1173 +
  1.1174 +    TEST_LOG(
  1.1175 +        cltsrv_log_file, TEST_LOG_ALWAYS, 
  1.1176 +        ("main(0x%p): test complete\n", PR_GetCurrentThread()));
  1.1177 +
  1.1178 +    PT_FPrintStats(debug_out, "\nPThread Statistics\n");
  1.1179 +
  1.1180 +    TimeOfDayMessage("Test exiting at", PR_GetCurrentThread());
  1.1181 +    PR_Cleanup();
  1.1182 +    return 0;
  1.1183 +}  /* main */
  1.1184 +
  1.1185 +/* cltsrv.c */

mercurial