tsocket: move tsocket_sendto_queue_send/recv() to tsocket_helpers.c
[jra/samba/.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