r3591: to get a bit more useful info from valgrind I'm disabling the
[samba.git] / source4 / smb_server / request.c
index e3f54bde654552294445f247b849b5ceb1bd698c..fddf63b1f71b9d05d0afa0836dfedeb99d52c264 100644 (file)
 */
 
 #include "includes.h"
+#include "events.h"
+#include "dlinklist.h"
+#include "smb_server/smb_server.h"
+
 
 /* we over allocate the data buffer to prevent too many realloc calls */
-#define REQ_OVER_ALLOCATION 256
+#define REQ_OVER_ALLOCATION 0
 
 /* destroy a request structure */
 void req_destroy(struct smbsrv_request *req)
 {
-       /* the request might be marked protected. This is done by the
-        * SMBecho code for example */
-       if (req->control_flags & REQ_CONTROL_PROTECTED) {
-               return;
-       }
-
        /* ahh, its so nice to destroy a complex structure in such a
         * simple way! */
-       talloc_destroy(req->mem_ctx);
+       talloc_free(req);
 }
 
 /****************************************************************************
@@ -48,20 +46,10 @@ such as change notify and oplock break requests
 struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
 {
        struct smbsrv_request *req;
-       TALLOC_CTX *mem_ctx;
-
-       /* each request gets its own talloc context. The request
-          structure itself is also allocated inside this context, so
-          we need to allocate it before we construct the request
-       */
-       mem_ctx = talloc_init("request_context[%d]", smb_conn->connection->socket->pkt_count);
-       if (!mem_ctx) {
-               return NULL;
-       }
 
-       smb_conn->connection->socket->pkt_count++;
+       smb_conn->pkt_count++;
 
-       req = talloc(mem_ctx, sizeof(*req));
+       req = talloc_p(smb_conn, struct smbsrv_request);
        if (!req) {
                return NULL;
        }
@@ -70,8 +58,14 @@ struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
 
        /* setup the request context */
        req->smb_conn = smb_conn;
-       req->mem_ctx = mem_ctx;
-       
+
+       req->async_states = talloc_p(req, struct ntvfs_async_state);
+       if (!req->async_states) {
+               talloc_free(req);
+               return NULL;
+       }
+       req->async_states->state = 0;
+
        return req;
 }
 
@@ -89,7 +83,7 @@ static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t
        /* over allocate by a small amount */
        req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
 
-       req->out.buffer = talloc_realloc(req->out.buffer, req->out.allocated);
+       req->out.buffer = talloc_realloc(req, req->out.buffer, req->out.allocated);
        if (!req->out.buffer) {
                smbsrv_terminate_connection(req->smb_conn, "allocation failed");
        }
@@ -123,7 +117,7 @@ void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
        /* over allocate by a small amount */
        req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
 
-       req->out.buffer = talloc(req->mem_ctx, req->out.allocated);
+       req->out.buffer = talloc(req, req->out.allocated);
        if (!req->out.buffer) {
                smbsrv_terminate_connection(req->smb_conn, "allocation failed");
        }
@@ -165,6 +159,37 @@ void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
        }
 }
 
+
+/*
+  setup a copy of a request, used when the server needs to send
+  more than one reply for a single request packet
+*/
+struct smbsrv_request *req_setup_secondary(struct smbsrv_request *old_req)
+{
+       struct smbsrv_request *req;
+       ptrdiff_t diff;
+
+       req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
+       if (req == NULL) {
+               return NULL;
+       }
+
+       req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
+       if (req->out.buffer == NULL) {
+               talloc_free(req);
+               return NULL;
+       }
+
+       diff = req->out.buffer - old_req->out.buffer;
+
+       req->out.hdr  += diff;
+       req->out.vwv  += diff;
+       req->out.data += diff;
+       req->out.ptr  += diff;
+
+       return req;
+}
+
 /*
   work out the maximum data size we will allow for this reply, given
   the negotiated max_xmit. The basic reply packet must be setup before
@@ -203,7 +228,7 @@ static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
 
        /* we need to realloc */
        req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
-       buf2 = talloc_realloc(req->out.buffer, req->out.allocated);
+       buf2 = talloc_realloc(req, req->out.buffer, req->out.allocated);
        if (buf2 == NULL) {
                smb_panic("out of memory in req_grow_allocation");
        }
@@ -262,11 +287,12 @@ void req_send_reply_nosign(struct smbsrv_request *req)
                _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
        }
 
-       if (write_data(req->smb_conn->connection->socket->fde->fd, req->out.buffer, req->out.size) != req->out.size) {
-               smbsrv_terminate_connection(req->smb_conn, "failed to send reply\n");
-       }
+       /* add the request to the list of requests that need to be
+          sent to the client, then mark the socket event structure
+          ready for write events */
+       DLIST_ADD_END(req->smb_conn->pending_send, req, struct smbsrv_request *);
 
-       req_destroy(req);
+       req->smb_conn->connection->event.fde->flags |= EVENT_FD_WRITE;
 }
 
 /*
@@ -382,7 +408,7 @@ size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int
                dest = req->out.buffer + PTR_DIFF(dest, buf0);
        }
 
-       len = push_string(req->out.hdr, dest, str, len, flags);
+       len = push_string(dest, str, len, flags);
 
        grow_size = len + PTR_DIFF(dest, req->out.data);
 
@@ -398,7 +424,7 @@ size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int
   return the number of bytes added
 */
 size_t req_append_bytes(struct smbsrv_request *req, 
-               const uint8_t *bytes, size_t byte_len)
+                       const uint8_t *bytes, size_t byte_len)
 {
        req_grow_allocation(req, byte_len + req->out.data_size);
        memcpy(req->out.data + req->out.data_size, bytes, byte_len);
@@ -438,6 +464,7 @@ static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const
 {
        int src_len, src_len2, alignment=0;
        ssize_t ret;
+       char *dest2;
 
        if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
                src++;
@@ -461,19 +488,14 @@ static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const
                }
        }
 
-       src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
-
-       if (src_len2 <= src_len - 2) {
-               /* include the termination if we didn't reach the end of the packet */
-               src_len2 += 2;
-       }
-
-       ret = convert_string_talloc(req->mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
+       src_len2 = utf16_len_n(src, src_len);
+       ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
 
        if (ret == -1) {
                *dest = NULL;
                return 0;
        }
+       *dest = dest2;
 
        return src_len2 + alignment;
 }
@@ -495,6 +517,7 @@ static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, cons
 {
        int src_len, src_len2;
        ssize_t ret;
+       char *dest2;
 
        if (flags & STR_NO_RANGE_CHECK) {
                src_len = byte_len;
@@ -515,12 +538,13 @@ static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, cons
                src_len2++;
        }
 
-       ret = convert_string_talloc(req->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
+       ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
 
        if (ret == -1) {
                *dest = NULL;
                return 0;
        }
+       *dest = dest2;
 
        return src_len2;
 }
@@ -564,7 +588,7 @@ size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const char
 
        if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
                /* win2000 treats this as the NULL string! */
-               (*dest) = talloc_strdup(req->mem_ctx, "");
+               (*dest) = talloc_strdup(req, "");
                return 0;
        }
 
@@ -575,7 +599,7 @@ size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const char
 
        ret = req_pull_string(req, dest, src, -1, flags);
        if (ret == -1) {
-               (*dest) = talloc_strdup(req->mem_ctx, "");
+               (*dest) = talloc_strdup(req, "");
                return 1;
        }
        
@@ -593,7 +617,7 @@ BOOL req_pull_blob(struct smbsrv_request *req, const char *src, int len, DATA_BL
                return False;
        }
 
-       (*blob) = data_blob_talloc(req->mem_ctx, src, len);
+       (*blob) = data_blob_talloc(req, src, len);
 
        return True;
 }