Use async writev in wb_req_write
[ira/wip.git] / source3 / lib / wb_reqtrans.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Async transfer of winbindd_request and _response structs
5
6    Copyright (C) Volker Lendecke 2008
7
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.
12
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.
17
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/>.
20 */
21
22 #include "includes.h"
23 #include "wbc_async.h"
24
25 #undef DBGC_CLASS
26 #define DBGC_CLASS DBGC_WINBIND
27
28 struct req_read_state {
29         struct winbindd_request *wb_req;
30         struct tevent_context *ev;
31         size_t max_extra_data;
32         int fd;
33 };
34
35 bool async_req_is_wbcerr(struct async_req *req, wbcErr *pwbc_err)
36 {
37         enum async_req_state state;
38         uint64_t error;
39         if (!async_req_is_error(req, &state, &error)) {
40                 *pwbc_err = WBC_ERR_SUCCESS;
41                 return false;
42         }
43
44         switch (state) {
45         case ASYNC_REQ_USER_ERROR:
46                 *pwbc_err = error;
47                 break;
48         case ASYNC_REQ_TIMED_OUT:
49                 *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
50                 break;
51         case ASYNC_REQ_NO_MEMORY:
52                 *pwbc_err = WBC_ERR_NO_MEMORY;
53                 break;
54         default:
55                 *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
56                 break;
57         }
58         return true;
59 }
60
61 wbcErr map_wbc_err_from_errno(int error)
62 {
63         switch(error) {
64         case EPERM:
65         case EACCES:
66                 return WBC_ERR_AUTH_ERROR;
67         case ENOMEM:
68                 return WBC_ERR_NO_MEMORY;
69         case EIO:
70         default:
71                 return WBC_ERR_UNKNOWN_FAILURE;
72         }
73 }
74
75 wbcErr async_req_simple_recv_wbcerr(struct async_req *req)
76 {
77         wbcErr wbc_err;
78
79         if (async_req_is_wbcerr(req, &wbc_err)) {
80                 return wbc_err;
81         }
82
83         return WBC_ERR_SUCCESS;
84 }
85
86 static void wb_req_read_len(struct async_req *subreq);
87 static void wb_req_read_main(struct async_req *subreq);
88 static void wb_req_read_extra(struct async_req *subreq);
89
90 struct async_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
91                                    struct tevent_context *ev,
92                                    int fd, size_t max_extra_data)
93 {
94         struct async_req *result, *subreq;
95         struct req_read_state *state;
96
97         if (!async_req_setup(mem_ctx, &result, &state,
98                              struct req_read_state)) {
99                 return NULL;
100         }
101         state->fd = fd;
102         state->ev = ev;
103         state->max_extra_data = max_extra_data;
104         state->wb_req = talloc(state, struct winbindd_request);
105         if (state->wb_req == NULL) {
106                 goto nomem;
107         }
108
109         subreq = recvall_send(state, ev, state->fd, &(state->wb_req->length),
110                               sizeof(state->wb_req->length), 0);
111         if (subreq == NULL) {
112                 goto nomem;
113         }
114
115         subreq->async.fn = wb_req_read_len;
116         subreq->async.priv = result;
117         return result;
118
119  nomem:
120         TALLOC_FREE(result);
121         return NULL;
122 }
123
124 static void wb_req_read_len(struct async_req *subreq)
125 {
126         struct async_req *req = talloc_get_type_abort(
127                 subreq->async.priv, struct async_req);
128         struct req_read_state *state = talloc_get_type_abort(
129                 req->private_data, struct req_read_state);
130         int err;
131         ssize_t ret;
132
133         ret = recvall_recv(subreq, &err);
134         TALLOC_FREE(subreq);
135         if (ret < 0) {
136                 async_req_error(req, map_wbc_err_from_errno(err));
137                 return;
138         }
139
140         if (state->wb_req->length != sizeof(struct winbindd_request)) {
141                 DEBUG(0, ("wb_req_read_len: Invalid request size received: "
142                           "%d (expected %d)\n", (int)state->wb_req->length,
143                           (int)sizeof(struct winbindd_request)));
144                 async_req_error(req, WBC_ERR_INVALID_RESPONSE);
145                 return;
146         }
147
148         subreq = recvall_send(
149                 req, state->ev, state->fd, (uint32 *)(state->wb_req)+1,
150                 sizeof(struct winbindd_request) - sizeof(uint32), 0);
151         if (async_req_nomem(subreq, req)) {
152                 return;
153         }
154
155         subreq->async.fn = wb_req_read_main;
156         subreq->async.priv = req;
157 }
158
159 static void wb_req_read_main(struct async_req *subreq)
160 {
161         struct async_req *req = talloc_get_type_abort(
162                 subreq->async.priv, struct async_req);
163         struct req_read_state *state = talloc_get_type_abort(
164                 req->private_data, struct req_read_state);
165         int err;
166         ssize_t ret;
167
168         ret = recvall_recv(subreq, &err);
169         TALLOC_FREE(subreq);
170         if (ret < 0) {
171                 async_req_error(req, map_wbc_err_from_errno(err));
172                 return;
173         }
174
175         if ((state->max_extra_data != 0)
176             && (state->wb_req->extra_len > state->max_extra_data)) {
177                 DEBUG(3, ("Got request with %d bytes extra data on "
178                           "unprivileged socket\n",
179                           (int)state->wb_req->extra_len));
180                 async_req_error(req, WBC_ERR_INVALID_RESPONSE);
181                 return;
182         }
183
184         if (state->wb_req->extra_len == 0) {
185                 async_req_done(req);
186                 return;
187         }
188
189         state->wb_req->extra_data.data = TALLOC_ARRAY(
190                 state->wb_req, char, state->wb_req->extra_len + 1);
191         if (async_req_nomem(state->wb_req->extra_data.data, req)) {
192                 return;
193         }
194
195         state->wb_req->extra_data.data[state->wb_req->extra_len] = 0;
196
197         subreq = recvall_send(
198                 req, state->ev, state->fd, state->wb_req->extra_data.data,
199                 state->wb_req->extra_len, 0);
200         if (async_req_nomem(subreq, req)) {
201                 return;
202         }
203
204         subreq->async.fn = wb_req_read_extra;
205         subreq->async.priv = req;
206 }
207
208 static void wb_req_read_extra(struct async_req *subreq)
209 {
210         struct async_req *req = talloc_get_type_abort(
211                 subreq->async.priv, struct async_req);
212         int err;
213         ssize_t ret;
214
215         ret = recvall_recv(subreq, &err);
216         TALLOC_FREE(subreq);
217         if (ret < 0) {
218                 async_req_error(req, map_wbc_err_from_errno(err));
219                 return;
220         }
221         async_req_done(req);
222 }
223
224
225 wbcErr wb_req_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
226                         struct winbindd_request **preq)
227 {
228         struct req_read_state *state = talloc_get_type_abort(
229                 req->private_data, struct req_read_state);
230         wbcErr wbc_err;
231
232         if (async_req_is_wbcerr(req, &wbc_err)) {
233                 return wbc_err;
234         }
235         *preq = talloc_move(mem_ctx, &state->wb_req);
236         return WBC_ERR_SUCCESS;
237 }
238
239 struct req_write_state {
240         struct iovec iov[2];
241 };
242
243 static void wb_req_write_done(struct tevent_req *subreq);
244
245 struct async_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
246                                     struct tevent_context *ev, int fd,
247                                     struct winbindd_request *wb_req)
248 {
249         struct async_req *result;
250         struct tevent_req *subreq;
251         struct req_write_state *state;
252         int count = 1;
253
254         if (!async_req_setup(mem_ctx, &result, &state,
255                              struct req_write_state)) {
256                 return NULL;
257         }
258
259         state->iov[0].iov_base = wb_req;
260         state->iov[0].iov_len = sizeof(struct winbindd_request);
261
262         if (wb_req->extra_len != 0) {
263                 state->iov[1].iov_base = wb_req->extra_data.data;
264                 state->iov[1].iov_len = wb_req->extra_len;
265                 count = 2;
266         }
267
268         subreq = writev_send(state, ev, fd, state->iov, count);
269         if (subreq == NULL) {
270                 goto fail;
271         }
272         subreq->async.fn = wb_req_write_done;
273         subreq->async.private_data = result;
274         return result;
275
276  fail:
277         TALLOC_FREE(result);
278         return NULL;
279 }
280
281 static void wb_req_write_done(struct tevent_req *subreq)
282 {
283         struct async_req *req = talloc_get_type_abort(
284                 subreq->async.private_data, struct async_req);
285         int err;
286         ssize_t ret;
287
288         ret = writev_recv(subreq, &err);
289         TALLOC_FREE(subreq);
290         if (ret < 0) {
291                 async_req_error(req, map_wbc_err_from_errno(err));
292                 return;
293         }
294         async_req_done(req);
295 }
296
297 wbcErr wb_req_write_recv(struct async_req *req)
298 {
299         return async_req_simple_recv_wbcerr(req);
300 }
301
302 struct resp_read_state {
303         struct winbindd_response *wb_resp;
304         struct tevent_context *ev;
305         size_t max_extra_data;
306         int fd;
307 };
308
309 static void wb_resp_read_len(struct async_req *subreq);
310 static void wb_resp_read_main(struct async_req *subreq);
311 static void wb_resp_read_extra(struct async_req *subreq);
312
313 struct async_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
314                                     struct tevent_context *ev, int fd)
315 {
316         struct async_req *result, *subreq;
317         struct resp_read_state *state;
318
319         if (!async_req_setup(mem_ctx, &result, &state,
320                              struct resp_read_state)) {
321                 return NULL;
322         }
323         state->fd = fd;
324         state->ev = ev;
325         state->wb_resp = talloc(state, struct winbindd_response);
326         if (state->wb_resp == NULL) {
327                 goto nomem;
328         }
329
330         subreq = recvall_send(state, ev, state->fd, &(state->wb_resp->length),
331                               sizeof(state->wb_resp->length), 0);
332         if (subreq == NULL) {
333                 goto nomem;
334         }
335
336         subreq->async.fn = wb_resp_read_len;
337         subreq->async.priv = result;
338         return result;
339
340  nomem:
341         TALLOC_FREE(result);
342         return NULL;
343 }
344
345 static void wb_resp_read_len(struct async_req *subreq)
346 {
347         struct async_req *req = talloc_get_type_abort(
348                 subreq->async.priv, struct async_req);
349         struct resp_read_state *state = talloc_get_type_abort(
350                 req->private_data, struct resp_read_state);
351         int err;
352         ssize_t ret;
353
354         ret = recvall_recv(subreq, &err);
355         TALLOC_FREE(subreq);
356         if (ret < 0) {
357                 async_req_error(req, map_wbc_err_from_errno(err));
358                 return;
359         }
360
361         if (state->wb_resp->length < sizeof(struct winbindd_response)) {
362                 DEBUG(0, ("wb_resp_read_len: Invalid response size received: "
363                           "%d (expected at least%d)\n",
364                           (int)state->wb_resp->length,
365                           (int)sizeof(struct winbindd_response)));
366                 async_req_error(req, WBC_ERR_INVALID_RESPONSE);
367                 return;
368         }
369
370         subreq = recvall_send(
371                 req, state->ev, state->fd, (uint32 *)(state->wb_resp)+1,
372                 sizeof(struct winbindd_response) - sizeof(uint32), 0);
373         if (async_req_nomem(subreq, req)) {
374                 return;
375         }
376
377         subreq->async.fn = wb_resp_read_main;
378         subreq->async.priv = req;
379 }
380
381 static void wb_resp_read_main(struct async_req *subreq)
382 {
383         struct async_req *req = talloc_get_type_abort(
384                 subreq->async.priv, struct async_req);
385         struct resp_read_state *state = talloc_get_type_abort(
386                 req->private_data, struct resp_read_state);
387         int err;
388         ssize_t ret;
389         size_t extra_len;
390
391         ret = recvall_recv(subreq, &err);
392         TALLOC_FREE(subreq);
393         if (ret < 0) {
394                 async_req_error(req, map_wbc_err_from_errno(err));
395                 return;
396         }
397
398         extra_len = state->wb_resp->length - sizeof(struct winbindd_response);
399         if (extra_len == 0) {
400                 async_req_done(req);
401                 return;
402         }
403
404         state->wb_resp->extra_data.data = TALLOC_ARRAY(
405                 state->wb_resp, char, extra_len+1);
406         if (async_req_nomem(state->wb_resp->extra_data.data, req)) {
407                 return;
408         }
409         ((char *)state->wb_resp->extra_data.data)[extra_len] = 0;
410
411         subreq = recvall_send(
412                 req, state->ev, state->fd, state->wb_resp->extra_data.data,
413                 extra_len, 0);
414         if (async_req_nomem(subreq, req)) {
415                 return;
416         }
417
418         subreq->async.fn = wb_resp_read_extra;
419         subreq->async.priv = req;
420 }
421
422 static void wb_resp_read_extra(struct async_req *subreq)
423 {
424         struct async_req *req = talloc_get_type_abort(
425                 subreq->async.priv, struct async_req);
426         int err;
427         ssize_t ret;
428
429         ret = recvall_recv(subreq, &err);
430         TALLOC_FREE(subreq);
431         if (ret < 0) {
432                 async_req_error(req, map_wbc_err_from_errno(err));
433                 return;
434         }
435         async_req_done(req);
436 }
437
438
439 wbcErr wb_resp_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
440                          struct winbindd_response **presp)
441 {
442         struct resp_read_state *state = talloc_get_type_abort(
443                 req->private_data, struct resp_read_state);
444         wbcErr wbc_err;
445
446         if (async_req_is_wbcerr(req, &wbc_err)) {
447                 return wbc_err;
448         }
449         *presp = talloc_move(mem_ctx, &state->wb_resp);
450         return WBC_ERR_SUCCESS;
451 }
452
453 struct resp_write_state {
454         struct winbindd_response *wb_resp;
455         struct tevent_context *ev;
456         int fd;
457 };
458
459 static void wb_resp_write_main(struct async_req *subreq);
460 static void wb_resp_write_extra(struct async_req *subreq);
461
462 struct async_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
463                                     struct tevent_context *ev, int fd,
464                                     struct winbindd_response *wb_resp)
465 {
466         struct async_req *result, *subreq;
467         struct resp_write_state *state;
468
469         if (!async_req_setup(mem_ctx, &result, &state,
470                              struct resp_write_state)) {
471                 return NULL;
472         }
473         state->fd = fd;
474         state->ev = ev;
475         state->wb_resp = wb_resp;
476
477         subreq = sendall_send(state, state->ev, state->fd, state->wb_resp,
478                               sizeof(struct winbindd_response), 0);
479         if (subreq == NULL) {
480                 goto nomem;
481         }
482
483         subreq->async.fn = wb_resp_write_main;
484         subreq->async.priv = result;
485         return result;
486
487  nomem:
488         TALLOC_FREE(result);
489         return NULL;
490 }
491
492 static void wb_resp_write_main(struct async_req *subreq)
493 {
494         struct async_req *req = talloc_get_type_abort(
495                 subreq->async.priv, struct async_req);
496         struct resp_write_state *state = talloc_get_type_abort(
497                 req->private_data, struct resp_write_state);
498         int err;
499         ssize_t ret;
500
501         ret = sendall_recv(subreq, &err);
502         TALLOC_FREE(subreq);
503         if (ret < 0) {
504                 async_req_error(req, map_wbc_err_from_errno(err));
505                 return;
506         }
507
508         if (state->wb_resp->length == sizeof(struct winbindd_response)) {
509                 async_req_done(req);
510                 return;
511         }
512
513         subreq = sendall_send(
514                 state, state->ev, state->fd,
515                 state->wb_resp->extra_data.data,
516                 state->wb_resp->length - sizeof(struct winbindd_response), 0);
517         if (async_req_nomem(subreq, req)) {
518                 return;
519         }
520
521         subreq->async.fn = wb_resp_write_extra;
522         subreq->async.priv = req;
523 }
524
525 static void wb_resp_write_extra(struct async_req *subreq)
526 {
527         struct async_req *req = talloc_get_type_abort(
528                 subreq->async.priv, struct async_req);
529         int err;
530         ssize_t ret;
531
532         ret = sendall_recv(subreq, &err);
533         TALLOC_FREE(subreq);
534         if (err < 0) {
535                 async_req_error(req, map_wbc_err_from_errno(err));
536                 return;
537         }
538
539         async_req_done(req);
540 }
541
542 wbcErr wb_resp_write_recv(struct async_req *req)
543 {
544         return async_req_simple_recv_wbcerr(req);
545 }