8 * Copyright (C) 2001-2003 FhG Fokus
10 * This file is part of ser, a free SIP server.
12 * ser is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version
17 * For a license to use the ser software under conditions
18 * other than those described here, or to purchase support for this
19 * software, please contact iptel.org by e-mail at the following addresses:
22 * ser is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 * 2006-06-14 added process table in shared mem (dragos)
35 * 2006-09-20 added profile support (-DPROFILING) (hscholz)
36 * 2006-10-25 sanity check before allowing forking w/ tcp support (is_main
37 * & tcp not started yet); set is_main=0 in childs (andrei)
38 * 2007-07-04 added register_fds() and get_max_open_fds(() (andrei)
44 #include "sr_module.h"
45 #include "socket_info.h"
46 #include "rand/fastrand.h"
51 #include "mem/shm_mem.h"
53 #if defined PKG_MALLOC || defined SHM_MEM
58 #include <time.h> /* time(), used to initialize random numbers */
60 #define FORK_DONT_WAIT /* child doesn't wait for parent before starting
61 => faster startup, but the child should not assume
62 the parent fixed the pt[] entry for it */
68 extern void _start(void);
69 extern void etext(void);
73 static int estimated_proc_no=0;
74 static int estimated_fds_no=0;
77 /* number of known "common" used fds */
78 static int calc_common_open_fds_no()
82 /* 1 tcp send unix socket/all_proc,
83 * + 1 udp sock/udp proc + 1 possible dns comm. socket +
84 * + 1 temporary tcp send sock.
86 max_fds_no=estimated_proc_no*4 /* udp + tcp unix sock + tmp. tcp send +
87 tmp dns.*/ -1 /* timer (no udp)*/ +
88 3 /* stdin/out/err */;
94 /* returns 0 on success, -1 on error */
95 int init_pt(int proc_no)
101 estimated_proc_no+=proc_no;
102 estimated_fds_no+=calc_common_open_fds_no();
105 pt=shm_malloc(sizeof(struct process_table)*estimated_proc_no);
106 process_count = shm_malloc(sizeof(int));
108 pt=pkg_malloc(sizeof(struct process_table)*estimated_proc_no);
109 process_count = pkg_malloc(sizeof(int));
111 process_lock = lock_alloc();
112 process_lock = lock_init(process_lock);
113 if (pt==0||process_count==0||process_lock==0){
114 LOG(L_ERR, "ERROR: out of memory\n");
117 memset(pt, 0, sizeof(struct process_table)*estimated_proc_no);
119 for (r=0; r<estimated_proc_no; r++){
124 process_no=0; /*main process number*/
125 pt[process_no].pid=getpid();
126 memcpy(pt[process_no].desc,"main",5);
132 /* register no processes, used from mod_init when processes will be forked
134 * returns 0 on success, -1 on error
136 int register_procs(int no)
139 LOG(L_CRIT, "BUG: register_procs(%d) called at runtime\n", no);
142 estimated_proc_no+=no;
148 /* returns the maximum number of processes */
152 LOG(L_CRIT, "BUG: get_max_procs() called too early "
153 "(it must _not_ be called from mod_init())\n");
154 abort(); /* crash to quickly catch offenders */
156 return estimated_proc_no;
160 /* register no fds, used from mod_init when modules will open more global
161 * fds (from mod_init or child_init(PROC_INIT)
162 * or from child_init(rank) when the module will open fds local to the
164 * (this is needed because some other parts of ser code rely on knowing
165 * the maximum open fd number in a process)
166 * returns 0 on success, -1 on error
168 int register_fds(int no)
170 /* can be called at runtime, but should be called from child_init() */
171 estimated_fds_no+=no;
177 /* returns the maximum open fd number */
178 int get_max_open_fds()
181 LOG(L_CRIT, "BUG: get_max_open_fds() called too early "
182 "(it must _not_ be called from mod_init())\n");
183 abort(); /* crash to quickly catch offenders */
185 return estimated_fds_no;
189 /* return processes pid */
192 return pt ? pt[process_no].pid : getpid();
197 /* close unneeded sockets */
198 int close_extra_socks(int child_id, int proc_no)
202 struct socket_info* si;
204 if (child_id!=PROC_TCP_MAIN){
205 for (r=0; r<proc_no; r++){
206 if (pt[r].unix_sock>=0){
207 /* we can't change the value in pt[] because it's
208 * shared so we only close it */
209 close(pt[r].unix_sock);
212 /* close all listen sockets (needed only in tcp_main */
214 for(si=tcp_listen; si; si=si->next){
216 /* safe to change since this is a per process copy */
221 for(si=tls_listen; si; si=si->next){
223 /* safe to change since this is a per process copy */
229 /* we still need the udp sockets (for sending) so we don't close them
239 * Forks a new process.
240 * @param child_id - rank, if equal to PROC_NOCHLDINIT init_child will not be
241 * called for the new forked process (see sr_module.h)
242 * @param desc - text description for the process table
243 * @param make_sock - if to create a unix socket pair for it
244 * @returns the pid of the new process
246 int fork_process(int child_id, char *desc, int make_sock)
248 int pid, child_process_no;
250 unsigned int new_seed1;
251 unsigned int new_seed2;
258 sockfd[0]=sockfd[1]=-1;
259 if(make_sock && !tcp_disable){
261 LOG(L_CRIT, "BUG: fork_process(..., 1) called from a non "
262 "\"main\" process! If forking from a module's "
263 "child_init() fork only if rank==PROC_MAIN or"
264 " give up tcp send support (use 0 for make_sock)\n");
268 LOG(L_CRIT, "BUG: fork_process(..., 1) called, but tcp main "
269 " is already started\n");
272 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
273 LOG(L_ERR, "ERROR: fork_process(): socketpair failed: %s\n",
279 lock_get(process_lock);
280 if (*process_count>=estimated_proc_no) {
281 LOG(L_CRIT, "ERROR: fork_process(): Process limit of %d exceeded."
282 " Will simulate fork fail.\n", estimated_proc_no);
283 lock_release(process_lock);
288 child_process_no = *process_count;
293 lock_release(process_lock);
298 is_main=0; /* a forked process cannot be the "main" one */
299 process_no=child_process_no;
300 /* close tcp unix sockets if this is not tcp main */
302 close_extra_socks(child_id, process_no);
305 fastrand_seed(rand());
306 srandom(new_seed2+time(0));
307 shm_malloc_on_fork();
309 monstartup((u_long) &_start, (u_long) &etext);
311 #ifdef FORK_DONT_WAIT
312 /* record pid twice to avoid the child using it, before
313 * parent gets a chance to set it*/
314 pt[process_no].pid=getpid();
316 /* wait for parent to get out of critical zone.
317 * this is actually relevant as the parent updates
318 * the pt & process_count. */
319 lock_get(process_lock);
320 lock_release(process_lock);
323 if (make_sock && !tcp_disable){
325 unix_tcp_sock=sockfd[1];
328 if ((child_id!=PROC_NOCHLDINIT) && (init_child(child_id) < 0)) {
329 LOG(L_ERR, "ERROR: fork_process(): init_child failed for "
330 " process %d, pid %d, \"%s\"\n", process_no,
331 pt[process_no].pid, pt[process_no].desc);
338 #ifdef FORK_DONT_WAIT
339 lock_release(process_lock);
341 /* add the process to the list in shm */
342 pt[child_process_no].pid=pid;
344 strncpy(pt[child_process_no].desc, desc, MAX_PT_DESC);
347 if (make_sock && !tcp_disable){
349 pt[child_process_no].unix_sock=sockfd[0];
350 pt[child_process_no].idx=-1; /* this is not a "tcp" process*/
353 #ifdef FORK_DONT_WAIT
355 lock_release(process_lock);
362 if (sockfd[0]!=-1) close(sockfd[0]);
363 if (sockfd[1]!=-1) close(sockfd[1]);
370 * Forks a new TCP process.
371 * @param desc - text description for the process table
372 * @param r - index in the tcp_children array
373 * @param *reader_fd_1 - pointer to return the reader_fd[1]
374 * @returns the pid of the new process
377 int fork_tcp_process(int child_id, char *desc, int r, int *reader_fd_1)
379 int pid, child_process_no;
381 int reader_fd[2]; /* for comm. with the tcp children read */
384 unsigned int new_seed1;
385 unsigned int new_seed2;
388 sockfd[0]=sockfd[1]=-1;
389 reader_fd[0]=reader_fd[1]=-1;
393 LOG(L_CRIT, "BUG: fork_tcp_process() called from a non \"main\" "
398 LOG(L_CRIT, "BUG: fork_tcp_process(..., 1) called _after_ starting"
402 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
403 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
407 if (socketpair(AF_UNIX, SOCK_STREAM, 0, reader_fd)<0){
408 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
412 if (tcp_fix_child_sockets(reader_fd)<0){
413 LOG(L_ERR, "ERROR: fork_tcp_process(): failed to set non blocking"
414 "on child sockets\n");
415 /* continue, it's not critical (it will go slower under
416 * very high connection rates) */
418 lock_get(process_lock);
419 /* set the local process_no */
420 if (*process_count>=estimated_proc_no) {
421 LOG(L_CRIT, "ERROR: fork_tcp_process(): Process limit of %d exceeded."
422 " Simulating fork fail\n", estimated_proc_no);
423 lock_release(process_lock);
428 child_process_no = *process_count;
433 lock_release(process_lock);
438 is_main=0; /* a forked process cannot be the "main" one */
439 process_no=child_process_no;
440 /* close unneeded unix sockets */
441 close_extra_socks(child_id, process_no);
442 /* same for unneeded tcp_children <-> tcp_main unix socks */
444 if (tcp_children[i].unix_sock>=0){
445 close(tcp_children[i].unix_sock);
446 /* tcp_children is per process, so it's safe to change
447 * the unix_sock to -1 */
448 tcp_children[i].unix_sock=-1;
452 fastrand_seed(rand());
453 srandom(new_seed2+time(0));
454 shm_malloc_on_fork();
456 monstartup((u_long) &_start, (u_long) &etext);
458 #ifdef FORK_DONT_WAIT
459 /* record pid twice to avoid the child using it, before
460 - * parent gets a chance to set it*/
461 pt[process_no].pid=getpid();
463 /* wait for parent to get out of critical zone */
464 lock_get(process_lock);
465 lock_release(process_lock);
468 unix_tcp_sock=sockfd[1];
470 if (reader_fd_1) *reader_fd_1=reader_fd[1];
471 if ((child_id!=PROC_NOCHLDINIT) && (init_child(child_id) < 0)) {
472 LOG(L_ERR, "ERROR: fork_tcp_process(): init_child failed for "
473 "process %d, pid %d, \"%s\"\n", process_no,
474 pt[process_no].pid, pt[process_no].desc);
481 #ifdef FORK_DONT_WAIT
482 lock_release(process_lock);
484 /* add the process to the list in shm */
485 pt[child_process_no].pid=pid;
486 pt[child_process_no].unix_sock=sockfd[0];
487 pt[child_process_no].idx=r;
489 snprintf(pt[child_process_no].desc, MAX_PT_DESC, "%s child=%d",
492 #ifdef FORK_DONT_WAIT
494 lock_release(process_lock);
500 tcp_children[r].pid=pid;
501 tcp_children[r].proc_no=child_process_no;
502 tcp_children[r].busy=0;
503 tcp_children[r].n_reqs=0;
504 tcp_children[r].unix_sock=reader_fd[0];
510 if (sockfd[0]!=-1) close(sockfd[0]);
511 if (sockfd[1]!=-1) close(sockfd[1]);
512 if (reader_fd[0]!=-1) close(reader_fd[0]);
513 if (reader_fd[1]!=-1) close(reader_fd[1]);
520 /* Dumps pkg memory status.
521 * Per-child process callback that is called
522 * when mem_dump_pkg cfg var is changed.
524 void mem_dump_pkg_cb(str *name)
528 if (cfg_get(core, core_cfg, mem_dump_pkg) == my_pid()) {
529 /* set memlog to ALERT level to force
530 printing the log messages */
534 LOG(memlog, "Memory status (pkg) of process %d:\n", my_pid());
543 /* Dumps shm memory status.
544 * fixup function that is called
545 * when mem_dump_shm cfg var is set.
547 int mem_dump_shm_fixup(void *handle, str *name, void **val)
551 if ((long)(void*)(*val)) {
552 /* set memlog to ALERT level to force
553 printing the log messages */
557 LOG(memlog, "Memory status (shm)\n");
561 *val = (void*)(long)0;