libcli/util Rename common map_nt_error_from_unix to avoid duplicate symbol
[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                 tstream_read_pdu_blob_full_fn_t *full_fn;
34                 void *full_private;
35         } caller;
36
37         DATA_BLOB pdu_blob;
38         struct iovec tmp_vector;
39 };
40
41 static void tstream_read_pdu_blob_done(struct tevent_req *subreq);
42
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,
48                                 void *full_private)
49 {
50         struct tevent_req *req;
51         struct tstream_read_pdu_blob_state *state;
52         struct tevent_req *subreq;
53         uint8_t *buf;
54
55         req = tevent_req_create(mem_ctx, &state,
56                                 struct tstream_read_pdu_blob_state);
57         if (!req) {
58                 return NULL;
59         }
60
61         state->caller.ev                = ev;
62         state->caller.stream            = stream;
63         state->caller.full_fn           = full_fn;
64         state->caller.full_private      = full_private;
65
66         if (initial_read_size == 0) {
67                 tevent_req_error(req, EINVAL);
68                 return tevent_req_post(req, ev);
69         }
70
71         buf = talloc_array(state, uint8_t, initial_read_size);
72         if (tevent_req_nomem(buf, req)) {
73                 return tevent_req_post(req, ev);
74         }
75         state->pdu_blob.data = buf;
76         state->pdu_blob.length = initial_read_size;
77
78         state->tmp_vector.iov_base = (char *) buf;
79         state->tmp_vector.iov_len = initial_read_size;
80
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);
84         }
85         tevent_req_set_callback(subreq, tstream_read_pdu_blob_done, req);
86
87         return req;
88 }
89
90 static void tstream_read_pdu_blob_done(struct tevent_req *subreq)
91 {
92         struct tevent_req *req =
93                 tevent_req_callback_data(subreq,
94                 struct tevent_req);
95         struct tstream_read_pdu_blob_state *state =
96                 tevent_req_data(req,
97                 struct tstream_read_pdu_blob_state);
98         ssize_t ret;
99         int sys_errno;
100         size_t old_buf_size = state->pdu_blob.length;
101         size_t new_buf_size = 0;
102         size_t pdu_size = 0;
103         NTSTATUS status;
104         uint8_t *buf;
105
106         ret = tstream_readv_recv(subreq, &sys_errno);
107         TALLOC_FREE(subreq);
108         if (ret == -1) {
109                 status = map_nt_error_from_unix_common(sys_errno);
110                 tevent_req_nterror(req, status);
111                 return;
112         }
113
114         status = state->caller.full_fn(state->caller.full_private,
115                                        state->pdu_blob, &pdu_size);
116         if (NT_STATUS_IS_OK(status)) {
117                 tevent_req_done(req);
118                 return;
119         } else if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
120                 /* more to get */
121                 if (pdu_size > 0) {
122                         new_buf_size = pdu_size;
123                 } else {
124                         /* we don't know the size yet, so get one more byte */
125                         new_buf_size = old_buf_size + 1;
126                 }
127         } else if (!NT_STATUS_IS_OK(status)) {
128                 tevent_req_nterror(req, status);
129                 return;
130         }
131
132         buf = talloc_realloc(state, state->pdu_blob.data, uint8_t, new_buf_size);
133         if (tevent_req_nomem(buf, req)) {
134                 return;
135         }
136         state->pdu_blob.data = buf;
137         state->pdu_blob.length = new_buf_size;
138
139         state->tmp_vector.iov_base = (char *) (buf + old_buf_size);
140         state->tmp_vector.iov_len = new_buf_size - old_buf_size;
141
142         subreq = tstream_readv_send(state,
143                                     state->caller.ev,
144                                     state->caller.stream,
145                                     &state->tmp_vector,
146                                     1);
147         if (tevent_req_nomem(subreq, req)) {
148                 return;
149         }
150         tevent_req_set_callback(subreq, tstream_read_pdu_blob_done, req);
151 }
152
153 NTSTATUS tstream_read_pdu_blob_recv(struct tevent_req *req,
154                                     TALLOC_CTX *mem_ctx,
155                                     DATA_BLOB *pdu_blob)
156 {
157         struct tstream_read_pdu_blob_state *state = tevent_req_data(req,
158                                         struct tstream_read_pdu_blob_state);
159         NTSTATUS status;
160
161         if (tevent_req_is_nterror(req, &status)) {
162                 tevent_req_received(req);
163                 return status;
164         }
165
166         *pdu_blob = state->pdu_blob;
167         talloc_steal(mem_ctx, pdu_blob->data);
168
169         tevent_req_received(req);
170         return NT_STATUS_OK;
171 }
172