Line data Source code
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 34321 : 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 1242 : struct tevent_req *req;
54 1242 : struct tdgram_sendto_queue_state *state;
55 1242 : struct tevent_queue_entry *e;
56 :
57 34321 : req = tevent_req_create(mem_ctx, &state,
58 : struct tdgram_sendto_queue_state);
59 34321 : if (!req) {
60 0 : return NULL;
61 : }
62 :
63 34321 : state->caller.ev = ev;
64 34321 : state->caller.dgram = dgram;
65 34321 : state->caller.buf = buf;
66 34321 : state->caller.len = len;
67 34321 : state->caller.dst = dst;
68 34321 : state->ret = -1;
69 :
70 : /*
71 : * we use tevent_queue_add_optimize_empty() with allow_direct
72 : * in order to optimize for the empty queue case.
73 : */
74 34321 : e = tevent_queue_add_optimize_empty(
75 : queue,
76 : ev,
77 : req,
78 : tdgram_sendto_queue_trigger,
79 : NULL);
80 34321 : if (tevent_req_nomem(e, req)) {
81 0 : return tevent_req_post(req, ev);
82 : }
83 34321 : if (!tevent_req_is_in_progress(req)) {
84 0 : return tevent_req_post(req, ev);
85 : }
86 :
87 33079 : return req;
88 : }
89 :
90 34321 : static void tdgram_sendto_queue_trigger(struct tevent_req *req,
91 : void *private_data)
92 : {
93 34321 : struct tdgram_sendto_queue_state *state = tevent_req_data(req,
94 : struct tdgram_sendto_queue_state);
95 1242 : struct tevent_req *subreq;
96 :
97 34321 : 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 34321 : if (tevent_req_nomem(subreq, req)) {
104 0 : return;
105 : }
106 34321 : tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
107 : }
108 :
109 34321 : static void tdgram_sendto_queue_done(struct tevent_req *subreq)
110 : {
111 34321 : struct tevent_req *req = tevent_req_callback_data(subreq,
112 : struct tevent_req);
113 34321 : struct tdgram_sendto_queue_state *state = tevent_req_data(req,
114 : struct tdgram_sendto_queue_state);
115 1242 : ssize_t ret;
116 1242 : int sys_errno;
117 :
118 34321 : ret = tdgram_sendto_recv(subreq, &sys_errno);
119 34321 : talloc_free(subreq);
120 34321 : if (ret == -1) {
121 10 : tevent_req_error(req, sys_errno);
122 10 : return;
123 : }
124 34311 : state->ret = ret;
125 :
126 34311 : tevent_req_done(req);
127 : }
128 :
129 31895 : ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
130 : {
131 31895 : struct tdgram_sendto_queue_state *state = tevent_req_data(req,
132 : struct tdgram_sendto_queue_state);
133 1206 : ssize_t ret;
134 :
135 31895 : ret = tsocket_simple_int_recv(req, perrno);
136 31895 : if (ret == 0) {
137 31885 : ret = state->ret;
138 : }
139 :
140 31895 : tevent_req_received(req);
141 31895 : return ret;
142 : }
143 :
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;
152 :
153 : /*
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.
157 : *
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.
161 : */
162 : struct iovec *vector;
163 : size_t count;
164 :
165 : /*
166 : * the total number of bytes we read,
167 : * the return value of the _recv function
168 : */
169 : int total_read;
170 : };
171 :
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);
174 :
175 6109436 : 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)
180 : {
181 43632 : struct tevent_req *req;
182 43632 : struct tstream_readv_pdu_state *state;
183 :
184 6109436 : req = tevent_req_create(mem_ctx, &state,
185 : struct tstream_readv_pdu_state);
186 6109436 : if (!req) {
187 0 : return NULL;
188 : }
189 :
190 6109436 : state->caller.ev = ev;
191 6109436 : state->caller.stream = stream;
192 6109436 : state->caller.next_vector_fn = next_vector_fn;
193 6109436 : state->caller.next_vector_private = next_vector_private;
194 :
195 6109436 : state->vector = NULL;
196 6109436 : state->count = 0;
197 6109436 : state->total_read = 0;
198 :
199 6109436 : tstream_readv_pdu_ask_for_next_vector(req);
200 6109436 : if (!tevent_req_is_in_progress(req)) {
201 0 : goto post;
202 : }
203 :
204 6065804 : return req;
205 :
206 0 : post:
207 0 : return tevent_req_post(req, ev);
208 : }
209 :
210 16885462 : static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req)
211 : {
212 16885462 : struct tstream_readv_pdu_state *state = tevent_req_data(req,
213 : struct tstream_readv_pdu_state);
214 127622 : int ret;
215 16885462 : size_t to_read = 0;
216 127622 : size_t i;
217 127622 : struct tevent_req *subreq;
218 16885462 : bool optimize = false;
219 16885462 : bool save_optimize = false;
220 :
221 16885462 : if (state->count > 0) {
222 : /*
223 : * This is not the first time we asked for a vector,
224 : * which means parts of the pdu already arrived.
225 : *
226 : * In this case it make sense to enable
227 : * a syscall/performance optimization if the
228 : * low level tstream implementation supports it.
229 : */
230 10776026 : optimize = true;
231 : }
232 :
233 16885462 : TALLOC_FREE(state->vector);
234 16885462 : state->count = 0;
235 :
236 16885462 : ret = state->caller.next_vector_fn(state->caller.stream,
237 : state->caller.next_vector_private,
238 : state, &state->vector, &state->count);
239 16885462 : if (ret == -1) {
240 0 : tevent_req_error(req, errno);
241 0 : return;
242 : }
243 :
244 16885462 : if (state->count == 0) {
245 5973260 : tevent_req_done(req);
246 5973260 : return;
247 : }
248 :
249 23509031 : for (i=0; i < state->count; i++) {
250 12596829 : size_t tmp = to_read;
251 12596829 : tmp += state->vector[i].iov_len;
252 :
253 12596829 : if (tmp < to_read) {
254 0 : tevent_req_error(req, EMSGSIZE);
255 0 : return;
256 : }
257 :
258 12596829 : to_read = tmp;
259 : }
260 :
261 : /*
262 : * this is invalid the next vector function should have
263 : * reported count == 0.
264 : */
265 10912202 : if (to_read == 0) {
266 0 : tevent_req_error(req, EINVAL);
267 0 : return;
268 : }
269 :
270 10912202 : if (state->total_read + to_read < state->total_read) {
271 0 : tevent_req_error(req, EMSGSIZE);
272 0 : return;
273 : }
274 :
275 10912202 : if (optimize) {
276 : /*
277 : * If the low level stream is a bsd socket
278 : * we will get syscall optimization.
279 : *
280 : * If it is not a bsd socket
281 : * tstream_bsd_optimize_readv() just returns.
282 : */
283 4802766 : save_optimize = tstream_bsd_optimize_readv(state->caller.stream,
284 : true);
285 : }
286 10912202 : subreq = tstream_readv_send(state,
287 : state->caller.ev,
288 : state->caller.stream,
289 : state->vector,
290 : state->count);
291 10912202 : if (optimize) {
292 4802766 : tstream_bsd_optimize_readv(state->caller.stream,
293 : save_optimize);
294 : }
295 10912202 : if (tevent_req_nomem(subreq, req)) {
296 0 : return;
297 : }
298 10912202 : tevent_req_set_callback(subreq, tstream_readv_pdu_readv_done, req);
299 : }
300 :
301 10911776 : static void tstream_readv_pdu_readv_done(struct tevent_req *subreq)
302 : {
303 10911776 : struct tevent_req *req = tevent_req_callback_data(subreq,
304 : struct tevent_req);
305 10911776 : struct tstream_readv_pdu_state *state = tevent_req_data(req,
306 : struct tstream_readv_pdu_state);
307 85602 : int ret;
308 85602 : int sys_errno;
309 :
310 10911776 : ret = tstream_readv_recv(subreq, &sys_errno);
311 10911776 : TALLOC_FREE(subreq);
312 10911776 : if (ret == -1) {
313 135750 : tevent_req_error(req, sys_errno);
314 135282 : return;
315 : }
316 :
317 10776026 : state->total_read += ret;
318 :
319 : /* ask the callback for a new vector we should fill */
320 10776026 : tstream_readv_pdu_ask_for_next_vector(req);
321 : }
322 :
323 6109010 : int tstream_readv_pdu_recv(struct tevent_req *req, int *perrno)
324 : {
325 6109010 : struct tstream_readv_pdu_state *state = tevent_req_data(req,
326 : struct tstream_readv_pdu_state);
327 43607 : int ret;
328 :
329 6109010 : ret = tsocket_simple_int_recv(req, perrno);
330 6109010 : if (ret == 0) {
331 5973260 : ret = state->total_read;
332 : }
333 :
334 6109010 : tevent_req_received(req);
335 6109010 : return ret;
336 : }
337 :
338 : struct tstream_readv_pdu_queue_state {
339 : /* this structs are owned by the caller */
340 : struct {
341 : struct tevent_context *ev;
342 : struct tstream_context *stream;
343 : tstream_readv_pdu_next_vector_t next_vector_fn;
344 : void *next_vector_private;
345 : } caller;
346 : int ret;
347 : };
348 :
349 : static void tstream_readv_pdu_queue_trigger(struct tevent_req *req,
350 : void *private_data);
351 : static void tstream_readv_pdu_queue_done(struct tevent_req *subreq);
352 :
353 1546048 : struct tevent_req *tstream_readv_pdu_queue_send(TALLOC_CTX *mem_ctx,
354 : struct tevent_context *ev,
355 : struct tstream_context *stream,
356 : struct tevent_queue *queue,
357 : tstream_readv_pdu_next_vector_t next_vector_fn,
358 : void *next_vector_private)
359 : {
360 7598 : struct tevent_req *req;
361 7598 : struct tstream_readv_pdu_queue_state *state;
362 7598 : struct tevent_queue_entry *e;
363 :
364 1546048 : req = tevent_req_create(mem_ctx, &state,
365 : struct tstream_readv_pdu_queue_state);
366 1546048 : if (!req) {
367 0 : return NULL;
368 : }
369 :
370 1546048 : state->caller.ev = ev;
371 1546048 : state->caller.stream = stream;
372 1546048 : state->caller.next_vector_fn = next_vector_fn;
373 1546048 : state->caller.next_vector_private = next_vector_private;
374 1546048 : state->ret = -1;
375 :
376 : /*
377 : * we use tevent_queue_add_optimize_empty() with allow_direct
378 : * in order to optimize for the empty queue case.
379 : */
380 1546048 : e = tevent_queue_add_optimize_empty(
381 : queue,
382 : ev,
383 : req,
384 : tstream_readv_pdu_queue_trigger,
385 : NULL);
386 1546048 : if (tevent_req_nomem(e, req)) {
387 0 : return tevent_req_post(req, ev);
388 : }
389 1546048 : if (!tevent_req_is_in_progress(req)) {
390 0 : return tevent_req_post(req, ev);
391 : }
392 :
393 1538450 : return req;
394 : }
395 :
396 1546048 : static void tstream_readv_pdu_queue_trigger(struct tevent_req *req,
397 : void *private_data)
398 : {
399 1546048 : struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
400 : struct tstream_readv_pdu_queue_state);
401 7598 : struct tevent_req *subreq;
402 :
403 1546048 : subreq = tstream_readv_pdu_send(state,
404 : state->caller.ev,
405 : state->caller.stream,
406 : state->caller.next_vector_fn,
407 : state->caller.next_vector_private);
408 1546048 : if (tevent_req_nomem(subreq, req)) {
409 0 : return;
410 : }
411 1546048 : tevent_req_set_callback(subreq, tstream_readv_pdu_queue_done ,req);
412 : }
413 :
414 1546048 : static void tstream_readv_pdu_queue_done(struct tevent_req *subreq)
415 : {
416 1546048 : struct tevent_req *req = tevent_req_callback_data(subreq,
417 : struct tevent_req);
418 1546048 : struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
419 : struct tstream_readv_pdu_queue_state);
420 7598 : int ret;
421 7598 : int sys_errno;
422 :
423 1546048 : ret = tstream_readv_pdu_recv(subreq, &sys_errno);
424 1546048 : talloc_free(subreq);
425 1546048 : if (ret == -1) {
426 15 : tevent_req_error(req, sys_errno);
427 15 : return;
428 : }
429 1546033 : state->ret = ret;
430 :
431 1546033 : tevent_req_done(req);
432 : }
433 :
434 1546048 : int tstream_readv_pdu_queue_recv(struct tevent_req *req, int *perrno)
435 : {
436 1546048 : struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
437 : struct tstream_readv_pdu_queue_state);
438 7598 : int ret;
439 :
440 1546048 : ret = tsocket_simple_int_recv(req, perrno);
441 1546048 : if (ret == 0) {
442 1546033 : ret = state->ret;
443 : }
444 :
445 1546048 : tevent_req_received(req);
446 1546048 : return ret;
447 : }
448 :
449 : struct tstream_writev_queue_state {
450 : /* this structs are owned by the caller */
451 : struct {
452 : struct tevent_context *ev;
453 : struct tstream_context *stream;
454 : const struct iovec *vector;
455 : size_t count;
456 : } caller;
457 : int ret;
458 : };
459 :
460 : static void tstream_writev_queue_trigger(struct tevent_req *req,
461 : void *private_data);
462 : static void tstream_writev_queue_done(struct tevent_req *subreq);
463 :
464 3799827 : struct tevent_req *tstream_writev_queue_send(TALLOC_CTX *mem_ctx,
465 : struct tevent_context *ev,
466 : struct tstream_context *stream,
467 : struct tevent_queue *queue,
468 : const struct iovec *vector,
469 : size_t count)
470 : {
471 28254 : struct tevent_req *req;
472 28254 : struct tstream_writev_queue_state *state;
473 28254 : struct tevent_queue_entry *e;
474 :
475 3799827 : req = tevent_req_create(mem_ctx, &state,
476 : struct tstream_writev_queue_state);
477 3799827 : if (!req) {
478 0 : return NULL;
479 : }
480 :
481 3799827 : state->caller.ev = ev;
482 3799827 : state->caller.stream = stream;
483 3799827 : state->caller.vector = vector;
484 3799827 : state->caller.count = count;
485 3799827 : state->ret = -1;
486 :
487 : /*
488 : * we use tevent_queue_add_optimize_empty() with allow_direct
489 : * in order to optimize for the empty queue case.
490 : */
491 3799827 : e = tevent_queue_add_optimize_empty(
492 : queue,
493 : ev,
494 : req,
495 : tstream_writev_queue_trigger,
496 : NULL);
497 3799827 : if (tevent_req_nomem(e, req)) {
498 0 : return tevent_req_post(req, ev);
499 : }
500 3799827 : if (!tevent_req_is_in_progress(req)) {
501 0 : return tevent_req_post(req, ev);
502 : }
503 :
504 3771573 : return req;
505 : }
506 :
507 3799812 : static void tstream_writev_queue_trigger(struct tevent_req *req,
508 : void *private_data)
509 : {
510 3799812 : struct tstream_writev_queue_state *state = tevent_req_data(req,
511 : struct tstream_writev_queue_state);
512 28251 : struct tevent_req *subreq;
513 :
514 3799812 : subreq = tstream_writev_send(state,
515 : state->caller.ev,
516 : state->caller.stream,
517 : state->caller.vector,
518 : state->caller.count);
519 3799812 : if (tevent_req_nomem(subreq, req)) {
520 0 : return;
521 : }
522 3799812 : tevent_req_set_callback(subreq, tstream_writev_queue_done ,req);
523 : }
524 :
525 3799726 : static void tstream_writev_queue_done(struct tevent_req *subreq)
526 : {
527 3799726 : struct tevent_req *req = tevent_req_callback_data(subreq,
528 : struct tevent_req);
529 3799726 : struct tstream_writev_queue_state *state = tevent_req_data(req,
530 : struct tstream_writev_queue_state);
531 28251 : int ret;
532 28251 : int sys_errno;
533 :
534 3799726 : ret = tstream_writev_recv(subreq, &sys_errno);
535 3799726 : talloc_free(subreq);
536 3799726 : if (ret == -1) {
537 31 : tevent_req_error(req, sys_errno);
538 31 : return;
539 : }
540 3799695 : state->ret = ret;
541 :
542 3799695 : tevent_req_done(req);
543 : }
544 :
545 3799726 : int tstream_writev_queue_recv(struct tevent_req *req, int *perrno)
546 : {
547 3799726 : struct tstream_writev_queue_state *state = tevent_req_data(req,
548 : struct tstream_writev_queue_state);
549 28251 : int ret;
550 :
551 3799726 : ret = tsocket_simple_int_recv(req, perrno);
552 3799726 : if (ret == 0) {
553 3799695 : ret = state->ret;
554 : }
555 :
556 3799726 : tevent_req_received(req);
557 3799726 : return ret;
558 : }
559 :
|