f12792cfb76f2ac12cd2bb7d8b0779cacab6ed64
[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  */
36
37
38 #include "pt.h"
39 #include "tcp_init.h"
40 #include "sr_module.h"
41
42 #include "stdio.h"
43
44
45 static int estimated_proc_no=0;
46
47 /* returns 0 on success, -1 on error */
48 int init_pt(int proc_no)
49 {
50         estimated_proc_no+=proc_no;
51         /*alloc pids*/
52 #ifdef SHM_MEM
53         pt=shm_malloc(sizeof(struct process_table)*estimated_proc_no);
54         process_count = shm_malloc(sizeof(int));
55 #else
56         pt=pkg_malloc(sizeof(struct process_table)*estimated_proc_no);
57         process_count = pkg_malloc(sizeof(int));
58 #endif
59         process_lock = lock_alloc();
60         process_lock = lock_init(process_lock);
61         if (pt==0||process_count==0||process_lock==0){
62                 LOG(L_ERR, "ERROR: out  of memory\n");
63                 return -1;
64         }
65         memset(pt, 0, sizeof(struct process_table)*estimated_proc_no);
66
67         process_no=0; /*main process number*/
68         pt[process_no].pid=getpid();
69         memcpy(pt[*process_count].desc,"main",5);
70         *process_count=1;
71         return 0;
72 }
73
74
75 /* register no processes, used from mod_init when processes will be forked
76  *  from mod_child 
77  *  returns 0 on success, -1 on error
78  */
79 int register_procs(int no)
80 {
81         if (pt){
82                 LOG(L_CRIT, "BUG: register_procs(%d) called at runtime\n", no);
83                 return -1;
84         }
85         estimated_proc_no+=no;
86         return 0;
87 }
88
89
90
91 /* returns the maximum number of processes */
92 int get_max_procs()
93 {
94         return estimated_proc_no;
95 }
96
97
98 /* return processes pid */
99 inline int my_pid()
100 {
101         return pt ? pt[process_no].pid : getpid();
102 }
103
104 /**
105  * Forks a new process.
106  * @param child_id - rank, if equal to PROC_NOCHLDINIT init_child will not be
107  *                   called for the new forked process (see sr_module.h)
108  * @param desc - text description for the process table
109  * @param make_sock - if to create a unix socket pair for it
110  * @returns the pid of the new process
111  */
112 inline int fork_process(int child_id, char *desc, int make_sock)
113 {
114         int pid,old_process_no;
115 #ifdef USE_TCP
116         int sockfd[2];
117 #endif
118
119         lock_get(process_lock); 
120         if (*process_count>=estimated_proc_no) {
121                 LOG(L_CRIT, "ERROR: fork_process(): Process limit of %d exceeded."
122                                         " Will simulate fork fail.\n", estimated_proc_no);
123                 lock_release(process_lock);
124                 return -1;
125         }       
126         
127         #ifdef USE_TCP
128                 if(make_sock && !tcp_disable){
129                          if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
130                                 LOG(L_ERR, "ERROR: fork_process(): socketpair failed: %s\n",
131                                         strerror(errno));
132                                 return -1;
133                         }
134                 }
135         #endif
136         
137         old_process_no = process_no;
138         process_no = *process_count;
139         pid = fork();
140         if (pid<0) {
141                 lock_release(process_lock);
142                 return pid;
143         }
144         if (pid==0){
145                 /* child */
146                 /* wait for parent to get out of critical zone.
147                  * this is actually relevant as the parent updates
148                  * the pt & process_count. */
149                 lock_get(process_lock);
150                 #ifdef USE_TCP
151                         if (make_sock && !tcp_disable){
152                                 close(sockfd[0]);
153                                 unix_tcp_sock=sockfd[1];
154                         }
155                 #endif          
156                 lock_release(process_lock);     
157                 if ((child_id!=PROC_NOCHLDINIT) && (init_child(child_id) < 0)) {
158                         LOG(L_ERR, "ERROR: fork_process(): init_child failed for %s\n",
159                                                 pt[process_no].desc);
160                         return -1;
161                 }
162                 return pid;
163         } else {
164                 /* parent */
165                 process_no = old_process_no;
166                 /* add the process to the list in shm */
167                 pt[*process_count].pid=pid;
168                 if (desc){
169                         strncpy(pt[*process_count].desc, desc, MAX_PT_DESC);
170                 }
171                 #ifdef USE_TCP
172                         if (make_sock && !tcp_disable){
173                                 close(sockfd[1]);
174                                 pt[*process_count].unix_sock=sockfd[0];
175                                 pt[*process_count].idx=-1; /* this is not "tcp" process*/
176                         }
177                 #endif          
178                 *process_count = (*process_count) +1;
179                 lock_release(process_lock);
180                 return pid;
181         }
182 }
183
184 /**
185  * Forks a new TCP process.
186  * @param desc - text description for the process table
187  * @param r - index in the tcp_children array
188  * @param *reader_fd_1 - pointer to return the reader_fd[1]
189  * @returns the pid of the new process
190  */
191 inline int fork_tcp_process(int child_id,char *desc,int r,int *reader_fd_1)
192 {
193         int pid,old_process_no;
194         int sockfd[2];
195         int reader_fd[2]; /* for comm. with the tcp children read  */
196
197
198         
199         lock_get(process_lock);
200         /* set the local process_no */
201         if (*process_count>=estimated_proc_no) {
202                 LOG(L_CRIT, "ERROR: fork_tcp_process(): Process limit of %d exceeded."
203                                         " Simulating fork fail\n", estimated_proc_no);
204                 return -1;
205         }       
206         
207         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
208                 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
209                                         strerror(errno));
210                 return -1;
211         }
212         if (socketpair(AF_UNIX, SOCK_STREAM, 0, reader_fd)<0){
213                 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
214                                         strerror(errno));
215                 return -1;
216         }
217         if (tcp_fix_child_sockets(reader_fd)<0){
218                 LOG(L_ERR, "ERROR: fork_tcp_process(): failed to set non blocking"
219                                         "on child sockets\n");
220                 /* continue, it's not critical (it will go slower under
221                  * very high connection rates) */
222         }
223         
224         old_process_no = process_no;
225         process_no = *process_count;
226         pid = fork();
227         if (pid<0) {
228                 lock_release(process_lock);
229                 return pid;
230         }
231         if (pid==0){
232                 /* wait for parent to get out of critical zone */
233                 lock_get(process_lock);
234                         close(sockfd[0]);
235                         unix_tcp_sock=sockfd[1];
236                         if (reader_fd_1) *reader_fd_1=reader_fd[1];
237                 lock_release(process_lock);
238                 if (init_child(child_id) < 0) {
239                         LOG(L_ERR, "ERROR: fork_tcp_process(): init_child failed for "
240                                         "%s\n", pt[process_no].desc);
241                         return -1;
242                 }
243                 return pid;
244         } else {
245                 /* parent */            
246                 process_no = old_process_no;
247                 /* add the process to the list in shm */
248                 pt[*process_count].pid=pid;
249                 pt[*process_count].unix_sock=sockfd[0];
250                 pt[*process_count].idx=r;       
251                 if (desc){
252                         snprintf(pt[*process_count].desc, MAX_PT_DESC, "%s child=%d", 
253                                                 desc, r);
254                 }
255                 
256                 close(sockfd[1]);
257                 close(reader_fd[1]);
258                 
259                 tcp_children[r].pid=pid;
260                 tcp_children[r].proc_no=process_no;
261                 tcp_children[r].busy=0;
262                 tcp_children[r].n_reqs=0;
263                 tcp_children[r].unix_sock=reader_fd[0];
264                 
265                 *process_count = (*process_count) +1;
266                 lock_release(process_lock);
267                 return pid;
268         }
269 }
270
271
272