nonblock.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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. #include "nspr.h"
  6. #include "prio.h"
  7. #include "prerror.h"
  8. #include "prlog.h"
  9. #include "prprf.h"
  10. #include "prnetdb.h"
  11. #include "plerror.h"
  12. #include "obsolete/probslet.h"
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #define NUMBER_ROUNDS 5
  17. #if defined(WIN16)
  18. /*
  19. ** Make win16 unit_time interval 300 milliseconds, others get 100
  20. */
  21. #define UNIT_TIME 200 /* unit time in milliseconds */
  22. #else
  23. #define UNIT_TIME 100 /* unit time in milliseconds */
  24. #endif
  25. #define CHUNK_SIZE 10
  26. #undef USE_PR_SELECT /* If defined, we use PR_Select.
  27. * If not defined, use PR_Poll instead. */
  28. #if defined(USE_PR_SELECT)
  29. #include "pprio.h"
  30. #endif
  31. static void PR_CALLBACK
  32. clientThreadFunc(void *arg)
  33. {
  34. PRUintn port = (PRUintn)arg;
  35. PRFileDesc *sock;
  36. PRNetAddr addr;
  37. char buf[CHUNK_SIZE];
  38. int i;
  39. PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME);
  40. PRSocketOptionData optval;
  41. PRStatus retVal;
  42. PRInt32 nBytes;
  43. /* Initialize the buffer so that Purify won't complain */
  44. memset(buf, 0, sizeof(buf));
  45. addr.inet.family = PR_AF_INET;
  46. addr.inet.port = PR_htons((PRUint16)port);
  47. addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
  48. PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip);
  49. /* time 1 */
  50. PR_Sleep(unitTime);
  51. sock = PR_NewTCPSocket();
  52. optval.option = PR_SockOpt_Nonblocking;
  53. optval.value.non_blocking = PR_TRUE;
  54. PR_SetSocketOption(sock, &optval);
  55. retVal = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
  56. if (retVal == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) {
  57. #if !defined(USE_PR_SELECT)
  58. PRPollDesc pd;
  59. PRInt32 n;
  60. fprintf(stderr, "connect: EWOULDBLOCK, good\n");
  61. pd.fd = sock;
  62. pd.in_flags = PR_POLL_WRITE;
  63. n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
  64. PR_ASSERT(n == 1);
  65. PR_ASSERT(pd.out_flags == PR_POLL_WRITE);
  66. #else
  67. PR_fd_set writeSet;
  68. PRInt32 n;
  69. fprintf(stderr, "connect: EWOULDBLOCK, good\n");
  70. PR_FD_ZERO(&writeSet);
  71. PR_FD_SET(sock, &writeSet);
  72. n = PR_Select(0, NULL, &writeSet, NULL, PR_INTERVAL_NO_TIMEOUT);
  73. PR_ASSERT(n == 1);
  74. PR_ASSERT(PR_FD_ISSET(sock, &writeSet));
  75. #endif
  76. }
  77. printf("client connected\n");
  78. fflush(stdout);
  79. /* time 4, 7, 11, etc. */
  80. for (i = 0; i < NUMBER_ROUNDS; i++) {
  81. PR_Sleep(3 * unitTime);
  82. nBytes = PR_Write(sock, buf, sizeof(buf));
  83. if (nBytes == -1) {
  84. if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
  85. fprintf(stderr, "write: EWOULDBLOCK\n");
  86. exit(1);
  87. } else {
  88. fprintf(stderr, "write: failed\n");
  89. }
  90. }
  91. printf("client sent %d bytes\n", nBytes);
  92. fflush(stdout);
  93. }
  94. PR_Close(sock);
  95. }
  96. static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv )
  97. {
  98. PRFileDesc *listenSock, *sock;
  99. PRUint16 listenPort;
  100. PRNetAddr addr;
  101. char buf[CHUNK_SIZE];
  102. PRThread *clientThread;
  103. PRInt32 retVal;
  104. PRSocketOptionData optval;
  105. PRIntn i;
  106. PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME);
  107. /* Create a listening socket */
  108. if ((listenSock = PR_NewTCPSocket()) == NULL) {
  109. fprintf(stderr, "Can't create a new TCP socket\n");
  110. exit(1);
  111. }
  112. addr.inet.family = PR_AF_INET;
  113. addr.inet.ip = PR_htonl(PR_INADDR_ANY);
  114. addr.inet.port = PR_htons(0);
  115. if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
  116. fprintf(stderr, "Can't bind socket\n");
  117. exit(1);
  118. }
  119. if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
  120. fprintf(stderr, "PR_GetSockName failed\n");
  121. exit(1);
  122. }
  123. listenPort = PR_ntohs(addr.inet.port);
  124. if (PR_Listen(listenSock, 5) == PR_FAILURE) {
  125. fprintf(stderr, "Can't listen on a socket\n");
  126. exit(1);
  127. }
  128. PR_snprintf(buf, sizeof(buf),
  129. "The server thread is listening on port %hu\n\n",
  130. listenPort);
  131. printf("%s", buf);
  132. clientThread = PR_CreateThread(PR_USER_THREAD,
  133. clientThreadFunc, (void *) listenPort,
  134. PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
  135. PR_UNJOINABLE_THREAD, 0);
  136. if (clientThread == NULL) {
  137. fprintf(stderr, "can't create thread\n");
  138. exit(1);
  139. }
  140. printf("client thread created.\n");
  141. optval.option = PR_SockOpt_Nonblocking;
  142. optval.value.non_blocking = PR_TRUE;
  143. PR_SetSocketOption(listenSock, &optval);
  144. /* time 0 */
  145. sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
  146. if (sock != NULL || PR_GetError() != PR_WOULD_BLOCK_ERROR) {
  147. PL_PrintError("First Accept\n");
  148. fprintf(stderr, "First PR_Accept() xxx\n" );
  149. exit(1);
  150. }
  151. printf("accept: EWOULDBLOCK, good\n");
  152. fflush(stdout);
  153. /* time 2 */
  154. PR_Sleep(2 * unitTime);
  155. sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
  156. if (sock == NULL) {
  157. PL_PrintError("Second Accept\n");
  158. fprintf(stderr, "Second PR_Accept() failed: (%d, %d)\n",
  159. PR_GetError(), PR_GetOSError());
  160. exit(1);
  161. }
  162. printf("accept: succeeded, good\n");
  163. fflush(stdout);
  164. PR_Close(listenSock);
  165. PR_SetSocketOption(sock, &optval);
  166. /* time 3, 5, 6, 8, etc. */
  167. for (i = 0; i < NUMBER_ROUNDS; i++) {
  168. PR_Sleep(unitTime);
  169. retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
  170. if (retVal != -1 || PR_GetError() != PR_WOULD_BLOCK_ERROR) {
  171. PL_PrintError("First Receive:\n");
  172. fprintf(stderr, "First PR_Recv: retVal: %ld, Error: %ld\n",
  173. retVal, PR_GetError());
  174. exit(1);
  175. }
  176. printf("read: EWOULDBLOCK, good\n");
  177. fflush(stdout);
  178. PR_Sleep(2 * unitTime);
  179. retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
  180. if (retVal != CHUNK_SIZE) {
  181. PL_PrintError("Second Receive:\n");
  182. fprintf(stderr, "Second PR_Recv: retVal: %ld, Error: %ld\n",
  183. retVal, PR_GetError());
  184. exit(1);
  185. }
  186. printf("read: %d bytes, good\n", retVal);
  187. fflush(stdout);
  188. }
  189. PR_Close(sock);
  190. printf("All tests finished\n");
  191. printf("PASS\n");
  192. return 0;
  193. }
  194. int main(int argc, char **argv)
  195. {
  196. PRIntn rv;
  197. PR_STDIO_INIT();
  198. rv = PR_Initialize(RealMain, argc, argv, 0);
  199. return rv;
  200. } /* main */