all: updated FSF address in GPL text
[sip-router] / modules / ctl / ctl.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2006 iptelorg GmbH
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License 
24  * along with this program; if not, write to the Free Software 
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
26  */
27 /* History:
28  * --------
29  *  2006-02-08  created by andrei
30  *  2007-01-18  use PROC_RPC rank when forking (andrei)
31  */
32
33
34
35 #include "../../sr_module.h"
36 #include "../../ut.h"
37 #include "../../dprint.h"
38 #include "../../pt.h"
39 #include "../../cfg/cfg_struct.h"
40 #include "ctrl_socks.h"
41 #include "io_listener.h"
42
43 #include <sys/types.h>
44 #include <sys/socket.h> /* socketpair */
45 #include <unistd.h> /* close, fork, getpid */
46 #include <stdio.h> /* snprintf */
47 #include <string.h> /* strerror */
48 #include <errno.h>
49
50 MODULE_VERSION
51
52 #include "ctl_defaults.h"
53 #include "binrpc_run.h"
54 #ifdef USE_FIFO
55 #include "fifo_server.h"
56 #endif
57
58 static int mod_init(void);
59 static int mod_child(int rank);
60 static void mod_destroy(void);
61
62 static cmd_export_t cmds[]={
63                 {0,0,0,0,0}
64 };
65
66
67 static int usock_mode=0600; /* permissions, default rw-------*/
68 static int usock_uid=-1; /* username and group for the unix sockets*/
69 static int usock_gid=-1;
70
71 /* if set try to automatically convert values to the requested type in
72    rpc->scan (default: not set) */
73 extern int autoconvert; 
74 extern int binrpc_max_body_size;
75 extern int binrpc_struct_max_body_size;
76
77 static int add_binrpc_socket(modparam_t type, void * val);
78 #ifdef USE_FIFO
79 static int add_fifo_socket(modparam_t type, void * val);
80 #endif
81 static int fix_user(modparam_t type, void * val);
82 static int fix_group(modparam_t type, void * val);
83
84
85 static void  ctrl_listen_ls_rpc(rpc_t* rpc, void* ctx);
86 void io_listen_who_rpc(rpc_t* rpc, void* ctx);
87 void io_listen_conn_rpc(rpc_t* rpc, void* ctx);
88
89
90 static char* io_listen_who_doc[]={ "list open connections", 0 };
91 static char* io_listen_conn_doc[]={ "returns number of open connections", 0 };
92 static char* ctl_listen_ls_doc[]={ "list ctl listen sockets", 0 };
93
94 static rpc_export_t ctl_rpc[]={
95         {"ctl.who",         io_listen_who_rpc, (const char**)io_listen_who_doc, 0},
96         {"ctl.connections", io_listen_conn_rpc,(const char**)io_listen_conn_doc,0},
97         {"ctl.listen",      ctrl_listen_ls_rpc,(const char**)ctl_listen_ls_doc, 0},
98         { 0, 0, 0, 0}
99 };
100
101 static param_export_t params[]={
102 #ifdef USE_FIFO
103         {"fifo",                PARAM_STRING|PARAM_USE_FUNC,    (void*) add_fifo_socket  },
104 #endif
105         {"binrpc",              PARAM_STRING|PARAM_USE_FUNC,    (void*) add_binrpc_socket},
106         {"mode",                PARAM_INT,                                              &usock_mode                              },
107         {"user",                PARAM_STRING|PARAM_USE_FUNC,    fix_user                                 },
108         {"group",               PARAM_STRING|PARAM_USE_FUNC,    fix_group                                },
109         {"autoconversion",      PARAM_INT,                                      &autoconvert                     },
110         {"binrpc_max_body_size",        PARAM_INT, &binrpc_max_body_size         },
111         {"binrpc_struct_max_body_size", PARAM_INT, &binrpc_struct_max_body_size  },
112         {0,0,0} 
113 }; /* no params */
114
115 struct module_exports exports= {
116         "ctl",
117         cmds,
118         ctl_rpc,        /* RPC methods */
119         params,
120         mod_init, /* module initialization function */
121         0, /* response function */
122         mod_destroy,  /* destroy function */
123         0, /* on_cancel function */
124         mod_child, /* per-child init function */
125 };
126
127
128 static struct id_list* listen_lst=0; /* binrpc sockets name list */
129 static struct ctrl_socket* ctrl_sock_lst=0;
130 static int fd_no=0; /* number of fd used */
131
132
133 static int add_binrpc_socket(modparam_t type, void * val)
134 {
135         char *s;
136         struct id_list* id;
137         
138         if ((type & PARAM_STRING)==0){
139                 LOG(L_CRIT, "BUG: ctl: add_binrpc_socket: bad parameter type %d\n",
140                                         type);
141                 goto error;
142         }
143         s=(char*)val;
144         id=parse_listen_id(s, strlen(s), UDP_SOCK); /* default udp proto */
145         if (id==0){
146                 LOG(L_ERR, "ERROR: ctl: bad listen socket: \"%s\"\n", s);
147                 goto error;
148         }
149         id->data_proto=P_BINRPC;
150         id->next=listen_lst;
151         listen_lst=id;
152         return 0;
153 error:
154         return -1;
155 }
156
157
158
159 #ifdef USE_FIFO
160 static int add_fifo_socket(modparam_t type, void * val)
161 {
162         char *s;
163         struct id_list* id;
164         
165         if ((type & PARAM_STRING)==0){
166                 LOG(L_CRIT, "BUG: ctl: add_fifo: bad parameter type %d\n",
167                                         type);
168                 goto error;
169         }
170         s=(char*)val;
171         id=parse_listen_id(s, strlen(s), FIFO_SOCK); /* default udp proto */
172         if (id==0){
173                 LOG(L_ERR, "ERROR: ctl: bad fifo: \"%s\"\n", s);
174                 goto error;
175         }
176         id->data_proto=P_FIFO;
177         id->next=listen_lst;
178         listen_lst=id;
179         return 0;
180 error:
181         return -1;
182 }
183 #endif
184
185
186
187 static int fix_user(modparam_t type, void * val)
188 {
189         char* s;
190         
191         if ((type & PARAM_STRING)==0){
192                 LOG(L_CRIT, "BUG: ctl: fix_user: bad parameter type %d\n",
193                                         type);
194                 goto error;
195         }
196         s=(char*)val;
197         if (user2uid(&usock_uid, 0, s)<0){
198                 LOG(L_ERR, "ERROR: ctl: bad user name/uid number %s\n", s);
199                 goto error;
200         }
201         return 0;
202 error:
203         return -1;
204 }
205
206
207
208 static int fix_group(modparam_t type, void * val)
209 {
210         char* s;
211         
212         if ((type & PARAM_STRING)==0){
213                 LOG(L_CRIT, "BUG: ctl: fix_group: bad parameter type %d\n",
214                                         type);
215                 goto error;
216         }
217         s=(char*)val;
218         if (group2gid(&usock_gid, s)<0){
219                 LOG(L_ERR, "ERROR: ctl: bad group name/gid number %s\n", s);
220                 goto error;
221         }
222         return 0;
223 error:
224         return -1;
225 }
226
227
228
229 static int mod_init(void)
230 {
231         struct id_list* l;
232
233         binrpc_callbacks_init();
234
235         if(binrpc_max_body_size<=0)
236                 binrpc_max_body_size = 4;
237         if(binrpc_struct_max_body_size<=0)
238                 binrpc_struct_max_body_size = 1;
239         binrpc_max_body_size *= 1024;
240         binrpc_struct_max_body_size *= 1024;
241
242         if (listen_lst==0) {
243                 add_binrpc_socket(PARAM_STRING, DEFAULT_CTL_SOCKET);
244         }
245         DBG("listening on:\n");
246         for (l=listen_lst; l; l=l->next){
247                 fd_no++;
248                 switch(l->proto){
249                         case UNIXD_SOCK:
250                                 DBG("        [%s:unix dgram]  %s\n",
251                                                 payload_proto_name(l->data_proto), l->name);
252                                 break;
253                         case UNIXS_SOCK:
254                                 DBG("        [%s:unix stream] %s\n",
255                                                 payload_proto_name(l->data_proto), l->name);
256                                 break;
257                         case UDP_SOCK:
258                                 DBG("        [%s:udp]         %s:%d\n", 
259                                                 payload_proto_name(l->data_proto), l->name,
260                                                 l->port?l->port:DEFAULT_CTL_PORT);
261                                 break;
262                         case TCP_SOCK:
263                                 DBG("        [%s:tcp]         %s:%d\n",
264                                                 payload_proto_name(l->data_proto), l->name,
265                                                 l->port?l->port:DEFAULT_CTL_PORT);
266                                 break;
267 #ifdef USE_FIFO
268                         case FIFO_SOCK:
269                                 DBG("        [%s:fifo]         %s\n",
270                                                 payload_proto_name(l->data_proto), l->name);
271                                 fd_no++; /* fifos use 2 fds */
272                                 break;
273 #endif
274                         default:
275                                 LOG(L_CRIT, "BUG: ctrl: listen protocol %d not supported\n",
276                                                 l->proto);
277                                 goto error;
278                         }
279         }
280         /* open socket now, before suid */
281         if (init_ctrl_sockets(&ctrl_sock_lst, listen_lst, DEFAULT_CTL_PORT,
282                         usock_mode, usock_uid, usock_gid)<0){
283                 LOG(L_ERR, "ERROR: ctl: mod_init: init ctrl. sockets failed\n");
284                 goto error;
285         }
286         if (ctrl_sock_lst){
287                 /* we will fork */
288                 register_procs(1); /* we will be creating an extra process */
289                 register_fds(fd_no);
290                 /* The child process will keep updating its local configuration */
291                 cfg_register_child(1);
292         }
293 #ifdef USE_FIFO
294         fifo_rpc_init();
295 #endif
296         return 0;
297 error:
298         return -1;
299 }
300
301
302
303 static int mod_child(int rank)
304 {
305         int pid;
306         struct ctrl_socket* cs;
307         static int rpc_handler=0;
308         
309         /* do nothing from PROC_INIT, is the same as PROC_MAIN */
310         if (rank==PROC_INIT)
311                 return 0;
312         /* we want to fork(), but only from one process */
313         if ((rank == PROC_MAIN ) && (ctrl_sock_lst)){ /* FIXME: no fork ?? */
314                 DBG("ctl: mod_child(%d), ctrl_sock_lst=%p\n", rank, ctrl_sock_lst);
315                 /* fork, but make sure we know not to close our own sockets when
316                  * ctl child_init will be called for the new child */
317                 rpc_handler=1;
318                 /* child should start with a correct estimated used fds number*/
319                 register_fds(MAX_IO_READ_CONNECTIONS);
320                 pid=fork_process(PROC_RPC, "ctl handler", 1);
321                 DBG("ctl: mod_child(%d), fork_process=%d, csl=%p\n",
322                                 rank, pid, ctrl_sock_lst);
323                 if (pid<0){                     
324                         goto error;
325                 }
326                 if (pid == 0){ /* child */
327                         is_main=0;
328                         DBG("ctl: %d io_listen_loop(%d, %p)\n",
329                                         rank, fd_no, ctrl_sock_lst);
330                         io_listen_loop(fd_no, ctrl_sock_lst);
331                 }else{ /* parent */
332                         /* not used in parent */
333                         register_fds(-MAX_IO_READ_CONNECTIONS);
334                         rpc_handler=0;
335                 }
336         }
337         if (rank!=PROC_RPC || !rpc_handler){
338                 /* close all the opened fds, we don't need them here */
339                 for (cs=ctrl_sock_lst; cs; cs=cs->next){
340                         close(cs->fd);
341                         cs->fd=-1;
342                         if (cs->write_fd!=-1){
343                                 close(cs->write_fd);
344                                 cs->write_fd=-1;
345                         }
346                 }
347                 if (rank!=PROC_MAIN){ /* we need the lists in main for on_exit cleanup,
348                                                                  see mod_destroy */
349                         /* free memory, we don't need the lists anymore */
350                         free_ctrl_socket_list(ctrl_sock_lst);
351                         ctrl_sock_lst=0;
352                         free_id_list(listen_lst);
353                         listen_lst=0;
354                 }
355         }
356         return 0;
357 error:
358         return -1;
359 }
360
361
362
363 static void mod_destroy(void)
364 {
365         struct ctrl_socket* cs;
366         
367         /* close all the opened fds & unlink the files */
368         for (cs=ctrl_sock_lst; cs; cs=cs->next){
369                 switch(cs->transport){
370                         case UNIXS_SOCK:
371                         case UNIXD_SOCK:
372                                 close(cs->fd);
373                                 cs->fd=-1;
374                                 if (cs->write_fd!=-1){
375                                         close(cs->write_fd);
376                                         cs->write_fd=-1;
377                                 }
378                                 if (cs->name){
379                                         if (unlink(cs->name)<0){
380                                                 LOG(L_ERR, "ERROR: ctl: could not delete unix"
381                                                                         " socket %s: %s (%d)\n",
382                                                                         cs->name, strerror(errno), errno);
383                                         }
384                                 }
385                                 break;
386 #ifdef USE_FIFO
387                         case FIFO_SOCK:
388                                 destroy_fifo(cs->fd, cs->write_fd, cs->name);
389                                 break;
390 #endif
391                         default:
392                                 close(cs->fd);
393                                 cs->fd=-1;
394                                 if (cs->write_fd!=-1){
395                                         close(cs->write_fd);
396                                         cs->write_fd=-1;
397                                 }
398                 }
399         }
400         if (listen_lst){
401                 free_id_list(listen_lst);
402                 listen_lst=0;
403         }
404         if (ctrl_sock_lst){
405                 free_ctrl_socket_list(ctrl_sock_lst);
406                 ctrl_sock_lst=0;
407         }
408 }
409
410
411 static void  ctrl_listen_ls_rpc(rpc_t* rpc, void* ctx)
412 {
413         struct ctrl_socket* cs;
414         
415         for (cs=ctrl_sock_lst; cs; cs=cs->next){
416                 rpc->add(ctx, "ssss", payload_proto_name(cs->p_proto),
417                                                 socket_proto_name(cs->transport),
418                                                 cs->name, (cs->port)?int2str(cs->port, 0):"");
419         }
420 }