2 Unix SMB/CIFS implementation.
5 Copyright (C) Simo Sorce <idra@samba.org> 2011
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/time.h"
25 #include "system/shmem.h"
26 #include "system/filesys.h"
27 #include "server_prefork.h"
28 #include "../lib/util/samba_util.h"
29 #include "../lib/util/tevent_unix.h"
33 struct pf_listen_fd
*listen_fds
;
35 prefork_main_fn_t
*main_fn
;
39 struct pf_worker_data
*pool
;
43 prefork_sigchld_fn_t
*sigchld_fn
;
47 static bool prefork_setup_sigchld_handler(struct tevent_context
*ev_ctx
,
48 struct prefork_pool
*pfp
);
50 static int prefork_pool_destructor(struct prefork_pool
*pfp
)
52 anonymous_shared_free(pfp
->pool
);
56 bool prefork_create_pool(TALLOC_CTX
*mem_ctx
,
57 struct tevent_context
*ev_ctx
,
58 struct messaging_context
*msg_ctx
,
59 int listen_fd_size
, struct pf_listen_fd
*listen_fds
,
60 int min_children
, int max_children
,
61 prefork_main_fn_t
*main_fn
, void *private_data
,
62 struct prefork_pool
**pf_pool
)
64 struct prefork_pool
*pfp
;
66 time_t now
= time(NULL
);
72 pfp
= talloc_zero(mem_ctx
, struct prefork_pool
);
74 DEBUG(1, ("Out of memory!\n"));
77 pfp
->listen_fd_size
= listen_fd_size
;
78 pfp
->listen_fds
= talloc_array(pfp
, struct pf_listen_fd
,
80 if (!pfp
->listen_fds
) {
81 DEBUG(1, ("Out of memory!\n"));
84 for (i
= 0; i
< listen_fd_size
; i
++) {
85 pfp
->listen_fds
[i
] = listen_fds
[i
];
86 /* force sockets in non-blocking mode */
87 set_blocking(listen_fds
[i
].fd
, false);
89 pfp
->main_fn
= main_fn
;
90 pfp
->private_data
= private_data
;
92 pfp
->pool_size
= max_children
;
93 data_size
= sizeof(struct pf_worker_data
) * max_children
;
95 pfp
->pool
= (struct pf_worker_data
*)anonymous_shared_allocate(
97 if (pfp
->pool
== NULL
) {
98 DEBUG(1, ("Failed to mmap memory for prefork pool!\n"));
102 talloc_set_destructor(pfp
, prefork_pool_destructor
);
104 for (i
= 0; i
< min_children
; i
++) {
106 pfp
->pool
[i
].allowed_clients
= 1;
107 pfp
->pool
[i
].started
= now
;
112 DEBUG(1, ("Failed to prefork child n. %d !\n", i
));
115 case 0: /* THE CHILD */
117 pfp
->pool
[i
].status
= PF_WORKER_ALIVE
;
118 ret
= pfp
->main_fn(ev_ctx
, msg_ctx
,
119 &pfp
->pool
[i
], i
+ 1,
125 default: /* THE PARENT */
126 pfp
->pool
[i
].pid
= pid
;
131 ok
= prefork_setup_sigchld_handler(ev_ctx
, pfp
);
133 DEBUG(1, ("Failed to setup SIGCHLD Handler!\n"));
142 /* Provide the new max children number in new_max
143 * (must be larger than current max).
144 * Returns: 0 if all fine
145 * ENOSPC if mremap fails to expand
146 * EINVAL if new_max is invalid
148 int prefork_expand_pool(struct prefork_pool
*pfp
, int new_max
)
150 struct prefork_pool
*pool
;
155 if (new_max
<= pfp
->pool_size
) {
159 old_size
= sizeof(struct pf_worker_data
) * pfp
->pool_size
;
160 new_size
= sizeof(struct pf_worker_data
) * new_max
;
162 pool
= (struct prefork_pool
*)anonymous_shared_resize(
163 &pfp
->pool
, new_size
, false);
166 DEBUG(3, ("Failed to mremap memory (%d: %s)!\n",
167 ret
, strerror(ret
)));
171 memset(&pool
[pfp
->pool_size
], 0, new_size
- old_size
);
173 pfp
->pool_size
= new_max
;
178 int prefork_add_children(struct tevent_context
*ev_ctx
,
179 struct messaging_context
*msg_ctx
,
180 struct prefork_pool
*pfp
,
184 time_t now
= time(NULL
);
188 for (i
= 0, j
= 0; i
< pfp
->pool_size
&& j
< num_children
; i
++) {
190 if (pfp
->pool
[i
].status
!= PF_WORKER_NONE
) {
194 pfp
->pool
[i
].allowed_clients
= 1;
195 pfp
->pool
[i
].started
= now
;
200 DEBUG(1, ("Failed to prefork child n. %d !\n", j
));
203 case 0: /* THE CHILD */
205 pfp
->pool
[i
].status
= PF_WORKER_ALIVE
;
206 ret
= pfp
->main_fn(ev_ctx
, msg_ctx
,
207 &pfp
->pool
[i
], i
+ 1,
212 pfp
->pool
[i
].status
= PF_WORKER_EXITING
;
215 default: /* THE PARENT */
216 pfp
->pool
[i
].pid
= pid
;
222 DEBUG(5, ("Added %d children!\n", j
));
227 struct prefork_oldest
{
232 /* sort in inverse order */
233 static int prefork_sort_oldest(const void *ap
, const void *bp
)
235 const struct prefork_oldest
*a
= (const struct prefork_oldest
*)ap
;
236 const struct prefork_oldest
*b
= (const struct prefork_oldest
*)bp
;
238 if (a
->started
== b
->started
) {
241 if (a
->started
< b
->started
) {
247 int prefork_retire_children(struct messaging_context
*msg_ctx
,
248 struct prefork_pool
*pfp
,
249 int num_children
, time_t age_limit
)
251 const DATA_BLOB ping
= data_blob_null
;
252 time_t now
= time(NULL
);
253 struct prefork_oldest
*oldest
;
256 oldest
= talloc_array(pfp
, struct prefork_oldest
, pfp
->pool_size
);
261 for (i
= 0; i
< pfp
->pool_size
; i
++) {
263 if (pfp
->pool
[i
].status
== PF_WORKER_ALIVE
||
264 pfp
->pool
[i
].status
== PF_WORKER_ACCEPTING
) {
265 oldest
[i
].started
= pfp
->pool
[i
].started
;
267 oldest
[i
].started
= now
;
271 qsort(oldest
, pfp
->pool_size
,
272 sizeof(struct prefork_oldest
),
273 prefork_sort_oldest
);
275 for (i
= 0, j
= 0; i
< pfp
->pool_size
&& j
< num_children
; i
++) {
276 if (((pfp
->pool
[i
].status
== PF_WORKER_ALIVE
) &&
277 (pfp
->pool
[i
].num_clients
< 1)) &&
278 (pfp
->pool
[i
].started
<= age_limit
)) {
279 /* tell the child it's time to give up */
280 DEBUG(5, ("Retiring pid %u!\n", (unsigned int)pfp
->pool
[i
].pid
));
281 pfp
->pool
[i
].cmds
= PF_SRV_MSG_EXIT
;
282 messaging_send(msg_ctx
,
283 pid_to_procid(pfp
->pool
[i
].pid
),
284 MSG_PREFORK_PARENT_EVENT
, &ping
);
292 int prefork_count_children(struct prefork_pool
*pfp
, int *active
)
298 for (i
= 0; i
< pfp
->pool_size
; i
++) {
299 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
) {
305 if ((pfp
->pool
[i
].status
== PF_WORKER_EXITING
) ||
306 (pfp
->pool
[i
].num_clients
<= 0)) {
319 static void prefork_cleanup_loop(struct prefork_pool
*pfp
)
325 /* TODO: should we use a process group id wait instead of looping ? */
326 for (i
= 0; i
< pfp
->pool_size
; i
++) {
327 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
||
328 pfp
->pool
[i
].pid
== 0) {
332 pid
= waitpid(pfp
->pool
[i
].pid
, &status
, WNOHANG
);
335 if (pfp
->pool
[i
].status
!= PF_WORKER_EXITING
) {
336 DEBUG(3, ("Child (%d) terminated abnormally:"
337 " %d\n", (int)pid
, status
));
339 DEBUG(10, ("Child (%d) terminated with status:"
340 " %d\n", (int)pid
, status
));
344 * this makes status = PF_WORK_NONE */
345 memset(&pfp
->pool
[i
], 0,
346 sizeof(struct pf_worker_data
));
352 int prefork_count_allowed_connections(struct prefork_pool
*pfp
)
358 for (i
= 0; i
< pfp
->pool_size
; i
++) {
359 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
||
360 pfp
->pool
[i
].status
== PF_WORKER_EXITING
) {
364 if (pfp
->pool
[i
].num_clients
< 0) {
368 c
+= pfp
->pool
[i
].allowed_clients
- pfp
->pool
[i
].num_clients
;
374 void prefork_increase_allowed_clients(struct prefork_pool
*pfp
, int max
)
378 for (i
= 0; i
< pfp
->pool_size
; i
++) {
379 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
||
380 pfp
->pool
[i
].status
== PF_WORKER_EXITING
) {
384 if (pfp
->pool
[i
].num_clients
< 0) {
388 if (pfp
->pool
[i
].allowed_clients
< max
) {
389 pfp
->pool
[i
].allowed_clients
++;
394 void prefork_decrease_allowed_clients(struct prefork_pool
*pfp
)
398 for (i
= 0; i
< pfp
->pool_size
; i
++) {
399 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
||
400 pfp
->pool
[i
].status
== PF_WORKER_EXITING
) {
404 if (pfp
->pool
[i
].num_clients
< 0) {
408 if (pfp
->pool
[i
].allowed_clients
> 1) {
409 pfp
->pool
[i
].allowed_clients
--;
414 void prefork_reset_allowed_clients(struct prefork_pool
*pfp
)
418 for (i
= 0; i
< pfp
->pool_size
; i
++) {
419 pfp
->pool
[i
].allowed_clients
= 1;
423 void prefork_send_signal_to_all(struct prefork_pool
*pfp
, int signal_num
)
427 for (i
= 0; i
< pfp
->pool_size
; i
++) {
428 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
) {
432 kill(pfp
->pool
[i
].pid
, signal_num
);
436 void prefork_warn_active_children(struct messaging_context
*msg_ctx
,
437 struct prefork_pool
*pfp
)
439 const DATA_BLOB ping
= data_blob_null
;
442 for (i
= 0; i
< pfp
->pool_size
; i
++) {
443 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
) {
447 messaging_send(msg_ctx
,
448 pid_to_procid(pfp
->pool
[i
].pid
),
449 MSG_PREFORK_PARENT_EVENT
, &ping
);
453 static void prefork_sigchld_handler(struct tevent_context
*ev_ctx
,
454 struct tevent_signal
*se
,
455 int signum
, int count
,
456 void *siginfo
, void *pvt
)
458 struct prefork_pool
*pfp
;
460 pfp
= talloc_get_type_abort(pvt
, struct prefork_pool
);
462 /* run the cleanup function to make sure all dead children are
463 * properly and timely retired. */
464 prefork_cleanup_loop(pfp
);
466 if (pfp
->sigchld_fn
) {
467 pfp
->sigchld_fn(ev_ctx
, pfp
, pfp
->sigchld_data
);
471 static bool prefork_setup_sigchld_handler(struct tevent_context
*ev_ctx
,
472 struct prefork_pool
*pfp
)
474 struct tevent_signal
*se
;
476 se
= tevent_add_signal(ev_ctx
, pfp
, SIGCHLD
, 0,
477 prefork_sigchld_handler
, pfp
);
479 DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
486 void prefork_set_sigchld_callback(struct prefork_pool
*pfp
,
487 prefork_sigchld_fn_t
*sigchld_fn
,
490 pfp
->sigchld_fn
= sigchld_fn
;
491 pfp
->sigchld_data
= private_data
;
494 /* ==== Functions used by children ==== */
496 struct pf_listen_state
{
497 struct tevent_context
*ev
;
498 struct pf_worker_data
*pf
;
501 struct pf_listen_fd
*listen_fds
;
503 struct pf_listen_fd accept
;
505 struct tsocket_address
*srv_addr
;
506 struct tsocket_address
*cli_addr
;
511 struct pf_listen_ctx
{
513 struct tevent_req
*req
;
515 void *listen_fd_data
;
518 static void prefork_listen_accept_handler(struct tevent_context
*ev
,
519 struct tevent_fd
*fde
,
520 uint16_t flags
, void *pvt
);
522 struct tevent_req
*prefork_listen_send(TALLOC_CTX
*mem_ctx
,
523 struct tevent_context
*ev
,
524 struct pf_worker_data
*pf
,
526 struct pf_listen_fd
*listen_fds
)
528 struct tevent_req
*req
;
529 struct pf_listen_state
*state
;
530 struct pf_listen_ctx
*ctx
;
531 struct tevent_fd
*fde
;
535 req
= tevent_req_create(mem_ctx
, &state
, struct pf_listen_state
);
542 state
->listen_fd_size
= listen_fd_size
;
543 state
->listen_fds
= listen_fds
;
544 state
->accept
.fd
= -1;
545 state
->accept
.fd_data
= NULL
;
548 fde_ctx
= talloc_new(state
);
549 if (tevent_req_nomem(fde_ctx
, req
)) {
550 return tevent_req_post(req
, ev
);
554 for (i
= 0; i
< state
->listen_fd_size
; i
++) {
555 ctx
= talloc(fde_ctx
, struct pf_listen_ctx
);
556 if (tevent_req_nomem(ctx
, req
)) {
557 return tevent_req_post(req
, ev
);
559 ctx
->fde_ctx
= fde_ctx
;
561 ctx
->listen_fd
= state
->listen_fds
[i
].fd
;
562 ctx
->listen_fd_data
= state
->listen_fds
[i
].fd_data
;
564 fde
= tevent_add_fd(state
->ev
, fde_ctx
,
565 ctx
->listen_fd
, TEVENT_FD_READ
,
566 prefork_listen_accept_handler
, ctx
);
567 if (tevent_req_nomem(fde
, req
)) {
568 return tevent_req_post(req
, ev
);
572 pf
->status
= PF_WORKER_ACCEPTING
;
577 static void prefork_listen_accept_handler(struct tevent_context
*ev
,
578 struct tevent_fd
*fde
,
579 uint16_t flags
, void *pvt
)
581 struct pf_listen_state
*state
;
582 struct tevent_req
*req
;
583 struct pf_listen_ctx
*ctx
;
584 struct sockaddr_storage addr
;
587 socklen_t solen
= sizeof(soerr
);
591 ctx
= talloc_get_type_abort(pvt
, struct pf_listen_ctx
);
593 state
= tevent_req_data(ctx
->req
, struct pf_listen_state
);
595 if ((state
->pf
->cmds
== PF_SRV_MSG_EXIT
) &&
596 (state
->pf
->num_clients
<= 0)) {
597 /* We have been asked to exit, so drop here and the next
598 * child will pick it up */
599 state
->pf
->status
= PF_WORKER_EXITING
;
600 state
->error
= EINTR
;
604 /* before proceeding check that the listening fd is ok */
605 ret
= getsockopt(ctx
->listen_fd
, SOL_SOCKET
, SO_ERROR
, &soerr
, &solen
);
607 /* this is a fatal error, we cannot continue listening */
608 state
->error
= EBADF
;
612 /* this is a fatal error, we cannot continue listening */
613 state
->error
= soerr
;
618 addrlen
= sizeof(addr
);
619 sd
= accept(ctx
->listen_fd
, (struct sockaddr
*)&addr
, &addrlen
);
621 state
->error
= errno
;
622 DEBUG(6, ("Accept failed! (%d, %s)\n",
623 state
->error
, strerror(state
->error
)));
626 smb_set_close_on_exec(sd
);
628 state
->accept
.fd
= sd
;
629 state
->accept
.fd_data
= ctx
->listen_fd_data
;
631 ret
= tsocket_address_bsd_from_sockaddr(state
,
632 (struct sockaddr
*)(void *)&addr
,
633 addrlen
, &state
->cli_addr
);
635 state
->error
= errno
;
640 addrlen
= sizeof(addr
);
641 ret
= getsockname(sd
, (struct sockaddr
*)(void *)&addr
, &addrlen
);
643 state
->error
= errno
;
647 ret
= tsocket_address_bsd_from_sockaddr(state
,
648 (struct sockaddr
*)(void *)&addr
,
649 addrlen
, &state
->srv_addr
);
651 state
->error
= errno
;
656 /* do not track the listen fds anymore */
657 talloc_free(ctx
->fde_ctx
);
658 tevent_req_done(req
);
661 int prefork_listen_recv(struct tevent_req
*req
,
662 TALLOC_CTX
*mem_ctx
, int *fd
,
664 struct tsocket_address
**srv_addr
,
665 struct tsocket_address
**cli_addr
)
667 struct pf_listen_state
*state
;
670 state
= tevent_req_data(req
, struct pf_listen_state
);
675 if (!tevent_req_is_unix_error(req
, &ret
)) {
681 if (state
->accept
.fd
!= -1) {
682 close(state
->accept
.fd
);
685 *fd
= state
->accept
.fd
;
686 if (fd_data
!= NULL
) {
687 *fd_data
= state
->accept
.fd_data
;
689 *srv_addr
= talloc_move(mem_ctx
, &state
->srv_addr
);
690 *cli_addr
= talloc_move(mem_ctx
, &state
->cli_addr
);
691 state
->pf
->num_clients
++;
693 if (state
->pf
->status
== PF_WORKER_ACCEPTING
) {
694 state
->pf
->status
= PF_WORKER_ALIVE
;
697 tevent_req_received(req
);