libwbclient: Add async call framework.
[Samba/gebeck_regimport.git] / nsswitch / libwbclient / wb_reqtrans.c
blob84ed7198f2f21f98f7c1734b7f37e268bf5fc3e1
1 /*
2 Unix SMB/CIFS implementation.
4 Async transfer of winbindd_request and _response structs
6 Copyright (C) Volker Lendecke 2008
8 ** NOTE! The following LGPL license applies to the wbclient
9 ** library. This does NOT imply that all of Samba is released
10 ** under the LGPL
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 3 of the License, or (at your option) any later version.
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Library General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "replace.h"
27 #include "system/filesys.h"
28 #include "system/network.h"
29 #include <talloc.h>
30 #include <tevent.h>
31 struct fd_event;
32 struct event_context;
33 #include "lib/async_req/async_sock.h"
34 #include "lib/util/tevent_unix.h"
35 #include "nsswitch/winbind_struct_protocol.h"
36 #include "nsswitch/libwbclient/wbclient.h"
37 #include "nsswitch/libwbclient/wbc_async.h"
39 #ifdef DBGC_CLASS
40 #undef DBGC_CLASS
41 #define DBGC_CLASS DBGC_WINBIND
42 #endif
44 struct req_read_state {
45 struct winbindd_request *wb_req;
46 size_t max_extra_data;
47 ssize_t ret;
50 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data);
51 static void wb_req_read_done(struct tevent_req *subreq);
53 struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
54 struct tevent_context *ev,
55 int fd, size_t max_extra_data)
57 struct tevent_req *req, *subreq;
58 struct req_read_state *state;
60 req = tevent_req_create(mem_ctx, &state, struct req_read_state);
61 if (req == NULL) {
62 return NULL;
64 state->max_extra_data = max_extra_data;
66 subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
67 if (tevent_req_nomem(subreq, req)) {
68 return tevent_req_post(req, ev);
70 tevent_req_set_callback(subreq, wb_req_read_done, req);
71 return req;
74 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
76 struct req_read_state *state = talloc_get_type_abort(
77 private_data, struct req_read_state);
78 struct winbindd_request *req = (struct winbindd_request *)buf;
80 if (buflen == 4) {
81 if (req->length != sizeof(struct winbindd_request)) {
82 DEBUG(0, ("wb_req_read_len: Invalid request size "
83 "received: %d (expected %d)\n",
84 (int)req->length,
85 (int)sizeof(struct winbindd_request)));
86 return -1;
88 return sizeof(struct winbindd_request) - 4;
91 if ((state->max_extra_data != 0)
92 && (req->extra_len > state->max_extra_data)) {
93 DEBUG(3, ("Got request with %d bytes extra data on "
94 "unprivileged socket\n", (int)req->extra_len));
95 return -1;
98 return req->extra_len;
101 static void wb_req_read_done(struct tevent_req *subreq)
103 struct tevent_req *req = tevent_req_callback_data(
104 subreq, struct tevent_req);
105 struct req_read_state *state = tevent_req_data(
106 req, struct req_read_state);
107 int err;
108 uint8_t *buf;
110 state->ret = read_packet_recv(subreq, state, &buf, &err);
111 TALLOC_FREE(subreq);
112 if (state->ret == -1) {
113 tevent_req_error(req, err);
114 return;
117 state->wb_req = (struct winbindd_request *)buf;
119 if (state->wb_req->extra_len != 0) {
120 state->wb_req->extra_data.data =
121 (char *)buf + sizeof(struct winbindd_request);
122 } else {
123 state->wb_req->extra_data.data = NULL;
125 tevent_req_done(req);
128 ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
129 struct winbindd_request **preq, int *err)
131 struct req_read_state *state = tevent_req_data(
132 req, struct req_read_state);
134 if (tevent_req_is_unix_error(req, err)) {
135 return -1;
137 *preq = talloc_move(mem_ctx, &state->wb_req);
138 return state->ret;
141 struct req_write_state {
142 struct iovec iov[2];
143 ssize_t ret;
146 static void wb_req_write_done(struct tevent_req *subreq);
148 struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
149 struct tevent_context *ev,
150 struct tevent_queue *queue, int fd,
151 struct winbindd_request *wb_req)
153 struct tevent_req *req, *subreq;
154 struct req_write_state *state;
155 int count = 1;
157 req = tevent_req_create(mem_ctx, &state, struct req_write_state);
158 if (req == NULL) {
159 return NULL;
162 state->iov[0].iov_base = (void *)wb_req;
163 state->iov[0].iov_len = sizeof(struct winbindd_request);
165 if (wb_req->extra_len != 0) {
166 state->iov[1].iov_base = (void *)wb_req->extra_data.data;
167 state->iov[1].iov_len = wb_req->extra_len;
168 count = 2;
171 subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
172 if (tevent_req_nomem(subreq, req)) {
173 return tevent_req_post(req, ev);
175 tevent_req_set_callback(subreq, wb_req_write_done, req);
176 return req;
179 static void wb_req_write_done(struct tevent_req *subreq)
181 struct tevent_req *req = tevent_req_callback_data(
182 subreq, struct tevent_req);
183 struct req_write_state *state = tevent_req_data(
184 req, struct req_write_state);
185 int err;
187 state->ret = writev_recv(subreq, &err);
188 TALLOC_FREE(subreq);
189 if (state->ret < 0) {
190 tevent_req_error(req, err);
191 return;
193 tevent_req_done(req);
196 ssize_t wb_req_write_recv(struct tevent_req *req, int *err)
198 struct req_write_state *state = tevent_req_data(
199 req, struct req_write_state);
201 if (tevent_req_is_unix_error(req, err)) {
202 return -1;
204 return state->ret;
207 struct resp_read_state {
208 struct winbindd_response *wb_resp;
209 ssize_t ret;
212 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data);
213 static void wb_resp_read_done(struct tevent_req *subreq);
215 struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
216 struct tevent_context *ev, int fd)
218 struct tevent_req *req, *subreq;
219 struct resp_read_state *state;
221 req = tevent_req_create(mem_ctx, &state, struct resp_read_state);
222 if (req == NULL) {
223 return NULL;
226 subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
227 if (tevent_req_nomem(subreq, req)) {
228 return tevent_req_post(req, ev);
230 tevent_req_set_callback(subreq, wb_resp_read_done, req);
231 return req;
234 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
236 struct winbindd_response *resp = (struct winbindd_response *)buf;
238 if (buflen == 4) {
239 if (resp->length < sizeof(struct winbindd_response)) {
240 DEBUG(0, ("wb_resp_read_len: Invalid response size "
241 "received: %d (expected at least%d)\n",
242 (int)resp->length,
243 (int)sizeof(struct winbindd_response)));
244 return -1;
247 return resp->length - buflen;
250 static void wb_resp_read_done(struct tevent_req *subreq)
252 struct tevent_req *req = tevent_req_callback_data(
253 subreq, struct tevent_req);
254 struct resp_read_state *state = tevent_req_data(
255 req, struct resp_read_state);
256 uint8_t *buf;
257 int err;
259 state->ret = read_packet_recv(subreq, state, &buf, &err);
260 TALLOC_FREE(subreq);
261 if (state->ret == -1) {
262 tevent_req_error(req, err);
263 return;
266 state->wb_resp = (struct winbindd_response *)buf;
268 if (state->wb_resp->length > sizeof(struct winbindd_response)) {
269 state->wb_resp->extra_data.data =
270 (char *)buf + sizeof(struct winbindd_response);
271 } else {
272 state->wb_resp->extra_data.data = NULL;
274 tevent_req_done(req);
277 ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
278 struct winbindd_response **presp, int *err)
280 struct resp_read_state *state = tevent_req_data(
281 req, struct resp_read_state);
283 if (tevent_req_is_unix_error(req, err)) {
284 return -1;
286 *presp = talloc_move(mem_ctx, &state->wb_resp);
287 return state->ret;
290 struct resp_write_state {
291 struct iovec iov[2];
292 ssize_t ret;
295 static void wb_resp_write_done(struct tevent_req *subreq);
297 struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
298 struct tevent_context *ev,
299 struct tevent_queue *queue, int fd,
300 struct winbindd_response *wb_resp)
302 struct tevent_req *req, *subreq;
303 struct resp_write_state *state;
304 int count = 1;
306 req = tevent_req_create(mem_ctx, &state, struct resp_write_state);
307 if (req == NULL) {
308 return NULL;
311 state->iov[0].iov_base = (void *)wb_resp;
312 state->iov[0].iov_len = sizeof(struct winbindd_response);
314 if (wb_resp->length > sizeof(struct winbindd_response)) {
315 state->iov[1].iov_base = (void *)wb_resp->extra_data.data;
316 state->iov[1].iov_len =
317 wb_resp->length - sizeof(struct winbindd_response);
318 count = 2;
321 subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
322 if (tevent_req_nomem(subreq, req)) {
323 return tevent_req_post(req, ev);
325 tevent_req_set_callback(subreq, wb_resp_write_done, req);
326 return req;
329 static void wb_resp_write_done(struct tevent_req *subreq)
331 struct tevent_req *req = tevent_req_callback_data(
332 subreq, struct tevent_req);
333 struct resp_write_state *state = tevent_req_data(
334 req, struct resp_write_state);
335 int err;
337 state->ret = writev_recv(subreq, &err);
338 TALLOC_FREE(subreq);
339 if (state->ret < 0) {
340 tevent_req_error(req, err);
341 return;
343 tevent_req_done(req);
346 ssize_t wb_resp_write_recv(struct tevent_req *req, int *err)
348 struct resp_write_state *state = tevent_req_data(
349 req, struct resp_write_state);
351 if (tevent_req_is_unix_error(req, err)) {
352 return -1;
354 return state->ret;
357 struct wb_simple_trans_state {
358 struct tevent_context *ev;
359 int fd;
360 struct winbindd_response *wb_resp;
363 static void wb_simple_trans_write_done(struct tevent_req *subreq);
364 static void wb_simple_trans_read_done(struct tevent_req *subreq);
366 struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx,
367 struct tevent_context *ev,
368 struct tevent_queue *queue, int fd,
369 struct winbindd_request *wb_req)
371 struct tevent_req *req, *subreq;
372 struct wb_simple_trans_state *state;
374 req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state);
375 if (req == NULL) {
376 return NULL;
379 wb_req->length = sizeof(struct winbindd_request);
381 state->ev = ev;
382 state->fd = fd;
384 subreq = wb_req_write_send(state, ev, queue, fd, wb_req);
385 if (tevent_req_nomem(subreq, req)) {
386 return tevent_req_post(req, ev);
388 tevent_req_set_callback(subreq, wb_simple_trans_write_done, req);
390 return req;
393 static void wb_simple_trans_write_done(struct tevent_req *subreq)
395 struct tevent_req *req = tevent_req_callback_data(
396 subreq, struct tevent_req);
397 struct wb_simple_trans_state *state = tevent_req_data(
398 req, struct wb_simple_trans_state);
399 ssize_t ret;
400 int err;
402 ret = wb_req_write_recv(subreq, &err);
403 TALLOC_FREE(subreq);
404 if (ret == -1) {
405 tevent_req_error(req, err);
406 return;
408 subreq = wb_resp_read_send(state, state->ev, state->fd);
409 if (tevent_req_nomem(subreq, req)) {
410 return;
412 tevent_req_set_callback(subreq, wb_simple_trans_read_done, req);
415 static void wb_simple_trans_read_done(struct tevent_req *subreq)
417 struct tevent_req *req = tevent_req_callback_data(
418 subreq, struct tevent_req);
419 struct wb_simple_trans_state *state = tevent_req_data(
420 req, struct wb_simple_trans_state);
421 ssize_t ret;
422 int err;
424 ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err);
425 TALLOC_FREE(subreq);
426 if (ret == -1) {
427 tevent_req_error(req, err);
428 return;
431 tevent_req_done(req);
434 int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
435 struct winbindd_response **presponse, int *err)
437 struct wb_simple_trans_state *state = tevent_req_data(
438 req, struct wb_simple_trans_state);
440 if (tevent_req_is_unix_error(req, err)) {
441 return -1;
443 *presponse = talloc_move(mem_ctx, &state->wb_resp);
444 return 0;