f93d8bcdee7200ca66bac11a3a2b202c55678acc
[samba.git] / lib / tevent / echo_server.c
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  **/
8
9 /*
10  * This file is being made available by the Samba Team under the following
11  * license:
12  *
13  * Permission to use, copy, modify, and distribute this sample file for any
14  * purpose is hereby granted without fee.
15  *
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.
19  */
20
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"
31
32 /**
33  * @brief Helper function to get a useful unix error from tevent_req
34  */
35
36 static bool tevent_req_is_unix_error(struct tevent_req *req, int *perrno)
37 {
38         enum tevent_req_state state;
39         uint64_t err;
40
41         if (!tevent_req_is_error(req, &state, &err)) {
42                 return false;
43         }
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;
57         }
58         return true;
59 }
60
61 /**
62  * @brief Wrapper around accept(2)
63  */
64
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;
71 };
72
73 static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
74                            uint16_t flags, void *private_data);
75
76 static struct tevent_req *accept_send(TALLOC_CTX *mem_ctx,
77                                       struct tevent_context *ev,
78                                       int listen_sock)
79 {
80         struct tevent_req *req;
81         struct accept_state *state;
82
83         req = tevent_req_create(mem_ctx, &state, struct accept_state);
84         if (req == NULL) {
85                 return NULL;
86         }
87
88         state->listen_sock = listen_sock;
89
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);
94         }
95         return req;
96 }
97
98 static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
99                            uint16_t flags, void *private_data)
100 {
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;
105
106         TALLOC_FREE(state->fde);
107
108         if ((flags & TEVENT_FD_READ) == 0) {
109                 tevent_req_error(req, EIO);
110                 return;
111         }
112         state->addrlen = sizeof(state->addr);
113
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;
120         }
121         smb_set_close_on_exec(ret);
122         state->sock = ret;
123         tevent_req_done(req);
124 }
125
126 static int accept_recv(struct tevent_req *req, struct sockaddr *paddr,
127                        socklen_t *paddrlen, int *perr)
128 {
129         struct accept_state *state = tevent_req_data(req, struct accept_state);
130         int err;
131
132         if (tevent_req_is_unix_error(req, &err)) {
133                 if (perr != NULL) {
134                         *perr = err;
135                 }
136                 return -1;
137         }
138         if (paddr != NULL) {
139                 memcpy(paddr, &state->addr, state->addrlen);
140         }
141         if (paddrlen != NULL) {
142                 *paddrlen = state->addrlen;
143         }
144         return state->sock;
145 }
146
147 /**
148  * @brief Wrapper around read(2)
149  */
150
151 struct read_state {
152         struct tevent_fd *fde;
153         int fd;
154         void *buf;
155         size_t count;
156
157         ssize_t nread;
158 };
159
160 static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
161                          uint16_t flags, void *private_data);
162
163 static struct tevent_req *read_send(TALLOC_CTX *mem_ctx,
164                                     struct tevent_context *ev,
165                                     int fd, void *buf, size_t count)
166 {
167         struct tevent_req *req;
168         struct read_state *state;
169
170         req = tevent_req_create(mem_ctx, &state, struct read_state);
171         if (req == NULL) {
172                 return NULL;
173         }
174
175         state->fd = fd;
176         state->buf = buf;
177         state->count = count;
178
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);
183         }
184         return req;
185 }
186
187 static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
188                          uint16_t flags, void *private_data)
189 {
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;
194
195         TALLOC_FREE(state->fde);
196
197         if ((flags & TEVENT_FD_READ) == 0) {
198                 tevent_req_error(req, EIO);
199                 return;
200         }
201
202         ret = read(state->fd, state->buf, state->count);
203         if (ret == -1) {
204                 tevent_req_error(req, errno);
205                 return;
206         }
207         state->nread = ret;
208         tevent_req_done(req);
209 }
210
211 static ssize_t read_recv(struct tevent_req *req, int *perr)
212 {
213         struct read_state *state = tevent_req_data(req, struct read_state);
214         int err;
215
216         if (tevent_req_is_unix_error(req, &err)) {
217                 if (perr != NULL) {
218                         *perr = err;
219                 }
220                 return -1;
221         }
222         return state->nread;
223 }
224
225 /**
226  * @brief Wrapper around write(2)
227  */
228
229 struct write_state {
230         struct tevent_fd *fde;
231         int fd;
232         const void *buf;
233         size_t count;
234
235         ssize_t nwritten;
236 };
237
238 static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
239                          uint16_t flags, void *private_data);
240
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)
244 {
245         struct tevent_req *req;
246         struct write_state *state;
247
248         req = tevent_req_create(mem_ctx, &state, struct write_state);
249         if (req == NULL) {
250                 return NULL;
251         }
252
253         state->fd = fd;
254         state->buf = buf;
255         state->count = count;
256
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);
261         }
262         return req;
263 }
264
265 static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
266                          uint16_t flags, void *private_data)
267 {
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;
272
273         TALLOC_FREE(state->fde);
274
275         if ((flags & TEVENT_FD_WRITE) == 0) {
276                 tevent_req_error(req, EIO);
277                 return;
278         }
279
280         ret = write(state->fd, state->buf, state->count);
281         if (ret == -1) {
282                 tevent_req_error(req, errno);
283                 return;
284         }
285         state->nwritten = ret;
286         tevent_req_done(req);
287 }
288
289 static ssize_t write_recv(struct tevent_req *req, int *perr)
290 {
291         struct write_state *state = tevent_req_data(req, struct write_state);
292         int err;
293
294         if (tevent_req_is_unix_error(req, &err)) {
295                 if (perr != NULL) {
296                         *perr = err;
297                 }
298                 return -1;
299         }
300         return state->nwritten;
301 }
302
303 /**
304  * @brief Wrapper function that deals with short writes
305  */
306
307 struct writeall_state {
308         struct tevent_context *ev;
309         int fd;
310         const void *buf;
311         size_t count;
312         size_t nwritten;
313 };
314
315 static void writeall_done(struct tevent_req *subreq);
316
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)
320 {
321         struct tevent_req *req, *subreq;
322         struct writeall_state *state;
323
324         req = tevent_req_create(mem_ctx, &state, struct writeall_state);
325         if (req == NULL) {
326                 return NULL;
327         }
328         state->ev = ev;
329         state->fd = fd;
330         state->buf = buf;
331         state->count = count;
332         state->nwritten = 0;
333
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);
339         }
340         tevent_req_set_callback(subreq, writeall_done, req);
341         return req;
342 }
343
344 static void writeall_done(struct tevent_req *subreq)
345 {
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;
352
353         nwritten = write_recv(subreq, &err);
354         TALLOC_FREE(subreq);
355         if (nwritten == -1) {
356                 tevent_req_error(req, err);
357                 return;
358         }
359
360         state->nwritten += nwritten;
361
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;
368                 }
369                 tevent_req_set_callback(subreq, writeall_done, req);
370                 return;
371         }
372         tevent_req_done(req);
373 }
374
375 static ssize_t writeall_recv(struct tevent_req *req, int *perr)
376 {
377         struct writeall_state *state = tevent_req_data(
378                 req, struct writeall_state);
379         int err;
380
381         if (tevent_req_is_unix_error(req, &err)) {
382                 if (perr != NULL) {
383                         *perr = err;
384                 }
385                 return -1;
386         }
387         return state->nwritten;
388 }
389
390 /**
391  * @brief Async echo handler code dealing with one client
392  */
393
394 struct echo_state {
395         struct tevent_context *ev;
396         int fd;
397         uint8_t *buf;
398 };
399
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);
403
404 static struct tevent_req *echo_send(TALLOC_CTX *mem_ctx,
405                                     struct tevent_context *ev,
406                                     int fd, size_t bufsize)
407 {
408         struct tevent_req *req, *subreq;
409         struct echo_state *state;
410
411         req = tevent_req_create(mem_ctx, &state, struct echo_state);
412         if (req == NULL) {
413                 return NULL;
414         }
415         state->ev = ev;
416         state->fd = fd;
417
418         talloc_set_destructor(state, echo_state_destructor);
419
420         state->buf = talloc_array(state, uint8_t, bufsize);
421         if (tevent_req_nomem(state->buf, req)) {
422                 return tevent_req_post(req, ev);
423         }
424
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);
429         }
430         tevent_req_set_callback(subreq, echo_read_done, req);
431         return req;
432 }
433
434 static int echo_state_destructor(struct echo_state *s)
435 {
436         if (s->fd != -1) {
437                 printf("Closing client fd %d\n", s->fd);
438                 close(s->fd);
439                 s->fd = -1;
440         }
441         return 0;
442 }
443
444 static void echo_read_done(struct tevent_req *subreq)
445 {
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;
452
453         nread = read_recv(subreq, &err);
454         TALLOC_FREE(subreq);
455         if (nread == -1) {
456                 tevent_req_error(req, err);
457                 return;
458         }
459         if (nread == 0) {
460                 tevent_req_done(req);
461                 return;
462         }
463
464         subreq = writeall_send(state, state->ev, state->fd, state->buf, nread);
465         if (tevent_req_nomem(subreq, req)) {
466                 return;
467         }
468         tevent_req_set_callback(subreq, echo_writeall_done, req);
469 }
470
471 static void echo_writeall_done(struct tevent_req *subreq)
472 {
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;
479
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;
486                 }
487                 tevent_req_error(req, err);
488                 return;
489         }
490
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;
495         }
496         tevent_req_set_callback(subreq, echo_read_done, req);
497 }
498
499 static bool echo_recv(struct tevent_req *req, int *perr)
500 {
501         int err;
502
503         if (tevent_req_is_unix_error(req, &err)) {
504                 *perr = err;
505                 return false;
506         }
507         return true;
508 }
509
510 /**
511  * @brief Full echo handler code accepting and handling clients
512  */
513
514 struct echo_server_state {
515         struct tevent_context *ev;
516         int listen_sock;
517 };
518
519 static void echo_server_accepted(struct tevent_req *subreq);
520 static void echo_server_client_done(struct tevent_req *subreq);
521
522 static struct tevent_req *echo_server_send(TALLOC_CTX *mem_ctx,
523                                            struct tevent_context *ev,
524                                            int listen_sock)
525 {
526         struct tevent_req *req, *subreq;
527         struct echo_server_state *state;
528
529         req = tevent_req_create(mem_ctx, &state,
530                                 struct echo_server_state);
531         if (req == NULL) {
532                 return NULL;
533         }
534         state->ev = ev;
535         state->listen_sock = listen_sock;
536
537         subreq = accept_send(state, state->ev, state->listen_sock);
538         if (tevent_req_nomem(subreq, req)) {
539                 return tevent_req_post(req, ev);
540         }
541         tevent_req_set_callback(subreq, echo_server_accepted, req);
542         return req;
543 }
544
545 static void echo_server_accepted(struct tevent_req *subreq)
546 {
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;
552
553         sock = accept_recv(subreq, NULL, NULL, &err);
554         TALLOC_FREE(subreq);
555         if (sock == -1) {
556                 tevent_req_error(req, err);
557                 return;
558         }
559
560         printf("new client fd %d\n", sock);
561
562         subreq = echo_send(state, state->ev, sock, 100);
563         if (tevent_req_nomem(subreq, req)) {
564                 return;
565         }
566         tevent_req_set_callback(subreq, echo_server_client_done, req);
567
568         subreq = accept_send(state, state->ev, state->listen_sock);
569         if (tevent_req_nomem(subreq, req)) {
570                 return;
571         }
572         tevent_req_set_callback(subreq, echo_server_accepted, req);
573 }
574
575 static void echo_server_client_done(struct tevent_req *subreq)
576 {
577         bool ret;
578         int err;
579
580         ret = echo_recv(subreq, &err);
581         TALLOC_FREE(subreq);
582
583         if (ret) {
584                 printf("Client done\n");
585         } else {
586                 printf("Client failed: %s\n", strerror(err));
587         }
588 }
589
590 static bool echo_server_recv(struct tevent_req *req, int *perr)
591 {
592         int err;
593
594         if (tevent_req_is_unix_error(req, &err)) {
595                 *perr = err;
596                 return false;
597         }
598         return true;
599 }
600
601 int main(int argc, const char **argv)
602 {
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;
608
609         if (argc != 2) {
610                 fprintf(stderr, "Usage: %s <port>\n", argv[0]);
611                 exit(1);
612         }
613
614         port = atoi(argv[1]);
615
616         printf("listening on port %d\n", port);
617
618         listen_sock = socket(AF_INET, SOCK_STREAM, 0);
619
620         if (listen_sock == -1) {
621                 perror("socket() failed");
622                 exit(1);
623         }
624
625         addr = (struct sockaddr_in) {
626                 .sin_family = AF_INET,
627                 .sin_port = htons(port)
628         };
629
630         ret = bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
631         if (ret == -1) {
632                 perror("bind() failed");
633                 exit(1);
634         }
635
636         ret = listen(listen_sock, 5);
637         if (ret == -1) {
638                 perror("listen() failed");
639                 exit(1);
640         }
641
642         ev = tevent_context_init(NULL);
643         if (ev == NULL) {
644                 fprintf(stderr, "tevent_context_init failed\n");
645                 exit(1);
646         }
647
648         req = echo_server_send(ev, ev, listen_sock);
649         if (req == NULL) {
650                 fprintf(stderr, "echo_server_send failed\n");
651                 exit(1);
652         }
653
654         if (!tevent_req_poll(req, ev)) {
655                 perror("tevent_req_poll() failed");
656                 exit(1);
657         }
658
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);
664         }
665
666         return 0;
667 }