tsocket: optimize tdgram_bsd a lot
[ira/wip.git] / lib / tsocket / tsocket.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2009
5
6      ** NOTE! The following LGPL license applies to the tevent
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 3 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "replace.h"
25 #include "system/network.h"
26 #include "tsocket.h"
27 #include "tsocket_internal.h"
28
29 static int tsocket_context_destructor(struct tsocket_context *sock)
30 {
31         tsocket_disconnect(sock);
32         return 0;
33 }
34
35 struct tsocket_context *_tsocket_context_create(TALLOC_CTX *mem_ctx,
36                                                 const struct tsocket_context_ops *ops,
37                                                 void *pstate,
38                                                 size_t psize,
39                                                 const char *type,
40                                                 const char *location)
41 {
42         void **ppstate = (void **)pstate;
43         struct tsocket_context *sock;
44
45         sock = talloc_zero(mem_ctx, struct tsocket_context);
46         if (!sock) {
47                 return NULL;
48         }
49         sock->ops = ops;
50         sock->location = location;
51         sock->private_data = talloc_size(sock, psize);
52         if (!sock->private_data) {
53                 talloc_free(sock);
54                 return NULL;
55         }
56         talloc_set_name_const(sock->private_data, type);
57
58         talloc_set_destructor(sock, tsocket_context_destructor);
59
60         *ppstate = sock->private_data;
61         return sock;
62 }
63
64 int tsocket_set_event_context(struct tsocket_context *sock,
65                               struct tevent_context *ev)
66 {
67         return sock->ops->set_event_context(sock, ev);
68 }
69
70 int tsocket_set_readable_handler(struct tsocket_context *sock,
71                                  tsocket_event_handler_t handler,
72                                  void *private_data)
73 {
74         return sock->ops->set_read_handler(sock, handler, private_data);
75 }
76
77 int tsocket_set_writeable_handler(struct tsocket_context *sock,
78                                   tsocket_event_handler_t handler,
79                                   void *private_data)
80 {
81         return sock->ops->set_write_handler(sock, handler, private_data);
82 }
83
84 int tsocket_connect(struct tsocket_context *sock,
85                     const struct tsocket_address *remote_addr)
86 {
87         return sock->ops->connect_to(sock, remote_addr);
88 }
89
90 int tsocket_listen(struct tsocket_context *sock,
91                    int queue_size)
92 {
93         return sock->ops->listen_on(sock, queue_size);
94 }
95
96 int _tsocket_accept(struct tsocket_context *sock,
97                     TALLOC_CTX *mem_ctx,
98                     struct tsocket_context **new_sock,
99                     const char *location)
100 {
101         return sock->ops->accept_new(sock, mem_ctx, new_sock, location);
102 }
103
104 ssize_t tsocket_pending(struct tsocket_context *sock)
105 {
106         return sock->ops->pending_data(sock);
107 }
108
109 int tsocket_readv(struct tsocket_context *sock,
110                   const struct iovec *vector, size_t count)
111 {
112         return sock->ops->readv_data(sock, vector, count);
113 }
114
115 int tsocket_writev(struct tsocket_context *sock,
116                    const struct iovec *vector, size_t count)
117 {
118         return sock->ops->writev_data(sock, vector, count);
119 }
120
121 ssize_t tsocket_recvfrom(struct tsocket_context *sock,
122                          uint8_t *data, size_t len,
123                          TALLOC_CTX *addr_ctx,
124                          struct tsocket_address **src_addr)
125 {
126         return sock->ops->recvfrom_data(sock, data, len, addr_ctx, src_addr);
127 }
128
129 ssize_t tsocket_sendto(struct tsocket_context *sock,
130                        const uint8_t *data, size_t len,
131                        const struct tsocket_address *dest_addr)
132 {
133         return sock->ops->sendto_data(sock, data, len, dest_addr);
134 }
135
136 int tsocket_get_status(const struct tsocket_context *sock)
137 {
138         return sock->ops->get_status(sock);
139 }
140
141 int _tsocket_get_local_address(const struct tsocket_context *sock,
142                                TALLOC_CTX *mem_ctx,
143                                struct tsocket_address **local_addr,
144                                const char *location)
145 {
146         return sock->ops->get_local_address(sock, mem_ctx,
147                                             local_addr, location);
148 }
149
150 int _tsocket_get_remote_address(const struct tsocket_context *sock,
151                                 TALLOC_CTX *mem_ctx,
152                                 struct tsocket_address **remote_addr,
153                                 const char *location)
154 {
155         return sock->ops->get_remote_address(sock, mem_ctx,
156                                              remote_addr, location);
157 }
158
159 int tsocket_get_option(const struct tsocket_context *sock,
160                        const char *option,
161                        TALLOC_CTX *mem_ctx,
162                        char **value)
163 {
164         return sock->ops->get_option(sock, option, mem_ctx, value);
165 }
166
167 int tsocket_set_option(const struct tsocket_context *sock,
168                        const char *option,
169                        bool force,
170                        const char *value)
171 {
172         return sock->ops->set_option(sock, option, force, value);
173 }
174
175 void tsocket_disconnect(struct tsocket_context *sock)
176 {
177         sock->ops->disconnect(sock);
178 }
179
180 struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
181                                                 const struct tsocket_address_ops *ops,
182                                                 void *pstate,
183                                                 size_t psize,
184                                                 const char *type,
185                                                 const char *location)
186 {
187         void **ppstate = (void **)pstate;
188         struct tsocket_address *addr;
189
190         addr = talloc_zero(mem_ctx, struct tsocket_address);
191         if (!addr) {
192                 return NULL;
193         }
194         addr->ops = ops;
195         addr->location = location;
196         addr->private_data = talloc_size(addr, psize);
197         if (!addr->private_data) {
198                 talloc_free(addr);
199                 return NULL;
200         }
201         talloc_set_name_const(addr->private_data, type);
202
203         *ppstate = addr->private_data;
204         return addr;
205 }
206
207 char *tsocket_address_string(const struct tsocket_address *addr,
208                              TALLOC_CTX *mem_ctx)
209 {
210         if (!addr) {
211                 return talloc_strdup(mem_ctx, "NULL");
212         }
213         return addr->ops->string(addr, mem_ctx);
214 }
215
216 struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
217                                               TALLOC_CTX *mem_ctx,
218                                               const char *location)
219 {
220         return addr->ops->copy(addr, mem_ctx, location);
221 }
222
223 int _tsocket_address_create_socket(const struct tsocket_address *addr,
224                                    enum tsocket_type type,
225                                    TALLOC_CTX *mem_ctx,
226                                    struct tsocket_context **sock,
227                                    const char *location)
228 {
229         return addr->ops->create_socket(addr, type, mem_ctx, sock, location);
230 }
231
232 struct tdgram_context {
233         const char *location;
234         const struct tdgram_context_ops *ops;
235         void *private_data;
236 };
237
238 struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
239                                         const struct tdgram_context_ops *ops,
240                                         void *pstate,
241                                         size_t psize,
242                                         const char *type,
243                                         const char *location)
244 {
245         struct tdgram_context *dgram;
246         void **ppstate = (void **)pstate;
247         void *state;
248
249         dgram = talloc(mem_ctx, struct tdgram_context);
250         if (dgram == NULL) {
251                 return NULL;
252         }
253         dgram->location = location;
254         dgram->ops      = ops;
255
256         state = talloc_size(dgram, psize);
257         if (state == NULL) {
258                 talloc_free(dgram);
259                 return NULL;
260         }
261         talloc_set_name_const(state, type);
262
263         dgram->private_data = state;
264
265         *ppstate = state;
266         return dgram;
267 }
268
269 void *_tdgram_context_data(struct tdgram_context *dgram)
270 {
271         return dgram->private_data;
272 }
273
274 struct tdgram_recvfrom_state {
275         const struct tdgram_context_ops *ops;
276         uint8_t *buf;
277         size_t len;
278         struct tsocket_address *src;
279 };
280
281 static void tdgram_recvfrom_done(struct tevent_req *subreq);
282
283 struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
284                                         struct tevent_context *ev,
285                                         struct tdgram_context *dgram)
286 {
287         struct tevent_req *req;
288         struct tdgram_recvfrom_state *state;
289         struct tevent_req *subreq;
290
291         req = tevent_req_create(mem_ctx, &state,
292                                 struct tdgram_recvfrom_state);
293         if (req == NULL) {
294                 return NULL;
295         }
296
297         state->ops = dgram->ops;
298
299         subreq = state->ops->recvfrom_send(state, ev, dgram);
300         if (tevent_req_nomem(subreq, req)) {
301                 goto post;
302         }
303         tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
304
305         return req;
306
307  post:
308         tevent_req_post(req, ev);
309         return req;
310 }
311
312 static void tdgram_recvfrom_done(struct tevent_req *subreq)
313 {
314         struct tevent_req *req = tevent_req_callback_data(subreq,
315                                  struct tevent_req);
316         struct tdgram_recvfrom_state *state = tevent_req_data(req,
317                                               struct tdgram_recvfrom_state);
318         ssize_t ret;
319         int sys_errno;
320
321         ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
322                                         &state->buf, &state->src);
323         if (ret == -1) {
324                 tevent_req_error(req, sys_errno);
325                 return;
326         }
327
328         state->len = ret;
329
330         tevent_req_done(req);
331 }
332
333 ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
334                              int *perrno,
335                              TALLOC_CTX *mem_ctx,
336                              uint8_t **buf,
337                              struct tsocket_address **src)
338 {
339         struct tdgram_recvfrom_state *state = tevent_req_data(req,
340                                               struct tdgram_recvfrom_state);
341         ssize_t ret;
342
343         ret = tsocket_simple_int_recv(req, perrno);
344         if (ret == 0) {
345                 *buf = talloc_move(mem_ctx, &state->buf);
346                 ret = state->len;
347                 if (src) {
348                         *src = talloc_move(mem_ctx, &state->src);
349                 }
350         }
351
352         tevent_req_received(req);
353         return ret;
354 }
355
356 struct tdgram_sendto_state {
357         const struct tdgram_context_ops *ops;
358         ssize_t ret;
359 };
360
361 static void tdgram_sendto_done(struct tevent_req *subreq);
362
363 struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
364                                       struct tevent_context *ev,
365                                       struct tdgram_context *dgram,
366                                       const uint8_t *buf, size_t len,
367                                       const struct tsocket_address *dst)
368 {
369         struct tevent_req *req;
370         struct tdgram_sendto_state *state;
371         struct tevent_req *subreq;
372
373         req = tevent_req_create(mem_ctx, &state,
374                                 struct tdgram_sendto_state);
375         if (req == NULL) {
376                 return NULL;
377         }
378
379         state->ops = dgram->ops;
380         state->ret = -1;
381
382         subreq = state->ops->sendto_send(state, ev, dgram,
383                                          buf, len, dst);
384         if (tevent_req_nomem(subreq, req)) {
385                 goto post;
386         }
387         tevent_req_set_callback(subreq, tdgram_sendto_done, req);
388
389         return req;
390
391  post:
392         tevent_req_post(req, ev);
393         return req;
394 }
395
396 static void tdgram_sendto_done(struct tevent_req *subreq)
397 {
398         struct tevent_req *req = tevent_req_callback_data(subreq,
399                                  struct tevent_req);
400         struct tdgram_sendto_state *state = tevent_req_data(req,
401                                             struct tdgram_sendto_state);
402         ssize_t ret;
403         int sys_errno;
404
405         ret = state->ops->sendto_recv(subreq, &sys_errno);
406         if (ret == -1) {
407                 tevent_req_error(req, sys_errno);
408                 return;
409         }
410
411         state->ret = ret;
412
413         tevent_req_done(req);
414 }
415
416 ssize_t tdgram_sendto_recv(struct tevent_req *req,
417                            int *perrno)
418 {
419         struct tdgram_sendto_state *state = tevent_req_data(req,
420                                             struct tdgram_sendto_state);
421         ssize_t ret;
422
423         ret = tsocket_simple_int_recv(req, perrno);
424         if (ret == 0) {
425                 ret = state->ret;
426         }
427
428         tevent_req_received(req);
429         return ret;
430 }
431
432 struct tdgram_disconnect_state {
433         const struct tdgram_context_ops *ops;
434 };
435
436 static void tdgram_disconnect_done(struct tevent_req *subreq);
437
438 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
439                                           struct tevent_context *ev,
440                                           struct tdgram_context *dgram)
441 {
442         struct tevent_req *req;
443         struct tdgram_disconnect_state *state;
444         struct tevent_req *subreq;
445
446         req = tevent_req_create(mem_ctx, &state,
447                                 struct tdgram_disconnect_state);
448         if (req == NULL) {
449                 return NULL;
450         }
451
452         state->ops = dgram->ops;
453
454         subreq = state->ops->disconnect_send(state, ev, dgram);
455         if (tevent_req_nomem(subreq, req)) {
456                 goto post;
457         }
458         tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
459
460         return req;
461
462  post:
463         tevent_req_post(req, ev);
464         return req;
465 }
466
467 static void tdgram_disconnect_done(struct tevent_req *subreq)
468 {
469         struct tevent_req *req = tevent_req_callback_data(subreq,
470                                  struct tevent_req);
471         struct tdgram_disconnect_state *state = tevent_req_data(req,
472                                                 struct tdgram_disconnect_state);
473         int ret;
474         int sys_errno;
475
476         ret = state->ops->disconnect_recv(subreq, &sys_errno);
477         if (ret == -1) {
478                 tevent_req_error(req, sys_errno);
479                 return;
480         }
481
482         tevent_req_done(req);
483 }
484
485 int tdgram_disconnect_recv(struct tevent_req *req,
486                            int *perrno)
487 {
488         int ret;
489
490         ret = tsocket_simple_int_recv(req, perrno);
491
492         tevent_req_received(req);
493         return ret;
494 }
495
496 struct tdgram_sendto_queue_state {
497         /* this structs are owned by the caller */
498         struct {
499                 struct tevent_context *ev;
500                 struct tdgram_context *dgram;
501                 const uint8_t *buf;
502                 size_t len;
503                 const struct tsocket_address *dst;
504         } caller;
505         ssize_t ret;
506 };
507
508 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
509                                          void *private_data);
510 static void tdgram_sendto_queue_done(struct tevent_req *subreq);
511
512 /**
513  * @brief Queue a dgram blob for sending through the socket
514  * @param[in] mem_ctx   The memory context for the result
515  * @param[in] ev        The event context the operation should work on
516  * @param[in] dgram     The tdgram_context to send the message buffer
517  * @param[in] queue     The existing dgram queue
518  * @param[in] buf       The message buffer
519  * @param[in] len       The message length
520  * @param[in] dst       The destination socket address
521  * @retval              The async request handle
522  *
523  * This function queues a blob for sending to destination through an existing
524  * dgram socket. The async callback is triggered when the whole blob is
525  * delivered to the underlying system socket.
526  *
527  * The caller needs to make sure that all non-scalar input parameters hang
528  * arround for the whole lifetime of the request.
529  */
530 struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
531                                             struct tevent_context *ev,
532                                             struct tdgram_context *dgram,
533                                             struct tevent_queue *queue,
534                                             const uint8_t *buf,
535                                             size_t len,
536                                             struct tsocket_address *dst)
537 {
538         struct tevent_req *req;
539         struct tdgram_sendto_queue_state *state;
540         bool ok;
541
542         req = tevent_req_create(mem_ctx, &state,
543                                 struct tdgram_sendto_queue_state);
544         if (!req) {
545                 return NULL;
546         }
547
548         state->caller.ev        = ev;
549         state->caller.dgram     = dgram;
550         state->caller.buf       = buf;
551         state->caller.len       = len;
552         state->caller.dst       = dst;
553         state->ret              = -1;
554
555         ok = tevent_queue_add(queue,
556                               ev,
557                               req,
558                               tdgram_sendto_queue_trigger,
559                               NULL);
560         if (!ok) {
561                 tevent_req_nomem(NULL, req);
562                 goto post;
563         }
564
565         return req;
566
567  post:
568         tevent_req_post(req, ev);
569         return req;
570 }
571
572 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
573                                          void *private_data)
574 {
575         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
576                                         struct tdgram_sendto_queue_state);
577         struct tevent_req *subreq;
578
579         subreq = tdgram_sendto_send(state,
580                                     state->caller.ev,
581                                     state->caller.dgram,
582                                     state->caller.buf,
583                                     state->caller.len,
584                                     state->caller.dst);
585         if (tevent_req_nomem(subreq, req)) {
586                 return;
587         }
588         tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
589 }
590
591 static void tdgram_sendto_queue_done(struct tevent_req *subreq)
592 {
593         struct tevent_req *req = tevent_req_callback_data(subreq,
594                                  struct tevent_req);
595         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
596                                         struct tdgram_sendto_queue_state);
597         ssize_t ret;
598         int sys_errno;
599
600         ret = tdgram_sendto_recv(subreq, &sys_errno);
601         talloc_free(subreq);
602         if (ret == -1) {
603                 tevent_req_error(req, sys_errno);
604                 return;
605         }
606         state->ret = ret;
607
608         tevent_req_done(req);
609 }
610
611 ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
612 {
613         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
614                                         struct tdgram_sendto_queue_state);
615         ssize_t ret;
616
617         ret = tsocket_simple_int_recv(req, perrno);
618         if (ret == 0) {
619                 ret = state->ret;
620         }
621
622         tevent_req_received(req);
623         return ret;
624 }
625