tdb: cleanup: tdb_release_extra_locks() helper
[ira/wip.git] / lib / tsocket / tsocket_helpers.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2009
5
6      ** NOTE! The following LGPL license applies to the tsocket
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/filesys.h"
26 #include "tsocket.h"
27 #include "tsocket_internal.h"
28
29 struct tdgram_sendto_queue_state {
30         /* this structs are owned by the caller */
31         struct {
32                 struct tevent_context *ev;
33                 struct tdgram_context *dgram;
34                 const uint8_t *buf;
35                 size_t len;
36                 const struct tsocket_address *dst;
37         } caller;
38         ssize_t ret;
39 };
40
41 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
42                                          void *private_data);
43 static void tdgram_sendto_queue_done(struct tevent_req *subreq);
44
45 struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
46                                             struct tevent_context *ev,
47                                             struct tdgram_context *dgram,
48                                             struct tevent_queue *queue,
49                                             const uint8_t *buf,
50                                             size_t len,
51                                             struct tsocket_address *dst)
52 {
53         struct tevent_req *req;
54         struct tdgram_sendto_queue_state *state;
55         bool ok;
56
57         req = tevent_req_create(mem_ctx, &state,
58                                 struct tdgram_sendto_queue_state);
59         if (!req) {
60                 return NULL;
61         }
62
63         state->caller.ev        = ev;
64         state->caller.dgram     = dgram;
65         state->caller.buf       = buf;
66         state->caller.len       = len;
67         state->caller.dst       = dst;
68         state->ret              = -1;
69
70         ok = tevent_queue_add(queue,
71                               ev,
72                               req,
73                               tdgram_sendto_queue_trigger,
74                               NULL);
75         if (!ok) {
76                 tevent_req_nomem(NULL, req);
77                 goto post;
78         }
79
80         return req;
81
82  post:
83         tevent_req_post(req, ev);
84         return req;
85 }
86
87 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
88                                          void *private_data)
89 {
90         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
91                                         struct tdgram_sendto_queue_state);
92         struct tevent_req *subreq;
93
94         subreq = tdgram_sendto_send(state,
95                                     state->caller.ev,
96                                     state->caller.dgram,
97                                     state->caller.buf,
98                                     state->caller.len,
99                                     state->caller.dst);
100         if (tevent_req_nomem(subreq, req)) {
101                 return;
102         }
103         tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
104 }
105
106 static void tdgram_sendto_queue_done(struct tevent_req *subreq)
107 {
108         struct tevent_req *req = tevent_req_callback_data(subreq,
109                                  struct tevent_req);
110         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
111                                         struct tdgram_sendto_queue_state);
112         ssize_t ret;
113         int sys_errno;
114
115         ret = tdgram_sendto_recv(subreq, &sys_errno);
116         talloc_free(subreq);
117         if (ret == -1) {
118                 tevent_req_error(req, sys_errno);
119                 return;
120         }
121         state->ret = ret;
122
123         tevent_req_done(req);
124 }
125
126 ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
127 {
128         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
129                                         struct tdgram_sendto_queue_state);
130         ssize_t ret;
131
132         ret = tsocket_simple_int_recv(req, perrno);
133         if (ret == 0) {
134                 ret = state->ret;
135         }
136
137         tevent_req_received(req);
138         return ret;
139 }
140
141 struct tstream_readv_pdu_state {
142         /* this structs are owned by the caller */
143         struct {
144                 struct tevent_context *ev;
145                 struct tstream_context *stream;
146                 tstream_readv_pdu_next_vector_t next_vector_fn;
147                 void *next_vector_private;
148         } caller;
149
150         /*
151          * Each call to the callback resets iov and count
152          * the callback allocated the iov as child of our state,
153          * that means we are allowed to modify and free it.
154          *
155          * we should call the callback every time we filled the given
156          * vector and ask for a new vector. We return if the callback
157          * ask for 0 bytes.
158          */
159         struct iovec *vector;
160         size_t count;
161
162         /*
163          * the total number of bytes we read,
164          * the return value of the _recv function
165          */
166         int total_read;
167 };
168
169 static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req);
170 static void tstream_readv_pdu_readv_done(struct tevent_req *subreq);
171
172 struct tevent_req *tstream_readv_pdu_send(TALLOC_CTX *mem_ctx,
173                                 struct tevent_context *ev,
174                                 struct tstream_context *stream,
175                                 tstream_readv_pdu_next_vector_t next_vector_fn,
176                                 void *next_vector_private)
177 {
178         struct tevent_req *req;
179         struct tstream_readv_pdu_state *state;
180
181         req = tevent_req_create(mem_ctx, &state,
182                                 struct tstream_readv_pdu_state);
183         if (!req) {
184                 return NULL;
185         }
186
187         state->caller.ev                        = ev;
188         state->caller.stream                    = stream;
189         state->caller.next_vector_fn            = next_vector_fn;
190         state->caller.next_vector_private       = next_vector_private;
191
192         state->vector           = NULL;
193         state->count            = 0;
194         state->total_read       = 0;
195
196         tstream_readv_pdu_ask_for_next_vector(req);
197         if (!tevent_req_is_in_progress(req)) {
198                 goto post;
199         }
200
201         return req;
202
203  post:
204         return tevent_req_post(req, ev);
205 }
206
207 static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req)
208 {
209         struct tstream_readv_pdu_state *state = tevent_req_data(req,
210                                             struct tstream_readv_pdu_state);
211         int ret;
212         size_t to_read = 0;
213         size_t i;
214         struct tevent_req *subreq;
215
216         TALLOC_FREE(state->vector);
217         state->count = 0;
218
219         ret = state->caller.next_vector_fn(state->caller.stream,
220                                            state->caller.next_vector_private,
221                                            state, &state->vector, &state->count);
222         if (ret == -1) {
223                 tevent_req_error(req, errno);
224                 return;
225         }
226
227         if (state->count == 0) {
228                 tevent_req_done(req);
229                 return;
230         }
231
232         for (i=0; i < state->count; i++) {
233                 size_t tmp = to_read;
234                 tmp += state->vector[i].iov_len;
235
236                 if (tmp < to_read) {
237                         tevent_req_error(req, EMSGSIZE);
238                         return;
239                 }
240
241                 to_read = tmp;
242         }
243
244         /*
245          * this is invalid the next vector function should have
246          * reported count == 0.
247          */
248         if (to_read == 0) {
249                 tevent_req_error(req, EINVAL);
250                 return;
251         }
252
253         if (state->total_read + to_read < state->total_read) {
254                 tevent_req_error(req, EMSGSIZE);
255                 return;
256         }
257
258         subreq = tstream_readv_send(state,
259                                     state->caller.ev,
260                                     state->caller.stream,
261                                     state->vector,
262                                     state->count);
263         if (tevent_req_nomem(subreq, req)) {
264                 return;
265         }
266         tevent_req_set_callback(subreq, tstream_readv_pdu_readv_done, req);
267 }
268
269 static void tstream_readv_pdu_readv_done(struct tevent_req *subreq)
270 {
271         struct tevent_req *req = tevent_req_callback_data(subreq,
272                                  struct tevent_req);
273         struct tstream_readv_pdu_state *state = tevent_req_data(req,
274                                             struct tstream_readv_pdu_state);
275         int ret;
276         int sys_errno;
277
278         ret = tstream_readv_recv(subreq, &sys_errno);
279         if (ret == -1) {
280                 tevent_req_error(req, sys_errno);
281                 return;
282         }
283
284         state->total_read += ret;
285
286         /* ask the callback for a new vector we should fill */
287         tstream_readv_pdu_ask_for_next_vector(req);
288 }
289
290 int tstream_readv_pdu_recv(struct tevent_req *req, int *perrno)
291 {
292         struct tstream_readv_pdu_state *state = tevent_req_data(req,
293                                             struct tstream_readv_pdu_state);
294         int ret;
295
296         ret = tsocket_simple_int_recv(req, perrno);
297         if (ret == 0) {
298                 ret = state->total_read;
299         }
300
301         tevent_req_received(req);
302         return ret;
303 }
304
305 struct tstream_readv_pdu_queue_state {
306         /* this structs are owned by the caller */
307         struct {
308                 struct tevent_context *ev;
309                 struct tstream_context *stream;
310                 tstream_readv_pdu_next_vector_t next_vector_fn;
311                 void *next_vector_private;
312         } caller;
313         int ret;
314 };
315
316 static void tstream_readv_pdu_queue_trigger(struct tevent_req *req,
317                                          void *private_data);
318 static void tstream_readv_pdu_queue_done(struct tevent_req *subreq);
319
320 struct tevent_req *tstream_readv_pdu_queue_send(TALLOC_CTX *mem_ctx,
321                                 struct tevent_context *ev,
322                                 struct tstream_context *stream,
323                                 struct tevent_queue *queue,
324                                 tstream_readv_pdu_next_vector_t next_vector_fn,
325                                 void *next_vector_private)
326 {
327         struct tevent_req *req;
328         struct tstream_readv_pdu_queue_state *state;
329         bool ok;
330
331         req = tevent_req_create(mem_ctx, &state,
332                                 struct tstream_readv_pdu_queue_state);
333         if (!req) {
334                 return NULL;
335         }
336
337         state->caller.ev                        = ev;
338         state->caller.stream                    = stream;
339         state->caller.next_vector_fn            = next_vector_fn;
340         state->caller.next_vector_private       = next_vector_private;
341         state->ret                              = -1;
342
343         ok = tevent_queue_add(queue,
344                               ev,
345                               req,
346                               tstream_readv_pdu_queue_trigger,
347                               NULL);
348         if (!ok) {
349                 tevent_req_nomem(NULL, req);
350                 goto post;
351         }
352
353         return req;
354
355  post:
356         return tevent_req_post(req, ev);
357 }
358
359 static void tstream_readv_pdu_queue_trigger(struct tevent_req *req,
360                                          void *private_data)
361 {
362         struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
363                                         struct tstream_readv_pdu_queue_state);
364         struct tevent_req *subreq;
365
366         subreq = tstream_readv_pdu_send(state,
367                                         state->caller.ev,
368                                         state->caller.stream,
369                                         state->caller.next_vector_fn,
370                                         state->caller.next_vector_private);
371         if (tevent_req_nomem(subreq, req)) {
372                 return;
373         }
374         tevent_req_set_callback(subreq, tstream_readv_pdu_queue_done ,req);
375 }
376
377 static void tstream_readv_pdu_queue_done(struct tevent_req *subreq)
378 {
379         struct tevent_req *req = tevent_req_callback_data(subreq,
380                                  struct tevent_req);
381         struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
382                                         struct tstream_readv_pdu_queue_state);
383         int ret;
384         int sys_errno;
385
386         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
387         talloc_free(subreq);
388         if (ret == -1) {
389                 tevent_req_error(req, sys_errno);
390                 return;
391         }
392         state->ret = ret;
393
394         tevent_req_done(req);
395 }
396
397 int tstream_readv_pdu_queue_recv(struct tevent_req *req, int *perrno)
398 {
399         struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
400                                         struct tstream_readv_pdu_queue_state);
401         int ret;
402
403         ret = tsocket_simple_int_recv(req, perrno);
404         if (ret == 0) {
405                 ret = state->ret;
406         }
407
408         tevent_req_received(req);
409         return ret;
410 }
411
412 struct tstream_writev_queue_state {
413         /* this structs are owned by the caller */
414         struct {
415                 struct tevent_context *ev;
416                 struct tstream_context *stream;
417                 const struct iovec *vector;
418                 size_t count;
419         } caller;
420         int ret;
421 };
422
423 static void tstream_writev_queue_trigger(struct tevent_req *req,
424                                          void *private_data);
425 static void tstream_writev_queue_done(struct tevent_req *subreq);
426
427 struct tevent_req *tstream_writev_queue_send(TALLOC_CTX *mem_ctx,
428                                              struct tevent_context *ev,
429                                              struct tstream_context *stream,
430                                              struct tevent_queue *queue,
431                                              const struct iovec *vector,
432                                              size_t count)
433 {
434         struct tevent_req *req;
435         struct tstream_writev_queue_state *state;
436         bool ok;
437
438         req = tevent_req_create(mem_ctx, &state,
439                                 struct tstream_writev_queue_state);
440         if (!req) {
441                 return NULL;
442         }
443
444         state->caller.ev        = ev;
445         state->caller.stream    = stream;
446         state->caller.vector    = vector;
447         state->caller.count     = count;
448         state->ret              = -1;
449
450         ok = tevent_queue_add(queue,
451                               ev,
452                               req,
453                               tstream_writev_queue_trigger,
454                               NULL);
455         if (!ok) {
456                 tevent_req_nomem(NULL, req);
457                 goto post;
458         }
459
460         return req;
461
462  post:
463         return tevent_req_post(req, ev);
464 }
465
466 static void tstream_writev_queue_trigger(struct tevent_req *req,
467                                          void *private_data)
468 {
469         struct tstream_writev_queue_state *state = tevent_req_data(req,
470                                         struct tstream_writev_queue_state);
471         struct tevent_req *subreq;
472
473         subreq = tstream_writev_send(state,
474                                      state->caller.ev,
475                                      state->caller.stream,
476                                      state->caller.vector,
477                                      state->caller.count);
478         if (tevent_req_nomem(subreq, req)) {
479                 return;
480         }
481         tevent_req_set_callback(subreq, tstream_writev_queue_done ,req);
482 }
483
484 static void tstream_writev_queue_done(struct tevent_req *subreq)
485 {
486         struct tevent_req *req = tevent_req_callback_data(subreq,
487                                  struct tevent_req);
488         struct tstream_writev_queue_state *state = tevent_req_data(req,
489                                         struct tstream_writev_queue_state);
490         int ret;
491         int sys_errno;
492
493         ret = tstream_writev_recv(subreq, &sys_errno);
494         talloc_free(subreq);
495         if (ret == -1) {
496                 tevent_req_error(req, sys_errno);
497                 return;
498         }
499         state->ret = ret;
500
501         tevent_req_done(req);
502 }
503
504 int tstream_writev_queue_recv(struct tevent_req *req, int *perrno)
505 {
506         struct tstream_writev_queue_state *state = tevent_req_data(req,
507                                         struct tstream_writev_queue_state);
508         int ret;
509
510         ret = tsocket_simple_int_recv(req, perrno);
511         if (ret == 0) {
512                 ret = state->ret;
513         }
514
515         tevent_req_received(req);
516         return ret;
517 }
518