Add more conventional async_send
[jra/samba/.git] / lib / async_req / async_sock.c
1 /*
2    Unix SMB/CIFS implementation.
3    async socket syscalls
4    Copyright (C) Volker Lendecke 2008
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "lib/talloc/talloc.h"
22 #include "lib/tevent/tevent.h"
23 #include "lib/async_req/async_req.h"
24 #include "lib/async_req/async_sock.h"
25 #include "lib/util/tevent_unix.h"
26 #include <fcntl.h>
27
28 #ifndef TALLOC_FREE
29 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
30 #endif
31
32 /**
33  * Discriminator for async_syscall_state
34  */
35 enum async_syscall_type {
36         ASYNC_SYSCALL_SEND,
37         ASYNC_SYSCALL_RECV,
38 };
39
40 /**
41  * Holder for syscall arguments and the result
42  */
43
44 struct async_syscall_state {
45         enum async_syscall_type syscall_type;
46         struct tevent_fd *fde;
47
48         union {
49                 struct param_send {
50                         int fd;
51                         const void *buffer;
52                         size_t length;
53                         int flags;
54                 } param_send;
55                 struct param_recv {
56                         int fd;
57                         void *buffer;
58                         size_t length;
59                         int flags;
60                 } param_recv;
61         } param;
62
63         union {
64                 ssize_t result_ssize_t;
65                 size_t result_size_t;
66                 int result_int;
67         } result;
68         int sys_errno;
69 };
70
71 /**
72  * @brief Map async_req states to unix-style errnos
73  * @param[in]  req      The async req to get the state from
74  * @param[out] err      Pointer to take the unix-style errno
75  *
76  * @return true if the async_req is in an error state, false otherwise
77  */
78
79 bool async_req_is_errno(struct async_req *req, int *err)
80 {
81         enum async_req_state state;
82         uint64_t error;
83
84         if (!async_req_is_error(req, &state, &error)) {
85                 return false;
86         }
87
88         switch (state) {
89         case ASYNC_REQ_USER_ERROR:
90                 *err = (int)error;
91                 break;
92         case ASYNC_REQ_TIMED_OUT:
93 #ifdef ETIMEDOUT
94                 *err = ETIMEDOUT;
95 #else
96                 *err = EAGAIN;
97 #endif
98                 break;
99         case ASYNC_REQ_NO_MEMORY:
100                 *err = ENOMEM;
101                 break;
102         default:
103                 *err = EIO;
104                 break;
105         }
106         return true;
107 }
108
109 int async_req_simple_recv_errno(struct async_req *req)
110 {
111         int err;
112
113         if (async_req_is_errno(req, &err)) {
114                 return err;
115         }
116
117         return 0;
118 }
119
120 /**
121  * @brief Create a new async syscall req
122  * @param[in] mem_ctx   The memory context to hang the result off
123  * @param[in] ev        The event context to work from
124  * @param[in] type      Which syscall will this be
125  * @param[in] pstate    Where to put the newly created private_data state
126  * @retval The new request
127  *
128  * This is a helper function to prepare a new struct async_req with an
129  * associated struct async_syscall_state. The async_syscall_state will be put
130  * into the async_req as private_data.
131  */
132
133 static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx,
134                                            struct tevent_context *ev,
135                                            enum async_syscall_type type,
136                                            struct async_syscall_state **pstate)
137 {
138         struct async_req *result;
139         struct async_syscall_state *state;
140
141         if (!async_req_setup(mem_ctx, &result, &state,
142                              struct async_syscall_state)) {
143                 return NULL;
144         }
145         state->syscall_type = type;
146
147         result->private_data = state;
148
149         *pstate = state;
150
151         return result;
152 }
153
154 /**
155  * @brief Create a new async syscall req based on a fd
156  * @param[in] mem_ctx   The memory context to hang the result off
157  * @param[in] ev        The event context to work from
158  * @param[in] type      Which syscall will this be
159  * @param[in] fd        The file descriptor we work on
160  * @param[in] fde_flags TEVENT_FD_READ/WRITE -- what are we interested in?
161  * @param[in] fde_cb    The callback function for the file descriptor event
162  * @param[in] pstate    Where to put the newly created private_data state
163  * @retval The new request
164  *
165  * This is a helper function to prepare a new struct async_req with an
166  * associated struct async_syscall_state and an associated file descriptor
167  * event.
168  */
169
170 static struct async_req *async_fde_syscall_new(
171         TALLOC_CTX *mem_ctx,
172         struct tevent_context *ev,
173         enum async_syscall_type type,
174         int fd,
175         uint16_t fde_flags,
176         void (*fde_cb)(struct tevent_context *ev,
177                        struct tevent_fd *fde, uint16_t flags,
178                        void *priv),
179         struct async_syscall_state **pstate)
180 {
181         struct async_req *result;
182         struct async_syscall_state *state;
183
184         result = async_syscall_new(mem_ctx, ev, type, &state);
185         if (result == NULL) {
186                 return NULL;
187         }
188
189         state->fde = tevent_add_fd(ev, state, fd, fde_flags, fde_cb, result);
190         if (state->fde == NULL) {
191                 TALLOC_FREE(result);
192                 return NULL;
193         }
194         *pstate = state;
195         return result;
196 }
197
198 /**
199  * Retrieve a ssize_t typed result from an async syscall
200  * @param[in] req       The syscall that has just finished
201  * @param[out] perrno   Where to put the syscall's errno
202  * @retval The return value from the asynchronously called syscall
203  */
204
205 ssize_t async_syscall_result_ssize_t(struct async_req *req, int *perrno)
206 {
207         struct async_syscall_state *state = talloc_get_type_abort(
208                 req->private_data, struct async_syscall_state);
209
210         *perrno = state->sys_errno;
211         return state->result.result_ssize_t;
212 }
213
214 /**
215  * Retrieve a size_t typed result from an async syscall
216  * @param[in] req       The syscall that has just finished
217  * @param[out] perrno   Where to put the syscall's errno
218  * @retval The return value from the asynchronously called syscall
219  */
220
221 size_t async_syscall_result_size_t(struct async_req *req, int *perrno)
222 {
223         struct async_syscall_state *state = talloc_get_type_abort(
224                 req->private_data, struct async_syscall_state);
225
226         *perrno = state->sys_errno;
227         return state->result.result_size_t;
228 }
229
230 /**
231  * Retrieve a int typed result from an async syscall
232  * @param[in] req       The syscall that has just finished
233  * @param[out] perrno   Where to put the syscall's errno
234  * @retval The return value from the asynchronously called syscall
235  */
236
237 int async_syscall_result_int(struct async_req *req, int *perrno)
238 {
239         struct async_syscall_state *state = talloc_get_type_abort(
240                 req->private_data, struct async_syscall_state);
241
242         *perrno = state->sys_errno;
243         return state->result.result_int;
244 }
245
246 /**
247  * fde event handler for the "send" syscall
248  * @param[in] ev        The event context that sent us here
249  * @param[in] fde       The file descriptor event associated with the send
250  * @param[in] flags     Can only be TEVENT_FD_WRITE here
251  * @param[in] priv      private data, "struct async_req *" in this case
252  */
253
254 static void async_send_callback(struct tevent_context *ev,
255                                 struct tevent_fd *fde, uint16_t flags,
256                                 void *priv)
257 {
258         struct async_req *req = talloc_get_type_abort(
259                 priv, struct async_req);
260         struct async_syscall_state *state = talloc_get_type_abort(
261                 req->private_data, struct async_syscall_state);
262         struct param_send *p = &state->param.param_send;
263
264         if (state->syscall_type != ASYNC_SYSCALL_SEND) {
265                 async_req_error(req, EIO);
266                 return;
267         }
268
269         state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
270                                             p->flags);
271         state->sys_errno = errno;
272
273         TALLOC_FREE(state->fde);
274
275         async_req_done(req);
276 }
277
278 /**
279  * Async version of send(2)
280  * @param[in] mem_ctx   The memory context to hang the result off
281  * @param[in] ev        The event context to work from
282  * @param[in] fd        The socket to send to
283  * @param[in] buffer    The buffer to send
284  * @param[in] length    How many bytes to send
285  * @param[in] flags     flags passed to send(2)
286  *
287  * This function is a direct counterpart of send(2)
288  */
289
290 struct async_req *async_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
291                              int fd, const void *buffer, size_t length,
292                              int flags)
293 {
294         struct async_req *result;
295         struct async_syscall_state *state;
296
297         result = async_fde_syscall_new(
298                 mem_ctx, ev, ASYNC_SYSCALL_SEND,
299                 fd, TEVENT_FD_WRITE, async_send_callback,
300                 &state);
301         if (result == NULL) {
302                 return NULL;
303         }
304
305         state->param.param_send.fd = fd;
306         state->param.param_send.buffer = buffer;
307         state->param.param_send.length = length;
308         state->param.param_send.flags = flags;
309
310         return result;
311 }
312
313 /**
314  * fde event handler for the "recv" syscall
315  * @param[in] ev        The event context that sent us here
316  * @param[in] fde       The file descriptor event associated with the recv
317  * @param[in] flags     Can only be TEVENT_FD_READ here
318  * @param[in] priv      private data, "struct async_req *" in this case
319  */
320
321 static void async_recv_callback(struct tevent_context *ev,
322                                 struct tevent_fd *fde, uint16_t flags,
323                                 void *priv)
324 {
325         struct async_req *req = talloc_get_type_abort(
326                 priv, struct async_req);
327         struct async_syscall_state *state = talloc_get_type_abort(
328                 req->private_data, struct async_syscall_state);
329         struct param_recv *p = &state->param.param_recv;
330
331         if (state->syscall_type != ASYNC_SYSCALL_RECV) {
332                 async_req_error(req, EIO);
333                 return;
334         }
335
336         state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
337                                             p->flags);
338         state->sys_errno = errno;
339
340         TALLOC_FREE(state->fde);
341
342         async_req_done(req);
343 }
344
345 /**
346  * Async version of recv(2)
347  * @param[in] mem_ctx   The memory context to hang the result off
348  * @param[in] ev        The event context to work from
349  * @param[in] fd        The socket to recv from
350  * @param[in] buffer    The buffer to recv into
351  * @param[in] length    How many bytes to recv
352  * @param[in] flags     flags passed to recv(2)
353  *
354  * This function is a direct counterpart of recv(2)
355  */
356
357 struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
358                              int fd, void *buffer, size_t length,
359                              int flags)
360 {
361         struct async_req *result;
362         struct async_syscall_state *state;
363
364         result = async_fde_syscall_new(
365                 mem_ctx, ev, ASYNC_SYSCALL_RECV,
366                 fd, TEVENT_FD_READ, async_recv_callback,
367                 &state);
368
369         if (result == NULL) {
370                 return NULL;
371         }
372
373         state->param.param_recv.fd = fd;
374         state->param.param_recv.buffer = buffer;
375         state->param.param_recv.length = length;
376         state->param.param_recv.flags = flags;
377
378         return result;
379 }
380
381 struct async_send_state {
382         int fd;
383         const void *buf;
384         size_t len;
385         int flags;
386         ssize_t sent;
387 };
388
389 static void async_send_handler(struct tevent_context *ev,
390                                struct tevent_fd *fde,
391                                uint16_t flags, void *private_data);
392
393 struct tevent_req *async_send_send(TALLOC_CTX *mem_ctx,
394                                    struct tevent_context *ev,
395                                    int fd, const void *buf, size_t len,
396                                    int flags)
397 {
398         struct tevent_req *result;
399         struct async_send_state *state;
400         struct tevent_fd *fde;
401
402         result = tevent_req_create(mem_ctx, &state, struct async_send_state);
403         if (result == NULL) {
404                 return result;
405         }
406         state->fd = fd;
407         state->buf = buf;
408         state->len = len;
409         state->flags = flags;
410
411         fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, async_send_handler,
412                             result);
413         if (fde == NULL) {
414                 TALLOC_FREE(result);
415                 return NULL;
416         }
417         return result;
418 }
419
420 static void async_send_handler(struct tevent_context *ev,
421                                struct tevent_fd *fde,
422                                uint16_t flags, void *private_data)
423 {
424         struct tevent_req *req = talloc_get_type_abort(
425                 private_data, struct tevent_req);
426         struct async_send_state *state = talloc_get_type_abort(
427                 req->private_state, struct async_send_state);
428
429         state->sent = send(state->fd, state->buf, state->len, state->flags);
430         if (state->sent == -1) {
431                 tevent_req_error(req, errno);
432                 return;
433         }
434         tevent_req_done(req);
435 }
436
437 ssize_t async_send_recv(struct tevent_req *req, int *perrno)
438 {
439         struct async_send_state *state = talloc_get_type_abort(
440                 req->private_state, struct async_send_state);
441
442         if (tevent_req_is_unix_error(req, perrno)) {
443                 return -1;
444         }
445         return state->sent;
446 }
447
448 struct async_connect_state {
449         int fd;
450         int result;
451         int sys_errno;
452         long old_sockflags;
453 };
454
455 static void async_connect_connected(struct tevent_context *ev,
456                                     struct tevent_fd *fde, uint16_t flags,
457                                     void *priv);
458
459 /**
460  * @brief async version of connect(2)
461  * @param[in] mem_ctx   The memory context to hang the result off
462  * @param[in] ev        The event context to work from
463  * @param[in] fd        The socket to recv from
464  * @param[in] address   Where to connect?
465  * @param[in] address_len Length of *address
466  * @retval The async request
467  *
468  * This function sets the socket into non-blocking state to be able to call
469  * connect in an async state. This will be reset when the request is finished.
470  */
471
472 struct tevent_req *async_connect_send(TALLOC_CTX *mem_ctx,
473                                       struct tevent_context *ev,
474                                       int fd, const struct sockaddr *address,
475                                       socklen_t address_len)
476 {
477         struct tevent_req *result;
478         struct async_connect_state *state;
479         struct tevent_fd *fde;
480
481         result = tevent_req_create(
482                 mem_ctx, &state, struct async_connect_state);
483         if (result == NULL) {
484                 return NULL;
485         }
486
487         /**
488          * We have to set the socket to nonblocking for async connect(2). Keep
489          * the old sockflags around.
490          */
491
492         state->fd = fd;
493         state->sys_errno = 0;
494
495         state->old_sockflags = fcntl(fd, F_GETFL, 0);
496         if (state->old_sockflags == -1) {
497                 goto post_errno;
498         }
499
500         set_blocking(fd, false);
501
502         state->result = connect(fd, address, address_len);
503         if (state->result == 0) {
504                 errno = 0;
505                 goto post_errno;
506         }
507
508         /**
509          * A number of error messages show that something good is progressing
510          * and that we have to wait for readability.
511          *
512          * If none of them are present, bail out.
513          */
514
515         if (!(errno == EINPROGRESS || errno == EALREADY ||
516 #ifdef EISCONN
517               errno == EISCONN ||
518 #endif
519               errno == EAGAIN || errno == EINTR)) {
520                 goto post_errno;
521         }
522
523         fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
524                            async_connect_connected, result);
525         if (fde == NULL) {
526                 errno = ENOMEM;
527                 goto post_errno;
528         }
529         return result;
530
531  post_errno:
532         state->sys_errno = errno;
533         fcntl(fd, F_SETFL, state->old_sockflags);
534         if (state->sys_errno == 0) {
535                 tevent_req_done(result);
536         } else {
537                 tevent_req_error(result, state->sys_errno);
538         }
539         return tevent_req_post(result, ev);
540 }
541
542 /**
543  * fde event handler for connect(2)
544  * @param[in] ev        The event context that sent us here
545  * @param[in] fde       The file descriptor event associated with the connect
546  * @param[in] flags     Indicate read/writeability of the socket
547  * @param[in] priv      private data, "struct async_req *" in this case
548  */
549
550 static void async_connect_connected(struct tevent_context *ev,
551                                     struct tevent_fd *fde, uint16_t flags,
552                                     void *priv)
553 {
554         struct tevent_req *req = talloc_get_type_abort(
555                 priv, struct tevent_req);
556         struct async_connect_state *state = talloc_get_type_abort(
557                 req->private_state, struct async_connect_state);
558
559         TALLOC_FREE(fde);
560
561         /*
562          * Stevens, Network Programming says that if there's a
563          * successful connect, the socket is only writable. Upon an
564          * error, it's both readable and writable.
565          */
566         if ((flags & (TEVENT_FD_READ|TEVENT_FD_WRITE))
567             == (TEVENT_FD_READ|TEVENT_FD_WRITE)) {
568                 int sockerr;
569                 socklen_t err_len = sizeof(sockerr);
570
571                 if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
572                                (void *)&sockerr, &err_len) == 0) {
573                         errno = sockerr;
574                 }
575
576                 state->sys_errno = errno;
577
578                 DEBUG(10, ("connect returned %s\n", strerror(errno)));
579
580                 fcntl(state->fd, F_SETFL, state->old_sockflags);
581                 tevent_req_error(req, state->sys_errno);
582                 return;
583         }
584
585         state->sys_errno = 0;
586         tevent_req_done(req);
587 }
588
589 int async_connect_recv(struct tevent_req *req, int *perrno)
590 {
591         struct async_connect_state *state = talloc_get_type_abort(
592                 req->private_state, struct async_connect_state);
593         int err;
594
595         fcntl(state->fd, F_SETFL, state->old_sockflags);
596
597         if (tevent_req_is_unix_error(req, &err)) {
598                 *perrno = err;
599                 return -1;
600         }
601
602         if (state->sys_errno == 0) {
603                 return 0;
604         }
605
606         *perrno = state->sys_errno;
607         return -1;
608 }
609
610 struct writev_state {
611         struct tevent_context *ev;
612         int fd;
613         struct iovec *iov;
614         int count;
615         size_t total_size;
616 };
617
618 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
619                            uint16_t flags, void *private_data);
620
621 struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
622                                int fd, struct iovec *iov, int count)
623 {
624         struct tevent_req *result;
625         struct writev_state *state;
626         struct tevent_fd *fde;
627
628         result = tevent_req_create(mem_ctx, &state, struct writev_state);
629         if (result == NULL) {
630                 return NULL;
631         }
632         state->ev = ev;
633         state->fd = fd;
634         state->total_size = 0;
635         state->count = count;
636         state->iov = (struct iovec *)talloc_memdup(
637                 state, iov, sizeof(struct iovec) * count);
638         if (state->iov == NULL) {
639                 goto fail;
640         }
641
642         fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, writev_handler,
643                             result);
644         if (fde == NULL) {
645                 goto fail;
646         }
647         return result;
648
649  fail:
650         TALLOC_FREE(result);
651         return NULL;
652 }
653
654 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
655                            uint16_t flags, void *private_data)
656 {
657         struct tevent_req *req = talloc_get_type_abort(
658                 private_data, struct tevent_req);
659         struct writev_state *state = talloc_get_type_abort(
660                 req->private_state, struct writev_state);
661         size_t to_write, written;
662         int i;
663
664         to_write = 0;
665
666         for (i=0; i<state->count; i++) {
667                 to_write += state->iov[i].iov_len;
668         }
669
670         written = sys_writev(state->fd, state->iov, state->count);
671         if (written == -1) {
672                 tevent_req_error(req, errno);
673                 return;
674         }
675         if (written == 0) {
676                 tevent_req_error(req, EPIPE);
677                 return;
678         }
679         state->total_size += written;
680
681         if (written == to_write) {
682                 tevent_req_done(req);
683                 return;
684         }
685
686         /*
687          * We've written less than we were asked to, drop stuff from
688          * state->iov.
689          */
690
691         while (written > 0) {
692                 if (written < state->iov[0].iov_len) {
693                         state->iov[0].iov_base =
694                                 (char *)state->iov[0].iov_base + written;
695                         state->iov[0].iov_len -= written;
696                         break;
697                 }
698                 written = state->iov[0].iov_len;
699                 state->iov += 1;
700                 state->count -= 1;
701         }
702 }
703
704 ssize_t writev_recv(struct tevent_req *req, int *perrno)
705 {
706         struct writev_state *state = talloc_get_type_abort(
707                 req->private_state, struct writev_state);
708
709         if (tevent_req_is_unix_error(req, perrno)) {
710                 return -1;
711         }
712         return state->total_size;
713 }
714
715 struct read_packet_state {
716         int fd;
717         uint8_t *buf;
718         size_t nread;
719         ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
720         void *private_data;
721 };
722
723 static void read_packet_handler(struct tevent_context *ev,
724                                 struct tevent_fd *fde,
725                                 uint16_t flags, void *private_data);
726
727 struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
728                                     struct tevent_context *ev,
729                                     int fd, size_t initial,
730                                     ssize_t (*more)(uint8_t *buf,
731                                                     size_t buflen,
732                                                     void *private_data),
733                                     void *private_data)
734 {
735         struct tevent_req *result;
736         struct read_packet_state *state;
737         struct tevent_fd *fde;
738
739         result = tevent_req_create(mem_ctx, &state, struct read_packet_state);
740         if (result == NULL) {
741                 return NULL;
742         }
743         state->fd = fd;
744         state->nread = 0;
745         state->more = more;
746         state->private_data = private_data;
747
748         state->buf = talloc_array(state, uint8_t, initial);
749         if (state->buf == NULL) {
750                 goto fail;
751         }
752
753         fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler,
754                             result);
755         if (fde == NULL) {
756                 goto fail;
757         }
758         return result;
759  fail:
760         TALLOC_FREE(result);
761         return NULL;
762 }
763
764 static void read_packet_handler(struct tevent_context *ev,
765                                 struct tevent_fd *fde,
766                                 uint16_t flags, void *private_data)
767 {
768         struct tevent_req *req = talloc_get_type_abort(
769                 private_data, struct tevent_req);
770         struct read_packet_state *state = talloc_get_type_abort(
771                 req->private_state, struct read_packet_state);
772         size_t total = talloc_get_size(state->buf);
773         ssize_t nread, more;
774         uint8_t *tmp;
775
776         nread = read(state->fd, state->buf+state->nread, total-state->nread);
777         if (nread == -1) {
778                 tevent_req_error(req, errno);
779                 return;
780         }
781         if (nread == 0) {
782                 tevent_req_error(req, EPIPE);
783                 return;
784         }
785
786         state->nread += nread;
787         if (state->nread < total) {
788                 /* Come back later */
789                 return;
790         }
791
792         /*
793          * We got what was initially requested. See if "more" asks for -- more.
794          */
795         if (state->more == NULL) {
796                 /* Nobody to ask, this is a async read_data */
797                 tevent_req_done(req);
798                 return;
799         }
800
801         more = state->more(state->buf, total, state->private_data);
802         if (more == -1) {
803                 /* We got an invalid packet, tell the caller */
804                 tevent_req_error(req, EIO);
805                 return;
806         }
807         if (more == 0) {
808                 /* We're done, full packet received */
809                 tevent_req_done(req);
810                 return;
811         }
812
813         tmp = TALLOC_REALLOC_ARRAY(state, state->buf, uint8_t, total+more);
814         if (tevent_req_nomem(tmp, req)) {
815                 return;
816         }
817         state->buf = tmp;
818 }
819
820 ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
821                          uint8_t **pbuf, int *perrno)
822 {
823         struct read_packet_state *state = talloc_get_type_abort(
824                 req->private_state, struct read_packet_state);
825
826         if (tevent_req_is_unix_error(req, perrno)) {
827                 return -1;
828         }
829         *pbuf = talloc_move(mem_ctx, &state->buf);
830         return talloc_get_size(*pbuf);
831 }