dbac6e26cf896eeb0e98a7a2c0f497a4e981e857
[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 "tsocket.h"
26 #include "tsocket_internal.h"
27
28 int tsocket_simple_int_recv(struct tevent_req *req, int *perrno)
29 {
30         enum tevent_req_state state;
31         uint64_t error;
32
33         if (!tevent_req_is_error(req, &state, &error)) {
34                 return 0;
35         }
36
37         switch (state) {
38         case TEVENT_REQ_NO_MEMORY:
39                 *perrno = ENOMEM;
40                 return -1;
41         case TEVENT_REQ_TIMED_OUT:
42                 *perrno = ETIMEDOUT;
43                 return -1;
44         case TEVENT_REQ_USER_ERROR:
45                 *perrno = (int)error;
46                 return -1;
47         default:
48                 *perrno = EIO;
49                 return -1;
50         }
51
52         *perrno = EIO;
53         return -1;
54 }
55
56 struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
57                                                 const struct tsocket_address_ops *ops,
58                                                 void *pstate,
59                                                 size_t psize,
60                                                 const char *type,
61                                                 const char *location)
62 {
63         void **ppstate = (void **)pstate;
64         struct tsocket_address *addr;
65
66         addr = talloc_zero(mem_ctx, struct tsocket_address);
67         if (!addr) {
68                 return NULL;
69         }
70         addr->ops = ops;
71         addr->location = location;
72         addr->private_data = talloc_size(addr, psize);
73         if (!addr->private_data) {
74                 talloc_free(addr);
75                 return NULL;
76         }
77         talloc_set_name_const(addr->private_data, type);
78
79         *ppstate = addr->private_data;
80         return addr;
81 }
82
83 char *tsocket_address_string(const struct tsocket_address *addr,
84                              TALLOC_CTX *mem_ctx)
85 {
86         if (!addr) {
87                 return talloc_strdup(mem_ctx, "NULL");
88         }
89         return addr->ops->string(addr, mem_ctx);
90 }
91
92 struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
93                                               TALLOC_CTX *mem_ctx,
94                                               const char *location)
95 {
96         return addr->ops->copy(addr, mem_ctx, location);
97 }
98
99 struct tdgram_context {
100         const char *location;
101         const struct tdgram_context_ops *ops;
102         void *private_data;
103
104         struct tevent_req *recvfrom_req;
105         struct tevent_req *sendto_req;
106 };
107
108 static int tdgram_context_destructor(struct tdgram_context *dgram)
109 {
110         if (dgram->recvfrom_req) {
111                 tevent_req_received(dgram->recvfrom_req);
112         }
113
114         if (dgram->sendto_req) {
115                 tevent_req_received(dgram->sendto_req);
116         }
117
118         return 0;
119 }
120
121 struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
122                                         const struct tdgram_context_ops *ops,
123                                         void *pstate,
124                                         size_t psize,
125                                         const char *type,
126                                         const char *location)
127 {
128         struct tdgram_context *dgram;
129         void **ppstate = (void **)pstate;
130         void *state;
131
132         dgram = talloc(mem_ctx, struct tdgram_context);
133         if (dgram == NULL) {
134                 return NULL;
135         }
136         dgram->location         = location;
137         dgram->ops              = ops;
138         dgram->recvfrom_req     = NULL;
139         dgram->sendto_req       = NULL;
140
141         state = talloc_size(dgram, psize);
142         if (state == NULL) {
143                 talloc_free(dgram);
144                 return NULL;
145         }
146         talloc_set_name_const(state, type);
147
148         dgram->private_data = state;
149
150         talloc_set_destructor(dgram, tdgram_context_destructor);
151
152         *ppstate = state;
153         return dgram;
154 }
155
156 void *_tdgram_context_data(struct tdgram_context *dgram)
157 {
158         return dgram->private_data;
159 }
160
161 struct tdgram_recvfrom_state {
162         const struct tdgram_context_ops *ops;
163         struct tdgram_context *dgram;
164         uint8_t *buf;
165         size_t len;
166         struct tsocket_address *src;
167 };
168
169 static int tdgram_recvfrom_destructor(struct tdgram_recvfrom_state *state)
170 {
171         if (state->dgram) {
172                 state->dgram->recvfrom_req = NULL;
173         }
174
175         return 0;
176 }
177
178 static void tdgram_recvfrom_done(struct tevent_req *subreq);
179
180 struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
181                                         struct tevent_context *ev,
182                                         struct tdgram_context *dgram)
183 {
184         struct tevent_req *req;
185         struct tdgram_recvfrom_state *state;
186         struct tevent_req *subreq;
187
188         req = tevent_req_create(mem_ctx, &state,
189                                 struct tdgram_recvfrom_state);
190         if (req == NULL) {
191                 return NULL;
192         }
193
194         state->ops = dgram->ops;
195         state->dgram = dgram;
196         state->buf = NULL;
197         state->len = 0;
198         state->src = NULL;
199
200         if (dgram->recvfrom_req) {
201                 tevent_req_error(req, EBUSY);
202                 goto post;
203         }
204         dgram->recvfrom_req = req;
205
206         talloc_set_destructor(state, tdgram_recvfrom_destructor);
207
208         subreq = state->ops->recvfrom_send(state, ev, dgram);
209         if (tevent_req_nomem(subreq, req)) {
210                 goto post;
211         }
212         tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
213
214         return req;
215
216  post:
217         tevent_req_post(req, ev);
218         return req;
219 }
220
221 static void tdgram_recvfrom_done(struct tevent_req *subreq)
222 {
223         struct tevent_req *req = tevent_req_callback_data(subreq,
224                                  struct tevent_req);
225         struct tdgram_recvfrom_state *state = tevent_req_data(req,
226                                               struct tdgram_recvfrom_state);
227         ssize_t ret;
228         int sys_errno;
229
230         ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
231                                         &state->buf, &state->src);
232         if (ret == -1) {
233                 tevent_req_error(req, sys_errno);
234                 return;
235         }
236
237         state->len = ret;
238
239         tevent_req_done(req);
240 }
241
242 ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
243                              int *perrno,
244                              TALLOC_CTX *mem_ctx,
245                              uint8_t **buf,
246                              struct tsocket_address **src)
247 {
248         struct tdgram_recvfrom_state *state = tevent_req_data(req,
249                                               struct tdgram_recvfrom_state);
250         ssize_t ret;
251
252         ret = tsocket_simple_int_recv(req, perrno);
253         if (ret == 0) {
254                 *buf = talloc_move(mem_ctx, &state->buf);
255                 ret = state->len;
256                 if (src) {
257                         *src = talloc_move(mem_ctx, &state->src);
258                 }
259         }
260
261         tevent_req_received(req);
262         return ret;
263 }
264
265 struct tdgram_sendto_state {
266         const struct tdgram_context_ops *ops;
267         struct tdgram_context *dgram;
268         ssize_t ret;
269 };
270
271 static int tdgram_sendto_destructor(struct tdgram_sendto_state *state)
272 {
273         if (state->dgram) {
274                 state->dgram->sendto_req = NULL;
275         }
276
277         return 0;
278 }
279
280 static void tdgram_sendto_done(struct tevent_req *subreq);
281
282 struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
283                                       struct tevent_context *ev,
284                                       struct tdgram_context *dgram,
285                                       const uint8_t *buf, size_t len,
286                                       const struct tsocket_address *dst)
287 {
288         struct tevent_req *req;
289         struct tdgram_sendto_state *state;
290         struct tevent_req *subreq;
291
292         req = tevent_req_create(mem_ctx, &state,
293                                 struct tdgram_sendto_state);
294         if (req == NULL) {
295                 return NULL;
296         }
297
298         state->ops = dgram->ops;
299         state->dgram = dgram;
300         state->ret = -1;
301
302         if (len == 0) {
303                 tevent_req_error(req, EINVAL);
304                 goto post;
305         }
306
307         if (dgram->sendto_req) {
308                 tevent_req_error(req, EBUSY);
309                 goto post;
310         }
311         dgram->sendto_req = req;
312
313         talloc_set_destructor(state, tdgram_sendto_destructor);
314
315         subreq = state->ops->sendto_send(state, ev, dgram,
316                                          buf, len, dst);
317         if (tevent_req_nomem(subreq, req)) {
318                 goto post;
319         }
320         tevent_req_set_callback(subreq, tdgram_sendto_done, req);
321
322         return req;
323
324  post:
325         tevent_req_post(req, ev);
326         return req;
327 }
328
329 static void tdgram_sendto_done(struct tevent_req *subreq)
330 {
331         struct tevent_req *req = tevent_req_callback_data(subreq,
332                                  struct tevent_req);
333         struct tdgram_sendto_state *state = tevent_req_data(req,
334                                             struct tdgram_sendto_state);
335         ssize_t ret;
336         int sys_errno;
337
338         ret = state->ops->sendto_recv(subreq, &sys_errno);
339         if (ret == -1) {
340                 tevent_req_error(req, sys_errno);
341                 return;
342         }
343
344         state->ret = ret;
345
346         tevent_req_done(req);
347 }
348
349 ssize_t tdgram_sendto_recv(struct tevent_req *req,
350                            int *perrno)
351 {
352         struct tdgram_sendto_state *state = tevent_req_data(req,
353                                             struct tdgram_sendto_state);
354         ssize_t ret;
355
356         ret = tsocket_simple_int_recv(req, perrno);
357         if (ret == 0) {
358                 ret = state->ret;
359         }
360
361         tevent_req_received(req);
362         return ret;
363 }
364
365 struct tdgram_disconnect_state {
366         const struct tdgram_context_ops *ops;
367 };
368
369 static void tdgram_disconnect_done(struct tevent_req *subreq);
370
371 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
372                                           struct tevent_context *ev,
373                                           struct tdgram_context *dgram)
374 {
375         struct tevent_req *req;
376         struct tdgram_disconnect_state *state;
377         struct tevent_req *subreq;
378
379         req = tevent_req_create(mem_ctx, &state,
380                                 struct tdgram_disconnect_state);
381         if (req == NULL) {
382                 return NULL;
383         }
384
385         state->ops = dgram->ops;
386
387         if (dgram->recvfrom_req || dgram->sendto_req) {
388                 tevent_req_error(req, EBUSY);
389                 goto post;
390         }
391
392         subreq = state->ops->disconnect_send(state, ev, dgram);
393         if (tevent_req_nomem(subreq, req)) {
394                 goto post;
395         }
396         tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
397
398         return req;
399
400  post:
401         tevent_req_post(req, ev);
402         return req;
403 }
404
405 static void tdgram_disconnect_done(struct tevent_req *subreq)
406 {
407         struct tevent_req *req = tevent_req_callback_data(subreq,
408                                  struct tevent_req);
409         struct tdgram_disconnect_state *state = tevent_req_data(req,
410                                                 struct tdgram_disconnect_state);
411         int ret;
412         int sys_errno;
413
414         ret = state->ops->disconnect_recv(subreq, &sys_errno);
415         if (ret == -1) {
416                 tevent_req_error(req, sys_errno);
417                 return;
418         }
419
420         tevent_req_done(req);
421 }
422
423 int tdgram_disconnect_recv(struct tevent_req *req,
424                            int *perrno)
425 {
426         int ret;
427
428         ret = tsocket_simple_int_recv(req, perrno);
429
430         tevent_req_received(req);
431         return ret;
432 }
433