tsocket: remove DGRAM support from tsocket_context
[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 int tsocket_get_status(const struct tsocket_context *sock)
122 {
123         return sock->ops->get_status(sock);
124 }
125
126 int _tsocket_get_local_address(const struct tsocket_context *sock,
127                                TALLOC_CTX *mem_ctx,
128                                struct tsocket_address **local_addr,
129                                const char *location)
130 {
131         return sock->ops->get_local_address(sock, mem_ctx,
132                                             local_addr, location);
133 }
134
135 int _tsocket_get_remote_address(const struct tsocket_context *sock,
136                                 TALLOC_CTX *mem_ctx,
137                                 struct tsocket_address **remote_addr,
138                                 const char *location)
139 {
140         return sock->ops->get_remote_address(sock, mem_ctx,
141                                              remote_addr, location);
142 }
143
144 int tsocket_get_option(const struct tsocket_context *sock,
145                        const char *option,
146                        TALLOC_CTX *mem_ctx,
147                        char **value)
148 {
149         return sock->ops->get_option(sock, option, mem_ctx, value);
150 }
151
152 int tsocket_set_option(const struct tsocket_context *sock,
153                        const char *option,
154                        bool force,
155                        const char *value)
156 {
157         return sock->ops->set_option(sock, option, force, value);
158 }
159
160 void tsocket_disconnect(struct tsocket_context *sock)
161 {
162         sock->ops->disconnect(sock);
163 }
164
165 struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
166                                                 const struct tsocket_address_ops *ops,
167                                                 void *pstate,
168                                                 size_t psize,
169                                                 const char *type,
170                                                 const char *location)
171 {
172         void **ppstate = (void **)pstate;
173         struct tsocket_address *addr;
174
175         addr = talloc_zero(mem_ctx, struct tsocket_address);
176         if (!addr) {
177                 return NULL;
178         }
179         addr->ops = ops;
180         addr->location = location;
181         addr->private_data = talloc_size(addr, psize);
182         if (!addr->private_data) {
183                 talloc_free(addr);
184                 return NULL;
185         }
186         talloc_set_name_const(addr->private_data, type);
187
188         *ppstate = addr->private_data;
189         return addr;
190 }
191
192 char *tsocket_address_string(const struct tsocket_address *addr,
193                              TALLOC_CTX *mem_ctx)
194 {
195         if (!addr) {
196                 return talloc_strdup(mem_ctx, "NULL");
197         }
198         return addr->ops->string(addr, mem_ctx);
199 }
200
201 struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
202                                               TALLOC_CTX *mem_ctx,
203                                               const char *location)
204 {
205         return addr->ops->copy(addr, mem_ctx, location);
206 }
207
208 int _tsocket_address_create_socket(const struct tsocket_address *addr,
209                                    enum tsocket_type type,
210                                    TALLOC_CTX *mem_ctx,
211                                    struct tsocket_context **sock,
212                                    const char *location)
213 {
214         return addr->ops->create_socket(addr, type, mem_ctx, sock, location);
215 }
216
217 struct tdgram_context {
218         const char *location;
219         const struct tdgram_context_ops *ops;
220         void *private_data;
221 };
222
223 struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
224                                         const struct tdgram_context_ops *ops,
225                                         void *pstate,
226                                         size_t psize,
227                                         const char *type,
228                                         const char *location)
229 {
230         struct tdgram_context *dgram;
231         void **ppstate = (void **)pstate;
232         void *state;
233
234         dgram = talloc(mem_ctx, struct tdgram_context);
235         if (dgram == NULL) {
236                 return NULL;
237         }
238         dgram->location = location;
239         dgram->ops      = ops;
240
241         state = talloc_size(dgram, psize);
242         if (state == NULL) {
243                 talloc_free(dgram);
244                 return NULL;
245         }
246         talloc_set_name_const(state, type);
247
248         dgram->private_data = state;
249
250         *ppstate = state;
251         return dgram;
252 }
253
254 void *_tdgram_context_data(struct tdgram_context *dgram)
255 {
256         return dgram->private_data;
257 }
258
259 struct tdgram_recvfrom_state {
260         const struct tdgram_context_ops *ops;
261         uint8_t *buf;
262         size_t len;
263         struct tsocket_address *src;
264 };
265
266 static void tdgram_recvfrom_done(struct tevent_req *subreq);
267
268 struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
269                                         struct tevent_context *ev,
270                                         struct tdgram_context *dgram)
271 {
272         struct tevent_req *req;
273         struct tdgram_recvfrom_state *state;
274         struct tevent_req *subreq;
275
276         req = tevent_req_create(mem_ctx, &state,
277                                 struct tdgram_recvfrom_state);
278         if (req == NULL) {
279                 return NULL;
280         }
281
282         state->ops = dgram->ops;
283
284         subreq = state->ops->recvfrom_send(state, ev, dgram);
285         if (tevent_req_nomem(subreq, req)) {
286                 goto post;
287         }
288         tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
289
290         return req;
291
292  post:
293         tevent_req_post(req, ev);
294         return req;
295 }
296
297 static void tdgram_recvfrom_done(struct tevent_req *subreq)
298 {
299         struct tevent_req *req = tevent_req_callback_data(subreq,
300                                  struct tevent_req);
301         struct tdgram_recvfrom_state *state = tevent_req_data(req,
302                                               struct tdgram_recvfrom_state);
303         ssize_t ret;
304         int sys_errno;
305
306         ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
307                                         &state->buf, &state->src);
308         if (ret == -1) {
309                 tevent_req_error(req, sys_errno);
310                 return;
311         }
312
313         state->len = ret;
314
315         tevent_req_done(req);
316 }
317
318 ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
319                              int *perrno,
320                              TALLOC_CTX *mem_ctx,
321                              uint8_t **buf,
322                              struct tsocket_address **src)
323 {
324         struct tdgram_recvfrom_state *state = tevent_req_data(req,
325                                               struct tdgram_recvfrom_state);
326         ssize_t ret;
327
328         ret = tsocket_simple_int_recv(req, perrno);
329         if (ret == 0) {
330                 *buf = talloc_move(mem_ctx, &state->buf);
331                 ret = state->len;
332                 if (src) {
333                         *src = talloc_move(mem_ctx, &state->src);
334                 }
335         }
336
337         tevent_req_received(req);
338         return ret;
339 }
340
341 struct tdgram_sendto_state {
342         const struct tdgram_context_ops *ops;
343         ssize_t ret;
344 };
345
346 static void tdgram_sendto_done(struct tevent_req *subreq);
347
348 struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
349                                       struct tevent_context *ev,
350                                       struct tdgram_context *dgram,
351                                       const uint8_t *buf, size_t len,
352                                       const struct tsocket_address *dst)
353 {
354         struct tevent_req *req;
355         struct tdgram_sendto_state *state;
356         struct tevent_req *subreq;
357
358         req = tevent_req_create(mem_ctx, &state,
359                                 struct tdgram_sendto_state);
360         if (req == NULL) {
361                 return NULL;
362         }
363
364         state->ops = dgram->ops;
365         state->ret = -1;
366
367         subreq = state->ops->sendto_send(state, ev, dgram,
368                                          buf, len, dst);
369         if (tevent_req_nomem(subreq, req)) {
370                 goto post;
371         }
372         tevent_req_set_callback(subreq, tdgram_sendto_done, req);
373
374         return req;
375
376  post:
377         tevent_req_post(req, ev);
378         return req;
379 }
380
381 static void tdgram_sendto_done(struct tevent_req *subreq)
382 {
383         struct tevent_req *req = tevent_req_callback_data(subreq,
384                                  struct tevent_req);
385         struct tdgram_sendto_state *state = tevent_req_data(req,
386                                             struct tdgram_sendto_state);
387         ssize_t ret;
388         int sys_errno;
389
390         ret = state->ops->sendto_recv(subreq, &sys_errno);
391         if (ret == -1) {
392                 tevent_req_error(req, sys_errno);
393                 return;
394         }
395
396         state->ret = ret;
397
398         tevent_req_done(req);
399 }
400
401 ssize_t tdgram_sendto_recv(struct tevent_req *req,
402                            int *perrno)
403 {
404         struct tdgram_sendto_state *state = tevent_req_data(req,
405                                             struct tdgram_sendto_state);
406         ssize_t ret;
407
408         ret = tsocket_simple_int_recv(req, perrno);
409         if (ret == 0) {
410                 ret = state->ret;
411         }
412
413         tevent_req_received(req);
414         return ret;
415 }
416
417 struct tdgram_disconnect_state {
418         const struct tdgram_context_ops *ops;
419 };
420
421 static void tdgram_disconnect_done(struct tevent_req *subreq);
422
423 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
424                                           struct tevent_context *ev,
425                                           struct tdgram_context *dgram)
426 {
427         struct tevent_req *req;
428         struct tdgram_disconnect_state *state;
429         struct tevent_req *subreq;
430
431         req = tevent_req_create(mem_ctx, &state,
432                                 struct tdgram_disconnect_state);
433         if (req == NULL) {
434                 return NULL;
435         }
436
437         state->ops = dgram->ops;
438
439         subreq = state->ops->disconnect_send(state, ev, dgram);
440         if (tevent_req_nomem(subreq, req)) {
441                 goto post;
442         }
443         tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
444
445         return req;
446
447  post:
448         tevent_req_post(req, ev);
449         return req;
450 }
451
452 static void tdgram_disconnect_done(struct tevent_req *subreq)
453 {
454         struct tevent_req *req = tevent_req_callback_data(subreq,
455                                  struct tevent_req);
456         struct tdgram_disconnect_state *state = tevent_req_data(req,
457                                                 struct tdgram_disconnect_state);
458         int ret;
459         int sys_errno;
460
461         ret = state->ops->disconnect_recv(subreq, &sys_errno);
462         if (ret == -1) {
463                 tevent_req_error(req, sys_errno);
464                 return;
465         }
466
467         tevent_req_done(req);
468 }
469
470 int tdgram_disconnect_recv(struct tevent_req *req,
471                            int *perrno)
472 {
473         int ret;
474
475         ret = tsocket_simple_int_recv(req, perrno);
476
477         tevent_req_received(req);
478         return ret;
479 }
480
481 struct tdgram_sendto_queue_state {
482         /* this structs are owned by the caller */
483         struct {
484                 struct tevent_context *ev;
485                 struct tdgram_context *dgram;
486                 const uint8_t *buf;
487                 size_t len;
488                 const struct tsocket_address *dst;
489         } caller;
490         ssize_t ret;
491 };
492
493 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
494                                          void *private_data);
495 static void tdgram_sendto_queue_done(struct tevent_req *subreq);
496
497 /**
498  * @brief Queue a dgram blob for sending through the socket
499  * @param[in] mem_ctx   The memory context for the result
500  * @param[in] ev        The event context the operation should work on
501  * @param[in] dgram     The tdgram_context to send the message buffer
502  * @param[in] queue     The existing dgram queue
503  * @param[in] buf       The message buffer
504  * @param[in] len       The message length
505  * @param[in] dst       The destination socket address
506  * @retval              The async request handle
507  *
508  * This function queues a blob for sending to destination through an existing
509  * dgram socket. The async callback is triggered when the whole blob is
510  * delivered to the underlying system socket.
511  *
512  * The caller needs to make sure that all non-scalar input parameters hang
513  * arround for the whole lifetime of the request.
514  */
515 struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
516                                             struct tevent_context *ev,
517                                             struct tdgram_context *dgram,
518                                             struct tevent_queue *queue,
519                                             const uint8_t *buf,
520                                             size_t len,
521                                             struct tsocket_address *dst)
522 {
523         struct tevent_req *req;
524         struct tdgram_sendto_queue_state *state;
525         bool ok;
526
527         req = tevent_req_create(mem_ctx, &state,
528                                 struct tdgram_sendto_queue_state);
529         if (!req) {
530                 return NULL;
531         }
532
533         state->caller.ev        = ev;
534         state->caller.dgram     = dgram;
535         state->caller.buf       = buf;
536         state->caller.len       = len;
537         state->caller.dst       = dst;
538         state->ret              = -1;
539
540         ok = tevent_queue_add(queue,
541                               ev,
542                               req,
543                               tdgram_sendto_queue_trigger,
544                               NULL);
545         if (!ok) {
546                 tevent_req_nomem(NULL, req);
547                 goto post;
548         }
549
550         return req;
551
552  post:
553         tevent_req_post(req, ev);
554         return req;
555 }
556
557 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
558                                          void *private_data)
559 {
560         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
561                                         struct tdgram_sendto_queue_state);
562         struct tevent_req *subreq;
563
564         subreq = tdgram_sendto_send(state,
565                                     state->caller.ev,
566                                     state->caller.dgram,
567                                     state->caller.buf,
568                                     state->caller.len,
569                                     state->caller.dst);
570         if (tevent_req_nomem(subreq, req)) {
571                 return;
572         }
573         tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
574 }
575
576 static void tdgram_sendto_queue_done(struct tevent_req *subreq)
577 {
578         struct tevent_req *req = tevent_req_callback_data(subreq,
579                                  struct tevent_req);
580         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
581                                         struct tdgram_sendto_queue_state);
582         ssize_t ret;
583         int sys_errno;
584
585         ret = tdgram_sendto_recv(subreq, &sys_errno);
586         talloc_free(subreq);
587         if (ret == -1) {
588                 tevent_req_error(req, sys_errno);
589                 return;
590         }
591         state->ret = ret;
592
593         tevent_req_done(req);
594 }
595
596 ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
597 {
598         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
599                                         struct tdgram_sendto_queue_state);
600         ssize_t ret;
601
602         ret = tsocket_simple_int_recv(req, perrno);
603         if (ret == 0) {
604                 ret = state->ret;
605         }
606
607         tevent_req_received(req);
608         return ret;
609 }
610