home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / tmoacc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  10.1 KB  |  310 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "nspr.h"
  20.  
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. #include "plerror.h"
  25. #include "plgetopt.h"
  26.  
  27. #ifdef XP_MAC
  28. #include "prlog.h"
  29. #define printf PR_LogPrint
  30. #endif
  31.  
  32. #define BASE_PORT 9867
  33. #define DEFAULT_THREADS 1
  34. #define DEFAULT_BACKLOG 10
  35. #define DEFAULT_TIMEOUT 10
  36. #define RANDOM_RANGE 100  /* should be significantly smaller than RAND_MAX */
  37.  
  38. typedef enum {running, stopped} Status;
  39.  
  40. typedef struct Shared
  41. {
  42.     PRLock *ml;
  43.     PRCondVar *cv;
  44.     PRBool passed;
  45.     PRBool random;
  46.     PRFileDesc *debug;
  47.     PRIntervalTime timeout;
  48.     PRFileDesc *listenSock;
  49.     Status status;
  50. } Shared;
  51.  
  52. static PRIntervalTime Timeout(const Shared *shared)
  53. {
  54.     PRIntervalTime timeout = shared->timeout;
  55.     if (shared->random)
  56.     {
  57.         PRIntervalTime half = timeout >> 1;  /* one half of the interval */
  58.         PRIntervalTime quarter = half >> 1;  /* one quarter of the interval */
  59.         /* something in [0..timeout / 2) */
  60.         PRUint32 random = (rand() % RANDOM_RANGE) * half / RANDOM_RANGE;
  61.         timeout = (3 * quarter) + random;  /* [75..125)% */
  62.     }
  63.     return timeout;
  64. }  /* Timeout */
  65.  
  66. static void Accept(void *arg)
  67. {
  68.     PRStatus rv;
  69.     char *buffer = NULL;
  70.     PRNetAddr clientAddr;
  71.     Shared *shared = (Shared*)arg;
  72.     PRInt32 recv_length = 0, flags = 0;
  73.     PRFileDesc *clientSock;
  74.     PRIntn toread, byte, bytes, loop = 0;
  75.     struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor;
  76.  
  77.     do
  78.     {
  79.         PRUint32 checksum = 0;
  80.         if (NULL != shared->debug)
  81.             PR_fprintf(shared->debug, "[%d]accepting ... ", loop++);
  82.         clientSock = PR_Accept(
  83.             shared->listenSock, &clientAddr, Timeout(shared));
  84.         if (clientSock != NULL)
  85.         {
  86.             if (NULL != shared->debug)
  87.                 PR_fprintf(shared->debug, "reading length ... ");
  88.             bytes = PR_Recv(
  89.                 clientSock, &descriptor, sizeof(descriptor),
  90.                 flags, Timeout(shared));
  91.             if (sizeof(descriptor) == bytes)
  92.             {
  93.                 /* and, before doing something stupid ... */
  94.                 descriptor.length = PR_ntohl(descriptor.length);
  95.                 descriptor.checksum = PR_ntohl(descriptor.checksum);
  96.                 if (NULL != shared->debug)
  97.                     PR_fprintf(shared->debug, "%d bytes ... ", descriptor.length);
  98.                 toread = descriptor.length;
  99.                 if (recv_length < descriptor.length)
  100.                 {
  101.                     if (NULL != buffer) PR_DELETE(buffer);
  102.                     buffer = (char*)PR_MALLOC(descriptor.length);
  103.                     recv_length = descriptor.length;
  104.                 }
  105.                 for (toread = descriptor.length; toread > 0; toread -= bytes)
  106.                 {
  107.                     bytes = PR_Recv(
  108.                         clientSock, &buffer[descriptor.length - toread],
  109.                         toread, flags, Timeout(shared));
  110.                     if (-1 == bytes)
  111.                     {
  112.                         if (NULL != shared->debug)
  113.                             PR_fprintf(shared->debug, "read data failed...");
  114.                         bytes = 0;
  115.                     }
  116.                 }
  117.             }
  118.             else if (NULL != shared->debug)
  119.             {
  120.                 PR_fprintf(shared->debug, "read desciptor failed...");
  121.                 descriptor.length = -1;
  122.             }
  123.             if (NULL != shared->debug)
  124.                 PR_fprintf(shared->debug, "closing");
  125.             rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
  126.             if ((PR_FAILURE == rv) && (NULL != shared->debug))
  127.             {
  128.                 PR_fprintf(shared->debug, " failed");
  129.                 shared->passed = PR_FALSE;
  130.             }
  131.             rv = PR_Close(clientSock);
  132.             if (PR_FAILURE == rv) if (NULL != shared->debug)
  133.             {
  134.                 PR_fprintf(shared->debug, " failed");
  135.                 shared->passed = PR_FALSE;
  136.             }
  137.             if (descriptor.length > 0)
  138.             {
  139.                 for (byte = 0; byte < descriptor.length; ++byte)
  140.                 {
  141.                     PRUint32 overflow = checksum & 0x80000000;
  142.                     checksum = (checksum << 1);
  143.                     if (0x00000000 != overflow) checksum += 1;
  144.                     checksum += buffer[byte];
  145.                 }
  146.                 if ((descriptor.checksum != checksum) && (NULL != shared->debug))
  147.                 {
  148.                     PR_fprintf(shared->debug, " ... data mismatch");
  149.                     shared->passed = PR_FALSE;
  150.                 }
  151.             }
  152.             else if (0 == descriptor.length)
  153.             {
  154.                 PR_Lock(shared->ml);
  155.                 shared->status = stopped;
  156.                 PR_NotifyCondVar(shared->cv);
  157.                 PR_Unlock(shared->ml);
  158.             }
  159.             if (NULL != shared->debug)
  160.                 PR_fprintf(shared->debug, "\n");
  161.         }
  162.         else
  163.         {
  164.             if (PR_PENDING_INTERRUPT_ERROR != PR_GetError())
  165.             {
  166.                 if (NULL != shared->debug) PL_PrintError("Accept");
  167.                 shared->passed = PR_FALSE;
  168.             }
  169.         }        
  170.     } while (running == shared->status);
  171.     if (NULL != buffer) PR_DELETE(buffer);
  172. }  /* Accept */
  173.  
  174. PRIntn Tmoacc(PRIntn argc, char **argv)
  175. {
  176.     PRStatus rv;
  177.     PRIntn index;
  178.     Shared *shared;
  179.     PLOptStatus os;
  180.     PRThread **thread;
  181.     PRNetAddr listenAddr;
  182.     PRIntn timeout = DEFAULT_TIMEOUT;
  183.     PRIntn threads = DEFAULT_THREADS;
  184.     PRIntn backlog = DEFAULT_BACKLOG;
  185.     PRThreadScope thread_scope = PR_LOCAL_THREAD;
  186.  
  187.     PLOptState *opt = PL_CreateOptState(argc, argv, "dGb:t:T:R");
  188.  
  189. #ifdef _PR_INET6
  190.     PR_SetIPv6Enable(PR_TRUE);
  191. #endif
  192.  
  193.     shared = PR_NEWZAP(Shared);  /* this is leaked */
  194.  
  195.     shared->debug = NULL;
  196.     shared->passed = PR_TRUE;
  197.     shared->random = PR_TRUE;
  198.     shared->status = running;
  199.     shared->ml = PR_NewLock();
  200.     shared->cv = PR_NewCondVar(shared->ml);
  201.  
  202.     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  203.     {
  204.         if (PL_OPT_BAD == os) continue;
  205.         switch (opt->option)
  206.         {
  207.         case 'd':  /* debug mode */
  208.             shared->debug = PR_GetSpecialFD(PR_StandardError);
  209.             break;
  210.         case 'G':  /* use global threads */
  211.             thread_scope = PR_GLOBAL_THREAD;
  212.             break;
  213.         case 'b':  /* size of listen backlog */
  214.             backlog = atoi(opt->value);
  215.             break;
  216.         case 't':  /* number of threads doing accept */
  217.             threads = atoi(opt->value);
  218.             break;
  219.         case 'T':  /* timeout used for network operations */
  220.             timeout = atoi(opt->value);
  221.             break;
  222.         case 'R':  /* randomize the timeout values */
  223.             shared->random = PR_TRUE;
  224.             break;
  225.         default:
  226.             break;
  227.         }
  228.     }
  229.     PL_DestroyOptState(opt);
  230.     if (0 == threads) threads = DEFAULT_THREADS;
  231.     if (0 == backlog) backlog = DEFAULT_BACKLOG;
  232.     if (0 == timeout) timeout = DEFAULT_TIMEOUT;
  233.     
  234.     PR_STDIO_INIT();
  235.     rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr);
  236.     PR_ASSERT(PR_SUCCESS == rv);
  237.  
  238.     shared->timeout = PR_SecondsToInterval(timeout);
  239.  
  240.     /* First bind to the socket */
  241.     shared->listenSock = PR_NewTCPSocket();
  242.     if (shared->listenSock)
  243.     {
  244.         rv = PR_Bind(shared->listenSock, &listenAddr);
  245.         if (rv != PR_FAILURE)
  246.         {
  247.             rv = PR_Listen(shared->listenSock, threads + backlog);
  248.             if (PR_SUCCESS == rv)
  249.             {
  250.                 thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*));
  251.                 for (index = 0; index < threads; ++index)
  252.                 {
  253.                     thread[index] = PR_CreateThread(
  254.                         PR_USER_THREAD, Accept, shared,
  255.                         PR_PRIORITY_NORMAL, thread_scope,
  256.                         PR_JOINABLE_THREAD, 0);
  257.                     PR_ASSERT(NULL != thread[index]);
  258.                 }
  259.  
  260.                 PR_Lock(shared->ml);
  261.                 while (shared->status == running)
  262.                     PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT);
  263.                 PR_Unlock(shared->ml);
  264.                 for (index = 0; index < threads; ++index)
  265.                 {
  266.                     rv = PR_Interrupt(thread[index]);
  267.                     PR_ASSERT(PR_SUCCESS== rv);
  268.                     rv = PR_JoinThread(thread[index]);
  269.                     PR_ASSERT(PR_SUCCESS== rv);
  270.                 }
  271.                 PR_DELETE(thread);
  272.             }
  273.             else
  274.             {
  275.                 if (shared->debug) PL_PrintError("Listen");
  276.                 shared->passed = PR_FALSE;
  277.             }
  278.         }
  279.         else
  280.         {
  281.             if (shared->debug) PL_PrintError("Bind");
  282.             shared->passed = PR_FALSE;
  283.         }
  284.  
  285.         PR_Close(shared->listenSock);
  286.     }
  287.     else
  288.     {
  289.         if (shared->debug) PL_PrintError("Create");
  290.         shared->passed = PR_FALSE;
  291.     }
  292.  
  293.     PR_DestroyCondVar(shared->cv);
  294.     PR_DestroyLock(shared->ml);
  295.  
  296.     PR_fprintf(
  297.         PR_GetSpecialFD(PR_StandardError), "%s\n",
  298.         ((shared->passed) ? "PASSED" : "FAILED"));
  299.  
  300.     return (shared->passed) ? 0 : 1;
  301. }
  302.  
  303. int main(int argc, char **argv)
  304. {
  305.     return (PR_VersionCheck(PR_VERSION)) ?
  306.         PR_Initialize(Tmoacc, argc, argv, 4) : -1;
  307. }  /* main */
  308.  
  309. /* tmoacc */
  310.