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|sctp + tcp unix sock +
89 -1 /* timer (no udp)*/ + 3 /* stdin/out/err */;
95 /* returns 0 on success, -1 on error */
96 int init_pt(int proc_no)
102 estimated_proc_no+=proc_no;
103 estimated_fds_no+=calc_common_open_fds_no();
106 pt=shm_malloc(sizeof(struct process_table)*estimated_proc_no);
107 process_count = shm_malloc(sizeof(int));
109 pt=pkg_malloc(sizeof(struct process_table)*estimated_proc_no);
110 process_count = pkg_malloc(sizeof(int));
112 process_lock = lock_alloc();
113 process_lock = lock_init(process_lock);
114 if (pt==0||process_count==0||process_lock==0){
115 LOG(L_ERR, "ERROR: out of memory\n");
118 memset(pt, 0, sizeof(struct process_table)*estimated_proc_no);
120 for (r=0; r<estimated_proc_no; r++){
125 process_no=0; /*main process number*/
126 pt[process_no].pid=getpid();
127 memcpy(pt[process_no].desc,"main",5);
133 /* register no processes, used from mod_init when processes will be forked
135 * returns 0 on success, -1 on error
137 int register_procs(int no)
140 LOG(L_CRIT, "BUG: register_procs(%d) called at runtime\n", no);
143 estimated_proc_no+=no;
149 /* returns the maximum number of processes */
153 LOG(L_CRIT, "BUG: get_max_procs() called too early "
154 "(it must _not_ be called from mod_init())\n");
155 abort(); /* crash to quickly catch offenders */
157 return estimated_proc_no;
161 /* register no fds, used from mod_init when modules will open more global
162 * fds (from mod_init or child_init(PROC_INIT)
163 * or from child_init(rank) when the module will open fds local to the
165 * (this is needed because some other parts of ser code rely on knowing
166 * the maximum open fd number in a process)
167 * returns 0 on success, -1 on error
169 int register_fds(int no)
171 /* can be called at runtime, but should be called from child_init() */
172 estimated_fds_no+=no;
178 /* returns the maximum open fd number */
179 int get_max_open_fds()
182 LOG(L_CRIT, "BUG: get_max_open_fds() called too early "
183 "(it must _not_ be called from mod_init())\n");
184 abort(); /* crash to quickly catch offenders */
186 return estimated_fds_no;
190 /* return processes pid */
193 return pt ? pt[process_no].pid : getpid();
198 /* close unneeded sockets */
199 int close_extra_socks(int child_id, int proc_no)
203 struct socket_info* si;
205 if (child_id!=PROC_TCP_MAIN){
206 for (r=0; r<proc_no; r++){
207 if (pt[r].unix_sock>=0){
208 /* we can't change the value in pt[] because it's
209 * shared so we only close it */
210 close(pt[r].unix_sock);
213 /* close all listen sockets (needed only in tcp_main */
215 for(si=tcp_listen; si; si=si->next){
217 /* safe to change since this is a per process copy */
222 for(si=tls_listen; si; si=si->next){
224 /* safe to change since this is a per process copy */
230 /* we still need the udp sockets (for sending) so we don't close them
240 * Forks a new process.
241 * @param child_id - rank, if equal to PROC_NOCHLDINIT init_child will not be
242 * called for the new forked process (see sr_module.h)
243 * @param desc - text description for the process table
244 * @param make_sock - if to create a unix socket pair for it
245 * @returns the pid of the new process
247 int fork_process(int child_id, char *desc, int make_sock)
249 int pid, child_process_no;
251 unsigned int new_seed1;
252 unsigned int new_seed2;
259 sockfd[0]=sockfd[1]=-1;
260 if(make_sock && !tcp_disable){
262 LOG(L_CRIT, "BUG: fork_process(..., 1) called from a non "
263 "\"main\" process! If forking from a module's "
264 "child_init() fork only if rank==PROC_MAIN or"
265 " give up tcp send support (use 0 for make_sock)\n");
269 LOG(L_CRIT, "BUG: fork_process(..., 1) called, but tcp main "
270 " is already started\n");
273 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
274 LOG(L_ERR, "ERROR: fork_process(): socketpair failed: %s\n",
280 lock_get(process_lock);
281 if (*process_count>=estimated_proc_no) {
282 LOG(L_CRIT, "ERROR: fork_process(): Process limit of %d exceeded."
283 " Will simulate fork fail.\n", estimated_proc_no);
284 lock_release(process_lock);
289 child_process_no = *process_count;
294 lock_release(process_lock);
299 is_main=0; /* a forked process cannot be the "main" one */
300 process_no=child_process_no;
301 /* close tcp unix sockets if this is not tcp main */
303 close_extra_socks(child_id, process_no);
306 fastrand_seed(rand());
307 srandom(new_seed2+time(0));
308 shm_malloc_on_fork();
310 monstartup((u_long) &_start, (u_long) &etext);
312 #ifdef FORK_DONT_WAIT
313 /* record pid twice to avoid the child using it, before
314 * parent gets a chance to set it*/
315 pt[process_no].pid=getpid();
317 /* wait for parent to get out of critical zone.
318 * this is actually relevant as the parent updates
319 * the pt & process_count. */
320 lock_get(process_lock);
321 lock_release(process_lock);
324 if (make_sock && !tcp_disable){
326 unix_tcp_sock=sockfd[1];
329 if ((child_id!=PROC_NOCHLDINIT) && (init_child(child_id) < 0)) {
330 LOG(L_ERR, "ERROR: fork_process(): init_child failed for "
331 " process %d, pid %d, \"%s\"\n", process_no,
332 pt[process_no].pid, pt[process_no].desc);
339 #ifdef FORK_DONT_WAIT
340 lock_release(process_lock);
342 /* add the process to the list in shm */
343 pt[child_process_no].pid=pid;
345 strncpy(pt[child_process_no].desc, desc, MAX_PT_DESC);
348 if (make_sock && !tcp_disable){
350 pt[child_process_no].unix_sock=sockfd[0];
351 pt[child_process_no].idx=-1; /* this is not a "tcp" process*/
354 #ifdef FORK_DONT_WAIT
356 lock_release(process_lock);
363 if (sockfd[0]!=-1) close(sockfd[0]);
364 if (sockfd[1]!=-1) close(sockfd[1]);
371 * Forks a new TCP process.
372 * @param desc - text description for the process table
373 * @param r - index in the tcp_children array
374 * @param *reader_fd_1 - pointer to return the reader_fd[1]
375 * @returns the pid of the new process
378 int fork_tcp_process(int child_id, char *desc, int r, int *reader_fd_1)
380 int pid, child_process_no;
382 int reader_fd[2]; /* for comm. with the tcp children read */
385 unsigned int new_seed1;
386 unsigned int new_seed2;
389 sockfd[0]=sockfd[1]=-1;
390 reader_fd[0]=reader_fd[1]=-1;
394 LOG(L_CRIT, "BUG: fork_tcp_process() called from a non \"main\" "
399 LOG(L_CRIT, "BUG: fork_tcp_process(..., 1) called _after_ starting"
403 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
404 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
408 if (socketpair(AF_UNIX, SOCK_STREAM, 0, reader_fd)<0){
409 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
413 if (tcp_fix_child_sockets(reader_fd)<0){
414 LOG(L_ERR, "ERROR: fork_tcp_process(): failed to set non blocking"
415 "on child sockets\n");
416 /* continue, it's not critical (it will go slower under
417 * very high connection rates) */
419 lock_get(process_lock);
420 /* set the local process_no */
421 if (*process_count>=estimated_proc_no) {
422 LOG(L_CRIT, "ERROR: fork_tcp_process(): Process limit of %d exceeded."
423 " Simulating fork fail\n", estimated_proc_no);
424 lock_release(process_lock);
429 child_process_no = *process_count;
434 lock_release(process_lock);
439 is_main=0; /* a forked process cannot be the "main" one */
440 process_no=child_process_no;
441 /* close unneeded unix sockets */
442 close_extra_socks(child_id, process_no);
443 /* same for unneeded tcp_children <-> tcp_main unix socks */
445 if (tcp_children[i].unix_sock>=0){
446 close(tcp_children[i].unix_sock);
447 /* tcp_children is per process, so it's safe to change
448 * the unix_sock to -1 */
449 tcp_children[i].unix_sock=-1;
453 fastrand_seed(rand());
454 srandom(new_seed2+time(0));
455 shm_malloc_on_fork();
457 monstartup((u_long) &_start, (u_long) &etext);
459 #ifdef FORK_DONT_WAIT
460 /* record pid twice to avoid the child using it, before
461 - * parent gets a chance to set it*/
462 pt[process_no].pid=getpid();
464 /* wait for parent to get out of critical zone */
465 lock_get(process_lock);
466 lock_release(process_lock);
469 unix_tcp_sock=sockfd[1];
471 if (reader_fd_1) *reader_fd_1=reader_fd[1];
472 if ((child_id!=PROC_NOCHLDINIT) && (init_child(child_id) < 0)) {
473 LOG(L_ERR, "ERROR: fork_tcp_process(): init_child failed for "
474 "process %d, pid %d, \"%s\"\n", process_no,
475 pt[process_no].pid, pt[process_no].desc);
482 #ifdef FORK_DONT_WAIT
483 lock_release(process_lock);
485 /* add the process to the list in shm */
486 pt[child_process_no].pid=pid;
487 pt[child_process_no].unix_sock=sockfd[0];
488 pt[child_process_no].idx=r;
490 snprintf(pt[child_process_no].desc, MAX_PT_DESC, "%s child=%d",
493 #ifdef FORK_DONT_WAIT
495 lock_release(process_lock);
501 tcp_children[r].pid=pid;
502 tcp_children[r].proc_no=child_process_no;
503 tcp_children[r].busy=0;
504 tcp_children[r].n_reqs=0;
505 tcp_children[r].unix_sock=reader_fd[0];
511 if (sockfd[0]!=-1) close(sockfd[0]);
512 if (sockfd[1]!=-1) close(sockfd[1]);
513 if (reader_fd[0]!=-1) close(reader_fd[0]);
514 if (reader_fd[1]!=-1) close(reader_fd[1]);
521 /* Dumps pkg memory status.
522 * Per-child process callback that is called
523 * when mem_dump_pkg cfg var is changed.
525 void mem_dump_pkg_cb(str *name)
529 if (cfg_get(core, core_cfg, mem_dump_pkg) == my_pid()) {
530 /* set memlog to ALERT level to force
531 printing the log messages */
535 LOG(memlog, "Memory status (pkg) of process %d:\n", my_pid());
544 /* Dumps shm memory status.
545 * fixup function that is called
546 * when mem_dump_shm cfg var is set.
548 int mem_dump_shm_fixup(void *handle, str *name, void **val)
552 if ((long)(void*)(*val)) {
553 /* set memlog to ALERT level to force
554 printing the log messages */
558 LOG(memlog, "Memory status (shm)\n");
562 *val = (void*)(long)0;