forktest.c 7.2 KB

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