Back to index

lightning-sunbird  0.9+nobinonly
nblayer.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "prio.h"
00039 #include "prmem.h"
00040 #include "prprf.h"
00041 #include "prlog.h"
00042 #include "prerror.h"
00043 #include "prnetdb.h"
00044 #include "prthread.h"
00045 
00046 #include "plerror.h"
00047 #include "plgetopt.h"
00048 #include "prwin16.h"
00049 
00050 #include <stdlib.h>
00051 #include <string.h>
00052 
00053 /*
00054 ** Testing layering of I/O
00055 **
00056 **      The layered server
00057 ** A thread that acts as a server. It creates a TCP listener with a dummy
00058 ** layer pushed on top. Then listens for incoming connections. Each connection
00059 ** request for connection will be layered as well, accept one request, echo
00060 ** it back and close.
00061 **
00062 **      The layered client
00063 ** Pretty much what you'd expect.
00064 */
00065 
00066 static PRFileDesc *logFile;
00067 static PRDescIdentity identity;
00068 static PRNetAddr server_address;
00069 
00070 static PRIOMethods myMethods;
00071 
00072 typedef enum {rcv_get_debit, rcv_send_credit, rcv_data} RcvState;
00073 typedef enum {xmt_send_debit, xmt_recv_credit, xmt_data} XmtState;
00074 
00075 struct PRFilePrivate
00076 {
00077     RcvState rcvstate;
00078     XmtState xmtstate;
00079     PRInt32 rcvreq, rcvinprogress;
00080     PRInt32 xmtreq, xmtinprogress;
00081 };
00082 
00083 typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity;
00084 
00085 static PRIntn minor_iterations = 5;
00086 static PRIntn major_iterations = 1;
00087 static Verbosity verbosity = quiet;
00088 static PRUint16 default_port = 12273;
00089 
00090 static PRFileDesc *PushLayer(PRFileDesc *stack)
00091 {
00092     PRStatus rv;
00093     PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods);
00094     layer->secret = PR_NEWZAP(PRFilePrivate);
00095     rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
00096     PR_ASSERT(PR_SUCCESS == rv);
00097     if (verbosity > quiet)
00098         PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
00099     return stack;
00100 }  /* PushLayer */
00101 
00102 static PRFileDesc *PopLayer(PRFileDesc *stack)
00103 {
00104     PRFileDesc *popped = PR_PopIOLayer(stack, identity);
00105     if (verbosity > quiet)
00106         PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack);
00107     PR_DELETE(popped->secret);
00108     popped->dtor(popped);
00109     return stack;
00110 }  /* PopLayer */
00111 
00112 static void PR_CALLBACK Client(void *arg)
00113 {
00114     PRStatus rv;
00115     PRIntn mits;
00116     PRInt32 ready;
00117     PRUint8 buffer[100];
00118     PRPollDesc polldesc;
00119     PRIntn empty_flags = 0;
00120     PRIntn bytes_read, bytes_sent;
00121     PRFileDesc *stack = (PRFileDesc*)arg;
00122 
00123     /* Initialize the buffer so that Purify won't complain */
00124     memset(buffer, 0, sizeof(buffer));
00125 
00126     rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
00127     if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR == PR_GetError()))
00128     {
00129         if (verbosity > quiet)
00130             PR_fprintf(logFile, "Client connect 'in progress'\n");
00131         do
00132         {
00133             polldesc.fd = stack;
00134             polldesc.out_flags = 0;
00135             polldesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
00136             ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
00137             if ((1 != ready)  /* if not 1, then we're dead */
00138             || (0 == (polldesc.in_flags & polldesc.out_flags)))
00139                 { PR_ASSERT(!"Whoa!"); break; }
00140             if (verbosity > quiet)
00141                 PR_fprintf(
00142                     logFile, "Client connect 'in progress' [0x%x]\n",
00143                     polldesc.out_flags);
00144             rv = PR_GetConnectStatus(&polldesc);
00145             if ((PR_FAILURE == rv)
00146             && (PR_IN_PROGRESS_ERROR != PR_GetError())) break;
00147         } while (PR_FAILURE == rv);
00148     }
00149     PR_ASSERT(PR_SUCCESS == rv);
00150     if (verbosity > chatty)
00151         PR_fprintf(logFile, "Client created connection\n");
00152 
00153     for (mits = 0; mits < minor_iterations; ++mits)
00154     {
00155         bytes_sent = 0;
00156         if (verbosity > quiet)
00157             PR_fprintf(logFile, "Client sending %d bytes\n", sizeof(buffer));
00158         do
00159         {
00160             if (verbosity > chatty)
00161                 PR_fprintf(
00162                     logFile, "Client sending %d bytes\n",
00163                     sizeof(buffer) - bytes_sent);
00164             ready = PR_Send(
00165                 stack, buffer + bytes_sent, sizeof(buffer) - bytes_sent,
00166                 empty_flags, PR_INTERVAL_NO_TIMEOUT);
00167             if (verbosity > chatty)
00168                 PR_fprintf(logFile, "Client send status [%d]\n", ready);
00169             if (0 < ready) bytes_sent += ready;
00170             else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
00171             {
00172                 polldesc.fd = stack;
00173                 polldesc.out_flags = 0;
00174                 polldesc.in_flags = PR_POLL_WRITE;
00175                 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
00176                 if ((1 != ready)  /* if not 1, then we're dead */
00177                 || (0 == (polldesc.in_flags & polldesc.out_flags)))
00178                     { PR_ASSERT(!"Whoa!"); break; }
00179             }
00180             else break;
00181         } while (bytes_sent < sizeof(buffer));
00182         PR_ASSERT(sizeof(buffer) == bytes_sent);
00183 
00184         bytes_read = 0;
00185         do
00186         {
00187             if (verbosity > chatty)
00188                 PR_fprintf(
00189                     logFile, "Client receiving %d bytes\n",
00190                     bytes_sent - bytes_read);
00191             ready = PR_Recv(
00192                 stack, buffer + bytes_read, bytes_sent - bytes_read,
00193                 empty_flags, PR_INTERVAL_NO_TIMEOUT);
00194             if (verbosity > chatty)
00195                 PR_fprintf(
00196                     logFile, "Client receive status [%d]\n", ready);
00197             if (0 < ready) bytes_read += ready;
00198             else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
00199             {
00200                 polldesc.fd = stack;
00201                 polldesc.out_flags = 0;
00202                 polldesc.in_flags = PR_POLL_READ;
00203                 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
00204                 if ((1 != ready)  /* if not 1, then we're dead */
00205                 || (0 == (polldesc.in_flags & polldesc.out_flags)))
00206                     { PR_ASSERT(!"Whoa!"); break; }
00207             }
00208             else break;
00209         } while (bytes_read < bytes_sent);
00210         if (verbosity > chatty)
00211             PR_fprintf(logFile, "Client received %d bytes\n", bytes_read);
00212         PR_ASSERT(bytes_read == bytes_sent);
00213     }
00214 
00215     if (verbosity > quiet)
00216         PR_fprintf(logFile, "Client shutting down stack\n");
00217     
00218     rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
00219 }  /* Client */
00220 
00221 static void PR_CALLBACK Server(void *arg)
00222 {
00223     PRStatus rv;
00224     PRInt32 ready;
00225     PRUint8 buffer[100];
00226     PRFileDesc *service;
00227     PRUintn empty_flags = 0;
00228     struct PRPollDesc polldesc;
00229     PRIntn bytes_read, bytes_sent;
00230     PRFileDesc *stack = (PRFileDesc*)arg;
00231     PRNetAddr client_address;
00232 
00233     do
00234     {
00235         if (verbosity > chatty)
00236             PR_fprintf(logFile, "Server accepting connection\n");
00237         service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT);
00238         if (verbosity > chatty)
00239             PR_fprintf(logFile, "Server accept status [0x%p]\n", service);
00240         if ((NULL == service) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
00241         {
00242             polldesc.fd = stack;
00243             polldesc.out_flags = 0;
00244             polldesc.in_flags = PR_POLL_READ | PR_POLL_EXCEPT;
00245             ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
00246             if ((1 != ready)  /* if not 1, then we're dead */
00247             || (0 == (polldesc.in_flags & polldesc.out_flags)))
00248                 { PR_ASSERT(!"Whoa!"); break; }
00249         }
00250     } while (NULL == service);
00251     PR_ASSERT(NULL != service);
00252         
00253     if (verbosity > quiet)
00254         PR_fprintf(logFile, "Server accepting connection\n");
00255 
00256     do
00257     {
00258         bytes_read = 0;
00259         do
00260         {
00261             if (verbosity > chatty)
00262                 PR_fprintf(
00263                     logFile, "Server receiving %d bytes\n",
00264                     sizeof(buffer) - bytes_read);
00265             ready = PR_Recv(
00266                 service, buffer + bytes_read, sizeof(buffer) - bytes_read,
00267                 empty_flags, PR_INTERVAL_NO_TIMEOUT);
00268             if (verbosity > chatty)
00269                 PR_fprintf(logFile, "Server receive status [%d]\n", ready);
00270             if (0 < ready) bytes_read += ready;
00271             else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
00272             {
00273                 polldesc.fd = service;
00274                 polldesc.out_flags = 0;
00275                 polldesc.in_flags = PR_POLL_READ;
00276                 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
00277                 if ((1 != ready)  /* if not 1, then we're dead */
00278                 || (0 == (polldesc.in_flags & polldesc.out_flags)))
00279                     { PR_ASSERT(!"Whoa!"); break; }
00280             }
00281             else break;
00282         } while (bytes_read < sizeof(buffer));
00283 
00284         if (0 != bytes_read)
00285         {
00286             if (verbosity > chatty)
00287                 PR_fprintf(logFile, "Server received %d bytes\n", bytes_read);
00288             PR_ASSERT(bytes_read > 0);
00289 
00290             bytes_sent = 0;
00291             do
00292             {
00293                 ready = PR_Send(
00294                     service, buffer + bytes_sent, bytes_read - bytes_sent,
00295                     empty_flags, PR_INTERVAL_NO_TIMEOUT);
00296                 if (0 < ready)
00297                 {
00298                     bytes_sent += ready;
00299                 }
00300                 else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
00301                 {
00302                     polldesc.fd = service;
00303                     polldesc.out_flags = 0;
00304                     polldesc.in_flags = PR_POLL_WRITE;
00305                     ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
00306                     if ((1 != ready)  /* if not 1, then we're dead */
00307                     || (0 == (polldesc.in_flags & polldesc.out_flags)))
00308                         { PR_ASSERT(!"Whoa!"); break; }
00309                 }
00310                 else break;
00311             } while (bytes_sent < bytes_read);
00312             PR_ASSERT(bytes_read == bytes_sent);
00313             if (verbosity > chatty)
00314                 PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent);
00315         }
00316     } while (0 != bytes_read);
00317 
00318     if (verbosity > quiet)
00319         PR_fprintf(logFile, "Server shutting down stack\n");
00320     rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
00321     rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
00322 
00323 }  /* Server */
00324 
00325 static PRStatus PR_CALLBACK MyClose(PRFileDesc *fd)
00326 {
00327     PR_DELETE(fd->secret);  /* manage my secret file object */
00328     return (PR_GetDefaultIOMethods())->close(fd);  /* let him do all the work */
00329 }  /* MyClose */
00330 
00331 static PRInt16 PR_CALLBACK MyPoll(
00332     PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
00333 {
00334     PRInt16 my_flags, new_flags;
00335     PRFilePrivate *mine = (PRFilePrivate*)fd->secret;
00336     if (0 != (PR_POLL_READ & in_flags))
00337     {
00338         /* client thinks he's reading */
00339         switch (mine->rcvstate)
00340         {
00341             case rcv_send_credit:
00342                 my_flags = (in_flags & ~PR_POLL_READ) | PR_POLL_WRITE;
00343                 break;
00344             case rcv_data:
00345             case rcv_get_debit:
00346                 my_flags = in_flags;
00347             default: break;
00348         }
00349     }
00350     else if (0 != (PR_POLL_WRITE & in_flags))
00351     {
00352         /* client thinks he's writing */
00353         switch (mine->xmtstate)
00354         {
00355             case xmt_recv_credit:
00356                 my_flags = (in_flags & ~PR_POLL_WRITE) | PR_POLL_READ;
00357                 break;
00358             case xmt_send_debit:
00359             case xmt_data:
00360                 my_flags = in_flags;
00361             default: break;
00362         }
00363     }
00364     else PR_ASSERT(!"How'd I get here?");
00365     new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags);
00366     if (verbosity > chatty)
00367         PR_fprintf(
00368             logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n",
00369             in_flags, my_flags, *out_flags, new_flags);
00370     return new_flags;
00371 }  /* MyPoll */
00372 
00373 static PRFileDesc * PR_CALLBACK MyAccept(
00374     PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
00375 {
00376     PRStatus rv;
00377     PRFileDesc *newfd, *layer = fd;
00378     PRFileDesc *newstack;
00379     PRFilePrivate *newsecret;
00380 
00381     PR_ASSERT(fd != NULL);
00382     PR_ASSERT(fd->lower != NULL);
00383 
00384     newstack = PR_NEW(PRFileDesc);
00385     if (NULL == newstack)
00386     {
00387         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00388         return NULL;
00389     }
00390     newsecret = PR_NEW(PRFilePrivate);
00391     if (NULL == newsecret)
00392     {
00393         PR_DELETE(newstack);
00394         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00395         return NULL;
00396     }
00397     *newstack = *fd;  /* make a copy of the accepting layer */
00398     *newsecret = *fd->secret;
00399     newstack->secret = newsecret;
00400 
00401     newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
00402     if (NULL == newfd)
00403     {
00404         PR_DELETE(newsecret);
00405         PR_DELETE(newstack);
00406         return NULL;
00407     }
00408 
00409     /* this PR_PushIOLayer call cannot fail */
00410     rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
00411     PR_ASSERT(PR_SUCCESS == rv);
00412     return newfd;  /* that's it */
00413 }
00414 
00415 static PRInt32 PR_CALLBACK MyRecv(
00416     PRFileDesc *fd, void *buf, PRInt32 amount,
00417     PRIntn flags, PRIntervalTime timeout)
00418 {
00419     char *b;
00420     PRInt32 rv;
00421     PRFileDesc *lo = fd->lower;
00422     PRFilePrivate *mine = (PRFilePrivate*)fd->secret;
00423 
00424     do
00425     {
00426         switch (mine->rcvstate)
00427         {
00428         case rcv_get_debit:
00429             b = (char*)&mine->rcvreq;
00430             mine->rcvreq = amount;
00431             rv = lo->methods->recv(
00432                 lo, b + mine->rcvinprogress,
00433                 sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout);
00434             if (0 == rv) goto closed;
00435             if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
00436             mine->rcvinprogress += rv;  /* accumulate the read */
00437             if (mine->rcvinprogress < sizeof(mine->rcvreq)) break;  /* loop */
00438             mine->rcvstate = rcv_send_credit;
00439             mine->rcvinprogress = 0;
00440         case rcv_send_credit:
00441             b = (char*)&mine->rcvreq;
00442             rv = lo->methods->send(
00443                 lo, b + mine->rcvinprogress,
00444                 sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout);
00445             if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
00446             mine->rcvinprogress += rv;  /* accumulate the read */
00447             if (mine->rcvinprogress < sizeof(mine->rcvreq)) break;  /* loop */
00448             mine->rcvstate = rcv_data;
00449             mine->rcvinprogress = 0;
00450         case rcv_data:
00451             b = (char*)buf;
00452             rv = lo->methods->recv(
00453                 lo, b + mine->rcvinprogress,
00454                 mine->rcvreq - mine->rcvinprogress, flags, timeout);
00455             if (0 == rv) goto closed;
00456             if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
00457             mine->rcvinprogress += rv;  /* accumulate the read */
00458             if (mine->rcvinprogress < amount) break;  /* loop */
00459             mine->rcvstate = rcv_get_debit;
00460             mine->rcvinprogress = 0;
00461             return mine->rcvreq;  /* << -- that's it! */
00462         default:
00463             break;
00464         }
00465     } while (-1 != rv);
00466     return rv;
00467 closed:
00468     mine->rcvinprogress = 0;
00469     mine->rcvstate = rcv_get_debit;
00470     return 0;
00471 }  /* MyRecv */
00472 
00473 static PRInt32 PR_CALLBACK MySend(
00474     PRFileDesc *fd, const void *buf, PRInt32 amount,
00475     PRIntn flags, PRIntervalTime timeout)
00476 {
00477     char *b;
00478     PRInt32 rv;
00479     PRFileDesc *lo = fd->lower;
00480     PRFilePrivate *mine = (PRFilePrivate*)fd->secret;
00481 
00482     do
00483     {
00484         switch (mine->xmtstate)
00485         {
00486         case xmt_send_debit:
00487             b = (char*)&mine->xmtreq;
00488             mine->xmtreq = amount;
00489             rv = lo->methods->send(
00490                 lo, b - mine->xmtinprogress,
00491                 sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout);
00492             if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
00493             mine->xmtinprogress += rv;
00494             if (mine->xmtinprogress < sizeof(mine->xmtreq)) break;
00495             mine->xmtstate = xmt_recv_credit;
00496             mine->xmtinprogress = 0;
00497         case xmt_recv_credit:
00498              b = (char*)&mine->xmtreq;
00499              rv = lo->methods->recv(
00500                 lo, b + mine->xmtinprogress,
00501                 sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout);
00502             if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
00503             mine->xmtinprogress += rv;
00504             if (mine->xmtinprogress < sizeof(mine->xmtreq)) break;
00505             mine->xmtstate = xmt_data;
00506             mine->xmtinprogress = 0;
00507         case xmt_data:
00508             b = (char*)buf;
00509             rv = lo->methods->send(
00510                 lo, b + mine->xmtinprogress,
00511                 mine->xmtreq - mine->xmtinprogress, flags, timeout);
00512             if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break;
00513             mine->xmtinprogress += rv;
00514             if (mine->xmtinprogress < amount) break;
00515             mine->xmtstate = xmt_send_debit;
00516             mine->xmtinprogress = 0;
00517             return mine->xmtreq;  /* <<-- That's the one! */
00518         default:
00519             break;
00520         }
00521     } while (-1 != rv);
00522     return rv;
00523 }  /* MySend */
00524 
00525 static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta)
00526 {
00527     PRIntn verbage = (PRIntn)verbosity + delta;
00528     if (verbage < (PRIntn)silent) verbage = (PRIntn)silent;
00529     else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy;
00530     return (Verbosity)verbage;
00531 }  /* ChangeVerbosity */
00532 
00533 PRIntn main(PRIntn argc, char **argv)
00534 {
00535     PRStatus rv;
00536     PLOptStatus os;
00537     PRFileDesc *client, *service;
00538     PRNetAddr any_address;
00539     const char *server_name = NULL;
00540     const PRIOMethods *stubMethods;
00541     PRThread *client_thread, *server_thread;
00542     PRThreadScope thread_scope = PR_LOCAL_THREAD;
00543     PRSocketOptionData socket_noblock, socket_nodelay;
00544     PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:");
00545     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00546     {
00547         if (PL_OPT_BAD == os) continue;
00548         switch (opt->option)
00549         {
00550         case 0:
00551             server_name = opt->value;
00552             break;
00553         case 'd':  /* debug mode */
00554             if (verbosity < noisy)
00555                 verbosity = ChangeVerbosity(verbosity, 1);
00556             break;
00557         case 'q':  /* debug mode */
00558             if (verbosity > silent)
00559                 verbosity = ChangeVerbosity(verbosity, -1);
00560             break;
00561         case 'G':  /* use global threads */
00562             thread_scope = PR_GLOBAL_THREAD;
00563             break;
00564         case 'C':  /* number of threads waiting */
00565             major_iterations = atoi(opt->value);
00566             break;
00567         case 'c':  /* number of client threads */
00568             minor_iterations = atoi(opt->value);
00569             break;
00570         case 'p':  /* default port */
00571             default_port = atoi(opt->value);
00572             break;
00573         default:
00574             break;
00575         }
00576     }
00577     PL_DestroyOptState(opt);
00578     PR_STDIO_INIT();
00579 
00580     logFile = PR_GetSpecialFD(PR_StandardError);
00581     identity = PR_GetUniqueIdentity("Dummy");
00582     stubMethods = PR_GetDefaultIOMethods();
00583 
00584     /*
00585     ** The protocol we're going to implement is one where in order to initiate
00586     ** a send, the sender must first solicit permission. Therefore, every
00587     ** send is really a send - receive - send sequence.
00588     */
00589     myMethods = *stubMethods;  /* first get the entire batch */
00590     myMethods.accept = MyAccept;  /* then override the ones we care about */
00591     myMethods.recv = MyRecv;  /* then override the ones we care about */
00592     myMethods.send = MySend;  /* then override the ones we care about */
00593     myMethods.close = MyClose;  /* then override the ones we care about */
00594     myMethods.poll = MyPoll;  /* then override the ones we care about */
00595 
00596     if (NULL == server_name)
00597         rv = PR_InitializeNetAddr(
00598             PR_IpAddrLoopback, default_port, &server_address);
00599     else
00600     {
00601         rv = PR_StringToNetAddr(server_name, &server_address);
00602         PR_ASSERT(PR_SUCCESS == rv);
00603         rv = PR_InitializeNetAddr(
00604             PR_IpAddrNull, default_port, &server_address);
00605     }
00606     PR_ASSERT(PR_SUCCESS == rv);
00607 
00608     socket_noblock.value.non_blocking = PR_TRUE;
00609     socket_noblock.option = PR_SockOpt_Nonblocking;
00610     socket_nodelay.value.no_delay = PR_TRUE;
00611     socket_nodelay.option = PR_SockOpt_NoDelay;
00612 
00613     /* one type w/o layering */
00614 
00615     while (major_iterations-- > 0)
00616     {
00617         if (verbosity > silent)
00618             PR_fprintf(logFile, "Beginning non-layered test\n");
00619 
00620         client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
00621         service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
00622 
00623         rv = PR_SetSocketOption(client, &socket_noblock);
00624         PR_ASSERT(PR_SUCCESS == rv);
00625         rv = PR_SetSocketOption(service, &socket_noblock);
00626         PR_ASSERT(PR_SUCCESS == rv);
00627         rv = PR_SetSocketOption(client, &socket_nodelay);
00628         PR_ASSERT(PR_SUCCESS == rv);
00629         rv = PR_SetSocketOption(service, &socket_nodelay);
00630         PR_ASSERT(PR_SUCCESS == rv);
00631 
00632         rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
00633         PR_ASSERT(PR_SUCCESS == rv);
00634         rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
00635         rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
00636 
00637         server_thread = PR_CreateThread(
00638             PR_USER_THREAD, Server, service,
00639             PR_PRIORITY_HIGH, thread_scope,
00640             PR_JOINABLE_THREAD, 16 * 1024);
00641         PR_ASSERT(NULL != server_thread);
00642 
00643         client_thread = PR_CreateThread(
00644             PR_USER_THREAD, Client, client,
00645             PR_PRIORITY_NORMAL, thread_scope,
00646             PR_JOINABLE_THREAD, 16 * 1024);
00647         PR_ASSERT(NULL != client_thread);
00648 
00649         rv = PR_JoinThread(client_thread);
00650         PR_ASSERT(PR_SUCCESS == rv);
00651         rv = PR_JoinThread(server_thread);
00652         PR_ASSERT(PR_SUCCESS == rv);
00653 
00654         rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
00655         rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
00656         if (verbosity > silent)
00657             PR_fprintf(logFile, "Ending non-layered test\n");
00658 
00659         /* with layering */
00660         if (verbosity > silent)
00661             PR_fprintf(logFile, "Beginning layered test\n");
00662         client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
00663         service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
00664 
00665         rv = PR_SetSocketOption(client, &socket_noblock);
00666         PR_ASSERT(PR_SUCCESS == rv);
00667         rv = PR_SetSocketOption(service, &socket_noblock);
00668         PR_ASSERT(PR_SUCCESS == rv);
00669         rv = PR_SetSocketOption(client, &socket_nodelay);
00670         PR_ASSERT(PR_SUCCESS == rv);
00671         rv = PR_SetSocketOption(service, &socket_nodelay);
00672         PR_ASSERT(PR_SUCCESS == rv);
00673 
00674         PushLayer(client);
00675         PushLayer(service);
00676 
00677         rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
00678         PR_ASSERT(PR_SUCCESS == rv);
00679         rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
00680         rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
00681 
00682         server_thread = PR_CreateThread(
00683             PR_USER_THREAD, Server, service,
00684             PR_PRIORITY_HIGH, thread_scope,
00685             PR_JOINABLE_THREAD, 16 * 1024);
00686         PR_ASSERT(NULL != server_thread);
00687 
00688         client_thread = PR_CreateThread(
00689             PR_USER_THREAD, Client, client,
00690             PR_PRIORITY_NORMAL, thread_scope,
00691             PR_JOINABLE_THREAD, 16 * 1024);
00692         PR_ASSERT(NULL != client_thread);
00693 
00694         rv = PR_JoinThread(client_thread);
00695         PR_ASSERT(PR_SUCCESS == rv);
00696         rv = PR_JoinThread(server_thread);
00697         PR_ASSERT(PR_SUCCESS == rv);
00698 
00699         rv = PR_Close(PopLayer(client)); PR_ASSERT(PR_SUCCESS == rv);
00700         rv = PR_Close(PopLayer(service)); PR_ASSERT(PR_SUCCESS == rv);
00701         if (verbosity > silent)
00702             PR_fprintf(logFile, "Ending layered test\n");
00703     }
00704     return 0;
00705 }  /* main */
00706 
00707 /* nblayer.c */