tsocket: tdgram move input checks to the common code as there're needed for all backends
[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 struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
30                                                 const struct tsocket_address_ops *ops,
31                                                 void *pstate,
32                                                 size_t psize,
33                                                 const char *type,
34                                                 const char *location)
35 {
36         void **ppstate = (void **)pstate;
37         struct tsocket_address *addr;
38
39         addr = talloc_zero(mem_ctx, struct tsocket_address);
40         if (!addr) {
41                 return NULL;
42         }
43         addr->ops = ops;
44         addr->location = location;
45         addr->private_data = talloc_size(addr, psize);
46         if (!addr->private_data) {
47                 talloc_free(addr);
48                 return NULL;
49         }
50         talloc_set_name_const(addr->private_data, type);
51
52         *ppstate = addr->private_data;
53         return addr;
54 }
55
56 char *tsocket_address_string(const struct tsocket_address *addr,
57                              TALLOC_CTX *mem_ctx)
58 {
59         if (!addr) {
60                 return talloc_strdup(mem_ctx, "NULL");
61         }
62         return addr->ops->string(addr, mem_ctx);
63 }
64
65 struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
66                                               TALLOC_CTX *mem_ctx,
67                                               const char *location)
68 {
69         return addr->ops->copy(addr, mem_ctx, location);
70 }
71
72 struct tdgram_context {
73         const char *location;
74         const struct tdgram_context_ops *ops;
75         void *private_data;
76
77         struct tevent_req *recvfrom_req;
78         struct tevent_req *sendto_req;
79 };
80
81 static int tdgram_context_destructor(struct tdgram_context *dgram)
82 {
83         if (dgram->recvfrom_req) {
84                 tevent_req_received(dgram->recvfrom_req);
85         }
86
87         if (dgram->sendto_req) {
88                 tevent_req_received(dgram->sendto_req);
89         }
90
91         return 0;
92 }
93
94 struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
95                                         const struct tdgram_context_ops *ops,
96                                         void *pstate,
97                                         size_t psize,
98                                         const char *type,
99                                         const char *location)
100 {
101         struct tdgram_context *dgram;
102         void **ppstate = (void **)pstate;
103         void *state;
104
105         dgram = talloc(mem_ctx, struct tdgram_context);
106         if (dgram == NULL) {
107                 return NULL;
108         }
109         dgram->location         = location;
110         dgram->ops              = ops;
111         dgram->recvfrom_req     = NULL;
112         dgram->sendto_req       = NULL;
113
114         state = talloc_size(dgram, psize);
115         if (state == NULL) {
116                 talloc_free(dgram);
117                 return NULL;
118         }
119         talloc_set_name_const(state, type);
120
121         dgram->private_data = state;
122
123         talloc_set_destructor(dgram, tdgram_context_destructor);
124
125         *ppstate = state;
126         return dgram;
127 }
128
129 void *_tdgram_context_data(struct tdgram_context *dgram)
130 {
131         return dgram->private_data;
132 }
133
134 struct tdgram_recvfrom_state {
135         const struct tdgram_context_ops *ops;
136         struct tdgram_context *dgram;
137         uint8_t *buf;
138         size_t len;
139         struct tsocket_address *src;
140 };
141
142 static int tdgram_recvfrom_destructor(struct tdgram_recvfrom_state *state)
143 {
144         if (state->dgram) {
145                 state->dgram->recvfrom_req = NULL;
146         }
147
148         return 0;
149 }
150
151 static void tdgram_recvfrom_done(struct tevent_req *subreq);
152
153 struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
154                                         struct tevent_context *ev,
155                                         struct tdgram_context *dgram)
156 {
157         struct tevent_req *req;
158         struct tdgram_recvfrom_state *state;
159         struct tevent_req *subreq;
160
161         req = tevent_req_create(mem_ctx, &state,
162                                 struct tdgram_recvfrom_state);
163         if (req == NULL) {
164                 return NULL;
165         }
166
167         state->ops = dgram->ops;
168         state->dgram = dgram;
169         state->buf = NULL;
170         state->len = 0;
171         state->src = NULL;
172
173         if (dgram->recvfrom_req) {
174                 tevent_req_error(req, EBUSY);
175                 goto post;
176         }
177         dgram->recvfrom_req = req;
178
179         talloc_set_destructor(state, tdgram_recvfrom_destructor);
180
181         subreq = state->ops->recvfrom_send(state, ev, dgram);
182         if (tevent_req_nomem(subreq, req)) {
183                 goto post;
184         }
185         tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
186
187         return req;
188
189  post:
190         tevent_req_post(req, ev);
191         return req;
192 }
193
194 static void tdgram_recvfrom_done(struct tevent_req *subreq)
195 {
196         struct tevent_req *req = tevent_req_callback_data(subreq,
197                                  struct tevent_req);
198         struct tdgram_recvfrom_state *state = tevent_req_data(req,
199                                               struct tdgram_recvfrom_state);
200         ssize_t ret;
201         int sys_errno;
202
203         ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
204                                         &state->buf, &state->src);
205         if (ret == -1) {
206                 tevent_req_error(req, sys_errno);
207                 return;
208         }
209
210         state->len = ret;
211
212         tevent_req_done(req);
213 }
214
215 ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
216                              int *perrno,
217                              TALLOC_CTX *mem_ctx,
218                              uint8_t **buf,
219                              struct tsocket_address **src)
220 {
221         struct tdgram_recvfrom_state *state = tevent_req_data(req,
222                                               struct tdgram_recvfrom_state);
223         ssize_t ret;
224
225         ret = tsocket_simple_int_recv(req, perrno);
226         if (ret == 0) {
227                 *buf = talloc_move(mem_ctx, &state->buf);
228                 ret = state->len;
229                 if (src) {
230                         *src = talloc_move(mem_ctx, &state->src);
231                 }
232         }
233
234         tevent_req_received(req);
235         return ret;
236 }
237
238 struct tdgram_sendto_state {
239         const struct tdgram_context_ops *ops;
240         struct tdgram_context *dgram;
241         ssize_t ret;
242 };
243
244 static int tdgram_sendto_destructor(struct tdgram_sendto_state *state)
245 {
246         if (state->dgram) {
247                 state->dgram->sendto_req = NULL;
248         }
249
250         return 0;
251 }
252
253 static void tdgram_sendto_done(struct tevent_req *subreq);
254
255 struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
256                                       struct tevent_context *ev,
257                                       struct tdgram_context *dgram,
258                                       const uint8_t *buf, size_t len,
259                                       const struct tsocket_address *dst)
260 {
261         struct tevent_req *req;
262         struct tdgram_sendto_state *state;
263         struct tevent_req *subreq;
264
265         req = tevent_req_create(mem_ctx, &state,
266                                 struct tdgram_sendto_state);
267         if (req == NULL) {
268                 return NULL;
269         }
270
271         state->ops = dgram->ops;
272         state->dgram = dgram;
273         state->ret = -1;
274
275         if (len == 0) {
276                 tevent_req_error(req, EINVAL);
277                 goto post;
278         }
279
280         if (dgram->sendto_req) {
281                 tevent_req_error(req, EBUSY);
282                 goto post;
283         }
284         dgram->sendto_req = req;
285
286         talloc_set_destructor(state, tdgram_sendto_destructor);
287
288         subreq = state->ops->sendto_send(state, ev, dgram,
289                                          buf, len, dst);
290         if (tevent_req_nomem(subreq, req)) {
291                 goto post;
292         }
293         tevent_req_set_callback(subreq, tdgram_sendto_done, req);
294
295         return req;
296
297  post:
298         tevent_req_post(req, ev);
299         return req;
300 }
301
302 static void tdgram_sendto_done(struct tevent_req *subreq)
303 {
304         struct tevent_req *req = tevent_req_callback_data(subreq,
305                                  struct tevent_req);
306         struct tdgram_sendto_state *state = tevent_req_data(req,
307                                             struct tdgram_sendto_state);
308         ssize_t ret;
309         int sys_errno;
310
311         ret = state->ops->sendto_recv(subreq, &sys_errno);
312         if (ret == -1) {
313                 tevent_req_error(req, sys_errno);
314                 return;
315         }
316
317         state->ret = ret;
318
319         tevent_req_done(req);
320 }
321
322 ssize_t tdgram_sendto_recv(struct tevent_req *req,
323                            int *perrno)
324 {
325         struct tdgram_sendto_state *state = tevent_req_data(req,
326                                             struct tdgram_sendto_state);
327         ssize_t ret;
328
329         ret = tsocket_simple_int_recv(req, perrno);
330         if (ret == 0) {
331                 ret = state->ret;
332         }
333
334         tevent_req_received(req);
335         return ret;
336 }
337
338 struct tdgram_disconnect_state {
339         const struct tdgram_context_ops *ops;
340 };
341
342 static void tdgram_disconnect_done(struct tevent_req *subreq);
343
344 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
345                                           struct tevent_context *ev,
346                                           struct tdgram_context *dgram)
347 {
348         struct tevent_req *req;
349         struct tdgram_disconnect_state *state;
350         struct tevent_req *subreq;
351
352         req = tevent_req_create(mem_ctx, &state,
353                                 struct tdgram_disconnect_state);
354         if (req == NULL) {
355                 return NULL;
356         }
357
358         state->ops = dgram->ops;
359
360         if (dgram->recvfrom_req || dgram->sendto_req) {
361                 tevent_req_error(req, EBUSY);
362                 goto post;
363         }
364
365         subreq = state->ops->disconnect_send(state, ev, dgram);
366         if (tevent_req_nomem(subreq, req)) {
367                 goto post;
368         }
369         tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
370
371         return req;
372
373  post:
374         tevent_req_post(req, ev);
375         return req;
376 }
377
378 static void tdgram_disconnect_done(struct tevent_req *subreq)
379 {
380         struct tevent_req *req = tevent_req_callback_data(subreq,
381                                  struct tevent_req);
382         struct tdgram_disconnect_state *state = tevent_req_data(req,
383                                                 struct tdgram_disconnect_state);
384         int ret;
385         int sys_errno;
386
387         ret = state->ops->disconnect_recv(subreq, &sys_errno);
388         if (ret == -1) {
389                 tevent_req_error(req, sys_errno);
390                 return;
391         }
392
393         tevent_req_done(req);
394 }
395
396 int tdgram_disconnect_recv(struct tevent_req *req,
397                            int *perrno)
398 {
399         int ret;
400
401         ret = tsocket_simple_int_recv(req, perrno);
402
403         tevent_req_received(req);
404         return ret;
405 }
406
407 struct tdgram_sendto_queue_state {
408         /* this structs are owned by the caller */
409         struct {
410                 struct tevent_context *ev;
411                 struct tdgram_context *dgram;
412                 const uint8_t *buf;
413                 size_t len;
414                 const struct tsocket_address *dst;
415         } caller;
416         ssize_t ret;
417 };
418
419 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
420                                          void *private_data);
421 static void tdgram_sendto_queue_done(struct tevent_req *subreq);
422
423 /**
424  * @brief Queue a dgram blob for sending through the socket
425  * @param[in] mem_ctx   The memory context for the result
426  * @param[in] ev        The event context the operation should work on
427  * @param[in] dgram     The tdgram_context to send the message buffer
428  * @param[in] queue     The existing dgram queue
429  * @param[in] buf       The message buffer
430  * @param[in] len       The message length
431  * @param[in] dst       The destination socket address
432  * @retval              The async request handle
433  *
434  * This function queues a blob for sending to destination through an existing
435  * dgram socket. The async callback is triggered when the whole blob is
436  * delivered to the underlying system socket.
437  *
438  * The caller needs to make sure that all non-scalar input parameters hang
439  * arround for the whole lifetime of the request.
440  */
441 struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
442                                             struct tevent_context *ev,
443                                             struct tdgram_context *dgram,
444                                             struct tevent_queue *queue,
445                                             const uint8_t *buf,
446                                             size_t len,
447                                             struct tsocket_address *dst)
448 {
449         struct tevent_req *req;
450         struct tdgram_sendto_queue_state *state;
451         bool ok;
452
453         req = tevent_req_create(mem_ctx, &state,
454                                 struct tdgram_sendto_queue_state);
455         if (!req) {
456                 return NULL;
457         }
458
459         state->caller.ev        = ev;
460         state->caller.dgram     = dgram;
461         state->caller.buf       = buf;
462         state->caller.len       = len;
463         state->caller.dst       = dst;
464         state->ret              = -1;
465
466         ok = tevent_queue_add(queue,
467                               ev,
468                               req,
469                               tdgram_sendto_queue_trigger,
470                               NULL);
471         if (!ok) {
472                 tevent_req_nomem(NULL, req);
473                 goto post;
474         }
475
476         return req;
477
478  post:
479         tevent_req_post(req, ev);
480         return req;
481 }
482
483 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
484                                          void *private_data)
485 {
486         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
487                                         struct tdgram_sendto_queue_state);
488         struct tevent_req *subreq;
489
490         subreq = tdgram_sendto_send(state,
491                                     state->caller.ev,
492                                     state->caller.dgram,
493                                     state->caller.buf,
494                                     state->caller.len,
495                                     state->caller.dst);
496         if (tevent_req_nomem(subreq, req)) {
497                 return;
498         }
499         tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
500 }
501
502 static void tdgram_sendto_queue_done(struct tevent_req *subreq)
503 {
504         struct tevent_req *req = tevent_req_callback_data(subreq,
505                                  struct tevent_req);
506         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
507                                         struct tdgram_sendto_queue_state);
508         ssize_t ret;
509         int sys_errno;
510
511         ret = tdgram_sendto_recv(subreq, &sys_errno);
512         talloc_free(subreq);
513         if (ret == -1) {
514                 tevent_req_error(req, sys_errno);
515                 return;
516         }
517         state->ret = ret;
518
519         tevent_req_done(req);
520 }
521
522 ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
523 {
524         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
525                                         struct tdgram_sendto_queue_state);
526         ssize_t ret;
527
528         ret = tsocket_simple_int_recv(req, perrno);
529         if (ret == 0) {
530                 ret = state->ret;
531         }
532
533         tevent_req_received(req);
534         return ret;
535 }
536