lib: Remove sys_waitpid
[metze/samba/wip.git] / source3 / lib / server_prefork.c
1 /*
2    Unix SMB/CIFS implementation.
3    Common server globals
4
5    Copyright (C) Simo Sorce <idra@samba.org> 2011
6
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.
11
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.
16
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/>.
19 */
20
21 #include "includes.h"
22 #include "serverid.h"
23 #include "messages.h"
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"
30
31 struct prefork_pool {
32
33         int listen_fd_size;
34         int *listen_fds;
35
36         prefork_main_fn_t *main_fn;
37         void *private_data;
38
39         int pool_size;
40         struct pf_worker_data *pool;
41
42         int allowed_clients;
43
44         prefork_sigchld_fn_t *sigchld_fn;
45         void *sigchld_data;
46 };
47
48 static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx,
49                                             struct prefork_pool *pfp);
50
51 static int prefork_pool_destructor(struct prefork_pool *pfp)
52 {
53         anonymous_shared_free(pfp->pool);
54         return 0;
55 }
56
57 bool prefork_create_pool(TALLOC_CTX *mem_ctx,
58                          struct tevent_context *ev_ctx,
59                          struct messaging_context *msg_ctx,
60                          int listen_fd_size, int *listen_fds,
61                          int min_children, int max_children,
62                          prefork_main_fn_t *main_fn, void *private_data,
63                          struct prefork_pool **pf_pool)
64 {
65         struct prefork_pool *pfp;
66         pid_t pid;
67         time_t now = time(NULL);
68         size_t data_size;
69         int ret;
70         int i;
71         bool ok;
72
73         pfp = talloc_zero(mem_ctx, struct prefork_pool);
74         if (!pfp) {
75                 DEBUG(1, ("Out of memory!\n"));
76                 return false;
77         }
78         pfp->listen_fd_size = listen_fd_size;
79         pfp->listen_fds = talloc_array(pfp, int, listen_fd_size);
80         if (!pfp->listen_fds) {
81                 DEBUG(1, ("Out of memory!\n"));
82                 return false;
83         }
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], false);
88         }
89         pfp->main_fn = main_fn;
90         pfp->private_data = private_data;
91
92         pfp->pool_size = max_children;
93         data_size = sizeof(struct pf_worker_data) * max_children;
94
95         pfp->pool = (struct pf_worker_data *)anonymous_shared_allocate(
96                 data_size);
97         if (pfp->pool == NULL) {
98                 DEBUG(1, ("Failed to mmap memory for prefork pool!\n"));
99                 talloc_free(pfp);
100                 return false;
101         }
102         talloc_set_destructor(pfp, prefork_pool_destructor);
103
104         for (i = 0; i < min_children; i++) {
105
106                 pfp->pool[i].allowed_clients = 1;
107                 pfp->pool[i].started = now;
108
109                 pid = fork();
110                 switch (pid) {
111                 case -1:
112                         DEBUG(1, ("Failed to prefork child n. %d !\n", i));
113                         break;
114
115                 case 0: /* THE CHILD */
116
117                         pfp->pool[i].status = PF_WORKER_ALIVE;
118                         ret = pfp->main_fn(ev_ctx, msg_ctx,
119                                            &pfp->pool[i], i + 1,
120                                            pfp->listen_fd_size,
121                                            pfp->listen_fds,
122                                            pfp->private_data);
123                         exit(ret);
124
125                 default: /* THE PARENT */
126                         pfp->pool[i].pid = pid;
127                         break;
128                 }
129         }
130
131         ok = prefork_setup_sigchld_handler(ev_ctx, pfp);
132         if (!ok) {
133                 DEBUG(1, ("Failed to setup SIGCHLD Handler!\n"));
134                 talloc_free(pfp);
135                 return false;
136         }
137
138         *pf_pool = pfp;
139         return true;
140 }
141
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
147  */
148 int prefork_expand_pool(struct prefork_pool *pfp, int new_max)
149 {
150         struct prefork_pool *pool;
151         size_t old_size;
152         size_t new_size;
153         int ret;
154
155         if (new_max <= pfp->pool_size) {
156                 return EINVAL;
157         }
158
159         old_size = sizeof(struct pf_worker_data) * pfp->pool_size;
160         new_size = sizeof(struct pf_worker_data) * new_max;
161
162         pool = (struct prefork_pool *)anonymous_shared_resize(
163                 &pfp->pool, new_size, false);
164         if (pool == NULL) {
165                 ret = errno;
166                 DEBUG(3, ("Failed to mremap memory (%d: %s)!\n",
167                           ret, strerror(ret)));
168                 return ret;
169         }
170
171         memset(&pool[pfp->pool_size], 0, new_size - old_size);
172
173         pfp->pool_size = new_max;
174
175         return 0;
176 }
177
178 int prefork_add_children(struct tevent_context *ev_ctx,
179                          struct messaging_context *msg_ctx,
180                          struct prefork_pool *pfp,
181                          int num_children)
182 {
183         pid_t pid;
184         time_t now = time(NULL);
185         int ret;
186         int i, j;
187
188         for (i = 0, j = 0; i < pfp->pool_size && j < num_children; i++) {
189
190                 if (pfp->pool[i].status != PF_WORKER_NONE) {
191                         continue;
192                 }
193
194                 pfp->pool[i].allowed_clients = 1;
195                 pfp->pool[i].started = now;
196
197                 pid = fork();
198                 switch (pid) {
199                 case -1:
200                         DEBUG(1, ("Failed to prefork child n. %d !\n", j));
201                         break;
202
203                 case 0: /* THE CHILD */
204
205                         pfp->pool[i].status = PF_WORKER_ALIVE;
206                         ret = pfp->main_fn(ev_ctx, msg_ctx,
207                                            &pfp->pool[i], i + 1,
208                                            pfp->listen_fd_size,
209                                            pfp->listen_fds,
210                                            pfp->private_data);
211
212                         pfp->pool[i].status = PF_WORKER_EXITING;
213                         exit(ret);
214
215                 default: /* THE PARENT */
216                         pfp->pool[i].pid = pid;
217                         j++;
218                         break;
219                 }
220         }
221
222         DEBUG(5, ("Added %d children!\n", j));
223
224         return j;
225 }
226
227 struct prefork_oldest {
228         int num;
229         time_t started;
230 };
231
232 /* sort in inverse order */
233 static int prefork_sort_oldest(const void *ap, const void *bp)
234 {
235         const struct prefork_oldest *a = (const struct prefork_oldest *)ap;
236         const struct prefork_oldest *b = (const struct prefork_oldest *)bp;
237
238         if (a->started == b->started) {
239                 return 0;
240         }
241         if (a->started < b->started) {
242                 return 1;
243         }
244         return -1;
245 }
246
247 int prefork_retire_children(struct messaging_context *msg_ctx,
248                             struct prefork_pool *pfp,
249                             int num_children, time_t age_limit)
250 {
251         const DATA_BLOB ping = data_blob_null;
252         time_t now = time(NULL);
253         struct prefork_oldest *oldest;
254         int i, j;
255
256         oldest = talloc_array(pfp, struct prefork_oldest, pfp->pool_size);
257         if (!oldest) {
258                 return -1;
259         }
260
261         for (i = 0; i < pfp->pool_size; i++) {
262                 oldest[i].num = 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;
266                 } else {
267                         oldest[i].started = now;
268                 }
269         }
270
271         qsort(oldest, pfp->pool_size,
272                 sizeof(struct prefork_oldest),
273                 prefork_sort_oldest);
274
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);
285                         j++;
286                 }
287         }
288
289         return j;
290 }
291
292 int prefork_count_children(struct prefork_pool *pfp, int *active)
293 {
294         int i, a, t;
295
296         a = 0;
297         t = 0;
298         for (i = 0; i < pfp->pool_size; i++) {
299                 if (pfp->pool[i].status == PF_WORKER_NONE) {
300                         continue;
301                 }
302
303                 t++;
304
305                 if ((pfp->pool[i].status == PF_WORKER_EXITING) ||
306                     (pfp->pool[i].num_clients <= 0)) {
307                         continue;
308                 }
309
310                 a++;
311         }
312
313         if (active) {
314                 *active = a;
315         }
316         return t;
317 }
318
319 static void prefork_cleanup_loop(struct prefork_pool *pfp)
320 {
321         int status;
322         pid_t pid;
323         int i;
324
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) {
329                         continue;
330                 }
331
332                 pid = waitpid(pfp->pool[i].pid, &status, WNOHANG);
333                 if (pid > 0) {
334
335                         if (pfp->pool[i].status != PF_WORKER_EXITING) {
336                                 DEBUG(3, ("Child (%d) terminated abnormally:"
337                                           " %d\n", (int)pid, status));
338                         } else {
339                                 DEBUG(10, ("Child (%d) terminated with status:"
340                                            " %d\n", (int)pid, status));
341                         }
342
343                         /* reset all fields,
344                          * this makes status = PF_WORK_NONE */
345                         memset(&pfp->pool[i], 0,
346                                 sizeof(struct pf_worker_data));
347                 }
348         }
349
350 }
351
352 int prefork_count_allowed_connections(struct prefork_pool *pfp)
353 {
354         int c;
355         int i;
356
357         c = 0;
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) {
361                         continue;
362                 }
363
364                 if (pfp->pool[i].num_clients < 0) {
365                         continue;
366                 }
367
368                 c += pfp->pool[i].allowed_clients - pfp->pool[i].num_clients;
369         }
370
371         return c;
372 }
373
374 void prefork_increase_allowed_clients(struct prefork_pool *pfp, int max)
375 {
376         int i;
377
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) {
381                         continue;
382                 }
383
384                 if (pfp->pool[i].num_clients < 0) {
385                         continue;
386                 }
387
388                 if (pfp->pool[i].allowed_clients < max) {
389                         pfp->pool[i].allowed_clients++;
390                 }
391         }
392 }
393
394 void prefork_decrease_allowed_clients(struct prefork_pool *pfp)
395 {
396         int i;
397
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) {
401                         continue;
402                 }
403
404                 if (pfp->pool[i].num_clients < 0) {
405                         continue;
406                 }
407
408                 if (pfp->pool[i].allowed_clients > 1) {
409                         pfp->pool[i].allowed_clients--;
410                 }
411         }
412 }
413
414 void prefork_reset_allowed_clients(struct prefork_pool *pfp)
415 {
416         int i;
417
418         for (i = 0; i < pfp->pool_size; i++) {
419                 pfp->pool[i].allowed_clients = 1;
420         }
421 }
422
423 void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num)
424 {
425         int i;
426
427         for (i = 0; i < pfp->pool_size; i++) {
428                 if (pfp->pool[i].status == PF_WORKER_NONE) {
429                         continue;
430                 }
431
432                 kill(pfp->pool[i].pid, signal_num);
433         }
434 }
435
436 void prefork_warn_active_children(struct messaging_context *msg_ctx,
437                                   struct prefork_pool *pfp)
438 {
439         const DATA_BLOB ping = data_blob_null;
440         int i;
441
442         for (i = 0; i < pfp->pool_size; i++) {
443                 if (pfp->pool[i].status == PF_WORKER_NONE) {
444                         continue;
445                 }
446
447                 messaging_send(msg_ctx,
448                                 pid_to_procid(pfp->pool[i].pid),
449                                 MSG_PREFORK_PARENT_EVENT, &ping);
450         }
451 }
452
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)
457 {
458         struct prefork_pool *pfp;
459
460         pfp = talloc_get_type_abort(pvt, struct prefork_pool);
461
462         /* run the cleanup function to make sure all dead children are
463          * properly and timely retired. */
464         prefork_cleanup_loop(pfp);
465
466         if (pfp->sigchld_fn) {
467                 pfp->sigchld_fn(ev_ctx, pfp, pfp->sigchld_data);
468         }
469 }
470
471 static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx,
472                                           struct prefork_pool *pfp)
473 {
474         struct tevent_signal *se;
475
476         se = tevent_add_signal(ev_ctx, pfp, SIGCHLD, 0,
477                                 prefork_sigchld_handler, pfp);
478         if (!se) {
479                 DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
480                 return false;
481         }
482
483         return true;
484 }
485
486 void prefork_set_sigchld_callback(struct prefork_pool *pfp,
487                                   prefork_sigchld_fn_t *sigchld_fn,
488                                   void *private_data)
489 {
490         pfp->sigchld_fn = sigchld_fn;
491         pfp->sigchld_data = private_data;
492 }
493
494 /* ==== Functions used by children ==== */
495
496 struct pf_listen_state {
497         struct tevent_context *ev;
498         struct pf_worker_data *pf;
499
500         int listen_fd_size;
501         int *listen_fds;
502
503         int accept_fd;
504
505         struct tsocket_address *srv_addr;
506         struct tsocket_address *cli_addr;
507
508         int error;
509 };
510
511 struct pf_listen_ctx {
512         TALLOC_CTX *fde_ctx;
513         struct tevent_req *req;
514         int listen_fd;
515 };
516
517 static void prefork_listen_accept_handler(struct tevent_context *ev,
518                                           struct tevent_fd *fde,
519                                           uint16_t flags, void *pvt);
520
521 struct tevent_req *prefork_listen_send(TALLOC_CTX *mem_ctx,
522                                         struct tevent_context *ev,
523                                         struct pf_worker_data *pf,
524                                         int listen_fd_size,
525                                         int *listen_fds)
526 {
527         struct tevent_req *req;
528         struct pf_listen_state *state;
529         struct pf_listen_ctx *ctx;
530         struct tevent_fd *fde;
531         TALLOC_CTX *fde_ctx;
532         int i;
533
534         req = tevent_req_create(mem_ctx, &state, struct pf_listen_state);
535         if (!req) {
536                 return NULL;
537         }
538
539         state->ev = ev;
540         state->pf = pf;
541         state->listen_fd_size = listen_fd_size;
542         state->listen_fds = listen_fds;
543         state->accept_fd = -1;
544         state->error = 0;
545
546         fde_ctx = talloc_new(state);
547         if (tevent_req_nomem(fde_ctx, req)) {
548                 return tevent_req_post(req, ev);
549         }
550
551         /* race on accept */
552         for (i = 0; i < state->listen_fd_size; i++) {
553                 ctx = talloc(fde_ctx, struct pf_listen_ctx);
554                 if (tevent_req_nomem(ctx, req)) {
555                         return tevent_req_post(req, ev);
556                 }
557                 ctx->fde_ctx = fde_ctx;
558                 ctx->req = req;
559                 ctx->listen_fd = state->listen_fds[i];
560
561                 fde = tevent_add_fd(state->ev, fde_ctx,
562                                     ctx->listen_fd, TEVENT_FD_READ,
563                                     prefork_listen_accept_handler, ctx);
564                 if (tevent_req_nomem(fde, req)) {
565                         return tevent_req_post(req, ev);
566                 }
567         }
568
569         pf->status = PF_WORKER_ACCEPTING;
570
571         return req;
572 }
573
574 static void prefork_listen_accept_handler(struct tevent_context *ev,
575                                           struct tevent_fd *fde,
576                                           uint16_t flags, void *pvt)
577 {
578         struct pf_listen_state *state;
579         struct tevent_req *req;
580         struct pf_listen_ctx *ctx;
581         struct sockaddr_storage addr;
582         socklen_t addrlen;
583         int soerr = 0;
584         socklen_t solen = sizeof(soerr);
585         int sd = -1;
586         int ret;
587
588         ctx = talloc_get_type_abort(pvt, struct pf_listen_ctx);
589         req = ctx->req;
590         state = tevent_req_data(ctx->req, struct pf_listen_state);
591
592         if ((state->pf->cmds == PF_SRV_MSG_EXIT) &&
593             (state->pf->num_clients <= 0)) {
594                 /* We have been asked to exit, so drop here and the next
595                  * child will pick it up */
596                 state->pf->status = PF_WORKER_EXITING;
597                 state->error = EINTR;
598                 goto done;
599         }
600
601         /* before proceeding check that the listening fd is ok */
602         ret = getsockopt(ctx->listen_fd, SOL_SOCKET, SO_ERROR, &soerr, &solen);
603         if (ret == -1) {
604                 /* this is a fatal error, we cannot continue listening */
605                 state->error = EBADF;
606                 goto done;
607         }
608         if (soerr != 0) {
609                 /* this is a fatal error, we cannot continue listening */
610                 state->error = soerr;
611                 goto done;
612         }
613
614         ZERO_STRUCT(addr);
615         addrlen = sizeof(addr);
616         sd = accept(ctx->listen_fd, (struct sockaddr *)&addr, &addrlen);
617         if (sd == -1) {
618                 state->error = errno;
619                 DEBUG(6, ("Accept failed! (%d, %s)\n",
620                           state->error, strerror(state->error)));
621                 goto done;
622         }
623
624         state->accept_fd = sd;
625
626         ret = tsocket_address_bsd_from_sockaddr(state,
627                                         (struct sockaddr *)(void *)&addr,
628                                         addrlen, &state->cli_addr);
629         if (ret < 0) {
630                 state->error = errno;
631                 goto done;
632         }
633
634         ZERO_STRUCT(addr);
635         addrlen = sizeof(addr);
636         ret = getsockname(sd, (struct sockaddr *)(void *)&addr, &addrlen);
637         if (ret < 0) {
638                 state->error = errno;
639                 goto done;
640         }
641
642         ret = tsocket_address_bsd_from_sockaddr(state,
643                                         (struct sockaddr *)(void *)&addr,
644                                         addrlen, &state->srv_addr);
645         if (ret < 0) {
646                 state->error = errno;
647                 goto done;
648         }
649
650 done:
651         /* do not track the listen fds anymore */
652         talloc_free(ctx->fde_ctx);
653         tevent_req_done(req);
654 }
655
656 int prefork_listen_recv(struct tevent_req *req,
657                         TALLOC_CTX *mem_ctx, int *fd,
658                         struct tsocket_address **srv_addr,
659                         struct tsocket_address **cli_addr)
660 {
661         struct pf_listen_state *state;
662         int ret = 0;
663
664         state = tevent_req_data(req, struct pf_listen_state);
665
666         if (state->error) {
667                 ret = state->error;
668         } else {
669                 if (!tevent_req_is_unix_error(req, &ret)) {
670                         ret = 0;
671                 }
672         }
673
674         if (ret) {
675                 if (state->accept_fd != -1) {
676                         close(state->accept_fd);
677                 }
678         } else {
679                 *fd = state->accept_fd;
680                 *srv_addr = talloc_move(mem_ctx, &state->srv_addr);
681                 *cli_addr = talloc_move(mem_ctx, &state->cli_addr);
682                 state->pf->num_clients++;
683         }
684         if (state->pf->status == PF_WORKER_ACCEPTING) {
685                 state->pf->status = PF_WORKER_ALIVE;
686         }
687
688         tevent_req_received(req);
689         return ret;
690 }