home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / servr_uu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  16.6 KB  |  565 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. ** This server simulates a server running in loopback mode.
  22. **
  23. ** The idea is that a single server is created.  The server initially creates
  24. ** a number of worker threads.  Then, with the server running, a number of 
  25. ** clients are created which start requesting service from the server.
  26. **
  27. **
  28. ** Modification History:
  29. ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  30. **             The debug mode will print all of the printfs associated with this test.
  31. **             The regress mode will be the default mode. Since the regress tool limits
  32. **           the output to a one line status:PASS or FAIL,all of the printf statements
  33. **             have been handled with an if (debug_mode) statement.
  34. ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
  35. **            recognize the return code from tha main program.
  36. ***********************************************************************/
  37.  
  38. /***********************************************************************
  39. ** Includes
  40. ***********************************************************************/
  41. /* Used to get the command line option */
  42. #include "plgetopt.h"
  43.  
  44. #include "nspr.h"
  45. #include "pprthred.h"
  46.  
  47. #include <string.h>
  48.  
  49. #define PORT 15004
  50. #define STACKSIZE 0
  51.  
  52. static int _iterations = 1000;
  53. static int _clients = 1;
  54. static int _client_data = 250;
  55. static int _server_data = (8*1024);
  56.  
  57. static PRThreadScope ServerScope, ClientScope;
  58.  
  59. #define SERVER "Server"
  60. #define MAIN   "Main"
  61.  
  62. #define SERVER_STATE_STARTUP 0
  63. #define SERVER_STATE_READY   1
  64. #define SERVER_STATE_DYING   2
  65. #define SERVER_STATE_DEAD    4
  66. int       ServerState;
  67. PRLock    *ServerStateCVLock;
  68. PRCondVar *ServerStateCV;
  69.  
  70. #undef DEBUGPRINTS
  71. #ifdef DEBUGPRINTS
  72. #define DPRINTF printf
  73. #else
  74. #define DPRINTF
  75. #endif
  76.  
  77. PRIntn failed_already=0;
  78. PRIntn debug_mode;
  79.  
  80. static void do_work(void);
  81.  
  82. /* --- Server state functions --------------------------------------------- */
  83. void
  84. SetServerState(char *waiter, PRInt32 state)
  85. {
  86.     PR_Lock(ServerStateCVLock);
  87.     ServerState = state;
  88.     PR_NotifyCondVar(ServerStateCV);
  89.  
  90.     if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state);
  91.  
  92.     PR_Unlock(ServerStateCVLock);
  93. }
  94.  
  95. int
  96. WaitServerState(char *waiter, PRInt32 state)
  97. {
  98.     PRInt32 rv;
  99.  
  100.     PR_Lock(ServerStateCVLock);
  101.  
  102.     if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state);
  103.  
  104.     while(!(ServerState & state))
  105.         PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT);
  106.     rv = ServerState;
  107.  
  108.     if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", 
  109.         waiter, state, ServerState);
  110.     PR_Unlock(ServerStateCVLock);
  111.  
  112.     return rv;
  113. }
  114.  
  115. /* --- Server Functions ------------------------------------------- */
  116.  
  117. PRLock *workerThreadsLock;
  118. PRInt32 workerThreads;
  119. PRInt32 workerThreadsBusy;
  120.  
  121. void
  122. WorkerThreadFunc(void *_listenSock)
  123. {
  124.     PRFileDesc *listenSock = (PRFileDesc *)_listenSock;
  125.     PRInt32 bytesRead;
  126.     PRInt32 bytesWritten;
  127.     char *dataBuf;
  128.     char *sendBuf;
  129.  
  130.     if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n",
  131.             _client_data+(4*sizeof(PRNetAddr)), _client_data, (4*sizeof(PRNetAddr)));
  132.     dataBuf = (char *)PR_MALLOC(_client_data *sizeof(char) + 4*sizeof(PRNetAddr));
  133.     if (!dataBuf)
  134.         if (debug_mode) printf("\tServer could not malloc space!?\n");
  135.     sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char));
  136.     if (!sendBuf)
  137.         if (debug_mode) printf("\tServer could not malloc space!?\n");
  138.  
  139.     if (debug_mode) DPRINTF("\tServer worker thread running\n");
  140.  
  141.     while(1) {
  142.         PRInt32 bytesToRead = _client_data;
  143.         PRInt32 bytesToWrite = _server_data;
  144.         PRFileDesc *newSock;
  145.         PRNetAddr *rAddr;
  146.         PRInt32 loops = 0;
  147.  
  148.         loops++;
  149.  
  150.         if (debug_mode) DPRINTF("\tServer thread going into accept\n");
  151.  
  152.         bytesRead = PR_AcceptRead(listenSock, 
  153.                                   &newSock,
  154.                                   &rAddr,
  155.                                   dataBuf,
  156.                                   bytesToRead,
  157.                                   PR_INTERVAL_NO_TIMEOUT);
  158.  
  159.         if (bytesRead < 0) {
  160.             if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead);
  161.             continue;
  162.         }
  163.  
  164.         if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead);
  165.         
  166.         PR_AtomicIncrement(&workerThreadsBusy);
  167.         if (workerThreadsBusy == workerThreads) {
  168.  
  169.             PR_Lock(workerThreadsLock);
  170.             if (workerThreadsBusy == workerThreads) {
  171.                 PRThread *WorkerThread;
  172.  
  173.                 WorkerThread = PR_CreateThread(
  174.                                   PR_SYSTEM_THREAD,
  175.                                   WorkerThreadFunc,
  176.                                   listenSock,
  177.                                   PR_PRIORITY_NORMAL,
  178.                                   ServerScope,
  179.                                   PR_UNJOINABLE_THREAD,
  180.                                   STACKSIZE);
  181.  
  182.                 if (!WorkerThread)
  183.                     if (debug_mode) printf("Error creating client thread %d\n", workerThreads);
  184.                 else {
  185.                     PR_AtomicIncrement(&workerThreads);
  186.                     if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads);
  187.                 }
  188.             }
  189.             PR_Unlock(workerThreadsLock);
  190.         }
  191.  
  192.         bytesToRead -= bytesRead;
  193.         while (bytesToRead) {
  194.             bytesRead = PR_Recv(newSock, 
  195.                                 dataBuf, 
  196.                                 bytesToRead, 
  197.                                 0, 
  198.                                 PR_INTERVAL_NO_TIMEOUT);
  199.             if (bytesRead < 0) {
  200.                 if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead);
  201.                 continue;
  202.             }
  203.             if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead);
  204.         }
  205.  
  206.         bytesWritten = PR_Send(newSock,
  207.                                sendBuf, 
  208.                                bytesToWrite, 
  209.                                0, 
  210.                                PR_INTERVAL_NO_TIMEOUT);
  211.         if (bytesWritten != _server_data)
  212.             if (debug_mode) printf("\tError sending data to client (%d, %d)\n", 
  213.                 bytesWritten, PR_GetOSError());
  214.         else
  215.             if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten);
  216.  
  217.         PR_Close(newSock);
  218.         PR_AtomicDecrement(&workerThreadsBusy);
  219.     }
  220. }
  221.  
  222. PRFileDesc *
  223. ServerSetup(void)
  224. {
  225.     PRFileDesc *listenSocket;
  226.     PRNetAddr serverAddr;
  227.     PRThread *WorkerThread;
  228.  
  229.     if ( (listenSocket = PR_NewTCPSocket()) == NULL) {
  230.         if (debug_mode) printf("\tServer error creating listen socket\n");
  231.         else failed_already=1;
  232.         return NULL;
  233.     }
  234.  
  235.     memset(&serverAddr, 0, sizeof(PRNetAddr));
  236.     serverAddr.inet.family = AF_INET;
  237.     serverAddr.inet.port = PR_htons(PORT);
  238.     serverAddr.inet.ip = PR_htonl(INADDR_ANY);
  239.  
  240.     if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) {
  241.         if (debug_mode) printf("\tServer error binding to server address: OS error %d\n",
  242.                 PR_GetOSError());
  243.         else failed_already=1;
  244.         PR_Close(listenSocket);
  245.         return NULL;
  246.     }
  247.  
  248.     if ( PR_Listen(listenSocket, 128) == PR_FAILURE) {
  249.         if (debug_mode) printf("\tServer error listening to server socket\n");
  250.         else failed_already=1;
  251.         PR_Close(listenSocket);
  252.  
  253.         return NULL;
  254.     }
  255.  
  256.     /* Create Clients */
  257.     workerThreads = 0;
  258.     workerThreadsBusy = 0;
  259.  
  260.     workerThreadsLock = PR_NewLock();
  261.  
  262.     WorkerThread = PR_CreateThread(
  263.                       PR_SYSTEM_THREAD,
  264.                       WorkerThreadFunc,
  265.                       listenSocket,
  266.                       PR_PRIORITY_NORMAL,
  267.                       ServerScope,
  268.                       PR_UNJOINABLE_THREAD,
  269.                       STACKSIZE);
  270.  
  271.     if (!WorkerThread) {
  272.         if (debug_mode) printf("error creating working thread\n");
  273.         PR_Close(listenSocket);
  274.         return NULL;
  275.     }
  276.     PR_AtomicIncrement(&workerThreads);
  277.     if (debug_mode) DPRINTF("\tServer created primordial worker thread\n");
  278.  
  279.     return listenSocket;
  280. }
  281.  
  282. /* The main server loop */
  283. void
  284. ServerThreadFunc(void *unused)
  285. {
  286.     PRFileDesc *listenSocket;
  287.  
  288.     /* Do setup */
  289.     listenSocket = ServerSetup();
  290.  
  291.     if (!listenSocket) {
  292.         SetServerState(SERVER, SERVER_STATE_DEAD);
  293.     } else {
  294.  
  295.         if (debug_mode) DPRINTF("\tServer up\n");
  296.  
  297.         /* Tell clients they can start now. */
  298.         SetServerState(SERVER, SERVER_STATE_READY);
  299.  
  300.         /* Now wait for server death signal */
  301.         WaitServerState(SERVER, SERVER_STATE_DYING);
  302.  
  303.         /* Cleanup */
  304.         SetServerState(SERVER, SERVER_STATE_DEAD);
  305.     }
  306. }
  307.  
  308. /* --- Client Functions ------------------------------------------- */
  309.  
  310. PRInt32 numRequests;
  311. PRInt32 numClients;
  312. PRMonitor *clientMonitor;
  313.  
  314. void
  315. ClientThreadFunc(void *unused)
  316. {
  317.     PRNetAddr serverAddr;
  318.     PRFileDesc *clientSocket;
  319.     char *sendBuf;
  320.     char *recvBuf;
  321.     PRInt32 rv;
  322.     PRInt32 bytesNeeded;
  323.  
  324.     sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char));
  325.     if (!sendBuf)
  326.         if (debug_mode) printf("\tClient could not malloc space!?\n");
  327.     recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char));
  328.     if (!recvBuf)
  329.         if (debug_mode) printf("\tClient could not malloc space!?\n");
  330.  
  331.     memset(&serverAddr, 0, sizeof(PRNetAddr));
  332.     serverAddr.inet.family = AF_INET;
  333.     serverAddr.inet.port = PR_htons(PORT);
  334.     serverAddr.inet.ip = PR_htonl(INADDR_LOOPBACK);
  335.  
  336.     while(numRequests > 0) {
  337.  
  338.         if ( (numRequests % 10) == 0 )
  339.             if (debug_mode) printf(".");
  340.         if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests);
  341.  
  342.         clientSocket = PR_NewTCPSocket();
  343.         if (!clientSocket) {
  344.             if (debug_mode) printf("Client error creating socket: OS error %d\n",
  345.             PR_GetOSError());
  346.             continue;
  347.         }
  348.  
  349.         if (debug_mode) DPRINTF("\tClient connecting\n");
  350.  
  351.         rv = PR_Connect(clientSocket, 
  352.                         &serverAddr,
  353.                         PR_INTERVAL_NO_TIMEOUT);
  354.         if (!clientSocket) {
  355.             if (debug_mode) printf("\tClient error connecting\n");
  356.             continue;
  357.         }
  358.  
  359.         if (debug_mode) DPRINTF("\tClient connected\n");
  360.  
  361.         rv = PR_Send(clientSocket, 
  362.                      sendBuf, 
  363.                      _client_data, 
  364.                      0, 
  365.                      PR_INTERVAL_NO_TIMEOUT);
  366.         if (rv != _client_data) {
  367.             if (debug_mode) printf("Client error sending data (%d)\n", rv);
  368.             PR_Close(clientSocket);
  369.             continue;
  370.         }
  371.  
  372.         if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv);
  373.  
  374.         bytesNeeded = _server_data;
  375.         while(bytesNeeded) {
  376.             rv = PR_Recv(clientSocket, 
  377.                          recvBuf, 
  378.                          bytesNeeded, 
  379.                          0, 
  380.                          PR_INTERVAL_NO_TIMEOUT);
  381.             if (rv <= 0) {
  382.                 if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", 
  383.                     rv, (_server_data - bytesNeeded), _server_data);
  384.                 break;
  385.             }
  386.             if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv);
  387.             bytesNeeded -= rv;
  388.         }
  389.  
  390.         PR_Close(clientSocket);
  391.  
  392.         PR_AtomicDecrement(&numRequests);
  393.     }
  394.  
  395.     PR_EnterMonitor(clientMonitor);
  396.     --numClients;
  397.     PR_Notify(clientMonitor);
  398.     PR_ExitMonitor(clientMonitor);
  399.  
  400.     PR_DELETE(sendBuf);
  401.     PR_DELETE(recvBuf);
  402. }
  403.  
  404. void
  405. RunClients(void)
  406. {
  407.     PRInt32 index;
  408.  
  409.     numRequests = _iterations;
  410.     numClients = _clients;
  411.     clientMonitor = PR_NewMonitor();
  412.  
  413.     for (index=0; index<_clients; index++) {
  414.         PRThread *clientThread;
  415.  
  416.   
  417.         clientThread = PR_CreateThread(
  418.                           PR_USER_THREAD,
  419.                           ClientThreadFunc,
  420.                           NULL,
  421.                           PR_PRIORITY_NORMAL,
  422.                           ClientScope,
  423.                           PR_UNJOINABLE_THREAD,
  424.                           STACKSIZE);
  425.  
  426.         if (!clientThread) {
  427.             if (debug_mode) printf("\terror creating client thread %d\n", index);
  428.         } else
  429.             if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients);
  430.  
  431.     }
  432.  
  433.     PR_EnterMonitor(clientMonitor);
  434.     while(numClients)
  435.         PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT);
  436.     PR_ExitMonitor(clientMonitor);
  437. }
  438.  
  439. /* --- Main Function ---------------------------------------------- */
  440.  
  441. static
  442. void do_work()
  443. {
  444.     PRThread *ServerThread;
  445.     PRInt32 state;
  446.  
  447.     SetServerState(MAIN, SERVER_STATE_STARTUP);
  448.     ServerThread = PR_CreateThread(
  449.                       PR_USER_THREAD,
  450.                       ServerThreadFunc,
  451.                       NULL,
  452.                       PR_PRIORITY_NORMAL,
  453.                       ServerScope,
  454.                       PR_JOINABLE_THREAD,
  455.                       STACKSIZE);
  456.     if (!ServerThread) {
  457.         if (debug_mode) printf("error creating main server thread\n");
  458.         return;
  459.     }
  460.  
  461.     /* Wait for server to be ready */
  462.     state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD);
  463.  
  464.     if (!(state & SERVER_STATE_DEAD)) {
  465.         /* Run Test Clients */
  466.         RunClients();
  467.  
  468.         /* Send death signal to server */
  469.         SetServerState(MAIN, SERVER_STATE_DYING);
  470.     }
  471.  
  472.     PR_JoinThread(ServerThread);
  473. }
  474.  
  475. static void do_workUU(void)
  476. {
  477.     ServerScope = PR_LOCAL_THREAD;
  478.     ClientScope = PR_LOCAL_THREAD;
  479.     do_work();
  480. }
  481.  
  482.  
  483.  
  484. static void Measure(void (*func)(void), const char *msg)
  485. {
  486.     PRIntervalTime start, stop;
  487.     double d;
  488.  
  489.     start = PR_IntervalNow();
  490.     (*func)();
  491.     stop = PR_IntervalNow();
  492.  
  493.     d = (double)PR_IntervalToMicroseconds(stop - start);
  494.  
  495.     if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations);
  496. }
  497.  
  498.  
  499. main(int argc, char **argv)
  500. {
  501.     /* The command line argument: -d is used to determine if the test is being run
  502.     in debug mode. The regress tool requires only one line output:PASS or FAIL.
  503.     All of the printfs associated with this test has been handled with a if (debug_mode)
  504.     test.
  505.     Usage: test_name -d
  506.     */
  507.     PLOptStatus os;
  508.     PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
  509.     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  510.     {
  511.         if (PL_OPT_BAD == os) continue;
  512.         switch (opt->option)
  513.         {
  514.         case 'd':  /* debug mode */
  515.             debug_mode = 1;
  516.             break;
  517.          default:
  518.             break;
  519.         }
  520.     }
  521.     PL_DestroyOptState(opt);
  522.  
  523.  /* main test */
  524.     if (debug_mode) {
  525.         printf("Enter number of iterations: \n");
  526.         scanf("%d", &_iterations);
  527.         printf("Enter number of clients   : \n");
  528.         scanf("%d", &_clients);
  529.         printf("Enter size of client data : \n");
  530.         scanf("%d", &_client_data);
  531.         printf("Enter size of server data : \n");
  532.         scanf("%d", &_server_data);
  533.     }
  534.     else {
  535.         _iterations = 7;
  536.         _clients = 7;
  537.         _client_data = 100;
  538.         _server_data = 100;
  539.     }
  540.  
  541.     if (debug_mode) {
  542.         printf("\n\n%d iterations with %d client threads.\n", 
  543.         _iterations, _clients);
  544.         printf("Sending %d bytes of client data and %d bytes of server data\n", 
  545.         _client_data, _server_data);
  546.     }
  547.     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
  548.     PR_STDIO_INIT();
  549.  
  550.     PR_SetThreadRecycleMode(64);
  551.  
  552.     ServerStateCVLock = PR_NewLock();
  553.     ServerStateCV = PR_NewCondVar(ServerStateCVLock);
  554.  
  555.     Measure(do_workUU, "server loop user/user");
  556.  
  557.     PR_Cleanup();
  558.     
  559.     if(failed_already)    
  560.         return 1;
  561.     else
  562.         return 0;
  563.     
  564. }
  565.