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/>.
23 #include "wbc_async.h"
26 #define DBGC_CLASS DBGC_WINBIND
28 struct req_read_state
{
29 struct winbindd_request
*wb_req
;
30 size_t max_extra_data
;
34 static ssize_t
wb_req_more(uint8_t *buf
, size_t buflen
, void *private_data
);
35 static void wb_req_read_done(struct tevent_req
*subreq
);
37 struct tevent_req
*wb_req_read_send(TALLOC_CTX
*mem_ctx
,
38 struct tevent_context
*ev
,
39 int fd
, size_t max_extra_data
)
41 struct tevent_req
*req
, *subreq
;
42 struct req_read_state
*state
;
44 req
= tevent_req_create(mem_ctx
, &state
, struct req_read_state
);
48 state
->max_extra_data
= max_extra_data
;
50 subreq
= read_packet_send(state
, ev
, fd
, 4, wb_req_more
, state
);
51 if (tevent_req_nomem(subreq
, req
)) {
52 return tevent_req_post(req
, ev
);
54 tevent_req_set_callback(subreq
, wb_req_read_done
, req
);
58 static ssize_t
wb_req_more(uint8_t *buf
, size_t buflen
, void *private_data
)
60 struct req_read_state
*state
= talloc_get_type_abort(
61 private_data
, struct req_read_state
);
62 struct winbindd_request
*req
= (struct winbindd_request
*)buf
;
65 if (req
->length
!= sizeof(struct winbindd_request
)) {
66 DEBUG(0, ("wb_req_read_len: Invalid request size "
67 "received: %d (expected %d)\n",
69 (int)sizeof(struct winbindd_request
)));
72 return sizeof(struct winbindd_request
) - 4;
75 if ((state
->max_extra_data
!= 0)
76 && (req
->extra_len
> state
->max_extra_data
)) {
77 DEBUG(3, ("Got request with %d bytes extra data on "
78 "unprivileged socket\n", (int)req
->extra_len
));
82 return req
->extra_len
;
85 static void wb_req_read_done(struct tevent_req
*subreq
)
87 struct tevent_req
*req
= tevent_req_callback_data(
88 subreq
, struct tevent_req
);
89 struct req_read_state
*state
= tevent_req_data(
90 req
, struct req_read_state
);
94 state
->ret
= read_packet_recv(subreq
, state
, &buf
, &err
);
96 if (state
->ret
== -1) {
97 tevent_req_error(req
, err
);
101 state
->wb_req
= (struct winbindd_request
*)buf
;
103 if (state
->wb_req
->extra_len
!= 0) {
104 state
->wb_req
->extra_data
.data
=
105 (char *)buf
+ sizeof(struct winbindd_request
);
107 state
->wb_req
->extra_data
.data
= NULL
;
109 tevent_req_done(req
);
112 ssize_t
wb_req_read_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
113 struct winbindd_request
**preq
, int *err
)
115 struct req_read_state
*state
= tevent_req_data(
116 req
, struct req_read_state
);
118 if (tevent_req_is_unix_error(req
, err
)) {
121 *preq
= talloc_move(mem_ctx
, &state
->wb_req
);
125 struct req_write_state
{
130 static void wb_req_write_done(struct tevent_req
*subreq
);
132 struct tevent_req
*wb_req_write_send(TALLOC_CTX
*mem_ctx
,
133 struct tevent_context
*ev
,
134 struct tevent_queue
*queue
, int fd
,
135 struct winbindd_request
*wb_req
)
137 struct tevent_req
*req
, *subreq
;
138 struct req_write_state
*state
;
141 req
= tevent_req_create(mem_ctx
, &state
, struct req_write_state
);
146 state
->iov
[0].iov_base
= (void *)wb_req
;
147 state
->iov
[0].iov_len
= sizeof(struct winbindd_request
);
149 if (wb_req
->extra_len
!= 0) {
150 state
->iov
[1].iov_base
= (void *)wb_req
->extra_data
.data
;
151 state
->iov
[1].iov_len
= wb_req
->extra_len
;
155 subreq
= writev_send(state
, ev
, queue
, fd
, true, state
->iov
, count
);
156 if (tevent_req_nomem(subreq
, req
)) {
157 return tevent_req_post(req
, ev
);
159 tevent_req_set_callback(subreq
, wb_req_write_done
, req
);
163 static void wb_req_write_done(struct tevent_req
*subreq
)
165 struct tevent_req
*req
= tevent_req_callback_data(
166 subreq
, struct tevent_req
);
167 struct req_write_state
*state
= tevent_req_data(
168 req
, struct req_write_state
);
171 state
->ret
= writev_recv(subreq
, &err
);
173 if (state
->ret
< 0) {
174 tevent_req_error(req
, err
);
177 tevent_req_done(req
);
180 ssize_t
wb_req_write_recv(struct tevent_req
*req
, int *err
)
182 struct req_write_state
*state
= tevent_req_data(
183 req
, struct req_write_state
);
185 if (tevent_req_is_unix_error(req
, err
)) {
191 struct resp_read_state
{
192 struct winbindd_response
*wb_resp
;
196 static ssize_t
wb_resp_more(uint8_t *buf
, size_t buflen
, void *private_data
);
197 static void wb_resp_read_done(struct tevent_req
*subreq
);
199 struct tevent_req
*wb_resp_read_send(TALLOC_CTX
*mem_ctx
,
200 struct tevent_context
*ev
, int fd
)
202 struct tevent_req
*req
, *subreq
;
203 struct resp_read_state
*state
;
205 req
= tevent_req_create(mem_ctx
, &state
, struct resp_read_state
);
210 subreq
= read_packet_send(state
, ev
, fd
, 4, wb_resp_more
, state
);
211 if (tevent_req_nomem(subreq
, req
)) {
212 return tevent_req_post(req
, ev
);
214 tevent_req_set_callback(subreq
, wb_resp_read_done
, req
);
218 static ssize_t
wb_resp_more(uint8_t *buf
, size_t buflen
, void *private_data
)
220 struct winbindd_response
*resp
= (struct winbindd_response
*)buf
;
223 if (resp
->length
< sizeof(struct winbindd_response
)) {
224 DEBUG(0, ("wb_resp_read_len: Invalid response size "
225 "received: %d (expected at least%d)\n",
227 (int)sizeof(struct winbindd_response
)));
231 return resp
->length
- buflen
;
234 static void wb_resp_read_done(struct tevent_req
*subreq
)
236 struct tevent_req
*req
= tevent_req_callback_data(
237 subreq
, struct tevent_req
);
238 struct resp_read_state
*state
= tevent_req_data(
239 req
, struct resp_read_state
);
243 state
->ret
= read_packet_recv(subreq
, state
, &buf
, &err
);
245 if (state
->ret
== -1) {
246 tevent_req_error(req
, err
);
250 state
->wb_resp
= (struct winbindd_response
*)buf
;
252 if (state
->wb_resp
->length
> sizeof(struct winbindd_response
)) {
253 state
->wb_resp
->extra_data
.data
=
254 (char *)buf
+ sizeof(struct winbindd_response
);
256 state
->wb_resp
->extra_data
.data
= NULL
;
258 tevent_req_done(req
);
261 ssize_t
wb_resp_read_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
262 struct winbindd_response
**presp
, int *err
)
264 struct resp_read_state
*state
= tevent_req_data(
265 req
, struct resp_read_state
);
267 if (tevent_req_is_unix_error(req
, err
)) {
270 *presp
= talloc_move(mem_ctx
, &state
->wb_resp
);
274 struct resp_write_state
{
279 static void wb_resp_write_done(struct tevent_req
*subreq
);
281 struct tevent_req
*wb_resp_write_send(TALLOC_CTX
*mem_ctx
,
282 struct tevent_context
*ev
,
283 struct tevent_queue
*queue
, int fd
,
284 struct winbindd_response
*wb_resp
)
286 struct tevent_req
*req
, *subreq
;
287 struct resp_write_state
*state
;
290 req
= tevent_req_create(mem_ctx
, &state
, struct resp_write_state
);
295 state
->iov
[0].iov_base
= (void *)wb_resp
;
296 state
->iov
[0].iov_len
= sizeof(struct winbindd_response
);
298 if (wb_resp
->length
> sizeof(struct winbindd_response
)) {
299 state
->iov
[1].iov_base
= (void *)wb_resp
->extra_data
.data
;
300 state
->iov
[1].iov_len
=
301 wb_resp
->length
- sizeof(struct winbindd_response
);
305 subreq
= writev_send(state
, ev
, queue
, fd
, true, state
->iov
, count
);
306 if (tevent_req_nomem(subreq
, req
)) {
307 return tevent_req_post(req
, ev
);
309 tevent_req_set_callback(subreq
, wb_resp_write_done
, req
);
313 static void wb_resp_write_done(struct tevent_req
*subreq
)
315 struct tevent_req
*req
= tevent_req_callback_data(
316 subreq
, struct tevent_req
);
317 struct resp_write_state
*state
= tevent_req_data(
318 req
, struct resp_write_state
);
321 state
->ret
= writev_recv(subreq
, &err
);
323 if (state
->ret
< 0) {
324 tevent_req_error(req
, err
);
327 tevent_req_done(req
);
330 ssize_t
wb_resp_write_recv(struct tevent_req
*req
, int *err
)
332 struct resp_write_state
*state
= tevent_req_data(
333 req
, struct resp_write_state
);
335 if (tevent_req_is_unix_error(req
, err
)) {
341 static bool closed_fd(int fd
)
355 selret
= select(fd
+1, &r_fds
, NULL
, NULL
, &tv
);
362 return (FD_ISSET(fd
, &r_fds
));
365 struct wb_simple_trans_state
{
366 struct tevent_context
*ev
;
368 struct winbindd_response
*wb_resp
;
371 static void wb_simple_trans_write_done(struct tevent_req
*subreq
);
372 static void wb_simple_trans_read_done(struct tevent_req
*subreq
);
374 struct tevent_req
*wb_simple_trans_send(TALLOC_CTX
*mem_ctx
,
375 struct tevent_context
*ev
,
376 struct tevent_queue
*queue
, int fd
,
377 struct winbindd_request
*wb_req
)
379 struct tevent_req
*req
, *subreq
;
380 struct wb_simple_trans_state
*state
;
382 req
= tevent_req_create(mem_ctx
, &state
, struct wb_simple_trans_state
);
388 tevent_req_error(req
, EPIPE
);
389 return tevent_req_post(req
, ev
);
392 wb_req
->length
= sizeof(struct winbindd_request
);
397 subreq
= wb_req_write_send(state
, ev
, queue
, fd
, wb_req
);
398 if (tevent_req_nomem(subreq
, req
)) {
399 return tevent_req_post(req
, ev
);
401 tevent_req_set_callback(subreq
, wb_simple_trans_write_done
, req
);
406 static void wb_simple_trans_write_done(struct tevent_req
*subreq
)
408 struct tevent_req
*req
= tevent_req_callback_data(
409 subreq
, struct tevent_req
);
410 struct wb_simple_trans_state
*state
= tevent_req_data(
411 req
, struct wb_simple_trans_state
);
415 ret
= wb_req_write_recv(subreq
, &err
);
418 tevent_req_error(req
, err
);
421 subreq
= wb_resp_read_send(state
, state
->ev
, state
->fd
);
422 if (tevent_req_nomem(subreq
, req
)) {
425 tevent_req_set_callback(subreq
, wb_simple_trans_read_done
, req
);
428 static void wb_simple_trans_read_done(struct tevent_req
*subreq
)
430 struct tevent_req
*req
= tevent_req_callback_data(
431 subreq
, struct tevent_req
);
432 struct wb_simple_trans_state
*state
= tevent_req_data(
433 req
, struct wb_simple_trans_state
);
437 ret
= wb_resp_read_recv(subreq
, state
, &state
->wb_resp
, &err
);
440 tevent_req_error(req
, err
);
444 tevent_req_done(req
);
447 int wb_simple_trans_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
448 struct winbindd_response
**presponse
, int *err
)
450 struct wb_simple_trans_state
*state
= tevent_req_data(
451 req
, struct wb_simple_trans_state
);
453 if (tevent_req_is_unix_error(req
, err
)) {
456 *presponse
= talloc_move(mem_ctx
, &state
->wb_resp
);