nsprpub/pr/tests/nblayer.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/tests/nblayer.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,675 @@
     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 +#include "prio.h"
    1.10 +#include "prmem.h"
    1.11 +#include "prprf.h"
    1.12 +#include "prlog.h"
    1.13 +#include "prerror.h"
    1.14 +#include "prnetdb.h"
    1.15 +#include "prthread.h"
    1.16 +
    1.17 +#include "plerror.h"
    1.18 +#include "plgetopt.h"
    1.19 +#include "prwin16.h"
    1.20 +
    1.21 +#include <stdlib.h>
    1.22 +#include <string.h>
    1.23 +
    1.24 +/*
    1.25 +** Testing layering of I/O
    1.26 +**
    1.27 +**      The layered server
    1.28 +** A thread that acts as a server. It creates a TCP listener with a dummy
    1.29 +** layer pushed on top. Then listens for incoming connections. Each connection
    1.30 +** request for connection will be layered as well, accept one request, echo
    1.31 +** it back and close.
    1.32 +**
    1.33 +**      The layered client
    1.34 +** Pretty much what you'd expect.
    1.35 +*/
    1.36 +
    1.37 +static PRFileDesc *logFile;
    1.38 +static PRDescIdentity identity;
    1.39 +static PRNetAddr server_address;
    1.40 +
    1.41 +static PRIOMethods myMethods;
    1.42 +
    1.43 +typedef enum {rcv_get_debit, rcv_send_credit, rcv_data} RcvState;
    1.44 +typedef enum {xmt_send_debit, xmt_recv_credit, xmt_data} XmtState;
    1.45 +
    1.46 +struct PRFilePrivate
    1.47 +{
    1.48 +    RcvState rcvstate;
    1.49 +    XmtState xmtstate;
    1.50 +    PRInt32 rcvreq, rcvinprogress;
    1.51 +    PRInt32 xmtreq, xmtinprogress;
    1.52 +};
    1.53 +
    1.54 +typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity;
    1.55 +
    1.56 +static PRIntn minor_iterations = 5;
    1.57 +static PRIntn major_iterations = 1;
    1.58 +static Verbosity verbosity = quiet;
    1.59 +static PRUint16 default_port = 12273;
    1.60 +
    1.61 +static PRFileDesc *PushLayer(PRFileDesc *stack)
    1.62 +{
    1.63 +    PRStatus rv;
    1.64 +    PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods);
    1.65 +    layer->secret = PR_NEWZAP(PRFilePrivate);
    1.66 +    rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
    1.67 +    PR_ASSERT(PR_SUCCESS == rv);
    1.68 +    if (verbosity > quiet)
    1.69 +        PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
    1.70 +    return stack;
    1.71 +}  /* PushLayer */
    1.72 +
    1.73 +static PRFileDesc *PopLayer(PRFileDesc *stack)
    1.74 +{
    1.75 +    PRFileDesc *popped = PR_PopIOLayer(stack, identity);
    1.76 +    if (verbosity > quiet)
    1.77 +        PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack);
    1.78 +    PR_DELETE(popped->secret);
    1.79 +    popped->dtor(popped);
    1.80 +    return stack;
    1.81 +}  /* PopLayer */
    1.82 +
    1.83 +static void PR_CALLBACK Client(void *arg)
    1.84 +{
    1.85 +    PRStatus rv;
    1.86 +    PRIntn mits;
    1.87 +    PRInt32 ready;
    1.88 +    PRUint8 buffer[100];
    1.89 +    PRPollDesc polldesc;
    1.90 +    PRIntn empty_flags = 0;
    1.91 +    PRIntn bytes_read, bytes_sent;
    1.92 +    PRFileDesc *stack = (PRFileDesc*)arg;
    1.93 +
    1.94 +    /* Initialize the buffer so that Purify won't complain */
    1.95 +    memset(buffer, 0, sizeof(buffer));
    1.96 +
    1.97 +    rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
    1.98 +    if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR == PR_GetError()))
    1.99 +    {
   1.100 +        if (verbosity > quiet)
   1.101 +            PR_fprintf(logFile, "Client connect 'in progress'\n");
   1.102 +        do
   1.103 +        {
   1.104 +            polldesc.fd = stack;
   1.105 +            polldesc.out_flags = 0;
   1.106 +            polldesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
   1.107 +            ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
   1.108 +            if ((1 != ready)  /* if not 1, then we're dead */
   1.109 +            || (0 == (polldesc.in_flags & polldesc.out_flags)))
   1.110 +                { PR_ASSERT(!"Whoa!"); break; }
   1.111 +            if (verbosity > quiet)
   1.112 +                PR_fprintf(
   1.113 +                    logFile, "Client connect 'in progress' [0x%x]\n",
   1.114 +                    polldesc.out_flags);
   1.115 +            rv = PR_GetConnectStatus(&polldesc);
   1.116 +            if ((PR_FAILURE == rv)
   1.117 +            && (PR_IN_PROGRESS_ERROR != PR_GetError())) break;
   1.118 +        } while (PR_FAILURE == rv);
   1.119 +    }
   1.120 +    PR_ASSERT(PR_SUCCESS == rv);
   1.121 +    if (verbosity > chatty)
   1.122 +        PR_fprintf(logFile, "Client created connection\n");
   1.123 +
   1.124 +    for (mits = 0; mits < minor_iterations; ++mits)
   1.125 +    {
   1.126 +        bytes_sent = 0;
   1.127 +        if (verbosity > quiet)
   1.128 +            PR_fprintf(logFile, "Client sending %d bytes\n", sizeof(buffer));
   1.129 +        do
   1.130 +        {
   1.131 +            if (verbosity > chatty)
   1.132 +                PR_fprintf(
   1.133 +                    logFile, "Client sending %d bytes\n",
   1.134 +                    sizeof(buffer) - bytes_sent);
   1.135 +            ready = PR_Send(
   1.136 +                stack, buffer + bytes_sent, sizeof(buffer) - bytes_sent,
   1.137 +                empty_flags, PR_INTERVAL_NO_TIMEOUT);
   1.138 +            if (verbosity > chatty)
   1.139 +                PR_fprintf(logFile, "Client send status [%d]\n", ready);
   1.140 +            if (0 < ready) bytes_sent += ready;
   1.141 +            else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
   1.142 +            {
   1.143 +                polldesc.fd = stack;
   1.144 +                polldesc.out_flags = 0;
   1.145 +                polldesc.in_flags = PR_POLL_WRITE;
   1.146 +                ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
   1.147 +                if ((1 != ready)  /* if not 1, then we're dead */
   1.148 +                || (0 == (polldesc.in_flags & polldesc.out_flags)))
   1.149 +                    { PR_ASSERT(!"Whoa!"); break; }
   1.150 +            }
   1.151 +            else break;
   1.152 +        } while (bytes_sent < sizeof(buffer));
   1.153 +        PR_ASSERT(sizeof(buffer) == bytes_sent);
   1.154 +
   1.155 +        bytes_read = 0;
   1.156 +        do
   1.157 +        {
   1.158 +            if (verbosity > chatty)
   1.159 +                PR_fprintf(
   1.160 +                    logFile, "Client receiving %d bytes\n",
   1.161 +                    bytes_sent - bytes_read);
   1.162 +            ready = PR_Recv(
   1.163 +                stack, buffer + bytes_read, bytes_sent - bytes_read,
   1.164 +                empty_flags, PR_INTERVAL_NO_TIMEOUT);
   1.165 +            if (verbosity > chatty)
   1.166 +                PR_fprintf(
   1.167 +                    logFile, "Client receive status [%d]\n", ready);
   1.168 +            if (0 < ready) bytes_read += ready;
   1.169 +            else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
   1.170 +            {
   1.171 +                polldesc.fd = stack;
   1.172 +                polldesc.out_flags = 0;
   1.173 +                polldesc.in_flags = PR_POLL_READ;
   1.174 +                ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
   1.175 +                if ((1 != ready)  /* if not 1, then we're dead */
   1.176 +                || (0 == (polldesc.in_flags & polldesc.out_flags)))
   1.177 +                    { PR_ASSERT(!"Whoa!"); break; }
   1.178 +            }
   1.179 +            else break;
   1.180 +        } while (bytes_read < bytes_sent);
   1.181 +        if (verbosity > chatty)
   1.182 +            PR_fprintf(logFile, "Client received %d bytes\n", bytes_read);
   1.183 +        PR_ASSERT(bytes_read == bytes_sent);
   1.184 +    }
   1.185 +
   1.186 +    if (verbosity > quiet)
   1.187 +        PR_fprintf(logFile, "Client shutting down stack\n");
   1.188 +    
   1.189 +    rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
   1.190 +}  /* Client */
   1.191 +
   1.192 +static void PR_CALLBACK Server(void *arg)
   1.193 +{
   1.194 +    PRStatus rv;
   1.195 +    PRInt32 ready;
   1.196 +    PRUint8 buffer[100];
   1.197 +    PRFileDesc *service;
   1.198 +    PRUintn empty_flags = 0;
   1.199 +    struct PRPollDesc polldesc;
   1.200 +    PRIntn bytes_read, bytes_sent;
   1.201 +    PRFileDesc *stack = (PRFileDesc*)arg;
   1.202 +    PRNetAddr client_address;
   1.203 +
   1.204 +    do
   1.205 +    {
   1.206 +        if (verbosity > chatty)
   1.207 +            PR_fprintf(logFile, "Server accepting connection\n");
   1.208 +        service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT);
   1.209 +        if (verbosity > chatty)
   1.210 +            PR_fprintf(logFile, "Server accept status [0x%p]\n", service);
   1.211 +        if ((NULL == service) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
   1.212 +        {
   1.213 +            polldesc.fd = stack;
   1.214 +            polldesc.out_flags = 0;
   1.215 +            polldesc.in_flags = PR_POLL_READ | PR_POLL_EXCEPT;
   1.216 +            ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
   1.217 +            if ((1 != ready)  /* if not 1, then we're dead */
   1.218 +            || (0 == (polldesc.in_flags & polldesc.out_flags)))
   1.219 +                { PR_ASSERT(!"Whoa!"); break; }
   1.220 +        }
   1.221 +    } while (NULL == service);
   1.222 +    PR_ASSERT(NULL != service);
   1.223 +        
   1.224 +    if (verbosity > quiet)
   1.225 +        PR_fprintf(logFile, "Server accepting connection\n");
   1.226 +
   1.227 +    do
   1.228 +    {
   1.229 +        bytes_read = 0;
   1.230 +        do
   1.231 +        {
   1.232 +            if (verbosity > chatty)
   1.233 +                PR_fprintf(
   1.234 +                    logFile, "Server receiving %d bytes\n",
   1.235 +                    sizeof(buffer) - bytes_read);
   1.236 +            ready = PR_Recv(
   1.237 +                service, buffer + bytes_read, sizeof(buffer) - bytes_read,
   1.238 +                empty_flags, PR_INTERVAL_NO_TIMEOUT);
   1.239 +            if (verbosity > chatty)
   1.240 +                PR_fprintf(logFile, "Server receive status [%d]\n", ready);
   1.241 +            if (0 < ready) bytes_read += ready;
   1.242 +            else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
   1.243 +            {
   1.244 +                polldesc.fd = service;
   1.245 +                polldesc.out_flags = 0;
   1.246 +                polldesc.in_flags = PR_POLL_READ;
   1.247 +                ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
   1.248 +                if ((1 != ready)  /* if not 1, then we're dead */
   1.249 +                || (0 == (polldesc.in_flags & polldesc.out_flags)))
   1.250 +                    { PR_ASSERT(!"Whoa!"); break; }
   1.251 +            }
   1.252 +            else break;
   1.253 +        } while (bytes_read < sizeof(buffer));
   1.254 +
   1.255 +        if (0 != bytes_read)
   1.256 +        {
   1.257 +            if (verbosity > chatty)
   1.258 +                PR_fprintf(logFile, "Server received %d bytes\n", bytes_read);
   1.259 +            PR_ASSERT(bytes_read > 0);
   1.260 +
   1.261 +            bytes_sent = 0;
   1.262 +            do
   1.263 +            {
   1.264 +                ready = PR_Send(
   1.265 +                    service, buffer + bytes_sent, bytes_read - bytes_sent,
   1.266 +                    empty_flags, PR_INTERVAL_NO_TIMEOUT);
   1.267 +                if (0 < ready)
   1.268 +                {
   1.269 +                    bytes_sent += ready;
   1.270 +                }
   1.271 +                else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
   1.272 +                {
   1.273 +                    polldesc.fd = service;
   1.274 +                    polldesc.out_flags = 0;
   1.275 +                    polldesc.in_flags = PR_POLL_WRITE;
   1.276 +                    ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
   1.277 +                    if ((1 != ready)  /* if not 1, then we're dead */
   1.278 +                    || (0 == (polldesc.in_flags & polldesc.out_flags)))
   1.279 +                        { PR_ASSERT(!"Whoa!"); break; }
   1.280 +                }
   1.281 +                else break;
   1.282 +            } while (bytes_sent < bytes_read);
   1.283 +            PR_ASSERT(bytes_read == bytes_sent);
   1.284 +            if (verbosity > chatty)
   1.285 +                PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent);
   1.286 +        }
   1.287 +    } while (0 != bytes_read);
   1.288 +
   1.289 +    if (verbosity > quiet)
   1.290 +        PR_fprintf(logFile, "Server shutting down stack\n");
   1.291 +    rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
   1.292 +    rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
   1.293 +
   1.294 +}  /* Server */
   1.295 +
   1.296 +static PRStatus PR_CALLBACK MyClose(PRFileDesc *fd)
   1.297 +{
   1.298 +    PR_DELETE(fd->secret);  /* manage my secret file object */
   1.299 +    return (PR_GetDefaultIOMethods())->close(fd);  /* let him do all the work */
   1.300 +}  /* MyClose */
   1.301 +
   1.302 +static PRInt16 PR_CALLBACK MyPoll(
   1.303 +    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
   1.304 +{
   1.305 +    PRInt16 my_flags, new_flags;
   1.306 +    PRFilePrivate *mine = (PRFilePrivate*)fd->secret;
   1.307 +    if (0 != (PR_POLL_READ & in_flags))
   1.308 +    {
   1.309 +        /* client thinks he's reading */
   1.310 +        switch (mine->rcvstate)
   1.311 +        {
   1.312 +            case rcv_send_credit:
   1.313 +                my_flags = (in_flags & ~PR_POLL_READ) | PR_POLL_WRITE;
   1.314 +                break;
   1.315 +            case rcv_data:
   1.316 +            case rcv_get_debit:
   1.317 +                my_flags = in_flags;
   1.318 +            default: break;
   1.319 +        }
   1.320 +    }
   1.321 +    else if (0 != (PR_POLL_WRITE & in_flags))
   1.322 +    {
   1.323 +        /* client thinks he's writing */
   1.324 +        switch (mine->xmtstate)
   1.325 +        {
   1.326 +            case xmt_recv_credit:
   1.327 +                my_flags = (in_flags & ~PR_POLL_WRITE) | PR_POLL_READ;
   1.328 +                break;
   1.329 +            case xmt_send_debit:
   1.330 +            case xmt_data:
   1.331 +                my_flags = in_flags;
   1.332 +            default: break;
   1.333 +        }
   1.334 +    }
   1.335 +    else PR_ASSERT(!"How'd I get here?");
   1.336 +    new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags);
   1.337 +    if (verbosity > chatty)
   1.338 +        PR_fprintf(
   1.339 +            logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n",
   1.340 +            in_flags, my_flags, *out_flags, new_flags);
   1.341 +    return new_flags;
   1.342 +}  /* MyPoll */
   1.343 +
   1.344 +static PRFileDesc * PR_CALLBACK MyAccept(
   1.345 +    PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
   1.346 +{
   1.347 +    PRStatus rv;
   1.348 +    PRFileDesc *newfd, *layer = fd;
   1.349 +    PRFileDesc *newstack;
   1.350 +    PRFilePrivate *newsecret;
   1.351 +
   1.352 +    PR_ASSERT(fd != NULL);
   1.353 +    PR_ASSERT(fd->lower != NULL);
   1.354 +
   1.355 +    newstack = PR_NEW(PRFileDesc);
   1.356 +    if (NULL == newstack)
   1.357 +    {
   1.358 +        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.359 +        return NULL;
   1.360 +    }
   1.361 +    newsecret = PR_NEW(PRFilePrivate);
   1.362 +    if (NULL == newsecret)
   1.363 +    {
   1.364 +        PR_DELETE(newstack);
   1.365 +        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.366 +        return NULL;
   1.367 +    }
   1.368 +    *newstack = *fd;  /* make a copy of the accepting layer */
   1.369 +    *newsecret = *fd->secret;
   1.370 +    newstack->secret = newsecret;
   1.371 +
   1.372 +    newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
   1.373 +    if (NULL == newfd)
   1.374 +    {
   1.375 +        PR_DELETE(newsecret);
   1.376 +        PR_DELETE(newstack);
   1.377 +        return NULL;
   1.378 +    }
   1.379 +
   1.380 +    /* this PR_PushIOLayer call cannot fail */
   1.381 +    rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
   1.382 +    PR_ASSERT(PR_SUCCESS == rv);
   1.383 +    return newfd;  /* that's it */
   1.384 +}
   1.385 +
   1.386 +static PRInt32 PR_CALLBACK MyRecv(
   1.387 +    PRFileDesc *fd, void *buf, PRInt32 amount,
   1.388 +    PRIntn flags, PRIntervalTime timeout)
   1.389 +{
   1.390 +    char *b;
   1.391 +    PRInt32 rv;
   1.392 +    PRFileDesc *lo = fd->lower;
   1.393 +    PRFilePrivate *mine = (PRFilePrivate*)fd->secret;
   1.394 +
   1.395 +    do
   1.396 +    {
   1.397 +        switch (mine->rcvstate)
   1.398 +        {
   1.399 +        case rcv_get_debit:
   1.400 +            b = (char*)&mine->rcvreq;
   1.401 +            mine->rcvreq = amount;
   1.402 +            rv = lo->methods->recv(
   1.403 +                lo, b + mine->rcvinprogress,
   1.404 +                sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout);
   1.405 +            if (0 == rv) goto closed;
   1.406 +            if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
   1.407 +            mine->rcvinprogress += rv;  /* accumulate the read */
   1.408 +            if (mine->rcvinprogress < sizeof(mine->rcvreq)) break;  /* loop */
   1.409 +            mine->rcvstate = rcv_send_credit;
   1.410 +            mine->rcvinprogress = 0;
   1.411 +        case rcv_send_credit:
   1.412 +            b = (char*)&mine->rcvreq;
   1.413 +            rv = lo->methods->send(
   1.414 +                lo, b + mine->rcvinprogress,
   1.415 +                sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout);
   1.416 +            if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
   1.417 +            mine->rcvinprogress += rv;  /* accumulate the read */
   1.418 +            if (mine->rcvinprogress < sizeof(mine->rcvreq)) break;  /* loop */
   1.419 +            mine->rcvstate = rcv_data;
   1.420 +            mine->rcvinprogress = 0;
   1.421 +        case rcv_data:
   1.422 +            b = (char*)buf;
   1.423 +            rv = lo->methods->recv(
   1.424 +                lo, b + mine->rcvinprogress,
   1.425 +                mine->rcvreq - mine->rcvinprogress, flags, timeout);
   1.426 +            if (0 == rv) goto closed;
   1.427 +            if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
   1.428 +            mine->rcvinprogress += rv;  /* accumulate the read */
   1.429 +            if (mine->rcvinprogress < amount) break;  /* loop */
   1.430 +            mine->rcvstate = rcv_get_debit;
   1.431 +            mine->rcvinprogress = 0;
   1.432 +            return mine->rcvreq;  /* << -- that's it! */
   1.433 +        default:
   1.434 +            break;
   1.435 +        }
   1.436 +    } while (-1 != rv);
   1.437 +    return rv;
   1.438 +closed:
   1.439 +    mine->rcvinprogress = 0;
   1.440 +    mine->rcvstate = rcv_get_debit;
   1.441 +    return 0;
   1.442 +}  /* MyRecv */
   1.443 +
   1.444 +static PRInt32 PR_CALLBACK MySend(
   1.445 +    PRFileDesc *fd, const void *buf, PRInt32 amount,
   1.446 +    PRIntn flags, PRIntervalTime timeout)
   1.447 +{
   1.448 +    char *b;
   1.449 +    PRInt32 rv;
   1.450 +    PRFileDesc *lo = fd->lower;
   1.451 +    PRFilePrivate *mine = (PRFilePrivate*)fd->secret;
   1.452 +
   1.453 +    do
   1.454 +    {
   1.455 +        switch (mine->xmtstate)
   1.456 +        {
   1.457 +        case xmt_send_debit:
   1.458 +            b = (char*)&mine->xmtreq;
   1.459 +            mine->xmtreq = amount;
   1.460 +            rv = lo->methods->send(
   1.461 +                lo, b - mine->xmtinprogress,
   1.462 +                sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout);
   1.463 +            if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
   1.464 +            mine->xmtinprogress += rv;
   1.465 +            if (mine->xmtinprogress < sizeof(mine->xmtreq)) break;
   1.466 +            mine->xmtstate = xmt_recv_credit;
   1.467 +            mine->xmtinprogress = 0;
   1.468 +        case xmt_recv_credit:
   1.469 +             b = (char*)&mine->xmtreq;
   1.470 +             rv = lo->methods->recv(
   1.471 +                lo, b + mine->xmtinprogress,
   1.472 +                sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout);
   1.473 +            if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
   1.474 +            mine->xmtinprogress += rv;
   1.475 +            if (mine->xmtinprogress < sizeof(mine->xmtreq)) break;
   1.476 +            mine->xmtstate = xmt_data;
   1.477 +            mine->xmtinprogress = 0;
   1.478 +        case xmt_data:
   1.479 +            b = (char*)buf;
   1.480 +            rv = lo->methods->send(
   1.481 +                lo, b + mine->xmtinprogress,
   1.482 +                mine->xmtreq - mine->xmtinprogress, flags, timeout);
   1.483 +            if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
   1.484 +            mine->xmtinprogress += rv;
   1.485 +            if (mine->xmtinprogress < amount) break;
   1.486 +            mine->xmtstate = xmt_send_debit;
   1.487 +            mine->xmtinprogress = 0;
   1.488 +            return mine->xmtreq;  /* <<-- That's the one! */
   1.489 +        default:
   1.490 +            break;
   1.491 +        }
   1.492 +    } while (-1 != rv);
   1.493 +    return rv;
   1.494 +}  /* MySend */
   1.495 +
   1.496 +static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta)
   1.497 +{
   1.498 +    PRIntn verbage = (PRIntn)verbosity + delta;
   1.499 +    if (verbage < (PRIntn)silent) verbage = (PRIntn)silent;
   1.500 +    else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy;
   1.501 +    return (Verbosity)verbage;
   1.502 +}  /* ChangeVerbosity */
   1.503 +
   1.504 +int main(int argc, char **argv)
   1.505 +{
   1.506 +    PRStatus rv;
   1.507 +    PLOptStatus os;
   1.508 +    PRFileDesc *client, *service;
   1.509 +    PRNetAddr any_address;
   1.510 +    const char *server_name = NULL;
   1.511 +    const PRIOMethods *stubMethods;
   1.512 +    PRThread *client_thread, *server_thread;
   1.513 +    PRThreadScope thread_scope = PR_LOCAL_THREAD;
   1.514 +    PRSocketOptionData socket_noblock, socket_nodelay;
   1.515 +    PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:");
   1.516 +    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
   1.517 +    {
   1.518 +        if (PL_OPT_BAD == os) continue;
   1.519 +        switch (opt->option)
   1.520 +        {
   1.521 +        case 0:
   1.522 +            server_name = opt->value;
   1.523 +            break;
   1.524 +        case 'd':  /* debug mode */
   1.525 +            if (verbosity < noisy)
   1.526 +                verbosity = ChangeVerbosity(verbosity, 1);
   1.527 +            break;
   1.528 +        case 'q':  /* debug mode */
   1.529 +            if (verbosity > silent)
   1.530 +                verbosity = ChangeVerbosity(verbosity, -1);
   1.531 +            break;
   1.532 +        case 'G':  /* use global threads */
   1.533 +            thread_scope = PR_GLOBAL_THREAD;
   1.534 +            break;
   1.535 +        case 'C':  /* number of threads waiting */
   1.536 +            major_iterations = atoi(opt->value);
   1.537 +            break;
   1.538 +        case 'c':  /* number of client threads */
   1.539 +            minor_iterations = atoi(opt->value);
   1.540 +            break;
   1.541 +        case 'p':  /* default port */
   1.542 +            default_port = atoi(opt->value);
   1.543 +            break;
   1.544 +        default:
   1.545 +            break;
   1.546 +        }
   1.547 +    }
   1.548 +    PL_DestroyOptState(opt);
   1.549 +    PR_STDIO_INIT();
   1.550 +
   1.551 +    logFile = PR_GetSpecialFD(PR_StandardError);
   1.552 +    identity = PR_GetUniqueIdentity("Dummy");
   1.553 +    stubMethods = PR_GetDefaultIOMethods();
   1.554 +
   1.555 +    /*
   1.556 +    ** The protocol we're going to implement is one where in order to initiate
   1.557 +    ** a send, the sender must first solicit permission. Therefore, every
   1.558 +    ** send is really a send - receive - send sequence.
   1.559 +    */
   1.560 +    myMethods = *stubMethods;  /* first get the entire batch */
   1.561 +    myMethods.accept = MyAccept;  /* then override the ones we care about */
   1.562 +    myMethods.recv = MyRecv;  /* then override the ones we care about */
   1.563 +    myMethods.send = MySend;  /* then override the ones we care about */
   1.564 +    myMethods.close = MyClose;  /* then override the ones we care about */
   1.565 +    myMethods.poll = MyPoll;  /* then override the ones we care about */
   1.566 +
   1.567 +    if (NULL == server_name)
   1.568 +        rv = PR_InitializeNetAddr(
   1.569 +            PR_IpAddrLoopback, default_port, &server_address);
   1.570 +    else
   1.571 +    {
   1.572 +        rv = PR_StringToNetAddr(server_name, &server_address);
   1.573 +        PR_ASSERT(PR_SUCCESS == rv);
   1.574 +        rv = PR_InitializeNetAddr(
   1.575 +            PR_IpAddrNull, default_port, &server_address);
   1.576 +    }
   1.577 +    PR_ASSERT(PR_SUCCESS == rv);
   1.578 +
   1.579 +    socket_noblock.value.non_blocking = PR_TRUE;
   1.580 +    socket_noblock.option = PR_SockOpt_Nonblocking;
   1.581 +    socket_nodelay.value.no_delay = PR_TRUE;
   1.582 +    socket_nodelay.option = PR_SockOpt_NoDelay;
   1.583 +
   1.584 +    /* one type w/o layering */
   1.585 +
   1.586 +    while (major_iterations-- > 0)
   1.587 +    {
   1.588 +        if (verbosity > silent)
   1.589 +            PR_fprintf(logFile, "Beginning non-layered test\n");
   1.590 +
   1.591 +        client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
   1.592 +        service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
   1.593 +
   1.594 +        rv = PR_SetSocketOption(client, &socket_noblock);
   1.595 +        PR_ASSERT(PR_SUCCESS == rv);
   1.596 +        rv = PR_SetSocketOption(service, &socket_noblock);
   1.597 +        PR_ASSERT(PR_SUCCESS == rv);
   1.598 +        rv = PR_SetSocketOption(client, &socket_nodelay);
   1.599 +        PR_ASSERT(PR_SUCCESS == rv);
   1.600 +        rv = PR_SetSocketOption(service, &socket_nodelay);
   1.601 +        PR_ASSERT(PR_SUCCESS == rv);
   1.602 +
   1.603 +        rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
   1.604 +        PR_ASSERT(PR_SUCCESS == rv);
   1.605 +        rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
   1.606 +        rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
   1.607 +
   1.608 +        server_thread = PR_CreateThread(
   1.609 +            PR_USER_THREAD, Server, service,
   1.610 +            PR_PRIORITY_HIGH, thread_scope,
   1.611 +            PR_JOINABLE_THREAD, 16 * 1024);
   1.612 +        PR_ASSERT(NULL != server_thread);
   1.613 +
   1.614 +        client_thread = PR_CreateThread(
   1.615 +            PR_USER_THREAD, Client, client,
   1.616 +            PR_PRIORITY_NORMAL, thread_scope,
   1.617 +            PR_JOINABLE_THREAD, 16 * 1024);
   1.618 +        PR_ASSERT(NULL != client_thread);
   1.619 +
   1.620 +        rv = PR_JoinThread(client_thread);
   1.621 +        PR_ASSERT(PR_SUCCESS == rv);
   1.622 +        rv = PR_JoinThread(server_thread);
   1.623 +        PR_ASSERT(PR_SUCCESS == rv);
   1.624 +
   1.625 +        rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
   1.626 +        rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
   1.627 +        if (verbosity > silent)
   1.628 +            PR_fprintf(logFile, "Ending non-layered test\n");
   1.629 +
   1.630 +        /* with layering */
   1.631 +        if (verbosity > silent)
   1.632 +            PR_fprintf(logFile, "Beginning layered test\n");
   1.633 +        client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
   1.634 +        service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
   1.635 +
   1.636 +        rv = PR_SetSocketOption(client, &socket_noblock);
   1.637 +        PR_ASSERT(PR_SUCCESS == rv);
   1.638 +        rv = PR_SetSocketOption(service, &socket_noblock);
   1.639 +        PR_ASSERT(PR_SUCCESS == rv);
   1.640 +        rv = PR_SetSocketOption(client, &socket_nodelay);
   1.641 +        PR_ASSERT(PR_SUCCESS == rv);
   1.642 +        rv = PR_SetSocketOption(service, &socket_nodelay);
   1.643 +        PR_ASSERT(PR_SUCCESS == rv);
   1.644 +
   1.645 +        PushLayer(client);
   1.646 +        PushLayer(service);
   1.647 +
   1.648 +        rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
   1.649 +        PR_ASSERT(PR_SUCCESS == rv);
   1.650 +        rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
   1.651 +        rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
   1.652 +
   1.653 +        server_thread = PR_CreateThread(
   1.654 +            PR_USER_THREAD, Server, service,
   1.655 +            PR_PRIORITY_HIGH, thread_scope,
   1.656 +            PR_JOINABLE_THREAD, 16 * 1024);
   1.657 +        PR_ASSERT(NULL != server_thread);
   1.658 +
   1.659 +        client_thread = PR_CreateThread(
   1.660 +            PR_USER_THREAD, Client, client,
   1.661 +            PR_PRIORITY_NORMAL, thread_scope,
   1.662 +            PR_JOINABLE_THREAD, 16 * 1024);
   1.663 +        PR_ASSERT(NULL != client_thread);
   1.664 +
   1.665 +        rv = PR_JoinThread(client_thread);
   1.666 +        PR_ASSERT(PR_SUCCESS == rv);
   1.667 +        rv = PR_JoinThread(server_thread);
   1.668 +        PR_ASSERT(PR_SUCCESS == rv);
   1.669 +
   1.670 +        rv = PR_Close(PopLayer(client)); PR_ASSERT(PR_SUCCESS == rv);
   1.671 +        rv = PR_Close(PopLayer(service)); PR_ASSERT(PR_SUCCESS == rv);
   1.672 +        if (verbosity > silent)
   1.673 +            PR_fprintf(logFile, "Ending layered test\n");
   1.674 +    }
   1.675 +    return 0;
   1.676 +}  /* main */
   1.677 +
   1.678 +/* nblayer.c */

mercurial