Fix wb_simple_trans queueing
[ira/wip.git] / source3 / lib / wb_reqtrans.c
index 0e6e5d15c47e6008a2cf9ef17bc74dc3437ec8ed..16d71fe03e36aadc715380e3810ca6bfed1e96bd 100644 (file)
 */
 
 #include "includes.h"
-#include "winbindd/winbindd.h"
+#include "wbc_async.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
 struct req_read_state {
        struct winbindd_request *wb_req;
-       struct event_context *ev;
        size_t max_extra_data;
-       int fd;
+       ssize_t ret;
 };
 
-static void wb_req_read_len(struct async_req *subreq);
-static void wb_req_read_main(struct async_req *subreq);
-static void wb_req_read_extra(struct async_req *subreq);
+static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data);
+static void wb_req_read_done(struct tevent_req *subreq);
 
-struct async_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
-                                  struct event_context *ev,
-                                  int fd, size_t max_extra_data)
+struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
+                                   struct tevent_context *ev,
+                                   int fd, size_t max_extra_data)
 {
-       struct async_req *result, *subreq;
+       struct tevent_req *req, *subreq;
        struct req_read_state *state;
 
-       if (!async_req_setup(mem_ctx, &result, &state,
-                            struct req_read_state)) {
+       req = tevent_req_create(mem_ctx, &state, struct req_read_state);
+       if (req == NULL) {
                return NULL;
        }
-       state->fd = fd;
-       state->ev = ev;
        state->max_extra_data = max_extra_data;
-       state->wb_req = talloc(state, struct winbindd_request);
-       if (state->wb_req == NULL) {
-               goto nomem;
-       }
 
-       subreq = recvall_send(state, ev, state->fd, &(state->wb_req->length),
-                             sizeof(state->wb_req->length), 0);
-       if (subreq == NULL) {
-               goto nomem;
+       subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
-
-       subreq->async.fn = wb_req_read_len;
-       subreq->async.priv = result;
-       return result;
-
- nomem:
-       TALLOC_FREE(result);
-       return NULL;
+       tevent_req_set_callback(subreq, wb_req_read_done, req);
+       return req;
 }
 
-static void wb_req_read_len(struct async_req *subreq)
+static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
        struct req_read_state *state = talloc_get_type_abort(
-               req->private_data, struct req_read_state);
-       NTSTATUS status;
+               private_data, struct req_read_state);
+       struct winbindd_request *req = (struct winbindd_request *)buf;
 
-       status = recvall_recv(subreq);
-       TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_error(req, status);
-               return;
+       if (buflen == 4) {
+               if (req->length != sizeof(struct winbindd_request)) {
+                       DEBUG(0, ("wb_req_read_len: Invalid request size "
+                                 "received: %d (expected %d)\n",
+                                 (int)req->length,
+                                 (int)sizeof(struct winbindd_request)));
+                       return -1;
+               }
+               return sizeof(struct winbindd_request) - 4;
        }
 
-       if (state->wb_req->length != sizeof(struct winbindd_request)) {
-               DEBUG(0, ("wb_req_read_len: Invalid request size received: "
-                         "%d (expected %d)\n", (int)state->wb_req->length,
-                         (int)sizeof(struct winbindd_request)));
-               async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE);
-               return;
-       }
-
-       subreq = recvall_send(
-               req, state->ev, state->fd, (uint32 *)(state->wb_req)+1,
-               sizeof(struct winbindd_request) - sizeof(uint32), 0);
-       if (async_req_nomem(subreq, req)) {
-               return;
+       if ((state->max_extra_data != 0)
+           && (req->extra_len > state->max_extra_data)) {
+               DEBUG(3, ("Got request with %d bytes extra data on "
+                         "unprivileged socket\n", (int)req->extra_len));
+               return -1;
        }
 
-       subreq->async.fn = wb_req_read_main;
-       subreq->async.priv = req;
+       return req->extra_len;
 }
 
-static void wb_req_read_main(struct async_req *subreq)
+static void wb_req_read_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct req_read_state *state = talloc_get_type_abort(
-               req->private_data, struct req_read_state);
-       NTSTATUS status;
-
-       status = recvall_recv(subreq);
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct req_read_state *state = tevent_req_data(
+               req, struct req_read_state);
+       int err;
+       uint8_t *buf;
+
+       state->ret = read_packet_recv(subreq, state, &buf, &err);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_error(req, status);
+       if (state->ret == -1) {
+               tevent_req_error(req, err);
                return;
        }
 
-       if ((state->max_extra_data != 0)
-           && (state->wb_req->extra_len > state->max_extra_data)) {
-               DEBUG(3, ("Got request with %d bytes extra data on "
-                         "unprivileged socket\n",
-                         (int)state->wb_req->extra_len));
-               async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE);
-               return;
-       }
+       state->wb_req = (struct winbindd_request *)buf;
 
-       if (state->wb_req->extra_len == 0) {
-               async_req_done(req);
-               return;
+       if (state->wb_req->extra_len != 0) {
+               state->wb_req->extra_data.data =
+                       (char *)buf + sizeof(struct winbindd_request);
+       } else {
+               state->wb_req->extra_data.data = NULL;
        }
-
-       state->wb_req->extra_data.data = TALLOC_ARRAY(
-               state->wb_req, char, state->wb_req->extra_len + 1);
-       if (async_req_nomem(state->wb_req->extra_data.data, req)) {
-               return;
-       }
-
-       state->wb_req->extra_data.data[state->wb_req->extra_len] = 0;
-
-       subreq = recvall_send(
-               req, state->ev, state->fd, state->wb_req->extra_data.data,
-               state->wb_req->extra_len, 0);
-       if (async_req_nomem(subreq, req)) {
-               return;
-       }
-
-       subreq->async.fn = wb_req_read_extra;
-       subreq->async.priv = req;
+       tevent_req_done(req);
 }
 
-static void wb_req_read_extra(struct async_req *subreq)
+ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                        struct winbindd_request **preq, int *err)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       NTSTATUS status;
+       struct req_read_state *state = tevent_req_data(
+               req, struct req_read_state);
 
-       status = recvall_recv(subreq);
-       TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_error(req, status);
-               return;
-       }
-       async_req_done(req);
-}
-
-
-NTSTATUS wb_req_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
-                         struct winbindd_request **preq)
-{
-       struct req_read_state *state = talloc_get_type_abort(
-               req->private_data, struct req_read_state);
-       NTSTATUS status;
-
-       if (async_req_is_error(req, &status)) {
-               return status;
+       if (tevent_req_is_unix_error(req, err)) {
+               return -1;
        }
        *preq = talloc_move(mem_ctx, &state->wb_req);
-       return NT_STATUS_OK;
+       return state->ret;
 }
 
 struct req_write_state {
-       struct winbindd_request *wb_req;
-       struct event_context *ev;
-       int fd;
+       struct iovec iov[2];
+       ssize_t ret;
 };
 
-static void wb_req_write_main(struct async_req *subreq);
-static void wb_req_write_extra(struct async_req *subreq);
+static void wb_req_write_done(struct tevent_req *subreq);
 
-struct async_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
-                                   struct event_context *ev, int fd,
-                                   struct winbindd_request *wb_req)
+struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
+                                    struct tevent_context *ev,
+                                    struct tevent_queue *queue, int fd,
+                                    struct winbindd_request *wb_req)
 {
-       struct async_req *result, *subreq;
+       struct tevent_req *req, *subreq;
        struct req_write_state *state;
+       int count = 1;
 
-       if (!async_req_setup(mem_ctx, &result, &state,
-                            struct req_write_state)) {
+       req = tevent_req_create(mem_ctx, &state, struct req_write_state);
+       if (req == NULL) {
                return NULL;
        }
-       state->fd = fd;
-       state->ev = ev;
-       state->wb_req = wb_req;
 
-       subreq = sendall_send(state, state->ev, state->fd, state->wb_req,
-                             sizeof(struct winbindd_request), 0);
-       if (subreq == NULL) {
-               goto nomem;
-       }
-
-       subreq->async.fn = wb_req_write_main;
-       subreq->async.priv = result;
-       return result;
+       state->iov[0].iov_base = (void *)wb_req;
+       state->iov[0].iov_len = sizeof(struct winbindd_request);
 
- nomem:
-       TALLOC_FREE(result);
-       return NULL;
-}
-
-static void wb_req_write_main(struct async_req *subreq)
-{
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct req_write_state *state = talloc_get_type_abort(
-               req->private_data, struct req_write_state);
-       NTSTATUS status;
-
-       status = sendall_recv(subreq);
-       TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_error(req, status);
-               return;
-       }
-
-       if (state->wb_req->extra_len == 0) {
-               async_req_done(req);
-               return;
+       if (wb_req->extra_len != 0) {
+               state->iov[1].iov_base = (void *)wb_req->extra_data.data;
+               state->iov[1].iov_len = wb_req->extra_len;
+               count = 2;
        }
 
-       subreq = sendall_send(state, state->ev, state->fd,
-                             state->wb_req->extra_data.data,
-                             state->wb_req->extra_len, 0);
-       if (async_req_nomem(subreq, req)) {
-               return;
+       subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
-
-       subreq->async.fn = wb_req_write_extra;
-       subreq->async.priv = req;
+       tevent_req_set_callback(subreq, wb_req_write_done, req);
+       return req;
 }
 
-static void wb_req_write_extra(struct async_req *subreq)
+static void wb_req_write_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       NTSTATUS status;
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct req_write_state *state = tevent_req_data(
+               req, struct req_write_state);
+       int err;
 
-       status = sendall_recv(subreq);
+       state->ret = writev_recv(subreq, &err);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_error(req, status);
+       if (state->ret < 0) {
+               tevent_req_error(req, err);
                return;
        }
-
-       async_req_done(req);
+       tevent_req_done(req);
 }
 
-NTSTATUS wb_req_write_recv(struct async_req *req)
+ssize_t wb_req_write_recv(struct tevent_req *req, int *err)
 {
-       return async_req_simple_recv(req);
+       struct req_write_state *state = tevent_req_data(
+               req, struct req_write_state);
+
+       if (tevent_req_is_unix_error(req, err)) {
+               return -1;
+       }
+       return state->ret;
 }
 
 struct resp_read_state {
        struct winbindd_response *wb_resp;
-       struct event_context *ev;
-       size_t max_extra_data;
-       int fd;
+       ssize_t ret;
 };
 
-static void wb_resp_read_len(struct async_req *subreq);
-static void wb_resp_read_main(struct async_req *subreq);
-static void wb_resp_read_extra(struct async_req *subreq);
+static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data);
+static void wb_resp_read_done(struct tevent_req *subreq);
 
-struct async_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
-                                   struct event_context *ev, int fd)
+struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
+                                    struct tevent_context *ev, int fd)
 {
-       struct async_req *result, *subreq;
+       struct tevent_req *req, *subreq;
        struct resp_read_state *state;
 
-       if (!async_req_setup(mem_ctx, &result, &state,
-                            struct resp_read_state)) {
+       req = tevent_req_create(mem_ctx, &state, struct resp_read_state);
+       if (req == NULL) {
                return NULL;
        }
-       state->fd = fd;
-       state->ev = ev;
-       state->wb_resp = talloc(state, struct winbindd_response);
-       if (state->wb_resp == NULL) {
-               goto nomem;
-       }
 
-       subreq = recvall_send(state, ev, state->fd, &(state->wb_resp->length),
-                             sizeof(state->wb_resp->length), 0);
-       if (subreq == NULL) {
-               goto nomem;
+       subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
-
-       subreq->async.fn = wb_resp_read_len;
-       subreq->async.priv = result;
-       return result;
-
- nomem:
-       TALLOC_FREE(result);
-       return NULL;
+       tevent_req_set_callback(subreq, wb_resp_read_done, req);
+       return req;
 }
 
-static void wb_resp_read_len(struct async_req *subreq)
+static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct resp_read_state *state = talloc_get_type_abort(
-               req->private_data, struct resp_read_state);
-       NTSTATUS status;
+       struct winbindd_response *resp = (struct winbindd_response *)buf;
+
+       if (buflen == 4) {
+               if (resp->length < sizeof(struct winbindd_response)) {
+                       DEBUG(0, ("wb_resp_read_len: Invalid response size "
+                                 "received: %d (expected at least%d)\n",
+                                 (int)resp->length,
+                                 (int)sizeof(struct winbindd_response)));
+                       return -1;
+               }
+       }
+       return resp->length - buflen;
+}
 
-       status = recvall_recv(subreq);
+static void wb_resp_read_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct resp_read_state *state = tevent_req_data(
+               req, struct resp_read_state);
+       uint8_t *buf;
+       int err;
+
+       state->ret = read_packet_recv(subreq, state, &buf, &err);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_error(req, status);
+       if (state->ret == -1) {
+               tevent_req_error(req, err);
                return;
        }
 
-       if (state->wb_resp->length < sizeof(struct winbindd_response)) {
-               DEBUG(0, ("wb_resp_read_len: Invalid response size received: "
-                         "%d (expected at least%d)\n",
-                         (int)state->wb_resp->length,
-                         (int)sizeof(struct winbindd_response)));
-               async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE);
-               return;
-       }
+       state->wb_resp = (struct winbindd_response *)buf;
 
-       subreq = recvall_send(
-               req, state->ev, state->fd, (uint32 *)(state->wb_resp)+1,
-               sizeof(struct winbindd_response) - sizeof(uint32), 0);
-       if (async_req_nomem(subreq, req)) {
-               return;
+       if (state->wb_resp->length > sizeof(struct winbindd_response)) {
+               state->wb_resp->extra_data.data =
+                       (char *)buf + sizeof(struct winbindd_response);
+       } else {
+               state->wb_resp->extra_data.data = NULL;
        }
-
-       subreq->async.fn = wb_resp_read_main;
-       subreq->async.priv = req;
+       tevent_req_done(req);
 }
 
-static void wb_resp_read_main(struct async_req *subreq)
+ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                         struct winbindd_response **presp, int *err)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct resp_read_state *state = talloc_get_type_abort(
-               req->private_data, struct resp_read_state);
-       NTSTATUS status;
-       size_t extra_len;
-
-       status = recvall_recv(subreq);
-       TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_error(req, status);
-               return;
-       }
+       struct resp_read_state *state = tevent_req_data(
+               req, struct resp_read_state);
 
-       extra_len = state->wb_resp->length - sizeof(struct winbindd_response);
-       if (extra_len == 0) {
-               async_req_done(req);
-               return;
+       if (tevent_req_is_unix_error(req, err)) {
+               return -1;
        }
+       *presp = talloc_move(mem_ctx, &state->wb_resp);
+       return state->ret;
+}
 
-       state->wb_resp->extra_data.data = TALLOC_ARRAY(
-               state->wb_resp, char, extra_len+1);
-       if (async_req_nomem(state->wb_resp->extra_data.data, req)) {
-               return;
+struct resp_write_state {
+       struct iovec iov[2];
+       ssize_t ret;
+};
+
+static void wb_resp_write_done(struct tevent_req *subreq);
+
+struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
+                                     struct tevent_context *ev,
+                                     struct tevent_queue *queue, int fd,
+                                     struct winbindd_response *wb_resp)
+{
+       struct tevent_req *req, *subreq;
+       struct resp_write_state *state;
+       int count = 1;
+
+       req = tevent_req_create(mem_ctx, &state, struct resp_write_state);
+       if (req == NULL) {
+               return NULL;
        }
-       ((char *)state->wb_resp->extra_data.data)[extra_len] = 0;
 
-       subreq = recvall_send(
-               req, state->ev, state->fd, state->wb_resp->extra_data.data,
-               extra_len, 0);
-       if (async_req_nomem(subreq, req)) {
-               return;
+       state->iov[0].iov_base = (void *)wb_resp;
+       state->iov[0].iov_len = sizeof(struct winbindd_response);
+
+       if (wb_resp->length > sizeof(struct winbindd_response)) {
+               state->iov[1].iov_base = (void *)wb_resp->extra_data.data;
+               state->iov[1].iov_len =
+                       wb_resp->length - sizeof(struct winbindd_response);
+               count = 2;
        }
 
-       subreq->async.fn = wb_resp_read_extra;
-       subreq->async.priv = req;
+       subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, wb_resp_write_done, req);
+       return req;
 }
 
-static void wb_resp_read_extra(struct async_req *subreq)
+static void wb_resp_write_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       NTSTATUS status;
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct resp_write_state *state = tevent_req_data(
+               req, struct resp_write_state);
+       int err;
 
-       status = recvall_recv(subreq);
+       state->ret = writev_recv(subreq, &err);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_error(req, status);
+       if (state->ret < 0) {
+               tevent_req_error(req, err);
                return;
        }
-       async_req_done(req);
+       tevent_req_done(req);
 }
 
+ssize_t wb_resp_write_recv(struct tevent_req *req, int *err)
+{
+       struct resp_write_state *state = tevent_req_data(
+               req, struct resp_write_state);
+
+       if (tevent_req_is_unix_error(req, err)) {
+               return -1;
+       }
+       return state->ret;
+}
 
-NTSTATUS wb_resp_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
-                          struct winbindd_response **presp)
+static bool closed_fd(int fd)
 {
-       struct resp_read_state *state = talloc_get_type_abort(
-               req->private_data, struct resp_read_state);
-       NTSTATUS status;
+       struct timeval tv;
+       fd_set r_fds;
 
-       if (async_req_is_error(req, &status)) {
-               return status;
+       if (fd == -1) {
+               return true;
        }
-       *presp = talloc_move(mem_ctx, &state->wb_resp);
-       return NT_STATUS_OK;
+
+       FD_ZERO(&r_fds);
+       FD_SET(fd, &r_fds);
+       ZERO_STRUCT(tv);
+
+       if ((select(fd+1, &r_fds, NULL, NULL, &tv) == -1)
+           || FD_ISSET(fd, &r_fds)) {
+               return true;
+       }
+
+       return false;
 }
 
-struct resp_write_state {
-       struct winbindd_response *wb_resp;
-       struct event_context *ev;
+struct wb_simple_trans_state {
+       struct tevent_context *ev;
        int fd;
+       struct winbindd_response *wb_resp;
 };
 
-static void wb_resp_write_main(struct async_req *subreq);
-static void wb_resp_write_extra(struct async_req *subreq);
+static void wb_simple_trans_write_done(struct tevent_req *subreq);
+static void wb_simple_trans_read_done(struct tevent_req *subreq);
 
-struct async_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
-                                   struct event_context *ev, int fd,
-                                   struct winbindd_response *wb_resp)
+struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct tevent_queue *queue, int fd,
+                                       struct winbindd_request *wb_req)
 {
-       struct async_req *result, *subreq;
-       struct resp_write_state *state;
+       struct tevent_req *req, *subreq;
+       struct wb_simple_trans_state *state;
 
-       if (!async_req_setup(mem_ctx, &result, &state,
-                            struct resp_write_state)) {
+       req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state);
+       if (req == NULL) {
                return NULL;
        }
-       state->fd = fd;
-       state->ev = ev;
-       state->wb_resp = wb_resp;
 
-       subreq = sendall_send(state, state->ev, state->fd, state->wb_resp,
-                             sizeof(struct winbindd_response), 0);
-       if (subreq == NULL) {
-               goto nomem;
+       if (closed_fd(fd)) {
+               tevent_req_error(req, EPIPE);
+               return tevent_req_post(req, ev);
        }
 
-       subreq->async.fn = wb_resp_write_main;
-       subreq->async.priv = result;
-       return result;
+       wb_req->length = sizeof(struct winbindd_request);
 
- nomem:
-       TALLOC_FREE(result);
-       return NULL;
+       state->ev = ev;
+       state->fd = fd;
+
+       subreq = wb_req_write_send(state, ev, queue, fd, wb_req);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, wb_simple_trans_write_done, req);
+
+       return req;
 }
 
-static void wb_resp_write_main(struct async_req *subreq)
+static void wb_simple_trans_write_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct resp_write_state *state = talloc_get_type_abort(
-               req->private_data, struct resp_write_state);
-       NTSTATUS status;
-
-       status = sendall_recv(subreq);
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct wb_simple_trans_state *state = tevent_req_data(
+               req, struct wb_simple_trans_state);
+       ssize_t ret;
+       int err;
+
+       ret = wb_req_write_recv(subreq, &err);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_error(req, status);
-               return;
-       }
-
-       if (state->wb_resp->length == sizeof(struct winbindd_response)) {
-               async_req_done(req);
+       if (ret == -1) {
+               tevent_req_error(req, err);
                return;
        }
-
-       subreq = sendall_send(
-               state, state->ev, state->fd,
-               state->wb_resp->extra_data.data,
-               state->wb_resp->length - sizeof(struct winbindd_response), 0);
-       if (async_req_nomem(subreq, req)) {
+       subreq = wb_resp_read_send(state, state->ev, state->fd);
+       if (tevent_req_nomem(subreq, req)) {
                return;
        }
-
-       subreq->async.fn = wb_resp_write_extra;
-       subreq->async.priv = req;
+       tevent_req_set_callback(subreq, wb_simple_trans_read_done, req);
 }
 
-static void wb_resp_write_extra(struct async_req *subreq)
+static void wb_simple_trans_read_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       NTSTATUS status;
-
-       status = sendall_recv(subreq);
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct wb_simple_trans_state *state = tevent_req_data(
+               req, struct wb_simple_trans_state);
+       ssize_t ret;
+       int err;
+
+       ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_error(req, status);
+       if (ret == -1) {
+               tevent_req_error(req, err);
                return;
        }
 
-       async_req_done(req);
+       tevent_req_done(req);
 }
 
-NTSTATUS wb_resp_write_recv(struct async_req *req)
+int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                        struct winbindd_response **presponse, int *err)
 {
-       return async_req_simple_recv(req);
+       struct wb_simple_trans_state *state = tevent_req_data(
+               req, struct wb_simple_trans_state);
+
+       if (tevent_req_is_unix_error(req, err)) {
+               return -1;
+       }
+       *presponse = talloc_move(mem_ctx, &state->wb_resp);
+       return 0;
 }