forktest.c (6692B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /*********************************************************************** 7 ** 8 ** Name: forktest.c 9 ** 10 ** Description: UNIX test for fork functions. 11 ** 12 ** Modification History: 13 ** 15-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. 14 ** The debug mode will print all of the printfs associated with 15 *this test. 16 ** The regress mode will be the default mode. Since the 17 *regress tool limits 18 ** the output to a one line status:PASS or FAIL,all of the printf 19 *statements 20 ** have been handled with an if (debug_mode) statement. 21 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been 22 *updated to 23 ** recognize the return code from tha main program. 24 ** 12-June-97 AGarcic - Revert to return code 0 and 1, remove debug option 25 *(obsolete). 26 ***********************************************************************/ 27 28 /*********************************************************************** 29 ** Includes 30 ***********************************************************************/ 31 /* Used to get the command line option */ 32 #include "plgetopt.h" 33 34 #include "nspr.h" 35 #include <string.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 39 PRIntn failed_already = 0; 40 41 #ifdef XP_UNIX 42 43 # include <sys/types.h> 44 # include <sys/wait.h> 45 # include <unistd.h> 46 # include <errno.h> 47 48 static char* message = "Hello world!"; 49 50 static void ClientThreadFunc(void* arg) { 51 PRNetAddr addr; 52 PRFileDesc* sock = NULL; 53 PRInt32 tmp = (PRInt32)arg; 54 55 /* 56 * Make sure the PR_Accept call will block 57 */ 58 59 printf("Wait one second before connect\n"); 60 fflush(stdout); 61 PR_Sleep(PR_SecondsToInterval(1)); 62 63 addr.inet.family = AF_INET; 64 addr.inet.ip = PR_htonl(INADDR_ANY); 65 addr.inet.port = 0; 66 if ((sock = PR_NewTCPSocket()) == NULL) { 67 fprintf(stderr, "failed to create TCP socket: error code %d\n", 68 PR_GetError()); 69 failed_already = 1; 70 goto finish; 71 } 72 if (PR_Bind(sock, &addr) != PR_SUCCESS) { 73 fprintf(stderr, "PR_Bind failed: error code %d\n", PR_GetError()); 74 failed_already = 1; 75 goto finish; 76 } 77 addr.inet.ip = PR_htonl(INADDR_LOOPBACK); 78 addr.inet.port = PR_htons((PRInt16)tmp); 79 printf("Connecting to port %hu\n", PR_ntohs(addr.inet.port)); 80 fflush(stdout); 81 if (PR_Connect(sock, &addr, PR_SecondsToInterval(5)) != PR_SUCCESS) { 82 fprintf(stderr, "PR_Connect failed: error code %d\n", PR_GetError()); 83 failed_already = 1; 84 goto finish; 85 } 86 printf("Writing message \"%s\"\n", message); 87 fflush(stdout); 88 if (PR_Send(sock, message, strlen(message) + 1, 0, PR_INTERVAL_NO_TIMEOUT) == 89 -1) { 90 fprintf(stderr, "PR_Send failed: error code %d\n", PR_GetError()); 91 failed_already = 1; 92 goto finish; 93 } 94 finish: 95 if (sock) { 96 PR_Close(sock); 97 } 98 return; 99 } 100 101 /* 102 * DoIO -- 103 * This function creates a thread that acts as a client and itself. 104 * acts as a server. Then it joins the client thread. 105 */ 106 static void DoIO(void) { 107 PRThread* clientThread; 108 PRFileDesc* listenSock = NULL; 109 PRFileDesc* sock = NULL; 110 PRNetAddr addr; 111 PRInt32 nBytes; 112 char buf[128]; 113 114 listenSock = PR_NewTCPSocket(); 115 if (!listenSock) { 116 fprintf(stderr, "failed to create a TCP socket: error code %d\n", 117 PR_GetError()); 118 failed_already = 1; 119 goto finish; 120 } 121 addr.inet.family = AF_INET; 122 addr.inet.ip = PR_htonl(INADDR_ANY); 123 addr.inet.port = 0; 124 if (PR_Bind(listenSock, &addr) == PR_FAILURE) { 125 fprintf(stderr, "failed to bind socket: error code %d\n", PR_GetError()); 126 failed_already = 1; 127 goto finish; 128 } 129 if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { 130 fprintf(stderr, "failed to get socket port number: error code %d\n", 131 PR_GetError()); 132 failed_already = 1; 133 goto finish; 134 } 135 if (PR_Listen(listenSock, 5) == PR_FAILURE) { 136 fprintf(stderr, "PR_Listen failed: error code %d\n", PR_GetError()); 137 failed_already = 1; 138 goto finish; 139 } 140 clientThread = PR_CreateThread( 141 PR_USER_THREAD, ClientThreadFunc, (void*)PR_ntohs(addr.inet.port), 142 PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); 143 if (clientThread == NULL) { 144 fprintf(stderr, "Cannot create client thread: (%d, %d)\n", PR_GetError(), 145 PR_GetOSError()); 146 failed_already = 1; 147 goto finish; 148 } 149 printf("Accepting connection at port %hu\n", PR_ntohs(addr.inet.port)); 150 fflush(stdout); 151 sock = PR_Accept(listenSock, &addr, PR_SecondsToInterval(5)); 152 if (!sock) { 153 fprintf(stderr, "PR_Accept failed: error code %d\n", PR_GetError()); 154 failed_already = 1; 155 goto finish; 156 } 157 nBytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); 158 if (nBytes == -1) { 159 fprintf(stderr, "PR_Recv failed: error code %d\n", PR_GetError()); 160 failed_already = 1; 161 goto finish; 162 } 163 164 /* 165 * Make sure it has proper null byte to mark end of string 166 */ 167 168 buf[sizeof(buf) - 1] = '\0'; 169 printf("Received \"%s\" from the client\n", buf); 170 fflush(stdout); 171 if (!strcmp(buf, message)) { 172 PR_JoinThread(clientThread); 173 174 printf("The message is received correctly\n"); 175 fflush(stdout); 176 } else { 177 fprintf(stderr, "The message should be \"%s\"\n", message); 178 failed_already = 1; 179 } 180 181 finish: 182 if (listenSock) { 183 PR_Close(listenSock); 184 } 185 if (sock) { 186 PR_Close(sock); 187 } 188 return; 189 } 190 191 int main(int argc, char** argv) { 192 pid_t pid; 193 194 /* main test program */ 195 196 DoIO(); 197 198 pid = fork(); 199 200 if (pid == (pid_t)-1) { 201 fprintf(stderr, "Fork failed: errno %d\n", errno); 202 failed_already = 1; 203 return 1; 204 } else if (pid > 0) { 205 int childStatus; 206 207 printf("Fork succeeded. Parent process continues.\n"); 208 DoIO(); 209 if (waitpid(pid, &childStatus, 0) != pid) { 210 { 211 fprintf(stderr, "waitpid failed: %d\n", errno); 212 failed_already = 1; 213 } 214 } else if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) != 0) { 215 failed_already = 1; 216 } 217 printf("Parent process exits.\n"); 218 if (!failed_already) { 219 printf("PASSED\n"); 220 } else { 221 printf("FAILED\n"); 222 } 223 return failed_already; 224 } else { 225 printf("Fork succeeded. Child process continues.\n"); 226 DoIO(); 227 printf("Child process exits.\n"); 228 return failed_already; 229 } 230 } 231 232 #else /* XP_UNIX */ 233 234 int main(int argc, char* argv[]) { 235 printf("The fork test is applicable to Unix only.\n"); 236 return 0; 237 } 238 239 #endif /* XP_UNIX */