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, const 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. /* Free the read/write buffer and the request */
  44. wr = (write_req_t*) req;
  45. free(wr->buf.base);
  46. free(wr);
  47. if (status == 0)
  48. return;
  49. fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
  50. if (status == UV_ECANCELED)
  51. return;
  52. ASSERT(status == UV_EPIPE);
  53. uv_close((uv_handle_t*)req->handle, on_close);
  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* req;
  65. if (nread < 0) {
  66. /* Error or EOF */
  67. ASSERT(nread == 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 void echo_alloc(uv_handle_t* handle,
  108. size_t suggested_size,
  109. uv_buf_t* buf) {
  110. buf->base = malloc(suggested_size);
  111. buf->len = suggested_size;
  112. }
  113. static void on_connection(uv_stream_t* server, int status) {
  114. uv_stream_t* stream;
  115. int r;
  116. if (status != 0) {
  117. fprintf(stderr, "Connect error %s\n", uv_err_name(status));
  118. }
  119. ASSERT(status == 0);
  120. switch (serverType) {
  121. case TCP:
  122. stream = malloc(sizeof(uv_tcp_t));
  123. ASSERT(stream != NULL);
  124. r = uv_tcp_init(loop, (uv_tcp_t*)stream);
  125. ASSERT(r == 0);
  126. break;
  127. case PIPE:
  128. stream = malloc(sizeof(uv_pipe_t));
  129. ASSERT(stream != NULL);
  130. r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
  131. ASSERT(r == 0);
  132. break;
  133. default:
  134. ASSERT(0 && "Bad serverType");
  135. abort();
  136. }
  137. /* associate server with stream */
  138. stream->data = server;
  139. r = uv_accept(server, stream);
  140. ASSERT(r == 0);
  141. r = uv_read_start(stream, echo_alloc, after_read);
  142. ASSERT(r == 0);
  143. }
  144. static void on_server_close(uv_handle_t* handle) {
  145. ASSERT(handle == server);
  146. }
  147. static void on_send(uv_udp_send_t* req, int status);
  148. static void on_recv(uv_udp_t* handle,
  149. ssize_t nread,
  150. const uv_buf_t* rcvbuf,
  151. const struct sockaddr* addr,
  152. unsigned flags) {
  153. uv_udp_send_t* req;
  154. uv_buf_t sndbuf;
  155. ASSERT(nread > 0);
  156. ASSERT(addr->sa_family == AF_INET);
  157. req = malloc(sizeof(*req));
  158. ASSERT(req != NULL);
  159. sndbuf = *rcvbuf;
  160. ASSERT(0 == uv_udp_send(req, handle, &sndbuf, 1, addr, on_send));
  161. }
  162. static void on_send(uv_udp_send_t* req, int status) {
  163. ASSERT(status == 0);
  164. free(req);
  165. }
  166. static int tcp4_echo_start(int port) {
  167. struct sockaddr_in addr;
  168. int r;
  169. ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
  170. server = (uv_handle_t*)&tcpServer;
  171. serverType = TCP;
  172. r = uv_tcp_init(loop, &tcpServer);
  173. if (r) {
  174. /* TODO: Error codes */
  175. fprintf(stderr, "Socket creation error\n");
  176. return 1;
  177. }
  178. r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
  179. if (r) {
  180. /* TODO: Error codes */
  181. fprintf(stderr, "Bind error\n");
  182. return 1;
  183. }
  184. r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
  185. if (r) {
  186. /* TODO: Error codes */
  187. fprintf(stderr, "Listen error %s\n", uv_err_name(r));
  188. return 1;
  189. }
  190. return 0;
  191. }
  192. static int tcp6_echo_start(int port) {
  193. struct sockaddr_in6 addr6;
  194. int r;
  195. ASSERT(0 == uv_ip6_addr("::1", port, &addr6));
  196. server = (uv_handle_t*)&tcpServer;
  197. serverType = TCP;
  198. r = uv_tcp_init(loop, &tcpServer);
  199. if (r) {
  200. /* TODO: Error codes */
  201. fprintf(stderr, "Socket creation error\n");
  202. return 1;
  203. }
  204. /* IPv6 is optional as not all platforms support it */
  205. r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr6, 0);
  206. if (r) {
  207. /* show message but return OK */
  208. fprintf(stderr, "IPv6 not supported\n");
  209. return 0;
  210. }
  211. r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
  212. if (r) {
  213. /* TODO: Error codes */
  214. fprintf(stderr, "Listen error\n");
  215. return 1;
  216. }
  217. return 0;
  218. }
  219. static int udp4_echo_start(int port) {
  220. int r;
  221. server = (uv_handle_t*)&udpServer;
  222. serverType = UDP;
  223. r = uv_udp_init(loop, &udpServer);
  224. if (r) {
  225. fprintf(stderr, "uv_udp_init: %s\n", uv_strerror(r));
  226. return 1;
  227. }
  228. r = uv_udp_recv_start(&udpServer, echo_alloc, on_recv);
  229. if (r) {
  230. fprintf(stderr, "uv_udp_recv_start: %s\n", uv_strerror(r));
  231. return 1;
  232. }
  233. return 0;
  234. }
  235. static int pipe_echo_start(char* pipeName) {
  236. int r;
  237. #ifndef _WIN32
  238. {
  239. uv_fs_t req;
  240. uv_fs_unlink(uv_default_loop(), &req, pipeName, NULL);
  241. uv_fs_req_cleanup(&req);
  242. }
  243. #endif
  244. server = (uv_handle_t*)&pipeServer;
  245. serverType = PIPE;
  246. r = uv_pipe_init(loop, &pipeServer, 0);
  247. if (r) {
  248. fprintf(stderr, "uv_pipe_init: %s\n", uv_strerror(r));
  249. return 1;
  250. }
  251. r = uv_pipe_bind(&pipeServer, pipeName);
  252. if (r) {
  253. fprintf(stderr, "uv_pipe_bind: %s\n", uv_strerror(r));
  254. return 1;
  255. }
  256. r = uv_listen((uv_stream_t*)&pipeServer, SOMAXCONN, on_connection);
  257. if (r) {
  258. fprintf(stderr, "uv_pipe_listen: %s\n", uv_strerror(r));
  259. return 1;
  260. }
  261. return 0;
  262. }
  263. HELPER_IMPL(tcp4_echo_server) {
  264. loop = uv_default_loop();
  265. if (tcp4_echo_start(TEST_PORT))
  266. return 1;
  267. uv_run(loop, UV_RUN_DEFAULT);
  268. return 0;
  269. }
  270. HELPER_IMPL(tcp6_echo_server) {
  271. loop = uv_default_loop();
  272. if (tcp6_echo_start(TEST_PORT))
  273. return 1;
  274. uv_run(loop, UV_RUN_DEFAULT);
  275. return 0;
  276. }
  277. HELPER_IMPL(pipe_echo_server) {
  278. loop = uv_default_loop();
  279. if (pipe_echo_start(TEST_PIPENAME))
  280. return 1;
  281. uv_run(loop, UV_RUN_DEFAULT);
  282. return 0;
  283. }
  284. HELPER_IMPL(udp4_echo_server) {
  285. loop = uv_default_loop();
  286. if (udp4_echo_start(TEST_PORT))
  287. return 1;
  288. uv_run(loop, UV_RUN_DEFAULT);
  289. return 0;
  290. }