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 "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 stream_socket {
const struct stream_server_ops *ops;
+ struct loadparm_context *lp_ctx;
struct event_context *event_ctx;
const struct model_ops *model_ops;
struct socket_context *sock;
struct event_context *event_ctx = srv_conn->event.ctx;
const struct model_ops *model_ops = srv_conn->model_ops;
- if (!reason) reason = "unknwon reason";
+ if (!reason) reason = "unknown 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()
+ * defer the termination to the end of stream_io_hendler()
*
* and we don't want to read or write to the connection...
*/
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;
+ conn->processing = true;
if (flags & EVENT_FD_WRITE) {
conn->ops->send_handler(conn, flags);
} else if (flags & EVENT_FD_READ) {
conn->ops->recv_handler(conn, flags);
}
- conn->processing = False;
+ conn->processing = false;
if (conn->terminate) {
stream_terminate_connection(conn, conn->terminate);
}
}
-void stream_io_handler_callback(void *conn, uint16_t flags)
+static void stream_io_handler_fde(struct event_context *ev, struct fd_event *fde,
+ uint16_t flags, void *private)
{
- stream_io_handler(NULL, NULL, flags, conn);
+ 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);
}
/*
srv_conn->private = private_data;
srv_conn->model_ops = model_ops;
srv_conn->socket = sock;
- srv_conn->server_id = 0;
+ srv_conn->server_id = cluster_id(0, 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);
+ stream_io_handler_fde, srv_conn);
*_srv_conn = srv_conn;
return NT_STATUS_OK;
}
context of the new process (if appropriate)
*/
static void stream_new_connection(struct event_context *ev,
+ struct loadparm_context *lp_ctx,
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;
srv_conn->server_id = server_id;
srv_conn->ops = stream_socket->ops;
srv_conn->event.ctx = ev;
+ srv_conn->lp_ctx = lp_ctx;
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_default_service(lp_ctx)), lp_hostsdeny(NULL, lp_default_service(lp_ctx)))) {
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, lp_ctx),
+ srv_conn->server_id,
+ lp_iconv_convenience(lp_ctx),
+ ev);
if (!srv_conn->msg_ctx) {
stream_terminate_connection(srv_conn, "messaging_init() failed");
return;
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]",
+ 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,
- server_id);
+ 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);
}
/* ask the process model to create us a process for this new
connection. When done, it calls stream_new_connection()
with the newly created socket */
- stream_socket->model_ops->accept_connection(ev, stream_socket->sock,
+ stream_socket->model_ops->accept_connection(ev, stream_socket->lp_ctx,
+ stream_socket->sock,
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,
+ struct loadparm_context *lp_ctx,
const struct model_ops *model_ops,
const struct stream_server_ops *stream_ops,
const char *family,
const char *sock_addr,
uint16_t *port,
+ const char *socket_options,
void *private)
{
NTSTATUS status;
talloc_steal(stream_socket, stream_socket->sock);
+ stream_socket->lp_ctx = talloc_reference(stream_socket, lp_ctx);
+
/* ready to listen */
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);
- NT_STATUS_NOT_OK_RETURN(status);
+ if (socket_options != NULL) {
+ status = socket_set_option(stream_socket->sock, socket_options, NULL);
+ NT_STATUS_NOT_OK_RETURN(status);
+ }
+
+ /* TODO: set socket ACL's (host allow etc) here when they're
+ * implemented */
- /* TODO: set socket ACL's here when they're implemented */
+ /* Some sockets don't have a port, or are just described from
+ * the string. We are indicating this by having port == NULL */
+ if (!port) {
+ socket_address = socket_address_from_strings(stream_socket,
+ stream_socket->sock->backend_name,
+ sock_addr, 0);
+ NT_STATUS_HAVE_NO_MEMORY(socket_address);
+ status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0);
+ talloc_free(socket_address);
- if (*port == 0) {
+ } else if (*port == 0) {
for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
socket_address = socket_address_from_strings(stream_socket,
stream_socket->sock->backend_name,
return status;
}
+ /* By specifying EVENT_FD_AUTOCLOSE below, we indicate that we
+ * will close the socket using the events system. This avoids
+ * nasty interactions with waiting for talloc to close the socket. */
+
+ socket_set_flags(stream_socket->sock, SOCKET_FLAG_NOCLOSE);
+
+ /* Add the FD from the newly created socket into the event
+ * subsystem. it will call the accept handler whenever we get
+ * new connections */
+
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;