echo-server.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to
  5. * deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. * sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. * IN THE SOFTWARE.
  20. */
  21. #include "uv.h"
  22. #include "task.h"
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. typedef struct {
  26. uv_write_t req;
  27. uv_buf_t buf;
  28. } write_req_t;
  29. static uv_loop_t* loop;
  30. static int server_closed;
  31. static stream_type serverType;
  32. static uv_tcp_t tcpServer;
  33. static uv_udp_t udpServer;
  34. static uv_pipe_t pipeServer;
  35. static uv_handle_t* server;
  36. static uv_udp_send_t* send_freelist;
  37. static void after_write(uv_write_t* req, int status);
  38. static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf);
  39. static void on_close(uv_handle_t* peer);
  40. static void on_server_close(uv_handle_t* handle);
  41. static void on_connection(uv_stream_t*, int status);
  42. static void after_write(uv_write_t* req, int status) {
  43. write_req_t* wr;
  44. /* Free the read/write buffer and the request */
  45. wr = (write_req_t*) req;
  46. free(wr->buf.base);
  47. free(wr);
  48. if (status == 0)
  49. return;
  50. fprintf(stderr,
  51. "uv_write error: %s - %s\n",
  52. uv_err_name(status),
  53. uv_strerror(status));
  54. }
  55. static void after_shutdown(uv_shutdown_t* req, int status) {
  56. uv_close((uv_handle_t*) req->handle, on_close);
  57. free(req);
  58. }
  59. static void after_read(uv_stream_t* handle,
  60. ssize_t nread,
  61. const uv_buf_t* buf) {
  62. int i;
  63. write_req_t *wr;
  64. uv_shutdown_t* sreq;
  65. if (nread < 0) {
  66. /* Error or EOF */
  67. ASSERT(nread == UV_EOF);
  68. free(buf->base);
  69. sreq = malloc(sizeof* sreq);
  70. ASSERT(0 == uv_shutdown(sreq, handle, after_shutdown));
  71. return;
  72. }
  73. if (nread == 0) {
  74. /* Everything OK, but nothing read. */
  75. free(buf->base);
  76. return;
  77. }
  78. /*
  79. * Scan for the letter Q which signals that we should quit the server.
  80. * If we get QS it means close the stream.
  81. */
  82. if (!server_closed) {
  83. for (i = 0; i < nread; i++) {
  84. if (buf->base[i] == 'Q') {
  85. if (i + 1 < nread && buf->base[i + 1] == 'S') {
  86. free(buf->base);
  87. uv_close((uv_handle_t*)handle, on_close);
  88. return;
  89. } else {
  90. uv_close(server, on_server_close);
  91. server_closed = 1;
  92. }
  93. }
  94. }
  95. }
  96. wr = (write_req_t*) malloc(sizeof *wr);
  97. ASSERT(wr != NULL);
  98. wr->buf = uv_buf_init(buf->base, nread);
  99. if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {
  100. FATAL("uv_write failed");
  101. }
  102. }
  103. static void on_close(uv_handle_t* peer) {
  104. free(peer);
  105. }
  106. static void echo_alloc(uv_handle_t* handle,
  107. size_t suggested_size,
  108. uv_buf_t* buf) {
  109. buf->base = malloc(suggested_size);
  110. buf->len = suggested_size;
  111. }
  112. static void slab_alloc(uv_handle_t* handle,
  113. size_t suggested_size,
  114. uv_buf_t* buf) {
  115. /* up to 16 datagrams at once */
  116. static char slab[16 * 64 * 1024];
  117. buf->base = slab;
  118. buf->len = sizeof(slab);
  119. }
  120. static void on_connection(uv_stream_t* server, int status) {
  121. uv_stream_t* stream;
  122. int r;
  123. if (status != 0) {
  124. fprintf(stderr, "Connect error %s\n", uv_err_name(status));
  125. }
  126. ASSERT(status == 0);
  127. switch (serverType) {
  128. case TCP:
  129. stream = malloc(sizeof(uv_tcp_t));
  130. ASSERT(stream != NULL);
  131. r = uv_tcp_init(loop, (uv_tcp_t*)stream);
  132. ASSERT(r == 0);
  133. break;
  134. case PIPE:
  135. stream = malloc(sizeof(uv_pipe_t));
  136. ASSERT(stream != NULL);
  137. r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
  138. ASSERT(r == 0);
  139. break;
  140. default:
  141. ASSERT(0 && "Bad serverType");
  142. abort();
  143. }
  144. /* associate server with stream */
  145. stream->data = server;
  146. r = uv_accept(server, stream);
  147. ASSERT(r == 0);
  148. r = uv_read_start(stream, echo_alloc, after_read);
  149. ASSERT(r == 0);
  150. }
  151. static void on_server_close(uv_handle_t* handle) {
  152. ASSERT(handle == server);
  153. }
  154. static uv_udp_send_t* send_alloc(void) {
  155. uv_udp_send_t* req = send_freelist;
  156. if (req != NULL)
  157. send_freelist = req->data;
  158. else
  159. req = malloc(sizeof(*req));
  160. return req;
  161. }
  162. static void on_send(uv_udp_send_t* req, int status) {
  163. ASSERT(req != NULL);
  164. ASSERT(status == 0);
  165. req->data = send_freelist;
  166. send_freelist = req;
  167. }
  168. static void on_recv(uv_udp_t* handle,
  169. ssize_t nread,
  170. const uv_buf_t* rcvbuf,
  171. const struct sockaddr* addr,
  172. unsigned flags) {
  173. uv_buf_t sndbuf;
  174. if (nread == 0) {
  175. /* Everything OK, but nothing read. */
  176. return;
  177. }
  178. ASSERT(nread > 0);
  179. ASSERT(addr->sa_family == AF_INET);
  180. uv_udp_send_t* req = send_alloc();
  181. ASSERT(req != NULL);
  182. sndbuf = uv_buf_init(rcvbuf->base, nread);
  183. ASSERT(0 <= uv_udp_send(req, handle, &sndbuf, 1, addr, on_send));
  184. }
  185. static int tcp4_echo_start(int port) {
  186. struct sockaddr_in addr;
  187. int r;
  188. ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
  189. server = (uv_handle_t*)&tcpServer;
  190. serverType = TCP;
  191. r = uv_tcp_init(loop, &tcpServer);
  192. if (r) {
  193. /* TODO: Error codes */
  194. fprintf(stderr, "Socket creation error\n");
  195. return 1;
  196. }
  197. r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
  198. if (r) {
  199. /* TODO: Error codes */
  200. fprintf(stderr, "Bind error\n");
  201. return 1;
  202. }
  203. r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
  204. if (r) {
  205. /* TODO: Error codes */
  206. fprintf(stderr, "Listen error %s\n", uv_err_name(r));
  207. return 1;
  208. }
  209. return 0;
  210. }
  211. static int tcp6_echo_start(int port) {
  212. struct sockaddr_in6 addr6;
  213. int r;
  214. ASSERT(0 == uv_ip6_addr("::1", port, &addr6));
  215. server = (uv_handle_t*)&tcpServer;
  216. serverType = TCP;
  217. r = uv_tcp_init(loop, &tcpServer);
  218. if (r) {
  219. /* TODO: Error codes */
  220. fprintf(stderr, "Socket creation error\n");
  221. return 1;
  222. }
  223. /* IPv6 is optional as not all platforms support it */
  224. r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr6, 0);
  225. if (r) {
  226. /* show message but return OK */
  227. fprintf(stderr, "IPv6 not supported\n");
  228. return 0;
  229. }
  230. r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
  231. if (r) {
  232. /* TODO: Error codes */
  233. fprintf(stderr, "Listen error\n");
  234. return 1;
  235. }
  236. return 0;
  237. }
  238. static int udp4_echo_start(int port) {
  239. struct sockaddr_in addr;
  240. int r;
  241. ASSERT(0 == uv_ip4_addr("127.0.0.1", port, &addr));
  242. server = (uv_handle_t*)&udpServer;
  243. serverType = UDP;
  244. r = uv_udp_init(loop, &udpServer);
  245. if (r) {
  246. fprintf(stderr, "uv_udp_init: %s\n", uv_strerror(r));
  247. return 1;
  248. }
  249. r = uv_udp_bind(&udpServer, (const struct sockaddr*) &addr, 0);
  250. if (r) {
  251. fprintf(stderr, "uv_udp_bind: %s\n", uv_strerror(r));
  252. return 1;
  253. }
  254. r = uv_udp_recv_start(&udpServer, slab_alloc, on_recv);
  255. if (r) {
  256. fprintf(stderr, "uv_udp_recv_start: %s\n", uv_strerror(r));
  257. return 1;
  258. }
  259. return 0;
  260. }
  261. static int pipe_echo_start(char* pipeName) {
  262. int r;
  263. #ifndef _WIN32
  264. {
  265. uv_fs_t req;
  266. uv_fs_unlink(NULL, &req, pipeName, NULL);
  267. uv_fs_req_cleanup(&req);
  268. }
  269. #endif
  270. server = (uv_handle_t*)&pipeServer;
  271. serverType = PIPE;
  272. r = uv_pipe_init(loop, &pipeServer, 0);
  273. if (r) {
  274. fprintf(stderr, "uv_pipe_init: %s\n", uv_strerror(r));
  275. return 1;
  276. }
  277. r = uv_pipe_bind(&pipeServer, pipeName);
  278. if (r) {
  279. fprintf(stderr, "uv_pipe_bind: %s\n", uv_strerror(r));
  280. return 1;
  281. }
  282. r = uv_listen((uv_stream_t*)&pipeServer, SOMAXCONN, on_connection);
  283. if (r) {
  284. fprintf(stderr, "uv_pipe_listen: %s\n", uv_strerror(r));
  285. return 1;
  286. }
  287. return 0;
  288. }
  289. HELPER_IMPL(tcp4_echo_server) {
  290. loop = uv_default_loop();
  291. if (tcp4_echo_start(TEST_PORT))
  292. return 1;
  293. notify_parent_process();
  294. uv_run(loop, UV_RUN_DEFAULT);
  295. return 0;
  296. }
  297. HELPER_IMPL(tcp6_echo_server) {
  298. loop = uv_default_loop();
  299. if (tcp6_echo_start(TEST_PORT))
  300. return 1;
  301. notify_parent_process();
  302. uv_run(loop, UV_RUN_DEFAULT);
  303. return 0;
  304. }
  305. HELPER_IMPL(pipe_echo_server) {
  306. loop = uv_default_loop();
  307. if (pipe_echo_start(TEST_PIPENAME))
  308. return 1;
  309. notify_parent_process();
  310. uv_run(loop, UV_RUN_DEFAULT);
  311. return 0;
  312. }
  313. HELPER_IMPL(udp4_echo_server) {
  314. loop = uv_default_loop();
  315. if (udp4_echo_start(TEST_PORT))
  316. return 1;
  317. notify_parent_process();
  318. uv_run(loop, UV_RUN_DEFAULT);
  319. return 0;
  320. }