s3: Add an async smbsock_connect
[Samba.git] / source3 / lib / wb_reqtrans.c
blobdbea8b6686df30f2d2810783ad370c69799f38a8
1 /*
2 Unix SMB/CIFS implementation.
4 Async transfer of winbindd_request and _response structs
6 Copyright (C) Volker Lendecke 2008
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "wbc_async.h"
25 #undef DBGC_CLASS
26 #define DBGC_CLASS DBGC_WINBIND
28 wbcErr map_wbc_err_from_errno(int error)
30 switch(error) {
31 case EPERM:
32 case EACCES:
33 return WBC_ERR_AUTH_ERROR;
34 case ENOMEM:
35 return WBC_ERR_NO_MEMORY;
36 case EIO:
37 default:
38 return WBC_ERR_UNKNOWN_FAILURE;
42 bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err)
44 enum tevent_req_state state;
45 uint64_t error;
46 if (!tevent_req_is_error(req, &state, &error)) {
47 *pwbc_err = WBC_ERR_SUCCESS;
48 return false;
51 switch (state) {
52 case TEVENT_REQ_USER_ERROR:
53 *pwbc_err = error;
54 break;
55 case TEVENT_REQ_TIMED_OUT:
56 *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
57 break;
58 case TEVENT_REQ_NO_MEMORY:
59 *pwbc_err = WBC_ERR_NO_MEMORY;
60 break;
61 default:
62 *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
63 break;
65 return true;
68 wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req)
70 wbcErr wbc_err;
72 if (tevent_req_is_wbcerr(req, &wbc_err)) {
73 return wbc_err;
76 return WBC_ERR_SUCCESS;
79 struct req_read_state {
80 struct winbindd_request *wb_req;
81 size_t max_extra_data;
84 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data);
85 static void wb_req_read_done(struct tevent_req *subreq);
87 struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
88 struct tevent_context *ev,
89 int fd, size_t max_extra_data)
91 struct tevent_req *result, *subreq;
92 struct req_read_state *state;
94 result = tevent_req_create(mem_ctx, &state, struct req_read_state);
95 if (result == NULL) {
96 return NULL;
98 state->max_extra_data = max_extra_data;
100 subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
101 if (subreq == NULL) {
102 goto nomem;
105 tevent_req_set_callback(subreq, wb_req_read_done, result);
106 return result;
107 nomem:
108 TALLOC_FREE(result);
109 return NULL;
112 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
114 struct req_read_state *state = talloc_get_type_abort(
115 private_data, struct req_read_state);
116 struct winbindd_request *req = (struct winbindd_request *)buf;
118 if (buflen == 4) {
119 if (req->length != sizeof(struct winbindd_request)) {
120 DEBUG(0, ("wb_req_read_len: Invalid request size "
121 "received: %d (expected %d)\n",
122 (int)req->length,
123 (int)sizeof(struct winbindd_request)));
124 return -1;
126 return sizeof(struct winbindd_request) - 4;
129 if ((state->max_extra_data != 0)
130 && (req->extra_len > state->max_extra_data)) {
131 DEBUG(3, ("Got request with %d bytes extra data on "
132 "unprivileged socket\n", (int)req->extra_len));
133 return -1;
136 return req->extra_len;
139 static void wb_req_read_done(struct tevent_req *subreq)
141 struct tevent_req *req = tevent_req_callback_data(
142 subreq, struct tevent_req);
143 struct req_read_state *state = tevent_req_data(
144 req, struct req_read_state);
145 int err;
146 ssize_t ret;
147 uint8_t *buf;
149 ret = read_packet_recv(subreq, state, &buf, &err);
150 TALLOC_FREE(subreq);
151 if (ret == -1) {
152 tevent_req_error(req, map_wbc_err_from_errno(err));
153 return;
156 state->wb_req = (struct winbindd_request *)buf;
158 if (state->wb_req->extra_len != 0) {
159 state->wb_req->extra_data.data =
160 (char *)buf + sizeof(struct winbindd_request);
161 } else {
162 state->wb_req->extra_data.data = NULL;
164 tevent_req_done(req);
167 wbcErr wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
168 struct winbindd_request **preq)
170 struct req_read_state *state = tevent_req_data(
171 req, struct req_read_state);
172 wbcErr wbc_err;
174 if (tevent_req_is_wbcerr(req, &wbc_err)) {
175 return wbc_err;
177 *preq = talloc_move(mem_ctx, &state->wb_req);
178 return WBC_ERR_SUCCESS;
181 struct req_write_state {
182 struct iovec iov[2];
185 static void wb_req_write_done(struct tevent_req *subreq);
187 struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
188 struct tevent_context *ev,
189 struct tevent_queue *queue, int fd,
190 struct winbindd_request *wb_req)
192 struct tevent_req *result, *subreq;
193 struct req_write_state *state;
194 int count = 1;
196 result = tevent_req_create(mem_ctx, &state, struct req_write_state);
197 if (result == NULL) {
198 return NULL;
201 state->iov[0].iov_base = wb_req;
202 state->iov[0].iov_len = sizeof(struct winbindd_request);
204 if (wb_req->extra_len != 0) {
205 state->iov[1].iov_base = wb_req->extra_data.data;
206 state->iov[1].iov_len = wb_req->extra_len;
207 count = 2;
210 subreq = writev_send(state, ev, queue, fd, state->iov, count);
211 if (subreq == NULL) {
212 goto fail;
214 tevent_req_set_callback(subreq, wb_req_write_done, result);
215 return result;
217 fail:
218 TALLOC_FREE(result);
219 return NULL;
222 static void wb_req_write_done(struct tevent_req *subreq)
224 struct tevent_req *req = tevent_req_callback_data(
225 subreq, struct tevent_req);
226 int err;
227 ssize_t ret;
229 ret = writev_recv(subreq, &err);
230 TALLOC_FREE(subreq);
231 if (ret < 0) {
232 tevent_req_error(req, map_wbc_err_from_errno(err));
233 return;
235 tevent_req_done(req);
238 wbcErr wb_req_write_recv(struct tevent_req *req)
240 return tevent_req_simple_recv_wbcerr(req);
243 struct resp_read_state {
244 struct winbindd_response *wb_resp;
247 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data);
248 static void wb_resp_read_done(struct tevent_req *subreq);
250 struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
251 struct tevent_context *ev, int fd)
253 struct tevent_req *result, *subreq;
254 struct resp_read_state *state;
256 result = tevent_req_create(mem_ctx, &state, struct resp_read_state);
257 if (result == NULL) {
258 return NULL;
261 subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
262 if (subreq == NULL) {
263 goto nomem;
265 tevent_req_set_callback(subreq, wb_resp_read_done, result);
266 return result;
268 nomem:
269 TALLOC_FREE(result);
270 return NULL;
273 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
275 struct winbindd_response *resp = (struct winbindd_response *)buf;
277 if (buflen == 4) {
278 if (resp->length < sizeof(struct winbindd_response)) {
279 DEBUG(0, ("wb_resp_read_len: Invalid response size "
280 "received: %d (expected at least%d)\n",
281 (int)resp->length,
282 (int)sizeof(struct winbindd_response)));
283 return -1;
286 return resp->length - buflen;
289 static void wb_resp_read_done(struct tevent_req *subreq)
291 struct tevent_req *req = tevent_req_callback_data(
292 subreq, struct tevent_req);
293 struct resp_read_state *state = tevent_req_data(
294 req, struct resp_read_state);
295 uint8_t *buf;
296 int err;
297 ssize_t ret;
299 ret = read_packet_recv(subreq, state, &buf, &err);
300 TALLOC_FREE(subreq);
301 if (ret == -1) {
302 tevent_req_error(req, map_wbc_err_from_errno(err));
303 return;
306 state->wb_resp = (struct winbindd_response *)buf;
308 if (state->wb_resp->length > sizeof(struct winbindd_response)) {
309 state->wb_resp->extra_data.data =
310 (char *)buf + sizeof(struct winbindd_response);
311 } else {
312 state->wb_resp->extra_data.data = NULL;
314 tevent_req_done(req);
317 wbcErr wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
318 struct winbindd_response **presp)
320 struct resp_read_state *state = tevent_req_data(
321 req, struct resp_read_state);
322 wbcErr wbc_err;
324 if (tevent_req_is_wbcerr(req, &wbc_err)) {
325 return wbc_err;
327 *presp = talloc_move(mem_ctx, &state->wb_resp);
328 return WBC_ERR_SUCCESS;
331 struct resp_write_state {
332 struct iovec iov[2];
335 static void wb_resp_write_done(struct tevent_req *subreq);
337 struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
338 struct tevent_context *ev,
339 struct tevent_queue *queue, int fd,
340 struct winbindd_response *wb_resp)
342 struct tevent_req *result, *subreq;
343 struct resp_write_state *state;
344 int count = 1;
346 result = tevent_req_create(mem_ctx, &state, struct resp_write_state);
347 if (result == NULL) {
348 return NULL;
351 state->iov[0].iov_base = wb_resp;
352 state->iov[0].iov_len = sizeof(struct winbindd_response);
354 if (wb_resp->length > sizeof(struct winbindd_response)) {
355 state->iov[1].iov_base = wb_resp->extra_data.data;
356 state->iov[1].iov_len =
357 wb_resp->length - sizeof(struct winbindd_response);
358 count = 2;
361 subreq = writev_send(state, ev, queue, fd, state->iov, count);
362 if (subreq == NULL) {
363 goto fail;
365 tevent_req_set_callback(subreq, wb_resp_write_done, result);
366 return result;
368 fail:
369 TALLOC_FREE(result);
370 return NULL;
373 static void wb_resp_write_done(struct tevent_req *subreq)
375 struct tevent_req *req = tevent_req_callback_data(
376 subreq, struct tevent_req);
377 int err;
378 ssize_t ret;
380 ret = writev_recv(subreq, &err);
381 TALLOC_FREE(subreq);
382 if (ret < 0) {
383 tevent_req_error(req, map_wbc_err_from_errno(err));
384 return;
386 tevent_req_done(req);
389 wbcErr wb_resp_write_recv(struct tevent_req *req)
391 return tevent_req_simple_recv_wbcerr(req);