s3-libnet: avoid using lp_dns_hostname() in join code
[samba.git] / libcli / tstream_binding_handle / tstream_binding_handle.c
blob672fd3b89c680d4bfb91a1d22e3f71d2f7d46d17
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Ralph Boehme 2016
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include <tevent.h>
22 #include "libcli/tstream_binding_handle/tstream_binding_handle.h"
23 #include "system/filesys.h"
24 #include "lib/util/tevent_ntstatus.h"
25 #include "lib/tsocket/tsocket.h"
26 #include "lib/util/debug.h"
27 #include "lib/util/tevent_ntstatus.h"
28 #include "libcli/smb/tstream_smbXcli_np.h"
30 struct tstream_bh_state {
31 struct tstream_context *stream;
32 struct tevent_queue *write_queue;
33 const struct ndr_interface_table *table;
34 uint32_t request_timeout;
35 size_t call_initial_read_size;
36 tstream_read_pdu_blob_full_fn_t *complete_pdu_fn;
37 void *complete_pdu_fn_private;
38 const struct dcerpc_binding *binding;
41 static const struct dcerpc_binding *tstream_bh_get_binding(struct dcerpc_binding_handle *h)
43 struct tstream_bh_state *hs = dcerpc_binding_handle_data(
44 h, struct tstream_bh_state);
46 return hs->binding;
49 static bool tstream_bh_is_connected(struct dcerpc_binding_handle *h)
51 struct tstream_bh_state *hs = dcerpc_binding_handle_data(
52 h, struct tstream_bh_state);
53 ssize_t ret;
55 if (hs->stream == NULL) {
56 return false;
59 ret = tstream_pending_bytes(hs->stream);
60 if (ret == -1) {
61 return false;
64 return true;
67 static uint32_t tstream_bh_set_timeout(struct dcerpc_binding_handle *h,
68 uint32_t timeout)
70 struct tstream_bh_state *hs = dcerpc_binding_handle_data(
71 h, struct tstream_bh_state);
72 uint32_t old;
74 old = hs->request_timeout;
75 hs->request_timeout = timeout;
77 return old;
80 struct tstream_bh_disconnect_state {
81 struct tstream_bh_state *hs;
84 static void tstream_bh_disconnect_done(struct tevent_req *subreq);
86 static struct tevent_req *tstream_bh_disconnect_send(
87 TALLOC_CTX *mem_ctx,
88 struct tevent_context *ev,
89 struct dcerpc_binding_handle *h)
91 struct tstream_bh_state *hs = dcerpc_binding_handle_data(
92 h, struct tstream_bh_state);
93 struct tevent_req *req = NULL;
94 struct tstream_bh_disconnect_state *state = NULL;
95 struct tevent_req *subreq = NULL;
96 bool ok;
98 req = tevent_req_create(mem_ctx, &state,
99 struct tstream_bh_disconnect_state);
100 if (req == NULL) {
101 return NULL;
104 state->hs = hs;
106 ok = tstream_bh_is_connected(h);
107 if (!ok) {
108 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
109 return tevent_req_post(req, ev);
112 subreq = tstream_disconnect_send(state, ev, hs->stream);
113 if (tevent_req_nomem(subreq, req)) {
114 tevent_req_post(req, ev);
115 return req;
117 tevent_req_set_callback(subreq, tstream_bh_disconnect_done, req);
119 return req;
122 static void tstream_bh_disconnect_done(struct tevent_req *subreq)
124 struct tevent_req *req = tevent_req_callback_data(
125 subreq, struct tevent_req);
126 struct tstream_bh_disconnect_state *state = tevent_req_data(
127 req, struct tstream_bh_disconnect_state);
128 int ret, err;
130 ret = tstream_disconnect_recv(subreq, &err);
131 TALLOC_FREE(subreq);
132 if (ret != 0) {
133 DBG_ERR("tstream_bh_disconnect failed [%s]\n", strerror(err));
134 tevent_req_nterror(req, map_nt_error_from_unix_common(err));
135 return;
138 state->hs->stream = NULL;
141 static NTSTATUS tstream_bh_disconnect_recv(struct tevent_req *req)
143 NTSTATUS status;
145 if (tevent_req_is_nterror(req, &status)) {
146 tevent_req_received(req);
147 return status;
150 tevent_req_received(req);
151 return NT_STATUS_OK;
154 struct tstream_bh_call_state {
155 struct tevent_context *ev;
156 struct tstream_context *stream;
157 struct tstream_bh_state *hs;
158 struct iovec out_data;
159 DATA_BLOB in_data;
162 static void tstream_bh_call_writev_done(struct tevent_req *subreq);
163 static void tstream_bh_call_read_pdu_done(struct tevent_req *subreq);
165 static struct tevent_req *tstream_bh_call_send(TALLOC_CTX *mem_ctx,
166 struct tevent_context *ev,
167 struct dcerpc_binding_handle *h,
168 const struct GUID *object,
169 uint32_t opnum,
170 uint32_t in_flags,
171 const uint8_t *out_data,
172 size_t out_length)
174 struct tstream_bh_state *hs = dcerpc_binding_handle_data(
175 h, struct tstream_bh_state);
176 struct tevent_req *req = NULL;
177 struct tevent_req *subreq = NULL;
178 struct tstream_bh_call_state* state = NULL;
179 struct timeval timeout;
180 bool ok;
182 req = tevent_req_create(mem_ctx, &state,
183 struct tstream_bh_call_state);
184 if (req == NULL) {
185 return NULL;
188 *state = (struct tstream_bh_call_state) {
189 .ev = ev,
190 .stream = hs->stream,
191 .hs = hs,
192 .out_data = {
193 .iov_base = discard_const_p(uint8_t, out_data),
194 .iov_len = out_length,
198 ok = tstream_bh_is_connected(h);
199 if (!ok) {
200 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
201 return tevent_req_post(req, ev);
204 if (tstream_is_smbXcli_np(hs->stream)) {
205 tstream_smbXcli_np_use_trans(hs->stream);
207 if (tevent_queue_length(hs->write_queue) > 0) {
208 tevent_req_nterror(req, NT_STATUS_PIPE_BUSY);
211 timeout = timeval_current_ofs(hs->request_timeout, 0);
213 subreq = tstream_writev_queue_send(state, ev,
214 state->stream,
215 hs->write_queue,
216 &state->out_data, 1);
217 if (tevent_req_nomem(subreq, req)) {
218 return tevent_req_post(req, ev);
220 if (!tevent_req_set_endtime(subreq, ev, timeout)) {
221 return tevent_req_post(req, ev);
223 tevent_req_set_callback(subreq, tstream_bh_call_writev_done, req);
225 subreq = tstream_read_pdu_blob_send(state,
227 hs->stream,
228 hs->call_initial_read_size,
229 hs->complete_pdu_fn,
230 hs->complete_pdu_fn_private);
231 if (tevent_req_nomem(subreq, req)) {
232 return tevent_req_post(req, ev);
234 if (!tevent_req_set_endtime(subreq, ev, timeout)) {
235 return tevent_req_post(req, ev);
237 tevent_req_set_callback(subreq, tstream_bh_call_read_pdu_done, req);
239 return req;
242 static void tstream_bh_call_writev_done(struct tevent_req *subreq)
244 struct tevent_req *req = tevent_req_callback_data(
245 subreq, struct tevent_req);
246 struct tstream_bh_call_state *state = tevent_req_data(
247 req, struct tstream_bh_call_state);
248 int ret, err;
250 ret = tstream_writev_queue_recv(subreq, &err);
251 TALLOC_FREE(subreq);
252 if (ret == -1) {
253 state->hs->stream = NULL;
254 tevent_req_nterror(req, map_nt_error_from_unix_common(err));
255 return;
259 static void tstream_bh_call_read_pdu_done(struct tevent_req *subreq)
261 struct tevent_req *req = tevent_req_callback_data(
262 subreq, struct tevent_req);
263 struct tstream_bh_call_state *state = tevent_req_data(
264 req, struct tstream_bh_call_state);
265 NTSTATUS status;
267 status = tstream_read_pdu_blob_recv(subreq, state, &state->in_data);
268 TALLOC_FREE(subreq);
269 if (!NT_STATUS_IS_OK(status)) {
270 state->hs->stream = NULL;
271 tevent_req_nterror(req, status);
272 return;
275 tevent_req_done(req);
278 static NTSTATUS tstream_bh_call_recv(struct tevent_req *req,
279 TALLOC_CTX *mem_ctx,
280 uint8_t **in_data,
281 size_t *in_length,
282 uint32_t *in_flags)
284 NTSTATUS status;
285 struct tstream_bh_call_state *state = tevent_req_data(
286 req, struct tstream_bh_call_state);
288 if (tevent_req_is_nterror(req, &status)) {
289 tevent_req_received(req);
290 return status;
293 *in_data = talloc_move(mem_ctx, &state->in_data.data);
294 *in_length = state->in_data.length;
296 tevent_req_received(req);
297 return NT_STATUS_OK;
300 static const struct dcerpc_binding_handle_ops tstream_bh_ops = {
301 .name = "tstream_binding_handle",
302 .get_binding = tstream_bh_get_binding,
303 .is_connected = tstream_bh_is_connected,
304 .set_timeout = tstream_bh_set_timeout,
305 .raw_call_send = tstream_bh_call_send,
306 .raw_call_recv = tstream_bh_call_recv,
307 .disconnect_send = tstream_bh_disconnect_send,
308 .disconnect_recv = tstream_bh_disconnect_recv,
311 struct dcerpc_binding_handle *tstream_binding_handle_create(
312 TALLOC_CTX *mem_ctx,
313 const struct ndr_interface_table *table,
314 struct tstream_context **stream,
315 size_t call_initial_read_size,
316 tstream_read_pdu_blob_full_fn_t *complete_pdu_fn,
317 void *complete_pdu_fn_private,
318 uint32_t max_data)
320 struct dcerpc_binding_handle *h = NULL;
321 struct tstream_bh_state *hs = NULL;
322 struct dcerpc_binding *b = NULL;
323 NTSTATUS status;
325 h = dcerpc_binding_handle_create(mem_ctx,
326 &tstream_bh_ops,
327 NULL,
328 table,
329 &hs,
330 struct tstream_bh_state,
331 __location__);
332 if (h == NULL) {
333 return NULL;
336 hs->table = table;
337 hs->stream = talloc_move(hs, stream);
338 hs->call_initial_read_size = call_initial_read_size;
339 hs->complete_pdu_fn = complete_pdu_fn;
340 hs->complete_pdu_fn_private = complete_pdu_fn_private;
342 hs->write_queue = tevent_queue_create(hs, "write_queue");
343 if (hs->write_queue == NULL) {
344 TALLOC_FREE(h);
345 return NULL;
348 status = dcerpc_parse_binding(hs, "", &b);
349 if (!NT_STATUS_IS_OK(status)) {
350 TALLOC_FREE(h);
351 return NULL;
353 hs->binding = b;
355 if (max_data > 0) {
356 tstream_smbXcli_np_set_max_data(hs->stream, max_data);
359 return h;