home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / forktest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  8.6 KB  |  313 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: forktest.c
  22. **
  23. ** Description: UNIX test for fork functions.
  24. **
  25. ** Modification History:
  26. ** 15-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. ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
  32. **                        recognize the return code from tha main program.
  33. ** 12-June-97 AGarcic - Revert to return code 0 and 1, remove debug option (obsolete).
  34. ***********************************************************************/
  35.  
  36. /***********************************************************************
  37. ** Includes
  38. ***********************************************************************/
  39. /* Used to get the command line option */
  40. #include "plgetopt.h"
  41.  
  42. #include "nspr.h"
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45.  
  46. PRIntn failed_already=0;
  47.  
  48. #ifdef XP_UNIX
  49.  
  50. #include <sys/types.h>
  51. #include <sys/wait.h>
  52. #include <unistd.h>
  53. #include <errno.h>
  54.  
  55. static char *message = "Hello world!";
  56.  
  57. static void
  58. ClientThreadFunc(void *arg)
  59. {
  60.     PRNetAddr addr;
  61.     PRFileDesc *sock = NULL;
  62.     PRInt32 tmp = (PRInt32)arg;
  63.  
  64.     /*
  65.      * Make sure the PR_Accept call will block
  66.      */
  67.  
  68.     printf("Wait one second before connect\n");
  69.     fflush(stdout);
  70.     PR_Sleep(PR_SecondsToInterval(1));
  71.  
  72.     addr.inet.family = AF_INET;
  73.     addr.inet.ip = PR_htonl(INADDR_ANY);
  74.     addr.inet.port = 0;
  75.     if ((sock = PR_NewTCPSocket()) == NULL) {
  76.         fprintf(stderr, "failed to create TCP socket: error code %d\n",
  77.             PR_GetError());
  78.         failed_already = 1;
  79.         goto finish;
  80.     }
  81.     if (PR_Bind(sock, &addr) != PR_SUCCESS) {
  82.         fprintf(stderr, "PR_Bind failed: error code %d\n",
  83.             PR_GetError());
  84.         failed_already = 1;
  85.         goto finish;
  86.     }
  87.     addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
  88.     addr.inet.port = PR_htons((PRInt16)tmp);
  89.     printf("Connecting to port %hu\n", PR_ntohs(addr.inet.port));
  90.     fflush(stdout);
  91.     if (PR_Connect(sock, &addr, PR_SecondsToInterval(5)) !=
  92.         PR_SUCCESS) {
  93.         fprintf(stderr, "PR_Connect failed: error code %d\n",
  94.             PR_GetError());
  95.         failed_already = 1;
  96.         goto finish;
  97.     }
  98.     printf("Writing message \"%s\"\n", message);
  99.     fflush(stdout);
  100.     if (PR_Send(sock, message, strlen(message) + 1, 0, PR_INTERVAL_NO_TIMEOUT) ==
  101.         -1) {
  102.         fprintf(stderr, "PR_Send failed: error code %d\n",
  103.             PR_GetError());
  104.         failed_already = 1;
  105.         goto finish;
  106.     }
  107. finish:
  108.     if (sock) {
  109.         PR_Close(sock);
  110.     }
  111.     return;
  112. }
  113.  
  114. /*
  115.  * DoIO --
  116.  *     This function creates a thread that acts as a client and itself.
  117.  *     acts as a server.  Then it joins the client thread.
  118.  */
  119. static void
  120. DoIO(void)
  121. {
  122.     PRThread *clientThread;
  123.     PRFileDesc *listenSock = NULL;
  124.     PRFileDesc *sock = NULL;
  125.     PRNetAddr addr;
  126.     PRInt32 nBytes;
  127.     char buf[128];
  128.  
  129.     listenSock = PR_NewTCPSocket();
  130.     if (!listenSock) {
  131.         fprintf(stderr, "failed to create a TCP socket: error code %d\n",
  132.             PR_GetError());
  133.         failed_already = 1;
  134.         goto finish;
  135.     }
  136.     addr.inet.family = AF_INET;
  137.     addr.inet.ip = PR_htonl(INADDR_ANY);
  138.     addr.inet.port = 0;
  139.     if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
  140.         fprintf(stderr, "failed to bind socket: error code %d\n",
  141.             PR_GetError());
  142.         failed_already = 1;
  143.         goto finish;
  144.     }
  145.     if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
  146.         fprintf(stderr, "failed to get socket port number: error code %d\n",
  147.             PR_GetError());
  148.         failed_already = 1;
  149.         goto finish;
  150.     }
  151.     if (PR_Listen(listenSock, 5) == PR_FAILURE) {
  152.         fprintf(stderr, "PR_Listen failed: error code %d\n",
  153.             PR_GetError());
  154.         failed_already = 1;
  155.         goto finish;
  156.     }
  157.     clientThread = PR_CreateThread( PR_USER_THREAD, ClientThreadFunc,
  158.         (void *) PR_ntohs(addr.inet.port), PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
  159.         PR_JOINABLE_THREAD, 0);
  160.     if (clientThread == NULL) {
  161.         fprintf(stderr, "Cannot create client thread: (%d, %d)\n",
  162.             PR_GetError(), PR_GetOSError());
  163.         failed_already = 1;
  164.         goto finish;
  165.     }
  166.     printf("Accepting connection at port %hu\n", PR_ntohs(addr.inet.port));
  167.     fflush(stdout);
  168.     sock = PR_Accept(listenSock, &addr, PR_SecondsToInterval(5));
  169.     if (!sock) {
  170.         fprintf(stderr, "PR_Accept failed: error code %d\n",
  171.             PR_GetError());
  172.         failed_already = 1;
  173.         goto finish;
  174.     }
  175.     nBytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
  176.     if (nBytes == -1) {
  177.         fprintf(stderr, "PR_Recv failed: error code %d\n",
  178.             PR_GetError());
  179.         failed_already = 1;
  180.         goto finish;
  181.     }
  182.  
  183.     /*
  184.      * Make sure it has proper null byte to mark end of string 
  185.      */
  186.  
  187.     buf[sizeof(buf) - 1] = '\0';
  188.     printf("Received \"%s\" from the client\n", buf);
  189.     fflush(stdout);
  190.     if (!strcmp(buf, message)) {
  191.         PR_JoinThread(clientThread);
  192.  
  193.         printf("The message is received correctly\n");
  194.         fflush(stdout);
  195.     } else {
  196.         fprintf(stderr, "The message should be \"%s\"\n",
  197.             message);
  198.         failed_already = 1;
  199.     }
  200.  
  201. finish:
  202.     if (listenSock) {
  203.         PR_Close(listenSock);
  204.     }
  205.     if (sock) {
  206.         PR_Close(sock);
  207.     }
  208.     return;
  209. }
  210.  
  211. #ifdef _PR_DCETHREADS
  212.  
  213. #include <syscall.h>
  214.  
  215. pid_t PR_UnixFork1(void)
  216. {
  217.     pid_t parent = getpid();
  218.     int rv = syscall(SYS_fork);
  219.  
  220.     if (rv == -1) {
  221.         return (pid_t) -1;
  222.     } else {
  223.         /* For each process, rv is the pid of the other process */
  224.         if (rv == parent) {
  225.             /* the child */
  226.             return 0;
  227.         } else {
  228.             /* the parent */
  229.             return rv;
  230.         }
  231.     }
  232. }
  233.  
  234. #elif defined(SOLARIS)
  235.  
  236. /*
  237.  * It seems like that in Solaris 2.4 one must call fork1() if the
  238.  * the child process is going to use thread functions.  Solaris 2.5
  239.  * doesn't have this problem. Calling fork() also works. 
  240.  */
  241.  
  242. pid_t PR_UnixFork1(void)
  243. {
  244.     return fork1();
  245. }
  246.  
  247. #else
  248.  
  249. pid_t PR_UnixFork1(void)
  250. {
  251.     return fork();
  252. }
  253.  
  254. #endif  /* PR_DCETHREADS */
  255.  
  256. int main(
  257. int     argc,
  258. char   *argv[]
  259. )
  260. {
  261.     pid_t pid;
  262.  
  263.     /* main test program */
  264.  
  265.     DoIO();
  266.  
  267.     pid = PR_UnixFork1();
  268.  
  269.     if (pid  == (pid_t) -1) {
  270.         fprintf(stderr, "Fork failed: errno %d\n", errno);
  271.         failed_already=1;
  272.         return 1;
  273.     } else if (pid > 0) {
  274.         int childStatus;
  275.  
  276.         printf("Fork succeeded.  Parent process continues.\n");
  277.         DoIO();
  278.         if (waitpid(pid, &childStatus, 0) != pid) {
  279.             fprintf(stderr, "waitpid failed: %d\n", errno);
  280.             failed_already = 1;
  281.         } else if (!WIFEXITED(childStatus)
  282.                 || WEXITSTATUS(childStatus) != 0) {
  283.             failed_already = 1;
  284.         }
  285.         printf("Parent process exits.\n");
  286.         if (!failed_already) {
  287.             printf("PASSED\n");
  288.         } else {
  289.             printf("FAILED\n");
  290.         }
  291.         return failed_already;
  292.     } else {
  293.         printf("Fork succeeded.  Child process continues.\n");
  294.         DoIO();
  295.         printf("Child process exits.\n");
  296.         return failed_already;
  297.     }
  298. }
  299.  
  300. #else  /* XP_UNIX */
  301.  
  302. int main(    int     argc,
  303. char   *argv[]
  304. )
  305. {
  306.  
  307.     printf("The fork test is applicable to Unix only.\n");
  308.     return 0;
  309.  
  310. }
  311.  
  312. #endif  /* XP_UNIX */
  313.