Simplify async programming a bit with helper routines
[kai/samba.git] / source3 / lib / 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
22 /**
23  * Discriminator for async_syscall_state
24  */
25 enum async_syscall_type {
26         ASYNC_SYSCALL_SEND,
27         ASYNC_SYSCALL_SENDALL,
28         ASYNC_SYSCALL_RECV,
29         ASYNC_SYSCALL_RECVALL,
30         ASYNC_SYSCALL_CONNECT
31 };
32
33 /**
34  * Holder for syscall arguments and the result
35  */
36
37 struct async_syscall_state {
38         enum async_syscall_type syscall_type;
39         struct fd_event *fde;
40
41         union {
42                 struct param_send {
43                         int fd;
44                         const void *buffer;
45                         size_t length;
46                         int flags;
47                 } param_send;
48                 struct param_sendall {
49                         int fd;
50                         const void *buffer;
51                         size_t length;
52                         int flags;
53                         size_t sent;
54                 } param_sendall;
55                 struct param_recv {
56                         int fd;
57                         void *buffer;
58                         size_t length;
59                         int flags;
60                 } param_recv;
61                 struct param_recvall {
62                         int fd;
63                         void *buffer;
64                         size_t length;
65                         int flags;
66                         size_t received;
67                 } param_recvall;
68                 struct param_connect {
69                         /**
70                          * connect needs to be done on a nonblocking
71                          * socket. Keep the old flags around
72                          */
73                         long old_sockflags;
74                         int fd;
75                         const struct sockaddr *address;
76                         socklen_t address_len;
77                 } param_connect;
78         } param;
79
80         union {
81                 ssize_t result_ssize_t;
82                 size_t result_size_t;
83                 int result_int;
84         } result;
85         int sys_errno;
86 };
87
88 /**
89  * @brief Create a new async syscall req
90  * @param[in] mem_ctx   The memory context to hang the result off
91  * @param[in] ev        The event context to work from
92  * @param[in] type      Which syscall will this be
93  * @param[in] pstate    Where to put the newly created private_data state
94  * @retval The new request
95  *
96  * This is a helper function to prepare a new struct async_req with an
97  * associated struct async_syscall_state. The async_syscall_state will be put
98  * into the async_req as private_data.
99  */
100
101 static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx,
102                                            struct event_context *ev,
103                                            enum async_syscall_type type,
104                                            struct async_syscall_state **pstate)
105 {
106         struct async_req *result;
107         struct async_syscall_state *state;
108
109         result = async_req_new(mem_ctx, ev);
110         if (result == NULL) {
111                 return NULL;
112         }
113
114         state = talloc(result, struct async_syscall_state);
115         if (state == NULL) {
116                 TALLOC_FREE(result);
117                 return NULL;
118         }
119
120         state->syscall_type = type;
121
122         result->private_data = state;
123
124         *pstate = state;
125
126         return result;
127 }
128
129 /**
130  * @brief Create a new async syscall req based on a fd
131  * @param[in] mem_ctx   The memory context to hang the result off
132  * @param[in] ev        The event context to work from
133  * @param[in] type      Which syscall will this be
134  * @param[in] fd        The file descriptor we work on
135  * @param[in] fde_flags EVENT_FD_READ/WRITE -- what are we interested in?
136  * @param[in] fde_cb    The callback function for the file descriptor event
137  * @param[in] pstate    Where to put the newly created private_data state
138  * @retval The new request
139  *
140  * This is a helper function to prepare a new struct async_req with an
141  * associated struct async_syscall_state and an associated file descriptor
142  * event.
143  */
144
145 static struct async_req *async_fde_syscall_new(
146         TALLOC_CTX *mem_ctx,
147         struct event_context *ev,
148         enum async_syscall_type type,
149         int fd,
150         uint16_t fde_flags,
151         void (*fde_cb)(struct event_context *ev,
152                        struct fd_event *fde, uint16_t flags,
153                        void *priv),
154         struct async_syscall_state **pstate)
155 {
156         struct async_req *result;
157         struct async_syscall_state *state;
158
159         result = async_syscall_new(mem_ctx, ev, type, &state);
160         if (result == NULL) {
161                 return NULL;
162         }
163
164         state->fde = event_add_fd(ev, state, fd, fde_flags, fde_cb, result);
165         if (state->fde == NULL) {
166                 TALLOC_FREE(result);
167                 return NULL;
168         }
169         *pstate = state;
170         return result;
171 }
172
173 /**
174  * Retrieve a ssize_t typed result from an async syscall
175  * @param[in] req       The syscall that has just finished
176  * @param[out] perrno   Where to put the syscall's errno
177  * @retval The return value from the asynchronously called syscall
178  */
179
180 ssize_t async_syscall_result_ssize_t(struct async_req *req, int *perrno)
181 {
182         struct async_syscall_state *state = talloc_get_type_abort(
183                 req->private_data, struct async_syscall_state);
184
185         *perrno = state->sys_errno;
186         return state->result.result_ssize_t;
187 }
188
189 /**
190  * Retrieve a size_t typed result from an async syscall
191  * @param[in] req       The syscall that has just finished
192  * @param[out] perrno   Where to put the syscall's errno
193  * @retval The return value from the asynchronously called syscall
194  */
195
196 size_t async_syscall_result_size_t(struct async_req *req, int *perrno)
197 {
198         struct async_syscall_state *state = talloc_get_type_abort(
199                 req->private_data, struct async_syscall_state);
200
201         *perrno = state->sys_errno;
202         return state->result.result_size_t;
203 }
204
205 /**
206  * Retrieve a int typed result from an async syscall
207  * @param[in] req       The syscall that has just finished
208  * @param[out] perrno   Where to put the syscall's errno
209  * @retval The return value from the asynchronously called syscall
210  */
211
212 ssize_t async_syscall_result_int(struct async_req *req, int *perrno)
213 {
214         struct async_syscall_state *state = talloc_get_type_abort(
215                 req->private_data, struct async_syscall_state);
216
217         *perrno = state->sys_errno;
218         return state->result.result_int;
219 }
220
221 /**
222  * fde event handler for the "send" syscall
223  * @param[in] ev        The event context that sent us here
224  * @param[in] fde       The file descriptor event associated with the send
225  * @param[in] flags     Can only be EVENT_FD_WRITE here
226  * @param[in] priv      private data, "struct async_req *" in this case
227  */
228
229 static void async_send_callback(struct event_context *ev,
230                                 struct fd_event *fde, uint16_t flags,
231                                 void *priv)
232 {
233         struct async_req *req = talloc_get_type_abort(
234                 priv, struct async_req);
235         struct async_syscall_state *state = talloc_get_type_abort(
236                 req->private_data, struct async_syscall_state);
237         struct param_send *p = &state->param.param_send;
238
239         SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_SEND);
240
241         state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
242                                             p->flags);
243         state->sys_errno = errno;
244
245         TALLOC_FREE(state->fde);
246
247         async_req_done(req);
248 }
249
250 /**
251  * Async version of send(2)
252  * @param[in] mem_ctx   The memory context to hang the result off
253  * @param[in] ev        The event context to work from
254  * @param[in] fd        The socket to send to
255  * @param[in] buffer    The buffer to send
256  * @param[in] length    How many bytes to send
257  * @param[in] flags     flags passed to send(2)
258  *
259  * This function is a direct counterpart of send(2)
260  */
261
262 struct async_req *async_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
263                              int fd, const void *buffer, size_t length,
264                              int flags)
265 {
266         struct async_req *result;
267         struct async_syscall_state *state;
268
269         result = async_fde_syscall_new(
270                 mem_ctx, ev, ASYNC_SYSCALL_SEND,
271                 fd, EVENT_FD_WRITE, async_send_callback,
272                 &state);
273         if (result == NULL) {
274                 return NULL;
275         }
276
277         state->param.param_send.fd = fd;
278         state->param.param_send.buffer = buffer;
279         state->param.param_send.length = length;
280         state->param.param_send.flags = flags;
281
282         return result;
283 }
284
285 /**
286  * fde event handler for the "sendall" syscall group
287  * @param[in] ev        The event context that sent us here
288  * @param[in] fde       The file descriptor event associated with the send
289  * @param[in] flags     Can only be EVENT_FD_WRITE here
290  * @param[in] priv      private data, "struct async_req *" in this case
291  */
292
293 static void async_sendall_callback(struct event_context *ev,
294                                    struct fd_event *fde, uint16_t flags,
295                                    void *priv)
296 {
297         struct async_req *req = talloc_get_type_abort(
298                 priv, struct async_req);
299         struct async_syscall_state *state = talloc_get_type_abort(
300                 req->private_data, struct async_syscall_state);
301         struct param_sendall *p = &state->param.param_sendall;
302
303         SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_SENDALL);
304
305         state->result.result_ssize_t = send(p->fd, (char *)p->buffer + p->sent,
306                                             p->length - p->sent, p->flags);
307         state->sys_errno = errno;
308
309         if (state->result.result_ssize_t == -1) {
310                 async_req_error(req, map_nt_error_from_unix(state->sys_errno));
311                 return;
312         }
313
314         if (state->result.result_ssize_t == 0) {
315                 async_req_error(req, NT_STATUS_END_OF_FILE);
316                 return;
317         }
318
319         p->sent += state->result.result_ssize_t;
320         SMB_ASSERT(p->sent <= p->length);
321
322         if (p->sent == p->length) {
323                 TALLOC_FREE(state->fde);
324                 async_req_done(req);
325         }
326 }
327
328 /**
329  * @brief Send all bytes to a socket
330  * @param[in] mem_ctx   The memory context to hang the result off
331  * @param[in] ev        The event context to work from
332  * @param[in] fd        The socket to send to
333  * @param[in] buffer    The buffer to send
334  * @param[in] length    How many bytes to send
335  * @param[in] flags     flags passed to send(2)
336  *
337  * async_sendall calls send(2) as long as it is necessary to send all of the
338  * "length" bytes
339  */
340
341 struct async_req *sendall_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
342                                int fd, const void *buffer, size_t length,
343                                int flags)
344 {
345         struct async_req *result;
346         struct async_syscall_state *state;
347
348         result = async_fde_syscall_new(
349                 mem_ctx, ev, ASYNC_SYSCALL_SENDALL,
350                 fd, EVENT_FD_WRITE, async_sendall_callback,
351                 &state);
352         if (result == NULL) {
353                 return NULL;
354         }
355
356         state->param.param_sendall.fd = fd;
357         state->param.param_sendall.buffer = buffer;
358         state->param.param_sendall.length = length;
359         state->param.param_sendall.flags = flags;
360         state->param.param_sendall.sent = 0;
361
362         return result;
363 }
364
365 NTSTATUS sendall_recv(struct async_req *req)
366 {
367         return async_req_simple_recv(req);
368 }
369
370 /**
371  * fde event handler for the "recv" syscall
372  * @param[in] ev        The event context that sent us here
373  * @param[in] fde       The file descriptor event associated with the recv
374  * @param[in] flags     Can only be EVENT_FD_READ here
375  * @param[in] priv      private data, "struct async_req *" in this case
376  */
377
378 static void async_recv_callback(struct event_context *ev,
379                                 struct fd_event *fde, uint16_t flags,
380                                 void *priv)
381 {
382         struct async_req *req = talloc_get_type_abort(
383                 priv, struct async_req);
384         struct async_syscall_state *state = talloc_get_type_abort(
385                 req->private_data, struct async_syscall_state);
386         struct param_recv *p = &state->param.param_recv;
387
388         SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_RECV);
389
390         state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
391                                             p->flags);
392         state->sys_errno = errno;
393
394         TALLOC_FREE(state->fde);
395
396         async_req_done(req);
397 }
398
399 /**
400  * Async version of recv(2)
401  * @param[in] mem_ctx   The memory context to hang the result off
402  * @param[in] ev        The event context to work from
403  * @param[in] fd        The socket to recv from
404  * @param[in] buffer    The buffer to recv into
405  * @param[in] length    How many bytes to recv
406  * @param[in] flags     flags passed to recv(2)
407  *
408  * This function is a direct counterpart of recv(2)
409  */
410
411 struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct event_context *ev,
412                              int fd, void *buffer, size_t length,
413                              int flags)
414 {
415         struct async_req *result;
416         struct async_syscall_state *state;
417
418         result = async_fde_syscall_new(
419                 mem_ctx, ev, ASYNC_SYSCALL_RECV,
420                 fd, EVENT_FD_READ, async_recv_callback,
421                 &state);
422
423         if (result == NULL) {
424                 return NULL;
425         }
426
427         state->param.param_recv.fd = fd;
428         state->param.param_recv.buffer = buffer;
429         state->param.param_recv.length = length;
430         state->param.param_recv.flags = flags;
431
432         return result;
433 }
434
435 /**
436  * fde event handler for the "recvall" syscall group
437  * @param[in] ev        The event context that sent us here
438  * @param[in] fde       The file descriptor event associated with the recv
439  * @param[in] flags     Can only be EVENT_FD_READ here
440  * @param[in] priv      private data, "struct async_req *" in this case
441  */
442
443 static void async_recvall_callback(struct event_context *ev,
444                                    struct fd_event *fde, uint16_t flags,
445                                    void *priv)
446 {
447         struct async_req *req = talloc_get_type_abort(
448                 priv, struct async_req);
449         struct async_syscall_state *state = talloc_get_type_abort(
450                 req->private_data, struct async_syscall_state);
451         struct param_recvall *p = &state->param.param_recvall;
452
453         SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_RECVALL);
454
455         state->result.result_ssize_t = recv(p->fd,
456                                             (char *)p->buffer + p->received,
457                                             p->length - p->received, p->flags);
458         state->sys_errno = errno;
459
460         if (state->result.result_ssize_t == -1) {
461                 async_req_error(req, map_nt_error_from_unix(state->sys_errno));
462                 return;
463         }
464
465         if (state->result.result_ssize_t == 0) {
466                 async_req_error(req, NT_STATUS_END_OF_FILE);
467                 return;
468         }
469
470         p->received += state->result.result_ssize_t;
471         SMB_ASSERT(p->received <= p->length);
472
473         if (p->received == p->length) {
474                 TALLOC_FREE(state->fde);
475                 async_req_done(req);
476         }
477 }
478
479 /**
480  * Receive a specified number of bytes from a socket
481  * @param[in] mem_ctx   The memory context to hang the result off
482  * @param[in] ev        The event context to work from
483  * @param[in] fd        The socket to recv from
484  * @param[in] buffer    The buffer to recv into
485  * @param[in] length    How many bytes to recv
486  * @param[in] flags     flags passed to recv(2)
487  *
488  * async_recvall will call recv(2) until "length" bytes are received
489  */
490
491 struct async_req *recvall_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
492                                int fd, void *buffer, size_t length,
493                                int flags)
494 {
495         struct async_req *result;
496         struct async_syscall_state *state;
497
498         result = async_fde_syscall_new(
499                 mem_ctx, ev, ASYNC_SYSCALL_RECVALL,
500                 fd, EVENT_FD_READ, async_recvall_callback,
501                 &state);
502         if (result == NULL) {
503                 return NULL;
504         }
505
506         state->param.param_recvall.fd = fd;
507         state->param.param_recvall.buffer = buffer;
508         state->param.param_recvall.length = length;
509         state->param.param_recvall.flags = flags;
510         state->param.param_recvall.received = 0;
511
512         return result;
513 }
514
515 NTSTATUS recvall_recv(struct async_req *req)
516 {
517         return async_req_simple_recv(req);
518 }
519
520 /**
521  * fde event handler for connect(2)
522  * @param[in] ev        The event context that sent us here
523  * @param[in] fde       The file descriptor event associated with the connect
524  * @param[in] flags     Indicate read/writeability of the socket
525  * @param[in] priv      private data, "struct async_req *" in this case
526  */
527
528 static void async_connect_callback(struct event_context *ev,
529                                    struct fd_event *fde, uint16_t flags,
530                                    void *priv)
531 {
532         struct async_req *req = talloc_get_type_abort(
533                 priv, struct async_req);
534         struct async_syscall_state *state = talloc_get_type_abort(
535                 req->private_data, struct async_syscall_state);
536         struct param_connect *p = &state->param.param_connect;
537
538         SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_CONNECT);
539
540         TALLOC_FREE(state->fde);
541
542         /*
543          * Stevens, Network Programming says that if there's a
544          * successful connect, the socket is only writable. Upon an
545          * error, it's both readable and writable.
546          */
547         if ((flags & (EVENT_FD_READ|EVENT_FD_WRITE))
548             == (EVENT_FD_READ|EVENT_FD_WRITE)) {
549                 int sockerr;
550                 socklen_t err_len = sizeof(sockerr);
551
552                 if (getsockopt(p->fd, SOL_SOCKET, SO_ERROR,
553                                (void *)&sockerr, &err_len) == 0) {
554                         errno = sockerr;
555                 }
556
557                 state->sys_errno = errno;
558
559                 DEBUG(10, ("connect returned %s\n", strerror(errno)));
560
561                 sys_fcntl_long(p->fd, F_SETFL, p->old_sockflags);
562
563                 async_req_error(req, map_nt_error_from_unix(state->sys_errno));
564                 return;
565         }
566
567         sys_fcntl_long(p->fd, F_SETFL, p->old_sockflags);
568
569         state->result.result_int = 0;
570         state->sys_errno = 0;
571
572         async_req_done(req);
573 }
574
575 /**
576  * @brief async version of connect(2)
577  * @param[in] mem_ctx   The memory context to hang the result off
578  * @param[in] ev        The event context to work from
579  * @param[in] fd        The socket to recv from
580  * @param[in] address   Where to connect?
581  * @param[in] address_len Length of *address
582  * @retval The async request
583  *
584  * This function sets the socket into non-blocking state to be able to call
585  * connect in an async state. This will be reset when the request is finished.
586  */
587
588 struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev,
589                                 int fd, const struct sockaddr *address,
590                                 socklen_t address_len)
591 {
592         struct async_req *result;
593         struct async_syscall_state *state;
594         struct param_connect *p;
595
596         result = async_syscall_new(mem_ctx, ev, ASYNC_SYSCALL_CONNECT, &state);
597         if (result == NULL) {
598                 return NULL;
599         }
600         p = &state->param.param_connect;
601
602         /**
603          * We have to set the socket to nonblocking for async connect(2). Keep
604          * the old sockflags around.
605          */
606
607         p->old_sockflags = sys_fcntl_long(fd, F_GETFL, 0);
608
609         if (p->old_sockflags == -1) {
610                 if (async_post_status(result, map_nt_error_from_unix(errno))) {
611                         return result;
612                 }
613                 TALLOC_FREE(result);
614                 return NULL;
615         }
616
617         set_blocking(fd, true);
618
619         state->result.result_int = connect(fd, address, address_len);
620
621         if (state->result.result_int == 0) {
622                 state->sys_errno = 0;
623                 if (async_post_status(result, NT_STATUS_OK)) {
624                         return result;
625                 }
626                 sys_fcntl_long(fd, F_SETFL, p->old_sockflags);
627                 TALLOC_FREE(result);
628                 return NULL;
629         }
630
631         /**
632          * A number of error messages show that something good is progressing
633          * and that we have to wait for readability.
634          *
635          * If none of them are present, bail out.
636          */
637
638         if (!(errno == EINPROGRESS || errno == EALREADY ||
639 #ifdef EISCONN
640               errno == EISCONN ||
641 #endif
642               errno == EAGAIN || errno == EINTR)) {
643
644                 state->sys_errno = errno;
645
646                 if (async_post_status(result, map_nt_error_from_unix(errno))) {
647                         return result;
648                 }
649                 sys_fcntl_long(fd, F_SETFL, p->old_sockflags);
650                 TALLOC_FREE(result);
651                 return NULL;
652         }
653
654         state->fde = event_add_fd(ev, state, fd,
655                                   EVENT_FD_READ | EVENT_FD_WRITE,
656                                   async_connect_callback, result);
657         if (state->fde == NULL) {
658                 sys_fcntl_long(fd, F_SETFL, p->old_sockflags);
659                 TALLOC_FREE(result);
660                 return NULL;
661         }
662         result->private_data = state;
663
664         state->param.param_connect.fd = fd;
665         state->param.param_connect.address = address;
666         state->param.param_connect.address_len = address_len;
667
668         return result;
669 }
670