script/autobuild.py: add --branch option
[Samba/bb.git] / lib / tsocket / tsocket_helpers.c
blob1b92b9f82ca30d6bbaea2e06f94b4abf50e4052d
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2009
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
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.
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.
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/>.
24 #include "replace.h"
25 #include "system/filesys.h"
26 #include "tsocket.h"
27 #include "tsocket_internal.h"
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;
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);
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)
53 struct tevent_req *req;
54 struct tdgram_sendto_queue_state *state;
55 struct tevent_queue_entry *e;
57 req = tevent_req_create(mem_ctx, &state,
58 struct tdgram_sendto_queue_state);
59 if (!req) {
60 return NULL;
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;
71 * we use tevent_queue_add_optimize_empty() with allow_direct
72 * in order to optimize for the empty queue case.
74 e = tevent_queue_add_optimize_empty(
75 queue,
76 ev,
77 req,
78 tdgram_sendto_queue_trigger,
79 NULL);
80 if (tevent_req_nomem(e, req)) {
81 return tevent_req_post(req, ev);
83 if (!tevent_req_is_in_progress(req)) {
84 return tevent_req_post(req, ev);
87 return req;
90 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
91 void *private_data)
93 struct tdgram_sendto_queue_state *state = tevent_req_data(req,
94 struct tdgram_sendto_queue_state);
95 struct tevent_req *subreq;
97 subreq = tdgram_sendto_send(state,
98 state->caller.ev,
99 state->caller.dgram,
100 state->caller.buf,
101 state->caller.len,
102 state->caller.dst);
103 if (tevent_req_nomem(subreq, req)) {
104 return;
106 tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
109 static void tdgram_sendto_queue_done(struct tevent_req *subreq)
111 struct tevent_req *req = tevent_req_callback_data(subreq,
112 struct tevent_req);
113 struct tdgram_sendto_queue_state *state = tevent_req_data(req,
114 struct tdgram_sendto_queue_state);
115 ssize_t ret;
116 int sys_errno;
118 ret = tdgram_sendto_recv(subreq, &sys_errno);
119 talloc_free(subreq);
120 if (ret == -1) {
121 tevent_req_error(req, sys_errno);
122 return;
124 state->ret = ret;
126 tevent_req_done(req);
129 ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
131 struct tdgram_sendto_queue_state *state = tevent_req_data(req,
132 struct tdgram_sendto_queue_state);
133 ssize_t ret;
135 ret = tsocket_simple_int_recv(req, perrno);
136 if (ret == 0) {
137 ret = state->ret;
140 tevent_req_received(req);
141 return ret;
144 struct tstream_readv_pdu_state {
145 /* this structs are owned by the caller */
146 struct {
147 struct tevent_context *ev;
148 struct tstream_context *stream;
149 tstream_readv_pdu_next_vector_t next_vector_fn;
150 void *next_vector_private;
151 } caller;
154 * Each call to the callback resets iov and count
155 * the callback allocated the iov as child of our state,
156 * that means we are allowed to modify and free it.
158 * we should call the callback every time we filled the given
159 * vector and ask for a new vector. We return if the callback
160 * ask for 0 bytes.
162 struct iovec *vector;
163 size_t count;
166 * the total number of bytes we read,
167 * the return value of the _recv function
169 int total_read;
172 static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req);
173 static void tstream_readv_pdu_readv_done(struct tevent_req *subreq);
175 struct tevent_req *tstream_readv_pdu_send(TALLOC_CTX *mem_ctx,
176 struct tevent_context *ev,
177 struct tstream_context *stream,
178 tstream_readv_pdu_next_vector_t next_vector_fn,
179 void *next_vector_private)
181 struct tevent_req *req;
182 struct tstream_readv_pdu_state *state;
184 req = tevent_req_create(mem_ctx, &state,
185 struct tstream_readv_pdu_state);
186 if (!req) {
187 return NULL;
190 state->caller.ev = ev;
191 state->caller.stream = stream;
192 state->caller.next_vector_fn = next_vector_fn;
193 state->caller.next_vector_private = next_vector_private;
195 state->vector = NULL;
196 state->count = 0;
197 state->total_read = 0;
199 tstream_readv_pdu_ask_for_next_vector(req);
200 if (!tevent_req_is_in_progress(req)) {
201 goto post;
204 return req;
206 post:
207 return tevent_req_post(req, ev);
210 static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req)
212 struct tstream_readv_pdu_state *state = tevent_req_data(req,
213 struct tstream_readv_pdu_state);
214 int ret;
215 size_t to_read = 0;
216 size_t i;
217 struct tevent_req *subreq;
219 TALLOC_FREE(state->vector);
220 state->count = 0;
222 ret = state->caller.next_vector_fn(state->caller.stream,
223 state->caller.next_vector_private,
224 state, &state->vector, &state->count);
225 if (ret == -1) {
226 tevent_req_error(req, errno);
227 return;
230 if (state->count == 0) {
231 tevent_req_done(req);
232 return;
235 for (i=0; i < state->count; i++) {
236 size_t tmp = to_read;
237 tmp += state->vector[i].iov_len;
239 if (tmp < to_read) {
240 tevent_req_error(req, EMSGSIZE);
241 return;
244 to_read = tmp;
248 * this is invalid the next vector function should have
249 * reported count == 0.
251 if (to_read == 0) {
252 tevent_req_error(req, EINVAL);
253 return;
256 if (state->total_read + to_read < state->total_read) {
257 tevent_req_error(req, EMSGSIZE);
258 return;
261 subreq = tstream_readv_send(state,
262 state->caller.ev,
263 state->caller.stream,
264 state->vector,
265 state->count);
266 if (tevent_req_nomem(subreq, req)) {
267 return;
269 tevent_req_set_callback(subreq, tstream_readv_pdu_readv_done, req);
272 static void tstream_readv_pdu_readv_done(struct tevent_req *subreq)
274 struct tevent_req *req = tevent_req_callback_data(subreq,
275 struct tevent_req);
276 struct tstream_readv_pdu_state *state = tevent_req_data(req,
277 struct tstream_readv_pdu_state);
278 int ret;
279 int sys_errno;
281 ret = tstream_readv_recv(subreq, &sys_errno);
282 if (ret == -1) {
283 tevent_req_error(req, sys_errno);
284 return;
287 state->total_read += ret;
289 /* ask the callback for a new vector we should fill */
290 tstream_readv_pdu_ask_for_next_vector(req);
293 int tstream_readv_pdu_recv(struct tevent_req *req, int *perrno)
295 struct tstream_readv_pdu_state *state = tevent_req_data(req,
296 struct tstream_readv_pdu_state);
297 int ret;
299 ret = tsocket_simple_int_recv(req, perrno);
300 if (ret == 0) {
301 ret = state->total_read;
304 tevent_req_received(req);
305 return ret;
308 struct tstream_readv_pdu_queue_state {
309 /* this structs are owned by the caller */
310 struct {
311 struct tevent_context *ev;
312 struct tstream_context *stream;
313 tstream_readv_pdu_next_vector_t next_vector_fn;
314 void *next_vector_private;
315 } caller;
316 int ret;
319 static void tstream_readv_pdu_queue_trigger(struct tevent_req *req,
320 void *private_data);
321 static void tstream_readv_pdu_queue_done(struct tevent_req *subreq);
323 struct tevent_req *tstream_readv_pdu_queue_send(TALLOC_CTX *mem_ctx,
324 struct tevent_context *ev,
325 struct tstream_context *stream,
326 struct tevent_queue *queue,
327 tstream_readv_pdu_next_vector_t next_vector_fn,
328 void *next_vector_private)
330 struct tevent_req *req;
331 struct tstream_readv_pdu_queue_state *state;
332 struct tevent_queue_entry *e;
334 req = tevent_req_create(mem_ctx, &state,
335 struct tstream_readv_pdu_queue_state);
336 if (!req) {
337 return NULL;
340 state->caller.ev = ev;
341 state->caller.stream = stream;
342 state->caller.next_vector_fn = next_vector_fn;
343 state->caller.next_vector_private = next_vector_private;
344 state->ret = -1;
347 * we use tevent_queue_add_optimize_empty() with allow_direct
348 * in order to optimize for the empty queue case.
350 e = tevent_queue_add_optimize_empty(
351 queue,
353 req,
354 tstream_readv_pdu_queue_trigger,
355 NULL);
356 if (tevent_req_nomem(e, req)) {
357 return tevent_req_post(req, ev);
359 if (!tevent_req_is_in_progress(req)) {
360 return tevent_req_post(req, ev);
363 return req;
366 static void tstream_readv_pdu_queue_trigger(struct tevent_req *req,
367 void *private_data)
369 struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
370 struct tstream_readv_pdu_queue_state);
371 struct tevent_req *subreq;
373 subreq = tstream_readv_pdu_send(state,
374 state->caller.ev,
375 state->caller.stream,
376 state->caller.next_vector_fn,
377 state->caller.next_vector_private);
378 if (tevent_req_nomem(subreq, req)) {
379 return;
381 tevent_req_set_callback(subreq, tstream_readv_pdu_queue_done ,req);
384 static void tstream_readv_pdu_queue_done(struct tevent_req *subreq)
386 struct tevent_req *req = tevent_req_callback_data(subreq,
387 struct tevent_req);
388 struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
389 struct tstream_readv_pdu_queue_state);
390 int ret;
391 int sys_errno;
393 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
394 talloc_free(subreq);
395 if (ret == -1) {
396 tevent_req_error(req, sys_errno);
397 return;
399 state->ret = ret;
401 tevent_req_done(req);
404 int tstream_readv_pdu_queue_recv(struct tevent_req *req, int *perrno)
406 struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
407 struct tstream_readv_pdu_queue_state);
408 int ret;
410 ret = tsocket_simple_int_recv(req, perrno);
411 if (ret == 0) {
412 ret = state->ret;
415 tevent_req_received(req);
416 return ret;
419 struct tstream_writev_queue_state {
420 /* this structs are owned by the caller */
421 struct {
422 struct tevent_context *ev;
423 struct tstream_context *stream;
424 const struct iovec *vector;
425 size_t count;
426 } caller;
427 int ret;
430 static void tstream_writev_queue_trigger(struct tevent_req *req,
431 void *private_data);
432 static void tstream_writev_queue_done(struct tevent_req *subreq);
434 struct tevent_req *tstream_writev_queue_send(TALLOC_CTX *mem_ctx,
435 struct tevent_context *ev,
436 struct tstream_context *stream,
437 struct tevent_queue *queue,
438 const struct iovec *vector,
439 size_t count)
441 struct tevent_req *req;
442 struct tstream_writev_queue_state *state;
443 struct tevent_queue_entry *e;
445 req = tevent_req_create(mem_ctx, &state,
446 struct tstream_writev_queue_state);
447 if (!req) {
448 return NULL;
451 state->caller.ev = ev;
452 state->caller.stream = stream;
453 state->caller.vector = vector;
454 state->caller.count = count;
455 state->ret = -1;
458 * we use tevent_queue_add_optimize_empty() with allow_direct
459 * in order to optimize for the empty queue case.
461 e = tevent_queue_add_optimize_empty(
462 queue,
464 req,
465 tstream_writev_queue_trigger,
466 NULL);
467 if (tevent_req_nomem(e, req)) {
468 return tevent_req_post(req, ev);
470 if (!tevent_req_is_in_progress(req)) {
471 return tevent_req_post(req, ev);
474 return req;
477 static void tstream_writev_queue_trigger(struct tevent_req *req,
478 void *private_data)
480 struct tstream_writev_queue_state *state = tevent_req_data(req,
481 struct tstream_writev_queue_state);
482 struct tevent_req *subreq;
484 subreq = tstream_writev_send(state,
485 state->caller.ev,
486 state->caller.stream,
487 state->caller.vector,
488 state->caller.count);
489 if (tevent_req_nomem(subreq, req)) {
490 return;
492 tevent_req_set_callback(subreq, tstream_writev_queue_done ,req);
495 static void tstream_writev_queue_done(struct tevent_req *subreq)
497 struct tevent_req *req = tevent_req_callback_data(subreq,
498 struct tevent_req);
499 struct tstream_writev_queue_state *state = tevent_req_data(req,
500 struct tstream_writev_queue_state);
501 int ret;
502 int sys_errno;
504 ret = tstream_writev_recv(subreq, &sys_errno);
505 talloc_free(subreq);
506 if (ret == -1) {
507 tevent_req_error(req, sys_errno);
508 return;
510 state->ret = ret;
512 tevent_req_done(req);
515 int tstream_writev_queue_recv(struct tevent_req *req, int *perrno)
517 struct tstream_writev_queue_state *state = tevent_req_data(req,
518 struct tstream_writev_queue_state);
519 int ret;
521 ret = tsocket_simple_int_recv(req, perrno);
522 if (ret == 0) {
523 ret = state->ret;
526 tevent_req_received(req);
527 return ret;