Back to index

lightning-sunbird  0.9+nobinonly
tmoacc.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 "nspr.h"
00039 
00040 #include <stdlib.h>
00041 #include <string.h>
00042 
00043 #include "plerror.h"
00044 #include "plgetopt.h"
00045 
00046 #ifdef XP_MAC
00047 #include "prlog.h"
00048 #define printf PR_LogPrint
00049 #endif
00050 
00051 #define BASE_PORT 9867
00052 #define DEFAULT_THREADS 1
00053 #define DEFAULT_BACKLOG 10
00054 #define DEFAULT_TIMEOUT 10
00055 #define RANDOM_RANGE 100  /* should be significantly smaller than RAND_MAX */
00056 
00057 typedef enum {running, stopped} Status;
00058 
00059 typedef struct Shared
00060 {
00061     PRLock *ml;
00062     PRCondVar *cv;
00063     PRBool passed;
00064     PRBool random;
00065     PRFileDesc *debug;
00066     PRIntervalTime timeout;
00067     PRFileDesc *listenSock;
00068     Status status;
00069 } Shared;
00070 
00071 static PRIntervalTime Timeout(const Shared *shared)
00072 {
00073     PRIntervalTime timeout = shared->timeout;
00074     if (shared->random)
00075     {
00076         PRIntervalTime half = timeout >> 1;  /* one half of the interval */
00077         PRIntervalTime quarter = half >> 1;  /* one quarter of the interval */
00078         /* something in [0..timeout / 2) */
00079         PRUint32 random = (rand() % RANDOM_RANGE) * half / RANDOM_RANGE;
00080         timeout = (3 * quarter) + random;  /* [75..125)% */
00081     }
00082     return timeout;
00083 }  /* Timeout */
00084 
00085 static void Accept(void *arg)
00086 {
00087     PRStatus rv;
00088     char *buffer = NULL;
00089     PRNetAddr clientAddr;
00090     Shared *shared = (Shared*)arg;
00091     PRInt32 recv_length = 0, flags = 0;
00092     PRFileDesc *clientSock;
00093     PRIntn toread, byte, bytes, loop = 0;
00094     struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor;
00095 
00096     do
00097     {
00098         PRUint32 checksum = 0;
00099         if (NULL != shared->debug)
00100             PR_fprintf(shared->debug, "[%d]accepting ... ", loop++);
00101         clientSock = PR_Accept(
00102             shared->listenSock, &clientAddr, Timeout(shared));
00103         if (clientSock != NULL)
00104         {
00105             if (NULL != shared->debug)
00106                 PR_fprintf(shared->debug, "reading length ... ");
00107             bytes = PR_Recv(
00108                 clientSock, &descriptor, sizeof(descriptor),
00109                 flags, Timeout(shared));
00110             if (sizeof(descriptor) == bytes)
00111             {
00112                 /* and, before doing something stupid ... */
00113                 descriptor.length = PR_ntohl(descriptor.length);
00114                 descriptor.checksum = PR_ntohl(descriptor.checksum);
00115                 if (NULL != shared->debug)
00116                     PR_fprintf(shared->debug, "%d bytes ... ", descriptor.length);
00117                 toread = descriptor.length;
00118                 if (recv_length < descriptor.length)
00119                 {
00120                     if (NULL != buffer) PR_DELETE(buffer);
00121                     buffer = (char*)PR_MALLOC(descriptor.length);
00122                     recv_length = descriptor.length;
00123                 }
00124                 for (toread = descriptor.length; toread > 0; toread -= bytes)
00125                 {
00126                     bytes = PR_Recv(
00127                         clientSock, &buffer[descriptor.length - toread],
00128                         toread, flags, Timeout(shared));
00129                     if (-1 == bytes)
00130                     {
00131                         if (NULL != shared->debug)
00132                             PR_fprintf(shared->debug, "read data failed...");
00133                         bytes = 0;
00134                     }
00135                 }
00136             }
00137             else if (NULL != shared->debug)
00138             {
00139                 PR_fprintf(shared->debug, "read desciptor failed...");
00140                 descriptor.length = -1;
00141             }
00142             if (NULL != shared->debug)
00143                 PR_fprintf(shared->debug, "closing");
00144             rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
00145             if ((PR_FAILURE == rv) && (NULL != shared->debug))
00146             {
00147                 PR_fprintf(shared->debug, " failed");
00148                 shared->passed = PR_FALSE;
00149             }
00150             rv = PR_Close(clientSock);
00151             if (PR_FAILURE == rv) if (NULL != shared->debug)
00152             {
00153                 PR_fprintf(shared->debug, " failed");
00154                 shared->passed = PR_FALSE;
00155             }
00156             if (descriptor.length > 0)
00157             {
00158                 for (byte = 0; byte < descriptor.length; ++byte)
00159                 {
00160                     PRUint32 overflow = checksum & 0x80000000;
00161                     checksum = (checksum << 1);
00162                     if (0x00000000 != overflow) checksum += 1;
00163                     checksum += buffer[byte];
00164                 }
00165                 if ((descriptor.checksum != checksum) && (NULL != shared->debug))
00166                 {
00167                     PR_fprintf(shared->debug, " ... data mismatch");
00168                     shared->passed = PR_FALSE;
00169                 }
00170             }
00171             else if (0 == descriptor.length)
00172             {
00173                 PR_Lock(shared->ml);
00174                 shared->status = stopped;
00175                 PR_NotifyCondVar(shared->cv);
00176                 PR_Unlock(shared->ml);
00177             }
00178             if (NULL != shared->debug)
00179                 PR_fprintf(shared->debug, "\n");
00180         }
00181         else
00182         {
00183             if (PR_PENDING_INTERRUPT_ERROR != PR_GetError())
00184             {
00185                 if (NULL != shared->debug) PL_PrintError("Accept");
00186                 shared->passed = PR_FALSE;
00187             }
00188         }        
00189     } while (running == shared->status);
00190     if (NULL != buffer) PR_DELETE(buffer);
00191 }  /* Accept */
00192 
00193 PRIntn Tmoacc(PRIntn argc, char **argv)
00194 {
00195     PRStatus rv;
00196     PRIntn exitStatus;
00197     PRIntn index;
00198        Shared *shared;
00199        PLOptStatus os;
00200        PRThread **thread;
00201     PRNetAddr listenAddr;
00202     PRSocketOptionData sockOpt;
00203     PRIntn timeout = DEFAULT_TIMEOUT;
00204     PRIntn threads = DEFAULT_THREADS;
00205     PRIntn backlog = DEFAULT_BACKLOG;
00206     PRThreadScope thread_scope = PR_LOCAL_THREAD;
00207 
00208        PLOptState *opt = PL_CreateOptState(argc, argv, "dGb:t:T:R");
00209 
00210     shared = PR_NEWZAP(Shared);
00211 
00212     shared->debug = NULL;
00213     shared->passed = PR_TRUE;
00214     shared->random = PR_TRUE;
00215     shared->status = running;
00216     shared->ml = PR_NewLock();
00217     shared->cv = PR_NewCondVar(shared->ml);
00218 
00219        while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00220     {
00221         if (PL_OPT_BAD == os) continue;
00222         switch (opt->option)
00223         {
00224         case 'd':  /* debug mode */
00225             shared->debug = PR_GetSpecialFD(PR_StandardError);
00226             break;
00227         case 'G':  /* use global threads */
00228             thread_scope = PR_GLOBAL_THREAD;
00229             break;
00230         case 'b':  /* size of listen backlog */
00231             backlog = atoi(opt->value);
00232             break;
00233         case 't':  /* number of threads doing accept */
00234             threads = atoi(opt->value);
00235             break;
00236         case 'T':  /* timeout used for network operations */
00237             timeout = atoi(opt->value);
00238             break;
00239         case 'R':  /* randomize the timeout values */
00240             shared->random = PR_TRUE;
00241             break;
00242         default:
00243             break;
00244         }
00245     }
00246        PL_DestroyOptState(opt);
00247     if (0 == threads) threads = DEFAULT_THREADS;
00248     if (0 == backlog) backlog = DEFAULT_BACKLOG;
00249     if (0 == timeout) timeout = DEFAULT_TIMEOUT;
00250     
00251     PR_STDIO_INIT();
00252     memset(&listenAddr, 0, sizeof(listenAddr));
00253     rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr);
00254     PR_ASSERT(PR_SUCCESS == rv);
00255 
00256     shared->timeout = PR_SecondsToInterval(timeout);
00257 
00258     /* First bind to the socket */
00259     shared->listenSock = PR_NewTCPSocket();
00260     if (shared->listenSock)
00261     {
00262         sockOpt.option = PR_SockOpt_Reuseaddr;
00263         sockOpt.value.reuse_addr = PR_TRUE;
00264         rv = PR_SetSocketOption(shared->listenSock, &sockOpt);
00265         PR_ASSERT(PR_SUCCESS == rv);
00266         rv = PR_Bind(shared->listenSock, &listenAddr);
00267         if (rv != PR_FAILURE)
00268         {
00269             rv = PR_Listen(shared->listenSock, threads + backlog);
00270             if (PR_SUCCESS == rv)
00271             {
00272                 thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*));
00273                 for (index = 0; index < threads; ++index)
00274                 {
00275                     thread[index] = PR_CreateThread(
00276                         PR_USER_THREAD, Accept, shared,
00277                         PR_PRIORITY_NORMAL, thread_scope,
00278                         PR_JOINABLE_THREAD, 0);
00279                     PR_ASSERT(NULL != thread[index]);
00280                 }
00281 
00282                 PR_Lock(shared->ml);
00283                 while (shared->status == running)
00284                     PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT);
00285                 PR_Unlock(shared->ml);
00286                 for (index = 0; index < threads; ++index)
00287                 {
00288                     rv = PR_Interrupt(thread[index]);
00289                     PR_ASSERT(PR_SUCCESS== rv);
00290                     rv = PR_JoinThread(thread[index]);
00291                     PR_ASSERT(PR_SUCCESS== rv);
00292                 }
00293                 PR_DELETE(thread);
00294             }
00295             else
00296             {
00297                 if (shared->debug) PL_PrintError("Listen");
00298                 shared->passed = PR_FALSE;
00299             }
00300         }
00301         else
00302         {
00303             if (shared->debug) PL_PrintError("Bind");
00304             shared->passed = PR_FALSE;
00305         }
00306 
00307         PR_Close(shared->listenSock);
00308     }
00309     else
00310     {
00311         if (shared->debug) PL_PrintError("Create");
00312         shared->passed = PR_FALSE;
00313     }
00314 
00315     PR_DestroyCondVar(shared->cv);
00316     PR_DestroyLock(shared->ml);
00317 
00318     PR_fprintf(
00319         PR_GetSpecialFD(PR_StandardError), "%s\n",
00320         ((shared->passed) ? "PASSED" : "FAILED"));
00321 
00322     exitStatus = (shared->passed) ? 0 : 1;
00323     PR_DELETE(shared);
00324     return exitStatus;
00325 }
00326 
00327 int main(int argc, char **argv)
00328 {
00329     return (PR_VersionCheck(PR_VERSION)) ?
00330         PR_Initialize(Tmoacc, argc, argv, 4) : -1;
00331 }  /* main */
00332 
00333 /* tmoacc */