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
));