2 * Unix SMB/CIFS implementation.
4 * Copyright (C) Stefan Metzmacher 2009
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/>.
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"
28 struct tstream_read_pdu_blob_state
{
29 /* this structs are owned by the caller */
31 struct tevent_context
*ev
;
32 struct tstream_context
*stream
;
33 tstream_read_pdu_blob_full_fn_t
*full_fn
;
38 struct iovec tmp_vector
;
41 static void tstream_read_pdu_blob_done(struct tevent_req
*subreq
);
43 struct tevent_req
*tstream_read_pdu_blob_send(TALLOC_CTX
*mem_ctx
,
44 struct tevent_context
*ev
,
45 struct tstream_context
*stream
,
46 size_t initial_read_size
,
47 tstream_read_pdu_blob_full_fn_t
*full_fn
,
50 struct tevent_req
*req
;
51 struct tstream_read_pdu_blob_state
*state
;
52 struct tevent_req
*subreq
;
55 req
= tevent_req_create(mem_ctx
, &state
,
56 struct tstream_read_pdu_blob_state
);
61 state
->caller
.ev
= ev
;
62 state
->caller
.stream
= stream
;
63 state
->caller
.full_fn
= full_fn
;
64 state
->caller
.full_private
= full_private
;
66 if (initial_read_size
== 0) {
67 tevent_req_error(req
, EINVAL
);
68 return tevent_req_post(req
, ev
);
71 buf
= talloc_array(state
, uint8_t, initial_read_size
);
72 if (tevent_req_nomem(buf
, req
)) {
73 return tevent_req_post(req
, ev
);
75 state
->pdu_blob
.data
= buf
;
76 state
->pdu_blob
.length
= initial_read_size
;
78 state
->tmp_vector
.iov_base
= (char *) buf
;
79 state
->tmp_vector
.iov_len
= initial_read_size
;
81 subreq
= tstream_readv_send(state
, ev
, stream
, &state
->tmp_vector
, 1);
82 if (tevent_req_nomem(subreq
, req
)) {
83 return tevent_req_post(req
, ev
);
85 tevent_req_set_callback(subreq
, tstream_read_pdu_blob_done
, req
);
90 static void tstream_read_pdu_blob_done(struct tevent_req
*subreq
)
92 struct tevent_req
*req
=
93 tevent_req_callback_data(subreq
,
95 struct tstream_read_pdu_blob_state
*state
=
97 struct tstream_read_pdu_blob_state
);
100 size_t old_buf_size
= state
->pdu_blob
.length
;
101 size_t new_buf_size
= 0;
106 ret
= tstream_readv_recv(subreq
, &sys_errno
);
109 status
= map_nt_error_from_unix_common(sys_errno
);
110 tevent_req_nterror(req
, status
);
114 status
= state
->caller
.full_fn(state
->caller
.stream
,
115 state
->caller
.full_private
,
116 state
->pdu_blob
, &pdu_size
);
117 if (NT_STATUS_IS_OK(status
)) {
118 tevent_req_done(req
);
120 } else if (NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) {
123 new_buf_size
= pdu_size
;
125 /* we don't know the size yet, so get one more byte */
126 new_buf_size
= old_buf_size
+ 1;
128 } else if (!NT_STATUS_IS_OK(status
)) {
129 tevent_req_nterror(req
, status
);
133 if (new_buf_size
<= old_buf_size
) {
134 tevent_req_nterror(req
, NT_STATUS_INVALID_BUFFER_SIZE
);
138 buf
= talloc_realloc(state
, state
->pdu_blob
.data
, uint8_t, new_buf_size
);
139 if (tevent_req_nomem(buf
, req
)) {
142 state
->pdu_blob
.data
= buf
;
143 state
->pdu_blob
.length
= new_buf_size
;
145 state
->tmp_vector
.iov_base
= (char *) (buf
+ old_buf_size
);
146 state
->tmp_vector
.iov_len
= new_buf_size
- old_buf_size
;
148 subreq
= tstream_readv_send(state
,
150 state
->caller
.stream
,
153 if (tevent_req_nomem(subreq
, req
)) {
156 tevent_req_set_callback(subreq
, tstream_read_pdu_blob_done
, req
);
159 NTSTATUS
tstream_read_pdu_blob_recv(struct tevent_req
*req
,
163 struct tstream_read_pdu_blob_state
*state
= tevent_req_data(req
,
164 struct tstream_read_pdu_blob_state
);
167 if (tevent_req_is_nterror(req
, &status
)) {
168 tevent_req_received(req
);
172 *pdu_blob
= state
->pdu_blob
;
173 talloc_steal(mem_ctx
, pdu_blob
->data
);
175 tevent_req_received(req
);
179 NTSTATUS
tstream_full_request_u32(struct tstream_context
*stream
,
181 DATA_BLOB blob
, size_t *size
)
183 if (blob
.length
< 4) {
184 return STATUS_MORE_ENTRIES
;
186 *size
= 4 + RIVAL(blob
.data
, 0);
187 if (*size
> blob
.length
) {
188 return STATUS_MORE_ENTRIES
;
193 NTSTATUS
tstream_full_request_u16(struct tstream_context
*stream
,
195 DATA_BLOB blob
, size_t *size
)
197 if (blob
.length
< 2) {
198 return STATUS_MORE_ENTRIES
;
200 *size
= 2 + RSVAL(blob
.data
, 0);
201 if (*size
> blob
.length
) {
202 return STATUS_MORE_ENTRIES
;