r14079: I just found the setproctitle library from alt linux:-)
[jelmer/samba4-debian.git] / source / smbd / service_stream.c
index d832cc233db8fcb60d194315a7afafaef747926f..59e87304d3ae433c53b5de1b53be5cee7689ba76 100644 (file)
 
 #include "includes.h"
 #include "process_model.h"
-#include "events.h"
+#include "lib/events/events.h"
+#include "lib/socket/socket.h"
+#include "smbd/service.h"
 #include "smbd/service_stream.h"
+#include "lib/messaging/irpc.h"
 
 /* the range of ports to try for dcerpc over tcp endpoints */
 #define SERVER_TCP_LOW_PORT  1024
@@ -53,6 +56,24 @@ void stream_terminate_connection(struct stream_connection *srv_conn, const char
 {
        struct event_context *event_ctx = srv_conn->event.ctx;
        const struct model_ops *model_ops = srv_conn->model_ops;
+
+       if (!reason) reason = "unknwon reason";
+
+       srv_conn->terminate = reason;
+
+       if (srv_conn->processing) {
+               /* 
+                * if we're currently inside the stream_io_handler(),
+                * deferr the termination to the end of stream_io_hendler()
+                *
+                * and we don't want to read or write to the connection...
+                */
+               event_set_fd_flags(srv_conn->event.fde, 0);
+               return;
+       }
+
+       talloc_free(srv_conn->event.fde);
+       srv_conn->event.fde = NULL;
        talloc_free(srv_conn);
        model_ops->terminate(event_ctx, reason);
 }
@@ -61,20 +82,57 @@ void stream_terminate_connection(struct stream_connection *srv_conn, const char
   the select loop has indicated that a stream is ready for IO
 */
 static void stream_io_handler(struct event_context *ev, struct fd_event *fde, 
-                             struct timeval t, uint16_t flags)
+                             uint16_t flags, void *private)
 {
-       struct stream_connection *conn = talloc_get_type(fde->private, 
+       struct stream_connection *conn = talloc_get_type(private, 
                                                         struct stream_connection);
+
+       conn->processing = True;
        if (flags & EVENT_FD_WRITE) {
-               conn->ops->send_handler(conn, t, flags);
-               return;
+               conn->ops->send_handler(conn, flags);
+       } else if (flags & EVENT_FD_READ) {
+               conn->ops->recv_handler(conn, flags);
        }
+       conn->processing = False;
 
-       if (flags & EVENT_FD_READ) {
-               conn->ops->recv_handler(conn, t, flags);
+       if (conn->terminate) {
+               stream_terminate_connection(conn, conn->terminate);
        }
 }
 
+/*
+  this creates a stream_connection from an already existing connection,
+  used for protocols, where a client connection needs to switched into
+  a server connection
+*/
+NTSTATUS stream_new_connection_merge(struct event_context *ev,
+                                    const struct model_ops *model_ops,
+                                    struct socket_context *sock,
+                                    const struct stream_server_ops *stream_ops,
+                                    struct messaging_context *msg_ctx,
+                                    void *private_data,
+                                    struct stream_connection **_srv_conn)
+{
+       struct stream_connection *srv_conn;
+
+       srv_conn = talloc_zero(ev, struct stream_connection);
+       NT_STATUS_HAVE_NO_MEMORY(srv_conn);
+
+       talloc_steal(srv_conn, sock);
+
+       srv_conn->private       = private_data;
+       srv_conn->model_ops     = model_ops;
+       srv_conn->socket        = sock;
+       srv_conn->server_id     = 0;
+       srv_conn->ops           = stream_ops;
+       srv_conn->msg_ctx       = msg_ctx;
+       srv_conn->event.ctx     = ev;
+       srv_conn->event.fde     = event_add_fd(ev, srv_conn, socket_get_fd(sock),
+                                              EVENT_FD_READ, 
+                                              stream_io_handler, srv_conn);
+       *_srv_conn = srv_conn;
+       return NT_STATUS_OK;
+}
 
 /*
   called when a new socket connection has been established. This is called in the process
@@ -85,8 +143,8 @@ static void stream_new_connection(struct event_context *ev,
                                  uint32_t server_id, void *private)
 {
        struct stream_socket *stream_socket = talloc_get_type(private, struct stream_socket);
-       struct fd_event fde;
        struct stream_connection *srv_conn;
+       struct socket_address *c, *s;
 
        srv_conn = talloc_zero(ev, struct stream_connection);
        if (!srv_conn) {
@@ -96,19 +154,15 @@ static void stream_new_connection(struct event_context *ev,
 
        talloc_steal(srv_conn, sock);
 
-       fde.private     = srv_conn;
-       fde.fd          = socket_get_fd(sock);
-       fde.flags       = EVENT_FD_READ;
-       fde.handler     = stream_io_handler;
-
        srv_conn->private       = stream_socket->private;
        srv_conn->model_ops     = stream_socket->model_ops;
-       srv_conn->event.ctx     = ev;
-       srv_conn->event.fde     = &fde;
        srv_conn->socket        = sock;
        srv_conn->server_id     = server_id;
        srv_conn->ops           = stream_socket->ops;
-       srv_conn->event.fde     = event_add_fd(ev, &fde, srv_conn);
+       srv_conn->event.ctx     = ev;
+       srv_conn->event.fde     = event_add_fd(ev, srv_conn, socket_get_fd(sock),
+                                              EVENT_FD_READ, 
+                                              stream_io_handler, srv_conn);
 
        if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) {
                stream_terminate_connection(srv_conn, "denied by access rules");
@@ -122,6 +176,21 @@ static void stream_new_connection(struct event_context *ev,
                return;
        }
 
+       c = socket_get_peer_addr(sock, ev);
+       s = socket_get_my_addr(sock, ev);
+       if (s && c) {
+               const char *title;
+               title = talloc_asprintf(s, "conn[%s] c[%s:%u] s[%s:%u] server_id[%d]",
+                                       stream_socket->ops->name, 
+                                       c->addr, c->port, s->addr, s->port,
+                                       server_id);
+               if (title) {
+                       stream_connection_set_title(srv_conn, title);
+               }
+       }
+       talloc_free(c);
+       talloc_free(s);
+
        /* call the server specific accept code */
        stream_socket->ops->accept_connection(srv_conn);
 }
@@ -131,9 +200,9 @@ static void stream_new_connection(struct event_context *ev,
   called when someone opens a connection to one of our listening ports
 */
 static void stream_accept_handler(struct event_context *ev, struct fd_event *fde, 
-                                 struct timeval t, uint16_t flags)
+                                 uint16_t flags, void *private)
 {
-       struct stream_socket *stream_socket = talloc_get_type(fde->private, struct stream_socket);
+       struct stream_socket *stream_socket = talloc_get_type(private, struct stream_socket);
 
        /* ask the process model to create us a process for this new
           connection.  When done, it calls stream_new_connection()
@@ -158,7 +227,7 @@ NTSTATUS stream_setup_socket(struct event_context *event_context,
 {
        NTSTATUS status;
        struct stream_socket *stream_socket;
-       struct fd_event fde;
+       struct socket_address *socket_address;
        int i;
 
        stream_socket = talloc_zero(event_context, struct stream_socket);
@@ -180,15 +249,25 @@ NTSTATUS stream_setup_socket(struct event_context *event_context,
 
        if (*port == 0) {
                for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
-                       status = socket_listen(stream_socket->sock, sock_addr, i, 
+                       socket_address = socket_address_from_strings(stream_socket, 
+                                                                    stream_socket->sock->backend_name,
+                                                                    sock_addr, i);
+                       NT_STATUS_HAVE_NO_MEMORY(socket_address);
+                       status = socket_listen(stream_socket->sock, socket_address, 
                                               SERVER_LISTEN_BACKLOG, 0);
+                       talloc_free(socket_address);
                        if (NT_STATUS_IS_OK(status)) {
                                *port = i;
                                break;
                        }
                }
        } else {
-               status = socket_listen(stream_socket->sock, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0);
+               socket_address = socket_address_from_strings(stream_socket, 
+                                                            stream_socket->sock->backend_name,
+                                                            sock_addr, *port);
+               NT_STATUS_HAVE_NO_MEMORY(socket_address);
+               status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0);
+               talloc_free(socket_address);
        }
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -198,13 +277,9 @@ NTSTATUS stream_setup_socket(struct event_context *event_context,
                return status;
        }
 
-       /* we are only interested in read events on the listen socket */
-       fde.fd          = socket_get_fd(stream_socket->sock);
-       fde.flags       = EVENT_FD_READ;
-       fde.private     = stream_socket;
-       fde.handler     = stream_accept_handler;
-
-       event_add_fd(event_context, &fde, stream_socket->sock);
+       event_add_fd(event_context, stream_socket->sock, 
+                    socket_get_fd(stream_socket->sock), 
+                    EVENT_FD_READ, stream_accept_handler, stream_socket);
 
        stream_socket->private          = talloc_reference(stream_socket, private);
        stream_socket->ops              = stream_ops;
@@ -213,3 +288,11 @@ NTSTATUS stream_setup_socket(struct event_context *event_context,
 
        return NT_STATUS_OK;
 }
+
+/*
+  setup a connection title 
+*/
+void stream_connection_set_title(struct stream_connection *conn, const char *title)
+{
+       conn->model_ops->set_title(conn->event.ctx, title);
+}