echo-server.c
Go to the documentation of this file.
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 
22 #include "uv.h"
23 #include "task.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 
27 typedef struct {
29  uv_buf_t buf;
30 } write_req_t;
31 
32 static uv_loop_t* loop;
33 
34 static int server_closed;
41 
42 static void after_write(uv_write_t* req, int status);
43 static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf);
44 static void on_close(uv_handle_t* peer);
45 static void on_server_close(uv_handle_t* handle);
46 static void on_connection(uv_stream_t*, int status);
47 
48 
49 static void after_write(uv_write_t* req, int status) {
50  write_req_t* wr;
51 
52  /* Free the read/write buffer and the request */
53  wr = (write_req_t*) req;
54  free(wr->buf.base);
55  free(wr);
56 
57  if (status == 0)
58  return;
59 
60  fprintf(stderr,
61  "uv_write error: %s - %s\n",
64 }
65 
66 
67 static void after_shutdown(uv_shutdown_t* req, int status) {
69  free(req);
70 }
71 
72 
74  ssize_t nread,
75  const uv_buf_t* buf) {
76  int i;
77  write_req_t *wr;
78  uv_shutdown_t* sreq;
79 
80  if (nread < 0) {
81  /* Error or EOF */
82  ASSERT(nread == UV_EOF);
83 
84  free(buf->base);
85  sreq = malloc(sizeof* sreq);
87  return;
88  }
89 
90  if (nread == 0) {
91  /* Everything OK, but nothing read. */
92  free(buf->base);
93  return;
94  }
95 
96  /*
97  * Scan for the letter Q which signals that we should quit the server.
98  * If we get QS it means close the stream.
99  */
100  if (!server_closed) {
101  for (i = 0; i < nread; i++) {
102  if (buf->base[i] == 'Q') {
103  if (i + 1 < nread && buf->base[i + 1] == 'S') {
104  free(buf->base);
106  return;
107  } else {
109  server_closed = 1;
110  }
111  }
112  }
113  }
114 
115  wr = (write_req_t*) malloc(sizeof *wr);
116  ASSERT(wr != NULL);
117  wr->buf = uv_buf_init(buf->base, nread);
118 
119  if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {
120  FATAL("uv_write failed");
121  }
122 }
123 
124 
125 static void on_close(uv_handle_t* peer) {
126  free(peer);
127 }
128 
129 
131  size_t suggested_size,
132  uv_buf_t* buf) {
133  buf->base = malloc(suggested_size);
134  buf->len = suggested_size;
135 }
136 
138  size_t suggested_size,
139  uv_buf_t* buf) {
140  /* up to 16 datagrams at once */
141  static char slab[16 * 64 * 1024];
142  buf->base = slab;
143  buf->len = sizeof(slab);
144 }
145 
148  int r;
149 
150  if (status != 0) {
151  fprintf(stderr, "Connect error %s\n", uv_err_name(status));
152  }
153  ASSERT(status == 0);
154 
155  switch (serverType) {
156  case TCP:
157  stream = malloc(sizeof(uv_tcp_t));
158  ASSERT(stream != NULL);
160  ASSERT(r == 0);
161  break;
162 
163  case PIPE:
164  stream = malloc(sizeof(uv_pipe_t));
165  ASSERT(stream != NULL);
167  ASSERT(r == 0);
168  break;
169 
170  default:
171  ASSERT(0 && "Bad serverType");
172  abort();
173  }
174 
175  /* associate server with stream */
176  stream->data = server;
177 
178  r = uv_accept(server, stream);
179  ASSERT(r == 0);
180 
182  ASSERT(r == 0);
183 }
184 
185 
187  ASSERT(handle == server);
188 }
189 
190 static uv_udp_send_t* send_alloc(void) {
192  if (req != NULL)
193  send_freelist = req->data;
194  else
195  req = malloc(sizeof(*req));
196  return req;
197 }
198 
199 static void on_send(uv_udp_send_t* req, int status) {
200  ASSERT(req != NULL);
201  ASSERT(status == 0);
202  req->data = send_freelist;
203  send_freelist = req;
204 }
205 
206 static void on_recv(uv_udp_t* handle,
207  ssize_t nread,
208  const uv_buf_t* rcvbuf,
209  const struct sockaddr* addr,
210  unsigned flags) {
211  uv_buf_t sndbuf;
212 
213  if (nread == 0) {
214  /* Everything OK, but nothing read. */
215  return;
216  }
217 
218  ASSERT(nread > 0);
219  ASSERT(addr->sa_family == AF_INET);
220 
222  ASSERT(req != NULL);
223  sndbuf = uv_buf_init(rcvbuf->base, nread);
224  ASSERT(0 <= uv_udp_send(req, handle, &sndbuf, 1, addr, on_send));
225 }
226 
227 static int tcp4_echo_start(int port) {
228  struct sockaddr_in addr;
229  int r;
230 
231  ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
232 
234  serverType = TCP;
235 
237  if (r) {
238  /* TODO: Error codes */
239  fprintf(stderr, "Socket creation error\n");
240  return 1;
241  }
242 
243  r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
244  if (r) {
245  /* TODO: Error codes */
246  fprintf(stderr, "Bind error\n");
247  return 1;
248  }
249 
250  r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
251  if (r) {
252  /* TODO: Error codes */
253  fprintf(stderr, "Listen error %s\n", uv_err_name(r));
254  return 1;
255  }
256 
257  return 0;
258 }
259 
260 
261 static int tcp6_echo_start(int port) {
262  struct sockaddr_in6 addr6;
263  int r;
264 
265  ASSERT(0 == uv_ip6_addr("::1", port, &addr6));
266 
268  serverType = TCP;
269 
271  if (r) {
272  /* TODO: Error codes */
273  fprintf(stderr, "Socket creation error\n");
274  return 1;
275  }
276 
277  /* IPv6 is optional as not all platforms support it */
278  r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr6, 0);
279  if (r) {
280  /* show message but return OK */
281  fprintf(stderr, "IPv6 not supported\n");
282  return 0;
283  }
284 
285  r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
286  if (r) {
287  /* TODO: Error codes */
288  fprintf(stderr, "Listen error\n");
289  return 1;
290  }
291 
292  return 0;
293 }
294 
295 
296 static int udp4_echo_start(int port) {
297  struct sockaddr_in addr;
298  int r;
299 
300  ASSERT(0 == uv_ip4_addr("127.0.0.1", port, &addr));
302  serverType = UDP;
303 
305  if (r) {
306  fprintf(stderr, "uv_udp_init: %s\n", uv_strerror(r));
307  return 1;
308  }
309 
310  r = uv_udp_bind(&udpServer, (const struct sockaddr*) &addr, 0);
311  if (r) {
312  fprintf(stderr, "uv_udp_bind: %s\n", uv_strerror(r));
313  return 1;
314  }
315 
317  if (r) {
318  fprintf(stderr, "uv_udp_recv_start: %s\n", uv_strerror(r));
319  return 1;
320  }
321 
322  return 0;
323 }
324 
325 
326 static int pipe_echo_start(char* pipeName) {
327  int r;
328 
329 #ifndef _WIN32
330  {
331  uv_fs_t req;
332  uv_fs_unlink(NULL, &req, pipeName, NULL);
334  }
335 #endif
336 
338  serverType = PIPE;
339 
340  r = uv_pipe_init(loop, &pipeServer, 0);
341  if (r) {
342  fprintf(stderr, "uv_pipe_init: %s\n", uv_strerror(r));
343  return 1;
344  }
345 
346  r = uv_pipe_bind(&pipeServer, pipeName);
347  if (r) {
348  fprintf(stderr, "uv_pipe_bind: %s\n", uv_strerror(r));
349  return 1;
350  }
351 
352  r = uv_listen((uv_stream_t*)&pipeServer, SOMAXCONN, on_connection);
353  if (r) {
354  fprintf(stderr, "uv_pipe_listen: %s\n", uv_strerror(r));
355  return 1;
356  }
357 
358  return 0;
359 }
360 
361 
362 HELPER_IMPL(tcp4_echo_server) {
363  loop = uv_default_loop();
364 
366  return 1;
367 
370  return 0;
371 }
372 
373 
374 HELPER_IMPL(tcp6_echo_server) {
375  loop = uv_default_loop();
376 
378  return 1;
379 
382  return 0;
383 }
384 
385 
386 HELPER_IMPL(pipe_echo_server) {
387  loop = uv_default_loop();
388 
390  return 1;
391 
394  return 0;
395 }
396 
397 
398 HELPER_IMPL(udp4_echo_server) {
399  loop = uv_default_loop();
400 
402  return 1;
403 
406  return 0;
407 }
slab
static char slab[1]
Definition: test-watcher-cross-stop.c:37
uv_ip6_addr
UV_EXTERN int uv_ip6_addr(const char *ip, int port, struct sockaddr_in6 *addr)
Definition: uv-common.c:232
tcpServer
static uv_tcp_t tcpServer
Definition: echo-server.c:36
loop
static uv_loop_t * loop
Definition: echo-server.c:32
on_send
static void on_send(uv_udp_send_t *req, int status)
Definition: echo-server.c:199
task.h
write_req_t::req
uv_write_t req
Definition: worker.c:12
uv_pipe_init
UV_EXTERN int uv_pipe_init(uv_loop_t *, uv_pipe_t *handle, int ipc)
Definition: unix/pipe.c:33
uv_shutdown_s
Definition: uv.h:417
after_read
static void after_read(uv_stream_t *, ssize_t nread, const uv_buf_t *buf)
Definition: echo-server.c:73
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
uv_listen
UV_EXTERN int uv_listen(uv_stream_t *stream, int backlog, uv_connection_cb cb)
Definition: unix/stream.c:656
uv_connect_s::handle
uv_stream_t * handle
Definition: uv.h:583
uv_udp_send
UV_EXTERN int uv_udp_send(uv_udp_send_t *req, uv_udp_t *handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr *addr, uv_udp_send_cb send_cb)
Definition: uv-common.c:408
ASSERT
#define ASSERT(expr)
Definition: task.h:102
write_req_t
Definition: worker.c:11
status
absl::Status status
Definition: rls.cc:251
udpServer
static uv_udp_t udpServer
Definition: echo-server.c:37
tcp6_echo_start
static int tcp6_echo_start(int port)
Definition: echo-server.c:261
uv_strerror
const UV_EXTERN char * uv_strerror(int err)
Definition: uv-common.c:212
uv_run
UV_EXTERN int uv_run(uv_loop_t *, uv_run_mode mode)
Definition: unix/core.c:361
on_server_close
static void on_server_close(uv_handle_t *handle)
Definition: echo-server.c:186
uv_fs_s
Definition: uv.h:1294
echo_alloc
static void echo_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
Definition: echo-server.c:130
uv_tcp_bind
UV_EXTERN int uv_tcp_bind(uv_tcp_t *handle, const struct sockaddr *addr, unsigned int flags)
Definition: uv-common.c:277
TEST_PORT
#define TEST_PORT
Definition: task.h:53
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
uv_close
UV_EXTERN void uv_close(uv_handle_t *handle, uv_close_cb close_cb)
Definition: unix/core.c:112
uv_stream_s
Definition: uv.h:491
uv_ip4_addr
UV_EXTERN int uv_ip4_addr(const char *ip, int port, struct sockaddr_in *addr)
Definition: uv-common.c:221
uv_fs_unlink
UV_EXTERN int uv_fs_unlink(uv_loop_t *loop, uv_fs_t *req, const char *path, uv_fs_cb cb)
Definition: unix/fs.c:1974
uv_default_loop
UV_EXTERN uv_loop_t * uv_default_loop(void)
Definition: uv-common.c:733
uv_udp_init
UV_EXTERN int uv_udp_init(uv_loop_t *, uv_udp_t *handle)
Definition: unix/udp.c:988
ssize_t
intptr_t ssize_t
Definition: win.h:27
sockaddr_in6
Definition: ares_ipv6.h:25
uv_write
UV_EXTERN int uv_write(uv_write_t *req, uv_stream_t *handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb)
Definition: unix/stream.c:1492
send_alloc
static uv_udp_send_t * send_alloc(void)
Definition: echo-server.c:190
req
static uv_connect_t req
Definition: test-connection-fail.c:30
UV_RUN_DEFAULT
@ UV_RUN_DEFAULT
Definition: uv.h:254
uv_udp_s
Definition: uv.h:629
uv_shutdown
UV_PRIVATE_REQ_TYPES UV_EXTERN int uv_shutdown(uv_shutdown_t *req, uv_stream_t *handle, uv_shutdown_cb cb)
Definition: unix/stream.c:1259
HELPER_IMPL
HELPER_IMPL(tcp4_echo_server)
Definition: echo-server.c:362
on_recv
static void on_recv(uv_udp_t *handle, ssize_t nread, const uv_buf_t *rcvbuf, const struct sockaddr *addr, unsigned flags)
Definition: echo-server.c:206
uv_read_start
UV_EXTERN int uv_read_start(uv_stream_t *, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
Definition: unix/stream.c:1555
addr6
static struct sockaddr_in6 addr6
Definition: test-getnameinfo.c:34
UDP
@ UDP
Definition: task.h:83
tcp4_echo_start
static int tcp4_echo_start(int port)
Definition: echo-server.c:227
uv_tcp_init
UV_EXTERN int uv_tcp_init(uv_loop_t *, uv_tcp_t *handle)
Definition: unix/tcp.c:143
uv_accept
UV_EXTERN int uv_accept(uv_stream_t *server, uv_stream_t *client)
Definition: unix/stream.c:591
TCP
@ TCP
Definition: task.h:82
uv_tcp_s
Definition: uv.h:544
uv_buf_t::base
char * base
Definition: unix.h:122
notify_parent_process
void notify_parent_process(void)
Definition: runner-unix.c:54
slab_alloc
static void slab_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
Definition: echo-server.c:137
uv_udp_send_s
Definition: uv.h:645
tests.unit._exit_scenarios.port
port
Definition: _exit_scenarios.py:179
uv.h
uv_udp_recv_start
UV_EXTERN int uv_udp_recv_start(uv_udp_t *handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb)
Definition: uv-common.c:438
FATAL
#define FATAL(msg)
Definition: task.h:88
server_closed
static int server_closed
Definition: echo-server.c:34
uv_buf_t
Definition: unix.h:121
uv_udp_bind
UV_EXTERN int uv_udp_bind(uv_udp_t *handle, const struct sockaddr *addr, unsigned int flags)
Definition: uv-common.c:296
send_freelist
static uv_udp_send_t * send_freelist
Definition: echo-server.c:40
absl::flags_internal
Definition: abseil-cpp/absl/flags/commandlineflag.h:40
server
Definition: examples/python/async_streaming/server.py:1
pipe_echo_start
static int pipe_echo_start(char *pipeName)
Definition: echo-server.c:326
pipeServer
static uv_pipe_t pipeServer
Definition: echo-server.c:38
fix_build_deps.r
r
Definition: fix_build_deps.py:491
write_req_t::buf
uv_buf_t buf
Definition: worker.c:13
PIPE
@ PIPE
Definition: task.h:84
on_connection
static void on_connection(uv_stream_t *, int status)
Definition: echo-server.c:146
uv_pipe_s
Definition: uv.h:757
after_shutdown
static void after_shutdown(uv_shutdown_t *req, int status)
Definition: echo-server.c:67
uv_buf_init
UV_EXTERN uv_buf_t uv_buf_init(char *base, unsigned int len)
Definition: uv-common.c:157
udp4_echo_start
static int udp4_echo_start(int port)
Definition: echo-server.c:296
on_close
static void on_close(uv_handle_t *peer)
Definition: echo-server.c:125
uv_write_s
Definition: uv.h:522
uv_fs_req_cleanup
UV_EXTERN void uv_fs_req_cleanup(uv_fs_t *req)
Definition: unix/fs.c:2024
stream_type
stream_type
Definition: task.h:81
handle
static csh handle
Definition: test_arm_regression.c:16
uv_handle_s
Definition: uv.h:441
TEST_PIPENAME
#define TEST_PIPENAME
Definition: task.h:61
serverType
static stream_type serverType
Definition: echo-server.c:35
uv_loop_s
Definition: uv.h:1767
server
static uv_handle_t * server
Definition: echo-server.c:39
uv_pipe_bind
UV_EXTERN int uv_pipe_bind(uv_pipe_t *handle, const char *name)
Definition: unix/pipe.c:43
uv_err_name
const UV_EXTERN char * uv_err_name(int err)
Definition: uv-common.c:189
after_write
static void after_write(uv_write_t *req, int status)
Definition: echo-server.c:49
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
stream
voidpf stream
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:59:14