- core sctp support
[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|sctp + tcp unix sock +
87                                                                           tmp. tcp send +
88                                                                           tmp dns.*/
89                                 -1 /* timer (no udp)*/ + 3 /* stdin/out/err */;
90         return max_fds_no;
91 }
92
93
94
95 /* returns 0 on success, -1 on error */
96 int init_pt(int proc_no)
97 {
98 #ifdef USE_TCP
99         int r;
100 #endif
101         
102         estimated_proc_no+=proc_no;
103         estimated_fds_no+=calc_common_open_fds_no();
104         /*alloc pids*/
105 #ifdef SHM_MEM
106         pt=shm_malloc(sizeof(struct process_table)*estimated_proc_no);
107         process_count = shm_malloc(sizeof(int));
108 #else
109         pt=pkg_malloc(sizeof(struct process_table)*estimated_proc_no);
110         process_count = pkg_malloc(sizeof(int));
111 #endif
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");
116                 return -1;
117         }
118         memset(pt, 0, sizeof(struct process_table)*estimated_proc_no);
119 #ifdef USE_TCP
120         for (r=0; r<estimated_proc_no; r++){
121                 pt[r].unix_sock=-1;
122                 pt[r].idx=-1;
123         }
124 #endif
125         process_no=0; /*main process number*/
126         pt[process_no].pid=getpid();
127         memcpy(pt[process_no].desc,"main",5);
128         *process_count=1;
129         return 0;
130 }
131
132
133 /* register no processes, used from mod_init when processes will be forked
134  *  from mod_child 
135  *  returns 0 on success, -1 on error
136  */
137 int register_procs(int no)
138 {
139         if (pt){
140                 LOG(L_CRIT, "BUG: register_procs(%d) called at runtime\n", no);
141                 return -1;
142         }
143         estimated_proc_no+=no;
144         return 0;
145 }
146
147
148
149 /* returns the maximum number of processes */
150 int get_max_procs()
151 {
152         if (pt==0){
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 */
156         }
157         return estimated_proc_no;
158 }
159
160
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
164  *   process "rank".
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
168  */
169 int register_fds(int no)
170 {
171         /* can be called at runtime, but should be called from child_init() */
172         estimated_fds_no+=no;
173         return 0;
174 }
175
176
177
178 /* returns the maximum open fd number */
179 int get_max_open_fds()
180 {
181         if (pt==0){
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 */
185         }
186         return estimated_fds_no;
187 }
188
189
190 /* return processes pid */
191 int my_pid()
192 {
193         return pt ? pt[process_no].pid : getpid();
194 }
195
196
197
198 /* close unneeded sockets */
199 int close_extra_socks(int child_id, int proc_no)
200 {
201 #ifdef USE_TCP
202         int r;
203         struct socket_info* si;
204         
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);
211                         }
212                 }
213                 /* close all listen sockets (needed only in tcp_main */
214                 if (!tcp_disable){
215                         for(si=tcp_listen; si; si=si->next){
216                                 close(si->socket);
217                                 /* safe to change since this is a per process copy */
218                                 si->socket=-1;
219                         }
220 #ifdef USE_TLS
221                         if (!tls_disable){
222                                 for(si=tls_listen; si; si=si->next){
223                                         close(si->socket);
224                                         /* safe to change since this is a per process copy */
225                                         si->socket=-1;
226                                 }
227                         }
228 #endif /* USE_TLS */
229                 }
230                 /* we still need the udp sockets (for sending) so we don't close them
231                  * too */
232         }
233 #endif /* USE_TCP */
234         return 0;
235 }
236
237
238
239 /**
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
246  */
247 int fork_process(int child_id, char *desc, int make_sock)
248 {
249         int pid, child_process_no;
250         int ret;
251         unsigned int new_seed1;
252         unsigned int new_seed2;
253 #ifdef USE_TCP
254         int sockfd[2];
255 #endif
256
257         ret=-1;
258         #ifdef USE_TCP
259                 sockfd[0]=sockfd[1]=-1;
260                 if(make_sock && !tcp_disable){
261                          if (!is_main){
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");
266                                  goto error;
267                          }
268                          if (tcp_main_pid){
269                                  LOG(L_CRIT, "BUG: fork_process(..., 1) called, but tcp main "
270                                                  " is already started\n");
271                                  goto error;
272                          }
273                          if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
274                                 LOG(L_ERR, "ERROR: fork_process(): socketpair failed: %s\n",
275                                                         strerror(errno));
276                                 goto error;
277                         }
278                 }
279         #endif
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);
285                 goto error;
286         }       
287         
288         
289         child_process_no = *process_count;
290         new_seed1=rand();
291         new_seed2=random();
292         pid = fork();
293         if (pid<0) {
294                 lock_release(process_lock);
295                 ret=pid;
296                 goto error;
297         }else if (pid==0){
298                 /* child */
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 */
302 #ifdef USE_TCP
303                 close_extra_socks(child_id, process_no);
304 #endif /* USE_TCP */
305                 srand(new_seed1);
306                 fastrand_seed(rand());
307                 srandom(new_seed2+time(0));
308                 shm_malloc_on_fork();
309 #ifdef PROFILING
310                 monstartup((u_long) &_start, (u_long) &etext);
311 #endif
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();
316 #else
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);
322 #endif
323                 #ifdef USE_TCP
324                         if (make_sock && !tcp_disable){
325                                 close(sockfd[0]);
326                                 unix_tcp_sock=sockfd[1];
327                         }
328                 #endif          
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);
333                         return -1;
334                 }
335                 return pid;
336         } else {
337                 /* parent */
338                 (*process_count)++;
339 #ifdef FORK_DONT_WAIT
340                 lock_release(process_lock);
341 #endif
342                 /* add the process to the list in shm */
343                 pt[child_process_no].pid=pid;
344                 if (desc){
345                         strncpy(pt[child_process_no].desc, desc, MAX_PT_DESC);
346                 }
347                 #ifdef USE_TCP
348                         if (make_sock && !tcp_disable){
349                                 close(sockfd[1]);
350                                 pt[child_process_no].unix_sock=sockfd[0];
351                                 pt[child_process_no].idx=-1; /* this is not a "tcp" process*/
352                         }
353                 #endif
354 #ifdef FORK_DONT_WAIT
355 #else
356                 lock_release(process_lock);
357 #endif
358                 ret=pid;
359                 goto end;
360         }
361 error:
362 #ifdef USE_TCP
363         if (sockfd[0]!=-1) close(sockfd[0]);
364         if (sockfd[1]!=-1) close(sockfd[1]);
365 #endif
366 end:
367         return ret;
368 }
369
370 /**
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
376  */
377 #ifdef USE_TCP
378 int fork_tcp_process(int child_id, char *desc, int r, int *reader_fd_1)
379 {
380         int pid, child_process_no;
381         int sockfd[2];
382         int reader_fd[2]; /* for comm. with the tcp children read  */
383         int ret;
384         int i;
385         unsigned int new_seed1;
386         unsigned int new_seed2;
387         
388         /* init */
389         sockfd[0]=sockfd[1]=-1;
390         reader_fd[0]=reader_fd[1]=-1;
391         ret=-1;
392         
393         if (!is_main){
394                  LOG(L_CRIT, "BUG: fork_tcp_process() called from a non \"main\" "
395                                         "process\n");
396                  goto error;
397          }
398          if (tcp_main_pid){
399                  LOG(L_CRIT, "BUG: fork_tcp_process(..., 1) called _after_ starting"
400                                         " tcp main\n");
401                  goto error;
402          }
403         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
404                 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
405                                         strerror(errno));
406                 goto error;
407         }
408         if (socketpair(AF_UNIX, SOCK_STREAM, 0, reader_fd)<0){
409                 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
410                                         strerror(errno));
411                 goto error;
412         }
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) */
418         }
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);
425                 goto error;
426         }
427         
428         
429         child_process_no = *process_count;
430         new_seed1=rand();
431         new_seed2=random();
432         pid = fork();
433         if (pid<0) {
434                 lock_release(process_lock);
435                 ret=pid;
436                 goto end;
437         }
438         if (pid==0){
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 */
444                 for (i=0; i<r; i++){
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;
450                         }
451                 }
452                 srand(new_seed1);
453                 fastrand_seed(rand());
454                 srandom(new_seed2+time(0));
455                 shm_malloc_on_fork();
456 #ifdef PROFILING
457                 monstartup((u_long) &_start, (u_long) &etext);
458 #endif
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();
463 #else
464                 /* wait for parent to get out of critical zone */
465                 lock_get(process_lock);
466                 lock_release(process_lock);
467 #endif
468                 close(sockfd[0]);
469                 unix_tcp_sock=sockfd[1];
470                 close(reader_fd[0]);
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);
476                         return -1;
477                 }
478                 return pid;
479         } else {
480                 /* parent */
481                 (*process_count)++;
482 #ifdef FORK_DONT_WAIT
483                 lock_release(process_lock);
484 #endif
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;
489                 if (desc){
490                         snprintf(pt[child_process_no].desc, MAX_PT_DESC, "%s child=%d", 
491                                                 desc, r);
492                 }
493 #ifdef FORK_DONT_WAIT
494 #else
495                 lock_release(process_lock);
496 #endif
497                 
498                 close(sockfd[1]);
499                 close(reader_fd[1]);
500                 
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];
506                 
507                 ret=pid;
508                 goto end;
509         }
510 error:
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]);
515 end:
516         return ret;
517 }
518 #endif
519
520 #ifdef PKG_MALLOC
521 /* Dumps pkg memory status.
522  * Per-child process callback that is called
523  * when mem_dump_pkg cfg var is changed.
524  */
525 void mem_dump_pkg_cb(str *name)
526 {
527         int     old_memlog;
528
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 */
532                 old_memlog = memlog;
533                 memlog = L_ALERT;
534
535                 LOG(memlog, "Memory status (pkg) of process %d:\n", my_pid());
536                 pkg_status();
537
538                 memlog = old_memlog;
539         }
540 }
541 #endif
542
543 #ifdef SHM_MEM
544 /* Dumps shm memory status.
545  * fixup function that is called
546  * when mem_dump_shm cfg var is set.
547  */
548 int mem_dump_shm_fixup(void *handle, str *name, void **val)
549 {
550         int     old_memlog;
551
552         if ((long)(void*)(*val)) {
553                 /* set memlog to ALERT level to force
554                 printing the log messages */
555                 old_memlog = memlog;
556                 memlog = L_ALERT;
557
558                 LOG(memlog, "Memory status (shm)\n");
559                 shm_status();
560
561                 memlog = old_memlog;
562                 *val = (void*)(long)0;
563         }
564         return 0;
565 }
566 #endif