2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2010
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/>.
21 #include "system/network.h"
22 #include "libsmb/libsmb.h"
23 #include "libsmb/smb2cli.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "../lib/tsocket/tsocket.h"
26 #include "../lib/tsocket/tsocket_internal.h"
27 #include "cli_np_tstream.h"
29 static const struct tstream_context_ops tstream_cli_np_ops;
32 * Windows uses 4280 (the max xmit/recv size negotiated on DCERPC).
33 * This is fits into the max_xmit negotiated at the SMB layer.
35 * On the sending side they may use SMBtranss if the request does not
36 * fit into a single SMBtrans call.
38 * Windows uses 1024 as max data size of a SMBtrans request and then
39 * possibly reads the rest of the DCERPC fragment (up to 3256 bytes)
42 * For now we just ask for the full 4280 bytes (max data size) in the SMBtrans
43 * request to get the whole fragment at once (like samba 3.5.x and below did.
45 * It is important that we use do SMBwriteX with the size of a full fragment,
46 * otherwise we may get NT_STATUS_PIPE_BUSY on the SMBtrans request
47 * from NT4 servers. (See bug #8195)
49 #define TSTREAM_CLI_NP_MAX_BUF_SIZE 4280
51 struct tstream_cli_np {
52 struct cli_state *cli;
56 uint64_t fid_persistent;
57 uint64_t fid_volatile;
58 unsigned int default_timeout;
62 struct tevent_req *read_req;
63 struct tevent_req *write_req;
74 static int tstream_cli_np_destructor(struct tstream_cli_np *cli_nps)
78 if (!cli_state_is_connected(cli_nps->cli)) {
83 * TODO: do not use a sync call with a destructor!!!
85 * This only happens, if a caller does talloc_free(),
86 * while the everything was still ok.
88 * If we get an unexpected failure within a normal
89 * operation, we already do an async cli_close_send()/_recv().
91 * Once we've fixed all callers to call
92 * tstream_disconnect_send()/_recv(), this will
95 if (cli_nps->is_smb1) {
96 status = cli_close(cli_nps->cli, cli_nps->fnum);
98 status = smb2cli_close(cli_nps->cli, 0,
99 cli_nps->fid_persistent,
100 cli_nps->fid_volatile);
102 if (!NT_STATUS_IS_OK(status)) {
103 DEBUG(1, ("tstream_cli_np_destructor: cli_close "
104 "failed on pipe %s. Error was %s\n",
105 cli_nps->npipe, nt_errstr(status)));
108 * We can't do much on failure
113 struct tstream_cli_np_open_state {
114 struct cli_state *cli;
117 uint64_t fid_persistent;
118 uint64_t fid_volatile;
122 static void tstream_cli_np_open_done(struct tevent_req *subreq);
124 struct tevent_req *tstream_cli_np_open_send(TALLOC_CTX *mem_ctx,
125 struct tevent_context *ev,
126 struct cli_state *cli,
129 struct tevent_req *req;
130 struct tstream_cli_np_open_state *state;
131 struct tevent_req *subreq;
133 req = tevent_req_create(mem_ctx, &state,
134 struct tstream_cli_np_open_state);
140 state->npipe = talloc_strdup(state, npipe);
141 if (tevent_req_nomem(state->npipe, req)) {
142 return tevent_req_post(req, ev);
145 if (cli_state_protocol(cli) < PROTOCOL_SMB2_02) {
146 state->is_smb1 = true;
149 if (state->is_smb1) {
150 subreq = cli_ntcreate_send(state, ev, cli,
155 FILE_SHARE_READ|FILE_SHARE_WRITE,
160 subreq = smb2cli_create_send(state, ev, cli,
162 SMB2_OPLOCK_LEVEL_NONE,
163 SMB2_IMPERSONATION_IMPERSONATION,
165 0, /* file_attributes */
166 FILE_SHARE_READ|FILE_SHARE_WRITE,
168 0, /* create_options */
171 if (tevent_req_nomem(subreq, req)) {
172 return tevent_req_post(req, ev);
174 tevent_req_set_callback(subreq, tstream_cli_np_open_done, req);
179 static void tstream_cli_np_open_done(struct tevent_req *subreq)
181 struct tevent_req *req =
182 tevent_req_callback_data(subreq, struct tevent_req);
183 struct tstream_cli_np_open_state *state =
184 tevent_req_data(req, struct tstream_cli_np_open_state);
187 if (state->is_smb1) {
188 status = cli_ntcreate_recv(subreq, &state->fnum);
190 status = smb2cli_create_recv(subreq,
191 &state->fid_persistent,
192 &state->fid_volatile);
195 if (!NT_STATUS_IS_OK(status)) {
196 tevent_req_nterror(req, status);
200 tevent_req_done(req);
203 NTSTATUS _tstream_cli_np_open_recv(struct tevent_req *req,
205 struct tstream_context **_stream,
206 const char *location)
208 struct tstream_cli_np_open_state *state =
209 tevent_req_data(req, struct tstream_cli_np_open_state);
210 struct tstream_context *stream;
211 struct tstream_cli_np *cli_nps;
214 if (tevent_req_is_nterror(req, &status)) {
215 tevent_req_received(req);
219 stream = tstream_context_create(mem_ctx,
222 struct tstream_cli_np,
225 tevent_req_received(req);
226 return NT_STATUS_NO_MEMORY;
228 ZERO_STRUCTP(cli_nps);
230 cli_nps->cli = state->cli;
231 cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
232 cli_nps->is_smb1 = state->is_smb1;
233 cli_nps->fnum = state->fnum;
234 cli_nps->fid_persistent = state->fid_persistent;
235 cli_nps->fid_volatile = state->fid_volatile;
236 cli_nps->default_timeout = cli_set_timeout(state->cli, 0);
237 cli_set_timeout(state->cli, cli_nps->default_timeout);
239 talloc_set_destructor(cli_nps, tstream_cli_np_destructor);
241 cli_nps->trans.active = false;
242 cli_nps->trans.read_req = NULL;
243 cli_nps->trans.write_req = NULL;
244 SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
245 SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
248 tevent_req_received(req);
252 static ssize_t tstream_cli_np_pending_bytes(struct tstream_context *stream)
254 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
255 struct tstream_cli_np);
257 if (!cli_state_is_connected(cli_nps->cli)) {
262 return cli_nps->read.left;
265 bool tstream_is_cli_np(struct tstream_context *stream)
267 struct tstream_cli_np *cli_nps =
268 talloc_get_type(_tstream_context_data(stream),
269 struct tstream_cli_np);
278 NTSTATUS tstream_cli_np_use_trans(struct tstream_context *stream)
280 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
281 struct tstream_cli_np);
283 if (cli_nps->trans.read_req) {
284 return NT_STATUS_PIPE_BUSY;
287 if (cli_nps->trans.write_req) {
288 return NT_STATUS_PIPE_BUSY;
291 if (cli_nps->trans.active) {
292 return NT_STATUS_PIPE_BUSY;
295 cli_nps->trans.active = true;
300 unsigned int tstream_cli_np_set_timeout(struct tstream_context *stream,
301 unsigned int timeout)
303 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
304 struct tstream_cli_np);
306 if (!cli_state_is_connected(cli_nps->cli)) {
307 return cli_nps->default_timeout;
310 return cli_set_timeout(cli_nps->cli, timeout);
313 struct cli_state *tstream_cli_np_get_cli_state(struct tstream_context *stream)
315 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
316 struct tstream_cli_np);
321 struct tstream_cli_np_writev_state {
322 struct tstream_context *stream;
323 struct tevent_context *ev;
325 struct iovec *vector;
332 const char *location;
336 static int tstream_cli_np_writev_state_destructor(struct tstream_cli_np_writev_state *state)
338 struct tstream_cli_np *cli_nps =
339 tstream_context_data(state->stream,
340 struct tstream_cli_np);
342 cli_nps->trans.write_req = NULL;
347 static void tstream_cli_np_writev_write_next(struct tevent_req *req);
349 static struct tevent_req *tstream_cli_np_writev_send(TALLOC_CTX *mem_ctx,
350 struct tevent_context *ev,
351 struct tstream_context *stream,
352 const struct iovec *vector,
355 struct tevent_req *req;
356 struct tstream_cli_np_writev_state *state;
357 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
358 struct tstream_cli_np);
360 req = tevent_req_create(mem_ctx, &state,
361 struct tstream_cli_np_writev_state);
365 state->stream = stream;
369 talloc_set_destructor(state, tstream_cli_np_writev_state_destructor);
371 if (!cli_state_is_connected(cli_nps->cli)) {
372 tevent_req_error(req, ENOTCONN);
373 return tevent_req_post(req, ev);
377 * we make a copy of the vector so we can change the structure
379 state->vector = talloc_array(state, struct iovec, count);
380 if (tevent_req_nomem(state->vector, req)) {
381 return tevent_req_post(req, ev);
383 memcpy(state->vector, vector, sizeof(struct iovec) * count);
384 state->count = count;
386 tstream_cli_np_writev_write_next(req);
387 if (!tevent_req_is_in_progress(req)) {
388 return tevent_req_post(req, ev);
394 static void tstream_cli_np_readv_trans_start(struct tevent_req *req);
395 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq);
397 static void tstream_cli_np_writev_write_next(struct tevent_req *req)
399 struct tstream_cli_np_writev_state *state =
401 struct tstream_cli_np_writev_state);
402 struct tstream_cli_np *cli_nps =
403 tstream_context_data(state->stream,
404 struct tstream_cli_np);
405 struct tevent_req *subreq;
409 for (i=0; i < state->count; i++) {
410 left += state->vector[i].iov_len;
414 TALLOC_FREE(cli_nps->write.buf);
415 tevent_req_done(req);
419 cli_nps->write.ofs = 0;
420 cli_nps->write.left = MIN(left, TSTREAM_CLI_NP_MAX_BUF_SIZE);
421 cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
422 uint8_t, cli_nps->write.left);
423 if (tevent_req_nomem(cli_nps->write.buf, req)) {
428 * copy the pending buffer first
430 while (cli_nps->write.left > 0 && state->count > 0) {
431 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
432 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
434 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
437 state->vector[0].iov_base = base;
438 state->vector[0].iov_len -= len;
440 cli_nps->write.ofs += len;
441 cli_nps->write.left -= len;
443 if (state->vector[0].iov_len == 0) {
451 if (cli_nps->trans.active && state->count == 0) {
452 cli_nps->trans.active = false;
453 cli_nps->trans.write_req = req;
457 if (cli_nps->trans.read_req && state->count == 0) {
458 cli_nps->trans.write_req = req;
459 tstream_cli_np_readv_trans_start(cli_nps->trans.read_req);
463 if (cli_nps->is_smb1) {
464 subreq = cli_write_andx_send(state, state->ev, cli_nps->cli,
466 8, /* 8 means message mode. */
469 cli_nps->write.ofs); /* size */
471 subreq = smb2cli_write_send(state, state->ev, cli_nps->cli,
472 cli_nps->write.ofs, /* length */
474 cli_nps->fid_persistent,
475 cli_nps->fid_volatile,
476 0, /* remaining_bytes */
480 if (tevent_req_nomem(subreq, req)) {
483 tevent_req_set_callback(subreq,
484 tstream_cli_np_writev_write_done,
488 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
490 const char *location);
492 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq)
494 struct tevent_req *req =
495 tevent_req_callback_data(subreq, struct tevent_req);
496 struct tstream_cli_np_writev_state *state =
497 tevent_req_data(req, struct tstream_cli_np_writev_state);
498 struct tstream_cli_np *cli_nps =
499 tstream_context_data(state->stream,
500 struct tstream_cli_np);
504 if (cli_nps->is_smb1) {
505 status = cli_write_andx_recv(subreq, &written);
507 status = smb2cli_write_recv(subreq);
508 written = cli_nps->write.ofs; // TODO: get the value from the server
511 if (!NT_STATUS_IS_OK(status)) {
512 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
516 if (written != cli_nps->write.ofs) {
517 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
521 tstream_cli_np_writev_write_next(req);
524 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq);
526 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
528 const char *location)
530 struct tstream_cli_np_writev_state *state =
532 struct tstream_cli_np_writev_state);
533 struct tstream_cli_np *cli_nps =
534 tstream_context_data(state->stream,
535 struct tstream_cli_np);
536 struct tevent_req *subreq;
538 state->error.val = error;
539 state->error.location = location;
541 if (!cli_state_is_connected(cli_nps->cli)) {
542 /* return the original error */
543 _tevent_req_error(req, state->error.val, state->error.location);
547 if (cli_nps->is_smb1) {
548 subreq = cli_close_send(state, state->ev, cli_nps->cli,
551 subreq = smb2cli_close_send(state, state->ev, cli_nps->cli,
553 cli_nps->fid_persistent,
554 cli_nps->fid_volatile);
556 if (subreq == NULL) {
557 /* return the original error */
558 _tevent_req_error(req, state->error.val, state->error.location);
561 tevent_req_set_callback(subreq,
562 tstream_cli_np_writev_disconnect_done,
566 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq)
568 struct tevent_req *req =
569 tevent_req_callback_data(subreq, struct tevent_req);
570 struct tstream_cli_np_writev_state *state =
571 tevent_req_data(req, struct tstream_cli_np_writev_state);
572 struct tstream_cli_np *cli_nps =
573 tstream_context_data(state->stream, struct tstream_cli_np);
575 if (cli_nps->is_smb1) {
576 cli_close_recv(subreq);
578 smb2cli_close_recv(subreq);
584 /* return the original error */
585 _tevent_req_error(req, state->error.val, state->error.location);
588 static int tstream_cli_np_writev_recv(struct tevent_req *req,
591 struct tstream_cli_np_writev_state *state =
593 struct tstream_cli_np_writev_state);
596 ret = tsocket_simple_int_recv(req, perrno);
601 tevent_req_received(req);
605 struct tstream_cli_np_readv_state {
606 struct tstream_context *stream;
607 struct tevent_context *ev;
609 struct iovec *vector;
615 struct tevent_immediate *im;
620 const char *location;
624 static int tstream_cli_np_readv_state_destructor(struct tstream_cli_np_readv_state *state)
626 struct tstream_cli_np *cli_nps =
627 tstream_context_data(state->stream,
628 struct tstream_cli_np);
630 cli_nps->trans.read_req = NULL;
635 static void tstream_cli_np_readv_read_next(struct tevent_req *req);
637 static struct tevent_req *tstream_cli_np_readv_send(TALLOC_CTX *mem_ctx,
638 struct tevent_context *ev,
639 struct tstream_context *stream,
640 struct iovec *vector,
643 struct tevent_req *req;
644 struct tstream_cli_np_readv_state *state;
645 struct tstream_cli_np *cli_nps =
646 tstream_context_data(stream, struct tstream_cli_np);
648 req = tevent_req_create(mem_ctx, &state,
649 struct tstream_cli_np_readv_state);
653 state->stream = stream;
657 talloc_set_destructor(state, tstream_cli_np_readv_state_destructor);
659 if (!cli_state_is_connected(cli_nps->cli)) {
660 tevent_req_error(req, ENOTCONN);
661 return tevent_req_post(req, ev);
665 * we make a copy of the vector so we can change the structure
667 state->vector = talloc_array(state, struct iovec, count);
668 if (tevent_req_nomem(state->vector, req)) {
669 return tevent_req_post(req, ev);
671 memcpy(state->vector, vector, sizeof(struct iovec) * count);
672 state->count = count;
674 tstream_cli_np_readv_read_next(req);
675 if (!tevent_req_is_in_progress(req)) {
676 return tevent_req_post(req, ev);
682 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq);
684 static void tstream_cli_np_readv_read_next(struct tevent_req *req)
686 struct tstream_cli_np_readv_state *state =
688 struct tstream_cli_np_readv_state);
689 struct tstream_cli_np *cli_nps =
690 tstream_context_data(state->stream,
691 struct tstream_cli_np);
692 struct tevent_req *subreq;
695 * copy the pending buffer first
697 while (cli_nps->read.left > 0 && state->count > 0) {
698 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
699 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
701 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
704 state->vector[0].iov_base = base;
705 state->vector[0].iov_len -= len;
707 cli_nps->read.ofs += len;
708 cli_nps->read.left -= len;
710 if (state->vector[0].iov_len == 0) {
718 if (cli_nps->read.left == 0) {
719 TALLOC_FREE(cli_nps->read.buf);
722 if (state->count == 0) {
723 tevent_req_done(req);
727 if (cli_nps->trans.active) {
728 cli_nps->trans.active = false;
729 cli_nps->trans.read_req = req;
733 if (cli_nps->trans.write_req) {
734 cli_nps->trans.read_req = req;
735 tstream_cli_np_readv_trans_start(req);
739 if (cli_nps->is_smb1) {
740 subreq = cli_read_andx_send(state, state->ev, cli_nps->cli,
743 TSTREAM_CLI_NP_MAX_BUF_SIZE);
745 subreq = smb2cli_read_send(state, state->ev,
747 cli_nps->cli->timeout,
748 cli_nps->cli->smb2.session,
749 cli_nps->cli->smb2.tid,
750 TSTREAM_CLI_NP_MAX_BUF_SIZE, /* length */
752 cli_nps->fid_persistent,
753 cli_nps->fid_volatile,
754 0, /* minimum_count */
755 0); /* remaining_bytes */
757 if (tevent_req_nomem(subreq, req)) {
760 tevent_req_set_callback(subreq,
761 tstream_cli_np_readv_read_done,
765 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq);
767 static void tstream_cli_np_readv_trans_start(struct tevent_req *req)
769 struct tstream_cli_np_readv_state *state =
771 struct tstream_cli_np_readv_state);
772 struct tstream_cli_np *cli_nps =
773 tstream_context_data(state->stream,
774 struct tstream_cli_np);
775 struct tevent_req *subreq;
777 state->trans.im = tevent_create_immediate(state);
778 if (tevent_req_nomem(state->trans.im, req)) {
782 if (cli_nps->is_smb1) {
783 subreq = cli_trans_send(state, state->ev,
788 cli_nps->trans.setup, 2,
793 TSTREAM_CLI_NP_MAX_BUF_SIZE);
795 DATA_BLOB in_input_buffer = data_blob_null;
796 DATA_BLOB in_output_buffer = data_blob_null;
798 in_input_buffer = data_blob_const(cli_nps->write.buf,
801 subreq = smb2cli_ioctl_send(state, state->ev,
803 cli_nps->fid_persistent,
804 cli_nps->fid_volatile,
805 FSCTL_NAMED_PIPE_READ_WRITE,
806 0, /* in_max_input_length */
808 /* in_max_output_length */
809 TSTREAM_CLI_NP_MAX_BUF_SIZE,
811 SMB2_IOCTL_FLAG_IS_FSCTL);
813 if (tevent_req_nomem(subreq, req)) {
816 tevent_req_set_callback(subreq,
817 tstream_cli_np_readv_trans_done,
821 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
823 const char *location);
824 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
825 struct tevent_immediate *im,
828 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq)
830 struct tevent_req *req =
831 tevent_req_callback_data(subreq, struct tevent_req);
832 struct tstream_cli_np_readv_state *state =
833 tevent_req_data(req, struct tstream_cli_np_readv_state);
834 struct tstream_cli_np *cli_nps =
835 tstream_context_data(state->stream, struct tstream_cli_np);
840 if (cli_nps->is_smb1) {
841 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
843 &rcvbuf, 0, &received);
845 DATA_BLOB out_input_buffer = data_blob_null;
846 DATA_BLOB out_output_buffer = data_blob_null;
848 status = smb2cli_ioctl_recv(subreq, state,
852 /* Note that rcvbuf is not a talloc pointer here */
853 rcvbuf = out_output_buffer.data;
854 received = out_output_buffer.length;
857 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
858 status = NT_STATUS_OK;
860 if (!NT_STATUS_IS_OK(status)) {
861 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
865 if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) {
866 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
871 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
875 cli_nps->read.ofs = 0;
876 cli_nps->read.left = received;
877 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
878 if (cli_nps->read.buf == NULL) {
880 tevent_req_nomem(cli_nps->read.buf, req);
883 memcpy(cli_nps->read.buf, rcvbuf, received);
885 if (cli_nps->trans.write_req == NULL) {
886 tstream_cli_np_readv_read_next(req);
890 tevent_schedule_immediate(state->trans.im, state->ev,
891 tstream_cli_np_readv_trans_next, req);
893 tevent_req_done(cli_nps->trans.write_req);
896 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
897 struct tevent_immediate *im,
900 struct tevent_req *req =
901 talloc_get_type_abort(private_data,
904 tstream_cli_np_readv_read_next(req);
907 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq)
909 struct tevent_req *req =
910 tevent_req_callback_data(subreq, struct tevent_req);
911 struct tstream_cli_np_readv_state *state =
912 tevent_req_data(req, struct tstream_cli_np_readv_state);
913 struct tstream_cli_np *cli_nps =
914 tstream_context_data(state->stream, struct tstream_cli_np);
920 * We must free subreq in this function as there is
921 * a timer event attached to it.
924 if (cli_nps->is_smb1) {
925 status = cli_read_andx_recv(subreq, &received, &rcvbuf);
927 uint32_t data_length = 0;
928 status = smb2cli_read_recv(subreq, state, &rcvbuf, &data_length);
929 received = data_length;
932 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
935 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
937 * NT_STATUS_BUFFER_TOO_SMALL means that there's
938 * more data to read when the named pipe is used
939 * in message mode (which is the case here).
941 * But we hide this from the caller.
943 status = NT_STATUS_OK;
945 if (!NT_STATUS_IS_OK(status)) {
947 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
951 if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) {
953 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
959 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
963 cli_nps->read.ofs = 0;
964 cli_nps->read.left = received;
965 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
966 if (cli_nps->read.buf == NULL) {
968 tevent_req_nomem(cli_nps->read.buf, req);
971 memcpy(cli_nps->read.buf, rcvbuf, received);
974 tstream_cli_np_readv_read_next(req);
977 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq);
979 static void tstream_cli_np_readv_error(struct tevent_req *req);
981 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
983 const char *location)
985 struct tstream_cli_np_readv_state *state =
987 struct tstream_cli_np_readv_state);
988 struct tstream_cli_np *cli_nps =
989 tstream_context_data(state->stream,
990 struct tstream_cli_np);
991 struct tevent_req *subreq;
993 state->error.val = error;
994 state->error.location = location;
996 if (!cli_state_is_connected(cli_nps->cli)) {
997 /* return the original error */
998 tstream_cli_np_readv_error(req);
1002 if (cli_nps->is_smb1) {
1003 subreq = cli_close_send(state, state->ev, cli_nps->cli,
1006 subreq = smb2cli_close_send(state, state->ev, cli_nps->cli,
1008 cli_nps->fid_persistent,
1009 cli_nps->fid_volatile);
1011 if (subreq == NULL) {
1012 /* return the original error */
1013 tstream_cli_np_readv_error(req);
1016 tevent_req_set_callback(subreq,
1017 tstream_cli_np_readv_disconnect_done,
1021 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq)
1023 struct tevent_req *req =
1024 tevent_req_callback_data(subreq, struct tevent_req);
1025 struct tstream_cli_np_readv_state *state =
1026 tevent_req_data(req, struct tstream_cli_np_readv_state);
1027 struct tstream_cli_np *cli_nps =
1028 tstream_context_data(state->stream, struct tstream_cli_np);
1030 if (cli_nps->is_smb1) {
1031 cli_close_recv(subreq);
1033 smb2cli_close_recv(subreq);
1035 TALLOC_FREE(subreq);
1037 cli_nps->cli = NULL;
1039 tstream_cli_np_readv_error(req);
1042 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
1043 struct tevent_immediate *im,
1044 void *private_data);
1046 static void tstream_cli_np_readv_error(struct tevent_req *req)
1048 struct tstream_cli_np_readv_state *state =
1049 tevent_req_data(req,
1050 struct tstream_cli_np_readv_state);
1051 struct tstream_cli_np *cli_nps =
1052 tstream_context_data(state->stream,
1053 struct tstream_cli_np);
1055 if (cli_nps->trans.write_req == NULL) {
1056 /* return the original error */
1057 _tevent_req_error(req, state->error.val, state->error.location);
1061 if (state->trans.im == NULL) {
1062 /* return the original error */
1063 _tevent_req_error(req, state->error.val, state->error.location);
1067 tevent_schedule_immediate(state->trans.im, state->ev,
1068 tstream_cli_np_readv_error_trigger, req);
1070 /* return the original error for writev */
1071 _tevent_req_error(cli_nps->trans.write_req,
1072 state->error.val, state->error.location);
1075 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
1076 struct tevent_immediate *im,
1079 struct tevent_req *req =
1080 talloc_get_type_abort(private_data,
1082 struct tstream_cli_np_readv_state *state =
1083 tevent_req_data(req,
1084 struct tstream_cli_np_readv_state);
1086 /* return the original error */
1087 _tevent_req_error(req, state->error.val, state->error.location);
1090 static int tstream_cli_np_readv_recv(struct tevent_req *req,
1093 struct tstream_cli_np_readv_state *state =
1094 tevent_req_data(req, struct tstream_cli_np_readv_state);
1097 ret = tsocket_simple_int_recv(req, perrno);
1102 tevent_req_received(req);
1106 struct tstream_cli_np_disconnect_state {
1107 struct tstream_context *stream;
1110 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq);
1112 static struct tevent_req *tstream_cli_np_disconnect_send(TALLOC_CTX *mem_ctx,
1113 struct tevent_context *ev,
1114 struct tstream_context *stream)
1116 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
1117 struct tstream_cli_np);
1118 struct tevent_req *req;
1119 struct tstream_cli_np_disconnect_state *state;
1120 struct tevent_req *subreq;
1122 req = tevent_req_create(mem_ctx, &state,
1123 struct tstream_cli_np_disconnect_state);
1128 state->stream = stream;
1130 if (!cli_state_is_connected(cli_nps->cli)) {
1131 tevent_req_error(req, ENOTCONN);
1132 return tevent_req_post(req, ev);
1135 if (cli_nps->is_smb1) {
1136 subreq = cli_close_send(state, ev, cli_nps->cli,
1139 subreq = smb2cli_close_send(state, ev, cli_nps->cli,
1141 cli_nps->fid_persistent,
1142 cli_nps->fid_volatile);
1144 if (tevent_req_nomem(subreq, req)) {
1145 return tevent_req_post(req, ev);
1147 tevent_req_set_callback(subreq, tstream_cli_np_disconnect_done, req);
1152 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq)
1154 struct tevent_req *req = tevent_req_callback_data(subreq,
1156 struct tstream_cli_np_disconnect_state *state =
1157 tevent_req_data(req, struct tstream_cli_np_disconnect_state);
1158 struct tstream_cli_np *cli_nps =
1159 tstream_context_data(state->stream, struct tstream_cli_np);
1162 if (cli_nps->is_smb1) {
1163 status = cli_close_recv(subreq);
1165 status = smb2cli_close_recv(subreq);
1167 TALLOC_FREE(subreq);
1168 if (!NT_STATUS_IS_OK(status)) {
1169 tevent_req_error(req, EIO);
1173 cli_nps->cli = NULL;
1175 tevent_req_done(req);
1178 static int tstream_cli_np_disconnect_recv(struct tevent_req *req,
1183 ret = tsocket_simple_int_recv(req, perrno);
1185 tevent_req_received(req);
1189 static const struct tstream_context_ops tstream_cli_np_ops = {
1192 .pending_bytes = tstream_cli_np_pending_bytes,
1194 .readv_send = tstream_cli_np_readv_send,
1195 .readv_recv = tstream_cli_np_readv_recv,
1197 .writev_send = tstream_cli_np_writev_send,
1198 .writev_recv = tstream_cli_np_writev_recv,
1200 .disconnect_send = tstream_cli_np_disconnect_send,
1201 .disconnect_recv = tstream_cli_np_disconnect_recv,