tsocket: return EINVAL when tdgram_sendto_send() is used with len == 0
[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         if (len == 0) {
223                 tevent_req_error(req, EINVAL);
224                 goto post;
225         }
226
227         subreq = state->ops->sendto_send(state, ev, dgram,
228                                          buf, len, dst);
229         if (tevent_req_nomem(subreq, req)) {
230                 goto post;
231         }
232         tevent_req_set_callback(subreq, tdgram_sendto_done, req);
233
234         return req;
235
236  post:
237         tevent_req_post(req, ev);
238         return req;
239 }
240
241 static void tdgram_sendto_done(struct tevent_req *subreq)
242 {
243         struct tevent_req *req = tevent_req_callback_data(subreq,
244                                  struct tevent_req);
245         struct tdgram_sendto_state *state = tevent_req_data(req,
246                                             struct tdgram_sendto_state);
247         ssize_t ret;
248         int sys_errno;
249
250         ret = state->ops->sendto_recv(subreq, &sys_errno);
251         if (ret == -1) {
252                 tevent_req_error(req, sys_errno);
253                 return;
254         }
255
256         state->ret = ret;
257
258         tevent_req_done(req);
259 }
260
261 ssize_t tdgram_sendto_recv(struct tevent_req *req,
262                            int *perrno)
263 {
264         struct tdgram_sendto_state *state = tevent_req_data(req,
265                                             struct tdgram_sendto_state);
266         ssize_t ret;
267
268         ret = tsocket_simple_int_recv(req, perrno);
269         if (ret == 0) {
270                 ret = state->ret;
271         }
272
273         tevent_req_received(req);
274         return ret;
275 }
276
277 struct tdgram_disconnect_state {
278         const struct tdgram_context_ops *ops;
279 };
280
281 static void tdgram_disconnect_done(struct tevent_req *subreq);
282
283 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
284                                           struct tevent_context *ev,
285                                           struct tdgram_context *dgram)
286 {
287         struct tevent_req *req;
288         struct tdgram_disconnect_state *state;
289         struct tevent_req *subreq;
290
291         req = tevent_req_create(mem_ctx, &state,
292                                 struct tdgram_disconnect_state);
293         if (req == NULL) {
294                 return NULL;
295         }
296
297         state->ops = dgram->ops;
298
299         subreq = state->ops->disconnect_send(state, ev, dgram);
300         if (tevent_req_nomem(subreq, req)) {
301                 goto post;
302         }
303         tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
304
305         return req;
306
307  post:
308         tevent_req_post(req, ev);
309         return req;
310 }
311
312 static void tdgram_disconnect_done(struct tevent_req *subreq)
313 {
314         struct tevent_req *req = tevent_req_callback_data(subreq,
315                                  struct tevent_req);
316         struct tdgram_disconnect_state *state = tevent_req_data(req,
317                                                 struct tdgram_disconnect_state);
318         int ret;
319         int sys_errno;
320
321         ret = state->ops->disconnect_recv(subreq, &sys_errno);
322         if (ret == -1) {
323                 tevent_req_error(req, sys_errno);
324                 return;
325         }
326
327         tevent_req_done(req);
328 }
329
330 int tdgram_disconnect_recv(struct tevent_req *req,
331                            int *perrno)
332 {
333         int ret;
334
335         ret = tsocket_simple_int_recv(req, perrno);
336
337         tevent_req_received(req);
338         return ret;
339 }
340
341 struct tdgram_sendto_queue_state {
342         /* this structs are owned by the caller */
343         struct {
344                 struct tevent_context *ev;
345                 struct tdgram_context *dgram;
346                 const uint8_t *buf;
347                 size_t len;
348                 const struct tsocket_address *dst;
349         } caller;
350         ssize_t ret;
351 };
352
353 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
354                                          void *private_data);
355 static void tdgram_sendto_queue_done(struct tevent_req *subreq);
356
357 /**
358  * @brief Queue a dgram blob for sending through the socket
359  * @param[in] mem_ctx   The memory context for the result
360  * @param[in] ev        The event context the operation should work on
361  * @param[in] dgram     The tdgram_context to send the message buffer
362  * @param[in] queue     The existing dgram queue
363  * @param[in] buf       The message buffer
364  * @param[in] len       The message length
365  * @param[in] dst       The destination socket address
366  * @retval              The async request handle
367  *
368  * This function queues a blob for sending to destination through an existing
369  * dgram socket. The async callback is triggered when the whole blob is
370  * delivered to the underlying system socket.
371  *
372  * The caller needs to make sure that all non-scalar input parameters hang
373  * arround for the whole lifetime of the request.
374  */
375 struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
376                                             struct tevent_context *ev,
377                                             struct tdgram_context *dgram,
378                                             struct tevent_queue *queue,
379                                             const uint8_t *buf,
380                                             size_t len,
381                                             struct tsocket_address *dst)
382 {
383         struct tevent_req *req;
384         struct tdgram_sendto_queue_state *state;
385         bool ok;
386
387         req = tevent_req_create(mem_ctx, &state,
388                                 struct tdgram_sendto_queue_state);
389         if (!req) {
390                 return NULL;
391         }
392
393         state->caller.ev        = ev;
394         state->caller.dgram     = dgram;
395         state->caller.buf       = buf;
396         state->caller.len       = len;
397         state->caller.dst       = dst;
398         state->ret              = -1;
399
400         ok = tevent_queue_add(queue,
401                               ev,
402                               req,
403                               tdgram_sendto_queue_trigger,
404                               NULL);
405         if (!ok) {
406                 tevent_req_nomem(NULL, req);
407                 goto post;
408         }
409
410         return req;
411
412  post:
413         tevent_req_post(req, ev);
414         return req;
415 }
416
417 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
418                                          void *private_data)
419 {
420         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
421                                         struct tdgram_sendto_queue_state);
422         struct tevent_req *subreq;
423
424         subreq = tdgram_sendto_send(state,
425                                     state->caller.ev,
426                                     state->caller.dgram,
427                                     state->caller.buf,
428                                     state->caller.len,
429                                     state->caller.dst);
430         if (tevent_req_nomem(subreq, req)) {
431                 return;
432         }
433         tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
434 }
435
436 static void tdgram_sendto_queue_done(struct tevent_req *subreq)
437 {
438         struct tevent_req *req = tevent_req_callback_data(subreq,
439                                  struct tevent_req);
440         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
441                                         struct tdgram_sendto_queue_state);
442         ssize_t ret;
443         int sys_errno;
444
445         ret = tdgram_sendto_recv(subreq, &sys_errno);
446         talloc_free(subreq);
447         if (ret == -1) {
448                 tevent_req_error(req, sys_errno);
449                 return;
450         }
451         state->ret = ret;
452
453         tevent_req_done(req);
454 }
455
456 ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
457 {
458         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
459                                         struct tdgram_sendto_queue_state);
460         ssize_t ret;
461
462         ret = tsocket_simple_int_recv(req, perrno);
463         if (ret == 0) {
464                 ret = state->ret;
465         }
466
467         tevent_req_received(req);
468         return ret;
469 }
470