s4:libcli/util/tstream.c - Need to include "system/network.h"
[samba.git] / libcli / util / tstream.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *
4  *  Copyright (C) Stefan Metzmacher 2009
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 <tevent.h>
22 #include "system/filesys.h"
23 #include "system/network.h"
24 #include "../lib/tsocket/tsocket.h"
25 #include "../libcli/util/tstream.h"
26 #include "../lib/util/tevent_ntstatus.h"
27
28 struct tstream_read_pdu_blob_state {
29         /* this structs are owned by the caller */
30         struct {
31                 struct tevent_context *ev;
32                 struct tstream_context *stream;
33                 NTSTATUS (*full_fn)(void *private_data,
34                                     DATA_BLOB blob,
35                                     size_t *packet_size);
36                 void *full_private;
37         } caller;
38
39         DATA_BLOB pdu_blob;
40         struct iovec tmp_vector;
41 };
42
43 static void tstream_read_pdu_blob_done(struct tevent_req *subreq);
44
45 struct tevent_req *tstream_read_pdu_blob_send(TALLOC_CTX *mem_ctx,
46                                 struct tevent_context *ev,
47                                 struct tstream_context *stream,
48                                 size_t initial_read_size,
49                                 NTSTATUS (*full_fn)(void *private_data,
50                                                     DATA_BLOB blob,
51                                                     size_t *packet_size),
52                                 void *full_private)
53 {
54         struct tevent_req *req;
55         struct tstream_read_pdu_blob_state *state;
56         struct tevent_req *subreq;
57         uint8_t *buf;
58
59         req = tevent_req_create(mem_ctx, &state,
60                                 struct tstream_read_pdu_blob_state);
61         if (!req) {
62                 return NULL;
63         }
64
65         state->caller.ev                = ev;
66         state->caller.stream            = stream;
67         state->caller.full_fn           = full_fn;
68         state->caller.full_private      = full_private;
69
70         if (initial_read_size == 0) {
71                 tevent_req_error(req, EINVAL);
72                 return tevent_req_post(req, ev);
73         }
74
75         buf = talloc_array(state, uint8_t, initial_read_size);
76         if (tevent_req_nomem(buf, req)) {
77                 return tevent_req_post(req, ev);
78         }
79         state->pdu_blob.data = buf;
80         state->pdu_blob.length = initial_read_size;
81
82         state->tmp_vector.iov_base = buf;
83         state->tmp_vector.iov_len = initial_read_size;
84
85         subreq = tstream_readv_send(state, ev, stream, &state->tmp_vector, 1);
86         if (tevent_req_nomem(subreq, req)) {
87                 return tevent_req_post(req, ev);
88         }
89         tevent_req_set_callback(subreq, tstream_read_pdu_blob_done, req);
90
91         return req;
92 }
93
94 static void tstream_read_pdu_blob_done(struct tevent_req *subreq)
95 {
96         struct tevent_req *req =
97                 tevent_req_callback_data(subreq,
98                 struct tevent_req);
99         struct tstream_read_pdu_blob_state *state =
100                 tevent_req_data(req,
101                 struct tstream_read_pdu_blob_state);
102         ssize_t ret;
103         int sys_errno;
104         size_t pdu_size;
105         NTSTATUS status;
106         uint8_t *buf;
107
108         ret = tstream_readv_recv(subreq, &sys_errno);
109         TALLOC_FREE(subreq);
110         if (ret == -1) {
111                 status = map_nt_error_from_unix(sys_errno);
112                 tevent_req_nterror(req, status);
113                 return;
114         }
115
116         status = state->caller.full_fn(state->caller.full_private,
117                                        state->pdu_blob, &pdu_size);
118         if (NT_STATUS_IS_OK(status)) {
119                 tevent_req_done(req);
120                 return;
121         } else if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
122                 /* more to get */
123         } else if (!NT_STATUS_IS_OK(status)) {
124                 tevent_req_nterror(req, status);
125                 return;
126         }
127
128         buf = talloc_realloc(state, state->pdu_blob.data, uint8_t, pdu_size);
129         if (tevent_req_nomem(buf, req)) {
130                 return;
131         }
132         state->pdu_blob.data = buf;
133         state->pdu_blob.length = pdu_size;
134
135         state->tmp_vector.iov_base = buf + state->tmp_vector.iov_len;
136         state->tmp_vector.iov_len = pdu_size - state->tmp_vector.iov_len;
137
138         subreq = tstream_readv_send(state,
139                                     state->caller.ev,
140                                     state->caller.stream,
141                                     &state->tmp_vector,
142                                     1);
143         if (tevent_req_nomem(subreq, req)) {
144                 return;
145         }
146         tevent_req_set_callback(subreq, tstream_read_pdu_blob_done, req);
147 }
148
149 NTSTATUS tstream_read_pdu_blob_recv(struct tevent_req *req,
150                                     TALLOC_CTX *mem_ctx,
151                                     DATA_BLOB *pdu_blob)
152 {
153         struct tstream_read_pdu_blob_state *state = tevent_req_data(req,
154                                         struct tstream_read_pdu_blob_state);
155         NTSTATUS status;
156
157         if (tevent_req_is_nterror(req, &status)) {
158                 tevent_req_received(req);
159                 return status;
160         }
161
162         *pdu_blob = state->pdu_blob;
163         talloc_steal(mem_ctx, pdu_blob->data);
164
165         tevent_req_received(req);
166         return NT_STATUS_OK;
167 }
168