fc71413bd0bf9c0772f1dc1c24a90f9af8c59949
[sip-router] / pt.c
1 /*
2  * $Id$
3  *
4  * Process Table
5  *
6  *
7  *
8  * Copyright (C) 2001-2003 FhG Fokus
9  *
10  * This file is part of ser, a free SIP server.
11  *
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
16  *
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:
20  *    info@iptel.org
21  *
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.
26  *
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
30  */
31 /*
32  * History:
33  * --------
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)
39  */
40
41
42 #include "pt.h"
43 #include "tcp_init.h"
44 #include "sr_module.h"
45 #include "socket_info.h"
46 #include "rand/fastrand.h"
47 #ifdef PKG_MALLOC
48 #include "mem/mem.h"
49 #endif
50 #ifdef SHM_MEM
51 #include "mem/shm_mem.h"
52 #endif
53 #if defined PKG_MALLOC || defined SHM_MEM
54 #include "cfg_core.h"
55 #endif
56
57 #include <stdio.h>
58 #include <time.h> /* time(), used to initialize random numbers */
59
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 */
63
64
65 #ifdef PROFILING
66 #include <sys/gmon.h>
67
68         extern void _start(void);
69         extern void etext(void);
70 #endif
71
72
73 static int estimated_proc_no=0;
74 static int estimated_fds_no=0;
75
76
77 /* number of known "common" used fds */
78 static int calc_common_open_fds_no()
79 {
80         int max_fds_no;
81         
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.
85          */
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 */;
89         return max_fds_no;
90 }
91
92
93
94 /* returns 0 on success, -1 on error */
95 int init_pt(int proc_no)
96 {
97 #ifdef USE_TCP
98         int r;
99 #endif
100         
101         estimated_proc_no+=proc_no;
102         estimated_fds_no+=calc_common_open_fds_no();
103         /*alloc pids*/
104 #ifdef SHM_MEM
105         pt=shm_malloc(sizeof(struct process_table)*estimated_proc_no);
106         process_count = shm_malloc(sizeof(int));
107 #else
108         pt=pkg_malloc(sizeof(struct process_table)*estimated_proc_no);
109         process_count = pkg_malloc(sizeof(int));
110 #endif
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");
115                 return -1;
116         }
117         memset(pt, 0, sizeof(struct process_table)*estimated_proc_no);
118 #ifdef USE_TCP
119         for (r=0; r<estimated_proc_no; r++){
120                 pt[r].unix_sock=-1;
121                 pt[r].idx=-1;
122         }
123 #endif
124         process_no=0; /*main process number*/
125         pt[process_no].pid=getpid();
126         memcpy(pt[process_no].desc,"main",5);
127         *process_count=1;
128         return 0;
129 }
130
131
132 /* register no processes, used from mod_init when processes will be forked
133  *  from mod_child 
134  *  returns 0 on success, -1 on error
135  */
136 int register_procs(int no)
137 {
138         if (pt){
139                 LOG(L_CRIT, "BUG: register_procs(%d) called at runtime\n", no);
140                 return -1;
141         }
142         estimated_proc_no+=no;
143         return 0;
144 }
145
146
147
148 /* returns the maximum number of processes */
149 int get_max_procs()
150 {
151         if (pt==0){
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 */
155         }
156         return estimated_proc_no;
157 }
158
159
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
163  *   process "rank".
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
167  */
168 int register_fds(int no)
169 {
170         /* can be called at runtime, but should be called from child_init() */
171         estimated_fds_no+=no;
172         return 0;
173 }
174
175
176
177 /* returns the maximum open fd number */
178 int get_max_open_fds()
179 {
180         if (pt==0){
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 */
184         }
185         return estimated_fds_no;
186 }
187
188
189 /* return processes pid */
190 int my_pid()
191 {
192         return pt ? pt[process_no].pid : getpid();
193 }
194
195
196
197 /* close unneeded sockets */
198 int close_extra_socks(int child_id, int proc_no)
199 {
200 #ifdef USE_TCP
201         int r;
202         struct socket_info* si;
203         
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);
210                         }
211                 }
212                 /* close all listen sockets (needed only in tcp_main */
213                 if (!tcp_disable){
214                         for(si=tcp_listen; si; si=si->next){
215                                 close(si->socket);
216                                 /* safe to change since this is a per process copy */
217                                 si->socket=-1;
218                         }
219 #ifdef USE_TLS
220                         if (!tls_disable){
221                                 for(si=tls_listen; si; si=si->next){
222                                         close(si->socket);
223                                         /* safe to change since this is a per process copy */
224                                         si->socket=-1;
225                                 }
226                         }
227 #endif /* USE_TLS */
228                 }
229                 /* we still need the udp sockets (for sending) so we don't close them
230                  * too */
231         }
232 #endif /* USE_TCP */
233         return 0;
234 }
235
236
237
238 /**
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
245  */
246 int fork_process(int child_id, char *desc, int make_sock)
247 {
248         int pid, child_process_no;
249         int ret;
250         unsigned int new_seed1;
251         unsigned int new_seed2;
252 #ifdef USE_TCP
253         int sockfd[2];
254 #endif
255
256         ret=-1;
257         #ifdef USE_TCP
258                 sockfd[0]=sockfd[1]=-1;
259                 if(make_sock && !tcp_disable){
260                          if (!is_main){
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");
265                                  goto error;
266                          }
267                          if (tcp_main_pid){
268                                  LOG(L_CRIT, "BUG: fork_process(..., 1) called, but tcp main "
269                                                  " is already started\n");
270                                  goto error;
271                          }
272                          if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
273                                 LOG(L_ERR, "ERROR: fork_process(): socketpair failed: %s\n",
274                                                         strerror(errno));
275                                 goto error;
276                         }
277                 }
278         #endif
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);
284                 goto error;
285         }       
286         
287         
288         child_process_no = *process_count;
289         new_seed1=rand();
290         new_seed2=random();
291         pid = fork();
292         if (pid<0) {
293                 lock_release(process_lock);
294                 ret=pid;
295                 goto error;
296         }else if (pid==0){
297                 /* child */
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 */
301 #ifdef USE_TCP
302                 close_extra_socks(child_id, process_no);
303 #endif /* USE_TCP */
304                 srand(new_seed1);
305                 fastrand_seed(rand());
306                 srandom(new_seed2+time(0));
307                 shm_malloc_on_fork();
308 #ifdef PROFILING
309                 monstartup((u_long) &_start, (u_long) &etext);
310 #endif
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();
315 #else
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);
321 #endif
322                 #ifdef USE_TCP
323                         if (make_sock && !tcp_disable){
324                                 close(sockfd[0]);
325                                 unix_tcp_sock=sockfd[1];
326                         }
327                 #endif          
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);
332                         return -1;
333                 }
334                 return pid;
335         } else {
336                 /* parent */
337                 (*process_count)++;
338 #ifdef FORK_DONT_WAIT
339                 lock_release(process_lock);
340 #endif
341                 /* add the process to the list in shm */
342                 pt[child_process_no].pid=pid;
343                 if (desc){
344                         strncpy(pt[child_process_no].desc, desc, MAX_PT_DESC);
345                 }
346                 #ifdef USE_TCP
347                         if (make_sock && !tcp_disable){
348                                 close(sockfd[1]);
349                                 pt[child_process_no].unix_sock=sockfd[0];
350                                 pt[child_process_no].idx=-1; /* this is not a "tcp" process*/
351                         }
352                 #endif
353 #ifdef FORK_DONT_WAIT
354 #else
355                 lock_release(process_lock);
356 #endif
357                 ret=pid;
358                 goto end;
359         }
360 error:
361 #ifdef USE_TCP
362         if (sockfd[0]!=-1) close(sockfd[0]);
363         if (sockfd[1]!=-1) close(sockfd[1]);
364 #endif
365 end:
366         return ret;
367 }
368
369 /**
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
375  */
376 #ifdef USE_TCP
377 int fork_tcp_process(int child_id, char *desc, int r, int *reader_fd_1)
378 {
379         int pid, child_process_no;
380         int sockfd[2];
381         int reader_fd[2]; /* for comm. with the tcp children read  */
382         int ret;
383         int i;
384         unsigned int new_seed1;
385         unsigned int new_seed2;
386         
387         /* init */
388         sockfd[0]=sockfd[1]=-1;
389         reader_fd[0]=reader_fd[1]=-1;
390         ret=-1;
391         
392         if (!is_main){
393                  LOG(L_CRIT, "BUG: fork_tcp_process() called from a non \"main\" "
394                                         "process\n");
395                  goto error;
396          }
397          if (tcp_main_pid){
398                  LOG(L_CRIT, "BUG: fork_tcp_process(..., 1) called _after_ starting"
399                                         " tcp main\n");
400                  goto error;
401          }
402         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
403                 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
404                                         strerror(errno));
405                 goto error;
406         }
407         if (socketpair(AF_UNIX, SOCK_STREAM, 0, reader_fd)<0){
408                 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
409                                         strerror(errno));
410                 goto error;
411         }
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) */
417         }
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);
424                 goto error;
425         }
426         
427         
428         child_process_no = *process_count;
429         new_seed1=rand();
430         new_seed2=random();
431         pid = fork();
432         if (pid<0) {
433                 lock_release(process_lock);
434                 ret=pid;
435                 goto end;
436         }
437         if (pid==0){
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 */
443                 for (i=0; i<r; i++){
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;
449                         }
450                 }
451                 srand(new_seed1);
452                 fastrand_seed(rand());
453                 srandom(new_seed2+time(0));
454                 shm_malloc_on_fork();
455 #ifdef PROFILING
456                 monstartup((u_long) &_start, (u_long) &etext);
457 #endif
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();
462 #else
463                 /* wait for parent to get out of critical zone */
464                 lock_get(process_lock);
465                 lock_release(process_lock);
466 #endif
467                 close(sockfd[0]);
468                 unix_tcp_sock=sockfd[1];
469                 close(reader_fd[0]);
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);
475                         return -1;
476                 }
477                 return pid;
478         } else {
479                 /* parent */
480                 (*process_count)++;
481 #ifdef FORK_DONT_WAIT
482                 lock_release(process_lock);
483 #endif
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;
488                 if (desc){
489                         snprintf(pt[child_process_no].desc, MAX_PT_DESC, "%s child=%d", 
490                                                 desc, r);
491                 }
492 #ifdef FORK_DONT_WAIT
493 #else
494                 lock_release(process_lock);
495 #endif
496                 
497                 close(sockfd[1]);
498                 close(reader_fd[1]);
499                 
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];
505                 
506                 ret=pid;
507                 goto end;
508         }
509 error:
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]);
514 end:
515         return ret;
516 }
517 #endif
518
519 #ifdef PKG_MALLOC
520 /* Dumps pkg memory status.
521  * Per-child process callback that is called
522  * when mem_dump_pkg cfg var is changed.
523  */
524 void mem_dump_pkg_cb(str *name)
525 {
526         int     old_memlog;
527
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 */
531                 old_memlog = memlog;
532                 memlog = L_ALERT;
533
534                 LOG(memlog, "Memory status (pkg) of process %d:\n", my_pid());
535                 pkg_status();
536
537                 memlog = old_memlog;
538         }
539 }
540 #endif
541
542 #ifdef SHM_MEM
543 /* Dumps shm memory status.
544  * fixup function that is called
545  * when mem_dump_shm cfg var is set.
546  */
547 int mem_dump_shm_fixup(void *handle, str *name, void **val)
548 {
549         int     old_memlog;
550
551         if ((long)(void*)(*val)) {
552                 /* set memlog to ALERT level to force
553                 printing the log messages */
554                 old_memlog = memlog;
555                 memlog = L_ALERT;
556
557                 LOG(memlog, "Memory status (shm)\n");
558                 shm_status();
559
560                 memlog = old_memlog;
561                 *val = (void*)(long)0;
562         }
563         return 0;
564 }
565 #endif