Add wb_simple_trans_send/recv
[ira/wip.git] / source3 / lib / wb_reqtrans.c
index a5adf8f10841c6e3129da3701d06c1ecd1f58561..c11561f14e8726ff080e2dc6bfd97388cc45e881 100644 (file)
 struct req_read_state {
        struct winbindd_request *wb_req;
        size_t max_extra_data;
+       ssize_t ret;
 };
 
-bool async_req_is_wbcerr(struct async_req *req, wbcErr *pwbc_err)
-{
-       enum async_req_state state;
-       uint64_t error;
-       if (!async_req_is_error(req, &state, &error)) {
-               *pwbc_err = WBC_ERR_SUCCESS;
-               return false;
-       }
-
-       switch (state) {
-       case ASYNC_REQ_USER_ERROR:
-               *pwbc_err = error;
-               break;
-       case ASYNC_REQ_TIMED_OUT:
-               *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
-               break;
-       case ASYNC_REQ_NO_MEMORY:
-               *pwbc_err = WBC_ERR_NO_MEMORY;
-               break;
-       default:
-               *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
-               break;
-       }
-       return true;
-}
-
-wbcErr map_wbc_err_from_errno(int error)
-{
-       switch(error) {
-       case EPERM:
-       case EACCES:
-               return WBC_ERR_AUTH_ERROR;
-       case ENOMEM:
-               return WBC_ERR_NO_MEMORY;
-       case EIO:
-       default:
-               return WBC_ERR_UNKNOWN_FAILURE;
-       }
-}
-
-wbcErr async_req_simple_recv_wbcerr(struct async_req *req)
-{
-       wbcErr wbc_err;
-
-       if (async_req_is_wbcerr(req, &wbc_err)) {
-               return wbc_err;
-       }
-
-       return WBC_ERR_SUCCESS;
-}
-
 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 tevent_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;
-       struct tevent_req *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->max_extra_data = max_extra_data;
 
        subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
-       if (subreq == NULL) {
-               goto nomem;
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
-
-       subreq->async.fn = wb_req_read_done;
-       subreq->async.private_data = result;
-       return result;
- nomem:
-       TALLOC_FREE(result);
-       return NULL;
+       tevent_req_set_callback(subreq, wb_req_read_done, req);
+       return req;
 }
 
 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
@@ -140,18 +84,17 @@ 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 *req = talloc_get_type_abort(
-               subreq->async.private_data, struct async_req);
-       struct req_read_state *state = talloc_get_type_abort(
-               req->private_data, struct req_read_state);
+       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;
-       ssize_t ret;
        uint8_t *buf;
 
-       ret = read_packet_recv(subreq, state, &buf, &err);
+       state->ret = read_packet_recv(subreq, state, &buf, &err);
        TALLOC_FREE(subreq);
-       if (ret == -1) {
-               async_req_error(req, map_wbc_err_from_errno(err));
+       if (state->ret == -1) {
+               tevent_req_error(req, err);
                return;
        }
 
@@ -163,40 +106,40 @@ static void wb_req_read_done(struct tevent_req *subreq)
        } else {
                state->wb_req->extra_data.data = NULL;
        }
-       async_req_done(req);
+       tevent_req_done(req);
 }
 
-wbcErr wb_req_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
-                       struct winbindd_request **preq)
+ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                        struct winbindd_request **preq, int *err)
 {
-       struct req_read_state *state = talloc_get_type_abort(
-               req->private_data, struct req_read_state);
-       wbcErr wbc_err;
+       struct req_read_state *state = tevent_req_data(
+               req, struct req_read_state);
 
-       if (async_req_is_wbcerr(req, &wbc_err)) {
-               return wbc_err;
+       if (tevent_req_is_unix_error(req, err)) {
+               return -1;
        }
        *preq = talloc_move(mem_ctx, &state->wb_req);
-       return WBC_ERR_SUCCESS;
+       return state->ret;
 }
 
 struct req_write_state {
        struct iovec iov[2];
+       ssize_t ret;
 };
 
 static void wb_req_write_done(struct tevent_req *subreq);
 
-struct async_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
-                                   struct tevent_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;
-       struct tevent_req *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;
        }
 
@@ -209,70 +152,74 @@ struct async_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
                count = 2;
        }
 
-       subreq = writev_send(state, ev, fd, state->iov, count);
-       if (subreq == NULL) {
-               goto fail;
+       subreq = writev_send(state, ev, queue, fd, state->iov, count);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
-       subreq->async.fn = wb_req_write_done;
-       subreq->async.private_data = result;
-       return result;
-
- fail:
-       TALLOC_FREE(result);
-       return NULL;
+       tevent_req_set_callback(subreq, wb_req_write_done, req);
+       return req;
 }
 
 static void wb_req_write_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.private_data, struct async_req);
+       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;
-       ssize_t ret;
 
-       ret = writev_recv(subreq, &err);
-       TALLOC_FREE(subreq);
-       if (ret < 0) {
-               async_req_error(req, map_wbc_err_from_errno(err));
+       state->ret = writev_recv(subreq, &err);
+       /*
+        * We do not TALLOC_FREE(subreq) here, as this would trigger the next
+        * write of a client. The winbind protocol is purely request/response
+        * without multiplex ID's, so having multiple requeusts on the fly
+        * would confuse sequencing.
+        *
+        * Eventually the writev_req will be freed, "subreq" a child of "req"
+        */
+       if (state->ret < 0) {
+               tevent_req_error(req, err);
                return;
        }
-       async_req_done(req);
+       tevent_req_done(req);
 }
 
-wbcErr 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_wbcerr(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;
+       ssize_t ret;
 };
 
 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 tevent_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;
-       struct tevent_req *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;
        }
 
        subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
-       if (subreq == NULL) {
-               goto nomem;
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
-       subreq->async.fn = wb_resp_read_done;
-       subreq->async.private_data = result;
-       return result;
-
- nomem:
-       TALLOC_FREE(result);
-       return NULL;
+       tevent_req_set_callback(subreq, wb_resp_read_done, req);
+       return req;
 }
 
 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
@@ -288,23 +235,22 @@ static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
                        return -1;
                }
        }
-       return resp->length - 4;
+       return resp->length - buflen;
 }
 
 static void wb_resp_read_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.private_data, struct async_req);
-       struct resp_read_state *state = talloc_get_type_abort(
-               req->private_data, struct resp_read_state);
+       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;
-       ssize_t ret;
 
-       ret = read_packet_recv(subreq, state, &buf, &err);
+       state->ret = read_packet_recv(subreq, state, &buf, &err);
        TALLOC_FREE(subreq);
-       if (ret == -1) {
-               async_req_error(req, map_wbc_err_from_errno(err));
+       if (state->ret == -1) {
+               tevent_req_error(req, err);
                return;
        }
 
@@ -316,40 +262,40 @@ static void wb_resp_read_done(struct tevent_req *subreq)
        } else {
                state->wb_resp->extra_data.data = NULL;
        }
-       async_req_done(req);
+       tevent_req_done(req);
 }
 
-wbcErr wb_resp_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
-                        struct winbindd_response **presp)
+ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                         struct winbindd_response **presp, int *err)
 {
-       struct resp_read_state *state = talloc_get_type_abort(
-               req->private_data, struct resp_read_state);
-       wbcErr wbc_err;
+       struct resp_read_state *state = tevent_req_data(
+               req, struct resp_read_state);
 
-       if (async_req_is_wbcerr(req, &wbc_err)) {
-               return wbc_err;
+       if (tevent_req_is_unix_error(req, err)) {
+               return -1;
        }
        *presp = talloc_move(mem_ctx, &state->wb_resp);
-       return WBC_ERR_SUCCESS;
+       return state->ret;
 }
 
 struct resp_write_state {
        struct iovec iov[2];
+       ssize_t ret;
 };
 
 static void wb_resp_write_done(struct tevent_req *subreq);
 
-struct async_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
-                                   struct tevent_context *ev, int fd,
-                                   struct winbindd_response *wb_resp)
+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 async_req *result;
-       struct tevent_req *subreq;
+       struct tevent_req *req, *subreq;
        struct resp_write_state *state;
        int count = 1;
 
-       if (!async_req_setup(mem_ctx, &result, &state,
-                            struct resp_write_state)) {
+       req = tevent_req_create(mem_ctx, &state, struct resp_write_state);
+       if (req == NULL) {
                return NULL;
        }
 
@@ -363,36 +309,160 @@ struct async_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
                count = 2;
        }
 
-       subreq = writev_send(state, ev, fd, state->iov, count);
-       if (subreq == NULL) {
-               goto fail;
+       subreq = writev_send(state, ev, queue, fd, state->iov, count);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
-       subreq->async.fn = wb_resp_write_done;
-       subreq->async.private_data = result;
-       return result;
-
- fail:
-       TALLOC_FREE(result);
-       return NULL;
+       tevent_req_set_callback(subreq, wb_resp_write_done, req);
+       return req;
 }
 
 static void wb_resp_write_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.private_data, struct async_req);
+       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;
-       ssize_t ret;
 
-       ret = writev_recv(subreq, &err);
+       state->ret = writev_recv(subreq, &err);
        TALLOC_FREE(subreq);
-       if (ret < 0) {
-               async_req_error(req, map_wbc_err_from_errno(err));
+       if (state->ret < 0) {
+               tevent_req_error(req, err);
                return;
        }
-       async_req_done(req);
+       tevent_req_done(req);
 }
 
-wbcErr wb_resp_write_recv(struct async_req *req)
+ssize_t wb_resp_write_recv(struct tevent_req *req, int *err)
 {
-       return async_req_simple_recv_wbcerr(req);
+       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;
+}
+
+static bool closed_fd(int fd)
+{
+       struct timeval tv;
+       fd_set r_fds;
+
+       if (fd == -1) {
+               return true;
+       }
+
+       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 wb_simple_trans_state {
+       struct tevent_context *ev;
+       int fd;
+       struct winbindd_response *wb_resp;
+};
+
+static void wb_simple_trans_write_done(struct tevent_req *subreq);
+static void wb_simple_trans_read_done(struct tevent_req *subreq);
+
+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 tevent_req *req, *subreq;
+       struct wb_simple_trans_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       if (closed_fd(fd)) {
+               tevent_req_error(req, EPIPE);
+               return tevent_req_post(req, ev);
+       }
+
+       wb_req->length = sizeof(struct winbindd_request);
+
+       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_simple_trans_write_done(struct tevent_req *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);
+       /*
+        * We do not TALLOC_FREE(subreq) here, as this would trigger the next
+        * write of a client. The winbind protocol is purely request/response
+        * without multiplex ID's, so having multiple requeusts on the fly
+        * would confuse sequencing.
+        *
+        * Eventually the "subreq" will be freed, it is a child of "req"
+        */
+       if (ret == -1) {
+               tevent_req_error(req, err);
+               return;
+       }
+       subreq = wb_resp_read_send(state, state->ev, state->fd);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, wb_simple_trans_read_done, req);
+}
+
+static void wb_simple_trans_read_done(struct tevent_req *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);
+       if (ret == -1) {
+               tevent_req_error(req, err);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                        struct winbindd_response **presponse, int *err)
+{
+       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;
 }