6e7f1811f42fe3388be758ec2db389f5a1bf79fb
[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         state->sock = ret;
122         tevent_req_done(req);
123 }
124
125 static int accept_recv(struct tevent_req *req, struct sockaddr *paddr,
126                        socklen_t *paddrlen, int *perr)
127 {
128         struct accept_state *state = tevent_req_data(req, struct accept_state);
129         int err;
130
131         if (tevent_req_is_unix_error(req, &err)) {
132                 if (perr != NULL) {
133                         *perr = err;
134                 }
135                 return -1;
136         }
137         if (paddr != NULL) {
138                 memcpy(paddr, &state->addr, state->addrlen);
139         }
140         if (paddrlen != NULL) {
141                 *paddrlen = state->addrlen;
142         }
143         return state->sock;
144 }
145
146 /**
147  * @brief Wrapper around read(2)
148  */
149
150 struct read_state {
151         struct tevent_fd *fde;
152         int fd;
153         void *buf;
154         size_t count;
155
156         ssize_t nread;
157 };
158
159 static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
160                          uint16_t flags, void *private_data);
161
162 static struct tevent_req *read_send(TALLOC_CTX *mem_ctx,
163                                     struct tevent_context *ev,
164                                     int fd, void *buf, size_t count)
165 {
166         struct tevent_req *req;
167         struct read_state *state;
168
169         req = tevent_req_create(mem_ctx, &state, struct read_state);
170         if (req == NULL) {
171                 return NULL;
172         }
173
174         state->fd = fd;
175         state->buf = buf;
176         state->count = count;
177
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);
182         }
183         return req;
184 }
185
186 static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
187                          uint16_t flags, void *private_data)
188 {
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;
193
194         TALLOC_FREE(state->fde);
195
196         if ((flags & TEVENT_FD_READ) == 0) {
197                 tevent_req_error(req, EIO);
198                 return;
199         }
200
201         ret = read(state->fd, state->buf, state->count);
202         if (ret == -1) {
203                 tevent_req_error(req, errno);
204                 return;
205         }
206         state->nread = ret;
207         tevent_req_done(req);
208 }
209
210 static ssize_t read_recv(struct tevent_req *req, int *perr)
211 {
212         struct read_state *state = tevent_req_data(req, struct read_state);
213         int err;
214
215         if (tevent_req_is_unix_error(req, &err)) {
216                 if (perr != NULL) {
217                         *perr = err;
218                 }
219                 return -1;
220         }
221         return state->nread;
222 }
223
224 /**
225  * @brief Wrapper around write(2)
226  */
227
228 struct write_state {
229         struct tevent_fd *fde;
230         int fd;
231         const void *buf;
232         size_t count;
233
234         ssize_t nwritten;
235 };
236
237 static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
238                          uint16_t flags, void *private_data);
239
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)
243 {
244         struct tevent_req *req;
245         struct write_state *state;
246
247         req = tevent_req_create(mem_ctx, &state, struct write_state);
248         if (req == NULL) {
249                 return NULL;
250         }
251
252         state->fd = fd;
253         state->buf = buf;
254         state->count = count;
255
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);
260         }
261         return req;
262 }
263
264 static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
265                          uint16_t flags, void *private_data)
266 {
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;
271
272         TALLOC_FREE(state->fde);
273
274         if ((flags & TEVENT_FD_WRITE) == 0) {
275                 tevent_req_error(req, EIO);
276                 return;
277         }
278
279         ret = write(state->fd, state->buf, state->count);
280         if (ret == -1) {
281                 tevent_req_error(req, errno);
282                 return;
283         }
284         state->nwritten = ret;
285         tevent_req_done(req);
286 }
287
288 static ssize_t write_recv(struct tevent_req *req, int *perr)
289 {
290         struct write_state *state = tevent_req_data(req, struct write_state);
291         int err;
292
293         if (tevent_req_is_unix_error(req, &err)) {
294                 if (perr != NULL) {
295                         *perr = err;
296                 }
297                 return -1;
298         }
299         return state->nwritten;
300 }
301
302 /**
303  * @brief Wrapper function that deals with short writes
304  */
305
306 struct writeall_state {
307         struct tevent_context *ev;
308         int fd;
309         const void *buf;
310         size_t count;
311         size_t nwritten;
312 };
313
314 static void writeall_done(struct tevent_req *subreq);
315
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)
319 {
320         struct tevent_req *req, *subreq;
321         struct writeall_state *state;
322
323         req = tevent_req_create(mem_ctx, &state, struct writeall_state);
324         if (req == NULL) {
325                 return NULL;
326         }
327         state->ev = ev;
328         state->fd = fd;
329         state->buf = buf;
330         state->count = count;
331         state->nwritten = 0;
332
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);
338         }
339         tevent_req_set_callback(subreq, writeall_done, req);
340         return req;
341 }
342
343 static void writeall_done(struct tevent_req *subreq)
344 {
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;
351
352         nwritten = write_recv(subreq, &err);
353         TALLOC_FREE(subreq);
354         if (nwritten == -1) {
355                 tevent_req_error(req, err);
356                 return;
357         }
358
359         state->nwritten += nwritten;
360
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;
367                 }
368                 tevent_req_set_callback(subreq, writeall_done, req);
369                 return;
370         }
371         tevent_req_done(req);
372 }
373
374 static ssize_t writeall_recv(struct tevent_req *req, int *perr)
375 {
376         struct writeall_state *state = tevent_req_data(
377                 req, struct writeall_state);
378         int err;
379
380         if (tevent_req_is_unix_error(req, &err)) {
381                 if (perr != NULL) {
382                         *perr = err;
383                 }
384                 return -1;
385         }
386         return state->nwritten;
387 }
388
389 /**
390  * @brief Async echo handler code dealing with one client
391  */
392
393 struct echo_state {
394         struct tevent_context *ev;
395         int fd;
396         uint8_t *buf;
397 };
398
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);
402
403 static struct tevent_req *echo_send(TALLOC_CTX *mem_ctx,
404                                     struct tevent_context *ev,
405                                     int fd, size_t bufsize)
406 {
407         struct tevent_req *req, *subreq;
408         struct echo_state *state;
409
410         req = tevent_req_create(mem_ctx, &state, struct echo_state);
411         if (req == NULL) {
412                 return NULL;
413         }
414         state->ev = ev;
415         state->fd = fd;
416
417         talloc_set_destructor(state, echo_state_destructor);
418
419         state->buf = talloc_array(state, uint8_t, bufsize);
420         if (tevent_req_nomem(state->buf, req)) {
421                 return tevent_req_post(req, ev);
422         }
423
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);
428         }
429         tevent_req_set_callback(subreq, echo_read_done, req);
430         return req;
431 }
432
433 static int echo_state_destructor(struct echo_state *s)
434 {
435         if (s->fd != -1) {
436                 printf("Closing client fd %d\n", s->fd);
437                 close(s->fd);
438                 s->fd = -1;
439         }
440         return 0;
441 }
442
443 static void echo_read_done(struct tevent_req *subreq)
444 {
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;
451
452         nread = read_recv(subreq, &err);
453         TALLOC_FREE(subreq);
454         if (nread == -1) {
455                 tevent_req_error(req, err);
456                 return;
457         }
458         if (nread == 0) {
459                 tevent_req_done(req);
460                 return;
461         }
462
463         subreq = writeall_send(state, state->ev, state->fd, state->buf, nread);
464         if (tevent_req_nomem(subreq, req)) {
465                 return;
466         }
467         tevent_req_set_callback(subreq, echo_writeall_done, req);
468 }
469
470 static void echo_writeall_done(struct tevent_req *subreq)
471 {
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;
478
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;
485                 }
486                 tevent_req_error(req, err);
487                 return;
488         }
489
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;
494         }
495         tevent_req_set_callback(subreq, echo_read_done, req);
496 }
497
498 static bool echo_recv(struct tevent_req *req, int *perr)
499 {
500         int err;
501
502         if (tevent_req_is_unix_error(req, &err)) {
503                 *perr = err;
504                 return false;
505         }
506         return true;
507 }
508
509 /**
510  * @brief Full echo handler code accepting and handling clients
511  */
512
513 struct echo_server_state {
514         struct tevent_context *ev;
515         int listen_sock;
516 };
517
518 static void echo_server_accepted(struct tevent_req *subreq);
519 static void echo_server_client_done(struct tevent_req *subreq);
520
521 static struct tevent_req *echo_server_send(TALLOC_CTX *mem_ctx,
522                                            struct tevent_context *ev,
523                                            int listen_sock)
524 {
525         struct tevent_req *req, *subreq;
526         struct echo_server_state *state;
527
528         req = tevent_req_create(mem_ctx, &state,
529                                 struct echo_server_state);
530         if (req == NULL) {
531                 return NULL;
532         }
533         state->ev = ev;
534         state->listen_sock = listen_sock;
535
536         subreq = accept_send(state, state->ev, state->listen_sock);
537         if (tevent_req_nomem(subreq, req)) {
538                 return tevent_req_post(req, ev);
539         }
540         tevent_req_set_callback(subreq, echo_server_accepted, req);
541         return req;
542 }
543
544 static void echo_server_accepted(struct tevent_req *subreq)
545 {
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;
551
552         sock = accept_recv(subreq, NULL, NULL, &err);
553         TALLOC_FREE(subreq);
554         if (sock == -1) {
555                 tevent_req_error(req, err);
556                 return;
557         }
558
559         printf("new client fd %d\n", sock);
560
561         subreq = echo_send(state, state->ev, sock, 100);
562         if (tevent_req_nomem(subreq, req)) {
563                 return;
564         }
565         tevent_req_set_callback(subreq, echo_server_client_done, req);
566
567         subreq = accept_send(state, state->ev, state->listen_sock);
568         if (tevent_req_nomem(subreq, req)) {
569                 return;
570         }
571         tevent_req_set_callback(subreq, echo_server_accepted, req);
572 }
573
574 static void echo_server_client_done(struct tevent_req *subreq)
575 {
576         bool ret;
577         int err;
578
579         ret = echo_recv(subreq, &err);
580         TALLOC_FREE(subreq);
581
582         if (ret) {
583                 printf("Client done\n");
584         } else {
585                 printf("Client failed: %s\n", strerror(err));
586         }
587 }
588
589 static bool echo_server_recv(struct tevent_req *req, int *perr)
590 {
591         int err;
592
593         if (tevent_req_is_unix_error(req, &err)) {
594                 *perr = err;
595                 return false;
596         }
597         return true;
598 }
599
600 int main(int argc, const char **argv)
601 {
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;
607
608         if (argc != 2) {
609                 fprintf(stderr, "Usage: %s <port>\n", argv[0]);
610                 exit(1);
611         }
612
613         port = atoi(argv[1]);
614
615         printf("listening on port %d\n", port);
616
617         listen_sock = socket(AF_INET, SOCK_STREAM, 0);
618
619         if (listen_sock == -1) {
620                 perror("socket() failed");
621                 exit(1);
622         }
623
624         addr = (struct sockaddr_in) {
625                 .sin_family = AF_INET,
626                 .sin_port = htons(port)
627         };
628
629         ret = bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
630         if (ret == -1) {
631                 perror("bind() failed");
632                 exit(1);
633         }
634
635         ret = listen(listen_sock, 5);
636         if (ret == -1) {
637                 perror("listen() failed");
638                 exit(1);
639         }
640
641         ev = tevent_context_init(NULL);
642         if (ev == NULL) {
643                 fprintf(stderr, "tevent_context_init failed\n");
644                 exit(1);
645         }
646
647         req = echo_server_send(ev, ev, listen_sock);
648         if (req == NULL) {
649                 fprintf(stderr, "echo_server_send failed\n");
650                 exit(1);
651         }
652
653         if (!tevent_req_poll(req, ev)) {
654                 perror("tevent_req_poll() failed");
655                 exit(1);
656         }
657
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);
663         }
664
665         return 0;
666 }