s3-prefork: do not use a lock_fd, just race on accept()
[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_IDLE;
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_IDLE;
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_IDLE) {
256                         oldest[i].started = pfp->pool[i].started;
257                 } else {
258                         oldest[i].started = now;
259                 }
260         }
261
262         qsort(oldest, pfp->pool_size,
263                 sizeof(struct prefork_oldest),
264                 prefork_sort_oldest);
265
266         for (i = 0, j = 0; i < pfp->pool_size && j < num_children; i++) {
267                 if (pfp->pool[i].status == PF_WORKER_IDLE &&
268                     pfp->pool[i].started <= age_limit) {
269                         /* tell the child it's time to give up */
270                         DEBUG(5, ("Retiring pid %d!\n", pfp->pool[i].pid));
271                         pfp->pool[i].cmds = PF_SRV_MSG_EXIT;
272                         kill(pfp->pool[i].pid, SIGHUP);
273                         j++;
274                 }
275         }
276
277         return j;
278 }
279
280 int prefork_count_active_children(struct prefork_pool *pfp, int *total)
281 {
282         int i, a, t;
283
284         a = 0;
285         t = 0;
286         for (i = 0; i < pfp->pool_size; i++) {
287                 if (pfp->pool[i].status == PF_WORKER_NONE) {
288                         continue;
289                 }
290
291                 t++;
292
293                 if (pfp->pool[i].num_clients == 0) {
294                         continue;
295                 }
296
297                 a++;
298         }
299
300         *total = t;
301         return a;
302 }
303
304 static void prefork_cleanup_loop(struct prefork_pool *pfp)
305 {
306         int status;
307         pid_t pid;
308         int i;
309
310         /* TODO: should we use a process group id wait instead of looping ? */
311         for (i = 0; i < pfp->pool_size; i++) {
312                 if (pfp->pool[i].status == PF_WORKER_NONE ||
313                     pfp->pool[i].pid == 0) {
314                         continue;
315                 }
316
317                 pid = sys_waitpid(pfp->pool[i].pid, &status, WNOHANG);
318                 if (pid > 0) {
319
320                         if (pfp->pool[i].status != PF_WORKER_EXITING) {
321                                 DEBUG(3, ("Child (%d) terminated abnormally:"
322                                           " %d\n", (int)pid, status));
323                         } else {
324                                 DEBUG(10, ("Child (%d) terminated with status:"
325                                            " %d\n", (int)pid, status));
326                         }
327
328                         /* reset all fields,
329                          * this makes status = PF_WORK_NONE */
330                         memset(&pfp->pool[i], 0,
331                                 sizeof(struct pf_worker_data));
332                 }
333         }
334
335 }
336
337 int prefork_count_allowed_connections(struct prefork_pool *pfp)
338 {
339         int c;
340         int i;
341
342         c = 0;
343         for (i = 0; i < pfp->pool_size; i++) {
344                 if (pfp->pool[i].status == PF_WORKER_NONE) {
345                         continue;
346                 }
347
348                 c += pfp->pool[i].allowed_clients - pfp->pool[i].num_clients;
349         }
350
351         return c;
352 }
353
354 void prefork_increase_allowed_clients(struct prefork_pool *pfp, int max)
355 {
356         int i;
357
358         for (i = 0; i < pfp->pool_size; i++) {
359                 if (pfp->pool[i].status == PF_WORKER_NONE) {
360                         continue;
361                 }
362
363                 if (pfp->pool[i].allowed_clients < max) {
364                         pfp->pool[i].allowed_clients++;
365                 }
366         }
367 }
368
369 void prefork_decrease_allowed_clients(struct prefork_pool *pfp)
370 {
371         int i;
372
373         for (i = 0; i < pfp->pool_size; i++) {
374                 if (pfp->pool[i].status == PF_WORKER_NONE) {
375                         continue;
376                 }
377
378                 if (pfp->pool[i].allowed_clients > 1) {
379                         pfp->pool[i].allowed_clients--;
380                 }
381         }
382 }
383
384 void prefork_reset_allowed_clients(struct prefork_pool *pfp)
385 {
386         int i;
387
388         for (i = 0; i < pfp->pool_size; i++) {
389                 pfp->pool[i].allowed_clients = 1;
390         }
391 }
392
393 void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num)
394 {
395         int i;
396
397         for (i = 0; i < pfp->pool_size; i++) {
398                 if (pfp->pool[i].status == PF_WORKER_NONE) {
399                         continue;
400                 }
401
402                 kill(pfp->pool[i].pid, signal_num);
403         }
404 }
405
406 static void prefork_sigchld_handler(struct tevent_context *ev_ctx,
407                                     struct tevent_signal *se,
408                                     int signum, int count,
409                                     void *siginfo, void *pvt)
410 {
411         struct prefork_pool *pfp;
412
413         pfp = talloc_get_type_abort(pvt, struct prefork_pool);
414
415         /* run the cleanup function to make sure all dead children are
416          * properly and timely retired. */
417         prefork_cleanup_loop(pfp);
418
419         if (pfp->sigchld_fn) {
420                 pfp->sigchld_fn(ev_ctx, pfp, pfp->sigchld_data);
421         }
422 }
423
424 static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx,
425                                           struct prefork_pool *pfp)
426 {
427         struct tevent_signal *se;
428
429         se = tevent_add_signal(ev_ctx, pfp, SIGCHLD, 0,
430                                 prefork_sigchld_handler, pfp);
431         if (!se) {
432                 DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
433                 return false;
434         }
435
436         return true;
437 }
438
439 void prefork_set_sigchld_callback(struct prefork_pool *pfp,
440                                   prefork_sigchld_fn_t *sigchld_fn,
441                                   void *private_data)
442 {
443         pfp->sigchld_fn = sigchld_fn;
444         pfp->sigchld_data = private_data;
445 }
446
447 /* ==== Functions used by children ==== */
448
449 struct pf_listen_state {
450         struct tevent_context *ev;
451         struct pf_worker_data *pf;
452
453         int listen_fd_size;
454         int *listen_fds;
455
456         int accept_fd;
457
458         struct tsocket_address *srv_addr;
459         struct tsocket_address *cli_addr;
460
461         int error;
462 };
463
464 struct pf_listen_ctx {
465         TALLOC_CTX *fde_ctx;
466         struct tevent_req *req;
467         int listen_fd;
468 };
469
470 static void prefork_listen_accept_handler(struct tevent_context *ev,
471                                           struct tevent_fd *fde,
472                                           uint16_t flags, void *pvt);
473
474 struct tevent_req *prefork_listen_send(TALLOC_CTX *mem_ctx,
475                                         struct tevent_context *ev,
476                                         struct pf_worker_data *pf,
477                                         int listen_fd_size,
478                                         int *listen_fds)
479 {
480         struct tevent_req *req;
481         struct pf_listen_state *state;
482         struct pf_listen_ctx *ctx;
483         struct tevent_fd *fde;
484         TALLOC_CTX *fde_ctx;
485         int i;
486
487         req = tevent_req_create(mem_ctx, &state, struct pf_listen_state);
488         if (!req) {
489                 return NULL;
490         }
491
492         state->ev = ev;
493         state->pf = pf;
494         state->listen_fd_size = listen_fd_size;
495         state->listen_fds = listen_fds;
496         state->accept_fd = -1;
497         state->error = 0;
498
499         fde_ctx = talloc_new(state);
500         if (tevent_req_nomem(fde_ctx, req)) {
501                 return tevent_req_post(req, ev);
502         }
503
504         /* race on accept */
505         for (i = 0; i < state->listen_fd_size; i++) {
506                 ctx = talloc(fde_ctx, struct pf_listen_ctx);
507                 if (tevent_req_nomem(ctx, req)) {
508                         return tevent_req_post(req, ev);
509                 }
510                 ctx->fde_ctx = fde_ctx;
511                 ctx->req = req;
512                 ctx->listen_fd = state->listen_fds[i];
513
514                 fde = tevent_add_fd(state->ev, fde_ctx,
515                                     ctx->listen_fd, TEVENT_FD_READ,
516                                     prefork_listen_accept_handler, ctx);
517                 if (tevent_req_nomem(fde, req)) {
518                         return tevent_req_post(req, ev);
519                 }
520         }
521
522         return req;
523 }
524
525 static void prefork_listen_accept_handler(struct tevent_context *ev,
526                                           struct tevent_fd *fde,
527                                           uint16_t flags, void *pvt)
528 {
529         struct pf_listen_state *state;
530         struct tevent_req *req;
531         struct pf_listen_ctx *ctx;
532         struct sockaddr_storage addr;
533         socklen_t addrlen;
534         int err = 0;
535         int sd = -1;
536         int ret;
537
538         ctx = talloc_get_type_abort(pvt, struct pf_listen_ctx);
539         req = ctx->req;
540         state = tevent_req_data(ctx->req, struct pf_listen_state);
541
542         ZERO_STRUCT(addr);
543         addrlen = sizeof(addr);
544         sd = accept(ctx->listen_fd, (struct sockaddr *)&addr, &addrlen);
545         if (sd == -1) {
546                 err = errno;
547                 DEBUG(6, ("Accept failed! (%d, %s)\n", err, strerror(err)));
548         }
549
550         /* do not track the listen fds anymore */
551         talloc_free(ctx->fde_ctx);
552         ctx = NULL;
553         if (err) {
554                 state->error = err;
555                 goto done;
556         }
557
558         state->accept_fd = sd;
559
560         ret = tsocket_address_bsd_from_sockaddr(state,
561                                         (struct sockaddr *)(void *)&addr,
562                                         addrlen, &state->cli_addr);
563         if (ret < 0) {
564                 state->error = errno;
565                 goto done;
566         }
567
568         ZERO_STRUCT(addr);
569         addrlen = sizeof(addr);
570         ret = getsockname(sd, (struct sockaddr *)(void *)&addr, &addrlen);
571         if (ret < 0) {
572                 state->error = errno;
573                 goto done;
574         }
575
576         ret = tsocket_address_bsd_from_sockaddr(state,
577                                         (struct sockaddr *)(void *)&addr,
578                                         addrlen, &state->srv_addr);
579         if (ret < 0) {
580                 state->error = errno;
581                 goto done;
582         }
583
584 done:
585         tevent_req_done(req);
586 }
587
588 int prefork_listen_recv(struct tevent_req *req,
589                         TALLOC_CTX *mem_ctx, int *fd,
590                         struct tsocket_address **srv_addr,
591                         struct tsocket_address **cli_addr)
592 {
593         struct pf_listen_state *state;
594         int ret = 0;
595
596         state = tevent_req_data(req, struct pf_listen_state);
597
598         if (state->error) {
599                 ret = state->error;
600         } else {
601                 tevent_req_is_unix_error(req, &ret);
602         }
603
604         if (ret) {
605                 if (state->accept_fd != -1) {
606                         close(state->accept_fd);
607                 }
608         } else {
609                 *fd = state->accept_fd;
610                 *srv_addr = talloc_move(mem_ctx, &state->srv_addr);
611                 *cli_addr = talloc_move(mem_ctx, &state->cli_addr);
612                 state->pf->status = PF_WORKER_BUSY;
613                 state->pf->num_clients++;
614         }
615
616         tevent_req_received(req);
617         return ret;
618 }