Streamline the async_sock API a bit
[abartlet/samba.git/.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         SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
368         if (req->state == ASYNC_REQ_ERROR) {
369                 return req->status;
370         }
371         return NT_STATUS_OK;
372 }
373
374 /**
375  * fde event handler for the "recv" syscall
376  * @param[in] ev        The event context that sent us here
377  * @param[in] fde       The file descriptor event associated with the recv
378  * @param[in] flags     Can only be EVENT_FD_READ here
379  * @param[in] priv      private data, "struct async_req *" in this case
380  */
381
382 static void async_recv_callback(struct event_context *ev,
383                                 struct fd_event *fde, uint16_t flags,
384                                 void *priv)
385 {
386         struct async_req *req = talloc_get_type_abort(
387                 priv, struct async_req);
388         struct async_syscall_state *state = talloc_get_type_abort(
389                 req->private_data, struct async_syscall_state);
390         struct param_recv *p = &state->param.param_recv;
391
392         SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_RECV);
393
394         state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
395                                             p->flags);
396         state->sys_errno = errno;
397
398         TALLOC_FREE(state->fde);
399
400         async_req_done(req);
401 }
402
403 /**
404  * Async version of recv(2)
405  * @param[in] mem_ctx   The memory context to hang the result off
406  * @param[in] ev        The event context to work from
407  * @param[in] fd        The socket to recv from
408  * @param[in] buffer    The buffer to recv into
409  * @param[in] length    How many bytes to recv
410  * @param[in] flags     flags passed to recv(2)
411  *
412  * This function is a direct counterpart of recv(2)
413  */
414
415 struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct event_context *ev,
416                              int fd, void *buffer, size_t length,
417                              int flags)
418 {
419         struct async_req *result;
420         struct async_syscall_state *state;
421
422         result = async_fde_syscall_new(
423                 mem_ctx, ev, ASYNC_SYSCALL_RECV,
424                 fd, EVENT_FD_READ, async_recv_callback,
425                 &state);
426
427         if (result == NULL) {
428                 return NULL;
429         }
430
431         state->param.param_recv.fd = fd;
432         state->param.param_recv.buffer = buffer;
433         state->param.param_recv.length = length;
434         state->param.param_recv.flags = flags;
435
436         return result;
437 }
438
439 /**
440  * fde event handler for the "recvall" syscall group
441  * @param[in] ev        The event context that sent us here
442  * @param[in] fde       The file descriptor event associated with the recv
443  * @param[in] flags     Can only be EVENT_FD_READ here
444  * @param[in] priv      private data, "struct async_req *" in this case
445  */
446
447 static void async_recvall_callback(struct event_context *ev,
448                                    struct fd_event *fde, uint16_t flags,
449                                    void *priv)
450 {
451         struct async_req *req = talloc_get_type_abort(
452                 priv, struct async_req);
453         struct async_syscall_state *state = talloc_get_type_abort(
454                 req->private_data, struct async_syscall_state);
455         struct param_recvall *p = &state->param.param_recvall;
456
457         SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_RECVALL);
458
459         state->result.result_ssize_t = recv(p->fd,
460                                             (char *)p->buffer + p->received,
461                                             p->length - p->received, p->flags);
462         state->sys_errno = errno;
463
464         if (state->result.result_ssize_t == -1) {
465                 async_req_error(req, map_nt_error_from_unix(state->sys_errno));
466                 return;
467         }
468
469         if (state->result.result_ssize_t == 0) {
470                 async_req_error(req, NT_STATUS_END_OF_FILE);
471                 return;
472         }
473
474         p->received += state->result.result_ssize_t;
475         SMB_ASSERT(p->received <= p->length);
476
477         if (p->received == p->length) {
478                 TALLOC_FREE(state->fde);
479                 async_req_done(req);
480         }
481 }
482
483 /**
484  * Receive a specified number of bytes from a socket
485  * @param[in] mem_ctx   The memory context to hang the result off
486  * @param[in] ev        The event context to work from
487  * @param[in] fd        The socket to recv from
488  * @param[in] buffer    The buffer to recv into
489  * @param[in] length    How many bytes to recv
490  * @param[in] flags     flags passed to recv(2)
491  *
492  * async_recvall will call recv(2) until "length" bytes are received
493  */
494
495 struct async_req *recvall_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
496                                int fd, void *buffer, size_t length,
497                                int flags)
498 {
499         struct async_req *result;
500         struct async_syscall_state *state;
501
502         result = async_fde_syscall_new(
503                 mem_ctx, ev, ASYNC_SYSCALL_RECVALL,
504                 fd, EVENT_FD_READ, async_recvall_callback,
505                 &state);
506         if (result == NULL) {
507                 return NULL;
508         }
509
510         state->param.param_recvall.fd = fd;
511         state->param.param_recvall.buffer = buffer;
512         state->param.param_recvall.length = length;
513         state->param.param_recvall.flags = flags;
514         state->param.param_recvall.received = 0;
515
516         return result;
517 }
518
519 NTSTATUS recvall_recv(struct async_req *req)
520 {
521         SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
522         if (req->state == ASYNC_REQ_ERROR) {
523                 return req->status;
524         }
525         return NT_STATUS_OK;
526 }
527
528 /**
529  * fde event handler for connect(2)
530  * @param[in] ev        The event context that sent us here
531  * @param[in] fde       The file descriptor event associated with the connect
532  * @param[in] flags     Indicate read/writeability of the socket
533  * @param[in] priv      private data, "struct async_req *" in this case
534  */
535
536 static void async_connect_callback(struct event_context *ev,
537                                    struct fd_event *fde, uint16_t flags,
538                                    void *priv)
539 {
540         struct async_req *req = talloc_get_type_abort(
541                 priv, struct async_req);
542         struct async_syscall_state *state = talloc_get_type_abort(
543                 req->private_data, struct async_syscall_state);
544         struct param_connect *p = &state->param.param_connect;
545
546         SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_CONNECT);
547
548         TALLOC_FREE(state->fde);
549
550         /*
551          * Stevens, Network Programming says that if there's a
552          * successful connect, the socket is only writable. Upon an
553          * error, it's both readable and writable.
554          */
555         if ((flags & (EVENT_FD_READ|EVENT_FD_WRITE))
556             == (EVENT_FD_READ|EVENT_FD_WRITE)) {
557                 int sockerr;
558                 socklen_t err_len = sizeof(sockerr);
559
560                 if (getsockopt(p->fd, SOL_SOCKET, SO_ERROR,
561                                (void *)&sockerr, &err_len) == 0) {
562                         errno = sockerr;
563                 }
564
565                 state->sys_errno = errno;
566
567                 DEBUG(10, ("connect returned %s\n", strerror(errno)));
568
569                 sys_fcntl_long(p->fd, F_SETFL, p->old_sockflags);
570
571                 async_req_error(req, map_nt_error_from_unix(state->sys_errno));
572                 return;
573         }
574
575         sys_fcntl_long(p->fd, F_SETFL, p->old_sockflags);
576
577         state->result.result_int = 0;
578         state->sys_errno = 0;
579
580         async_req_done(req);
581 }
582
583 /**
584  * @brief async version of connect(2)
585  * @param[in] mem_ctx   The memory context to hang the result off
586  * @param[in] ev        The event context to work from
587  * @param[in] fd        The socket to recv from
588  * @param[in] address   Where to connect?
589  * @param[in] address_len Length of *address
590  * @retval The async request
591  *
592  * This function sets the socket into non-blocking state to be able to call
593  * connect in an async state. This will be reset when the request is finished.
594  */
595
596 struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev,
597                                 int fd, const struct sockaddr *address,
598                                 socklen_t address_len)
599 {
600         struct async_req *result;
601         struct async_syscall_state *state;
602         struct param_connect *p;
603
604         result = async_syscall_new(mem_ctx, ev, ASYNC_SYSCALL_CONNECT, &state);
605         if (result == NULL) {
606                 return NULL;
607         }
608         p = &state->param.param_connect;
609
610         /**
611          * We have to set the socket to nonblocking for async connect(2). Keep
612          * the old sockflags around.
613          */
614
615         p->old_sockflags = sys_fcntl_long(fd, F_GETFL, 0);
616
617         if (p->old_sockflags == -1) {
618                 if (async_post_status(result, map_nt_error_from_unix(errno))) {
619                         return result;
620                 }
621                 TALLOC_FREE(result);
622                 return NULL;
623         }
624
625         set_blocking(fd, true);
626
627         state->result.result_int = connect(fd, address, address_len);
628
629         if (state->result.result_int == 0) {
630                 state->sys_errno = 0;
631                 if (async_post_status(result, NT_STATUS_OK)) {
632                         return result;
633                 }
634                 sys_fcntl_long(fd, F_SETFL, p->old_sockflags);
635                 TALLOC_FREE(result);
636                 return NULL;
637         }
638
639         /**
640          * A number of error messages show that something good is progressing
641          * and that we have to wait for readability.
642          *
643          * If none of them are present, bail out.
644          */
645
646         if (!(errno == EINPROGRESS || errno == EALREADY ||
647 #ifdef EISCONN
648               errno == EISCONN ||
649 #endif
650               errno == EAGAIN || errno == EINTR)) {
651
652                 state->sys_errno = errno;
653
654                 if (async_post_status(result, map_nt_error_from_unix(errno))) {
655                         return result;
656                 }
657                 sys_fcntl_long(fd, F_SETFL, p->old_sockflags);
658                 TALLOC_FREE(result);
659                 return NULL;
660         }
661
662         state->fde = event_add_fd(ev, state, fd,
663                                   EVENT_FD_READ | EVENT_FD_WRITE,
664                                   async_connect_callback, result);
665         if (state->fde == NULL) {
666                 sys_fcntl_long(fd, F_SETFL, p->old_sockflags);
667                 TALLOC_FREE(result);
668                 return NULL;
669         }
670         result->private_data = state;
671
672         state->param.param_connect.fd = fd;
673         state->param.param_connect.address = address;
674         state->param.param_connect.address_len = address_len;
675
676         return result;
677 }
678