s4:kdc: only map SDB_ERR_NOT_FOUND_HERE to HDB_ERR_NOT_FOUND_HERE
[Samba.git] / lib / tevent / echo_server.c
blob6e7f1811f42fe3388be758ec2db389f5a1bf79fb
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 state->sock = ret;
122 tevent_req_done(req);
125 static int accept_recv(struct tevent_req *req, struct sockaddr *paddr,
126 socklen_t *paddrlen, int *perr)
128 struct accept_state *state = tevent_req_data(req, struct accept_state);
129 int err;
131 if (tevent_req_is_unix_error(req, &err)) {
132 if (perr != NULL) {
133 *perr = err;
135 return -1;
137 if (paddr != NULL) {
138 memcpy(paddr, &state->addr, state->addrlen);
140 if (paddrlen != NULL) {
141 *paddrlen = state->addrlen;
143 return state->sock;
147 * @brief Wrapper around read(2)
150 struct read_state {
151 struct tevent_fd *fde;
152 int fd;
153 void *buf;
154 size_t count;
156 ssize_t nread;
159 static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
160 uint16_t flags, void *private_data);
162 static struct tevent_req *read_send(TALLOC_CTX *mem_ctx,
163 struct tevent_context *ev,
164 int fd, void *buf, size_t count)
166 struct tevent_req *req;
167 struct read_state *state;
169 req = tevent_req_create(mem_ctx, &state, struct read_state);
170 if (req == NULL) {
171 return NULL;
174 state->fd = fd;
175 state->buf = buf;
176 state->count = count;
178 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
179 read_handler, req);
180 if (tevent_req_nomem(state->fde, req)) {
181 return tevent_req_post(req, ev);
183 return req;
186 static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
187 uint16_t flags, void *private_data)
189 struct tevent_req *req = talloc_get_type_abort(
190 private_data, struct tevent_req);
191 struct read_state *state = tevent_req_data(req, struct read_state);
192 ssize_t ret;
194 TALLOC_FREE(state->fde);
196 if ((flags & TEVENT_FD_READ) == 0) {
197 tevent_req_error(req, EIO);
198 return;
201 ret = read(state->fd, state->buf, state->count);
202 if (ret == -1) {
203 tevent_req_error(req, errno);
204 return;
206 state->nread = ret;
207 tevent_req_done(req);
210 static ssize_t read_recv(struct tevent_req *req, int *perr)
212 struct read_state *state = tevent_req_data(req, struct read_state);
213 int err;
215 if (tevent_req_is_unix_error(req, &err)) {
216 if (perr != NULL) {
217 *perr = err;
219 return -1;
221 return state->nread;
225 * @brief Wrapper around write(2)
228 struct write_state {
229 struct tevent_fd *fde;
230 int fd;
231 const void *buf;
232 size_t count;
234 ssize_t nwritten;
237 static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
238 uint16_t flags, void *private_data);
240 static struct tevent_req *write_send(TALLOC_CTX *mem_ctx,
241 struct tevent_context *ev,
242 int fd, const void *buf, size_t count)
244 struct tevent_req *req;
245 struct write_state *state;
247 req = tevent_req_create(mem_ctx, &state, struct write_state);
248 if (req == NULL) {
249 return NULL;
252 state->fd = fd;
253 state->buf = buf;
254 state->count = count;
256 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE,
257 write_handler, req);
258 if (tevent_req_nomem(state->fde, req)) {
259 return tevent_req_post(req, ev);
261 return req;
264 static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
265 uint16_t flags, void *private_data)
267 struct tevent_req *req = talloc_get_type_abort(
268 private_data, struct tevent_req);
269 struct write_state *state = tevent_req_data(req, struct write_state);
270 ssize_t ret;
272 TALLOC_FREE(state->fde);
274 if ((flags & TEVENT_FD_WRITE) == 0) {
275 tevent_req_error(req, EIO);
276 return;
279 ret = write(state->fd, state->buf, state->count);
280 if (ret == -1) {
281 tevent_req_error(req, errno);
282 return;
284 state->nwritten = ret;
285 tevent_req_done(req);
288 static ssize_t write_recv(struct tevent_req *req, int *perr)
290 struct write_state *state = tevent_req_data(req, struct write_state);
291 int err;
293 if (tevent_req_is_unix_error(req, &err)) {
294 if (perr != NULL) {
295 *perr = err;
297 return -1;
299 return state->nwritten;
303 * @brief Wrapper function that deals with short writes
306 struct writeall_state {
307 struct tevent_context *ev;
308 int fd;
309 const void *buf;
310 size_t count;
311 size_t nwritten;
314 static void writeall_done(struct tevent_req *subreq);
316 static struct tevent_req *writeall_send(TALLOC_CTX *mem_ctx,
317 struct tevent_context *ev,
318 int fd, const void *buf, size_t count)
320 struct tevent_req *req, *subreq;
321 struct writeall_state *state;
323 req = tevent_req_create(mem_ctx, &state, struct writeall_state);
324 if (req == NULL) {
325 return NULL;
327 state->ev = ev;
328 state->fd = fd;
329 state->buf = buf;
330 state->count = count;
331 state->nwritten = 0;
333 subreq = write_send(state, state->ev, state->fd,
334 ((char *)state->buf)+state->nwritten,
335 state->count - state->nwritten);
336 if (tevent_req_nomem(subreq, req)) {
337 return tevent_req_post(req, ev);
339 tevent_req_set_callback(subreq, writeall_done, req);
340 return req;
343 static void writeall_done(struct tevent_req *subreq)
345 struct tevent_req *req = tevent_req_callback_data(
346 subreq, struct tevent_req);
347 struct writeall_state *state = tevent_req_data(
348 req, struct writeall_state);
349 ssize_t nwritten;
350 int err = 0;
352 nwritten = write_recv(subreq, &err);
353 TALLOC_FREE(subreq);
354 if (nwritten == -1) {
355 tevent_req_error(req, err);
356 return;
359 state->nwritten += nwritten;
361 if (state->nwritten < state->count) {
362 subreq = write_send(state, state->ev, state->fd,
363 ((char *)state->buf)+state->nwritten,
364 state->count - state->nwritten);
365 if (tevent_req_nomem(subreq, req)) {
366 return;
368 tevent_req_set_callback(subreq, writeall_done, req);
369 return;
371 tevent_req_done(req);
374 static ssize_t writeall_recv(struct tevent_req *req, int *perr)
376 struct writeall_state *state = tevent_req_data(
377 req, struct writeall_state);
378 int err;
380 if (tevent_req_is_unix_error(req, &err)) {
381 if (perr != NULL) {
382 *perr = err;
384 return -1;
386 return state->nwritten;
390 * @brief Async echo handler code dealing with one client
393 struct echo_state {
394 struct tevent_context *ev;
395 int fd;
396 uint8_t *buf;
399 static int echo_state_destructor(struct echo_state *s);
400 static void echo_read_done(struct tevent_req *subreq);
401 static void echo_writeall_done(struct tevent_req *subreq);
403 static struct tevent_req *echo_send(TALLOC_CTX *mem_ctx,
404 struct tevent_context *ev,
405 int fd, size_t bufsize)
407 struct tevent_req *req, *subreq;
408 struct echo_state *state;
410 req = tevent_req_create(mem_ctx, &state, struct echo_state);
411 if (req == NULL) {
412 return NULL;
414 state->ev = ev;
415 state->fd = fd;
417 talloc_set_destructor(state, echo_state_destructor);
419 state->buf = talloc_array(state, uint8_t, bufsize);
420 if (tevent_req_nomem(state->buf, req)) {
421 return tevent_req_post(req, ev);
424 subreq = read_send(state, state->ev, state->fd,
425 state->buf, talloc_get_size(state->buf));
426 if (tevent_req_nomem(subreq, req)) {
427 return tevent_req_post(req, ev);
429 tevent_req_set_callback(subreq, echo_read_done, req);
430 return req;
433 static int echo_state_destructor(struct echo_state *s)
435 if (s->fd != -1) {
436 printf("Closing client fd %d\n", s->fd);
437 close(s->fd);
438 s->fd = -1;
440 return 0;
443 static void echo_read_done(struct tevent_req *subreq)
445 struct tevent_req *req = tevent_req_callback_data(
446 subreq, struct tevent_req);
447 struct echo_state *state = tevent_req_data(
448 req, struct echo_state);
449 ssize_t nread;
450 int err;
452 nread = read_recv(subreq, &err);
453 TALLOC_FREE(subreq);
454 if (nread == -1) {
455 tevent_req_error(req, err);
456 return;
458 if (nread == 0) {
459 tevent_req_done(req);
460 return;
463 subreq = writeall_send(state, state->ev, state->fd, state->buf, nread);
464 if (tevent_req_nomem(subreq, req)) {
465 return;
467 tevent_req_set_callback(subreq, echo_writeall_done, req);
470 static void echo_writeall_done(struct tevent_req *subreq)
472 struct tevent_req *req = tevent_req_callback_data(
473 subreq, struct tevent_req);
474 struct echo_state *state = tevent_req_data(
475 req, struct echo_state);
476 ssize_t nwritten;
477 int err;
479 nwritten = writeall_recv(subreq, &err);
480 TALLOC_FREE(subreq);
481 if (nwritten == -1) {
482 if (err == EPIPE) {
483 tevent_req_done(req);
484 return;
486 tevent_req_error(req, err);
487 return;
490 subreq = read_send(state, state->ev, state->fd,
491 state->buf, talloc_get_size(state->buf));
492 if (tevent_req_nomem(subreq, req)) {
493 return;
495 tevent_req_set_callback(subreq, echo_read_done, req);
498 static bool echo_recv(struct tevent_req *req, int *perr)
500 int err;
502 if (tevent_req_is_unix_error(req, &err)) {
503 *perr = err;
504 return false;
506 return true;
510 * @brief Full echo handler code accepting and handling clients
513 struct echo_server_state {
514 struct tevent_context *ev;
515 int listen_sock;
518 static void echo_server_accepted(struct tevent_req *subreq);
519 static void echo_server_client_done(struct tevent_req *subreq);
521 static struct tevent_req *echo_server_send(TALLOC_CTX *mem_ctx,
522 struct tevent_context *ev,
523 int listen_sock)
525 struct tevent_req *req, *subreq;
526 struct echo_server_state *state;
528 req = tevent_req_create(mem_ctx, &state,
529 struct echo_server_state);
530 if (req == NULL) {
531 return NULL;
533 state->ev = ev;
534 state->listen_sock = listen_sock;
536 subreq = accept_send(state, state->ev, state->listen_sock);
537 if (tevent_req_nomem(subreq, req)) {
538 return tevent_req_post(req, ev);
540 tevent_req_set_callback(subreq, echo_server_accepted, req);
541 return req;
544 static void echo_server_accepted(struct tevent_req *subreq)
546 struct tevent_req *req = tevent_req_callback_data(
547 subreq, struct tevent_req);
548 struct echo_server_state *state = tevent_req_data(
549 req, struct echo_server_state);
550 int sock, err;
552 sock = accept_recv(subreq, NULL, NULL, &err);
553 TALLOC_FREE(subreq);
554 if (sock == -1) {
555 tevent_req_error(req, err);
556 return;
559 printf("new client fd %d\n", sock);
561 subreq = echo_send(state, state->ev, sock, 100);
562 if (tevent_req_nomem(subreq, req)) {
563 return;
565 tevent_req_set_callback(subreq, echo_server_client_done, req);
567 subreq = accept_send(state, state->ev, state->listen_sock);
568 if (tevent_req_nomem(subreq, req)) {
569 return;
571 tevent_req_set_callback(subreq, echo_server_accepted, req);
574 static void echo_server_client_done(struct tevent_req *subreq)
576 bool ret;
577 int err;
579 ret = echo_recv(subreq, &err);
580 TALLOC_FREE(subreq);
582 if (ret) {
583 printf("Client done\n");
584 } else {
585 printf("Client failed: %s\n", strerror(err));
589 static bool echo_server_recv(struct tevent_req *req, int *perr)
591 int err;
593 if (tevent_req_is_unix_error(req, &err)) {
594 *perr = err;
595 return false;
597 return true;
600 int main(int argc, const char **argv)
602 int ret, port, listen_sock, err;
603 struct tevent_context *ev;
604 struct sockaddr_in addr;
605 struct tevent_req *req;
606 bool result;
608 if (argc != 2) {
609 fprintf(stderr, "Usage: %s <port>\n", argv[0]);
610 exit(1);
613 port = atoi(argv[1]);
615 printf("listening on port %d\n", port);
617 listen_sock = socket(AF_INET, SOCK_STREAM, 0);
619 if (listen_sock == -1) {
620 perror("socket() failed");
621 exit(1);
624 addr = (struct sockaddr_in) {
625 .sin_family = AF_INET,
626 .sin_port = htons(port)
629 ret = bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
630 if (ret == -1) {
631 perror("bind() failed");
632 exit(1);
635 ret = listen(listen_sock, 5);
636 if (ret == -1) {
637 perror("listen() failed");
638 exit(1);
641 ev = tevent_context_init(NULL);
642 if (ev == NULL) {
643 fprintf(stderr, "tevent_context_init failed\n");
644 exit(1);
647 req = echo_server_send(ev, ev, listen_sock);
648 if (req == NULL) {
649 fprintf(stderr, "echo_server_send failed\n");
650 exit(1);
653 if (!tevent_req_poll(req, ev)) {
654 perror("tevent_req_poll() failed");
655 exit(1);
658 result = echo_server_recv(req, &err);
659 TALLOC_FREE(req);
660 if (!result) {
661 fprintf(stderr, "echo_server failed: %s\n", strerror(err));
662 exit(1);
665 return 0;