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.
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.
10 * This file is being made available by the Samba Team under the following
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.
24 #include <netinet/in.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
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;
41 if (!tevent_req_is_error(req, &state, &err)) {
45 case TEVENT_REQ_TIMED_OUT:
48 case TEVENT_REQ_NO_MEMORY:
51 case TEVENT_REQ_USER_ERROR:
62 * @brief Wrapper around accept(2)
66 struct tevent_fd *fde;
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,
80 struct tevent_req *req;
81 struct accept_state *state;
83 req = tevent_req_create(mem_ctx, &state, struct accept_state);
88 state->listen_sock = listen_sock;
90 state->fde = tevent_add_fd(ev, state, listen_sock, TEVENT_FD_READ,
92 if (tevent_req_nomem(state->fde, req)) {
93 return tevent_req_post(req, ev);
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);
106 TALLOC_FREE(state->fde);
108 if ((flags & TEVENT_FD_READ) == 0) {
109 tevent_req_error(req, EIO);
112 state->addrlen = sizeof(state->addr);
114 ret = accept(state->listen_sock, &state->addr, &state->addrlen);
116 tevent_req_error(req, errno);
120 tevent_req_done(req);
123 static int accept_recv(struct tevent_req *req, struct sockaddr *paddr,
124 socklen_t *paddrlen, int *perr)
126 struct accept_state *state = tevent_req_data(req, struct accept_state);
129 if (tevent_req_is_unix_error(req, &err)) {
136 *paddr = state->addr;
138 if (paddrlen != NULL) {
139 *paddrlen = state->addrlen;
145 * @brief Wrapper around read(2)
149 struct tevent_fd *fde;
157 static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
158 uint16_t flags, void *private_data);
160 static struct tevent_req *read_send(TALLOC_CTX *mem_ctx,
161 struct tevent_context *ev,
162 int fd, void *buf, size_t count)
164 struct tevent_req *req;
165 struct read_state *state;
167 req = tevent_req_create(mem_ctx, &state, struct read_state);
174 state->count = count;
176 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
178 if (tevent_req_nomem(state->fde, req)) {
179 return tevent_req_post(req, ev);
184 static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
185 uint16_t flags, void *private_data)
187 struct tevent_req *req = talloc_get_type_abort(
188 private_data, struct tevent_req);
189 struct read_state *state = tevent_req_data(req, struct read_state);
192 TALLOC_FREE(state->fde);
194 if ((flags & TEVENT_FD_READ) == 0) {
195 tevent_req_error(req, EIO);
199 ret = read(state->fd, state->buf, state->count);
201 tevent_req_error(req, errno);
205 tevent_req_done(req);
208 static ssize_t read_recv(struct tevent_req *req, int *perr)
210 struct read_state *state = tevent_req_data(req, struct read_state);
213 if (tevent_req_is_unix_error(req, &err)) {
223 * @brief Wrapper around write(2)
227 struct tevent_fd *fde;
235 static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
236 uint16_t flags, void *private_data);
238 static struct tevent_req *write_send(TALLOC_CTX *mem_ctx,
239 struct tevent_context *ev,
240 int fd, const void *buf, size_t count)
242 struct tevent_req *req;
243 struct write_state *state;
245 req = tevent_req_create(mem_ctx, &state, struct write_state);
252 state->count = count;
254 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE,
256 if (tevent_req_nomem(state->fde, req)) {
257 return tevent_req_post(req, ev);
262 static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
263 uint16_t flags, void *private_data)
265 struct tevent_req *req = talloc_get_type_abort(
266 private_data, struct tevent_req);
267 struct write_state *state = tevent_req_data(req, struct write_state);
270 TALLOC_FREE(state->fde);
272 if ((flags & TEVENT_FD_WRITE) == 0) {
273 tevent_req_error(req, EIO);
277 ret = write(state->fd, state->buf, state->count);
279 tevent_req_error(req, errno);
282 state->nwritten = ret;
283 tevent_req_done(req);
286 static ssize_t write_recv(struct tevent_req *req, int *perr)
288 struct write_state *state = tevent_req_data(req, struct write_state);
291 if (tevent_req_is_unix_error(req, &err)) {
297 return state->nwritten;
301 * @brief Wrapper function that deals with short writes
304 struct writeall_state {
305 struct tevent_context *ev;
312 static void writeall_done(struct tevent_req *subreq);
314 static struct tevent_req *writeall_send(TALLOC_CTX *mem_ctx,
315 struct tevent_context *ev,
316 int fd, const void *buf, size_t count)
318 struct tevent_req *req, *subreq;
319 struct writeall_state *state;
321 req = tevent_req_create(mem_ctx, &state, struct writeall_state);
328 state->count = count;
331 subreq = write_send(state, state->ev, state->fd,
332 ((char *)state->buf)+state->nwritten,
333 state->count - state->nwritten);
334 if (tevent_req_nomem(subreq, req)) {
335 return tevent_req_post(req, ev);
337 tevent_req_set_callback(subreq, writeall_done, req);
341 static void writeall_done(struct tevent_req *subreq)
343 struct tevent_req *req = tevent_req_callback_data(
344 subreq, struct tevent_req);
345 struct writeall_state *state = tevent_req_data(
346 req, struct writeall_state);
350 nwritten = write_recv(subreq, &err);
352 if (nwritten == -1) {
353 tevent_req_error(req, err);
357 state->nwritten += nwritten;
359 if (state->nwritten < state->count) {
360 subreq = write_send(state, state->ev, state->fd,
361 ((char *)state->buf)+state->nwritten,
362 state->count - state->nwritten);
363 if (tevent_req_nomem(subreq, req)) {
366 tevent_req_set_callback(subreq, writeall_done, req);
369 tevent_req_done(req);
372 static ssize_t writeall_recv(struct tevent_req *req, int *perr)
374 struct writeall_state *state = tevent_req_data(
375 req, struct writeall_state);
378 if (tevent_req_is_unix_error(req, &err)) {
384 return state->nwritten;
388 * @brief Async echo handler code dealing with one client
392 struct tevent_context *ev;
397 static int echo_state_destructor(struct echo_state *s);
398 static void echo_read_done(struct tevent_req *subreq);
399 static void echo_writeall_done(struct tevent_req *subreq);
401 static struct tevent_req *echo_send(TALLOC_CTX *mem_ctx,
402 struct tevent_context *ev,
403 int fd, size_t bufsize)
405 struct tevent_req *req, *subreq;
406 struct echo_state *state;
408 req = tevent_req_create(mem_ctx, &state, struct echo_state);
415 talloc_set_destructor(state, echo_state_destructor);
417 state->buf = talloc_array(state, uint8_t, bufsize);
418 if (tevent_req_nomem(state->buf, req)) {
419 return tevent_req_post(req, ev);
422 subreq = read_send(state, state->ev, state->fd,
423 state->buf, talloc_get_size(state->buf));
424 if (tevent_req_nomem(subreq, req)) {
425 return tevent_req_post(req, ev);
427 tevent_req_set_callback(subreq, echo_read_done, req);
431 static int echo_state_destructor(struct echo_state *s)
434 printf("Closing client fd %d\n", s->fd);
441 static void echo_read_done(struct tevent_req *subreq)
443 struct tevent_req *req = tevent_req_callback_data(
444 subreq, struct tevent_req);
445 struct echo_state *state = tevent_req_data(
446 req, struct echo_state);
450 nread = read_recv(subreq, &err);
453 tevent_req_error(req, err);
457 tevent_req_done(req);
461 subreq = writeall_send(state, state->ev, state->fd, state->buf, nread);
462 if (tevent_req_nomem(subreq, req)) {
465 tevent_req_set_callback(subreq, echo_writeall_done, req);
468 static void echo_writeall_done(struct tevent_req *subreq)
470 struct tevent_req *req = tevent_req_callback_data(
471 subreq, struct tevent_req);
472 struct echo_state *state = tevent_req_data(
473 req, struct echo_state);
477 nwritten = writeall_recv(subreq, &err);
479 if (nwritten == -1) {
481 tevent_req_done(req);
484 tevent_req_error(req, err);
488 subreq = read_send(state, state->ev, state->fd,
489 state->buf, talloc_get_size(state->buf));
490 if (tevent_req_nomem(subreq, req)) {
493 tevent_req_set_callback(subreq, echo_read_done, req);
496 static bool echo_recv(struct tevent_req *req, int *perr)
500 if (tevent_req_is_unix_error(req, &err)) {
508 * @brief Full echo handler code accepting and handling clients
511 struct echo_server_state {
512 struct tevent_context *ev;
516 static void echo_server_accepted(struct tevent_req *subreq);
517 static void echo_server_client_done(struct tevent_req *subreq);
519 static struct tevent_req *echo_server_send(TALLOC_CTX *mem_ctx,
520 struct tevent_context *ev,
523 struct tevent_req *req, *subreq;
524 struct echo_server_state *state;
526 req = tevent_req_create(mem_ctx, &state,
527 struct echo_server_state);
532 state->listen_sock = listen_sock;
534 subreq = accept_send(state, state->ev, state->listen_sock);
535 if (tevent_req_nomem(subreq, req)) {
536 return tevent_req_post(req, ev);
538 tevent_req_set_callback(subreq, echo_server_accepted, req);
542 static void echo_server_accepted(struct tevent_req *subreq)
544 struct tevent_req *req = tevent_req_callback_data(
545 subreq, struct tevent_req);
546 struct echo_server_state *state = tevent_req_data(
547 req, struct echo_server_state);
550 sock = accept_recv(subreq, NULL, NULL, &err);
553 tevent_req_error(req, err);
557 printf("new client fd %d\n", sock);
559 subreq = echo_send(state, state->ev, sock, 100);
560 if (tevent_req_nomem(subreq, req)) {
563 tevent_req_set_callback(subreq, echo_server_client_done, req);
565 subreq = accept_send(state, state->ev, state->listen_sock);
566 if (tevent_req_nomem(subreq, req)) {
569 tevent_req_set_callback(subreq, echo_server_accepted, req);
572 static void echo_server_client_done(struct tevent_req *subreq)
577 ret = echo_recv(subreq, &err);
581 printf("Client done\n");
583 printf("Client failed: %s\n", strerror(err));
587 static bool echo_server_recv(struct tevent_req *req, int *perr)
591 if (tevent_req_is_unix_error(req, &err)) {
598 int main(int argc, const char **argv)
600 int ret, port, listen_sock, err;
601 struct tevent_context *ev;
602 struct sockaddr_in addr;
603 struct tevent_req *req;
607 fprintf(stderr, "Usage: %s <port>\n", argv[0]);
611 port = atoi(argv[1]);
613 printf("listening on port %d\n", port);
615 listen_sock = socket(AF_INET, SOCK_STREAM, 0);
617 if (listen_sock == -1) {
618 perror("socket() failed");
622 addr = (struct sockaddr_in) {
623 .sin_family = AF_INET,
624 .sin_port = htons(port)
627 ret = bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
629 perror("bind() failed");
633 ret = listen(listen_sock, 5);
635 perror("listen() failed");
639 ev = tevent_context_init(NULL);
641 fprintf(stderr, "tevent_context_init failed\n");
645 req = echo_server_send(ev, ev, listen_sock);
647 fprintf(stderr, "echo_server_send failed\n");
651 if (!tevent_req_poll(req, ev)) {
652 perror("tevent_req_poll() failed");
656 result = echo_server_recv(req, &err);
659 fprintf(stderr, "echo_server failed: %s\n", strerror(err));