r1578: the first stage of the async client rewrite.
[amitay/samba.git] / source4 / libcli / raw / rawrequest.c
index 139f031178578cb6f34ff52b6f621cc05777166e..ce6cd0a1a49c567a908f4b0d583cd32fcfb32010 100644 (file)
@@ -40,9 +40,11 @@ NTSTATUS cli_request_destroy(struct cli_request *req)
           _send() call fails completely */
        if (!req) return NT_STATUS_UNSUCCESSFUL;
 
-       /* remove it from the list of pending requests (a null op if
-          its not in the list) */
-       DLIST_REMOVE(req->transport->pending_requests, req);
+       if (req->transport) {
+               /* remove it from the list of pending requests (a null op if
+                  its not in the list) */
+               DLIST_REMOVE(req->transport->pending_recv, req);
+       }
 
        /* ahh, its so nice to destroy a complex structure in such a
           simple way! */
@@ -77,6 +79,7 @@ struct cli_request *cli_request_setup_nonsmb(struct cli_transport *transport, ui
        ZERO_STRUCTP(req);
 
        /* setup the request context */
+       req->state = CLI_REQUEST_INIT;
        req->mem_ctx = mem_ctx;
        req->transport = transport;
        req->session = NULL;
@@ -101,7 +104,7 @@ struct cli_request *cli_request_setup_nonsmb(struct cli_transport *transport, ui
   setup a SMB packet at transport level
 */
 struct cli_request *cli_request_setup_transport(struct cli_transport *transport,
-                                               uint8 command, unsigned wct, unsigned buflen)
+                                               uint8_t command, uint_t wct, uint_t buflen)
 {
        struct cli_request *req;
 
@@ -147,11 +150,11 @@ struct cli_request *cli_request_setup_transport(struct cli_transport *transport,
   way. This interface is used before a session is setup.
 */
 struct cli_request *cli_request_setup_session(struct cli_session *session,
-                                             uint8 command, unsigned wct, unsigned buflen)
+                                             uint8_t command, uint_t wct, uint_t buflen)
 {
        struct cli_request *req;
-       uint16 flags2;
-       uint32 capabilities;
+       uint16_t flags2;
+       uint32_t capabilities;
 
        req = cli_request_setup_transport(session->transport, command, wct, buflen);
 
@@ -187,8 +190,8 @@ struct cli_request *cli_request_setup_session(struct cli_session *session,
   setup a request for tree based commands
 */
 struct cli_request *cli_request_setup(struct cli_tree *tree,
-                                     uint8 command, 
-                                     unsigned wct, unsigned buflen)
+                                     uint8_t command, 
+                                     uint_t wct, uint_t buflen)
 {
        struct cli_request *req;
 
@@ -208,7 +211,7 @@ struct cli_request *cli_request_setup(struct cli_tree *tree,
   To cope with this req->out.ptr is supplied. This will be updated to
   point at the same offset into the packet as before this call
 */
-static void cli_req_grow_allocation(struct cli_request *req, unsigned new_size)
+static void cli_req_grow_allocation(struct cli_request *req, uint_t new_size)
 {
        int delta;
        char *buf2;
@@ -249,7 +252,7 @@ static void cli_req_grow_allocation(struct cli_request *req, unsigned new_size)
   To cope with this req->out.ptr is supplied. This will be updated to
   point at the same offset into the packet as before this call
 */
-static void cli_req_grow_data(struct cli_request *req, unsigned new_size)
+static void cli_req_grow_data(struct cli_request *req, uint_t new_size)
 {
        int delta;
 
@@ -264,6 +267,7 @@ static void cli_req_grow_data(struct cli_request *req, unsigned new_size)
        SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
 }
 
+
 /*
   send a message
 */
@@ -275,17 +279,8 @@ BOOL cli_request_send(struct cli_request *req)
 
        cli_request_calculate_sign_mac(req);
 
-       if (req->out.size != cli_sock_write(req->transport->socket, req->out.buffer, req->out.size)) {
-               req->transport->error.etype = ETYPE_SOCKET;
-               req->transport->error.e.socket_error = SOCKET_WRITE_ERROR;
-               DEBUG(0,("Error writing %d bytes to server - %s\n",
-                        (int)req->out.size, strerror(errno)));
-               return False;
-       }
+       cli_transport_send(req);
 
-       /* add it to the list of pending requests */
-       DLIST_ADD(req->transport->pending_requests, req);
-       
        return True;
 }
 
@@ -300,12 +295,8 @@ BOOL cli_request_receive(struct cli_request *req)
        if (!req) return False;
 
        /* keep receiving packets until this one is replied to */
-       while (!req->in.buffer) {
-               if (!cli_transport_select(req->transport)) {
-                       return False;
-               }
-
-               cli_request_receive_next(req->transport);
+       while (req->state <= CLI_REQUEST_RECV) {
+               event_loop_once(req->transport->event.ctx);
        }
 
        return True;
@@ -316,7 +307,7 @@ BOOL cli_request_receive(struct cli_request *req)
   handle oplock break requests from the server - return True if the request was
   an oplock break
 */
-static BOOL handle_oplock_break(struct cli_transport *transport, uint_t len, const char *hdr, const char *vwv)
+BOOL handle_oplock_break(struct cli_transport *transport, uint_t len, const char *hdr, const char *vwv)
 {
        /* we must be very fussy about what we consider an oplock break to avoid
           matching readbraw replies */
@@ -330,167 +321,15 @@ static BOOL handle_oplock_break(struct cli_transport *transport, uint_t len, con
        }
 
        if (transport->oplock.handler) {
-               uint16 tid = SVAL(hdr, HDR_TID);
-               uint16 fnum = SVAL(vwv,VWV(2));
-               uint8 level = CVAL(vwv,VWV(3));
+               uint16_t tid = SVAL(hdr, HDR_TID);
+               uint16_t fnum = SVAL(vwv,VWV(2));
+               uint8_t level = CVAL(vwv,VWV(3)+1);
                transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
        }
 
        return True;
 }
 
-
-/*
-  receive an async message from the server
-  this function assumes that the caller already knows that the socket is readable
-  and that there is a packet waiting
-
-  The packet is not actually returned by this function, instead any
-  registered async message handlers are called
-
-  return True if a packet was successfully received and processed
-  return False if the socket appears to be dead
-*/
-BOOL cli_request_receive_next(struct cli_transport *transport)
-{
-       BOOL ret;
-       int len;
-       char header[NBT_HDR_SIZE];
-       char *buffer, *hdr, *vwv;
-       TALLOC_CTX *mem_ctx;
-       struct cli_request *req;
-       uint16 wct, mid = 0;
-
-       len = cli_sock_read(transport->socket, header, 4);
-       if (len != 4) {
-               return False;
-       }
-       
-       len = smb_len(header);
-
-       mem_ctx = talloc_init("cli_request_receive_next");
-       
-       /* allocate the incoming buffer at the right size */
-       buffer = talloc(mem_ctx, len+NBT_HDR_SIZE);
-       if (!buffer) {
-               talloc_destroy(mem_ctx);
-               return False;
-       }
-
-       /* fill in the already received header */
-       memcpy(buffer, header, NBT_HDR_SIZE);
-
-       ret = cli_sock_read(transport->socket, buffer + NBT_HDR_SIZE, len);
-       /* If the server is not responding, note that now */
-       if (ret != len) {
-               return False;
-       }
-
-       hdr = buffer+NBT_HDR_SIZE;
-       vwv = hdr + HDR_VWV;
-
-       /* see if it could be an oplock break request */
-       if (handle_oplock_break(transport, len, hdr, vwv)) {
-               goto done;
-       }
-
-       /* at this point we need to check for a readbraw reply, as these can be any length */
-       if (transport->readbraw_pending) {
-               transport->readbraw_pending = 0;
-
-               /* it must match the first entry in the pending queue as the client is not allowed
-                  to have outstanding readbraw requests */
-               req = transport->pending_requests;
-               if (!req) goto done;
-
-               req->in.buffer = buffer;
-               talloc_steal(mem_ctx, req->mem_ctx, buffer);
-               req->in.size = len + NBT_HDR_SIZE;
-               req->in.allocated = req->in.size;
-               goto async;
-       }
-
-       if (len >= MIN_SMB_SIZE) {
-               /* extract the mid for matching to pending requests */
-               mid = SVAL(hdr, HDR_MID);
-               wct = CVAL(hdr, HDR_WCT);
-       }
-
-       /* match the incoming request against the list of pending requests */
-       for (req=transport->pending_requests; req; req=req->next) {
-               if (req->mid == mid) break;
-       }
-
-       if (!req) {
-               DEBUG(3,("Discarding unmatched reply with mid %d\n", mid));
-               goto done;
-       }
-
-       /* fill in the 'in' portion of the matching request */
-       req->in.buffer = buffer;
-       talloc_steal(mem_ctx, req->mem_ctx, buffer);
-       req->in.size = len + NBT_HDR_SIZE;
-       req->in.allocated = req->in.size;
-
-       /* handle non-SMB replies */
-       if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE) {
-               goto done;
-       }
-
-       if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
-               DEBUG(2,("bad reply size for mid %d\n", mid));
-               req->status = NT_STATUS_UNSUCCESSFUL;
-               goto done;
-       }
-
-       req->in.hdr = hdr;
-       req->in.vwv = vwv;
-       req->in.wct = wct;
-       if (req->in.size >= NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
-               req->in.data = req->in.vwv + VWV(wct) + 2;
-               req->in.data_size = SVAL(req->in.vwv, VWV(wct));
-               if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + req->in.data_size) {
-                       DEBUG(3,("bad data size for mid %d\n", mid));
-                       /* blergh - w2k3 gives a bogus data size values in some
-                          openX replies */
-                       req->in.data_size = req->in.size - (NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct));
-               }
-       }
-       req->in.ptr = req->in.data;
-       req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
-
-       if (!(req->flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
-               transport->error.etype = ETYPE_DOS;
-               transport->error.e.dos.eclass = CVAL(req->in.hdr,HDR_RCLS);
-               transport->error.e.dos.ecode = SVAL(req->in.hdr,HDR_ERR);
-               req->status = dos_to_ntstatus(transport->error.e.dos.eclass, 
-                                             transport->error.e.dos.ecode);
-       } else {
-               transport->error.etype = ETYPE_NT;
-               transport->error.e.nt_status = NT_STATUS(IVAL(req->in.hdr, HDR_RCLS));
-               req->status = transport->error.e.nt_status;
-       }
-
-       if (!cli_request_check_sign_mac(req)) {
-               transport->error.etype = ETYPE_SOCKET;
-               transport->error.e.socket_error = SOCKET_READ_BAD_SIG;
-               return False;
-       };
-
-async:
-       /* if this request has an async handler then call that to
-          notify that the reply has been received. This might destroy
-          the request so it must happen last */
-       if (req->async.fn) {
-               req->async.fn(req);
-       }
-
-done:
-       talloc_destroy(mem_ctx);
-       return True;
-}
-
-
 /*
   wait for a reply to be received for a packet that just returns an error
   code and nothing more
@@ -513,7 +352,7 @@ BOOL cli_request_is_error(struct cli_request *req)
 
   return the number of bytes added to the packet
 */
-size_t cli_req_append_string(struct cli_request *req, const char *str, unsigned flags)
+size_t cli_req_append_string(struct cli_request *req, const char *str, uint_t flags)
 {
        size_t len;
 
@@ -544,7 +383,7 @@ size_t cli_req_append_string(struct cli_request *req, const char *str, unsigned
  this is used in places where the non-terminated string byte length is
  placed in the packet as a separate field  
 */
-size_t cli_req_append_string_len(struct cli_request *req, const char *str, unsigned flags, int *len)
+size_t cli_req_append_string_len(struct cli_request *req, const char *str, uint_t flags, int *len)
 {
        int diff = 0;
        size_t ret;
@@ -585,10 +424,10 @@ size_t cli_req_append_string_len(struct cli_request *req, const char *str, unsig
 
   if dest_len is -1 then no limit applies
 */
-size_t cli_req_append_ascii4(struct cli_request *req, const char *str, unsigned flags)
+size_t cli_req_append_ascii4(struct cli_request *req, const char *str, uint_t flags)
 {
        size_t size;
-       cli_req_append_bytes(req, (const uint8 *)"\4", 1);
+       cli_req_append_bytes(req, (const uint8_t *)"\4", 1);
        size = cli_req_append_string(req, str, flags);
        return size + 1;
 }
@@ -612,7 +451,7 @@ size_t cli_req_append_blob(struct cli_request *req, const DATA_BLOB *blob)
   append raw bytes into the data portion of the request packet
   return the number of bytes added
 */
-size_t cli_req_append_bytes(struct cli_request *req, const uint8 *bytes, size_t byte_len)
+size_t cli_req_append_bytes(struct cli_request *req, const uint8_t *bytes, size_t byte_len)
 {
        cli_req_grow_allocation(req, byte_len + req->out.data_size);
        memcpy(req->out.data + req->out.data_size, bytes, byte_len);
@@ -624,7 +463,7 @@ size_t cli_req_append_bytes(struct cli_request *req, const uint8 *bytes, size_t
   append variable block (type 5 buffer) into the data portion of the request packet
   return the number of bytes added
 */
-size_t cli_req_append_var_block(struct cli_request *req, const uint8 *bytes, uint16 byte_len)
+size_t cli_req_append_var_block(struct cli_request *req, const uint8_t *bytes, uint16_t byte_len)
 {
        cli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
        SCVAL(req->out.data + req->out.data_size, 0, 5);
@@ -651,7 +490,7 @@ size_t cli_req_append_var_block(struct cli_request *req, const uint8 *bytes, uin
   of bytes consumed in the packet is returned
 */
 static size_t cli_req_pull_ucs2(struct cli_request *req, TALLOC_CTX *mem_ctx,
-                               char **dest, const char *src, int byte_len, unsigned flags)
+                               char **dest, const char *src, int byte_len, uint_t flags)
 {
        int src_len, src_len2, alignment=0;
        ssize_t ret;
@@ -708,7 +547,7 @@ static size_t cli_req_pull_ucs2(struct cli_request *req, TALLOC_CTX *mem_ctx,
   of bytes consumed in the packet is returned
 */
 size_t cli_req_pull_ascii(struct cli_request *req, TALLOC_CTX *mem_ctx,
-                         char **dest, const char *src, int byte_len, unsigned flags)
+                         char **dest, const char *src, int byte_len, uint_t flags)
 {
        int src_len, src_len2;
        ssize_t ret;
@@ -751,7 +590,7 @@ size_t cli_req_pull_ascii(struct cli_request *req, TALLOC_CTX *mem_ctx,
   of bytes consumed in the packet is returned
 */
 size_t cli_req_pull_string(struct cli_request *req, TALLOC_CTX *mem_ctx, 
-                          char **dest, const char *src, int byte_len, unsigned flags)
+                          char **dest, const char *src, int byte_len, uint_t flags)
 {
        if (!(flags & STR_ASCII) && 
            (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
@@ -787,7 +626,7 @@ DATA_BLOB cli_req_pull_blob(struct cli_request *req, TALLOC_CTX *mem_ctx, const
 
 /* check that a lump of data in a request is within the bounds of the data section of
    the packet */
-static BOOL cli_req_data_oob(struct cli_request *req, const char *ptr, uint32 count)
+static BOOL cli_req_data_oob(struct cli_request *req, const char *ptr, uint32_t count)
 {
        /* be careful with wraparound! */
        if (ptr < req->in.data ||
@@ -820,21 +659,17 @@ BOOL cli_raw_pull_data(struct cli_request *req, const char *src, int len, char *
 /*
   put a NTTIME into a packet
 */
-
-void cli_push_nttime(void *base, uint16 offset, NTTIME *t)
+void cli_push_nttime(void *base, uint16_t offset, NTTIME t)
 {
-       SIVAL(base, offset,   t->low);
-       SIVAL(base, offset+4, t->high);
+       SBVAL(base, offset, t);
 }
 
 /*
   pull a NTTIME from a packet
 */
-NTTIME cli_pull_nttime(void *base, uint16 offset)
+NTTIME cli_pull_nttime(void *base, uint16_t offset)
 {
-       NTTIME ret;
-       ret.low = IVAL(base, offset);
-       ret.high = IVAL(base, offset+4);
+       NTTIME ret = BVAL(base, offset);
        return ret;
 }
 
@@ -853,7 +688,7 @@ NTTIME cli_pull_nttime(void *base, uint16 offset)
 */
 static size_t cli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
                                 DATA_BLOB *blob, const char **dest, 
-                                const char *src, int byte_len, unsigned flags)
+                                const char *src, int byte_len, uint_t flags)
 {
        int src_len, src_len2, alignment=0;
        ssize_t ret;
@@ -912,7 +747,7 @@ static size_t cli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
 */
 static size_t cli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
                                  DATA_BLOB *blob, const char **dest, 
-                                 const char *src, int byte_len, unsigned flags)
+                                 const char *src, int byte_len, uint_t flags)
 {
        int src_len, src_len2;
        ssize_t ret;
@@ -960,8 +795,8 @@ size_t cli_blob_pull_string(struct cli_session *session,
                            TALLOC_CTX *mem_ctx,
                            DATA_BLOB *blob, 
                            WIRE_STRING *dest, 
-                           uint16 len_offset, uint16 str_offset, 
-                           unsigned flags)
+                           uint16_t len_offset, uint16_t str_offset, 
+                           uint_t flags)
 {
        int extra;
        dest->s = NULL;
@@ -999,12 +834,58 @@ size_t cli_blob_pull_string(struct cli_session *session,
                                           blob->data+str_offset, dest->private_length, flags);
 }
 
+/*
+  pull a string from a blob, returning a talloced char *
+
+  Currently only used by the UNIX search info level.
+
+  the string length is limited by 2 things:
+   - the data size in the blob
+   - the end of string (null termination)
+
+  on failure zero is returned and dest->s is set to NULL, otherwise the number
+  of bytes consumed in the blob is returned
+*/
+size_t cli_blob_pull_unix_string(struct cli_session *session,
+                           TALLOC_CTX *mem_ctx,
+                           DATA_BLOB *blob, 
+                           const char **dest, 
+                           uint16_t str_offset, 
+                           uint_t flags)
+{
+       int extra = 0;
+       *dest = NULL;
+       
+       if (!(flags & STR_ASCII) && 
+           ((flags & STR_UNICODE) || 
+            (session->transport->negotiate.capabilities & CAP_UNICODE))) {
+               int align = 0;
+               if ((str_offset&1) && !(flags & STR_NOALIGN)) {
+                       align = 1;
+               }
+               if (flags & STR_LEN_NOTERM) {
+                       extra = 2;
+               }
+               return align + extra + cli_blob_pull_ucs2(mem_ctx, blob, dest, 
+                                                         blob->data+str_offset+align, 
+                                                         -1, flags);
+       }
+
+       if (flags & STR_LEN_NOTERM) {
+               extra = 1;
+       }
+
+       return extra + cli_blob_pull_ascii(mem_ctx, blob, dest,
+                                          blob->data+str_offset, -1, flags);
+}
+
+
 /*
   append a string into a blob
 */
 size_t cli_blob_append_string(struct cli_session *session,
                              TALLOC_CTX *mem_ctx, DATA_BLOB *blob, 
-                             const char *str, unsigned flags)
+                             const char *str, uint_t flags)
 {
        size_t max_len;
        int len;