From aa19318fd513fb4d6a36793b96fb7ffa66622d6f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 28 Oct 2004 05:09:42 +0000 Subject: r3307: fixed the send side of the smb_server code to be non-blocking. This means the whole of the SMB handling code is now non-blocking. (This used to be commit 30acedb943f0170d30e7b08925280d0dffc7873e) --- source4/smb_server/request.c | 18 +++++------------- source4/smb_server/smb_server.c | 42 ++++++++++++++++++++++++++++++++++++----- source4/smb_server/smb_server.h | 7 +++++++ 3 files changed, 49 insertions(+), 18 deletions(-) (limited to 'source4') diff --git a/source4/smb_server/request.c b/source4/smb_server/request.c index 4ca9c9ffda..3095d0b70c 100644 --- a/source4/smb_server/request.c +++ b/source4/smb_server/request.c @@ -241,24 +241,16 @@ void req_grow_data(struct smbsrv_request *req, uint_t new_size) */ void req_send_reply_nosign(struct smbsrv_request *req) { - NTSTATUS status; - DATA_BLOB tmp_blob; - size_t sendlen; - if (req->out.size > NBT_HDR_SIZE) { _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE); } - tmp_blob.data = req->out.buffer; - tmp_blob.length = req->out.size; - - status = socket_send(req->smb_conn->connection->socket, &tmp_blob, &sendlen, SOCKET_FLAG_BLOCK); - if (!NT_STATUS_IS_OK(status) || (req->out.size != sendlen)) { - smbsrv_terminate_connection(req->smb_conn, "failed to send reply\n"); - return; - } + /* 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; } /* diff --git a/source4/smb_server/smb_server.c b/source4/smb_server/smb_server.c index 91de20bb31..ff83bfc80c 100644 --- a/source4/smb_server/smb_server.c +++ b/source4/smb_server/smb_server.c @@ -804,8 +804,42 @@ static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags */ static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags) { - DEBUG(10,("smbsrv_send\n")); - return; + struct smbsrv_connection *smb_conn = conn->private_data; + + while (smb_conn->pending_send) { + struct smbsrv_request *req = smb_conn->pending_send; + DATA_BLOB blob; + NTSTATUS status; + size_t sendlen; + + blob.data = req->out.buffer; + blob.length = req->out.size; + + /* send as much of this request as we can */ + status = socket_send(conn->socket, &blob, &sendlen, 0); + if (NT_STATUS_IS_ERR(status)) { + smbsrv_terminate_connection(req->smb_conn, nt_errstr(status)); + return; + } + if (sendlen == 0) { + break; + } + + req->out.buffer += sendlen; + req->out.size -= sendlen; + + /* is the whole request gone? */ + if (req->out.size == 0) { + DLIST_REMOVE(smb_conn->pending_send, req); + req_destroy(req); + } + } + + /* if no more requests are pending to be sent then + we should stop select for write */ + if (smb_conn->pending_send == NULL) { + conn->event.fde->flags &= ~EVENT_FD_WRITE; + } } /* @@ -860,11 +894,9 @@ void smbsrv_accept(struct server_connection *conn) DEBUG(5,("smbsrv_accept\n")); - smb_conn = talloc_p(conn, struct smbsrv_connection); + smb_conn = talloc_zero_p(conn, struct smbsrv_connection); if (!smb_conn) return; - ZERO_STRUCTP(smb_conn); - smb_conn->pid = getpid(); sub_set_context(&smb_conn->substitute); diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h index 4fdbdfe671..4de2aac907 100644 --- a/source4/smb_server/smb_server.h +++ b/source4/smb_server/smb_server.h @@ -74,6 +74,9 @@ struct smbsrv_tcon { /* the context for a single SMB request. This is passed to any request-context functions */ struct smbsrv_request { + /* the smbsrv_connection needs a list of requests queued for send */ + struct smbsrv_request *next, *prev; + /* the server_context contains all context specific to this SMB socket */ struct smbsrv_connection *smb_conn; @@ -289,4 +292,8 @@ struct smbsrv_connection { /* this holds a partially received request */ struct smbsrv_request *partial_req; + + /* this holds list of replies that are waiting to be sent + to the client */ + struct smbsrv_request *pending_send; }; -- cgit