tsocket: fix dependecies
[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
78 struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
79                                         const struct tdgram_context_ops *ops,
80                                         void *pstate,
81                                         size_t psize,
82                                         const char *type,
83                                         const char *location)
84 {
85         struct tdgram_context *dgram;
86         void **ppstate = (void **)pstate;
87         void *state;
88
89         dgram = talloc(mem_ctx, struct tdgram_context);
90         if (dgram == NULL) {
91                 return NULL;
92         }
93         dgram->location = location;
94         dgram->ops      = ops;
95
96         state = talloc_size(dgram, psize);
97         if (state == NULL) {
98                 talloc_free(dgram);
99                 return NULL;
100         }
101         talloc_set_name_const(state, type);
102
103         dgram->private_data = state;
104
105         *ppstate = state;
106         return dgram;
107 }
108
109 void *_tdgram_context_data(struct tdgram_context *dgram)
110 {
111         return dgram->private_data;
112 }
113
114 struct tdgram_recvfrom_state {
115         const struct tdgram_context_ops *ops;
116         uint8_t *buf;
117         size_t len;
118         struct tsocket_address *src;
119 };
120
121 static void tdgram_recvfrom_done(struct tevent_req *subreq);
122
123 struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
124                                         struct tevent_context *ev,
125                                         struct tdgram_context *dgram)
126 {
127         struct tevent_req *req;
128         struct tdgram_recvfrom_state *state;
129         struct tevent_req *subreq;
130
131         req = tevent_req_create(mem_ctx, &state,
132                                 struct tdgram_recvfrom_state);
133         if (req == NULL) {
134                 return NULL;
135         }
136
137         state->ops = dgram->ops;
138
139         subreq = state->ops->recvfrom_send(state, ev, dgram);
140         if (tevent_req_nomem(subreq, req)) {
141                 goto post;
142         }
143         tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
144
145         return req;
146
147  post:
148         tevent_req_post(req, ev);
149         return req;
150 }
151
152 static void tdgram_recvfrom_done(struct tevent_req *subreq)
153 {
154         struct tevent_req *req = tevent_req_callback_data(subreq,
155                                  struct tevent_req);
156         struct tdgram_recvfrom_state *state = tevent_req_data(req,
157                                               struct tdgram_recvfrom_state);
158         ssize_t ret;
159         int sys_errno;
160
161         ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
162                                         &state->buf, &state->src);
163         if (ret == -1) {
164                 tevent_req_error(req, sys_errno);
165                 return;
166         }
167
168         state->len = ret;
169
170         tevent_req_done(req);
171 }
172
173 ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
174                              int *perrno,
175                              TALLOC_CTX *mem_ctx,
176                              uint8_t **buf,
177                              struct tsocket_address **src)
178 {
179         struct tdgram_recvfrom_state *state = tevent_req_data(req,
180                                               struct tdgram_recvfrom_state);
181         ssize_t ret;
182
183         ret = tsocket_simple_int_recv(req, perrno);
184         if (ret == 0) {
185                 *buf = talloc_move(mem_ctx, &state->buf);
186                 ret = state->len;
187                 if (src) {
188                         *src = talloc_move(mem_ctx, &state->src);
189                 }
190         }
191
192         tevent_req_received(req);
193         return ret;
194 }
195
196 struct tdgram_sendto_state {
197         const struct tdgram_context_ops *ops;
198         ssize_t ret;
199 };
200
201 static void tdgram_sendto_done(struct tevent_req *subreq);
202
203 struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
204                                       struct tevent_context *ev,
205                                       struct tdgram_context *dgram,
206                                       const uint8_t *buf, size_t len,
207                                       const struct tsocket_address *dst)
208 {
209         struct tevent_req *req;
210         struct tdgram_sendto_state *state;
211         struct tevent_req *subreq;
212
213         req = tevent_req_create(mem_ctx, &state,
214                                 struct tdgram_sendto_state);
215         if (req == NULL) {
216                 return NULL;
217         }
218
219         state->ops = dgram->ops;
220         state->ret = -1;
221
222         subreq = state->ops->sendto_send(state, ev, dgram,
223                                          buf, len, dst);
224         if (tevent_req_nomem(subreq, req)) {
225                 goto post;
226         }
227         tevent_req_set_callback(subreq, tdgram_sendto_done, req);
228
229         return req;
230
231  post:
232         tevent_req_post(req, ev);
233         return req;
234 }
235
236 static void tdgram_sendto_done(struct tevent_req *subreq)
237 {
238         struct tevent_req *req = tevent_req_callback_data(subreq,
239                                  struct tevent_req);
240         struct tdgram_sendto_state *state = tevent_req_data(req,
241                                             struct tdgram_sendto_state);
242         ssize_t ret;
243         int sys_errno;
244
245         ret = state->ops->sendto_recv(subreq, &sys_errno);
246         if (ret == -1) {
247                 tevent_req_error(req, sys_errno);
248                 return;
249         }
250
251         state->ret = ret;
252
253         tevent_req_done(req);
254 }
255
256 ssize_t tdgram_sendto_recv(struct tevent_req *req,
257                            int *perrno)
258 {
259         struct tdgram_sendto_state *state = tevent_req_data(req,
260                                             struct tdgram_sendto_state);
261         ssize_t ret;
262
263         ret = tsocket_simple_int_recv(req, perrno);
264         if (ret == 0) {
265                 ret = state->ret;
266         }
267
268         tevent_req_received(req);
269         return ret;
270 }
271
272 struct tdgram_disconnect_state {
273         const struct tdgram_context_ops *ops;
274 };
275
276 static void tdgram_disconnect_done(struct tevent_req *subreq);
277
278 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
279                                           struct tevent_context *ev,
280                                           struct tdgram_context *dgram)
281 {
282         struct tevent_req *req;
283         struct tdgram_disconnect_state *state;
284         struct tevent_req *subreq;
285
286         req = tevent_req_create(mem_ctx, &state,
287                                 struct tdgram_disconnect_state);
288         if (req == NULL) {
289                 return NULL;
290         }
291
292         state->ops = dgram->ops;
293
294         subreq = state->ops->disconnect_send(state, ev, dgram);
295         if (tevent_req_nomem(subreq, req)) {
296                 goto post;
297         }
298         tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
299
300         return req;
301
302  post:
303         tevent_req_post(req, ev);
304         return req;
305 }
306
307 static void tdgram_disconnect_done(struct tevent_req *subreq)
308 {
309         struct tevent_req *req = tevent_req_callback_data(subreq,
310                                  struct tevent_req);
311         struct tdgram_disconnect_state *state = tevent_req_data(req,
312                                                 struct tdgram_disconnect_state);
313         int ret;
314         int sys_errno;
315
316         ret = state->ops->disconnect_recv(subreq, &sys_errno);
317         if (ret == -1) {
318                 tevent_req_error(req, sys_errno);
319                 return;
320         }
321
322         tevent_req_done(req);
323 }
324
325 int tdgram_disconnect_recv(struct tevent_req *req,
326                            int *perrno)
327 {
328         int ret;
329
330         ret = tsocket_simple_int_recv(req, perrno);
331
332         tevent_req_received(req);
333         return ret;
334 }
335
336 struct tdgram_sendto_queue_state {
337         /* this structs are owned by the caller */
338         struct {
339                 struct tevent_context *ev;
340                 struct tdgram_context *dgram;
341                 const uint8_t *buf;
342                 size_t len;
343                 const struct tsocket_address *dst;
344         } caller;
345         ssize_t ret;
346 };
347
348 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
349                                          void *private_data);
350 static void tdgram_sendto_queue_done(struct tevent_req *subreq);
351
352 /**
353  * @brief Queue a dgram blob for sending through the socket
354  * @param[in] mem_ctx   The memory context for the result
355  * @param[in] ev        The event context the operation should work on
356  * @param[in] dgram     The tdgram_context to send the message buffer
357  * @param[in] queue     The existing dgram queue
358  * @param[in] buf       The message buffer
359  * @param[in] len       The message length
360  * @param[in] dst       The destination socket address
361  * @retval              The async request handle
362  *
363  * This function queues a blob for sending to destination through an existing
364  * dgram socket. The async callback is triggered when the whole blob is
365  * delivered to the underlying system socket.
366  *
367  * The caller needs to make sure that all non-scalar input parameters hang
368  * arround for the whole lifetime of the request.
369  */
370 struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
371                                             struct tevent_context *ev,
372                                             struct tdgram_context *dgram,
373                                             struct tevent_queue *queue,
374                                             const uint8_t *buf,
375                                             size_t len,
376                                             struct tsocket_address *dst)
377 {
378         struct tevent_req *req;
379         struct tdgram_sendto_queue_state *state;
380         bool ok;
381
382         req = tevent_req_create(mem_ctx, &state,
383                                 struct tdgram_sendto_queue_state);
384         if (!req) {
385                 return NULL;
386         }
387
388         state->caller.ev        = ev;
389         state->caller.dgram     = dgram;
390         state->caller.buf       = buf;
391         state->caller.len       = len;
392         state->caller.dst       = dst;
393         state->ret              = -1;
394
395         ok = tevent_queue_add(queue,
396                               ev,
397                               req,
398                               tdgram_sendto_queue_trigger,
399                               NULL);
400         if (!ok) {
401                 tevent_req_nomem(NULL, req);
402                 goto post;
403         }
404
405         return req;
406
407  post:
408         tevent_req_post(req, ev);
409         return req;
410 }
411
412 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
413                                          void *private_data)
414 {
415         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
416                                         struct tdgram_sendto_queue_state);
417         struct tevent_req *subreq;
418
419         subreq = tdgram_sendto_send(state,
420                                     state->caller.ev,
421                                     state->caller.dgram,
422                                     state->caller.buf,
423                                     state->caller.len,
424                                     state->caller.dst);
425         if (tevent_req_nomem(subreq, req)) {
426                 return;
427         }
428         tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
429 }
430
431 static void tdgram_sendto_queue_done(struct tevent_req *subreq)
432 {
433         struct tevent_req *req = tevent_req_callback_data(subreq,
434                                  struct tevent_req);
435         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
436                                         struct tdgram_sendto_queue_state);
437         ssize_t ret;
438         int sys_errno;
439
440         ret = tdgram_sendto_recv(subreq, &sys_errno);
441         talloc_free(subreq);
442         if (ret == -1) {
443                 tevent_req_error(req, sys_errno);
444                 return;
445         }
446         state->ret = ret;
447
448         tevent_req_done(req);
449 }
450
451 ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
452 {
453         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
454                                         struct tdgram_sendto_queue_state);
455         ssize_t ret;
456
457         ret = tsocket_simple_int_recv(req, perrno);
458         if (ret == 0) {
459                 ret = state->ret;
460         }
461
462         tevent_req_received(req);
463         return ret;
464 }
465