Back to index

lightning-sunbird  0.9+nobinonly
forktest.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 /***********************************************************************
00039 **
00040 ** Name: forktest.c
00041 **
00042 ** Description: UNIX test for fork functions.
00043 **
00044 ** Modification History:
00045 ** 15-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
00046 **                 The debug mode will print all of the printfs associated with this test.
00047 **                         The regress mode will be the default mode. Since the regress tool limits
00048 **           the output to a one line status:PASS or FAIL,all of the printf statements
00049 **                         have been handled with an if (debug_mode) statement.
00050 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
00051 **                        recognize the return code from tha main program.
00052 ** 12-June-97 AGarcic - Revert to return code 0 and 1, remove debug option (obsolete).
00053 ***********************************************************************/
00054 
00055 /***********************************************************************
00056 ** Includes
00057 ***********************************************************************/
00058 /* Used to get the command line option */
00059 #include "plgetopt.h"
00060 
00061 #include "nspr.h"
00062 #include <string.h>
00063 #include <stdio.h>
00064 #include <stdlib.h>
00065 
00066 PRIntn failed_already=0;
00067 
00068 #ifdef XP_UNIX
00069 
00070 #include <sys/types.h>
00071 #include <sys/wait.h>
00072 #include <unistd.h>
00073 #include <errno.h>
00074 
00075 static char *message = "Hello world!";
00076 
00077 static void
00078 ClientThreadFunc(void *arg)
00079 {
00080     PRNetAddr addr;
00081     PRFileDesc *sock = NULL;
00082     PRInt32 tmp = (PRInt32)arg;
00083 
00084     /*
00085      * Make sure the PR_Accept call will block
00086      */
00087 
00088     printf("Wait one second before connect\n");
00089     fflush(stdout);
00090     PR_Sleep(PR_SecondsToInterval(1));
00091 
00092     addr.inet.family = AF_INET;
00093     addr.inet.ip = PR_htonl(INADDR_ANY);
00094     addr.inet.port = 0;
00095     if ((sock = PR_NewTCPSocket()) == NULL) {
00096         fprintf(stderr, "failed to create TCP socket: error code %d\n",
00097             PR_GetError());
00098         failed_already = 1;
00099         goto finish;
00100     }
00101     if (PR_Bind(sock, &addr) != PR_SUCCESS) {
00102         fprintf(stderr, "PR_Bind failed: error code %d\n",
00103             PR_GetError());
00104         failed_already = 1;
00105         goto finish;
00106     }
00107     addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
00108     addr.inet.port = PR_htons((PRInt16)tmp);
00109     printf("Connecting to port %hu\n", PR_ntohs(addr.inet.port));
00110     fflush(stdout);
00111     if (PR_Connect(sock, &addr, PR_SecondsToInterval(5)) !=
00112         PR_SUCCESS) {
00113         fprintf(stderr, "PR_Connect failed: error code %d\n",
00114             PR_GetError());
00115         failed_already = 1;
00116         goto finish;
00117     }
00118     printf("Writing message \"%s\"\n", message);
00119     fflush(stdout);
00120     if (PR_Send(sock, message, strlen(message) + 1, 0, PR_INTERVAL_NO_TIMEOUT) ==
00121         -1) {
00122         fprintf(stderr, "PR_Send failed: error code %d\n",
00123             PR_GetError());
00124         failed_already = 1;
00125         goto finish;
00126     }
00127 finish:
00128     if (sock) {
00129         PR_Close(sock);
00130     }
00131     return;
00132 }
00133 
00134 /*
00135  * DoIO --
00136  *     This function creates a thread that acts as a client and itself.
00137  *     acts as a server.  Then it joins the client thread.
00138  */
00139 static void
00140 DoIO(void)
00141 {
00142     PRThread *clientThread;
00143     PRFileDesc *listenSock = NULL;
00144     PRFileDesc *sock = NULL;
00145     PRNetAddr addr;
00146     PRInt32 nBytes;
00147     char buf[128];
00148 
00149     listenSock = PR_NewTCPSocket();
00150     if (!listenSock) {
00151         fprintf(stderr, "failed to create a TCP socket: error code %d\n",
00152             PR_GetError());
00153         failed_already = 1;
00154         goto finish;
00155     }
00156     addr.inet.family = AF_INET;
00157     addr.inet.ip = PR_htonl(INADDR_ANY);
00158     addr.inet.port = 0;
00159     if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
00160         fprintf(stderr, "failed to bind socket: error code %d\n",
00161             PR_GetError());
00162         failed_already = 1;
00163         goto finish;
00164     }
00165     if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
00166         fprintf(stderr, "failed to get socket port number: error code %d\n",
00167             PR_GetError());
00168         failed_already = 1;
00169         goto finish;
00170     }
00171     if (PR_Listen(listenSock, 5) == PR_FAILURE) {
00172         fprintf(stderr, "PR_Listen failed: error code %d\n",
00173             PR_GetError());
00174         failed_already = 1;
00175         goto finish;
00176     }
00177     clientThread = PR_CreateThread( PR_USER_THREAD, ClientThreadFunc,
00178         (void *) PR_ntohs(addr.inet.port), PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
00179         PR_JOINABLE_THREAD, 0);
00180     if (clientThread == NULL) {
00181         fprintf(stderr, "Cannot create client thread: (%d, %d)\n",
00182             PR_GetError(), PR_GetOSError());
00183         failed_already = 1;
00184         goto finish;
00185     }
00186     printf("Accepting connection at port %hu\n", PR_ntohs(addr.inet.port));
00187     fflush(stdout);
00188     sock = PR_Accept(listenSock, &addr, PR_SecondsToInterval(5));
00189     if (!sock) {
00190         fprintf(stderr, "PR_Accept failed: error code %d\n",
00191             PR_GetError());
00192         failed_already = 1;
00193         goto finish;
00194     }
00195     nBytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
00196     if (nBytes == -1) {
00197         fprintf(stderr, "PR_Recv failed: error code %d\n",
00198             PR_GetError());
00199         failed_already = 1;
00200         goto finish;
00201     }
00202 
00203     /*
00204      * Make sure it has proper null byte to mark end of string 
00205      */
00206 
00207     buf[sizeof(buf) - 1] = '\0';
00208     printf("Received \"%s\" from the client\n", buf);
00209     fflush(stdout);
00210     if (!strcmp(buf, message)) {
00211         PR_JoinThread(clientThread);
00212 
00213         printf("The message is received correctly\n");
00214         fflush(stdout);
00215     } else {
00216         fprintf(stderr, "The message should be \"%s\"\n",
00217             message);
00218         failed_already = 1;
00219     }
00220 
00221 finish:
00222     if (listenSock) {
00223         PR_Close(listenSock);
00224     }
00225     if (sock) {
00226         PR_Close(sock);
00227     }
00228     return;
00229 }
00230 
00231 #ifdef _PR_DCETHREADS
00232 
00233 #include <syscall.h>
00234 
00235 pid_t PR_UnixFork1(void)
00236 {
00237     pid_t parent = getpid();
00238     int rv = syscall(SYS_fork);
00239 
00240     if (rv == -1) {
00241         return (pid_t) -1;
00242     } else {
00243         /* For each process, rv is the pid of the other process */
00244         if (rv == parent) {
00245             /* the child */
00246             return 0;
00247         } else {
00248             /* the parent */
00249             return rv;
00250         }
00251     }
00252 }
00253 
00254 #elif defined(SOLARIS)
00255 
00256 /*
00257  * It seems like that in Solaris 2.4 one must call fork1() if the
00258  * the child process is going to use thread functions.  Solaris 2.5
00259  * doesn't have this problem. Calling fork() also works. 
00260  */
00261 
00262 pid_t PR_UnixFork1(void)
00263 {
00264     return fork1();
00265 }
00266 
00267 #else
00268 
00269 pid_t PR_UnixFork1(void)
00270 {
00271     return fork();
00272 }
00273 
00274 #endif  /* PR_DCETHREADS */
00275 
00276 int main(
00277 int     argc,
00278 char   *argv[]
00279 )
00280 {
00281     pid_t pid;
00282        int rv;
00283 
00284     /* main test program */
00285 
00286     DoIO();
00287 
00288     pid = PR_UnixFork1();
00289 
00290     if (pid  == (pid_t) -1) {
00291         fprintf(stderr, "Fork failed: errno %d\n", errno);
00292         failed_already=1;
00293         return 1;
00294     } else if (pid > 0) {
00295         int childStatus;
00296 
00297         printf("Fork succeeded.  Parent process continues.\n");
00298         DoIO();
00299         if ((rv = waitpid(pid, &childStatus, 0)) != pid) {
00300 #if defined(IRIX) && !defined(_PR_PTHREADS)
00301                      /*
00302                       * nspr may handle SIGCLD signal
00303                       */
00304                      if ((rv < 0) && (errno == ECHILD)) {
00305                      } else 
00306 #endif
00307                      {
00308                             fprintf(stderr, "waitpid failed: %d\n", errno);
00309                             failed_already = 1;
00310                      }
00311         } else if (!WIFEXITED(childStatus)
00312                 || WEXITSTATUS(childStatus) != 0) {
00313             failed_already = 1;
00314         }
00315         printf("Parent process exits.\n");
00316         if (!failed_already) {
00317             printf("PASSED\n");
00318         } else {
00319             printf("FAILED\n");
00320         }
00321         return failed_already;
00322     } else {
00323 #if defined(IRIX) && !defined(_PR_PTHREADS)
00324               extern void _PR_IRIX_CHILD_PROCESS(void);
00325               _PR_IRIX_CHILD_PROCESS();
00326 #endif
00327         printf("Fork succeeded.  Child process continues.\n");
00328         DoIO();
00329         printf("Child process exits.\n");
00330         return failed_already;
00331     }
00332 }
00333 
00334 #else  /* XP_UNIX */
00335 
00336 int main(    int     argc,
00337 char   *argv[]
00338 )
00339 {
00340 
00341     printf("The fork test is applicable to Unix only.\n");
00342     return 0;
00343 
00344 }
00345 
00346 #endif  /* XP_UNIX */