lib: Add "unique_id" to ctdbd_process_exists
[Samba.git] / source4 / smbd / service_stream.c
blob917a1876e07970ed1c66fd010f9e8918173cc835
1 /*
2 Unix SMB/CIFS implementation.
4 helper functions for stream based servers
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Stefan (metze) Metzmacher 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include <tevent.h>
25 #include "process_model.h"
26 #include "lib/util/server_id.h"
27 #include "lib/messaging/irpc.h"
28 #include "cluster/cluster.h"
29 #include "param/param.h"
30 #include "../lib/tsocket/tsocket.h"
31 #include "lib/util/util_net.h"
33 /* size of listen() backlog in smbd */
34 #define SERVER_LISTEN_BACKLOG 10
38 private structure for a single listening stream socket
40 struct stream_socket {
41 const struct stream_server_ops *ops;
42 struct loadparm_context *lp_ctx;
43 struct tevent_context *event_ctx;
44 const struct model_ops *model_ops;
45 struct socket_context *sock;
46 void *private_data;
51 close the socket and shutdown a stream_connection
53 void stream_terminate_connection(struct stream_connection *srv_conn, const char *reason)
55 struct tevent_context *event_ctx = srv_conn->event.ctx;
56 const struct model_ops *model_ops = srv_conn->model_ops;
57 struct loadparm_context *lp_ctx = srv_conn->lp_ctx;
58 TALLOC_CTX *frame = NULL;
60 if (!reason) reason = "unknown reason";
62 if (srv_conn->processing) {
63 DEBUG(3,("Terminating connection deferred - '%s'\n", reason));
64 } else {
65 DEBUG(3,("Terminating connection - '%s'\n", reason));
68 srv_conn->terminate = reason;
70 if (srv_conn->processing) {
71 /*
72 * if we're currently inside the stream_io_handler(),
73 * defer the termination to the end of stream_io_hendler()
75 * and we don't want to read or write to the connection...
77 tevent_fd_set_flags(srv_conn->event.fde, 0);
78 return;
81 frame = talloc_stackframe();
83 reason = talloc_strdup(frame, reason);
84 if (reason == NULL) {
85 reason = "OOM - unknown reason";
88 talloc_free(srv_conn->event.fde);
89 srv_conn->event.fde = NULL;
90 imessaging_cleanup(srv_conn->msg_ctx);
91 TALLOC_FREE(srv_conn);
92 model_ops->terminate(event_ctx, lp_ctx, reason);
94 TALLOC_FREE(frame);
97 /**
98 the select loop has indicated that a stream is ready for IO
100 static void stream_io_handler(struct stream_connection *conn, uint16_t flags)
102 conn->processing++;
103 if (flags & TEVENT_FD_WRITE) {
104 conn->ops->send_handler(conn, flags);
105 } else if (flags & TEVENT_FD_READ) {
106 conn->ops->recv_handler(conn, flags);
108 conn->processing--;
110 if (conn->terminate) {
111 stream_terminate_connection(conn, conn->terminate);
115 void stream_io_handler_fde(struct tevent_context *ev, struct tevent_fd *fde,
116 uint16_t flags, void *private_data)
118 struct stream_connection *conn = talloc_get_type(private_data,
119 struct stream_connection);
120 stream_io_handler(conn, flags);
123 void stream_io_handler_callback(void *private_data, uint16_t flags)
125 struct stream_connection *conn = talloc_get_type(private_data,
126 struct stream_connection);
127 stream_io_handler(conn, flags);
131 this creates a stream_connection from an already existing connection,
132 used for protocols, where a client connection needs to switched into
133 a server connection
135 NTSTATUS stream_new_connection_merge(struct tevent_context *ev,
136 struct loadparm_context *lp_ctx,
137 const struct model_ops *model_ops,
138 const struct stream_server_ops *stream_ops,
139 struct imessaging_context *msg_ctx,
140 void *private_data,
141 struct stream_connection **_srv_conn)
143 struct stream_connection *srv_conn;
145 srv_conn = talloc_zero(ev, struct stream_connection);
146 NT_STATUS_HAVE_NO_MEMORY(srv_conn);
148 srv_conn->private_data = private_data;
149 srv_conn->model_ops = model_ops;
150 srv_conn->socket = NULL;
151 srv_conn->server_id = cluster_id(0, 0);
152 srv_conn->ops = stream_ops;
153 srv_conn->msg_ctx = msg_ctx;
154 srv_conn->event.ctx = ev;
155 srv_conn->lp_ctx = lp_ctx;
156 srv_conn->event.fde = NULL;
158 *_srv_conn = srv_conn;
159 return NT_STATUS_OK;
163 called when a new socket connection has been established. This is called in the process
164 context of the new process (if appropriate)
166 static void stream_new_connection(struct tevent_context *ev,
167 struct loadparm_context *lp_ctx,
168 struct socket_context *sock,
169 struct server_id server_id, void *private_data)
171 struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket);
172 struct stream_connection *srv_conn;
174 srv_conn = talloc_zero(ev, struct stream_connection);
175 if (!srv_conn) {
176 DEBUG(0,("talloc(mem_ctx, struct stream_connection) failed\n"));
177 return;
180 talloc_steal(srv_conn, sock);
182 srv_conn->private_data = stream_socket->private_data;
183 srv_conn->model_ops = stream_socket->model_ops;
184 srv_conn->socket = sock;
185 srv_conn->server_id = server_id;
186 srv_conn->ops = stream_socket->ops;
187 srv_conn->event.ctx = ev;
188 srv_conn->lp_ctx = lp_ctx;
190 if (!socket_check_access(sock, "smbd", lpcfg_hosts_allow(NULL, lpcfg_default_service(lp_ctx)), lpcfg_hosts_deny(NULL, lpcfg_default_service(lp_ctx)))) {
191 stream_terminate_connection(srv_conn, "denied by access rules");
192 return;
195 srv_conn->event.fde = tevent_add_fd(ev, srv_conn, socket_get_fd(sock),
196 0, stream_io_handler_fde, srv_conn);
197 if (!srv_conn->event.fde) {
198 stream_terminate_connection(srv_conn, "tevent_add_fd() failed");
199 return;
202 /* setup to receive internal messages on this connection */
203 srv_conn->msg_ctx = imessaging_init(srv_conn,
204 lp_ctx,
205 srv_conn->server_id, ev);
206 if (!srv_conn->msg_ctx) {
207 stream_terminate_connection(srv_conn, "imessaging_init() failed");
208 return;
211 srv_conn->remote_address = socket_get_remote_addr(srv_conn->socket, srv_conn);
212 if (!srv_conn->remote_address) {
213 stream_terminate_connection(srv_conn, "socket_get_remote_addr() failed");
214 return;
217 srv_conn->local_address = socket_get_local_addr(srv_conn->socket, srv_conn);
218 if (!srv_conn->local_address) {
219 stream_terminate_connection(srv_conn, "socket_get_local_addr() failed");
220 return;
224 TALLOC_CTX *tmp_ctx;
225 const char *title;
226 struct server_id_buf idbuf;
228 tmp_ctx = talloc_new(srv_conn);
230 title = talloc_asprintf(tmp_ctx, "conn[%s] c[%s] s[%s] server_id[%s]",
231 stream_socket->ops->name,
232 tsocket_address_string(srv_conn->remote_address, tmp_ctx),
233 tsocket_address_string(srv_conn->local_address, tmp_ctx),
234 server_id_str_buf(server_id, &idbuf));
235 if (title) {
236 stream_connection_set_title(srv_conn, title);
238 talloc_free(tmp_ctx);
241 /* we're now ready to start receiving events on this stream */
242 TEVENT_FD_READABLE(srv_conn->event.fde);
244 /* call the server specific accept code */
245 stream_socket->ops->accept_connection(srv_conn);
250 called when someone opens a connection to one of our listening ports
252 static void stream_accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
253 uint16_t flags, void *private_data)
255 struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket);
257 /* ask the process model to create us a process for this new
258 connection. When done, it calls stream_new_connection()
259 with the newly created socket */
260 stream_socket->model_ops->accept_connection(ev, stream_socket->lp_ctx,
261 stream_socket->sock,
262 stream_new_connection, stream_socket);
266 setup a listen stream socket
267 if you pass *port == 0, then a port > 1024 is used
269 FIXME: This function is TCP/IP specific - uses an int rather than
270 a string for the port. Should leave allocating a port nr
271 to the socket implementation - JRV20070903
273 NTSTATUS stream_setup_socket(TALLOC_CTX *mem_ctx,
274 struct tevent_context *event_context,
275 struct loadparm_context *lp_ctx,
276 const struct model_ops *model_ops,
277 const struct stream_server_ops *stream_ops,
278 const char *family,
279 const char *sock_addr,
280 uint16_t *port,
281 const char *socket_options,
282 void *private_data)
284 NTSTATUS status;
285 struct stream_socket *stream_socket;
286 struct socket_address *socket_address;
287 struct tevent_fd *fde;
288 int i;
289 struct sockaddr_storage ss;
291 stream_socket = talloc_zero(mem_ctx, struct stream_socket);
292 NT_STATUS_HAVE_NO_MEMORY(stream_socket);
294 if (strcmp(family, "ip") == 0) {
295 /* we will get the real family from the address itself */
296 if (!interpret_string_addr(&ss, sock_addr, 0)) {
297 talloc_free(stream_socket);
298 return NT_STATUS_INVALID_ADDRESS;
301 socket_address = socket_address_from_sockaddr_storage(stream_socket, &ss, port?*port:0);
302 if (socket_address == NULL) {
303 TALLOC_FREE(stream_socket);
304 return NT_STATUS_NO_MEMORY;
307 status = socket_create(socket_address->family, SOCKET_TYPE_STREAM, &stream_socket->sock, 0);
308 NT_STATUS_NOT_OK_RETURN(status);
309 } else {
310 status = socket_create(family, SOCKET_TYPE_STREAM, &stream_socket->sock, 0);
311 NT_STATUS_NOT_OK_RETURN(status);
313 /* this is for non-IP sockets, eg. unix domain sockets */
314 socket_address = socket_address_from_strings(stream_socket,
315 stream_socket->sock->backend_name,
316 sock_addr, port?*port:0);
317 NT_STATUS_HAVE_NO_MEMORY(socket_address);
321 talloc_steal(stream_socket, stream_socket->sock);
323 stream_socket->lp_ctx = talloc_reference(stream_socket, lp_ctx);
325 /* ready to listen */
326 status = socket_set_option(stream_socket->sock, "SO_KEEPALIVE", NULL);
327 NT_STATUS_NOT_OK_RETURN(status);
329 if (socket_options != NULL) {
330 status = socket_set_option(stream_socket->sock, socket_options, NULL);
331 NT_STATUS_NOT_OK_RETURN(status);
334 /* TODO: set socket ACL's (host allow etc) here when they're
335 * implemented */
337 /* Some sockets don't have a port, or are just described from
338 * the string. We are indicating this by having port == NULL */
339 if (!port) {
340 status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0);
341 } else if (*port == 0) {
342 for (i = lpcfg_rpc_low_port(lp_ctx);
343 i <= lpcfg_rpc_high_port(lp_ctx);
344 i++) {
345 socket_address->port = i;
346 status = socket_listen(stream_socket->sock, socket_address,
347 SERVER_LISTEN_BACKLOG, 0);
348 if (NT_STATUS_IS_OK(status)) {
349 *port = i;
350 break;
353 } else {
354 status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0);
357 if (!NT_STATUS_IS_OK(status)) {
358 DEBUG(0,("Failed to listen on %s:%u - %s\n",
359 sock_addr, port ? (unsigned int)(*port) : 0,
360 nt_errstr(status)));
361 talloc_free(stream_socket);
362 return status;
365 /* Add the FD from the newly created socket into the event
366 * subsystem. it will call the accept handler whenever we get
367 * new connections */
369 fde = tevent_add_fd(event_context, stream_socket->sock,
370 socket_get_fd(stream_socket->sock),
371 TEVENT_FD_READ,
372 stream_accept_handler, stream_socket);
373 if (!fde) {
374 DEBUG(0,("Failed to setup fd event\n"));
375 talloc_free(stream_socket);
376 return NT_STATUS_NO_MEMORY;
379 /* we let events system to the close on the socket. This avoids
380 * nasty interactions with waiting for talloc to close the socket. */
381 tevent_fd_set_close_fn(fde, socket_tevent_fd_close_fn);
382 socket_set_flags(stream_socket->sock, SOCKET_FLAG_NOCLOSE);
384 stream_socket->private_data = talloc_reference(stream_socket, private_data);
385 stream_socket->ops = stream_ops;
386 stream_socket->event_ctx = event_context;
387 stream_socket->model_ops = model_ops;
389 return NT_STATUS_OK;
394 setup a connection title
396 void stream_connection_set_title(struct stream_connection *conn, const char *title)
398 conn->model_ops->set_title(conn->event.ctx, title);