s3-libsmb: run minimal_includes.pl.
[nivanova/samba-autobuild/.git] / source3 / libsmb / cli_np_tstream.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2010
5
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.
10
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.
15
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/>.
18 */
19
20 #include "includes.h"
21 #include "system/network.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "../lib/tsocket/tsocket.h"
24 #include "../lib/tsocket/tsocket_internal.h"
25 #include "cli_np_tstream.h"
26
27 static const struct tstream_context_ops tstream_cli_np_ops;
28
29 /*
30  * Window uses 1024 hardcoded for read size and trans max data
31  */
32 #define TSTREAM_CLI_NP_BUF_SIZE 1024
33
34 struct tstream_cli_np {
35         struct cli_state *cli;
36         const char *npipe;
37         uint16_t fnum;
38         unsigned int default_timeout;
39
40         struct {
41                 bool active;
42                 struct tevent_req *read_req;
43                 struct tevent_req *write_req;
44                 uint16_t setup[2];
45         } trans;
46
47         struct {
48                 off_t ofs;
49                 size_t left;
50                 uint8_t buf[TSTREAM_CLI_NP_BUF_SIZE];
51         } read, write;
52 };
53
54 static int tstream_cli_np_destructor(struct tstream_cli_np *cli_nps)
55 {
56         NTSTATUS status;
57
58         if (!cli_state_is_connected(cli_nps->cli)) {
59                 return 0;
60         }
61
62         /*
63          * TODO: do not use a sync call with a destructor!!!
64          *
65          * This only happens, if a caller does talloc_free(),
66          * while the everything was still ok.
67          *
68          * If we get an unexpected failure within a normal
69          * operation, we already do an async cli_close_send()/_recv().
70          *
71          * Once we've fixed all callers to call
72          * tstream_disconnect_send()/_recv(), this will
73          * never be called.
74          */
75         status = cli_close(cli_nps->cli, cli_nps->fnum);
76         if (!NT_STATUS_IS_OK(status)) {
77                 DEBUG(1, ("tstream_cli_np_destructor: cli_close "
78                           "failed on pipe %s. Error was %s\n",
79                           cli_nps->npipe, nt_errstr(status)));
80         }
81         /*
82          * We can't do much on failure
83          */
84         return 0;
85 }
86
87 struct tstream_cli_np_open_state {
88         struct cli_state *cli;
89         uint16_t fnum;
90         const char *npipe;
91 };
92
93 static void tstream_cli_np_open_done(struct tevent_req *subreq);
94
95 struct tevent_req *tstream_cli_np_open_send(TALLOC_CTX *mem_ctx,
96                                             struct tevent_context *ev,
97                                             struct cli_state *cli,
98                                             const char *npipe)
99 {
100         struct tevent_req *req;
101         struct tstream_cli_np_open_state *state;
102         struct tevent_req *subreq;
103
104         req = tevent_req_create(mem_ctx, &state,
105                                 struct tstream_cli_np_open_state);
106         if (!req) {
107                 return NULL;
108         }
109         state->cli = cli;
110
111         state->npipe = talloc_strdup(state, npipe);
112         if (tevent_req_nomem(state->npipe, req)) {
113                 return tevent_req_post(req, ev);
114         }
115
116         subreq = cli_ntcreate_send(state, ev, cli,
117                                    npipe,
118                                    0,
119                                    DESIRED_ACCESS_PIPE,
120                                    0,
121                                    FILE_SHARE_READ|FILE_SHARE_WRITE,
122                                    FILE_OPEN,
123                                    0,
124                                    0);
125         if (tevent_req_nomem(subreq, req)) {
126                 return tevent_req_post(req, ev);
127         }
128         tevent_req_set_callback(subreq, tstream_cli_np_open_done, req);
129
130         return req;
131 }
132
133 static void tstream_cli_np_open_done(struct tevent_req *subreq)
134 {
135         struct tevent_req *req =
136                 tevent_req_callback_data(subreq, struct tevent_req);
137         struct tstream_cli_np_open_state *state =
138                 tevent_req_data(req, struct tstream_cli_np_open_state);
139         NTSTATUS status;
140
141         status = cli_ntcreate_recv(subreq, &state->fnum);
142         TALLOC_FREE(subreq);
143         if (!NT_STATUS_IS_OK(status)) {
144                 tevent_req_nterror(req, status);
145                 return;
146         }
147
148         tevent_req_done(req);
149 }
150
151 NTSTATUS _tstream_cli_np_open_recv(struct tevent_req *req,
152                                    TALLOC_CTX *mem_ctx,
153                                    struct tstream_context **_stream,
154                                    const char *location)
155 {
156         struct tstream_cli_np_open_state *state =
157                 tevent_req_data(req, struct tstream_cli_np_open_state);
158         struct tstream_context *stream;
159         struct tstream_cli_np *cli_nps;
160         NTSTATUS status;
161
162         if (tevent_req_is_nterror(req, &status)) {
163                 tevent_req_received(req);
164                 return status;
165         }
166
167         stream = tstream_context_create(mem_ctx,
168                                         &tstream_cli_np_ops,
169                                         &cli_nps,
170                                         struct tstream_cli_np,
171                                         location);
172         if (!stream) {
173                 tevent_req_received(req);
174                 return NT_STATUS_NO_MEMORY;
175         }
176         ZERO_STRUCTP(cli_nps);
177
178         cli_nps->cli = state->cli;
179         cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
180         cli_nps->fnum = state->fnum;
181         cli_nps->default_timeout = state->cli->timeout;
182
183         talloc_set_destructor(cli_nps, tstream_cli_np_destructor);
184
185         cli_nps->trans.active = false;
186         cli_nps->trans.read_req = NULL;
187         cli_nps->trans.write_req = NULL;
188         SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
189         SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
190
191         *_stream = stream;
192         tevent_req_received(req);
193         return NT_STATUS_OK;
194 }
195
196 static ssize_t tstream_cli_np_pending_bytes(struct tstream_context *stream)
197 {
198         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
199                                          struct tstream_cli_np);
200
201         if (!cli_state_is_connected(cli_nps->cli)) {
202                 errno = ENOTCONN;
203                 return -1;
204         }
205
206         return cli_nps->read.left;
207 }
208
209 bool tstream_is_cli_np(struct tstream_context *stream)
210 {
211         struct tstream_cli_np *cli_nps =
212                 talloc_get_type(_tstream_context_data(stream),
213                 struct tstream_cli_np);
214
215         if (!cli_nps) {
216                 return false;
217         }
218
219         return true;
220 }
221
222 NTSTATUS tstream_cli_np_use_trans(struct tstream_context *stream)
223 {
224         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
225                                          struct tstream_cli_np);
226
227         if (cli_nps->trans.read_req) {
228                 return NT_STATUS_PIPE_BUSY;
229         }
230
231         if (cli_nps->trans.write_req) {
232                 return NT_STATUS_PIPE_BUSY;
233         }
234
235         if (cli_nps->trans.active) {
236                 return NT_STATUS_PIPE_BUSY;
237         }
238
239         cli_nps->trans.active = true;
240
241         return NT_STATUS_OK;
242 }
243
244 unsigned int tstream_cli_np_set_timeout(struct tstream_context *stream,
245                                         unsigned int timeout)
246 {
247         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
248                                          struct tstream_cli_np);
249
250         if (!cli_state_is_connected(cli_nps->cli)) {
251                 return cli_nps->default_timeout;
252         }
253
254         return cli_set_timeout(cli_nps->cli, timeout);
255 }
256
257 struct cli_state *tstream_cli_np_get_cli_state(struct tstream_context *stream)
258 {
259         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
260                                          struct tstream_cli_np);
261
262         return cli_nps->cli;
263 }
264
265 struct tstream_cli_np_writev_state {
266         struct tstream_context *stream;
267         struct tevent_context *ev;
268
269         struct iovec *vector;
270         size_t count;
271
272         int ret;
273
274         struct {
275                 int val;
276                 const char *location;
277         } error;
278 };
279
280 static int tstream_cli_np_writev_state_destructor(struct tstream_cli_np_writev_state *state)
281 {
282         struct tstream_cli_np *cli_nps =
283                 tstream_context_data(state->stream,
284                 struct tstream_cli_np);
285
286         cli_nps->trans.write_req = NULL;
287
288         return 0;
289 }
290
291 static void tstream_cli_np_writev_write_next(struct tevent_req *req);
292
293 static struct tevent_req *tstream_cli_np_writev_send(TALLOC_CTX *mem_ctx,
294                                         struct tevent_context *ev,
295                                         struct tstream_context *stream,
296                                         const struct iovec *vector,
297                                         size_t count)
298 {
299         struct tevent_req *req;
300         struct tstream_cli_np_writev_state *state;
301         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
302                                          struct tstream_cli_np);
303
304         req = tevent_req_create(mem_ctx, &state,
305                                 struct tstream_cli_np_writev_state);
306         if (!req) {
307                 return NULL;
308         }
309         state->stream = stream;
310         state->ev = ev;
311         state->ret = 0;
312
313         talloc_set_destructor(state, tstream_cli_np_writev_state_destructor);
314
315         if (!cli_state_is_connected(cli_nps->cli)) {
316                 tevent_req_error(req, ENOTCONN);
317                 return tevent_req_post(req, ev);
318         }
319
320         /*
321          * we make a copy of the vector so we can change the structure
322          */
323         state->vector = talloc_array(state, struct iovec, count);
324         if (tevent_req_nomem(state->vector, req)) {
325                 return tevent_req_post(req, ev);
326         }
327         memcpy(state->vector, vector, sizeof(struct iovec) * count);
328         state->count = count;
329
330         tstream_cli_np_writev_write_next(req);
331         if (!tevent_req_is_in_progress(req)) {
332                 return tevent_req_post(req, ev);
333         }
334
335         return req;
336 }
337
338 static void tstream_cli_np_readv_trans_start(struct tevent_req *req);
339 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq);
340
341 static void tstream_cli_np_writev_write_next(struct tevent_req *req)
342 {
343         struct tstream_cli_np_writev_state *state =
344                 tevent_req_data(req,
345                 struct tstream_cli_np_writev_state);
346         struct tstream_cli_np *cli_nps =
347                 tstream_context_data(state->stream,
348                 struct tstream_cli_np);
349         struct tevent_req *subreq;
350
351         cli_nps->write.ofs = 0;
352         cli_nps->write.left = TSTREAM_CLI_NP_BUF_SIZE;
353
354         /*
355          * copy the pending buffer first
356          */
357         while (cli_nps->write.left > 0 && state->count > 0) {
358                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
359                 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
360
361                 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
362
363                 base += len;
364                 state->vector[0].iov_base = base;
365                 state->vector[0].iov_len -= len;
366
367                 cli_nps->write.ofs += len;
368                 cli_nps->write.left -= len;
369
370                 if (state->vector[0].iov_len == 0) {
371                         state->vector += 1;
372                         state->count -= 1;
373                 }
374
375                 state->ret += len;
376         }
377
378         if (cli_nps->write.ofs == 0) {
379                 tevent_req_done(req);
380                 return;
381         }
382
383         if (cli_nps->trans.active && state->count == 0) {
384                 cli_nps->trans.active = false;
385                 cli_nps->trans.write_req = req;
386                 return;
387         }
388
389         if (cli_nps->trans.read_req && state->count == 0) {
390                 cli_nps->trans.write_req = req;
391                 tstream_cli_np_readv_trans_start(cli_nps->trans.read_req);
392                 return;
393         }
394
395         subreq = cli_write_andx_send(state, state->ev, cli_nps->cli,
396                                      cli_nps->fnum,
397                                      8, /* 8 means message mode. */
398                                      cli_nps->write.buf, 0,
399                                      cli_nps->write.ofs);
400         if (tevent_req_nomem(subreq, req)) {
401                 return;
402         }
403         tevent_req_set_callback(subreq,
404                                 tstream_cli_np_writev_write_done,
405                                 req);
406 }
407
408 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
409                                                  int error,
410                                                  const char *location);
411
412 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq)
413 {
414         struct tevent_req *req =
415                 tevent_req_callback_data(subreq, struct tevent_req);
416         struct tstream_cli_np_writev_state *state =
417                 tevent_req_data(req, struct tstream_cli_np_writev_state);
418         struct tstream_cli_np *cli_nps =
419                 tstream_context_data(state->stream,
420                 struct tstream_cli_np);
421         size_t written;
422         NTSTATUS status;
423
424         status = cli_write_andx_recv(subreq, &written);
425         TALLOC_FREE(subreq);
426         if (!NT_STATUS_IS_OK(status)) {
427                 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
428                 return;
429         }
430
431         if (written != cli_nps->write.ofs) {
432                 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
433                 return;
434         }
435
436         tstream_cli_np_writev_write_next(req);
437 }
438
439 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq);
440
441 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
442                                                  int error,
443                                                  const char *location)
444 {
445         struct tstream_cli_np_writev_state *state =
446                 tevent_req_data(req,
447                 struct tstream_cli_np_writev_state);
448         struct tstream_cli_np *cli_nps =
449                 tstream_context_data(state->stream,
450                 struct tstream_cli_np);
451         struct tevent_req *subreq;
452
453         state->error.val = error;
454         state->error.location = location;
455
456         if (!cli_state_is_connected(cli_nps->cli)) {
457                 /* return the original error */
458                 _tevent_req_error(req, state->error.val, state->error.location);
459                 return;
460         }
461
462         subreq = cli_close_send(state, state->ev, cli_nps->cli, cli_nps->fnum);
463         if (subreq == NULL) {
464                 /* return the original error */
465                 _tevent_req_error(req, state->error.val, state->error.location);
466                 return;
467         }
468         tevent_req_set_callback(subreq,
469                                 tstream_cli_np_writev_disconnect_done,
470                                 req);
471 }
472
473 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq)
474 {
475         struct tevent_req *req =
476                 tevent_req_callback_data(subreq, struct tevent_req);
477         struct tstream_cli_np_writev_state *state =
478                 tevent_req_data(req, struct tstream_cli_np_writev_state);
479         struct tstream_cli_np *cli_nps =
480                 tstream_context_data(state->stream, struct tstream_cli_np);
481         NTSTATUS status;
482
483         status = cli_close_recv(subreq);
484         TALLOC_FREE(subreq);
485
486         cli_nps->cli = NULL;
487
488         /* return the original error */
489         _tevent_req_error(req, state->error.val, state->error.location);
490 }
491
492 static int tstream_cli_np_writev_recv(struct tevent_req *req,
493                                       int *perrno)
494 {
495         struct tstream_cli_np_writev_state *state =
496                 tevent_req_data(req,
497                 struct tstream_cli_np_writev_state);
498         int ret;
499
500         ret = tsocket_simple_int_recv(req, perrno);
501         if (ret == 0) {
502                 ret = state->ret;
503         }
504
505         tevent_req_received(req);
506         return ret;
507 }
508
509 struct tstream_cli_np_readv_state {
510         struct tstream_context *stream;
511         struct tevent_context *ev;
512
513         struct iovec *vector;
514         size_t count;
515
516         int ret;
517
518         struct {
519                 struct tevent_immediate *im;
520         } trans;
521
522         struct {
523                 int val;
524                 const char *location;
525         } error;
526 };
527
528 static int tstream_cli_np_readv_state_destructor(struct tstream_cli_np_readv_state *state)
529 {
530         struct tstream_cli_np *cli_nps =
531                 tstream_context_data(state->stream,
532                 struct tstream_cli_np);
533
534         cli_nps->trans.read_req = NULL;
535
536         return 0;
537 }
538
539 static void tstream_cli_np_readv_read_next(struct tevent_req *req);
540
541 static struct tevent_req *tstream_cli_np_readv_send(TALLOC_CTX *mem_ctx,
542                                         struct tevent_context *ev,
543                                         struct tstream_context *stream,
544                                         struct iovec *vector,
545                                         size_t count)
546 {
547         struct tevent_req *req;
548         struct tstream_cli_np_readv_state *state;
549         struct tstream_cli_np *cli_nps =
550                 tstream_context_data(stream, struct tstream_cli_np);
551
552         req = tevent_req_create(mem_ctx, &state,
553                                 struct tstream_cli_np_readv_state);
554         if (!req) {
555                 return NULL;
556         }
557         state->stream = stream;
558         state->ev = ev;
559         state->ret = 0;
560
561         talloc_set_destructor(state, tstream_cli_np_readv_state_destructor);
562
563         if (!cli_state_is_connected(cli_nps->cli)) {
564                 tevent_req_error(req, ENOTCONN);
565                 return tevent_req_post(req, ev);
566         }
567
568         /*
569          * we make a copy of the vector so we can change the structure
570          */
571         state->vector = talloc_array(state, struct iovec, count);
572         if (tevent_req_nomem(state->vector, req)) {
573                 return tevent_req_post(req, ev);
574         }
575         memcpy(state->vector, vector, sizeof(struct iovec) * count);
576         state->count = count;
577
578         tstream_cli_np_readv_read_next(req);
579         if (!tevent_req_is_in_progress(req)) {
580                 return tevent_req_post(req, ev);
581         }
582
583         return req;
584 }
585
586 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq);
587
588 static void tstream_cli_np_readv_read_next(struct tevent_req *req)
589 {
590         struct tstream_cli_np_readv_state *state =
591                 tevent_req_data(req,
592                 struct tstream_cli_np_readv_state);
593         struct tstream_cli_np *cli_nps =
594                 tstream_context_data(state->stream,
595                 struct tstream_cli_np);
596         struct tevent_req *subreq;
597
598         /*
599          * copy the pending buffer first
600          */
601         while (cli_nps->read.left > 0 && state->count > 0) {
602                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
603                 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
604
605                 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
606
607                 base += len;
608                 state->vector[0].iov_base = base;
609                 state->vector[0].iov_len -= len;
610
611                 cli_nps->read.ofs += len;
612                 cli_nps->read.left -= len;
613
614                 if (state->vector[0].iov_len == 0) {
615                         state->vector += 1;
616                         state->count -= 1;
617                 }
618
619                 state->ret += len;
620         }
621
622         if (state->count == 0) {
623                 tevent_req_done(req);
624                 return;
625         }
626
627         if (cli_nps->trans.active) {
628                 cli_nps->trans.active = false;
629                 cli_nps->trans.read_req = req;
630                 return;
631         }
632
633         if (cli_nps->trans.write_req) {
634                 cli_nps->trans.read_req = req;
635                 tstream_cli_np_readv_trans_start(req);
636                 return;
637         }
638
639         subreq = cli_read_andx_send(state, state->ev, cli_nps->cli,
640                                     cli_nps->fnum, 0, TSTREAM_CLI_NP_BUF_SIZE);
641         if (tevent_req_nomem(subreq, req)) {
642                 return;
643         }
644         tevent_req_set_callback(subreq,
645                                 tstream_cli_np_readv_read_done,
646                                 req);
647 }
648
649 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq);
650
651 static void tstream_cli_np_readv_trans_start(struct tevent_req *req)
652 {
653         struct tstream_cli_np_readv_state *state =
654                 tevent_req_data(req,
655                 struct tstream_cli_np_readv_state);
656         struct tstream_cli_np *cli_nps =
657                 tstream_context_data(state->stream,
658                 struct tstream_cli_np);
659         struct tevent_req *subreq;
660
661         state->trans.im = tevent_create_immediate(state);
662         if (tevent_req_nomem(state->trans.im, req)) {
663                 return;
664         }
665
666         subreq = cli_trans_send(state, state->ev,
667                                 cli_nps->cli,
668                                 SMBtrans,
669                                 "\\PIPE\\",
670                                 0, 0, 0,
671                                 cli_nps->trans.setup, 2,
672                                 0,
673                                 NULL, 0, 0,
674                                 cli_nps->write.buf,
675                                 cli_nps->write.ofs,
676                                 TSTREAM_CLI_NP_BUF_SIZE);
677         if (tevent_req_nomem(subreq, req)) {
678                 return;
679         }
680         tevent_req_set_callback(subreq,
681                                 tstream_cli_np_readv_trans_done,
682                                 req);
683 }
684
685 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
686                                                 int error,
687                                                 const char *location);
688 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
689                                             struct tevent_immediate *im,
690                                             void *private_data);
691
692 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq)
693 {
694         struct tevent_req *req =
695                 tevent_req_callback_data(subreq, struct tevent_req);
696         struct tstream_cli_np_readv_state *state =
697                 tevent_req_data(req, struct tstream_cli_np_readv_state);
698         struct tstream_cli_np *cli_nps =
699                 tstream_context_data(state->stream, struct tstream_cli_np);
700         uint8_t *rcvbuf;
701         uint32_t received;
702         NTSTATUS status;
703
704         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
705                                 NULL, 0, NULL,
706                                 &rcvbuf, 0, &received);
707         TALLOC_FREE(subreq);
708         if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
709                 status = NT_STATUS_OK;
710         }
711         if (!NT_STATUS_IS_OK(status)) {
712                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
713                 return;
714         }
715
716         if (received > TSTREAM_CLI_NP_BUF_SIZE) {
717                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
718                 return;
719         }
720
721         if (received == 0) {
722                 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
723                 return;
724         }
725
726         cli_nps->read.ofs = 0;
727         cli_nps->read.left = received;
728         memcpy(cli_nps->read.buf, rcvbuf, received);
729         TALLOC_FREE(rcvbuf);
730
731         if (cli_nps->trans.write_req == NULL) {
732                 tstream_cli_np_readv_read_next(req);
733                 return;
734         }
735
736         tevent_schedule_immediate(state->trans.im, state->ev,
737                                   tstream_cli_np_readv_trans_next, req);
738
739         tevent_req_done(cli_nps->trans.write_req);
740 }
741
742 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
743                                             struct tevent_immediate *im,
744                                             void *private_data)
745 {
746         struct tevent_req *req =
747                 talloc_get_type_abort(private_data,
748                 struct tevent_req);
749
750         tstream_cli_np_readv_read_next(req);
751 }
752
753 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq)
754 {
755         struct tevent_req *req =
756                 tevent_req_callback_data(subreq, struct tevent_req);
757         struct tstream_cli_np_readv_state *state =
758                 tevent_req_data(req, struct tstream_cli_np_readv_state);
759         struct tstream_cli_np *cli_nps =
760                 tstream_context_data(state->stream, struct tstream_cli_np);
761         uint8_t *rcvbuf;
762         ssize_t received;
763         NTSTATUS status;
764
765         /*
766          * We must free subreq in this function as there is
767          * a timer event attached to it.
768          */
769
770         status = cli_read_andx_recv(subreq, &received, &rcvbuf);
771         /*
772          * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
773          * child of that.
774          */
775         if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
776                 /*
777                  * NT_STATUS_BUFFER_TOO_SMALL means that there's
778                  * more data to read when the named pipe is used
779                  * in message mode (which is the case here).
780                  *
781                  * But we hide this from the caller.
782                  */
783                 status = NT_STATUS_OK;
784         }
785         if (!NT_STATUS_IS_OK(status)) {
786                 TALLOC_FREE(subreq);
787                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
788                 return;
789         }
790
791         if (received > TSTREAM_CLI_NP_BUF_SIZE) {
792                 TALLOC_FREE(subreq);
793                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
794                 return;
795         }
796
797         if (received == 0) {
798                 TALLOC_FREE(subreq);
799                 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
800                 return;
801         }
802
803         cli_nps->read.ofs = 0;
804         cli_nps->read.left = received;
805         memcpy(cli_nps->read.buf, rcvbuf, received);
806         TALLOC_FREE(subreq);
807
808         tstream_cli_np_readv_read_next(req);
809 }
810
811 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq);
812
813 static void tstream_cli_np_readv_error(struct tevent_req *req);
814
815 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
816                                                 int error,
817                                                 const char *location)
818 {
819         struct tstream_cli_np_readv_state *state =
820                 tevent_req_data(req,
821                 struct tstream_cli_np_readv_state);
822         struct tstream_cli_np *cli_nps =
823                 tstream_context_data(state->stream,
824                 struct tstream_cli_np);
825         struct tevent_req *subreq;
826
827         state->error.val = error;
828         state->error.location = location;
829
830         if (!cli_state_is_connected(cli_nps->cli)) {
831                 /* return the original error */
832                 tstream_cli_np_readv_error(req);
833                 return;
834         }
835
836         subreq = cli_close_send(state, state->ev, cli_nps->cli, cli_nps->fnum);
837         if (subreq == NULL) {
838                 /* return the original error */
839                 tstream_cli_np_readv_error(req);
840                 return;
841         }
842         tevent_req_set_callback(subreq,
843                                 tstream_cli_np_readv_disconnect_done,
844                                 req);
845 }
846
847 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq)
848 {
849         struct tevent_req *req =
850                 tevent_req_callback_data(subreq, struct tevent_req);
851         struct tstream_cli_np_readv_state *state =
852                 tevent_req_data(req, struct tstream_cli_np_readv_state);
853         struct tstream_cli_np *cli_nps =
854                 tstream_context_data(state->stream, struct tstream_cli_np);
855         NTSTATUS status;
856
857         status = cli_close_recv(subreq);
858         TALLOC_FREE(subreq);
859
860         cli_nps->cli = NULL;
861
862         tstream_cli_np_readv_error(req);
863 }
864
865 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
866                                                struct tevent_immediate *im,
867                                                void *private_data);
868
869 static void tstream_cli_np_readv_error(struct tevent_req *req)
870 {
871         struct tstream_cli_np_readv_state *state =
872                 tevent_req_data(req,
873                 struct tstream_cli_np_readv_state);
874         struct tstream_cli_np *cli_nps =
875                 tstream_context_data(state->stream,
876                 struct tstream_cli_np);
877
878         if (cli_nps->trans.write_req == NULL) {
879                 /* return the original error */
880                 _tevent_req_error(req, state->error.val, state->error.location);
881                 return;
882         }
883
884         if (state->trans.im == NULL) {
885                 /* return the original error */
886                 _tevent_req_error(req, state->error.val, state->error.location);
887                 return;
888         }
889
890         tevent_schedule_immediate(state->trans.im, state->ev,
891                                   tstream_cli_np_readv_error_trigger, req);
892
893         /* return the original error for writev */
894         _tevent_req_error(cli_nps->trans.write_req,
895                           state->error.val, state->error.location);
896 }
897
898 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
899                                                struct tevent_immediate *im,
900                                                void *private_data)
901 {
902         struct tevent_req *req =
903                 talloc_get_type_abort(private_data,
904                 struct tevent_req);
905         struct tstream_cli_np_readv_state *state =
906                 tevent_req_data(req,
907                 struct tstream_cli_np_readv_state);
908
909         /* return the original error */
910         _tevent_req_error(req, state->error.val, state->error.location);
911 }
912
913 static int tstream_cli_np_readv_recv(struct tevent_req *req,
914                                    int *perrno)
915 {
916         struct tstream_cli_np_readv_state *state =
917                 tevent_req_data(req, struct tstream_cli_np_readv_state);
918         int ret;
919
920         ret = tsocket_simple_int_recv(req, perrno);
921         if (ret == 0) {
922                 ret = state->ret;
923         }
924
925         tevent_req_received(req);
926         return ret;
927 }
928
929 struct tstream_cli_np_disconnect_state {
930         struct tstream_context *stream;
931 };
932
933 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq);
934
935 static struct tevent_req *tstream_cli_np_disconnect_send(TALLOC_CTX *mem_ctx,
936                                                 struct tevent_context *ev,
937                                                 struct tstream_context *stream)
938 {
939         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
940                                          struct tstream_cli_np);
941         struct tevent_req *req;
942         struct tstream_cli_np_disconnect_state *state;
943         struct tevent_req *subreq;
944
945         req = tevent_req_create(mem_ctx, &state,
946                                 struct tstream_cli_np_disconnect_state);
947         if (req == NULL) {
948                 return NULL;
949         }
950
951         state->stream = stream;
952
953         if (!cli_state_is_connected(cli_nps->cli)) {
954                 tevent_req_error(req, ENOTCONN);
955                 return tevent_req_post(req, ev);
956         }
957
958         subreq = cli_close_send(state, ev, cli_nps->cli, cli_nps->fnum);
959         if (tevent_req_nomem(subreq, req)) {
960                 return tevent_req_post(req, ev);
961         }
962         tevent_req_set_callback(subreq, tstream_cli_np_disconnect_done, req);
963
964         return req;
965 }
966
967 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq)
968 {
969         struct tevent_req *req = tevent_req_callback_data(subreq,
970                                                           struct tevent_req);
971         struct tstream_cli_np_disconnect_state *state =
972                 tevent_req_data(req, struct tstream_cli_np_disconnect_state);
973         struct tstream_cli_np *cli_nps =
974                 tstream_context_data(state->stream, struct tstream_cli_np);
975         NTSTATUS status;
976
977         status = cli_close_recv(subreq);
978         TALLOC_FREE(subreq);
979         if (!NT_STATUS_IS_OK(status)) {
980                 tevent_req_error(req, EIO);
981                 return;
982         }
983
984         cli_nps->cli = NULL;
985
986         tevent_req_done(req);
987 }
988
989 static int tstream_cli_np_disconnect_recv(struct tevent_req *req,
990                                           int *perrno)
991 {
992         int ret;
993
994         ret = tsocket_simple_int_recv(req, perrno);
995
996         tevent_req_received(req);
997         return ret;
998 }
999
1000 static const struct tstream_context_ops tstream_cli_np_ops = {
1001         .name                   = "cli_np",
1002
1003         .pending_bytes          = tstream_cli_np_pending_bytes,
1004
1005         .readv_send             = tstream_cli_np_readv_send,
1006         .readv_recv             = tstream_cli_np_readv_recv,
1007
1008         .writev_send            = tstream_cli_np_writev_send,
1009         .writev_recv            = tstream_cli_np_writev_recv,
1010
1011         .disconnect_send        = tstream_cli_np_disconnect_send,
1012         .disconnect_recv        = tstream_cli_np_disconnect_recv,
1013 };
1014
1015 NTSTATUS _tstream_cli_np_existing(TALLOC_CTX *mem_ctx,
1016                                   struct cli_state *cli,
1017                                   uint16_t fnum,
1018                                   struct tstream_context **_stream,
1019                                   const char *location)
1020 {
1021         struct tstream_context *stream;
1022         struct tstream_cli_np *cli_nps;
1023
1024         stream = tstream_context_create(mem_ctx,
1025                                         &tstream_cli_np_ops,
1026                                         &cli_nps,
1027                                         struct tstream_cli_np,
1028                                         location);
1029         if (!stream) {
1030                 return NT_STATUS_NO_MEMORY;
1031         }
1032         ZERO_STRUCTP(cli_nps);
1033
1034         cli_nps->cli = cli;
1035         cli_nps->fnum = fnum;
1036
1037         *_stream = stream;
1038         return NT_STATUS_OK;
1039 }