This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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"
+#include "cluster/cluster.h"
+#include "param/param.h"
/* the range of ports to try for dcerpc over tcp endpoints */
#define SERVER_TCP_LOW_PORT 1024
{
struct event_context *event_ctx = srv_conn->event.ctx;
const struct model_ops *model_ops = srv_conn->model_ops;
+
+ if (!reason) reason = "unknown reason";
+
+ srv_conn->terminate = reason;
+
+ if (srv_conn->processing) {
+ /*
+ * if we're currently inside the stream_io_handler(),
+ * defer 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);
}
/*
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,
- uint16_t flags, void *private)
+static void stream_io_handler(struct stream_connection *conn, uint16_t flags)
{
- struct stream_connection *conn = talloc_get_type(private,
- struct stream_connection);
+ conn->processing = True;
if (flags & EVENT_FD_WRITE) {
conn->ops->send_handler(conn, flags);
- return;
+ } 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, flags);
+ if (conn->terminate) {
+ stream_terminate_connection(conn, conn->terminate);
}
}
+static void stream_io_handler_fde(struct event_context *ev, struct fd_event *fde,
+ uint16_t flags, void *private)
+{
+ struct stream_connection *conn = talloc_get_type(private,
+ struct stream_connection);
+ stream_io_handler(conn, flags);
+}
+
+void stream_io_handler_callback(void *private, uint16_t flags)
+{
+ struct stream_connection *conn = talloc_get_type(private,
+ struct stream_connection);
+ stream_io_handler(conn, flags);
+}
+
+/*
+ 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 = cluster_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_fde, 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
*/
static void stream_new_connection(struct event_context *ev,
struct socket_context *sock,
- uint32_t server_id, void *private)
+ struct server_id server_id, void *private)
{
struct stream_socket *stream_socket = talloc_get_type(private, struct stream_socket);
struct stream_connection *srv_conn;
+ struct socket_address *c, *s;
srv_conn = talloc_zero(ev, struct stream_connection);
if (!srv_conn) {
srv_conn->ops = stream_socket->ops;
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);
+ 0, stream_io_handler_fde, srv_conn);
- if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) {
+ if (!socket_check_access(sock, "smbd", lp_hostsallow(NULL), lp_hostsdeny(NULL))) {
stream_terminate_connection(srv_conn, "denied by access rules");
return;
}
/* setup to receive internal messages on this connection */
- srv_conn->msg_ctx = messaging_init(srv_conn, srv_conn->server_id, ev);
+ srv_conn->msg_ctx = messaging_init(srv_conn,
+ lp_messaging_path(srv_conn, global_loadparm),
+ srv_conn->server_id, ev);
if (!srv_conn->msg_ctx) {
stream_terminate_connection(srv_conn, "messaging_init() failed");
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[%s]",
+ stream_socket->ops->name,
+ c->addr, c->port, s->addr, s->port,
+ cluster_id_string(s, server_id));
+ if (title) {
+ stream_connection_set_title(srv_conn, title);
+ }
+ }
+ talloc_free(c);
+ talloc_free(s);
+
+ /* we're now ready to start receiving events on this stream */
+ EVENT_FD_READABLE(srv_conn->event.fde);
+
/* call the server specific accept code */
stream_socket->ops->accept_connection(srv_conn);
}
stream_new_connection, stream_socket);
}
-
-
/*
setup a listen stream socket
if you pass *port == 0, then a port > 1024 is used
+
+ FIXME: This function is TCP/IP specific - uses an int rather than
+ a string for the port. Should leave allocating a port nr
+ to the socket implementation - JRV20070903
*/
NTSTATUS stream_setup_socket(struct event_context *event_context,
const struct model_ops *model_ops,
{
NTSTATUS status;
struct stream_socket *stream_socket;
+ struct socket_address *socket_address;
int i;
stream_socket = talloc_zero(event_context, struct stream_socket);
status = socket_set_option(stream_socket->sock, "SO_KEEPALIVE", NULL);
NT_STATUS_NOT_OK_RETURN(status);
- status = socket_set_option(stream_socket->sock, lp_socket_options(), NULL);
+ status = socket_set_option(stream_socket->sock, lp_socket_options(global_loadparm),
+ NULL);
NT_STATUS_NOT_OK_RETURN(status);
/* TODO: set socket ACL's here when they're implemented */
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)) {
return status;
}
+ /* we will close the socket using the events system */
+ socket_set_flags(stream_socket->sock, SOCKET_FLAG_NOCLOSE);
+
event_add_fd(event_context, stream_socket->sock,
socket_get_fd(stream_socket->sock),
- EVENT_FD_READ, stream_accept_handler, stream_socket);
+ EVENT_FD_READ|EVENT_FD_AUTOCLOSE,
+ stream_accept_handler, stream_socket);
stream_socket->private = talloc_reference(stream_socket, private);
stream_socket->ops = stream_ops;
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);
+}