s3:libsmb: add tstream_is_cli_np()
[Samba/gebeck_regimport.git] / source3 / libsmb / cli_np_tstream.c
blobaa5806bba84851e3953cace6da6ada39c0c90163
1 /*
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/>.
20 #include "includes.h"
21 #include "system/network.h"
22 #include "../util/tevent_unix.h"
23 #include "../lib/tsocket/tsocket.h"
24 #include "../lib/tsocket/tsocket_internal.h"
25 #include "cli_np_tstream.h"
27 static const struct tstream_context_ops tstream_cli_np_ops;
30 * Window uses 1024 hardcoded for read size and trans max data
32 #define TSTREAM_CLI_NP_BUF_SIZE 1024
34 struct tstream_cli_np {
35 struct cli_state *cli;
36 const char *npipe;
37 uint16_t fnum;
39 struct {
40 off_t ofs;
41 size_t left;
42 uint8_t buf[TSTREAM_CLI_NP_BUF_SIZE];
43 } read, write;
46 static int tstream_cli_np_destructor(struct tstream_cli_np *cli_nps)
48 NTSTATUS status;
50 if (!cli_state_is_connected(cli_nps->cli)) {
51 return 0;
55 * TODO: do not use a sync call with a destructor!!!
57 * This only happens, if a caller does talloc_free(),
58 * while the everything was still ok.
60 * If we get an unexpected failure within a normal
61 * operation, we already do an async cli_close_send()/_recv().
63 * Once we've fixed all callers to call
64 * tstream_disconnect_send()/_recv(), this will
65 * never be called.
67 status = cli_close(cli_nps->cli, cli_nps->fnum);
68 if (!NT_STATUS_IS_OK(status)) {
69 DEBUG(1, ("tstream_cli_np_destructor: cli_close "
70 "failed on pipe %s. Error was %s\n",
71 cli_nps->npipe, nt_errstr(status)));
74 * We can't do much on failure
76 return 0;
79 struct tstream_cli_np_open_state {
80 struct cli_state *cli;
81 uint16_t fnum;
82 const char *npipe;
85 static void tstream_cli_np_open_done(struct tevent_req *subreq);
87 struct tevent_req *tstream_cli_np_open_send(TALLOC_CTX *mem_ctx,
88 struct tevent_context *ev,
89 struct cli_state *cli,
90 const char *npipe)
92 struct tevent_req *req;
93 struct tstream_cli_np_open_state *state;
94 struct tevent_req *subreq;
96 req = tevent_req_create(mem_ctx, &state,
97 struct tstream_cli_np_open_state);
98 if (!req) {
99 return NULL;
101 state->cli = cli;
103 state->npipe = talloc_strdup(state, npipe);
104 if (tevent_req_nomem(state->npipe, req)) {
105 return tevent_req_post(req, ev);
108 subreq = cli_ntcreate_send(state, ev, cli,
109 npipe,
111 DESIRED_ACCESS_PIPE,
113 FILE_SHARE_READ|FILE_SHARE_WRITE,
114 FILE_OPEN,
117 if (tevent_req_nomem(subreq, req)) {
118 return tevent_req_post(req, ev);
120 tevent_req_set_callback(subreq, tstream_cli_np_open_done, req);
122 return req;
125 static void tstream_cli_np_open_done(struct tevent_req *subreq)
127 struct tevent_req *req =
128 tevent_req_callback_data(subreq, struct tevent_req);
129 struct tstream_cli_np_open_state *state =
130 tevent_req_data(req, struct tstream_cli_np_open_state);
131 NTSTATUS status;
133 status = cli_ntcreate_recv(subreq, &state->fnum);
134 TALLOC_FREE(subreq);
135 if (!NT_STATUS_IS_OK(status)) {
136 tevent_req_nterror(req, status);
137 return;
140 tevent_req_done(req);
143 NTSTATUS _tstream_cli_np_open_recv(struct tevent_req *req,
144 TALLOC_CTX *mem_ctx,
145 struct tstream_context **_stream,
146 const char *location)
148 struct tstream_cli_np_open_state *state =
149 tevent_req_data(req, struct tstream_cli_np_open_state);
150 struct tstream_context *stream;
151 struct tstream_cli_np *cli_nps;
152 NTSTATUS status;
154 if (tevent_req_is_nterror(req, &status)) {
155 tevent_req_received(req);
156 return status;
159 stream = tstream_context_create(mem_ctx,
160 &tstream_cli_np_ops,
161 &cli_nps,
162 struct tstream_cli_np,
163 location);
164 if (!stream) {
165 tevent_req_received(req);
166 return NT_STATUS_NO_MEMORY;
168 ZERO_STRUCTP(cli_nps);
170 cli_nps->cli = state->cli;
171 cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
172 cli_nps->fnum = state->fnum;
174 talloc_set_destructor(cli_nps, tstream_cli_np_destructor);
176 *_stream = stream;
177 tevent_req_received(req);
178 return NT_STATUS_OK;
181 static ssize_t tstream_cli_np_pending_bytes(struct tstream_context *stream)
183 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
184 struct tstream_cli_np);
186 if (!cli_state_is_connected(cli_nps->cli)) {
187 errno = ENOTCONN;
188 return -1;
191 return cli_nps->read.left;
194 bool tstream_is_cli_np(struct tstream_context *stream)
196 struct tstream_cli_np *cli_nps =
197 talloc_get_type(_tstream_context_data(stream),
198 struct tstream_cli_np);
200 if (!cli_nps) {
201 return false;
204 return true;
207 struct tstream_cli_np_writev_state {
208 struct tstream_context *stream;
209 struct tevent_context *ev;
211 struct iovec *vector;
212 size_t count;
214 int ret;
216 struct {
217 int val;
218 const char *location;
219 } error;
222 static void tstream_cli_np_writev_write_next(struct tevent_req *req);
224 static struct tevent_req *tstream_cli_np_writev_send(TALLOC_CTX *mem_ctx,
225 struct tevent_context *ev,
226 struct tstream_context *stream,
227 const struct iovec *vector,
228 size_t count)
230 struct tevent_req *req;
231 struct tstream_cli_np_writev_state *state;
232 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
233 struct tstream_cli_np);
235 req = tevent_req_create(mem_ctx, &state,
236 struct tstream_cli_np_writev_state);
237 if (!req) {
238 return NULL;
240 state->stream = stream;
241 state->ev = ev;
242 state->ret = 0;
244 if (!cli_state_is_connected(cli_nps->cli)) {
245 tevent_req_error(req, ENOTCONN);
246 return tevent_req_post(req, ev);
250 * we make a copy of the vector so we can change the structure
252 state->vector = talloc_array(state, struct iovec, count);
253 if (tevent_req_nomem(state->vector, req)) {
254 return tevent_req_post(req, ev);
256 memcpy(state->vector, vector, sizeof(struct iovec) * count);
257 state->count = count;
259 tstream_cli_np_writev_write_next(req);
260 if (!tevent_req_is_in_progress(req)) {
261 return tevent_req_post(req, ev);
264 return req;
267 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq);
269 static void tstream_cli_np_writev_write_next(struct tevent_req *req)
271 struct tstream_cli_np_writev_state *state =
272 tevent_req_data(req,
273 struct tstream_cli_np_writev_state);
274 struct tstream_cli_np *cli_nps =
275 tstream_context_data(state->stream,
276 struct tstream_cli_np);
277 struct tevent_req *subreq;
279 cli_nps->write.ofs = 0;
280 cli_nps->write.left = TSTREAM_CLI_NP_BUF_SIZE;
283 * copy the pending buffer first
285 while (cli_nps->write.left > 0 && state->count > 0) {
286 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
287 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
289 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
291 base += len;
292 state->vector[0].iov_base = base;
293 state->vector[0].iov_len -= len;
295 cli_nps->write.ofs += len;
296 cli_nps->write.left -= len;
298 if (state->vector[0].iov_len == 0) {
299 state->vector += 1;
300 state->count -= 1;
303 state->ret += len;
306 if (cli_nps->write.ofs == 0) {
307 tevent_req_done(req);
308 return;
311 subreq = cli_write_andx_send(state, state->ev, cli_nps->cli,
312 cli_nps->fnum,
313 8, /* 8 means message mode. */
314 cli_nps->write.buf, 0,
315 cli_nps->write.ofs);
316 if (tevent_req_nomem(subreq, req)) {
317 return;
319 tevent_req_set_callback(subreq,
320 tstream_cli_np_writev_write_done,
321 req);
324 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
325 int error,
326 const char *location);
328 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq)
330 struct tevent_req *req =
331 tevent_req_callback_data(subreq, struct tevent_req);
332 struct tstream_cli_np_writev_state *state =
333 tevent_req_data(req, struct tstream_cli_np_writev_state);
334 struct tstream_cli_np *cli_nps =
335 tstream_context_data(state->stream,
336 struct tstream_cli_np);
337 size_t written;
338 NTSTATUS status;
340 status = cli_write_andx_recv(subreq, &written);
341 TALLOC_FREE(subreq);
342 if (!NT_STATUS_IS_OK(status)) {
343 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
344 return;
347 if (written != cli_nps->write.ofs) {
348 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
349 return;
352 tstream_cli_np_writev_write_next(req);
355 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq);
357 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
358 int error,
359 const char *location)
361 struct tstream_cli_np_writev_state *state =
362 tevent_req_data(req,
363 struct tstream_cli_np_writev_state);
364 struct tstream_cli_np *cli_nps =
365 tstream_context_data(state->stream,
366 struct tstream_cli_np);
367 struct tevent_req *subreq;
369 state->error.val = error;
370 state->error.location = location;
372 if (!cli_state_is_connected(cli_nps->cli)) {
373 /* return the original error */
374 _tevent_req_error(req, state->error.val, state->error.location);
375 return;
378 subreq = cli_close_send(state, state->ev, cli_nps->cli, cli_nps->fnum);
379 if (subreq == NULL) {
380 /* return the original error */
381 _tevent_req_error(req, state->error.val, state->error.location);
382 return;
384 tevent_req_set_callback(subreq,
385 tstream_cli_np_writev_disconnect_done,
386 req);
389 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq)
391 struct tevent_req *req =
392 tevent_req_callback_data(subreq, struct tevent_req);
393 struct tstream_cli_np_writev_state *state =
394 tevent_req_data(req, struct tstream_cli_np_writev_state);
395 struct tstream_cli_np *cli_nps =
396 tstream_context_data(state->stream, struct tstream_cli_np);
397 NTSTATUS status;
399 status = cli_close_recv(subreq);
400 TALLOC_FREE(subreq);
402 cli_nps->cli = NULL;
404 /* return the original error */
405 _tevent_req_error(req, state->error.val, state->error.location);
408 static int tstream_cli_np_writev_recv(struct tevent_req *req,
409 int *perrno)
411 struct tstream_cli_np_writev_state *state =
412 tevent_req_data(req,
413 struct tstream_cli_np_writev_state);
414 int ret;
416 ret = tsocket_simple_int_recv(req, perrno);
417 if (ret == 0) {
418 ret = state->ret;
421 tevent_req_received(req);
422 return ret;
425 struct tstream_cli_np_readv_state {
426 struct tstream_context *stream;
427 struct tevent_context *ev;
429 struct iovec *vector;
430 size_t count;
432 int ret;
434 struct {
435 int val;
436 const char *location;
437 } error;
440 static void tstream_cli_np_readv_read_next(struct tevent_req *req);
442 static struct tevent_req *tstream_cli_np_readv_send(TALLOC_CTX *mem_ctx,
443 struct tevent_context *ev,
444 struct tstream_context *stream,
445 struct iovec *vector,
446 size_t count)
448 struct tevent_req *req;
449 struct tstream_cli_np_readv_state *state;
450 struct tstream_cli_np *cli_nps =
451 tstream_context_data(stream, struct tstream_cli_np);
453 req = tevent_req_create(mem_ctx, &state,
454 struct tstream_cli_np_readv_state);
455 if (!req) {
456 return NULL;
458 state->stream = stream;
459 state->ev = ev;
460 state->ret = 0;
462 if (!cli_state_is_connected(cli_nps->cli)) {
463 tevent_req_error(req, ENOTCONN);
464 return tevent_req_post(req, ev);
468 * we make a copy of the vector so we can change the structure
470 state->vector = talloc_array(state, struct iovec, count);
471 if (tevent_req_nomem(state->vector, req)) {
472 return tevent_req_post(req, ev);
474 memcpy(state->vector, vector, sizeof(struct iovec) * count);
475 state->count = count;
477 tstream_cli_np_readv_read_next(req);
478 if (!tevent_req_is_in_progress(req)) {
479 return tevent_req_post(req, ev);
482 return req;
485 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq);
487 static void tstream_cli_np_readv_read_next(struct tevent_req *req)
489 struct tstream_cli_np_readv_state *state =
490 tevent_req_data(req,
491 struct tstream_cli_np_readv_state);
492 struct tstream_cli_np *cli_nps =
493 tstream_context_data(state->stream,
494 struct tstream_cli_np);
495 struct tevent_req *subreq;
498 * copy the pending buffer first
500 while (cli_nps->read.left > 0 && state->count > 0) {
501 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
502 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
504 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
506 base += len;
507 state->vector[0].iov_base = base;
508 state->vector[0].iov_len -= len;
510 cli_nps->read.ofs += len;
511 cli_nps->read.left -= len;
513 if (state->vector[0].iov_len == 0) {
514 state->vector += 1;
515 state->count -= 1;
518 state->ret += len;
521 if (state->count == 0) {
522 tevent_req_done(req);
523 return;
526 subreq = cli_read_andx_send(state, state->ev, cli_nps->cli,
527 cli_nps->fnum, 0, TSTREAM_CLI_NP_BUF_SIZE);
528 if (tevent_req_nomem(subreq, req)) {
529 return;
531 tevent_req_set_callback(subreq,
532 tstream_cli_np_readv_read_done,
533 req);
536 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
537 int error,
538 const char *location);
540 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq)
542 struct tevent_req *req =
543 tevent_req_callback_data(subreq, struct tevent_req);
544 struct tstream_cli_np_readv_state *state =
545 tevent_req_data(req, struct tstream_cli_np_readv_state);
546 struct tstream_cli_np *cli_nps =
547 tstream_context_data(state->stream, struct tstream_cli_np);
548 uint8_t *rcvbuf;
549 ssize_t received;
550 NTSTATUS status;
553 * We must free subreq in this function as there is
554 * a timer event attached to it.
557 status = cli_read_andx_recv(subreq, &received, &rcvbuf);
559 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
560 * child of that.
562 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
564 * NT_STATUS_BUFFER_TOO_SMALL means that there's
565 * more data to read when the named pipe is used
566 * in message mode (which is the case here).
568 * But we hide this from the caller.
570 status = NT_STATUS_OK;
572 if (!NT_STATUS_IS_OK(status)) {
573 TALLOC_FREE(subreq);
574 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
575 return;
578 if (received > TSTREAM_CLI_NP_BUF_SIZE) {
579 TALLOC_FREE(subreq);
580 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
581 return;
584 if (received == 0) {
585 TALLOC_FREE(subreq);
586 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
587 return;
590 cli_nps->read.ofs = 0;
591 cli_nps->read.left = received;
592 memcpy(cli_nps->read.buf, rcvbuf, received);
593 TALLOC_FREE(subreq);
595 tstream_cli_np_readv_read_next(req);
598 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq);
600 static void tstream_cli_np_readv_error(struct tevent_req *req);
602 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
603 int error,
604 const char *location)
606 struct tstream_cli_np_readv_state *state =
607 tevent_req_data(req,
608 struct tstream_cli_np_readv_state);
609 struct tstream_cli_np *cli_nps =
610 tstream_context_data(state->stream,
611 struct tstream_cli_np);
612 struct tevent_req *subreq;
614 state->error.val = error;
615 state->error.location = location;
617 if (!cli_state_is_connected(cli_nps->cli)) {
618 /* return the original error */
619 tstream_cli_np_readv_error(req);
620 return;
623 subreq = cli_close_send(state, state->ev, cli_nps->cli, cli_nps->fnum);
624 if (subreq == NULL) {
625 /* return the original error */
626 tstream_cli_np_readv_error(req);
627 return;
629 tevent_req_set_callback(subreq,
630 tstream_cli_np_readv_disconnect_done,
631 req);
634 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq)
636 struct tevent_req *req =
637 tevent_req_callback_data(subreq, struct tevent_req);
638 struct tstream_cli_np_readv_state *state =
639 tevent_req_data(req, struct tstream_cli_np_readv_state);
640 struct tstream_cli_np *cli_nps =
641 tstream_context_data(state->stream, struct tstream_cli_np);
642 NTSTATUS status;
644 status = cli_close_recv(subreq);
645 TALLOC_FREE(subreq);
647 cli_nps->cli = NULL;
649 tstream_cli_np_readv_error(req);
652 static void tstream_cli_np_readv_error(struct tevent_req *req)
654 struct tstream_cli_np_readv_state *state =
655 tevent_req_data(req,
656 struct tstream_cli_np_readv_state);
658 /* return the original error */
659 _tevent_req_error(req, state->error.val, state->error.location);
662 static int tstream_cli_np_readv_recv(struct tevent_req *req,
663 int *perrno)
665 struct tstream_cli_np_readv_state *state =
666 tevent_req_data(req, struct tstream_cli_np_readv_state);
667 int ret;
669 ret = tsocket_simple_int_recv(req, perrno);
670 if (ret == 0) {
671 ret = state->ret;
674 tevent_req_received(req);
675 return ret;
678 struct tstream_cli_np_disconnect_state {
679 struct tstream_context *stream;
682 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq);
684 static struct tevent_req *tstream_cli_np_disconnect_send(TALLOC_CTX *mem_ctx,
685 struct tevent_context *ev,
686 struct tstream_context *stream)
688 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
689 struct tstream_cli_np);
690 struct tevent_req *req;
691 struct tstream_cli_np_disconnect_state *state;
692 struct tevent_req *subreq;
694 req = tevent_req_create(mem_ctx, &state,
695 struct tstream_cli_np_disconnect_state);
696 if (req == NULL) {
697 return NULL;
700 state->stream = stream;
702 if (!cli_state_is_connected(cli_nps->cli)) {
703 tevent_req_error(req, ENOTCONN);
704 return tevent_req_post(req, ev);
707 subreq = cli_close_send(state, ev, cli_nps->cli, cli_nps->fnum);
708 if (tevent_req_nomem(subreq, req)) {
709 return tevent_req_post(req, ev);
711 tevent_req_set_callback(subreq, tstream_cli_np_disconnect_done, req);
713 return req;
716 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq)
718 struct tevent_req *req = tevent_req_callback_data(subreq,
719 struct tevent_req);
720 struct tstream_cli_np_disconnect_state *state =
721 tevent_req_data(req, struct tstream_cli_np_disconnect_state);
722 struct tstream_cli_np *cli_nps =
723 tstream_context_data(state->stream, struct tstream_cli_np);
724 NTSTATUS status;
726 status = cli_close_recv(subreq);
727 TALLOC_FREE(subreq);
728 if (!NT_STATUS_IS_OK(status)) {
729 tevent_req_error(req, EIO);
730 return;
733 cli_nps->cli = NULL;
735 tevent_req_done(req);
738 static int tstream_cli_np_disconnect_recv(struct tevent_req *req,
739 int *perrno)
741 int ret;
743 ret = tsocket_simple_int_recv(req, perrno);
745 tevent_req_received(req);
746 return ret;
749 static const struct tstream_context_ops tstream_cli_np_ops = {
750 .name = "cli_np",
752 .pending_bytes = tstream_cli_np_pending_bytes,
754 .readv_send = tstream_cli_np_readv_send,
755 .readv_recv = tstream_cli_np_readv_recv,
757 .writev_send = tstream_cli_np_writev_send,
758 .writev_recv = tstream_cli_np_writev_recv,
760 .disconnect_send = tstream_cli_np_disconnect_send,
761 .disconnect_recv = tstream_cli_np_disconnect_recv,
764 NTSTATUS _tstream_cli_np_existing(TALLOC_CTX *mem_ctx,
765 struct cli_state *cli,
766 uint16_t fnum,
767 struct tstream_context **_stream,
768 const char *location)
770 struct tstream_context *stream;
771 struct tstream_cli_np *cli_nps;
773 stream = tstream_context_create(mem_ctx,
774 &tstream_cli_np_ops,
775 &cli_nps,
776 struct tstream_cli_np,
777 location);
778 if (!stream) {
779 return NT_STATUS_NO_MEMORY;
781 ZERO_STRUCTP(cli_nps);
783 cli_nps->cli = cli;
784 cli_nps->fnum = fnum;
786 *_stream = stream;
787 return NT_STATUS_OK;