VERSION: Bump version up to 4.10.8...
[Samba.git] / lib / tevent / echo_server.c
blobf93d8bcdee7200ca66bac11a3a2b202c55678acc
1 /**
2 ** NOTE! The following liberal license applies to this sample file only.
3 ** This does NOT imply that all of Samba is released under this license.
4 **
5 ** This file is meant as a starting point for libtevent users to be used
6 ** in any program linking against the LGPL licensed libtevent.
7 **/
9 /*
10 * This file is being made available by the Samba Team under the following
11 * license:
13 * Permission to use, copy, modify, and distribute this sample file for any
14 * purpose is hereby granted without fee.
16 * This work is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <netinet/in.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include "tevent.h"
30 #include "talloc.h"
32 /**
33 * @brief Helper function to get a useful unix error from tevent_req
36 static bool tevent_req_is_unix_error(struct tevent_req *req, int *perrno)
38 enum tevent_req_state state;
39 uint64_t err;
41 if (!tevent_req_is_error(req, &state, &err)) {
42 return false;
44 switch (state) {
45 case TEVENT_REQ_TIMED_OUT:
46 *perrno = ETIMEDOUT;
47 break;
48 case TEVENT_REQ_NO_MEMORY:
49 *perrno = ENOMEM;
50 break;
51 case TEVENT_REQ_USER_ERROR:
52 *perrno = err;
53 break;
54 default:
55 *perrno = EINVAL;
56 break;
58 return true;
61 /**
62 * @brief Wrapper around accept(2)
65 struct accept_state {
66 struct tevent_fd *fde;
67 int listen_sock;
68 socklen_t addrlen;
69 struct sockaddr_storage addr;
70 int sock;
73 static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
74 uint16_t flags, void *private_data);
76 static struct tevent_req *accept_send(TALLOC_CTX *mem_ctx,
77 struct tevent_context *ev,
78 int listen_sock)
80 struct tevent_req *req;
81 struct accept_state *state;
83 req = tevent_req_create(mem_ctx, &state, struct accept_state);
84 if (req == NULL) {
85 return NULL;
88 state->listen_sock = listen_sock;
90 state->fde = tevent_add_fd(ev, state, listen_sock, TEVENT_FD_READ,
91 accept_handler, req);
92 if (tevent_req_nomem(state->fde, req)) {
93 return tevent_req_post(req, ev);
95 return req;
98 static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
99 uint16_t flags, void *private_data)
101 struct tevent_req *req = talloc_get_type_abort(
102 private_data, struct tevent_req);
103 struct accept_state *state = tevent_req_data(req, struct accept_state);
104 int ret;
106 TALLOC_FREE(state->fde);
108 if ((flags & TEVENT_FD_READ) == 0) {
109 tevent_req_error(req, EIO);
110 return;
112 state->addrlen = sizeof(state->addr);
114 ret = accept(state->listen_sock,
115 (struct sockaddr *)&state->addr,
116 &state->addrlen);
117 if (ret == -1) {
118 tevent_req_error(req, errno);
119 return;
121 smb_set_close_on_exec(ret);
122 state->sock = ret;
123 tevent_req_done(req);
126 static int accept_recv(struct tevent_req *req, struct sockaddr *paddr,
127 socklen_t *paddrlen, int *perr)
129 struct accept_state *state = tevent_req_data(req, struct accept_state);
130 int err;
132 if (tevent_req_is_unix_error(req, &err)) {
133 if (perr != NULL) {
134 *perr = err;
136 return -1;
138 if (paddr != NULL) {
139 memcpy(paddr, &state->addr, state->addrlen);
141 if (paddrlen != NULL) {
142 *paddrlen = state->addrlen;
144 return state->sock;
148 * @brief Wrapper around read(2)
151 struct read_state {
152 struct tevent_fd *fde;
153 int fd;
154 void *buf;
155 size_t count;
157 ssize_t nread;
160 static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
161 uint16_t flags, void *private_data);
163 static struct tevent_req *read_send(TALLOC_CTX *mem_ctx,
164 struct tevent_context *ev,
165 int fd, void *buf, size_t count)
167 struct tevent_req *req;
168 struct read_state *state;
170 req = tevent_req_create(mem_ctx, &state, struct read_state);
171 if (req == NULL) {
172 return NULL;
175 state->fd = fd;
176 state->buf = buf;
177 state->count = count;
179 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
180 read_handler, req);
181 if (tevent_req_nomem(state->fde, req)) {
182 return tevent_req_post(req, ev);
184 return req;
187 static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
188 uint16_t flags, void *private_data)
190 struct tevent_req *req = talloc_get_type_abort(
191 private_data, struct tevent_req);
192 struct read_state *state = tevent_req_data(req, struct read_state);
193 ssize_t ret;
195 TALLOC_FREE(state->fde);
197 if ((flags & TEVENT_FD_READ) == 0) {
198 tevent_req_error(req, EIO);
199 return;
202 ret = read(state->fd, state->buf, state->count);
203 if (ret == -1) {
204 tevent_req_error(req, errno);
205 return;
207 state->nread = ret;
208 tevent_req_done(req);
211 static ssize_t read_recv(struct tevent_req *req, int *perr)
213 struct read_state *state = tevent_req_data(req, struct read_state);
214 int err;
216 if (tevent_req_is_unix_error(req, &err)) {
217 if (perr != NULL) {
218 *perr = err;
220 return -1;
222 return state->nread;
226 * @brief Wrapper around write(2)
229 struct write_state {
230 struct tevent_fd *fde;
231 int fd;
232 const void *buf;
233 size_t count;
235 ssize_t nwritten;
238 static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
239 uint16_t flags, void *private_data);
241 static struct tevent_req *write_send(TALLOC_CTX *mem_ctx,
242 struct tevent_context *ev,
243 int fd, const void *buf, size_t count)
245 struct tevent_req *req;
246 struct write_state *state;
248 req = tevent_req_create(mem_ctx, &state, struct write_state);
249 if (req == NULL) {
250 return NULL;
253 state->fd = fd;
254 state->buf = buf;
255 state->count = count;
257 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE,
258 write_handler, req);
259 if (tevent_req_nomem(state->fde, req)) {
260 return tevent_req_post(req, ev);
262 return req;
265 static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
266 uint16_t flags, void *private_data)
268 struct tevent_req *req = talloc_get_type_abort(
269 private_data, struct tevent_req);
270 struct write_state *state = tevent_req_data(req, struct write_state);
271 ssize_t ret;
273 TALLOC_FREE(state->fde);
275 if ((flags & TEVENT_FD_WRITE) == 0) {
276 tevent_req_error(req, EIO);
277 return;
280 ret = write(state->fd, state->buf, state->count);
281 if (ret == -1) {
282 tevent_req_error(req, errno);
283 return;
285 state->nwritten = ret;
286 tevent_req_done(req);
289 static ssize_t write_recv(struct tevent_req *req, int *perr)
291 struct write_state *state = tevent_req_data(req, struct write_state);
292 int err;
294 if (tevent_req_is_unix_error(req, &err)) {
295 if (perr != NULL) {
296 *perr = err;
298 return -1;
300 return state->nwritten;
304 * @brief Wrapper function that deals with short writes
307 struct writeall_state {
308 struct tevent_context *ev;
309 int fd;
310 const void *buf;
311 size_t count;
312 size_t nwritten;
315 static void writeall_done(struct tevent_req *subreq);
317 static struct tevent_req *writeall_send(TALLOC_CTX *mem_ctx,
318 struct tevent_context *ev,
319 int fd, const void *buf, size_t count)
321 struct tevent_req *req, *subreq;
322 struct writeall_state *state;
324 req = tevent_req_create(mem_ctx, &state, struct writeall_state);
325 if (req == NULL) {
326 return NULL;
328 state->ev = ev;
329 state->fd = fd;
330 state->buf = buf;
331 state->count = count;
332 state->nwritten = 0;
334 subreq = write_send(state, state->ev, state->fd,
335 ((char *)state->buf)+state->nwritten,
336 state->count - state->nwritten);
337 if (tevent_req_nomem(subreq, req)) {
338 return tevent_req_post(req, ev);
340 tevent_req_set_callback(subreq, writeall_done, req);
341 return req;
344 static void writeall_done(struct tevent_req *subreq)
346 struct tevent_req *req = tevent_req_callback_data(
347 subreq, struct tevent_req);
348 struct writeall_state *state = tevent_req_data(
349 req, struct writeall_state);
350 ssize_t nwritten;
351 int err = 0;
353 nwritten = write_recv(subreq, &err);
354 TALLOC_FREE(subreq);
355 if (nwritten == -1) {
356 tevent_req_error(req, err);
357 return;
360 state->nwritten += nwritten;
362 if (state->nwritten < state->count) {
363 subreq = write_send(state, state->ev, state->fd,
364 ((char *)state->buf)+state->nwritten,
365 state->count - state->nwritten);
366 if (tevent_req_nomem(subreq, req)) {
367 return;
369 tevent_req_set_callback(subreq, writeall_done, req);
370 return;
372 tevent_req_done(req);
375 static ssize_t writeall_recv(struct tevent_req *req, int *perr)
377 struct writeall_state *state = tevent_req_data(
378 req, struct writeall_state);
379 int err;
381 if (tevent_req_is_unix_error(req, &err)) {
382 if (perr != NULL) {
383 *perr = err;
385 return -1;
387 return state->nwritten;
391 * @brief Async echo handler code dealing with one client
394 struct echo_state {
395 struct tevent_context *ev;
396 int fd;
397 uint8_t *buf;
400 static int echo_state_destructor(struct echo_state *s);
401 static void echo_read_done(struct tevent_req *subreq);
402 static void echo_writeall_done(struct tevent_req *subreq);
404 static struct tevent_req *echo_send(TALLOC_CTX *mem_ctx,
405 struct tevent_context *ev,
406 int fd, size_t bufsize)
408 struct tevent_req *req, *subreq;
409 struct echo_state *state;
411 req = tevent_req_create(mem_ctx, &state, struct echo_state);
412 if (req == NULL) {
413 return NULL;
415 state->ev = ev;
416 state->fd = fd;
418 talloc_set_destructor(state, echo_state_destructor);
420 state->buf = talloc_array(state, uint8_t, bufsize);
421 if (tevent_req_nomem(state->buf, req)) {
422 return tevent_req_post(req, ev);
425 subreq = read_send(state, state->ev, state->fd,
426 state->buf, talloc_get_size(state->buf));
427 if (tevent_req_nomem(subreq, req)) {
428 return tevent_req_post(req, ev);
430 tevent_req_set_callback(subreq, echo_read_done, req);
431 return req;
434 static int echo_state_destructor(struct echo_state *s)
436 if (s->fd != -1) {
437 printf("Closing client fd %d\n", s->fd);
438 close(s->fd);
439 s->fd = -1;
441 return 0;
444 static void echo_read_done(struct tevent_req *subreq)
446 struct tevent_req *req = tevent_req_callback_data(
447 subreq, struct tevent_req);
448 struct echo_state *state = tevent_req_data(
449 req, struct echo_state);
450 ssize_t nread;
451 int err;
453 nread = read_recv(subreq, &err);
454 TALLOC_FREE(subreq);
455 if (nread == -1) {
456 tevent_req_error(req, err);
457 return;
459 if (nread == 0) {
460 tevent_req_done(req);
461 return;
464 subreq = writeall_send(state, state->ev, state->fd, state->buf, nread);
465 if (tevent_req_nomem(subreq, req)) {
466 return;
468 tevent_req_set_callback(subreq, echo_writeall_done, req);
471 static void echo_writeall_done(struct tevent_req *subreq)
473 struct tevent_req *req = tevent_req_callback_data(
474 subreq, struct tevent_req);
475 struct echo_state *state = tevent_req_data(
476 req, struct echo_state);
477 ssize_t nwritten;
478 int err;
480 nwritten = writeall_recv(subreq, &err);
481 TALLOC_FREE(subreq);
482 if (nwritten == -1) {
483 if (err == EPIPE) {
484 tevent_req_done(req);
485 return;
487 tevent_req_error(req, err);
488 return;
491 subreq = read_send(state, state->ev, state->fd,
492 state->buf, talloc_get_size(state->buf));
493 if (tevent_req_nomem(subreq, req)) {
494 return;
496 tevent_req_set_callback(subreq, echo_read_done, req);
499 static bool echo_recv(struct tevent_req *req, int *perr)
501 int err;
503 if (tevent_req_is_unix_error(req, &err)) {
504 *perr = err;
505 return false;
507 return true;
511 * @brief Full echo handler code accepting and handling clients
514 struct echo_server_state {
515 struct tevent_context *ev;
516 int listen_sock;
519 static void echo_server_accepted(struct tevent_req *subreq);
520 static void echo_server_client_done(struct tevent_req *subreq);
522 static struct tevent_req *echo_server_send(TALLOC_CTX *mem_ctx,
523 struct tevent_context *ev,
524 int listen_sock)
526 struct tevent_req *req, *subreq;
527 struct echo_server_state *state;
529 req = tevent_req_create(mem_ctx, &state,
530 struct echo_server_state);
531 if (req == NULL) {
532 return NULL;
534 state->ev = ev;
535 state->listen_sock = listen_sock;
537 subreq = accept_send(state, state->ev, state->listen_sock);
538 if (tevent_req_nomem(subreq, req)) {
539 return tevent_req_post(req, ev);
541 tevent_req_set_callback(subreq, echo_server_accepted, req);
542 return req;
545 static void echo_server_accepted(struct tevent_req *subreq)
547 struct tevent_req *req = tevent_req_callback_data(
548 subreq, struct tevent_req);
549 struct echo_server_state *state = tevent_req_data(
550 req, struct echo_server_state);
551 int sock, err;
553 sock = accept_recv(subreq, NULL, NULL, &err);
554 TALLOC_FREE(subreq);
555 if (sock == -1) {
556 tevent_req_error(req, err);
557 return;
560 printf("new client fd %d\n", sock);
562 subreq = echo_send(state, state->ev, sock, 100);
563 if (tevent_req_nomem(subreq, req)) {
564 return;
566 tevent_req_set_callback(subreq, echo_server_client_done, req);
568 subreq = accept_send(state, state->ev, state->listen_sock);
569 if (tevent_req_nomem(subreq, req)) {
570 return;
572 tevent_req_set_callback(subreq, echo_server_accepted, req);
575 static void echo_server_client_done(struct tevent_req *subreq)
577 bool ret;
578 int err;
580 ret = echo_recv(subreq, &err);
581 TALLOC_FREE(subreq);
583 if (ret) {
584 printf("Client done\n");
585 } else {
586 printf("Client failed: %s\n", strerror(err));
590 static bool echo_server_recv(struct tevent_req *req, int *perr)
592 int err;
594 if (tevent_req_is_unix_error(req, &err)) {
595 *perr = err;
596 return false;
598 return true;
601 int main(int argc, const char **argv)
603 int ret, port, listen_sock, err;
604 struct tevent_context *ev;
605 struct sockaddr_in addr;
606 struct tevent_req *req;
607 bool result;
609 if (argc != 2) {
610 fprintf(stderr, "Usage: %s <port>\n", argv[0]);
611 exit(1);
614 port = atoi(argv[1]);
616 printf("listening on port %d\n", port);
618 listen_sock = socket(AF_INET, SOCK_STREAM, 0);
620 if (listen_sock == -1) {
621 perror("socket() failed");
622 exit(1);
625 addr = (struct sockaddr_in) {
626 .sin_family = AF_INET,
627 .sin_port = htons(port)
630 ret = bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
631 if (ret == -1) {
632 perror("bind() failed");
633 exit(1);
636 ret = listen(listen_sock, 5);
637 if (ret == -1) {
638 perror("listen() failed");
639 exit(1);
642 ev = tevent_context_init(NULL);
643 if (ev == NULL) {
644 fprintf(stderr, "tevent_context_init failed\n");
645 exit(1);
648 req = echo_server_send(ev, ev, listen_sock);
649 if (req == NULL) {
650 fprintf(stderr, "echo_server_send failed\n");
651 exit(1);
654 if (!tevent_req_poll(req, ev)) {
655 perror("tevent_req_poll() failed");
656 exit(1);
659 result = echo_server_recv(req, &err);
660 TALLOC_FREE(req);
661 if (!result) {
662 fprintf(stderr, "echo_server failed: %s\n", strerror(err));
663 exit(1);
666 return 0;