s3:rpc_server: Switch to core dcerpc server loop
[Samba.git] / source3 / rpc_server / mdssd.c
blob24177e22b368cefc8576cb1b7e02e9557d3332a9
1 /*
2 * Unix SMB/CIFS implementation.
4 * mds service daemon
6 * Copyright (c) 2014 Ralph Boehme <rb@sernet.de>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "messages.h"
24 #include "ntdomain.h"
26 #include "lib/id_cache.h"
28 #include "../lib/tsocket/tsocket.h"
29 #include "lib/server_prefork.h"
30 #include "lib/server_prefork_util.h"
31 #include "librpc/rpc/dcerpc_ep.h"
32 #include "librpc/rpc/dcesrv_core.h"
34 #include "rpc_server/rpc_server.h"
35 #include "rpc_server/rpc_service_setup.h"
36 #include "rpc_server/rpc_ep_register.h"
37 #include "rpc_server/rpc_sock_helper.h"
38 #include "rpc_server/rpc_modules.h"
40 #include "librpc/gen_ndr/srv_mdssvc.h"
41 #include "rpc_server/mdssvc/srv_mdssvc_nt.h"
42 #include "rpc_server/mdssd.h"
44 #undef DBGC_CLASS
45 #define DBGC_CLASS DBGC_RPC_SRV
47 #define DAEMON_NAME "mdssd"
48 #define MDSSD_MAX_SOCKETS 64
50 static struct server_id parent_id;
51 static struct prefork_pool *mdssd_pool = NULL;
52 static int mdssd_child_id = 0;
54 static struct pf_daemon_config default_pf_mdssd_cfg = {
55 .prefork_status = PFH_INIT,
56 .min_children = 5,
57 .max_children = 25,
58 .spawn_rate = 5,
59 .max_allowed_clients = 1000,
60 .child_min_life = 60 /* 1 minute minimum life time */
62 static struct pf_daemon_config pf_mdssd_cfg = { 0 };
64 static void mdssd_smb_conf_updated(struct messaging_context *msg,
65 void *private_data,
66 uint32_t msg_type,
67 struct server_id server_id,
68 DATA_BLOB *data)
70 struct tevent_context *ev_ctx;
72 DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
73 ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
75 change_to_root_user();
76 lp_load_global(get_dyn_CONFIGFILE());
78 reopen_logs();
79 if (mdssd_child_id == 0) {
80 pfh_daemon_config(DAEMON_NAME,
81 &pf_mdssd_cfg,
82 &default_pf_mdssd_cfg);
83 pfh_manage_pool(ev_ctx, msg, &pf_mdssd_cfg, mdssd_pool);
87 static void mdssd_sig_term_handler(struct tevent_context *ev,
88 struct tevent_signal *se,
89 int signum,
90 int count,
91 void *siginfo,
92 void *private_data)
94 exit_server_cleanly("termination signal");
97 static void mdssd_setup_sig_term_handler(struct tevent_context *ev_ctx)
99 struct tevent_signal *se;
101 se = tevent_add_signal(ev_ctx,
102 ev_ctx,
103 SIGTERM, 0,
104 mdssd_sig_term_handler,
105 NULL);
106 if (!se) {
107 exit_server("failed to setup SIGTERM handler");
111 static void mdssd_sig_hup_handler(struct tevent_context *ev,
112 struct tevent_signal *se,
113 int signum,
114 int count,
115 void *siginfo,
116 void *pvt)
119 change_to_root_user();
120 lp_load_global(get_dyn_CONFIGFILE());
122 reopen_logs();
123 pfh_daemon_config(DAEMON_NAME,
124 &pf_mdssd_cfg,
125 &default_pf_mdssd_cfg);
127 /* relay to all children */
128 prefork_send_signal_to_all(mdssd_pool, SIGHUP);
131 static void mdssd_setup_sig_hup_handler(struct tevent_context *ev_ctx)
133 struct tevent_signal *se;
135 se = tevent_add_signal(ev_ctx,
136 ev_ctx,
137 SIGHUP, 0,
138 mdssd_sig_hup_handler,
139 NULL);
140 if (!se) {
141 DEBUG(0, ("failed to setup SIGHUP handler\n"));
142 exit(1);
146 /**********************************************************
147 * Children
148 **********************************************************/
150 static void mdssd_chld_sig_hup_handler(struct tevent_context *ev,
151 struct tevent_signal *se,
152 int signum,
153 int count,
154 void *siginfo,
155 void *pvt)
157 change_to_root_user();
158 reopen_logs();
161 static bool mdssd_setup_chld_hup_handler(struct tevent_context *ev_ctx)
163 struct tevent_signal *se;
165 se = tevent_add_signal(ev_ctx,
166 ev_ctx,
167 SIGHUP, 0,
168 mdssd_chld_sig_hup_handler,
169 NULL);
170 if (!se) {
171 DEBUG(1, ("failed to setup SIGHUP handler"));
172 return false;
175 return true;
178 static void parent_ping(struct messaging_context *msg_ctx,
179 void *private_data,
180 uint32_t msg_type,
181 struct server_id server_id,
182 DATA_BLOB *data)
185 * The fact we received this message is enough to let make the
186 * event loop if it was idle. mdssd_children_main will cycle
187 * through mdssd_next_client at least once. That function will
188 * take whatever action is necessary
190 DEBUG(10, ("Got message that the parent changed status.\n"));
191 return;
194 static bool mdssd_child_init(struct tevent_context *ev_ctx,
195 int child_id,
196 struct pf_worker_data *pf)
198 NTSTATUS status;
199 struct messaging_context *msg_ctx = global_messaging_context();
200 bool ok;
202 status = reinit_after_fork(msg_ctx, ev_ctx,
203 true, "mdssd-child");
204 if (!NT_STATUS_IS_OK(status)) {
205 DEBUG(0,("reinit_after_fork() failed\n"));
206 smb_panic("reinit_after_fork() failed");
209 mdssd_child_id = child_id;
210 reopen_logs();
212 ok = mdssd_setup_chld_hup_handler(ev_ctx);
213 if (!ok) {
214 return false;
217 messaging_register(msg_ctx, ev_ctx,
218 MSG_SMB_CONF_UPDATED, mdssd_smb_conf_updated);
219 messaging_register(msg_ctx, ev_ctx,
220 MSG_PREFORK_PARENT_EVENT, parent_ping);
222 return true;
225 struct mdssd_children_data {
226 struct tevent_context *ev_ctx;
227 struct messaging_context *msg_ctx;
228 struct dcesrv_context *dce_ctx;
229 struct pf_worker_data *pf;
230 int listen_fd_size;
231 struct pf_listen_fd *listen_fds;
234 static void mdssd_next_client(void *pvt);
236 static int mdssd_children_main(struct tevent_context *ev_ctx,
237 struct messaging_context *msg_ctx,
238 struct pf_worker_data *pf,
239 int child_id,
240 int listen_fd_size,
241 struct pf_listen_fd *listen_fds,
242 void *private_data)
244 struct mdssd_children_data *data;
245 bool ok;
246 int ret = 0;
247 struct dcesrv_context *dce_ctx = NULL;
249 dce_ctx = talloc_get_type_abort(private_data, struct dcesrv_context);
251 ok = mdssd_child_init(ev_ctx, child_id, pf);
252 if (!ok) {
253 return 1;
256 data = talloc(ev_ctx, struct mdssd_children_data);
257 if (!data) {
258 return 1;
260 data->pf = pf;
261 data->ev_ctx = ev_ctx;
262 data->msg_ctx = msg_ctx;
263 data->dce_ctx = dce_ctx;
264 data->listen_fd_size = listen_fd_size;
265 data->listen_fds = listen_fds;
267 /* loop until it is time to exit */
268 while (pf->status != PF_WORKER_EXITING) {
269 /* try to see if it is time to schedule the next client */
270 mdssd_next_client(data);
272 ret = tevent_loop_once(ev_ctx);
273 if (ret != 0) {
274 DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
275 ret, strerror(errno)));
276 pf->status = PF_WORKER_EXITING;
280 return ret;
283 static void mdssd_client_terminated(struct dcesrv_connection *conn, void *pvt)
285 struct mdssd_children_data *data;
287 data = talloc_get_type_abort(pvt, struct mdssd_children_data);
289 pfh_client_terminated(data->pf);
291 mdssd_next_client(pvt);
294 struct mdssd_new_client {
295 struct mdssd_children_data *data;
298 static void mdssd_handle_client(struct tevent_req *req);
300 static void mdssd_next_client(void *pvt)
302 struct tevent_req *req;
303 struct mdssd_children_data *data;
304 struct mdssd_new_client *next;
306 data = talloc_get_type_abort(pvt, struct mdssd_children_data);
308 if (!pfh_child_allowed_to_accept(data->pf)) {
309 /* nothing to do for now we are already listening
310 * or we are not allowed to listen further */
311 return;
314 next = talloc_zero(data, struct mdssd_new_client);
315 if (!next) {
316 DEBUG(1, ("Out of memory!?\n"));
317 return;
319 next->data = data;
321 req = prefork_listen_send(next,
322 data->ev_ctx,
323 data->pf,
324 data->listen_fd_size,
325 data->listen_fds);
326 if (!req) {
327 DEBUG(1, ("Failed to make listening request!?\n"));
328 talloc_free(next);
329 return;
331 tevent_req_set_callback(req, mdssd_handle_client, next);
334 static void mdssd_handle_client(struct tevent_req *req)
336 struct mdssd_children_data *data;
337 struct mdssd_new_client *client;
338 const DATA_BLOB ping = data_blob_null;
339 int rc;
340 int sd;
341 TALLOC_CTX *tmp_ctx;
342 struct tsocket_address *srv_addr;
343 struct tsocket_address *cli_addr;
344 void *listen_fd_data = NULL;
345 struct dcesrv_endpoint *ep = NULL;
346 enum dcerpc_transport_t transport;
347 dcerpc_ncacn_termination_fn term_fn = NULL;
348 void *term_fn_data = NULL;
350 client = tevent_req_callback_data(req, struct mdssd_new_client);
351 data = client->data;
353 tmp_ctx = talloc_stackframe();
354 if (tmp_ctx == NULL) {
355 DEBUG(1, ("Failed to allocate stackframe!\n"));
356 return;
359 rc = prefork_listen_recv(req,
360 tmp_ctx,
361 &sd,
362 &listen_fd_data,
363 &srv_addr,
364 &cli_addr);
366 /* this will free the request too */
367 talloc_free(client);
369 if (rc != 0) {
370 DEBUG(6, ("No client connection was available after all!\n"));
371 goto done;
374 ep = talloc_get_type_abort(listen_fd_data, struct dcesrv_endpoint);
375 transport = dcerpc_binding_get_transport(ep->ep_description);
376 if (transport == NCACN_NP) {
377 term_fn = mdssd_client_terminated;
378 term_fn_data = data;
381 /* Warn parent that our status changed */
382 messaging_send(data->msg_ctx, parent_id,
383 MSG_PREFORK_CHILD_EVENT, &ping);
385 DBG_INFO("MDSSD preforked child %d got client connection on '%s'\n",
386 (int)(data->pf->pid), dcerpc_binding_string(tmp_ctx,
387 ep->ep_description));
389 dcerpc_ncacn_accept(data->ev_ctx,
390 data->msg_ctx,
391 data->dce_ctx,
393 cli_addr,
394 srv_addr,
396 term_fn,
397 term_fn_data);
399 done:
400 talloc_free(tmp_ctx);
404 * MAIN
407 static void child_ping(struct messaging_context *msg_ctx,
408 void *private_data,
409 uint32_t msg_type,
410 struct server_id server_id,
411 DATA_BLOB *data)
413 struct tevent_context *ev_ctx;
415 ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
417 DEBUG(10, ("Got message that a child changed status.\n"));
418 pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
421 static bool mdssd_schedule_check(struct tevent_context *ev_ctx,
422 struct messaging_context *msg_ctx,
423 struct timeval current_time);
425 static void mdssd_check_children(struct tevent_context *ev_ctx,
426 struct tevent_timer *te,
427 struct timeval current_time,
428 void *pvt);
430 static void mdssd_sigchld_handler(struct tevent_context *ev_ctx,
431 struct prefork_pool *pfp,
432 void *pvt)
434 struct messaging_context *msg_ctx;
436 msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
438 /* run pool management so we can fork/retire or increase
439 * the allowed connections per child based on load */
440 pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
443 static bool mdssd_setup_children_monitor(struct tevent_context *ev_ctx,
444 struct messaging_context *msg_ctx)
446 bool ok;
448 /* add our oun sigchld callback */
449 prefork_set_sigchld_callback(mdssd_pool, mdssd_sigchld_handler, msg_ctx);
451 ok = mdssd_schedule_check(ev_ctx, msg_ctx, tevent_timeval_current());
453 return ok;
456 static bool mdssd_schedule_check(struct tevent_context *ev_ctx,
457 struct messaging_context *msg_ctx,
458 struct timeval current_time)
460 struct tevent_timer *te;
461 struct timeval next_event;
463 /* check situation again in 10 seconds */
464 next_event = tevent_timeval_current_ofs(10, 0);
466 /* TODO: check when the socket becomes readable, so that children
467 * are checked only when there is some activity ? */
468 te = tevent_add_timer(ev_ctx, mdssd_pool, next_event,
469 mdssd_check_children, msg_ctx);
470 if (!te) {
471 DEBUG(2, ("Failed to set up children monitoring!\n"));
472 return false;
475 return true;
478 static void mdssd_check_children(struct tevent_context *ev_ctx,
479 struct tevent_timer *te,
480 struct timeval current_time,
481 void *pvt)
483 struct messaging_context *msg_ctx;
485 msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
487 pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
489 mdssd_schedule_check(ev_ctx, msg_ctx, current_time);
493 * start it up
496 static NTSTATUS mdssd_create_sockets(struct tevent_context *ev_ctx,
497 struct messaging_context *msg_ctx,
498 struct dcesrv_context *dce_ctx,
499 struct pf_listen_fd *listen_fd,
500 int *listen_fd_size)
502 NTSTATUS status;
503 int fd = -1;
504 int rc;
505 uint32_t i;
506 struct dcesrv_endpoint *e = NULL;
508 DBG_INFO("Initializing DCE/RPC connection endpoints\n");
510 for (e = dce_ctx->endpoint_list; e; e = e->next) {
511 status = dcesrv_create_endpoint_sockets(ev_ctx,
512 msg_ctx,
513 dce_ctx,
515 listen_fd,
516 listen_fd_size);
517 if (!NT_STATUS_IS_OK(status)) {
518 char *ep_string = dcerpc_binding_string(
519 dce_ctx, e->ep_description);
520 DBG_ERR("Failed to create endpoint '%s': %s\n",
521 ep_string, nt_errstr(status));
522 TALLOC_FREE(ep_string);
523 goto done;
527 for (i = 0; i < *listen_fd_size; i++) {
528 rc = listen(listen_fd[i].fd, pf_mdssd_cfg.max_allowed_clients);
529 if (rc == -1) {
530 char *ep_string = dcerpc_binding_string(
531 dce_ctx, e->ep_description);
532 DBG_ERR("Failed to listen on endpoint '%s': %s\n",
533 ep_string, strerror(errno));
534 status = map_nt_error_from_unix(errno);
535 TALLOC_FREE(ep_string);
536 goto done;
540 for (e = dce_ctx->endpoint_list; e; e = e->next) {
541 struct dcesrv_if_list *ifl = NULL;
542 for (ifl = e->interface_list; ifl; ifl = ifl->next) {
543 status = rpc_ep_register(ev_ctx,
544 msg_ctx,
545 dce_ctx,
546 ifl->iface);
547 if (!NT_STATUS_IS_OK(status)) {
548 DBG_ERR("Failed to register interface in "
549 "endpoint mapper: %s",
550 nt_errstr(status));
551 goto done;
556 status = NT_STATUS_OK;
557 done:
558 if (fd != -1) {
559 close(fd);
561 return status;
564 void start_mdssd(struct tevent_context *ev_ctx,
565 struct messaging_context *msg_ctx,
566 struct dcesrv_context *dce_ctx)
568 NTSTATUS status;
569 struct pf_listen_fd listen_fd[MDSSD_MAX_SOCKETS];
570 int listen_fd_size = 0;
571 pid_t pid;
572 int rc;
573 bool ok;
575 DEBUG(1, ("Forking Metadata Service Daemon\n"));
578 * Block signals before forking child as it will have to
579 * set its own handlers. Child will re-enable SIGHUP as
580 * soon as the handlers are set up.
582 BlockSignals(true, SIGTERM);
583 BlockSignals(true, SIGHUP);
585 pid = fork();
586 if (pid == -1) {
587 DEBUG(0, ("Failed to fork mdssd [%s], aborting ...\n",
588 strerror(errno)));
589 exit(1);
592 /* parent or error */
593 if (pid != 0) {
595 /* Re-enable SIGHUP before returnig */
596 BlockSignals(false, SIGTERM);
597 BlockSignals(false, SIGHUP);
599 return;
602 status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true, "mdssd-master");
603 if (!NT_STATUS_IS_OK(status)) {
604 DEBUG(0,("reinit_after_fork() failed\n"));
605 smb_panic("reinit_after_fork() failed");
608 reopen_logs();
610 /* save the parent process id so the children can use it later */
611 parent_id = messaging_server_id(msg_ctx);
613 pfh_daemon_config(DAEMON_NAME,
614 &pf_mdssd_cfg,
615 &default_pf_mdssd_cfg);
617 mdssd_setup_sig_term_handler(ev_ctx);
618 mdssd_setup_sig_hup_handler(ev_ctx);
620 BlockSignals(false, SIGTERM);
621 BlockSignals(false, SIGHUP);
623 /* The module setup function will register the endpoint server,
624 * necessary to setup the endpoints below. It is not possible to
625 * register it here because MDS service is built as a module.
627 ok = setup_rpc_module(ev_ctx, msg_ctx, "mdssvc");
628 if (!ok) {
629 DBG_ERR("Failed to setup DCE/RPC module\n");
630 exit(1);
633 DBG_INFO("Reinitializing DCE/RPC server context\n");
635 status = dcesrv_reinit_context(dce_ctx);
636 if (!NT_STATUS_IS_OK(status)) {
637 DBG_ERR("Failed to reinit DCE/RPC context: %s\n",
638 nt_errstr(status));
639 exit(1);
642 DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
644 /* Init ep servers */
645 status = dcesrv_init_ep_server(dce_ctx, "mdssvc");
646 if (!NT_STATUS_IS_OK(status)) {
647 DBG_ERR("Failed to init DCE/RPC endpoint server: %s\n",
648 nt_errstr(status));
649 exit(1);
652 status = mdssd_create_sockets(ev_ctx,
653 msg_ctx,
654 dce_ctx,
655 listen_fd,
656 &listen_fd_size);
657 if (!NT_STATUS_IS_OK(status)) {
658 exit(1);
661 /* start children before any more initialization is done */
662 ok = prefork_create_pool(ev_ctx, /* mem_ctx */
663 ev_ctx,
664 msg_ctx,
665 listen_fd_size,
666 listen_fd,
667 pf_mdssd_cfg.min_children,
668 pf_mdssd_cfg.max_children,
669 &mdssd_children_main,
670 dce_ctx,
671 &mdssd_pool);
672 if (!ok) {
673 exit(1);
676 messaging_register(msg_ctx,
677 ev_ctx,
678 MSG_SMB_CONF_UPDATED,
679 mdssd_smb_conf_updated);
680 messaging_register(msg_ctx, ev_ctx,
681 MSG_PREFORK_CHILD_EVENT, child_ping);
683 ok = mdssd_setup_children_monitor(ev_ctx, msg_ctx);
684 if (!ok) {
685 exit(1);
688 DEBUG(1, ("mdssd Daemon Started (%u)\n", (unsigned int)getpid()));
690 /* loop forever */
691 rc = tevent_loop_wait(ev_ctx);
693 /* should not be reached */
694 DEBUG(0,("mdssd: tevent_loop_wait() exited with %d - %s\n",
695 rc, (rc == 0) ? "out of events" : strerror(errno)));
696 exit(1);