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
;
69 struct sockaddr_storage addr
;
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
,
115 (struct sockaddr
*)&state
->addr
,
118 tevent_req_error(req
, errno
);
121 smb_set_close_on_exec(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
);
132 if (tevent_req_is_unix_error(req
, &err
)) {
139 memcpy(paddr
, &state
->addr
, state
->addrlen
);
141 if (paddrlen
!= NULL
) {
142 *paddrlen
= state
->addrlen
;
148 * @brief Wrapper around read(2)
152 struct tevent_fd
*fde
;
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
);
177 state
->count
= count
;
179 state
->fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
,
181 if (tevent_req_nomem(state
->fde
, req
)) {
182 return tevent_req_post(req
, ev
);
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
);
195 TALLOC_FREE(state
->fde
);
197 if ((flags
& TEVENT_FD_READ
) == 0) {
198 tevent_req_error(req
, EIO
);
202 ret
= read(state
->fd
, state
->buf
, state
->count
);
204 tevent_req_error(req
, errno
);
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
);
216 if (tevent_req_is_unix_error(req
, &err
)) {
226 * @brief Wrapper around write(2)
230 struct tevent_fd
*fde
;
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
);
255 state
->count
= count
;
257 state
->fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_WRITE
,
259 if (tevent_req_nomem(state
->fde
, req
)) {
260 return tevent_req_post(req
, ev
);
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
);
273 TALLOC_FREE(state
->fde
);
275 if ((flags
& TEVENT_FD_WRITE
) == 0) {
276 tevent_req_error(req
, EIO
);
280 ret
= write(state
->fd
, state
->buf
, state
->count
);
282 tevent_req_error(req
, errno
);
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
);
294 if (tevent_req_is_unix_error(req
, &err
)) {
300 return state
->nwritten
;
304 * @brief Wrapper function that deals with short writes
307 struct writeall_state
{
308 struct tevent_context
*ev
;
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
);
331 state
->count
= count
;
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
);
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
);
353 nwritten
= write_recv(subreq
, &err
);
355 if (nwritten
== -1) {
356 tevent_req_error(req
, err
);
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
)) {
369 tevent_req_set_callback(subreq
, writeall_done
, req
);
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
);
381 if (tevent_req_is_unix_error(req
, &err
)) {
387 return state
->nwritten
;
391 * @brief Async echo handler code dealing with one client
395 struct tevent_context
*ev
;
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
);
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
);
434 static int echo_state_destructor(struct echo_state
*s
)
437 printf("Closing client fd %d\n", s
->fd
);
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
);
453 nread
= read_recv(subreq
, &err
);
456 tevent_req_error(req
, err
);
460 tevent_req_done(req
);
464 subreq
= writeall_send(state
, state
->ev
, state
->fd
, state
->buf
, nread
);
465 if (tevent_req_nomem(subreq
, req
)) {
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
);
480 nwritten
= writeall_recv(subreq
, &err
);
482 if (nwritten
== -1) {
484 tevent_req_done(req
);
487 tevent_req_error(req
, err
);
491 subreq
= read_send(state
, state
->ev
, state
->fd
,
492 state
->buf
, talloc_get_size(state
->buf
));
493 if (tevent_req_nomem(subreq
, req
)) {
496 tevent_req_set_callback(subreq
, echo_read_done
, req
);
499 static bool echo_recv(struct tevent_req
*req
, int *perr
)
503 if (tevent_req_is_unix_error(req
, &err
)) {
511 * @brief Full echo handler code accepting and handling clients
514 struct echo_server_state
{
515 struct tevent_context
*ev
;
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
,
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
);
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
);
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
);
553 sock
= accept_recv(subreq
, NULL
, NULL
, &err
);
556 tevent_req_error(req
, err
);
560 printf("new client fd %d\n", sock
);
562 subreq
= echo_send(state
, state
->ev
, sock
, 100);
563 if (tevent_req_nomem(subreq
, req
)) {
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
)) {
572 tevent_req_set_callback(subreq
, echo_server_accepted
, req
);
575 static void echo_server_client_done(struct tevent_req
*subreq
)
580 ret
= echo_recv(subreq
, &err
);
584 printf("Client done\n");
586 printf("Client failed: %s\n", strerror(err
));
590 static bool echo_server_recv(struct tevent_req
*req
, int *perr
)
594 if (tevent_req_is_unix_error(req
, &err
)) {
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
;
610 fprintf(stderr
, "Usage: %s <port>\n", argv
[0]);
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");
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
));
632 perror("bind() failed");
636 ret
= listen(listen_sock
, 5);
638 perror("listen() failed");
642 ev
= tevent_context_init(NULL
);
644 fprintf(stderr
, "tevent_context_init failed\n");
648 req
= echo_server_send(ev
, ev
, listen_sock
);
650 fprintf(stderr
, "echo_server_send failed\n");
654 if (!tevent_req_poll(req
, ev
)) {
655 perror("tevent_req_poll() failed");
659 result
= echo_server_recv(req
, &err
);
662 fprintf(stderr
, "echo_server failed: %s\n", strerror(err
));