s4:libcli: convert smbcli_transport_connect_* to tevent_req
authorStefan Metzmacher <metze@samba.org>
Tue, 29 Nov 2011 10:57:11 +0000 (11:57 +0100)
committerStefan Metzmacher <metze@samba.org>
Wed, 30 Nov 2011 12:41:08 +0000 (13:41 +0100)
metze

source4/libcli/cliconnect.c
source4/libcli/raw/clisocket.c
source4/libcli/smb_composite/connect.c

index d670324c88cf161243bb99c3022583e710c9cac4..e25a4009859d05fd272ffd6649ced37757149d76 100644 (file)
@@ -58,7 +58,17 @@ bool smbcli_transport_establish(struct smbcli_state *cli,
                                struct nbt_name *calling,
                                struct nbt_name *called)
 {
-       return smbcli_transport_connect(cli->transport, calling, called);
+       uint32_t timeout_msec = cli->transport->options.request_timeout * 1000;
+       NTSTATUS status;
+
+       status = smbcli_transport_connect(cli->transport->socket,
+                                         timeout_msec,
+                                         calling, called);
+       if (!NT_STATUS_IS_OK(status)) {
+               return false;
+       }
+
+       return true;
 }
 
 /* wrapper around smb_raw_negotiate() */
index 70a83a493f03c8d317e885766f3282b872438e04..d0867b2023561525d077f152babbe5a39c9029e5 100644 (file)
@@ -21,6 +21,9 @@
 */
 
 #include "includes.h"
+#include "system/network.h"
+#include "../lib/async_req/async_sock.h"
+#include "../lib/util/tevent_ntstatus.h"
 #include "lib/events/events.h"
 #include "libcli/raw/libcliraw.h"
 #include "libcli/composite/composite.h"
 #include "libcli/resolve/resolve.h"
 #include "param/param.h"
 #include "libcli/raw/raw_proto.h"
+#include "../libcli/smb/read_smb.h"
+
+struct smbcli_transport_connect_state {
+       struct tevent_context *ev;
+       struct smbcli_socket *sock;
+       uint8_t *request;
+       struct iovec iov;
+       uint8_t *response;
+};
 
-/*
-  send a session request
-*/
-struct smbcli_request *smbcli_transport_connect_send(struct smbcli_transport *transport,
-                                                    struct nbt_name *calling, 
-                                                    struct nbt_name *called)
+static void smbcli_transport_connect_writev_done(struct tevent_req *subreq);
+static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq);
+
+struct tevent_req *smbcli_transport_connect_send(TALLOC_CTX *mem_ctx,
+                                                struct tevent_context *ev,
+                                                struct smbcli_socket *sock,
+                                                uint32_t timeout_msec,
+                                                struct nbt_name *calling,
+                                                struct nbt_name *called)
 {
-       uint8_t *p;
-       struct smbcli_request *req;
+       struct tevent_req *req;
+       struct smbcli_transport_connect_state *state;
+       struct tevent_req *subreq;
        DATA_BLOB calling_blob, called_blob;
-       TALLOC_CTX *tmp_ctx = talloc_new(transport);
+       uint8_t *p;
        NTSTATUS status;
 
-       status = nbt_name_dup(transport, called, &transport->called);
-       if (!NT_STATUS_IS_OK(status)) goto failed;
-       
-       status = nbt_name_to_blob(tmp_ctx, &calling_blob, calling);
-       if (!NT_STATUS_IS_OK(status)) goto failed;
+       req = tevent_req_create(mem_ctx, &state,
+                               struct smbcli_transport_connect_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->ev = ev;
+       state->sock = sock;
+
+       if (sock->port != 139) {
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
+       }
 
-       status = nbt_name_to_blob(tmp_ctx, &called_blob, called);
-       if (!NT_STATUS_IS_OK(status)) goto failed;
+       status = nbt_name_to_blob(state, &calling_blob, calling);
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
 
-       /* allocate output buffer */
-       req = smbcli_request_setup_nonsmb(transport, 
-                                         NBT_HDR_SIZE + 
-                                         calling_blob.length + called_blob.length);
-       if (req == NULL) goto failed;
+       status = nbt_name_to_blob(state, &called_blob, called);
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
+
+       state->request = talloc_array(state, uint8_t,
+                                     NBT_HDR_SIZE +
+                                     called_blob.length +
+                                     calling_blob.length);
+       if (tevent_req_nomem(state->request, req)) {
+               return tevent_req_post(req, ev);
+       }
 
        /* put in the destination name */
-       p = req->out.buffer + NBT_HDR_SIZE;
+       p = state->request + NBT_HDR_SIZE;
        memcpy(p, called_blob.data, called_blob.length);
        p += called_blob.length;
 
        memcpy(p, calling_blob.data, calling_blob.length);
        p += calling_blob.length;
 
-       _smb_setlen_nbt(req->out.buffer, PTR_DIFF(p, req->out.buffer) - NBT_HDR_SIZE);
-       SCVAL(req->out.buffer,0,0x81);
+       _smb_setlen_nbt(state->request,
+                       PTR_DIFF(p, state->request) - NBT_HDR_SIZE);
+       SCVAL(state->request, 0, NBSSrequest);
+
+       state->iov.iov_len = talloc_array_length(state->request);
+       state->iov.iov_base = (void *)state->request;
 
-       if (!smbcli_request_send(req)) {
-               smbcli_request_destroy(req);
-               goto failed;
+       subreq = writev_send(state, ev, NULL,
+                            sock->sock->fd,
+                            true, /* err_on_readability */
+                            &state->iov, 1);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
+       tevent_req_set_callback(subreq,
+                               smbcli_transport_connect_writev_done,
+                               req);
 
-       talloc_free(tmp_ctx);
-       return req;
+       if (timeout_msec > 0) {
+               struct timeval endtime;
 
-failed:
-       talloc_free(tmp_ctx);
-       return NULL;
+               endtime = timeval_current_ofs_msec(timeout_msec);
+               if (!tevent_req_set_endtime(req, ev, endtime)) {
+                       return tevent_req_post(req, ev);
+               }
+       }
+
+       return req;
 }
 
-/*
-  map a session request error to a NTSTATUS
- */
-static NTSTATUS map_session_refused_error(uint8_t error)
+static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
 {
-       switch (error) {
-       case 0x80:
-       case 0x81:
-               return NT_STATUS_REMOTE_NOT_LISTENING;
-       case 0x82:
-               return NT_STATUS_RESOURCE_NAME_NOT_FOUND;
-       case 0x83:
-               return NT_STATUS_REMOTE_RESOURCES;
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct smbcli_transport_connect_state *state =
+               tevent_req_data(req,
+               struct smbcli_transport_connect_state);
+       ssize_t ret;
+       int err;
+
+       ret = writev_recv(subreq, &err);
+       TALLOC_FREE(subreq);
+       if (ret == -1) {
+               NTSTATUS status = map_nt_error_from_unix_common(err);
+
+               close(state->sock->sock->fd);
+               state->sock->sock->fd = -1;
+
+               tevent_req_nterror(req, status);
+               return;
        }
-       return NT_STATUS_UNEXPECTED_IO_ERROR;
-}
 
+       subreq = read_smb_send(state, state->ev,
+                              state->sock->sock->fd);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq,
+                               smbcli_transport_connect_read_smb_done,
+                               req);
+}
 
-/*
-  finish a smbcli_transport_connect()
-*/
-NTSTATUS smbcli_transport_connect_recv(struct smbcli_request *req)
+static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
 {
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct smbcli_transport_connect_state *state =
+               tevent_req_data(req,
+               struct smbcli_transport_connect_state);
+       ssize_t ret;
+       int err;
        NTSTATUS status;
+       uint8_t error;
+
+       ret = read_smb_recv(subreq, state,
+                           &state->response, &err);
+       if (ret == -1) {
+               status = map_nt_error_from_unix_common(err);
+
+               close(state->sock->sock->fd);
+               state->sock->sock->fd = -1;
 
-       if (!smbcli_request_receive(req)) {
-               smbcli_request_destroy(req);
-               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+               tevent_req_nterror(req, status);
+               return;
        }
 
-       switch (CVAL(req->in.buffer,0)) {
-       case 0x82:
-               status = NT_STATUS_OK;
-               break;
-       case 0x83:
-               status = map_session_refused_error(CVAL(req->in.buffer,4));
+       if (ret < 4) {
+               close(state->sock->sock->fd);
+               state->sock->sock->fd = -1;
+
+               tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+               return;
+       }
+
+       switch (CVAL(state->response, 0)) {
+       case NBSSpositive:
+               tevent_req_done(req);
+               return;
+
+       case NBSSnegative:
+               if (ret < 5) {
+                       close(state->sock->sock->fd);
+                       state->sock->sock->fd = -1;
+
+                       tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+                       return;
+               }
+
+               error = CVAL(state->response, 4);
+               switch (error) {
+               case 0x80:
+               case 0x81:
+                       status = NT_STATUS_REMOTE_NOT_LISTENING;
+                       break;
+               case 0x82:
+                       status = NT_STATUS_RESOURCE_NAME_NOT_FOUND;
+                       break;
+               case 0x83:
+                       status = NT_STATUS_REMOTE_RESOURCES;
+                       break;
+               default:
+                       status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+                       break;
+               }
                break;
-       case 0x84:
+
+       case NBSSretarget:
                DEBUG(1,("Warning: session retarget not supported\n"));
                status = NT_STATUS_NOT_SUPPORTED;
                break;
+
        default:
-               status = NT_STATUS_UNEXPECTED_IO_ERROR;
+               status = NT_STATUS_INVALID_NETWORK_RESPONSE;
                break;
        }
 
-       smbcli_request_destroy(req);
-       return status;
-}
+       close(state->sock->sock->fd);
+       state->sock->sock->fd = -1;
 
+       tevent_req_nterror(req, status);
+}
 
-/*
-  send a session request (if needed)
-*/
-bool smbcli_transport_connect(struct smbcli_transport *transport,
-                             struct nbt_name *calling, 
-                             struct nbt_name *called)
+NTSTATUS smbcli_transport_connect_recv(struct tevent_req *req)
 {
-       struct smbcli_request *req;
-       NTSTATUS status;
+       return tevent_req_simple_recv_ntstatus(req);
+}
 
-       if (transport->socket->port == 445) {
-               return true;
+NTSTATUS smbcli_transport_connect(struct smbcli_socket *sock,
+                                 uint32_t timeout_msec,
+                                 struct nbt_name *calling,
+                                 struct nbt_name *called)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+       bool ok;
+
+       ev = tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
        }
-
-       req = smbcli_transport_connect_send(transport, 
+       req = smbcli_transport_connect_send(frame, ev, sock,
+                                           timeout_msec,
                                            calling, called);
+       if (req == NULL) {
+               goto fail;
+       }
+       ok = tevent_req_poll(req, ev);
+       if (!ok) {
+               status = map_nt_error_from_unix_common(errno);
+               goto fail;
+       }
        status = smbcli_transport_connect_recv(req);
-       return NT_STATUS_IS_OK(status);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
 }
 
 struct sock_connect_state {
index d36bf2691410d4b3c0a95b4a322a154cb16ab933..306b96c1679717df9cddddde2ad7f3c5cd79970c 100644 (file)
@@ -52,11 +52,13 @@ struct connect_state {
        struct smb_composite_sesssetup *io_setup;
        struct smbcli_request *req;
        struct composite_context *creq;
+       struct tevent_req *subreq;
 };
 
 
 static void request_handler(struct smbcli_request *);
 static void composite_handler(struct composite_context *);
+static void subreq_handler(struct tevent_req *subreq);
 
 /*
   a tree connect request has completed
@@ -301,7 +303,8 @@ static NTSTATUS connect_session_request(struct composite_context *c,
        struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
        NTSTATUS status;
 
-       status = smbcli_transport_connect_recv(state->req);
+       status = smbcli_transport_connect_recv(state->subreq);
+       TALLOC_FREE(state->subreq);
        NT_STATUS_NOT_OK_RETURN(status);
 
        /* next step is a negprot */
@@ -317,6 +320,7 @@ static NTSTATUS connect_socket(struct composite_context *c,
        struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
        NTSTATUS status;
        struct nbt_name calling, called;
+       uint32_t timeout_msec = io->in.options.request_timeout * 1000;
 
        status = smbcli_sock_connect_recv(state->creq, state, &state->sock);
        NT_STATUS_NOT_OK_RETURN(status);
@@ -340,21 +344,18 @@ static NTSTATUS connect_socket(struct composite_context *c,
 
        nbt_choose_called_name(state, &called, io->in.called_name, NBT_NAME_SERVER);
 
-       /* we have a connected socket - next step is a session
-          request, if needed. Port 445 doesn't need it, so it goes
-          straight to the negprot */
-       if (state->sock->port == 445) {
-               status = nbt_name_dup(state->transport, &called, 
-                                     &state->transport->called);
-               NT_STATUS_NOT_OK_RETURN(status);
-               return connect_send_negprot(c, io);
-       }
+       status = nbt_name_dup(state->transport, &called,
+                             &state->transport->called);
+       NT_STATUS_NOT_OK_RETURN(status);
 
-       state->req = smbcli_transport_connect_send(state->transport, &calling, &called);
-       NT_STATUS_HAVE_NO_MEMORY(state->req);
+       state->subreq = smbcli_transport_connect_send(state,
+                                                     state->transport->ev,
+                                                     state->transport->socket,
+                                                     timeout_msec,
+                                                     &calling, &called);
+       NT_STATUS_HAVE_NO_MEMORY(state->subreq);
 
-       state->req->async.fn = request_handler;
-       state->req->async.private_data = c;
+       tevent_req_set_callback(state->subreq, subreq_handler, c);
        state->stage = CONNECT_SESSION_REQUEST;
 
        return NT_STATUS_OK;
@@ -420,6 +421,17 @@ static void composite_handler(struct composite_context *creq)
        state_handler(c);
 }
 
+/*
+  handler for completion of a tevent_req sub-request
+*/
+static void subreq_handler(struct tevent_req *subreq)
+{
+       struct composite_context *c =
+               tevent_req_callback_data(subreq,
+               struct composite_context);
+       state_handler(c);
+}
+
 /*
   a function to establish a smbcli_tree from scratch
 */