home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / tmocon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  14.2 KB  |  440 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. /***********************************************************************
  20. **
  21. ** Name: tmocon.c
  22. **
  23. ** Description: test client socket connection.
  24. **
  25. ** Modification History:
  26. ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  27. **             The debug mode will print all of the printfs associated with this test.
  28. **             The regress mode will be the default mode. Since the regress tool limits
  29. **           the output to a one line status:PASS or FAIL,all of the printf statements
  30. **             have been handled with an if (debug_mode) statement. 
  31. ***********************************************************************/
  32.  
  33. /***********************************************************************
  34. ** Includes
  35. ***********************************************************************/
  36. /* Used to get the command line option */
  37. #include "plgetopt.h"
  38.  
  39. #include "nspr.h"
  40. #include "pprio.h"
  41.  
  42. #include "plerror.h"
  43. #include "plgetopt.h"
  44.  
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48.  
  49. /* for getcwd */
  50. #if defined(XP_UNIX)
  51. #include <unistd.h>
  52. #elif defined(XP_PC)
  53. #include <direct.h>
  54. #endif
  55.  
  56. #ifdef XP_MAC
  57. #include "prlog.h"
  58. #define printf PR_LogPrint
  59. #endif
  60.  
  61.  
  62. #define BASE_PORT 9867
  63.  
  64. #define DEFAULT_DALLY 1
  65. #define DEFAULT_THREADS 1
  66. #define DEFAULT_TIMEOUT 10
  67. #define DEFAULT_MESSAGES 100
  68. #define DEFAULT_MESSAGESIZE 100
  69.  
  70. static PRFileDesc *debug_out = NULL;
  71.  
  72. typedef struct Shared
  73. {
  74.     PRBool random;
  75.     PRBool failed;
  76.     PRBool intermittant;
  77.     PRIntn debug;
  78.     PRInt32 messages;
  79.     PRIntervalTime dally;
  80.     PRIntervalTime timeout;
  81.     PRInt32 message_length;
  82.     PRNetAddr serverAddress;
  83. } Shared;
  84.  
  85. static PRIntervalTime Timeout(const Shared *shared)
  86. {
  87.     PRIntervalTime timeout = shared->timeout;
  88.     if (shared->random)
  89.     {
  90.         PRIntervalTime quarter = timeout >> 2;  /* one quarter of the interval */
  91.         PRUint32 random = rand() % quarter;  /* something in[0..timeout / 4) */
  92.         timeout = (((3 * quarter) + random) >> 2) + quarter;  /* [75..125)% */
  93.     }
  94.     return timeout;
  95. }  /* Timeout */
  96.  
  97. static void CauseTimeout(const Shared *shared)
  98. {
  99.     if (shared->intermittant) PR_Sleep(Timeout(shared));
  100. }  /* CauseTimeout */
  101.  
  102. static PRStatus MakeReceiver(Shared *shared)
  103. {
  104.     PRStatus rv = PR_FAILURE;
  105. #if defined(_PR_INET6)
  106.     if (IN6_IS_ADDR_LOOPBACK(&shared->serverAddress.ipv6.ip))
  107. #else
  108.     if (PR_htonl(INADDR_LOOPBACK) == shared->serverAddress.inet.ip)
  109. #endif
  110.     {
  111.         char *argv[3];
  112.         char path[1024 + sizeof("/tmoacc")];
  113.         (void)getcwd(path, sizeof(path));
  114.         (void)strcat(path, "/tmoacc");
  115. #ifdef XP_PC
  116.         (void)strcat(path, ".exe");
  117. #endif
  118.         argv[0] = path;
  119.         if (shared->debug > 0)
  120.         {
  121.             argv[1] = "-d";
  122.             argv[2] = NULL;
  123.         }
  124.         else argv[1] = NULL;
  125.         if (shared->debug > 1)
  126.             PR_fprintf(debug_out, " creating accept process %s ...", path);
  127.         fflush(stdout);
  128.         rv = PR_CreateProcessDetached(path, argv, NULL, NULL);
  129.         if (PR_SUCCESS == rv)
  130.         {
  131.             if (shared->debug > 1)
  132.                 PR_fprintf(debug_out, " wait 5 seconds");
  133.             if (shared->debug > 1)
  134.                 PR_fprintf(debug_out, " before connecting to accept process ...");
  135.             fflush(stdout);
  136.             PR_Sleep(PR_SecondsToInterval(5));
  137.             return rv;
  138.         }
  139.         shared->failed = PR_TRUE;
  140.         if (shared->debug > 0)
  141.             PL_FPrintError(debug_out, "PR_CreateProcessDetached failed");
  142.     }
  143.     return rv;
  144. }  /* MakeReceiver */
  145.  
  146. static void Connect(void *arg)
  147. {
  148.     PRStatus rv;
  149.     char *buffer = NULL;
  150.     PRFileDesc *clientSock;
  151.     Shared *shared = (Shared*)arg;
  152.     PRInt32 loop, bytes, flags = 0;
  153.     struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor;
  154.     debug_out = (0 == shared->debug) ? NULL : PR_GetSpecialFD(PR_StandardError);
  155.  
  156.     buffer = (char*)PR_MALLOC(shared->message_length);
  157.  
  158.     for (bytes = 0; bytes < shared->message_length; ++bytes)
  159.         buffer[bytes] = (char)bytes;
  160.  
  161.     descriptor.checksum = 0;
  162.     for (bytes = 0; bytes < shared->message_length; ++bytes)
  163.     {
  164.         PRUint32 overflow = descriptor.checksum & 0x80000000;
  165.         descriptor.checksum = (descriptor.checksum << 1);
  166.         if (0x00000000 != overflow) descriptor.checksum += 1;
  167.         descriptor.checksum += buffer[bytes];
  168.     }
  169.     descriptor.checksum = PR_htonl(descriptor.checksum);
  170.  
  171.     for (loop = 0; loop < shared->messages; ++loop)
  172.     {
  173.         if (shared->debug > 1)
  174.             PR_fprintf(debug_out, "[%d]socket ... ", loop);
  175.         clientSock = PR_NewTCPSocket();
  176.         if (clientSock)
  177.         {
  178.             /*
  179.              * We need to slow down the rate of generating connect requests,
  180.              * otherwise the listen backlog queue on the accept side may
  181.              * become full and we will get connection refused or timeout
  182.              * error.
  183.              */
  184.  
  185.             PR_Sleep(shared->dally);
  186.             if (shared->debug > 1) PR_fprintf(debug_out, "connecting ... ");
  187.             rv = PR_Connect(
  188.                 clientSock, &shared->serverAddress, Timeout(shared));
  189.             if (PR_SUCCESS == rv)
  190.             {
  191.                 PRInt32 descriptor_length = (loop < (shared->messages - 1)) ?
  192.                     shared->message_length : 0;
  193.                 descriptor.length = PR_htonl(descriptor_length);
  194.                 if (shared->debug > 1)
  195.                     PR_fprintf(
  196.                         debug_out, "sending %d bytes ... ", descriptor_length);
  197.                 CauseTimeout(shared);  /* might cause server to timeout */
  198.                 bytes = PR_Send(
  199.                     clientSock, &descriptor, sizeof(descriptor),
  200.                     flags, Timeout(shared));
  201.                 if (bytes != sizeof(descriptor))
  202.                 {
  203.                     shared->failed = PR_TRUE;
  204.                     if (shared->debug > 0)
  205.                         PL_FPrintError(debug_out, "PR_Send failed");
  206.                 }
  207.                 if (0 != descriptor_length)
  208.                 {
  209.                     CauseTimeout(shared);
  210.                     bytes = PR_Send(
  211.                         clientSock, buffer, descriptor_length,
  212.                         flags, Timeout(shared));
  213.                     if (bytes != descriptor_length)
  214.                     {
  215.                         shared->failed = PR_TRUE;
  216.                         if (shared->debug > 0)
  217.                             PL_FPrintError(debug_out, "PR_Send failed");
  218.                     }
  219.                 }
  220.                 if (shared->debug > 1) PR_fprintf(debug_out, "closing ... ");
  221.                 rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
  222.                 rv = PR_Close(clientSock);
  223.                 if (shared->debug > 1)
  224.                 {
  225.                     if (PR_SUCCESS == rv) PR_fprintf(debug_out, "\n");
  226.                     else PL_FPrintError(debug_out, "shutdown failed");
  227.                 }
  228.             }
  229.             else
  230.             {
  231.                 if (shared->debug > 1) PL_FPrintError(debug_out, "connect failed");
  232.                 PR_Close(clientSock);
  233.                 if ((loop == 0) && (PR_GetError() == PR_CONNECT_REFUSED_ERROR))
  234.                 {
  235.                     if (MakeReceiver(shared) == PR_FAILURE) break;
  236.                 }
  237.                 else
  238.                 {
  239.                     if (shared->debug > 1) PR_fprintf(debug_out, " exiting\n");
  240.                     break;
  241.                 }
  242.             }
  243.         }
  244.         else
  245.         {
  246.             shared->failed = PR_TRUE;
  247.             if (shared->debug > 0) PL_FPrintError(debug_out, "create socket");
  248.             break;
  249.         }
  250.     }
  251.  
  252.     PR_DELETE(buffer);
  253. }  /* Connect */
  254.  
  255. #ifdef _PR_INET6
  256.  
  257. /*
  258.  * Below are some of the IPv6 hosts at Netscape and their IPv4
  259.  * addresses.  We will use their IPv4-compatible IPv6 addresses
  260.  * for automatic tunneling.
  261.  */
  262.  
  263. static const char *ipv6_host[] = {
  264.     "dijkstra",
  265.     "wirth",
  266.     "gandalf",
  267.     "raven"
  268. };
  269.  
  270. static const unsigned char ipv6_host_ipv4_addr[] = {
  271.     208, 12, 62, 49,
  272.     208, 12, 62, 98,
  273.     208, 12, 62, 55,
  274.     206, 222, 228, 80
  275. };
  276.  
  277. /*
  278.  * Return PR_TRUE if 'host' is an IPv6 host at Netscape in the table
  279.  * above, and fill 'addr->ipv6.ip' with its IPv4-compatible IPv6 address
  280.  * for automatic tunneling.
  281.  */
  282.  
  283. static PRBool
  284. IPv6AutoTunnelHost(const char *host, PRNetAddr *addr)
  285. {
  286.     int nHosts = sizeof(ipv6_host) / sizeof(ipv6_host[0]);
  287.     int i;
  288.  
  289.     for (i = 0; i < nHosts; i++)
  290.     {
  291.         if (strcmp(host, ipv6_host[i]) == 0)
  292.         {
  293.             memset(&addr->ipv6.ip, 0, 12);
  294.             memcpy(((unsigned char *) &addr->ipv6.ip) + 12,
  295.                 &ipv6_host_ipv4_addr[4 * i], 4);
  296.             PR_ASSERT(IN6_IS_ADDR_V4COMPAT(&addr->ipv6.ip));
  297.             return PR_TRUE;
  298.         }
  299.     }
  300.     return PR_FALSE;
  301. }
  302. #endif /* _PR_INET6 */
  303.  
  304. int Tmocon(int argc, char **argv)
  305. {
  306.     /*
  307.      * USAGE
  308.      * -d       turn on debugging output                (default = off)
  309.      * -v       turn on verbose output                  (default = off)
  310.      * -h <n>   dns name of host serving the connection (default = self)
  311.      * -i       dally intermittantly to cause timeouts  (default = off)
  312.      * -m <n>   number of messages to send              (default = 100)
  313.      * -s <n>   size of each message                    (default = 100)
  314.      * -t <n>   number of threads sending               (default = 1)
  315.      * -G       use global threads                      (default = local)
  316.      * -T <n>   timeout on I/O operations (seconds)     (default = 10)
  317.      * -D <n>   dally between connect requests (seconds)(default = 0)
  318.      * -R       randomize the dally types around 'T'    (default = no)
  319.      */
  320.  
  321.     PRStatus rv;
  322.     PLOptStatus os;
  323.     Shared *shared = NULL;
  324.     PRThread **thread = NULL;
  325.     PRIntn index, threads = DEFAULT_THREADS;
  326.     PRThreadScope thread_scope = PR_LOCAL_THREAD;
  327.     PRInt32 dally = DEFAULT_DALLY, timeout = DEFAULT_TIMEOUT;
  328.     PLOptState *opt = PL_CreateOptState(argc, argv, "divGRh:m:s:t:T:D:");
  329.  
  330. #ifdef _PR_INET6
  331.     PR_SetIPv6Enable(PR_TRUE);
  332. #endif
  333.     shared = PR_NEWZAP(Shared);  /* this is leaked */
  334.  
  335.     shared->debug = 0;
  336.     shared->failed = PR_FALSE;
  337.     shared->random = PR_FALSE;
  338.     shared->messages = DEFAULT_MESSAGES;
  339.     shared->message_length = DEFAULT_MESSAGESIZE;
  340.  
  341.     PR_STDIO_INIT();
  342.     rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &shared->serverAddress);
  343.     PR_ASSERT(PR_SUCCESS == rv);
  344.     
  345.     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  346.     {
  347.         if (PL_OPT_BAD == os) continue;
  348.         switch (opt->option)
  349.         {
  350.         case 'd':
  351.             if (0 == shared->debug) shared->debug = 1;
  352.             break;
  353.         case 'v':
  354.             if (0 == shared->debug) shared->debug = 2;
  355.             break;
  356.         case 'i':
  357.             shared->intermittant = PR_TRUE;
  358.             break;
  359.         case 'R':
  360.             shared->random = PR_TRUE;
  361.             break;
  362.         case 'G':
  363.             thread_scope = PR_GLOBAL_THREAD;
  364.             break;
  365.         case 'h':  /* the value for backlock */
  366.             {
  367. #ifdef _PR_INET6
  368.                 if (!IPv6AutoTunnelHost(opt->value, &shared->serverAddress))
  369.                 {
  370. #endif
  371.                     PRIntn es = 0;
  372.                     PRHostEnt host;
  373.                     char buffer[1024];
  374.                     (void)PR_GetHostByName(
  375.                         opt->value, buffer, sizeof(buffer), &host);
  376.                     es = PR_EnumerateHostEnt(
  377.                         es, &host, BASE_PORT, &shared->serverAddress);
  378.                     PR_ASSERT(es > 0);
  379. #ifdef _PR_INET6
  380.                 }
  381. #endif
  382.             }
  383.             break;
  384.         case 'm':  /* number of messages to send */
  385.             shared->messages = atoi(opt->value);
  386.             break;
  387.         case 't':  /* number of threads sending */
  388.             threads = atoi(opt->value);
  389.             break;
  390.         case 'D':  /* dally time between transmissions */
  391.             dally = atoi(opt->value);
  392.             break;
  393.         case 'T':  /* timeout on I/O operations */
  394.             timeout = atoi(opt->value);
  395.             break;
  396.         case 's':  /* total size of each message */
  397.             shared->message_length = atoi(opt->value);
  398.             break;
  399.         default:
  400.             break;
  401.         }
  402.     }
  403.         PL_DestroyOptState(opt);
  404.  
  405.     if (0 == timeout) timeout = DEFAULT_TIMEOUT;
  406.     if (0 == threads) threads = DEFAULT_THREADS;
  407.     if (0 == shared->messages) shared->messages = DEFAULT_MESSAGES;
  408.     if (0 == shared->message_length) shared->message_length = DEFAULT_MESSAGESIZE;
  409.  
  410.     shared->dally = PR_SecondsToInterval(dally);
  411.     shared->timeout = PR_SecondsToInterval(timeout);
  412.  
  413.     thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*));
  414.  
  415.     for (index = 0; index < threads; ++index)
  416.         thread[index] = PR_CreateThread(
  417.             PR_USER_THREAD, Connect, shared,
  418.             PR_PRIORITY_NORMAL, thread_scope,
  419.             PR_JOINABLE_THREAD, 0);
  420.     for (index = 0; index < threads; ++index)
  421.         rv = PR_JoinThread(thread[index]);
  422.  
  423.     PR_DELETE(thread);
  424.  
  425.     PR_fprintf(
  426.         PR_GetSpecialFD(PR_StandardError), "%s\n",
  427.         ((shared->failed) ? "FAILED" : "PASSED"));
  428.     return (shared->failed) ? 0 : 1;
  429. }
  430.  
  431. int main(int argc, char **argv)
  432. {
  433.     return (PR_VersionCheck(PR_VERSION)) ?
  434.         PR_Initialize(Tmocon, argc, argv, 4) : -1;
  435. }  /* main */
  436.  
  437. /* tmocon.c */
  438.  
  439.  
  440.