prselect.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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. ** 1997 - Netscape Communications Corporation
  7. **
  8. ** Name: prselect_err.c
  9. **
  10. ** Description: tests PR_Select with sockets Error condition functions.
  11. **
  12. ** Modification History:
  13. ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  14. ** The debug mode will print all of the printfs associated with this test.
  15. ** The regress mode will be the default mode. Since the regress tool limits
  16. ** the output to a one line status:PASS or FAIL,all of the printf statements
  17. ** have been handled with an if (debug_mode) statement.
  18. ***********************************************************************/
  19. /***********************************************************************
  20. ** Includes
  21. ***********************************************************************/
  22. /* Used to get the command line option */
  23. #include "plgetopt.h"
  24. #include "prttools.h"
  25. #include "prinit.h"
  26. #include "prio.h"
  27. #include "prlog.h"
  28. #include "prprf.h"
  29. #include "prerror.h"
  30. #include "prnetdb.h"
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <stdlib.h>
  34. /***********************************************************************
  35. ** PRIVATE FUNCTION: Test_Result
  36. ** DESCRIPTION: Used in conjunction with the regress tool, prints out the
  37. ** status of the test case.
  38. ** INPUTS: PASS/FAIL
  39. ** OUTPUTS: None
  40. ** RETURN: None
  41. ** SIDE EFFECTS:
  42. **
  43. ** RESTRICTIONS:
  44. ** None
  45. ** MEMORY: NA
  46. ** ALGORITHM: Determine what the status is and print accordingly.
  47. **
  48. ***********************************************************************/
  49. static Test_Result (int result)
  50. {
  51. if (result == PASS) {
  52. printf ("PASS\n");
  53. }
  54. else {
  55. printf ("FAIL\n");
  56. }
  57. }
  58. static void
  59. clientThreadFunc(void *arg)
  60. {
  61. PRUint16 port = (PRUint16) arg;
  62. PRFileDesc *sock;
  63. PRNetAddr addr;
  64. char buf[128];
  65. int i;
  66. addr.inet.family = AF_INET;
  67. addr.inet.port = PR_htons(port);
  68. addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
  69. PR_snprintf(buf, sizeof(buf), "%hu", port);
  70. for (i = 0; i < 5; i++) {
  71. sock = PR_NewTCPSocket();
  72. PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
  73. PR_Write(sock, buf, sizeof(buf));
  74. PR_Close(sock);
  75. }
  76. }
  77. int main(int argc, char **argv)
  78. {
  79. PRFileDesc *listenSock1, *listenSock2;
  80. PRFileDesc *badFD;
  81. PRFileDesc *fds0[10], *fds1[10], **fds, **other_fds;
  82. PRIntn nfds;
  83. PRUint16 listenPort1, listenPort2;
  84. PRNetAddr addr;
  85. PR_fd_set readFdSet;
  86. char buf[128];
  87. PRThread *clientThread;
  88. PRInt32 retVal;
  89. PRIntn i, j;
  90. /* The command line argument: -d is used to determine if the test is being run
  91. in debug mode. The regress tool requires only one line output:PASS or FAIL.
  92. All of the printfs associated with this test has been handled with a if (debug_mode)
  93. test.
  94. Usage: test_name -d
  95. */
  96. PLOptStatus os;
  97. PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
  98. while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  99. {
  100. if (PL_OPT_BAD == os) {
  101. continue;
  102. }
  103. switch (opt->option)
  104. {
  105. case 'd': /* debug mode */
  106. debug_mode = 1;
  107. break;
  108. default:
  109. break;
  110. }
  111. }
  112. PL_DestroyOptState(opt);
  113. /* main test */
  114. PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
  115. PR_STDIO_INIT();
  116. if (debug_mode) {
  117. printf("This program tests PR_Select with sockets. Timeout, error\n");
  118. printf("reporting, and normal operation are tested.\n\n");
  119. }
  120. /* Create two listening sockets */
  121. if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
  122. fprintf(stderr, "Can't create a new TCP socket\n");
  123. if (!debug_mode) {
  124. Test_Result(FAIL);
  125. }
  126. exit(1);
  127. }
  128. addr.inet.family = AF_INET;
  129. addr.inet.ip = PR_htonl(INADDR_ANY);
  130. addr.inet.port = PR_htons(0);
  131. if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
  132. fprintf(stderr, "Can't bind socket\n");
  133. if (!debug_mode) {
  134. Test_Result(FAIL);
  135. }
  136. exit(1);
  137. }
  138. if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
  139. fprintf(stderr, "PR_GetSockName failed\n");
  140. if (!debug_mode) {
  141. Test_Result(FAIL);
  142. }
  143. exit(1);
  144. }
  145. listenPort1 = PR_ntohs(addr.inet.port);
  146. if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
  147. fprintf(stderr, "Can't listen on a socket\n");
  148. if (!debug_mode) {
  149. Test_Result(FAIL);
  150. }
  151. exit(1);
  152. }
  153. if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
  154. fprintf(stderr, "Can't create a new TCP socket\n");
  155. if (!debug_mode) {
  156. Test_Result(FAIL);
  157. }
  158. exit(1);
  159. }
  160. addr.inet.family = AF_INET;
  161. addr.inet.ip = PR_htonl(INADDR_ANY);
  162. addr.inet.port = PR_htons(0);
  163. if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
  164. fprintf(stderr, "Can't bind socket\n");
  165. if (!debug_mode) {
  166. Test_Result(FAIL);
  167. }
  168. exit(1);
  169. }
  170. if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
  171. fprintf(stderr, "PR_GetSockName failed\n");
  172. if (!debug_mode) {
  173. Test_Result(FAIL);
  174. }
  175. exit(1);
  176. }
  177. listenPort2 = PR_ntohs(addr.inet.port);
  178. if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
  179. fprintf(stderr, "Can't listen on a socket\n");
  180. if (!debug_mode) {
  181. Test_Result(FAIL);
  182. }
  183. exit(1);
  184. }
  185. PR_snprintf(buf, sizeof(buf),
  186. "The server thread is listening on ports %hu and %hu\n\n",
  187. listenPort1, listenPort2);
  188. printf("%s", buf);
  189. /* Set up the fd set */
  190. PR_FD_ZERO(&readFdSet);
  191. PR_FD_SET(listenSock1, &readFdSet);
  192. PR_FD_SET(listenSock2, &readFdSet);
  193. /* Testing timeout */
  194. if (debug_mode) {
  195. printf("PR_Select should time out in 5 seconds\n");
  196. }
  197. retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
  198. PR_SecondsToInterval(5));
  199. if (retVal != 0) {
  200. PR_snprintf(buf, sizeof(buf),
  201. "PR_Select should time out and return 0, but it returns %ld\n",
  202. retVal);
  203. fprintf(stderr, "%s", buf);
  204. if (retVal == -1) {
  205. fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(),
  206. PR_GetOSError());
  207. if (!debug_mode) {
  208. Test_Result(FAIL);
  209. }
  210. }
  211. exit(1);
  212. }
  213. if (debug_mode) {
  214. printf("PR_Select timed out. Test passed.\n\n");
  215. }
  216. else {
  217. Test_Result(PASS);
  218. }
  219. /* Testing bad fd */
  220. printf("PR_Select should detect a bad file descriptor\n");
  221. if ((badFD = PR_NewTCPSocket()) == NULL) {
  222. fprintf(stderr, "Can't create a TCP socket\n");
  223. exit(1);
  224. }
  225. PR_FD_SET(listenSock1, &readFdSet);
  226. PR_FD_SET(listenSock2, &readFdSet);
  227. PR_FD_SET(badFD, &readFdSet);
  228. PR_Close(badFD); /* make the fd bad */
  229. retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
  230. PR_INTERVAL_NO_TIMEOUT);
  231. if (retVal != -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR) {
  232. fprintf(stderr, "Failed to detect the bad fd: "
  233. "PR_Select returns %d\n", retVal);
  234. if (retVal == -1) {
  235. fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(),
  236. PR_GetOSError());
  237. }
  238. exit(1);
  239. }
  240. printf("PR_Select detected a bad fd. Test passed.\n\n");
  241. PR_FD_CLR(badFD, &readFdSet);
  242. clientThread = PR_CreateThread(PR_USER_THREAD,
  243. clientThreadFunc, (void *) listenPort1,
  244. PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
  245. PR_UNJOINABLE_THREAD, 0);
  246. if (clientThread == NULL) {
  247. fprintf(stderr, "can't create thread\n");
  248. exit(1);
  249. }
  250. clientThread = PR_CreateThread(PR_USER_THREAD,
  251. clientThreadFunc, (void *) listenPort2,
  252. PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
  253. PR_UNJOINABLE_THREAD, 0);
  254. if (clientThread == NULL) {
  255. fprintf(stderr, "can't create thread\n");
  256. exit(1);
  257. }
  258. printf("Two client threads are created. Each of them will\n");
  259. printf("send data to one of the two ports the server is listening on.\n");
  260. printf("The data they send is the port number. Each of them send\n");
  261. printf("the data five times, so you should see ten lines below,\n");
  262. printf("interleaved in an arbitrary order.\n");
  263. /* set up the fd array */
  264. fds = fds0;
  265. other_fds = fds1;
  266. fds[0] = listenSock1;
  267. fds[1] = listenSock2;
  268. nfds = 2;
  269. PR_FD_SET(listenSock1, &readFdSet);
  270. PR_FD_SET(listenSock2, &readFdSet);
  271. /* 20 events total */
  272. i = 0;
  273. while (i < 20) {
  274. PRFileDesc **tmp;
  275. int nextIndex;
  276. int nEvents = 0;
  277. retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
  278. PR_INTERVAL_NO_TIMEOUT);
  279. PR_ASSERT(retVal != 0); /* no timeout */
  280. if (retVal == -1) {
  281. fprintf(stderr, "PR_Select failed (%d, %d)\n", PR_GetError(),
  282. PR_GetOSError());
  283. exit(1);
  284. }
  285. nextIndex = 2;
  286. /* the two listening sockets */
  287. for (j = 0; j < 2; j++) {
  288. other_fds[j] = fds[j];
  289. if (PR_FD_ISSET(fds[j], &readFdSet)) {
  290. PRFileDesc *sock;
  291. nEvents++;
  292. sock = PR_Accept(fds[j], NULL, PR_INTERVAL_NO_TIMEOUT);
  293. if (sock == NULL) {
  294. fprintf(stderr, "PR_Accept() failed\n");
  295. exit(1);
  296. }
  297. other_fds[nextIndex] = sock;
  298. PR_FD_SET(sock, &readFdSet);
  299. nextIndex++;
  300. }
  301. PR_FD_SET(fds[j], &readFdSet);
  302. }
  303. for (j = 2; j < nfds; j++) {
  304. if (PR_FD_ISSET(fds[j], &readFdSet)) {
  305. PRInt32 nBytes;
  306. PR_FD_CLR(fds[j], &readFdSet);
  307. nEvents++;
  308. nBytes = PR_Read(fds[j], buf, sizeof(buf));
  309. if (nBytes == -1) {
  310. fprintf(stderr, "PR_Read() failed\n");
  311. exit(1);
  312. }
  313. /* Just to be safe */
  314. buf[127] = '\0';
  315. PR_Close(fds[j]);
  316. printf("The server received \"%s\" from a client\n", buf);
  317. } else {
  318. PR_FD_SET(fds[j], &readFdSet);
  319. other_fds[nextIndex] = fds[j];
  320. nextIndex++;
  321. }
  322. }
  323. PR_ASSERT(retVal == nEvents);
  324. /* swap */
  325. tmp = fds;
  326. fds = other_fds;
  327. other_fds = tmp;
  328. nfds = nextIndex;
  329. i += nEvents;
  330. }
  331. printf("All tests finished\n");
  332. PR_Cleanup();
  333. return 0;
  334. }