echo-server.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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 void after_write(uv_write_t* req, int status);
  37. static void after_read(uv_stream_t*, ssize_t nread, uv_buf_t buf);
  38. static void on_close(uv_handle_t* peer);
  39. static void on_server_close(uv_handle_t* handle);
  40. static void on_connection(uv_stream_t*, int status);
  41. static void after_write(uv_write_t* req, int status) {
  42. write_req_t* wr;
  43. uv_err_t err;
  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. err = uv_last_error(loop);
  51. fprintf(stderr, "uv_write error: %s\n", uv_strerror(err));
  52. if (err.code == UV_ECANCELED)
  53. return;
  54. ASSERT(err.code == UV_EPIPE);
  55. uv_close((uv_handle_t*)req->handle, on_close);
  56. }
  57. static void after_shutdown(uv_shutdown_t* req, int status) {
  58. uv_close((uv_handle_t*)req->handle, on_close);
  59. free(req);
  60. }
  61. static void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
  62. int i;
  63. write_req_t *wr;
  64. uv_shutdown_t* req;
  65. if (nread < 0) {
  66. /* Error or EOF */
  67. ASSERT (uv_last_error(loop).code == UV_EOF);
  68. if (buf.base) {
  69. free(buf.base);
  70. }
  71. req = (uv_shutdown_t*) malloc(sizeof *req);
  72. uv_shutdown(req, handle, after_shutdown);
  73. return;
  74. }
  75. if (nread == 0) {
  76. /* Everything OK, but nothing read. */
  77. free(buf.base);
  78. return;
  79. }
  80. /*
  81. * Scan for the letter Q which signals that we should quit the server.
  82. * If we get QS it means close the stream.
  83. */
  84. if (!server_closed) {
  85. for (i = 0; i < nread; i++) {
  86. if (buf.base[i] == 'Q') {
  87. if (i + 1 < nread && buf.base[i + 1] == 'S') {
  88. free(buf.base);
  89. uv_close((uv_handle_t*)handle, on_close);
  90. return;
  91. } else {
  92. uv_close(server, on_server_close);
  93. server_closed = 1;
  94. }
  95. }
  96. }
  97. }
  98. wr = (write_req_t*) malloc(sizeof *wr);
  99. wr->buf = uv_buf_init(buf.base, nread);
  100. if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {
  101. FATAL("uv_write failed");
  102. }
  103. }
  104. static void on_close(uv_handle_t* peer) {
  105. free(peer);
  106. }
  107. static uv_buf_t echo_alloc(uv_handle_t* handle, size_t suggested_size) {
  108. return uv_buf_init(malloc(suggested_size), suggested_size);
  109. }
  110. static void on_connection(uv_stream_t* server, int status) {
  111. uv_stream_t* stream;
  112. int r;
  113. if (status != 0) {
  114. fprintf(stderr, "Connect error %d\n",
  115. uv_last_error(loop).code);
  116. }
  117. ASSERT(status == 0);
  118. switch (serverType) {
  119. case TCP:
  120. stream = malloc(sizeof(uv_tcp_t));
  121. ASSERT(stream != NULL);
  122. r = uv_tcp_init(loop, (uv_tcp_t*)stream);
  123. ASSERT(r == 0);
  124. break;
  125. case PIPE:
  126. stream = malloc(sizeof(uv_pipe_t));
  127. ASSERT(stream != NULL);
  128. r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
  129. ASSERT(r == 0);
  130. break;
  131. default:
  132. ASSERT(0 && "Bad serverType");
  133. abort();
  134. }
  135. /* associate server with stream */
  136. stream->data = server;
  137. r = uv_accept(server, stream);
  138. ASSERT(r == 0);
  139. r = uv_read_start(stream, echo_alloc, after_read);
  140. ASSERT(r == 0);
  141. }
  142. static void on_server_close(uv_handle_t* handle) {
  143. ASSERT(handle == server);
  144. }
  145. static void on_send(uv_udp_send_t* req, int status);
  146. static void on_recv(uv_udp_t* handle,
  147. ssize_t nread,
  148. uv_buf_t buf,
  149. struct sockaddr* addr,
  150. unsigned flags) {
  151. uv_udp_send_t* req;
  152. int r;
  153. ASSERT(nread > 0);
  154. ASSERT(addr->sa_family == AF_INET);
  155. req = malloc(sizeof(*req));
  156. ASSERT(req != NULL);
  157. r = uv_udp_send(req, handle, &buf, 1, *(struct sockaddr_in*)addr, on_send);
  158. ASSERT(r == 0);
  159. }
  160. static void on_send(uv_udp_send_t* req, int status) {
  161. ASSERT(status == 0);
  162. free(req);
  163. }
  164. static int tcp4_echo_start(int port) {
  165. struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", port);
  166. int r;
  167. server = (uv_handle_t*)&tcpServer;
  168. serverType = TCP;
  169. r = uv_tcp_init(loop, &tcpServer);
  170. if (r) {
  171. /* TODO: Error codes */
  172. fprintf(stderr, "Socket creation error\n");
  173. return 1;
  174. }
  175. r = uv_tcp_bind(&tcpServer, addr);
  176. if (r) {
  177. /* TODO: Error codes */
  178. fprintf(stderr, "Bind error\n");
  179. return 1;
  180. }
  181. r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
  182. if (r) {
  183. /* TODO: Error codes */
  184. fprintf(stderr, "Listen error %s\n",
  185. uv_err_name(uv_last_error(loop)));
  186. return 1;
  187. }
  188. return 0;
  189. }
  190. static int tcp6_echo_start(int port) {
  191. struct sockaddr_in6 addr6 = uv_ip6_addr("::1", port);
  192. int r;
  193. server = (uv_handle_t*)&tcpServer;
  194. serverType = TCP;
  195. r = uv_tcp_init(loop, &tcpServer);
  196. if (r) {
  197. /* TODO: Error codes */
  198. fprintf(stderr, "Socket creation error\n");
  199. return 1;
  200. }
  201. /* IPv6 is optional as not all platforms support it */
  202. r = uv_tcp_bind6(&tcpServer, addr6);
  203. if (r) {
  204. /* show message but return OK */
  205. fprintf(stderr, "IPv6 not supported\n");
  206. return 0;
  207. }
  208. r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
  209. if (r) {
  210. /* TODO: Error codes */
  211. fprintf(stderr, "Listen error\n");
  212. return 1;
  213. }
  214. return 0;
  215. }
  216. static int udp4_echo_start(int port) {
  217. int r;
  218. server = (uv_handle_t*)&udpServer;
  219. serverType = UDP;
  220. r = uv_udp_init(loop, &udpServer);
  221. if (r) {
  222. fprintf(stderr, "uv_udp_init: %s\n",
  223. uv_strerror(uv_last_error(loop)));
  224. return 1;
  225. }
  226. r = uv_udp_recv_start(&udpServer, echo_alloc, on_recv);
  227. if (r) {
  228. fprintf(stderr, "uv_udp_recv_start: %s\n",
  229. uv_strerror(uv_last_error(loop)));
  230. return 1;
  231. }
  232. return 0;
  233. }
  234. static int pipe_echo_start(char* pipeName) {
  235. int r;
  236. #ifndef _WIN32
  237. {
  238. uv_fs_t req;
  239. uv_fs_unlink(uv_default_loop(), &req, pipeName, NULL);
  240. uv_fs_req_cleanup(&req);
  241. }
  242. #endif
  243. server = (uv_handle_t*)&pipeServer;
  244. serverType = PIPE;
  245. r = uv_pipe_init(loop, &pipeServer, 0);
  246. if (r) {
  247. fprintf(stderr, "uv_pipe_init: %s\n",
  248. uv_strerror(uv_last_error(loop)));
  249. return 1;
  250. }
  251. r = uv_pipe_bind(&pipeServer, pipeName);
  252. if (r) {
  253. fprintf(stderr, "uv_pipe_bind: %s\n",
  254. uv_strerror(uv_last_error(loop)));
  255. return 1;
  256. }
  257. r = uv_listen((uv_stream_t*)&pipeServer, SOMAXCONN, on_connection);
  258. if (r) {
  259. fprintf(stderr, "uv_pipe_listen: %s\n",
  260. uv_strerror(uv_last_error(loop)));
  261. return 1;
  262. }
  263. return 0;
  264. }
  265. HELPER_IMPL(tcp4_echo_server) {
  266. loop = uv_default_loop();
  267. if (tcp4_echo_start(TEST_PORT))
  268. return 1;
  269. uv_run(loop, UV_RUN_DEFAULT);
  270. return 0;
  271. }
  272. HELPER_IMPL(tcp6_echo_server) {
  273. loop = uv_default_loop();
  274. if (tcp6_echo_start(TEST_PORT))
  275. return 1;
  276. uv_run(loop, UV_RUN_DEFAULT);
  277. return 0;
  278. }
  279. HELPER_IMPL(pipe_echo_server) {
  280. loop = uv_default_loop();
  281. if (pipe_echo_start(TEST_PIPENAME))
  282. return 1;
  283. uv_run(loop, UV_RUN_DEFAULT);
  284. return 0;
  285. }
  286. HELPER_IMPL(udp4_echo_server) {
  287. loop = uv_default_loop();
  288. if (udp4_echo_start(TEST_PORT))
  289. return 1;
  290. uv_run(loop, UV_RUN_DEFAULT);
  291. return 0;
  292. }