poll_nm.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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: prpoll_norm.c
  8. **
  9. ** Description: This program tests PR_Poll with sockets.
  10. ** Normal operation are tested
  11. **
  12. ** Modification History:
  13. ** 19-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. ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
  19. ** recognize the return code from tha main program.
  20. ***********************************************************************/
  21. /***********************************************************************
  22. ** Includes
  23. ***********************************************************************/
  24. /* Used to get the command line option */
  25. #include "plgetopt.h"
  26. #include "prinit.h"
  27. #include "prio.h"
  28. #include "prlog.h"
  29. #include "prprf.h"
  30. #include "prnetdb.h"
  31. #include "obsolete/probslet.h"
  32. #include "private/pprio.h"
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <stdlib.h>
  36. PRIntn failed_already=0;
  37. PRIntn debug_mode;
  38. #define NUM_ITERATIONS 5
  39. static void PR_CALLBACK
  40. clientThreadFunc(void *arg)
  41. {
  42. PRUintn port = (PRUintn) arg;
  43. PRFileDesc *sock;
  44. PRNetAddr addr;
  45. char buf[128];
  46. int i;
  47. PRStatus sts;
  48. PRInt32 n;
  49. addr.inet.family = PR_AF_INET;
  50. addr.inet.port = PR_htons((PRUint16)port);
  51. addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
  52. memset(buf, 0, sizeof(buf));
  53. PR_snprintf(buf, sizeof(buf), "%hu", port);
  54. for (i = 0; i < NUM_ITERATIONS; i++) {
  55. sock = PR_NewTCPSocket();
  56. PR_ASSERT(sock != NULL);
  57. sts = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
  58. PR_ASSERT(sts == PR_SUCCESS);
  59. n = PR_Write(sock, buf, sizeof(buf));
  60. PR_ASSERT(n >= 0);
  61. sts = PR_Close(sock);
  62. PR_ASSERT(sts == PR_SUCCESS);
  63. }
  64. }
  65. int main(int argc, char **argv)
  66. {
  67. PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL;
  68. PRUint16 listenPort1, listenPort2;
  69. PRNetAddr addr;
  70. char buf[128];
  71. PRThread *clientThread;
  72. PRPollDesc pds0[20], pds1[20], *pds, *other_pds;
  73. PRIntn npds;
  74. PRInt32 retVal;
  75. PRIntn i, j;
  76. PRSocketOptionData optval;
  77. /* The command line argument: -d is used to determine if the test is being run
  78. in debug mode. The regress tool requires only one line output:PASS or FAIL.
  79. All of the printfs associated with this test has been handled with a if (debug_mode)
  80. test.
  81. Usage: test_name -d
  82. */
  83. PLOptStatus os;
  84. PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
  85. while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  86. {
  87. if (PL_OPT_BAD == os) {
  88. continue;
  89. }
  90. switch (opt->option)
  91. {
  92. case 'd': /* debug mode */
  93. debug_mode = 1;
  94. break;
  95. default:
  96. break;
  97. }
  98. }
  99. PL_DestroyOptState(opt);
  100. /* main test */
  101. PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
  102. PR_STDIO_INIT();
  103. if (debug_mode) {
  104. printf("This program tests PR_Poll with sockets.\n");
  105. printf("Normal operation are tested.\n\n");
  106. }
  107. /* Create two listening sockets */
  108. if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
  109. fprintf(stderr, "Can't create a new TCP socket\n");
  110. failed_already=1;
  111. goto exit_now;
  112. }
  113. memset(&addr, 0, sizeof(addr));
  114. addr.inet.family = PR_AF_INET;
  115. addr.inet.ip = PR_htonl(PR_INADDR_ANY);
  116. addr.inet.port = PR_htons(0);
  117. if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
  118. fprintf(stderr, "Can't bind socket\n");
  119. failed_already=1;
  120. goto exit_now;
  121. }
  122. if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
  123. fprintf(stderr, "PR_GetSockName failed\n");
  124. failed_already=1;
  125. goto exit_now;
  126. }
  127. listenPort1 = PR_ntohs(addr.inet.port);
  128. optval.option = PR_SockOpt_Nonblocking;
  129. optval.value.non_blocking = PR_TRUE;
  130. PR_SetSocketOption(listenSock1, &optval);
  131. if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
  132. fprintf(stderr, "Can't listen on a socket\n");
  133. failed_already=1;
  134. goto exit_now;
  135. }
  136. if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
  137. fprintf(stderr, "Can't create a new TCP socket\n");
  138. failed_already=1;
  139. goto exit_now;
  140. }
  141. addr.inet.family = PR_AF_INET;
  142. addr.inet.ip = PR_htonl(PR_INADDR_ANY);
  143. addr.inet.port = PR_htons(0);
  144. if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
  145. fprintf(stderr, "Can't bind socket\n");
  146. failed_already=1;
  147. goto exit_now;
  148. }
  149. if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
  150. fprintf(stderr, "PR_GetSockName failed\n");
  151. failed_already=1;
  152. goto exit_now;
  153. }
  154. listenPort2 = PR_ntohs(addr.inet.port);
  155. PR_SetSocketOption(listenSock2, &optval);
  156. if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
  157. fprintf(stderr, "Can't listen on a socket\n");
  158. failed_already=1;
  159. goto exit_now;
  160. }
  161. PR_snprintf(buf, sizeof(buf),
  162. "The server thread is listening on ports %hu and %hu\n\n",
  163. listenPort1, listenPort2);
  164. if (debug_mode) {
  165. printf("%s", buf);
  166. }
  167. /* Set up the poll descriptor array */
  168. pds = pds0;
  169. other_pds = pds1;
  170. memset(pds, 0, sizeof(pds));
  171. pds[0].fd = listenSock1;
  172. pds[0].in_flags = PR_POLL_READ;
  173. pds[1].fd = listenSock2;
  174. pds[1].in_flags = PR_POLL_READ;
  175. /* Add some unused entries to test if they are ignored by PR_Poll() */
  176. memset(&pds[2], 0, sizeof(pds[2]));
  177. memset(&pds[3], 0, sizeof(pds[3]));
  178. memset(&pds[4], 0, sizeof(pds[4]));
  179. npds = 5;
  180. clientThread = PR_CreateThread(PR_USER_THREAD,
  181. clientThreadFunc, (void *) listenPort1,
  182. PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
  183. PR_UNJOINABLE_THREAD, 0);
  184. if (clientThread == NULL) {
  185. fprintf(stderr, "can't create thread\n");
  186. failed_already=1;
  187. goto exit_now;
  188. }
  189. clientThread = PR_CreateThread(PR_USER_THREAD,
  190. clientThreadFunc, (void *) listenPort2,
  191. PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
  192. PR_UNJOINABLE_THREAD, 0);
  193. if (clientThread == NULL) {
  194. fprintf(stderr, "can't create thread\n");
  195. failed_already=1;
  196. goto exit_now;
  197. }
  198. if (debug_mode) {
  199. printf("Two client threads are created. Each of them will\n");
  200. printf("send data to one of the two ports the server is listening on.\n");
  201. printf("The data they send is the port number. Each of them send\n");
  202. printf("the data five times, so you should see ten lines below,\n");
  203. printf("interleaved in an arbitrary order.\n");
  204. }
  205. /* two clients, three events per iteration: accept, read, close */
  206. i = 0;
  207. while (i < 2 * 3 * NUM_ITERATIONS) {
  208. PRPollDesc *tmp;
  209. int nextIndex;
  210. int nEvents = 0;
  211. retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
  212. PR_ASSERT(retVal != 0); /* no timeout */
  213. if (retVal == -1) {
  214. fprintf(stderr, "PR_Poll failed\n");
  215. failed_already=1;
  216. goto exit_now;
  217. }
  218. nextIndex = 2;
  219. /* the two listening sockets */
  220. for (j = 0; j < 2; j++) {
  221. other_pds[j] = pds[j];
  222. PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
  223. && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
  224. if (pds[j].out_flags & PR_POLL_READ) {
  225. PRFileDesc *sock;
  226. nEvents++;
  227. sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT);
  228. if (sock == NULL) {
  229. fprintf(stderr, "PR_Accept() failed\n");
  230. failed_already=1;
  231. goto exit_now;
  232. }
  233. other_pds[nextIndex].fd = sock;
  234. other_pds[nextIndex].in_flags = PR_POLL_READ;
  235. nextIndex++;
  236. } else if (pds[j].out_flags & PR_POLL_ERR) {
  237. fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
  238. failed_already=1;
  239. goto exit_now;
  240. } else if (pds[j].out_flags & PR_POLL_NVAL) {
  241. fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n",
  242. PR_FileDesc2NativeHandle(pds[j].fd));
  243. failed_already=1;
  244. goto exit_now;
  245. }
  246. }
  247. for (j = 2; j < npds; j++) {
  248. if (NULL == pds[j].fd) {
  249. /*
  250. * Keep the unused entries in the poll descriptor array
  251. * for testing purposes.
  252. */
  253. other_pds[nextIndex] = pds[j];
  254. nextIndex++;
  255. continue;
  256. }
  257. PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
  258. && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
  259. if (pds[j].out_flags & PR_POLL_READ) {
  260. PRInt32 nAvail;
  261. PRInt32 nRead;
  262. nEvents++;
  263. nAvail = PR_Available(pds[j].fd);
  264. nRead = PR_Read(pds[j].fd, buf, sizeof(buf));
  265. PR_ASSERT(nAvail == nRead);
  266. if (nRead == -1) {
  267. fprintf(stderr, "PR_Read() failed\n");
  268. failed_already=1;
  269. goto exit_now;
  270. } else if (nRead == 0) {
  271. PR_Close(pds[j].fd);
  272. continue;
  273. } else {
  274. /* Just to be safe */
  275. buf[127] = '\0';
  276. if (debug_mode) {
  277. printf("The server received \"%s\" from a client\n", buf);
  278. }
  279. }
  280. } else if (pds[j].out_flags & PR_POLL_ERR) {
  281. fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
  282. failed_already=1;
  283. goto exit_now;
  284. } else if (pds[j].out_flags & PR_POLL_NVAL) {
  285. fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n");
  286. failed_already=1;
  287. goto exit_now;
  288. }
  289. other_pds[nextIndex] = pds[j];
  290. nextIndex++;
  291. }
  292. PR_ASSERT(retVal == nEvents);
  293. /* swap */
  294. tmp = pds;
  295. pds = other_pds;
  296. other_pds = tmp;
  297. npds = nextIndex;
  298. i += nEvents;
  299. }
  300. if (debug_mode) {
  301. printf("Tests passed\n");
  302. }
  303. exit_now:
  304. if (listenSock1) {
  305. PR_Close(listenSock1);
  306. }
  307. if (listenSock2) {
  308. PR_Close(listenSock2);
  309. }
  310. PR_Cleanup();
  311. if(failed_already) {
  312. return 1;
  313. }
  314. else {
  315. return 0;
  316. }
  317. }