71441c3303bbea0eaef1577ec2e33a675718d1b2
[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                     pfp->pool[i].status == PF_WORKER_EXITING) {
348                         continue;
349                 }
350
351                 if (pfp->pool[i].num_clients < 0) {
352                         continue;
353                 }
354
355                 c += pfp->pool[i].allowed_clients - pfp->pool[i].num_clients;
356         }
357
358         return c;
359 }
360
361 void prefork_increase_allowed_clients(struct prefork_pool *pfp, int max)
362 {
363         int i;
364
365         for (i = 0; i < pfp->pool_size; i++) {
366                 if (pfp->pool[i].status == PF_WORKER_NONE ||
367                     pfp->pool[i].status == PF_WORKER_EXITING) {
368                         continue;
369                 }
370
371                 if (pfp->pool[i].num_clients < 0) {
372                         continue;
373                 }
374
375                 if (pfp->pool[i].allowed_clients < max) {
376                         pfp->pool[i].allowed_clients++;
377                 }
378         }
379 }
380
381 void prefork_decrease_allowed_clients(struct prefork_pool *pfp)
382 {
383         int i;
384
385         for (i = 0; i < pfp->pool_size; i++) {
386                 if (pfp->pool[i].status == PF_WORKER_NONE ||
387                     pfp->pool[i].status == PF_WORKER_EXITING) {
388                         continue;
389                 }
390
391                 if (pfp->pool[i].num_clients < 0) {
392                         continue;
393                 }
394
395                 if (pfp->pool[i].allowed_clients > 1) {
396                         pfp->pool[i].allowed_clients--;
397                 }
398         }
399 }
400
401 void prefork_reset_allowed_clients(struct prefork_pool *pfp)
402 {
403         int i;
404
405         for (i = 0; i < pfp->pool_size; i++) {
406                 pfp->pool[i].allowed_clients = 1;
407         }
408 }
409
410 void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num)
411 {
412         int i;
413
414         for (i = 0; i < pfp->pool_size; i++) {
415                 if (pfp->pool[i].status == PF_WORKER_NONE) {
416                         continue;
417                 }
418
419                 kill(pfp->pool[i].pid, signal_num);
420         }
421 }
422
423 static void prefork_sigchld_handler(struct tevent_context *ev_ctx,
424                                     struct tevent_signal *se,
425                                     int signum, int count,
426                                     void *siginfo, void *pvt)
427 {
428         struct prefork_pool *pfp;
429
430         pfp = talloc_get_type_abort(pvt, struct prefork_pool);
431
432         /* run the cleanup function to make sure all dead children are
433          * properly and timely retired. */
434         prefork_cleanup_loop(pfp);
435
436         if (pfp->sigchld_fn) {
437                 pfp->sigchld_fn(ev_ctx, pfp, pfp->sigchld_data);
438         }
439 }
440
441 static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx,
442                                           struct prefork_pool *pfp)
443 {
444         struct tevent_signal *se;
445
446         se = tevent_add_signal(ev_ctx, pfp, SIGCHLD, 0,
447                                 prefork_sigchld_handler, pfp);
448         if (!se) {
449                 DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
450                 return false;
451         }
452
453         return true;
454 }
455
456 void prefork_set_sigchld_callback(struct prefork_pool *pfp,
457                                   prefork_sigchld_fn_t *sigchld_fn,
458                                   void *private_data)
459 {
460         pfp->sigchld_fn = sigchld_fn;
461         pfp->sigchld_data = private_data;
462 }
463
464 /* ==== Functions used by children ==== */
465
466 struct pf_listen_state {
467         struct tevent_context *ev;
468         struct pf_worker_data *pf;
469
470         int listen_fd_size;
471         int *listen_fds;
472
473         int accept_fd;
474
475         struct tsocket_address *srv_addr;
476         struct tsocket_address *cli_addr;
477
478         int error;
479 };
480
481 struct pf_listen_ctx {
482         TALLOC_CTX *fde_ctx;
483         struct tevent_req *req;
484         int listen_fd;
485 };
486
487 static void prefork_listen_accept_handler(struct tevent_context *ev,
488                                           struct tevent_fd *fde,
489                                           uint16_t flags, void *pvt);
490
491 struct tevent_req *prefork_listen_send(TALLOC_CTX *mem_ctx,
492                                         struct tevent_context *ev,
493                                         struct pf_worker_data *pf,
494                                         int listen_fd_size,
495                                         int *listen_fds)
496 {
497         struct tevent_req *req;
498         struct pf_listen_state *state;
499         struct pf_listen_ctx *ctx;
500         struct tevent_fd *fde;
501         TALLOC_CTX *fde_ctx;
502         int i;
503
504         req = tevent_req_create(mem_ctx, &state, struct pf_listen_state);
505         if (!req) {
506                 return NULL;
507         }
508
509         state->ev = ev;
510         state->pf = pf;
511         state->listen_fd_size = listen_fd_size;
512         state->listen_fds = listen_fds;
513         state->accept_fd = -1;
514         state->error = 0;
515
516         fde_ctx = talloc_new(state);
517         if (tevent_req_nomem(fde_ctx, req)) {
518                 return tevent_req_post(req, ev);
519         }
520
521         /* race on accept */
522         for (i = 0; i < state->listen_fd_size; i++) {
523                 ctx = talloc(fde_ctx, struct pf_listen_ctx);
524                 if (tevent_req_nomem(ctx, req)) {
525                         return tevent_req_post(req, ev);
526                 }
527                 ctx->fde_ctx = fde_ctx;
528                 ctx->req = req;
529                 ctx->listen_fd = state->listen_fds[i];
530
531                 fde = tevent_add_fd(state->ev, fde_ctx,
532                                     ctx->listen_fd, TEVENT_FD_READ,
533                                     prefork_listen_accept_handler, ctx);
534                 if (tevent_req_nomem(fde, req)) {
535                         return tevent_req_post(req, ev);
536                 }
537         }
538
539         pf->status = PF_WORKER_ACCEPTING;
540
541         return req;
542 }
543
544 static void prefork_listen_accept_handler(struct tevent_context *ev,
545                                           struct tevent_fd *fde,
546                                           uint16_t flags, void *pvt)
547 {
548         struct pf_listen_state *state;
549         struct tevent_req *req;
550         struct pf_listen_ctx *ctx;
551         struct sockaddr_storage addr;
552         socklen_t addrlen;
553         int err = 0;
554         int sd = -1;
555         int ret;
556
557         ctx = talloc_get_type_abort(pvt, struct pf_listen_ctx);
558         req = ctx->req;
559         state = tevent_req_data(ctx->req, struct pf_listen_state);
560
561         if (state->pf->cmds == PF_SRV_MSG_EXIT) {
562                 /* We have been asked to exit, so drop here and the next
563                  * child will pick it up */
564                 state->pf->status = PF_WORKER_EXITING;
565                 state->error = EINTR;
566                 goto done;
567         }
568
569         ZERO_STRUCT(addr);
570         addrlen = sizeof(addr);
571         sd = accept(ctx->listen_fd, (struct sockaddr *)&addr, &addrlen);
572         if (sd == -1) {
573                 err = errno;
574                 DEBUG(6, ("Accept failed! (%d, %s)\n", err, strerror(err)));
575         }
576
577         /* do not track the listen fds anymore */
578         talloc_free(ctx->fde_ctx);
579         ctx = NULL;
580         if (err) {
581                 state->error = err;
582                 goto done;
583         }
584
585         state->accept_fd = sd;
586
587         ret = tsocket_address_bsd_from_sockaddr(state,
588                                         (struct sockaddr *)(void *)&addr,
589                                         addrlen, &state->cli_addr);
590         if (ret < 0) {
591                 state->error = errno;
592                 goto done;
593         }
594
595         ZERO_STRUCT(addr);
596         addrlen = sizeof(addr);
597         ret = getsockname(sd, (struct sockaddr *)(void *)&addr, &addrlen);
598         if (ret < 0) {
599                 state->error = errno;
600                 goto done;
601         }
602
603         ret = tsocket_address_bsd_from_sockaddr(state,
604                                         (struct sockaddr *)(void *)&addr,
605                                         addrlen, &state->srv_addr);
606         if (ret < 0) {
607                 state->error = errno;
608                 goto done;
609         }
610
611 done:
612         tevent_req_done(req);
613 }
614
615 int prefork_listen_recv(struct tevent_req *req,
616                         TALLOC_CTX *mem_ctx, int *fd,
617                         struct tsocket_address **srv_addr,
618                         struct tsocket_address **cli_addr)
619 {
620         struct pf_listen_state *state;
621         int ret = 0;
622
623         state = tevent_req_data(req, struct pf_listen_state);
624
625         if (state->error) {
626                 ret = state->error;
627         } else {
628                 tevent_req_is_unix_error(req, &ret);
629         }
630
631         if (ret) {
632                 if (state->accept_fd != -1) {
633                         close(state->accept_fd);
634                 }
635         } else {
636                 *fd = state->accept_fd;
637                 *srv_addr = talloc_move(mem_ctx, &state->srv_addr);
638                 *cli_addr = talloc_move(mem_ctx, &state->cli_addr);
639                 state->pf->num_clients++;
640         }
641         if (state->pf->status == PF_WORKER_ACCEPTING) {
642                 state->pf->status = PF_WORKER_ALIVE;
643         }
644
645         tevent_req_received(req);
646         return ret;
647 }