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