Back to index

lightning-sunbird  0.9+nobinonly
tmocon.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 /***********************************************************************
00039 **
00040 ** Name: tmocon.c
00041 **
00042 ** Description: test client socket connection.
00043 **
00044 ** Modification History:
00045 ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
00046 **              The debug mode will print all of the printfs associated with this test.
00047 **                    The regress mode will be the default mode. Since the regress tool limits
00048 **           the output to a one line status:PASS or FAIL,all of the printf statements
00049 **                    have been handled with an if (debug_mode) statement. 
00050 ***********************************************************************/
00051 
00052 /***********************************************************************
00053 ** Includes
00054 ***********************************************************************/
00055 /* Used to get the command line option */
00056 #include "plgetopt.h"
00057 
00058 #include "nspr.h"
00059 #include "pprio.h"
00060 
00061 #include "plerror.h"
00062 #include "plgetopt.h"
00063 
00064 #include <stdio.h>
00065 #include <stdlib.h>
00066 #include <string.h>
00067 
00068 /* for getcwd */
00069 #if defined(XP_UNIX) || defined (XP_OS2_EMX) || defined(XP_BEOS)
00070 #include <unistd.h>
00071 #elif defined(XP_PC)
00072 #include <direct.h>
00073 #endif
00074 
00075 #ifdef XP_MAC
00076 #include "prlog.h"
00077 #define printf PR_LogPrint
00078 #endif
00079 
00080 
00081 #define BASE_PORT 9867
00082 
00083 #define DEFAULT_DALLY 1
00084 #define DEFAULT_THREADS 1
00085 #define DEFAULT_TIMEOUT 10
00086 #define DEFAULT_MESSAGES 100
00087 #define DEFAULT_MESSAGESIZE 100
00088 
00089 static PRFileDesc *debug_out = NULL;
00090 
00091 typedef struct Shared
00092 {
00093     PRBool random;
00094     PRBool failed;
00095     PRBool intermittant;
00096     PRIntn debug;
00097     PRInt32 messages;
00098     PRIntervalTime dally;
00099     PRIntervalTime timeout;
00100     PRInt32 message_length;
00101     PRNetAddr serverAddress;
00102 } Shared;
00103 
00104 static PRIntervalTime Timeout(const Shared *shared)
00105 {
00106     PRIntervalTime timeout = shared->timeout;
00107     if (shared->random)
00108     {
00109         PRIntervalTime quarter = timeout >> 2;  /* one quarter of the interval */
00110         PRUint32 random = rand() % quarter;  /* something in[0..timeout / 4) */
00111         timeout = (((3 * quarter) + random) >> 2) + quarter;  /* [75..125)% */
00112     }
00113     return timeout;
00114 }  /* Timeout */
00115 
00116 static void CauseTimeout(const Shared *shared)
00117 {
00118     if (shared->intermittant) PR_Sleep(Timeout(shared));
00119 }  /* CauseTimeout */
00120 
00121 static PRStatus MakeReceiver(Shared *shared)
00122 {
00123     PRStatus rv = PR_FAILURE;
00124     if (PR_IsNetAddrType(&shared->serverAddress, PR_IpAddrLoopback))
00125     {
00126         char *argv[3];
00127         char path[1024 + sizeof("/tmoacc")];
00128         (void)getcwd(path, sizeof(path));
00129         (void)strcat(path, "/tmoacc");
00130 #ifdef XP_PC
00131         (void)strcat(path, ".exe");
00132 #endif
00133         argv[0] = path;
00134         if (shared->debug > 0)
00135         {
00136             argv[1] = "-d";
00137             argv[2] = NULL;
00138         }
00139         else argv[1] = NULL;
00140         if (shared->debug > 1)
00141             PR_fprintf(debug_out, " creating accept process %s ...", path);
00142         fflush(stdout);
00143         rv = PR_CreateProcessDetached(path, argv, NULL, NULL);
00144         if (PR_SUCCESS == rv)
00145         {
00146             if (shared->debug > 1)
00147                 PR_fprintf(debug_out, " wait 5 seconds");
00148             if (shared->debug > 1)
00149                 PR_fprintf(debug_out, " before connecting to accept process ...");
00150             fflush(stdout);
00151             PR_Sleep(PR_SecondsToInterval(5));
00152             return rv;
00153         }
00154         shared->failed = PR_TRUE;
00155         if (shared->debug > 0)
00156             PL_FPrintError(debug_out, "PR_CreateProcessDetached failed");
00157     }
00158     return rv;
00159 }  /* MakeReceiver */
00160 
00161 static void Connect(void *arg)
00162 {
00163     PRStatus rv;
00164     char *buffer = NULL;
00165     PRFileDesc *clientSock;
00166     Shared *shared = (Shared*)arg;
00167     PRInt32 loop, bytes, flags = 0;
00168     struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor;
00169     debug_out = (0 == shared->debug) ? NULL : PR_GetSpecialFD(PR_StandardError);
00170 
00171     buffer = (char*)PR_MALLOC(shared->message_length);
00172 
00173     for (bytes = 0; bytes < shared->message_length; ++bytes)
00174         buffer[bytes] = (char)bytes;
00175 
00176     descriptor.checksum = 0;
00177     for (bytes = 0; bytes < shared->message_length; ++bytes)
00178     {
00179         PRUint32 overflow = descriptor.checksum & 0x80000000;
00180         descriptor.checksum = (descriptor.checksum << 1);
00181         if (0x00000000 != overflow) descriptor.checksum += 1;
00182         descriptor.checksum += buffer[bytes];
00183     }
00184     descriptor.checksum = PR_htonl(descriptor.checksum);
00185 
00186     for (loop = 0; loop < shared->messages; ++loop)
00187     {
00188         if (shared->debug > 1)
00189             PR_fprintf(debug_out, "[%d]socket ... ", loop);
00190         clientSock = PR_NewTCPSocket();
00191         if (clientSock)
00192         {
00193             /*
00194              * We need to slow down the rate of generating connect requests,
00195              * otherwise the listen backlog queue on the accept side may
00196              * become full and we will get connection refused or timeout
00197              * error.
00198              */
00199 
00200             PR_Sleep(shared->dally);
00201             if (shared->debug > 1)
00202             {
00203                 char buf[128];
00204                 PR_NetAddrToString(&shared->serverAddress, buf, sizeof(buf));
00205                 PR_fprintf(debug_out, "connecting to %s ... ", buf);
00206             }
00207             rv = PR_Connect(
00208                 clientSock, &shared->serverAddress, Timeout(shared));
00209             if (PR_SUCCESS == rv)
00210             {
00211                 PRInt32 descriptor_length = (loop < (shared->messages - 1)) ?
00212                     shared->message_length : 0;
00213                 descriptor.length = PR_htonl(descriptor_length);
00214                 if (shared->debug > 1)
00215                     PR_fprintf(
00216                         debug_out, "sending %d bytes ... ", descriptor_length);
00217                 CauseTimeout(shared);  /* might cause server to timeout */
00218                 bytes = PR_Send(
00219                     clientSock, &descriptor, sizeof(descriptor),
00220                     flags, Timeout(shared));
00221                 if (bytes != sizeof(descriptor))
00222                 {
00223                     shared->failed = PR_TRUE;
00224                     if (shared->debug > 0)
00225                         PL_FPrintError(debug_out, "PR_Send failed");
00226                 }
00227                 if (0 != descriptor_length)
00228                 {
00229                     CauseTimeout(shared);
00230                     bytes = PR_Send(
00231                         clientSock, buffer, descriptor_length,
00232                         flags, Timeout(shared));
00233                     if (bytes != descriptor_length)
00234                     {
00235                         shared->failed = PR_TRUE;
00236                         if (shared->debug > 0)
00237                             PL_FPrintError(debug_out, "PR_Send failed");
00238                     }
00239                 }
00240                 if (shared->debug > 1) PR_fprintf(debug_out, "closing ... ");
00241                 rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
00242                 rv = PR_Close(clientSock);
00243                 if (shared->debug > 1)
00244                 {
00245                     if (PR_SUCCESS == rv) PR_fprintf(debug_out, "\n");
00246                     else PL_FPrintError(debug_out, "shutdown failed");
00247                 }
00248             }
00249             else
00250             {
00251                 if (shared->debug > 1) PL_FPrintError(debug_out, "connect failed");
00252                 PR_Close(clientSock);
00253                 if ((loop == 0) && (PR_GetError() == PR_CONNECT_REFUSED_ERROR))
00254                 {
00255                     if (MakeReceiver(shared) == PR_FAILURE) break;
00256                 }
00257                 else
00258                 {
00259                     if (shared->debug > 1) PR_fprintf(debug_out, " exiting\n");
00260                     break;
00261                 }
00262             }
00263         }
00264         else
00265         {
00266             shared->failed = PR_TRUE;
00267             if (shared->debug > 0) PL_FPrintError(debug_out, "create socket");
00268             break;
00269         }
00270     }
00271 
00272     PR_DELETE(buffer);
00273 }  /* Connect */
00274 
00275 int Tmocon(int argc, char **argv)
00276 {
00277     /*
00278      * USAGE
00279      * -d       turn on debugging output                (default = off)
00280      * -v       turn on verbose output                  (default = off)
00281      * -h <n>   dns name of host serving the connection (default = self)
00282      * -i       dally intermittantly to cause timeouts  (default = off)
00283      * -m <n>   number of messages to send              (default = 100)
00284      * -s <n>   size of each message                    (default = 100)
00285      * -t <n>   number of threads sending               (default = 1)
00286      * -G       use global threads                      (default = local)
00287      * -T <n>   timeout on I/O operations (seconds)     (default = 10)
00288      * -D <n>   dally between connect requests (seconds)(default = 0)
00289      * -R       randomize the dally types around 'T'    (default = no)
00290      */
00291 
00292     PRStatus rv;
00293     int exitStatus;
00294     PLOptStatus os;
00295     Shared *shared = NULL;
00296     PRThread **thread = NULL;
00297     PRIntn index, threads = DEFAULT_THREADS;
00298     PRThreadScope thread_scope = PR_LOCAL_THREAD;
00299     PRInt32 dally = DEFAULT_DALLY, timeout = DEFAULT_TIMEOUT;
00300     PLOptState *opt = PL_CreateOptState(argc, argv, "divGRh:m:s:t:T:D:");
00301 
00302     shared = PR_NEWZAP(Shared);
00303 
00304     shared->debug = 0;
00305     shared->failed = PR_FALSE;
00306     shared->random = PR_FALSE;
00307     shared->messages = DEFAULT_MESSAGES;
00308     shared->message_length = DEFAULT_MESSAGESIZE;
00309 
00310     PR_STDIO_INIT();
00311     memset(&shared->serverAddress, 0, sizeof(shared->serverAddress));
00312     rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &shared->serverAddress);
00313     PR_ASSERT(PR_SUCCESS == rv);
00314     
00315     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00316     {
00317         if (PL_OPT_BAD == os) continue;
00318         switch (opt->option)
00319         {
00320         case 'd':
00321             if (0 == shared->debug) shared->debug = 1;
00322             break;
00323         case 'v':
00324             if (0 == shared->debug) shared->debug = 2;
00325             break;
00326         case 'i':
00327             shared->intermittant = PR_TRUE;
00328             break;
00329         case 'R':
00330             shared->random = PR_TRUE;
00331             break;
00332         case 'G':
00333             thread_scope = PR_GLOBAL_THREAD;
00334             break;
00335         case 'h':  /* the value for backlock */
00336             {
00337                 PRIntn es = 0;
00338                 PRHostEnt host;
00339                 char buffer[1024];
00340                 (void)PR_GetHostByName(
00341                     opt->value, buffer, sizeof(buffer), &host);
00342                 es = PR_EnumerateHostEnt(
00343                     es, &host, BASE_PORT, &shared->serverAddress);
00344                 PR_ASSERT(es > 0);
00345             }
00346             break;
00347         case 'm':  /* number of messages to send */
00348             shared->messages = atoi(opt->value);
00349             break;
00350         case 't':  /* number of threads sending */
00351             threads = atoi(opt->value);
00352             break;
00353         case 'D':  /* dally time between transmissions */
00354             dally = atoi(opt->value);
00355             break;
00356         case 'T':  /* timeout on I/O operations */
00357             timeout = atoi(opt->value);
00358             break;
00359         case 's':  /* total size of each message */
00360             shared->message_length = atoi(opt->value);
00361             break;
00362         default:
00363             break;
00364         }
00365     }
00366         PL_DestroyOptState(opt);
00367 
00368     if (0 == timeout) timeout = DEFAULT_TIMEOUT;
00369     if (0 == threads) threads = DEFAULT_THREADS;
00370     if (0 == shared->messages) shared->messages = DEFAULT_MESSAGES;
00371     if (0 == shared->message_length) shared->message_length = DEFAULT_MESSAGESIZE;
00372 
00373     shared->dally = PR_SecondsToInterval(dally);
00374     shared->timeout = PR_SecondsToInterval(timeout);
00375 
00376     thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*));
00377 
00378     for (index = 0; index < threads; ++index)
00379         thread[index] = PR_CreateThread(
00380             PR_USER_THREAD, Connect, shared,
00381             PR_PRIORITY_NORMAL, thread_scope,
00382             PR_JOINABLE_THREAD, 0);
00383     for (index = 0; index < threads; ++index)
00384         rv = PR_JoinThread(thread[index]);
00385 
00386     PR_DELETE(thread);
00387 
00388     PR_fprintf(
00389         PR_GetSpecialFD(PR_StandardError), "%s\n",
00390         ((shared->failed) ? "FAILED" : "PASSED"));
00391     exitStatus = (shared->failed) ? 1 : 0;
00392     PR_DELETE(shared);
00393     return exitStatus;
00394 }
00395 
00396 int main(int argc, char **argv)
00397 {
00398     return (PR_VersionCheck(PR_VERSION)) ?
00399         PR_Initialize(Tmocon, argc, argv, 4) : -1;
00400 }  /* main */
00401 
00402 /* tmocon.c */
00403 
00404