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