Back to index

lightning-sunbird  0.9+nobinonly
layer.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 "prprf.h"
00040 #include "prlog.h"
00041 #include "prnetdb.h"
00042 #include "prthread.h"
00043 
00044 #include "plerror.h"
00045 #include "plgetopt.h"
00046 #include "prwin16.h"
00047 
00048 #include <stdlib.h>
00049 #include <string.h>
00050 
00051 /*
00052 ** Testing layering of I/O
00053 **
00054 **      The layered server
00055 ** A thread that acts as a server. It creates a TCP listener with a dummy
00056 ** layer pushed on top. Then listens for incoming connections. Each connection
00057 ** request for connection will be layered as well, accept one request, echo
00058 ** it back and close.
00059 **
00060 **      The layered client
00061 ** Pretty much what you'd expect.
00062 */
00063 
00064 static PRFileDesc *logFile;
00065 static PRDescIdentity identity;
00066 static PRNetAddr server_address;
00067 
00068 static PRIOMethods myMethods;
00069 
00070 typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity;
00071 
00072 static PRIntn minor_iterations = 5;
00073 static PRIntn major_iterations = 1;
00074 static Verbosity verbosity = quiet;
00075 static PRUint16 default_port = 12273;
00076 
00077 static PRFileDesc *PushLayer(PRFileDesc *stack)
00078 {
00079     PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods);
00080     PRStatus rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
00081     if (verbosity > quiet)
00082         PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
00083     PR_ASSERT(PR_SUCCESS == rv);
00084     return stack;
00085 }  /* PushLayer */
00086 
00087 static PRFileDesc *PushNewLayers(PRFileDesc *stack)
00088 {
00089        PRDescIdentity tmp_identity;
00090     PRFileDesc *layer;
00091     PRStatus rv;
00092 
00093        /* push a dummy layer */
00094     tmp_identity = PR_GetUniqueIdentity("Dummy 1");
00095     layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods());
00096     rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
00097     if (verbosity > quiet)
00098         PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
00099                                                                                                          stack);
00100     PR_ASSERT(PR_SUCCESS == rv);
00101 
00102        /* push a data procesing layer */
00103     layer = PR_CreateIOLayerStub(identity, &myMethods);
00104     rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
00105     if (verbosity > quiet)
00106         PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
00107                                                                                            stack);
00108     PR_ASSERT(PR_SUCCESS == rv);
00109 
00110        /* push another dummy layer */
00111     tmp_identity = PR_GetUniqueIdentity("Dummy 2");
00112     layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods());
00113     rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
00114     if (verbosity > quiet)
00115         PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
00116                                                                                                          stack);
00117     PR_ASSERT(PR_SUCCESS == rv);
00118     return stack;
00119 }  /* PushLayer */
00120 
00121 #if 0
00122 static PRFileDesc *PopLayer(PRFileDesc *stack)
00123 {
00124     PRFileDesc *popped = PR_PopIOLayer(stack, identity);
00125     if (verbosity > quiet)
00126         PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack);
00127     popped->dtor(popped);
00128     
00129     return stack;
00130 }  /* PopLayer */
00131 #endif
00132 
00133 static void PR_CALLBACK Client(void *arg)
00134 {
00135     PRStatus rv;
00136     PRUint8 buffer[100];
00137     PRIntn empty_flags = 0;
00138     PRIntn bytes_read, bytes_sent;
00139     PRFileDesc *stack = (PRFileDesc*)arg;
00140 
00141     /* Initialize the buffer so that Purify won't complain */
00142     memset(buffer, 0, sizeof(buffer));
00143 
00144     rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
00145     PR_ASSERT(PR_SUCCESS == rv);
00146     while (minor_iterations-- > 0)
00147     {
00148         bytes_sent = PR_Send(
00149             stack, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
00150         PR_ASSERT(sizeof(buffer) == bytes_sent);
00151         if (verbosity > chatty)
00152             PR_fprintf(logFile, "Client sending %d bytes\n", bytes_sent);
00153         bytes_read = PR_Recv(
00154             stack, buffer, bytes_sent, empty_flags, PR_INTERVAL_NO_TIMEOUT);
00155         if (verbosity > chatty)
00156             PR_fprintf(logFile, "Client receiving %d bytes\n", bytes_read);
00157         PR_ASSERT(bytes_read == bytes_sent);
00158     }
00159 
00160     if (verbosity > quiet)
00161         PR_fprintf(logFile, "Client shutting down stack\n");
00162     
00163     rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
00164 }  /* Client */
00165 
00166 static void PR_CALLBACK Server(void *arg)
00167 {
00168     PRStatus rv;
00169     PRUint8 buffer[100];
00170     PRFileDesc *service;
00171     PRUintn empty_flags = 0;
00172     PRIntn bytes_read, bytes_sent;
00173     PRFileDesc *stack = (PRFileDesc*)arg;
00174     PRNetAddr client_address;
00175 
00176     service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT);
00177     if (verbosity > quiet)
00178         PR_fprintf(logFile, "Server accepting connection\n");
00179 
00180     do
00181     {
00182         bytes_read = PR_Recv(
00183             service, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
00184         if (0 != bytes_read)
00185         {
00186             if (verbosity > chatty)
00187                 PR_fprintf(logFile, "Server receiving %d bytes\n", bytes_read);
00188             PR_ASSERT(bytes_read > 0);
00189             bytes_sent = PR_Send(
00190                 service, buffer, bytes_read, empty_flags, PR_INTERVAL_NO_TIMEOUT);
00191             if (verbosity > chatty)
00192                 PR_fprintf(logFile, "Server sending %d bytes\n", bytes_sent);
00193             PR_ASSERT(bytes_read == bytes_sent);
00194         }
00195 
00196     } while (0 != bytes_read);
00197 
00198     if (verbosity > quiet)
00199         PR_fprintf(logFile, "Server shutting down and closing stack\n");
00200     rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
00201     rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
00202 
00203 }  /* Server */
00204 
00205 static PRInt32 PR_CALLBACK MyRecv(
00206     PRFileDesc *fd, void *buf, PRInt32 amount,
00207     PRIntn flags, PRIntervalTime timeout)
00208 {
00209     char *b = (char*)buf;
00210     PRFileDesc *lo = fd->lower;
00211     PRInt32 rv, readin = 0, request = 0;
00212     rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout);
00213     if (verbosity > chatty) PR_fprintf(
00214         logFile, "MyRecv sending permission for %d bytes\n", request);
00215     if (0 < rv)
00216     {
00217         if (verbosity > chatty) PR_fprintf(
00218             logFile, "MyRecv received permission request for %d bytes\n", request);
00219         rv = lo->methods->send(
00220             lo, &request, sizeof(request), flags, timeout);
00221         if (0 < rv)
00222         {
00223             if (verbosity > chatty) PR_fprintf(
00224                 logFile, "MyRecv sending permission for %d bytes\n", request);
00225             while (readin < request)
00226             {
00227                 rv = lo->methods->recv(
00228                     lo, b + readin, amount - readin, flags, timeout);
00229                 if (rv <= 0) break;
00230                 if (verbosity > chatty) PR_fprintf(
00231                     logFile, "MyRecv received %d bytes\n", rv);
00232                 readin += rv;
00233             }
00234             rv = readin;
00235         }
00236     }
00237     return rv;
00238 }  /* MyRecv */
00239 
00240 static PRInt32 PR_CALLBACK MySend(
00241     PRFileDesc *fd, const void *buf, PRInt32 amount,
00242     PRIntn flags, PRIntervalTime timeout)
00243 {
00244     PRFileDesc *lo = fd->lower;
00245     const char *b = (const char*)buf;
00246     PRInt32 rv, wroteout = 0, request;
00247     if (verbosity > chatty) PR_fprintf(
00248         logFile, "MySend asking permission to send %d bytes\n", amount);
00249     rv = lo->methods->send(lo, &amount, sizeof(amount), flags, timeout);
00250     if (0 < rv)
00251     {
00252         rv = lo->methods->recv(
00253             lo, &request, sizeof(request), flags, timeout);
00254         if (0 < rv)
00255         {
00256             PR_ASSERT(request == amount);
00257             if (verbosity > chatty) PR_fprintf(
00258                 logFile, "MySend got permission to send %d bytes\n", request);
00259             while (wroteout < request)
00260             {
00261                 rv = lo->methods->send(
00262                     lo, b + wroteout, request - wroteout, flags, timeout);
00263                 if (rv <= 0) break;
00264                 if (verbosity > chatty) PR_fprintf(
00265                     logFile, "MySend wrote %d bytes\n", rv);
00266                 wroteout += rv;
00267             }
00268             rv = amount;
00269         }
00270     }
00271     return rv;
00272 }  /* MySend */
00273 
00274 static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta)
00275 {
00276     PRIntn verbage = (PRIntn)verbosity + delta;
00277     if (verbage < (PRIntn)silent) verbage = (PRIntn)silent;
00278     else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy;
00279     return (Verbosity)verbage;
00280 }  /* ChangeVerbosity */
00281 
00282 PRIntn main(PRIntn argc, char **argv)
00283 {
00284     PRStatus rv;
00285     PRIntn mits;
00286     PLOptStatus os;
00287     PRFileDesc *client, *service;
00288     PRFileDesc *client_stack, *service_stack;
00289     PRNetAddr any_address;
00290     const char *server_name = NULL;
00291     const PRIOMethods *stubMethods;
00292     PRThread *client_thread, *server_thread;
00293     PRThreadScope thread_scope = PR_LOCAL_THREAD;
00294     PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:");
00295     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00296     {
00297         if (PL_OPT_BAD == os) continue;
00298         switch (opt->option)
00299         {
00300         case 0:
00301             server_name = opt->value;
00302             break;
00303         case 'd':  /* debug mode */
00304             if (verbosity < noisy)
00305                 verbosity = ChangeVerbosity(verbosity, 1);
00306             break;
00307         case 'q':  /* debug mode */
00308             if (verbosity > silent)
00309                 verbosity = ChangeVerbosity(verbosity, -1);
00310             break;
00311         case 'G':  /* use global threads */
00312             thread_scope = PR_GLOBAL_THREAD;
00313             break;
00314         case 'C':  /* number of threads waiting */
00315             major_iterations = atoi(opt->value);
00316             break;
00317         case 'c':  /* number of client threads */
00318             minor_iterations = atoi(opt->value);
00319             break;
00320         case 'p':  /* default port */
00321             default_port = atoi(opt->value);
00322             break;
00323         default:
00324             break;
00325         }
00326     }
00327     PL_DestroyOptState(opt);
00328     PR_STDIO_INIT();
00329 
00330     logFile = PR_GetSpecialFD(PR_StandardError);
00331 
00332     identity = PR_GetUniqueIdentity("Dummy");
00333     stubMethods = PR_GetDefaultIOMethods();
00334 
00335     /*
00336     ** The protocol we're going to implement is one where in order to initiate
00337     ** a send, the sender must first solicit permission. Therefore, every
00338     ** send is really a send - receive - send sequence.
00339     */
00340     myMethods = *stubMethods;  /* first get the entire batch */
00341     myMethods.recv = MyRecv;  /* then override the ones we care about */
00342     myMethods.send = MySend;  /* then override the ones we care about */
00343 
00344     if (NULL == server_name)
00345         rv = PR_InitializeNetAddr(
00346             PR_IpAddrLoopback, default_port, &server_address);
00347     else
00348     {
00349         rv = PR_StringToNetAddr(server_name, &server_address);
00350         PR_ASSERT(PR_SUCCESS == rv);
00351         rv = PR_InitializeNetAddr(
00352             PR_IpAddrNull, default_port, &server_address);
00353     }
00354     PR_ASSERT(PR_SUCCESS == rv);
00355 
00356     /* one type w/o layering */
00357 
00358     mits = minor_iterations;
00359     while (major_iterations-- > 0)
00360     {
00361         if (verbosity > silent)
00362             PR_fprintf(logFile, "Beginning non-layered test\n");
00363         client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
00364         service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
00365         rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
00366         PR_ASSERT(PR_SUCCESS == rv);
00367         rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
00368         rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
00369 
00370         minor_iterations = mits;
00371         server_thread = PR_CreateThread(
00372             PR_USER_THREAD, Server, service,
00373             PR_PRIORITY_HIGH, thread_scope,
00374             PR_JOINABLE_THREAD, 16 * 1024);
00375         PR_ASSERT(NULL != server_thread);
00376 
00377         client_thread = PR_CreateThread(
00378             PR_USER_THREAD, Client, client,
00379             PR_PRIORITY_NORMAL, thread_scope,
00380             PR_JOINABLE_THREAD, 16 * 1024);
00381         PR_ASSERT(NULL != client_thread);
00382 
00383         rv = PR_JoinThread(client_thread);
00384         PR_ASSERT(PR_SUCCESS == rv);
00385         rv = PR_JoinThread(server_thread);
00386         PR_ASSERT(PR_SUCCESS == rv);
00387 
00388         rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
00389         rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
00390         if (verbosity > silent)
00391             PR_fprintf(logFile, "Ending non-layered test\n");
00392 
00393         /* with layering */
00394         if (verbosity > silent)
00395             PR_fprintf(logFile, "Beginning layered test\n");
00396         client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
00397         PushLayer(client);
00398         service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
00399         PushLayer(service);
00400         rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
00401         PR_ASSERT(PR_SUCCESS == rv);
00402         rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
00403         rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
00404 
00405         minor_iterations = mits;
00406         server_thread = PR_CreateThread(
00407             PR_USER_THREAD, Server, service,
00408             PR_PRIORITY_HIGH, thread_scope,
00409             PR_JOINABLE_THREAD, 16 * 1024);
00410         PR_ASSERT(NULL != server_thread);
00411 
00412         client_thread = PR_CreateThread(
00413             PR_USER_THREAD, Client, client,
00414             PR_PRIORITY_NORMAL, thread_scope,
00415             PR_JOINABLE_THREAD, 16 * 1024);
00416         PR_ASSERT(NULL != client_thread);
00417 
00418         rv = PR_JoinThread(client_thread);
00419         PR_ASSERT(PR_SUCCESS == rv);
00420         rv = PR_JoinThread(server_thread);
00421         PR_ASSERT(PR_SUCCESS == rv);
00422 
00423         rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
00424         rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
00425         /* with layering, using new style stack */
00426         if (verbosity > silent)
00427             PR_fprintf(logFile,
00428                                                  "Beginning layered test with new style stack\n");
00429         client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
00430        client_stack = PR_CreateIOLayer(client);
00431         PushNewLayers(client_stack);
00432         service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
00433        service_stack = PR_CreateIOLayer(service);
00434         PushNewLayers(service_stack);
00435         rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
00436         PR_ASSERT(PR_SUCCESS == rv);
00437         rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
00438         rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
00439 
00440         minor_iterations = mits;
00441         server_thread = PR_CreateThread(
00442             PR_USER_THREAD, Server, service_stack,
00443             PR_PRIORITY_HIGH, thread_scope,
00444             PR_JOINABLE_THREAD, 16 * 1024);
00445         PR_ASSERT(NULL != server_thread);
00446 
00447         client_thread = PR_CreateThread(
00448             PR_USER_THREAD, Client, client_stack,
00449             PR_PRIORITY_NORMAL, thread_scope,
00450             PR_JOINABLE_THREAD, 16 * 1024);
00451         PR_ASSERT(NULL != client_thread);
00452 
00453         rv = PR_JoinThread(client_thread);
00454         PR_ASSERT(PR_SUCCESS == rv);
00455         rv = PR_JoinThread(server_thread);
00456         PR_ASSERT(PR_SUCCESS == rv);
00457 
00458         rv = PR_Close(client_stack); PR_ASSERT(PR_SUCCESS == rv);
00459         rv = PR_Close(service_stack); PR_ASSERT(PR_SUCCESS == rv);
00460         if (verbosity > silent)
00461             PR_fprintf(logFile, "Ending layered test\n");
00462     }
00463     return 0;
00464 }  /* main */
00465 
00466 /* layer.c */