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
tsocket_simple_int_recv(struct tevent_req * req,int * perrno)29 int tsocket_simple_int_recv(struct tevent_req *req, int *perrno)
30 {
31 enum tevent_req_state state;
32 uint64_t error;
33
34 if (!tevent_req_is_error(req, &state, &error)) {
35 return 0;
36 }
37
38 switch (state) {
39 case TEVENT_REQ_NO_MEMORY:
40 *perrno = ENOMEM;
41 return -1;
42 case TEVENT_REQ_TIMED_OUT:
43 *perrno = ETIMEDOUT;
44 return -1;
45 case TEVENT_REQ_USER_ERROR:
46 *perrno = (int)error;
47 return -1;
48 default:
49 break;
50 }
51
52 *perrno = EIO;
53 return -1;
54 }
55
_tsocket_address_create(TALLOC_CTX * mem_ctx,const struct tsocket_address_ops * ops,void * pstate,size_t psize,const char * type,const char * location)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
tsocket_address_string(const struct tsocket_address * addr,TALLOC_CTX * mem_ctx)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
_tsocket_address_copy(const struct tsocket_address * addr,TALLOC_CTX * mem_ctx,const char * location)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
tdgram_context_destructor(struct tdgram_context * dgram)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
_tdgram_context_create(TALLOC_CTX * mem_ctx,const struct tdgram_context_ops * ops,void * pstate,size_t psize,const char * type,const char * location)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
_tdgram_context_data(struct tdgram_context * dgram)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
tdgram_recvfrom_destructor(struct tdgram_recvfrom_state * state)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
tdgram_recvfrom_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct tdgram_context * dgram)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
tdgram_recvfrom_done(struct tevent_req * subreq)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
tdgram_recvfrom_recv(struct tevent_req * req,int * perrno,TALLOC_CTX * mem_ctx,uint8_t ** buf,struct tsocket_address ** src)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
tdgram_sendto_destructor(struct tdgram_sendto_state * state)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
tdgram_sendto_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct tdgram_context * dgram,const uint8_t * buf,size_t len,const struct tsocket_address * dst)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
tdgram_sendto_done(struct tevent_req * subreq)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
tdgram_sendto_recv(struct tevent_req * req,int * perrno)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
tdgram_disconnect_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct tdgram_context * dgram)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
tdgram_disconnect_done(struct tevent_req * subreq)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
tdgram_disconnect_recv(struct tevent_req * req,int * perrno)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
434 struct tstream_context {
435 const char *location;
436 const struct tstream_context_ops *ops;
437 void *private_data;
438
439 struct tevent_req *readv_req;
440 struct tevent_req *writev_req;
441 };
442
tstream_context_destructor(struct tstream_context * stream)443 static int tstream_context_destructor(struct tstream_context *stream)
444 {
445 if (stream->readv_req) {
446 tevent_req_received(stream->readv_req);
447 }
448
449 if (stream->writev_req) {
450 tevent_req_received(stream->writev_req);
451 }
452
453 return 0;
454 }
455
_tstream_context_create(TALLOC_CTX * mem_ctx,const struct tstream_context_ops * ops,void * pstate,size_t psize,const char * type,const char * location)456 struct tstream_context *_tstream_context_create(TALLOC_CTX *mem_ctx,
457 const struct tstream_context_ops *ops,
458 void *pstate,
459 size_t psize,
460 const char *type,
461 const char *location)
462 {
463 struct tstream_context *stream;
464 void **ppstate = (void **)pstate;
465 void *state;
466
467 stream = talloc(mem_ctx, struct tstream_context);
468 if (stream == NULL) {
469 return NULL;
470 }
471 stream->location = location;
472 stream->ops = ops;
473 stream->readv_req = NULL;
474 stream->writev_req = NULL;
475
476 state = talloc_size(stream, psize);
477 if (state == NULL) {
478 talloc_free(stream);
479 return NULL;
480 }
481 talloc_set_name_const(state, type);
482
483 stream->private_data = state;
484
485 talloc_set_destructor(stream, tstream_context_destructor);
486
487 *ppstate = state;
488 return stream;
489 }
490
_tstream_context_data(struct tstream_context * stream)491 void *_tstream_context_data(struct tstream_context *stream)
492 {
493 return stream->private_data;
494 }
495
tstream_pending_bytes(struct tstream_context * stream)496 ssize_t tstream_pending_bytes(struct tstream_context *stream)
497 {
498 return stream->ops->pending_bytes(stream);
499 }
500
501 struct tstream_readv_state {
502 const struct tstream_context_ops *ops;
503 struct tstream_context *stream;
504 int ret;
505 };
506
tstream_readv_destructor(struct tstream_readv_state * state)507 static int tstream_readv_destructor(struct tstream_readv_state *state)
508 {
509 if (state->stream) {
510 state->stream->readv_req = NULL;
511 }
512
513 return 0;
514 }
515
516 static void tstream_readv_done(struct tevent_req *subreq);
517
tstream_readv_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct tstream_context * stream,struct iovec * vector,size_t count)518 struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
519 struct tevent_context *ev,
520 struct tstream_context *stream,
521 struct iovec *vector,
522 size_t count)
523 {
524 struct tevent_req *req;
525 struct tstream_readv_state *state;
526 struct tevent_req *subreq;
527 int to_read = 0;
528 size_t i;
529
530 req = tevent_req_create(mem_ctx, &state,
531 struct tstream_readv_state);
532 if (req == NULL) {
533 return NULL;
534 }
535
536 state->ops = stream->ops;
537 state->stream = stream;
538 state->ret = -1;
539
540 /* first check if the input is ok */
541 #ifdef IOV_MAX
542 if (count > IOV_MAX) {
543 tevent_req_error(req, EMSGSIZE);
544 goto post;
545 }
546 #endif
547
548 for (i=0; i < count; i++) {
549 int tmp = to_read;
550 tmp += vector[i].iov_len;
551
552 if (tmp < to_read) {
553 tevent_req_error(req, EMSGSIZE);
554 goto post;
555 }
556
557 to_read = tmp;
558 }
559
560 if (to_read == 0) {
561 tevent_req_error(req, EINVAL);
562 goto post;
563 }
564
565 if (stream->readv_req) {
566 tevent_req_error(req, EBUSY);
567 goto post;
568 }
569 stream->readv_req = req;
570
571 talloc_set_destructor(state, tstream_readv_destructor);
572
573 subreq = state->ops->readv_send(state, ev, stream, vector, count);
574 if (tevent_req_nomem(subreq, req)) {
575 goto post;
576 }
577 tevent_req_set_callback(subreq, tstream_readv_done, req);
578
579 return req;
580
581 post:
582 tevent_req_post(req, ev);
583 return req;
584 }
585
tstream_readv_done(struct tevent_req * subreq)586 static void tstream_readv_done(struct tevent_req *subreq)
587 {
588 struct tevent_req *req = tevent_req_callback_data(subreq,
589 struct tevent_req);
590 struct tstream_readv_state *state = tevent_req_data(req,
591 struct tstream_readv_state);
592 ssize_t ret;
593 int sys_errno;
594
595 ret = state->ops->readv_recv(subreq, &sys_errno);
596 TALLOC_FREE(subreq);
597 if (ret == -1) {
598 tevent_req_error(req, sys_errno);
599 return;
600 }
601
602 state->ret = ret;
603
604 tevent_req_done(req);
605 }
606
tstream_readv_recv(struct tevent_req * req,int * perrno)607 int tstream_readv_recv(struct tevent_req *req,
608 int *perrno)
609 {
610 struct tstream_readv_state *state = tevent_req_data(req,
611 struct tstream_readv_state);
612 int ret;
613
614 ret = tsocket_simple_int_recv(req, perrno);
615 if (ret == 0) {
616 ret = state->ret;
617 }
618
619 tevent_req_received(req);
620 return ret;
621 }
622
623 struct tstream_writev_state {
624 const struct tstream_context_ops *ops;
625 struct tstream_context *stream;
626 int ret;
627 };
628
tstream_writev_destructor(struct tstream_writev_state * state)629 static int tstream_writev_destructor(struct tstream_writev_state *state)
630 {
631 if (state->stream) {
632 state->stream->writev_req = NULL;
633 }
634
635 return 0;
636 }
637
638 static void tstream_writev_done(struct tevent_req *subreq);
639
tstream_writev_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct tstream_context * stream,const struct iovec * vector,size_t count)640 struct tevent_req *tstream_writev_send(TALLOC_CTX *mem_ctx,
641 struct tevent_context *ev,
642 struct tstream_context *stream,
643 const struct iovec *vector,
644 size_t count)
645 {
646 struct tevent_req *req;
647 struct tstream_writev_state *state;
648 struct tevent_req *subreq;
649 int to_write = 0;
650 size_t i;
651
652 req = tevent_req_create(mem_ctx, &state,
653 struct tstream_writev_state);
654 if (req == NULL) {
655 return NULL;
656 }
657
658 state->ops = stream->ops;
659 state->stream = stream;
660 state->ret = -1;
661
662 /* first check if the input is ok */
663 #ifdef IOV_MAX
664 if (count > IOV_MAX) {
665 tevent_req_error(req, EMSGSIZE);
666 goto post;
667 }
668 #endif
669
670 for (i=0; i < count; i++) {
671 int tmp = to_write;
672 tmp += vector[i].iov_len;
673
674 if (tmp < to_write) {
675 tevent_req_error(req, EMSGSIZE);
676 goto post;
677 }
678
679 to_write = tmp;
680 }
681
682 if (to_write == 0) {
683 tevent_req_error(req, EINVAL);
684 goto post;
685 }
686
687 if (stream->writev_req) {
688 tevent_req_error(req, EBUSY);
689 goto post;
690 }
691 stream->writev_req = req;
692
693 talloc_set_destructor(state, tstream_writev_destructor);
694
695 subreq = state->ops->writev_send(state, ev, stream, vector, count);
696 if (tevent_req_nomem(subreq, req)) {
697 goto post;
698 }
699 tevent_req_set_callback(subreq, tstream_writev_done, req);
700
701 return req;
702
703 post:
704 tevent_req_post(req, ev);
705 return req;
706 }
707
tstream_writev_done(struct tevent_req * subreq)708 static void tstream_writev_done(struct tevent_req *subreq)
709 {
710 struct tevent_req *req = tevent_req_callback_data(subreq,
711 struct tevent_req);
712 struct tstream_writev_state *state = tevent_req_data(req,
713 struct tstream_writev_state);
714 ssize_t ret;
715 int sys_errno;
716
717 ret = state->ops->writev_recv(subreq, &sys_errno);
718 if (ret == -1) {
719 tevent_req_error(req, sys_errno);
720 return;
721 }
722
723 state->ret = ret;
724
725 tevent_req_done(req);
726 }
727
tstream_writev_recv(struct tevent_req * req,int * perrno)728 int tstream_writev_recv(struct tevent_req *req,
729 int *perrno)
730 {
731 struct tstream_writev_state *state = tevent_req_data(req,
732 struct tstream_writev_state);
733 int ret;
734
735 ret = tsocket_simple_int_recv(req, perrno);
736 if (ret == 0) {
737 ret = state->ret;
738 }
739
740 tevent_req_received(req);
741 return ret;
742 }
743
744 struct tstream_disconnect_state {
745 const struct tstream_context_ops *ops;
746 };
747
748 static void tstream_disconnect_done(struct tevent_req *subreq);
749
tstream_disconnect_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct tstream_context * stream)750 struct tevent_req *tstream_disconnect_send(TALLOC_CTX *mem_ctx,
751 struct tevent_context *ev,
752 struct tstream_context *stream)
753 {
754 struct tevent_req *req;
755 struct tstream_disconnect_state *state;
756 struct tevent_req *subreq;
757
758 req = tevent_req_create(mem_ctx, &state,
759 struct tstream_disconnect_state);
760 if (req == NULL) {
761 return NULL;
762 }
763
764 state->ops = stream->ops;
765
766 if (stream->readv_req || stream->writev_req) {
767 tevent_req_error(req, EBUSY);
768 goto post;
769 }
770
771 subreq = state->ops->disconnect_send(state, ev, stream);
772 if (tevent_req_nomem(subreq, req)) {
773 goto post;
774 }
775 tevent_req_set_callback(subreq, tstream_disconnect_done, req);
776
777 return req;
778
779 post:
780 tevent_req_post(req, ev);
781 return req;
782 }
783
tstream_disconnect_done(struct tevent_req * subreq)784 static void tstream_disconnect_done(struct tevent_req *subreq)
785 {
786 struct tevent_req *req = tevent_req_callback_data(subreq,
787 struct tevent_req);
788 struct tstream_disconnect_state *state = tevent_req_data(req,
789 struct tstream_disconnect_state);
790 int ret;
791 int sys_errno;
792
793 ret = state->ops->disconnect_recv(subreq, &sys_errno);
794 if (ret == -1) {
795 tevent_req_error(req, sys_errno);
796 return;
797 }
798
799 tevent_req_done(req);
800 }
801
tstream_disconnect_recv(struct tevent_req * req,int * perrno)802 int tstream_disconnect_recv(struct tevent_req *req,
803 int *perrno)
804 {
805 int ret;
806
807 ret = tsocket_simple_int_recv(req, perrno);
808
809 tevent_req_received(req);
810 return ret;
811 }
812
813