2 Unix SMB/CIFS implementation.
4 [MS-RPCH] - RPC over HTTP client
6 Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "lib/events/events.h"
24 #include "lib/util/tevent_ntstatus.h"
25 #include "lib/tls/tls.h"
26 #include "libcli/resolve/resolve.h"
27 #include "libcli/composite/composite.h"
28 #include "auth/credentials/credentials.h"
29 #include "tsocket/tsocket.h"
30 #include "tsocket/tsocket_internal.h"
31 #include "librpc/rpc/dcerpc.h"
32 #include "librpc/rpc/dcerpc_roh.h"
33 #include "librpc/rpc/dcerpc_proto.h"
34 #include "lib/param/param.h"
35 #include "libcli/http/http.h"
36 #include "lib/util/util_net.h"
38 static ssize_t
tstream_roh_pending_bytes(struct tstream_context
*stream
);
39 static struct tevent_req
* tstream_roh_readv_send(
41 struct tevent_context
*ev
,
42 struct tstream_context
*stream
,
45 static int tstream_roh_readv_recv(struct tevent_req
*req
, int *perrno
);
46 static struct tevent_req
* tstream_roh_writev_send(
48 struct tevent_context
*ev
,
49 struct tstream_context
*stream
,
50 const struct iovec
*vector
,
52 static int tstream_roh_writev_recv(struct tevent_req
*req
, int *perrno
);
53 static struct tevent_req
* tstream_roh_disconnect_send(
55 struct tevent_context
*ev
,
56 struct tstream_context
*stream
);
57 static int tstream_roh_disconnect_recv(struct tevent_req
*req
, int *perrno
);
59 static const struct tstream_context_ops tstream_roh_ops
= {
61 .pending_bytes
= tstream_roh_pending_bytes
,
62 .readv_send
= tstream_roh_readv_send
,
63 .readv_recv
= tstream_roh_readv_recv
,
64 .writev_send
= tstream_roh_writev_send
,
65 .writev_recv
= tstream_roh_writev_recv
,
66 .disconnect_send
= tstream_roh_disconnect_send
,
67 .disconnect_recv
= tstream_roh_disconnect_recv
,
70 struct tstream_roh_context
{
71 struct roh_connection
*roh_conn
;
74 struct roh_open_connection_state
{
75 struct tevent_req
*req
;
76 struct tevent_context
*event_ctx
;
77 struct cli_credentials
*credentials
;
78 struct resolve_context
*resolve_ctx
;
79 const char **rpcproxy_addresses
;
80 unsigned int rpcproxy_address_index
;
82 struct dcecli_connection
*conn
;
85 const char *rpc_proxy
;
86 unsigned int rpc_proxy_port
;
87 const char *rpc_server
;
88 unsigned int rpc_server_port
;
89 const char *target_hostname
;
91 struct roh_connection
*roh
;
92 struct tstream_tls_params
*tls_params
;
93 struct loadparm_context
*lp_ctx
;
97 NTSTATUS
dcerpc_pipe_open_roh_recv(struct tevent_req
*req
,
99 struct tstream_context
**stream
,
100 struct tevent_queue
**queue
)
102 struct roh_open_connection_state
*state
;
103 struct tstream_roh_context
*roh_stream_ctx
;
106 state
= tevent_req_data(req
, struct roh_open_connection_state
);
107 if (tevent_req_is_nterror(req
, &status
)) {
108 tevent_req_received(req
);
112 *stream
= tstream_context_create(mem_ctx
, &tstream_roh_ops
,
114 struct tstream_roh_context
,
117 tevent_req_received(req
);
118 return NT_STATUS_NO_MEMORY
;
120 ZERO_STRUCTP(roh_stream_ctx
);
122 roh_stream_ctx
->roh_conn
= talloc_move(mem_ctx
, &state
->roh
);
123 *queue
= http_conn_send_queue(
124 roh_stream_ctx
->roh_conn
->default_channel_in
->http_conn
);
126 tevent_req_received(req
);
131 struct roh_connect_channel_state
{
132 struct roh_channel
*channel
;
135 static void roh_connect_channel_done(struct tevent_req
*subreq
);
136 static struct tevent_req
*roh_connect_channel_send(TALLOC_CTX
*mem_ctx
,
137 struct tevent_context
*ev
,
138 const char *rpcproxy_ip_address
,
139 unsigned int rpcproxy_port
,
140 struct cli_credentials
*credentials
,
142 struct tstream_tls_params
*tls_params
)
144 struct tevent_req
*req
= NULL
;
145 struct tevent_req
*subreq
= NULL
;
146 struct roh_connect_channel_state
*state
= NULL
;
148 DBG_DEBUG("Connecting ROH channel socket, RPC proxy is "
149 "%s:%d (TLS: %s)\n", rpcproxy_ip_address
, rpcproxy_port
,
150 (tls
? "true" : "false"));
152 req
= tevent_req_create(mem_ctx
, &state
,
153 struct roh_connect_channel_state
);
158 if (!is_ipaddress(rpcproxy_ip_address
)) {
159 DBG_ERR("Invalid host (%s), needs to be an IP address\n",
160 rpcproxy_ip_address
);
161 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
162 return tevent_req_post(req
, ev
);
165 /* Initialize channel structure */
166 state
->channel
= talloc_zero(state
, struct roh_channel
);
167 if (tevent_req_nomem(state
->channel
, req
)) {
168 return tevent_req_post(req
, ev
);
171 state
->channel
->channel_cookie
= GUID_random();
173 subreq
= http_connect_send(state
,
178 tls
? tls_params
: NULL
);
179 if (tevent_req_nomem(subreq
, req
)) {
180 return tevent_req_post(req
, ev
);
182 tevent_req_set_callback(subreq
, roh_connect_channel_done
, req
);
187 static void roh_connect_channel_done(struct tevent_req
*subreq
)
189 struct tevent_req
*req
= NULL
;
190 struct roh_connect_channel_state
*state
= NULL
;
194 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
195 state
= tevent_req_data(req
, struct roh_connect_channel_state
);
197 ret
= http_connect_recv(subreq
,
199 &state
->channel
->http_conn
);
202 status
= map_nt_error_from_unix_common(ret
);
203 tevent_req_nterror(req
, status
);
207 DBG_DEBUG("HTTP connected\n");
208 tevent_req_done(req
);
211 static NTSTATUS
roh_connect_channel_recv(struct tevent_req
*req
,
213 struct roh_channel
**channel
)
215 struct roh_connect_channel_state
*state
= tevent_req_data(
216 req
, struct roh_connect_channel_state
);
219 if (tevent_req_is_nterror(req
, &status
)) {
220 tevent_req_received(req
);
224 *channel
= talloc_move(mem_ctx
, &state
->channel
);
225 tevent_req_received(req
);
230 static void roh_continue_resolve_name(struct composite_context
*ctx
);
233 * Send rpc pipe open request to given host:port using http transport
235 struct tevent_req
*dcerpc_pipe_open_roh_send(struct dcecli_connection
*conn
,
236 const char *localaddr
,
237 const char *rpc_server
,
238 uint32_t rpc_server_port
,
239 const char *rpc_proxy
,
240 uint32_t rpc_proxy_port
,
241 const char *http_proxy
,
242 uint32_t http_proxy_port
,
245 struct cli_credentials
*credentials
,
246 struct resolve_context
*resolve_ctx
,
247 struct loadparm_context
*lp_ctx
,
251 struct tevent_req
*req
;
252 struct composite_context
*ctx
;
253 struct roh_open_connection_state
*state
;
254 struct nbt_name name
;
256 req
= tevent_req_create(conn
, &state
, struct roh_open_connection_state
);
261 /* Set state fields */
263 state
->event_ctx
= conn
->event_ctx
;
264 state
->lp_ctx
= lp_ctx
,
265 state
->credentials
= credentials
;
267 state
->tls
= use_tls
;
269 /* Initialize connection structure (3.2.1.3) */
270 /* TODO Initialize virtual connection cookie table */
271 state
->rpc_server
= talloc_strdup(state
, rpc_server
);
272 state
->rpc_server_port
= rpc_server_port
;
273 state
->rpc_proxy
= talloc_strdup(state
, rpc_proxy
);
274 state
->rpc_proxy_port
= rpc_proxy_port
;
275 state
->http_auth
= http_auth
;
277 state
->roh
= talloc_zero(state
, struct roh_connection
);
278 state
->roh
->protocol_version
= ROH_V2
;
279 state
->roh
->connection_state
= ROH_STATE_OPEN_START
;
280 state
->roh
->connection_cookie
= GUID_random();
281 state
->roh
->association_group_id_cookie
= GUID_random();
283 /* Additional initialization steps (3.2.2.3) */
284 state
->roh
->proxy_use
= use_proxy
;
285 state
->roh
->current_keep_alive_time
= 0;
286 state
->roh
->current_keep_alive_interval
= 0;
290 char *ca_file
= lpcfg_tls_cafile(state
, lp_ctx
);
291 char *crl_file
= lpcfg_tls_crlfile(state
, lp_ctx
);
292 const char *tls_priority
= lpcfg_tls_priority(lp_ctx
);
293 enum tls_verify_peer_state verify_peer
=
294 lpcfg_tls_verify_peer(lp_ctx
);
296 status
= tstream_tls_params_client(state
->roh
,
302 if (!NT_STATUS_IS_OK(status
)) {
303 DEBUG(0,("%s: Failed tstream_tls_params_client - %s\n",
304 __func__
, nt_errstr(status
)));
305 tevent_req_nterror(req
, status
);
306 return tevent_req_post(req
, conn
->event_ctx
);
310 /* Resolve RPC proxy server name */
311 make_nbt_name_server(&name
, state
->rpc_proxy
);
312 ctx
= resolve_name_send(resolve_ctx
, state
, &name
, state
->event_ctx
);
313 if (tevent_req_nomem(ctx
, req
)) {
314 return tevent_req_post(req
, state
->event_ctx
);
316 ctx
->async
.fn
= roh_continue_resolve_name
;
317 ctx
->async
.private_data
= state
;
322 static void roh_connect_channel_in_done(struct tevent_req
*subreq
);
323 static void roh_continue_resolve_name(struct composite_context
*ctx
)
326 struct roh_open_connection_state
*state
;
327 struct tevent_req
*subreq
;
329 state
= talloc_get_type_abort(ctx
->async
.private_data
,
330 struct roh_open_connection_state
);
331 status
= resolve_name_multiple_recv(ctx
, state
,
332 &state
->rpcproxy_addresses
);
333 if (tevent_req_nterror(state
->req
, status
)) {
334 DEBUG(2, ("%s: No server found: %s\n", __func__
,
339 state
->rpcproxy_address_index
= 0;
340 if (state
->rpcproxy_addresses
[state
->rpcproxy_address_index
] == NULL
) {
341 DEBUG(2, ("%s: No server found\n", __func__
));
342 tevent_req_nterror(state
->req
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
347 * TODO Determine proxy use
348 * If state->roh->proxy_use == true, the client has requested to
349 * always use local proxy. Otherwise, run the proxy use discovery
351 state
->roh
->connection_state
= ROH_STATE_OPEN_START
;
352 subreq
= roh_connect_channel_send(state
,
354 state
->rpcproxy_addresses
[state
->rpcproxy_address_index
],
355 state
->rpc_proxy_port
,
359 if (tevent_req_nomem(subreq
, state
->req
)) {
362 tevent_req_set_callback(subreq
, roh_connect_channel_in_done
, state
->req
);
365 static void roh_connect_channel_out_done(struct tevent_req
*);
366 static void roh_connect_channel_in_done(struct tevent_req
*subreq
)
369 struct tevent_req
*req
;
370 struct roh_open_connection_state
*state
;
372 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
373 state
= tevent_req_data(req
, struct roh_open_connection_state
);
375 status
= roh_connect_channel_recv(subreq
, state
->roh
,
376 &state
->roh
->default_channel_in
);
378 if (tevent_req_nterror(req
, status
)) {
382 subreq
= roh_connect_channel_send(state
,
384 state
->rpcproxy_addresses
[state
->rpcproxy_address_index
],
385 state
->rpc_proxy_port
,
389 if (tevent_req_nomem(subreq
, req
)) {
392 tevent_req_set_callback(subreq
, roh_connect_channel_out_done
, req
);
395 static void roh_send_RPC_DATA_IN_done(struct tevent_req
*);
396 static void roh_connect_channel_out_done(struct tevent_req
*subreq
)
399 struct tevent_req
*req
;
400 struct roh_open_connection_state
*state
;
402 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
403 state
= tevent_req_data(req
, struct roh_open_connection_state
);
405 status
= roh_connect_channel_recv(subreq
, state
->roh
,
406 &state
->roh
->default_channel_out
);
408 if (tevent_req_nterror(req
, status
)) {
412 subreq
= roh_send_RPC_DATA_IN_send(state
, state
->lp_ctx
,
417 state
->rpc_server_port
,
420 if (tevent_req_nomem(subreq
, req
)) {
423 tevent_req_set_callback(subreq
, roh_send_RPC_DATA_IN_done
, req
);
426 static void roh_send_RPC_DATA_OUT_done(struct tevent_req
*);
427 static void roh_send_RPC_DATA_IN_done(struct tevent_req
*subreq
)
430 struct tevent_req
*req
;
431 struct roh_open_connection_state
*state
;
433 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
434 state
= tevent_req_data(req
, struct roh_open_connection_state
);
436 status
= roh_send_RPC_DATA_IN_recv(subreq
);
438 if (tevent_req_nterror(req
, status
)) {
442 subreq
= roh_send_RPC_DATA_OUT_send(state
,
448 state
->rpc_server_port
,
451 if (tevent_req_nomem(subreq
, req
)) {
454 tevent_req_set_callback(subreq
, roh_send_RPC_DATA_OUT_done
, req
);
457 static void roh_send_CONN_A1_done(struct tevent_req
*);
458 static void roh_send_RPC_DATA_OUT_done(struct tevent_req
*subreq
)
461 struct tevent_req
*req
;
462 struct roh_open_connection_state
*state
;
464 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
465 state
= tevent_req_data(req
, struct roh_open_connection_state
);
467 status
= roh_send_RPC_DATA_OUT_recv(subreq
);
469 if (tevent_req_nterror(req
, status
)) {
473 subreq
= roh_send_CONN_A1_send(state
, state
->event_ctx
, state
->roh
);
474 if (tevent_req_nomem(subreq
, req
)) {
477 tevent_req_set_callback(subreq
, roh_send_CONN_A1_done
, req
);
480 static void roh_send_CONN_B1_done(struct tevent_req
*);
481 static void roh_send_CONN_A1_done(struct tevent_req
*subreq
)
484 struct tevent_req
*req
;
485 struct roh_open_connection_state
*state
;
487 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
488 state
= tevent_req_data(req
, struct roh_open_connection_state
);
490 status
= roh_send_CONN_A1_recv(subreq
);
492 if (tevent_req_nterror(req
, status
)) {
496 subreq
= roh_send_CONN_B1_send(state
, state
->event_ctx
, state
->roh
);
497 if (tevent_req_nomem(subreq
, req
)) {
500 tevent_req_set_callback(subreq
, roh_send_CONN_B1_done
, req
);
503 static void roh_recv_out_channel_response_done(struct tevent_req
*);
504 static void roh_send_CONN_B1_done(struct tevent_req
*subreq
)
507 struct tevent_req
*req
;
508 struct roh_open_connection_state
*state
;
510 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
511 state
= tevent_req_data(req
, struct roh_open_connection_state
);
513 status
= roh_send_CONN_B1_recv(subreq
);
515 if (tevent_req_nterror(req
, status
)) {
519 state
->roh
->connection_state
= ROH_STATE_OUT_CHANNEL_WAIT
;
520 subreq
= roh_recv_out_channel_response_send(state
, state
->event_ctx
,
522 if (tevent_req_nomem(subreq
, req
)) {
525 tevent_req_set_callback(subreq
, roh_recv_out_channel_response_done
, req
);
528 static void roh_recv_CONN_A3_done(struct tevent_req
*);
529 static void roh_recv_out_channel_response_done(struct tevent_req
*subreq
)
533 struct tevent_req
*req
;
534 struct roh_open_connection_state
*state
;
536 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
537 state
= tevent_req_data(req
, struct roh_open_connection_state
);
539 status
= roh_recv_out_channel_response_recv(subreq
, state
, &response
);
541 if (tevent_req_nterror(req
, status
)) {
545 state
->roh
->connection_state
= ROH_STATE_WAIT_A3W
;
546 subreq
= roh_recv_CONN_A3_send(state
, state
->event_ctx
, state
->roh
);
547 if (tevent_req_nomem(subreq
, req
)) {
550 tevent_req_set_callback(subreq
, roh_recv_CONN_A3_done
, req
);
553 static void roh_recv_CONN_C2_done(struct tevent_req
*);
554 static void roh_recv_CONN_A3_done(struct tevent_req
*subreq
)
557 struct tevent_req
*req
;
558 struct roh_open_connection_state
*state
;
560 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
561 state
= tevent_req_data(req
, struct roh_open_connection_state
);
563 status
= roh_recv_CONN_A3_recv(subreq
, &state
->roh
->default_channel_out
->connection_timeout
);
565 if (tevent_req_nterror(req
, status
)) {
569 state
->roh
->connection_state
= ROH_STATE_WAIT_C2
;
570 subreq
= roh_recv_CONN_C2_send(state
, state
->event_ctx
, state
->roh
);
571 if (tevent_req_nomem(subreq
, req
)) {
574 tevent_req_set_callback(subreq
, roh_recv_CONN_C2_done
, req
);
577 static void roh_recv_CONN_C2_done(struct tevent_req
*subreq
)
580 struct tevent_req
*req
;
581 struct roh_open_connection_state
*state
;
582 unsigned int version
;
584 unsigned int timeout
;
586 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
587 state
= tevent_req_data(req
, struct roh_open_connection_state
);
589 status
= roh_recv_CONN_C2_recv(subreq
, &version
, &recv
, &timeout
);
591 if (tevent_req_nterror(req
, status
)) {
594 state
->roh
->connection_state
= ROH_STATE_OPENED
;
596 tevent_req_done(req
);
599 static ssize_t
tstream_roh_pending_bytes(struct tstream_context
*stream
)
601 struct tstream_roh_context
*ctx
= NULL
;
602 struct tstream_context
*tstream
= NULL
;
604 ctx
= tstream_context_data(stream
, struct tstream_roh_context
);
605 if (!ctx
->roh_conn
) {
610 tstream
= http_conn_tstream(
611 ctx
->roh_conn
->default_channel_out
->http_conn
);
612 if (tstream
== NULL
) {
616 return tstream_pending_bytes(tstream
);
619 struct tstream_roh_readv_state
{
620 struct roh_connection
*roh_conn
;
624 static void tstream_roh_readv_handler(struct tevent_req
*subreq
);
625 static struct tevent_req
* tstream_roh_readv_send(TALLOC_CTX
*mem_ctx
,
626 struct tevent_context
*ev
,
627 struct tstream_context
*stream
,
628 struct iovec
*vector
,
631 struct tstream_roh_context
*ctx
= NULL
;
632 struct tstream_roh_readv_state
*state
;
633 struct tevent_req
*req
, *subreq
;
634 struct tstream_context
*channel_stream
= NULL
;
636 req
= tevent_req_create(mem_ctx
, &state
, struct tstream_roh_readv_state
);
641 ctx
= tstream_context_data(stream
, struct tstream_roh_context
);
642 if (!ctx
->roh_conn
) {
643 tevent_req_error(req
, ENOTCONN
);
646 if (!ctx
->roh_conn
->default_channel_out
) {
647 tevent_req_error(req
, ENOTCONN
);
650 channel_stream
= http_conn_tstream(
651 ctx
->roh_conn
->default_channel_out
->http_conn
);
652 if (channel_stream
== NULL
) {
653 tevent_req_error(req
, ENOTCONN
);
657 state
->roh_conn
= ctx
->roh_conn
;
659 subreq
= tstream_readv_send(state
, ev
,
662 if (tevent_req_nomem(subreq
, req
)) {
665 tevent_req_set_callback(subreq
, tstream_roh_readv_handler
, req
);
669 tevent_req_post(req
, ev
);
673 static void tstream_roh_readv_handler(struct tevent_req
*subreq
)
675 struct tevent_req
*req
;
676 struct tstream_roh_readv_state
*state
;
680 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
681 state
= tevent_req_data(req
, struct tstream_roh_readv_state
);
682 ret
= tstream_readv_recv(subreq
, &sys_errno
);
685 tevent_req_error(req
, sys_errno
);
691 tevent_req_done(req
);
694 static int tstream_roh_readv_recv(struct tevent_req
*req
, int *perrno
)
696 struct tstream_roh_readv_state
*state
;
699 state
= tevent_req_data(req
, struct tstream_roh_readv_state
);
700 ret
= tsocket_simple_int_recv(req
, perrno
);
705 tevent_req_received(req
);
709 struct tstream_roh_writev_state
{
710 struct roh_connection
*roh_conn
;
714 static void tstream_roh_writev_handler(struct tevent_req
*subreq
);
715 static struct tevent_req
* tstream_roh_writev_send(TALLOC_CTX
*mem_ctx
,
716 struct tevent_context
*ev
,
717 struct tstream_context
*stream
,
718 const struct iovec
*vector
,
721 struct tstream_roh_context
*ctx
= NULL
;
722 struct tstream_roh_writev_state
*state
= NULL
;
723 struct tevent_req
*req
= NULL
;
724 struct tevent_req
*subreq
= NULL
;
725 struct tstream_context
*channel_stream
= NULL
;
727 req
= tevent_req_create(mem_ctx
, &state
,
728 struct tstream_roh_writev_state
);
733 ctx
= tstream_context_data(stream
, struct tstream_roh_context
);
734 if (!ctx
->roh_conn
) {
735 tevent_req_error(req
, ENOTCONN
);
738 if (!ctx
->roh_conn
->default_channel_in
) {
739 tevent_req_error(req
, ENOTCONN
);
742 channel_stream
= http_conn_tstream(
743 ctx
->roh_conn
->default_channel_in
->http_conn
);
744 if (channel_stream
== NULL
) {
745 tevent_req_error(req
, ENOTCONN
);
749 state
->roh_conn
= ctx
->roh_conn
;
751 subreq
= tstream_writev_send(state
, ev
,
754 if (tevent_req_nomem(subreq
, req
)) {
757 tevent_req_set_callback(subreq
, tstream_roh_writev_handler
, req
);
761 tevent_req_post(req
, ev
);
765 static void tstream_roh_writev_handler(struct tevent_req
*subreq
)
767 struct tevent_req
*req
;
768 struct tstream_roh_writev_state
*state
;
772 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
773 state
= tevent_req_data(req
, struct tstream_roh_writev_state
);
774 nwritten
= tstream_writev_recv(subreq
, &sys_errno
);
776 if (nwritten
== -1) {
777 tevent_req_error(req
, sys_errno
);
780 state
->nwritten
= nwritten
;
781 state
->roh_conn
->default_channel_in
->sent_bytes
+= nwritten
;
783 tevent_req_done(req
);
786 static int tstream_roh_writev_recv(struct tevent_req
*req
, int *perrno
)
788 struct tstream_roh_writev_state
*state
;
791 state
= tevent_req_data(req
, struct tstream_roh_writev_state
);
792 ret
= tsocket_simple_int_recv(req
, perrno
);
794 ret
= state
->nwritten
;
800 struct tstream_roh_disconnect_state
{
801 struct tstream_context
*stream
;
802 struct tevent_context
*ev
;
805 static void tstream_roh_disconnect_channel_in_handler(struct tevent_req
*subreq
);
806 static struct tevent_req
* tstream_roh_disconnect_send(TALLOC_CTX
*mem_ctx
,
807 struct tevent_context
*ev
,
808 struct tstream_context
*stream
)
810 struct tstream_roh_context
*ctx
= NULL
;
811 struct tevent_req
*req
, *subreq
;
812 struct tstream_roh_disconnect_state
*state
;
814 req
= tevent_req_create(mem_ctx
, &state
, struct tstream_roh_disconnect_state
);
819 state
->stream
= stream
;
822 ctx
= tstream_context_data(stream
, struct tstream_roh_context
);
823 if (!ctx
->roh_conn
) {
824 tevent_req_error(req
, ENOTCONN
);
827 if (!ctx
->roh_conn
->default_channel_in
) {
828 tevent_req_error(req
, ENOTCONN
);
832 subreq
= http_disconnect_send(
835 ctx
->roh_conn
->default_channel_in
->http_conn
);
836 if (tevent_req_nomem(subreq
, req
)) {
839 tevent_req_set_callback(subreq
, tstream_roh_disconnect_channel_in_handler
, req
);
843 tevent_req_post(req
, ev
);
847 static void tstream_roh_disconnect_channel_out_handler(struct tevent_req
*subreq
);
849 static void tstream_roh_disconnect_channel_in_handler(struct tevent_req
*subreq
)
851 struct tevent_req
*req
;
852 struct tstream_roh_disconnect_state
*state
;
853 struct tstream_context
*stream
;
854 struct tstream_roh_context
*roh_stream
;
857 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
858 state
= tevent_req_data(req
, struct tstream_roh_disconnect_state
);
859 stream
= state
->stream
;
860 roh_stream
= tstream_context_data(stream
, struct tstream_roh_context
);
862 ret
= http_disconnect_recv(subreq
);
865 tevent_req_error(req
, ret
);
868 TALLOC_FREE(roh_stream
->roh_conn
->default_channel_in
);
870 subreq
= http_disconnect_send(
873 roh_stream
->roh_conn
->default_channel_out
->http_conn
);
874 if (tevent_req_nomem(subreq
, req
)) {
877 tevent_req_set_callback(subreq
, tstream_roh_disconnect_channel_out_handler
, req
);
882 static void tstream_roh_disconnect_channel_out_handler(struct tevent_req
*subreq
)
884 struct tevent_req
*req
;
885 struct tstream_roh_disconnect_state
*state
;
886 struct tstream_context
*stream
;
887 struct tstream_roh_context
*roh_stream
;
890 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
891 state
= tevent_req_data(req
, struct tstream_roh_disconnect_state
);
892 stream
= state
->stream
;
893 roh_stream
= tstream_context_data(stream
, struct tstream_roh_context
);
895 ret
= http_disconnect_recv(subreq
);
898 tevent_req_error(req
, ret
);
901 TALLOC_FREE(roh_stream
->roh_conn
->default_channel_out
);
903 tevent_req_done(req
);
906 static int tstream_roh_disconnect_recv(struct tevent_req
*req
, int *perrno
)
910 ret
= tsocket_simple_int_recv(req
, perrno
);
911 tevent_req_received(req
);