2 Copyright (C) 2002-2005 Thomas Ries <tries@gmx.net>
4 This file is part of Siproxd.
6 Siproxd is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 Siproxd is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Siproxd; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
28 #include <netinet/in.h>
30 #include <osipparser2/osip_parser.h>
35 static char const ident[]="$Id: readconf.c,v 1.30 2005/01/08 10:05:12 hb9xar Exp $";
37 /* configuration storage */
38 extern struct siproxd_config configuration;
40 /* prototypes used locally only */
41 static int parse_config (FILE *configfile);
44 /* try to open (whichever is found first):
48 * /usr/etc/<name>.conf
49 * /usr/local/etc/<name>.conf
52 * STS_SUCCESS on success
53 * STS_FAILURE on error
55 int read_config(char *name, int search) {
57 FILE *configfile=NULL;
60 const char *completion[] = {
61 "%s/.%src", /* this one is special... (idx=0)*/
62 SIPROXDCONFPATH "/%s.conf",
65 "/usr/local/etc/%s.conf",
69 DEBUGC(DBCLASS_CONFIG,"trying to read config file");
71 /* shall I search the config file myself ? */
73 /* yup, try to find it */
74 for (i=0; completion[i]!=NULL; i++) {
77 sprintf(tmp,completion[i],getenv("HOME"),name);
80 sprintf(tmp,completion[i],name);
83 DEBUGC(DBCLASS_CONFIG,"... trying %s",tmp);
84 configfile = fopen(tmp,"r");
85 if (configfile==NULL) continue;
86 break; /* got config file */
89 /* don't search it, just try the one given file */
90 DEBUGC(DBCLASS_CONFIG,"... trying %s",name);
91 configfile = fopen(name,"r");
94 /* config file not found or unable to open for read */
95 if (configfile==NULL) {
96 ERROR ("could not open config file: %s", strerror(errno));
100 sts = parse_config(configfile);
104 * Post-process configuration variables that have conditions that
105 * must be met; warn if we have to adjust any.
107 if (configuration.rtp_port_low & 0x01) {
108 /* rtp_port_low must be an even number... */
109 configuration.rtp_port_low = (configuration.rtp_port_low + 1) & ~0x01;
110 WARN("rtp_port_low should be an even number; it's been rounded up to %i",
111 configuration.rtp_port_low);
113 if (configuration.rtp_port_high & 0x01) {
114 /* rtp_high_port should be either the top RTP port allowed, */
115 /* or the top RTCP port allowed. If the latter, then reset */
116 /* to the former... Don't need a warning here. It's okay. */
117 configuration.rtp_port_high = configuration.rtp_port_high & ~0x01;
118 DEBUGC(DBCLASS_CONFIG, "rounded rtp_port_high down to %i",
119 configuration.rtp_port_high);
127 * parse configuration file
130 * STS_SUCCESS on success
131 * STS_FAILURE on error
133 static int parse_config (FILE *configfile) {
143 enum type {TYP_INT4, TYP_STRING, TYP_FLOAT, TYP_STRINGA} type;
145 } configoptions[] = {
146 { "debug_level", TYP_INT4, &configuration.debuglevel },
147 { "debug_port", TYP_INT4, &configuration.debugport },
148 { "sip_listen_port", TYP_INT4, &configuration.sip_listen_port },
149 { "daemonize", TYP_INT4, &configuration.daemonize },
150 { "silence_log", TYP_INT4, &configuration.silence_log },
151 { "if_inbound", TYP_STRING, &configuration.inbound_if },
152 { "if_outbound", TYP_STRING, &configuration.outbound_if },
153 { "rtp_port_low", TYP_INT4, &configuration.rtp_port_low },
154 { "rtp_port_high", TYP_INT4, &configuration.rtp_port_high },
155 { "rtp_timeout", TYP_INT4, &configuration.rtp_timeout },
156 { "rtp_proxy_enable", TYP_INT4, &configuration.rtp_proxy_enable },
157 { "user", TYP_STRING, &configuration.user },
158 { "chrootjail", TYP_STRING, &configuration.chrootjail },
159 { "hosts_allow_reg", TYP_STRING, &configuration.hosts_allow_reg },
160 { "hosts_allow_sip", TYP_STRING, &configuration.hosts_allow_sip },
161 { "hosts_deny_sip", TYP_STRING, &configuration.hosts_deny_sip },
162 { "hosts_deny_sip", TYP_STRING, &configuration.hosts_deny_sip },
163 { "proxy_auth_realm", TYP_STRING, &configuration.proxy_auth_realm },
164 { "proxy_auth_passwd", TYP_STRING, &configuration.proxy_auth_passwd },
165 { "proxy_auth_pwfile", TYP_STRING, &configuration.proxy_auth_pwfile },
166 { "mask_host", TYP_STRINGA,&configuration.mask_host },
167 { "masked_host", TYP_STRINGA,&configuration.masked_host },
168 { "outbound_proxy_host", TYP_STRING, &configuration.outbound_proxy_host },
169 { "outbound_proxy_port", TYP_INT4, &configuration.outbound_proxy_port },
170 { "outbound_domain_name",TYP_STRINGA,&configuration.outbound_proxy_domain_name },
171 { "outbound_domain_host",TYP_STRINGA,&configuration.outbound_proxy_domain_host },
172 { "outbound_domain_port",TYP_STRINGA,&configuration.outbound_proxy_domain_port },
173 { "registration_file", TYP_STRING ,&configuration.registrationfile },
174 { "log_calls", TYP_INT4, &configuration.log_calls },
175 { "pid_file", TYP_STRING ,&configuration.pid_file },
176 { "default_expires", TYP_INT4 ,&configuration.default_expires },
181 while (fgets(buff,sizeof(buff),configfile) != NULL) {
183 buff[sizeof(buff)-1]='\0';
185 /* strip New line & CR if present */
186 for (i=1; i<=2; i++) {
187 if ((buff[strlen(buff)-i]=='\n') || (buff[strlen(buff)-i]=='\r')) {
188 buff[strlen(buff)-i]='\0';
192 /* strip emtpy lines */
193 if (strlen(buff) == 0) continue;
195 /* strip comments and line with only whitespaces */
196 for (i=0;i<strlen(buff);i++) {
197 if ((buff[i] == ' ') || (buff[i] == '\t')) continue;
198 if (buff[i] =='#') i=strlen(buff);
201 if (i == strlen(buff)) continue;
203 DEBUGC(DBCLASS_CONFIG,"pc:\"%s\"",buff);
205 /* scan for known keyword */
206 for (k=0; configoptions[k].keyword != NULL; k++) {
207 if ((ptr=strstr(buff, configoptions[k].keyword)) != NULL) {
208 ptr += strlen(configoptions[k].keyword);
209 DEBUGC(DBCLASS_CONFIG,"got keyword:\"%s\"",
210 configoptions[k].keyword);
212 /* check for argument separated by '=' */
213 if ((ptr=strchr(ptr,'=')) == NULL) {;
214 ERROR("argument missing to config parameter %s",
215 configoptions[k].keyword);
218 do {ptr++;} while (*ptr == ' '); /* skip spaces after '=' */
220 DEBUGC(DBCLASS_CONFIG,"got argument:\"%s\"",ptr);
223 if (strlen(ptr) <= 0) {
224 WARN("empty argument in config file, line:\"%s\"",buff);
228 switch (configoptions[k].type) {
234 num=sscanf(ptr,"%i",(int*)configoptions[k].dest);
235 DEBUGC(DBCLASS_BABBLE,"INT4=%i",*(int*)configoptions[k].dest);
242 /* the %as within sscanf seems to be not too portable.
243 * it is supposed to allocate the memory
244 * num=sscanf(ptr,"%as",(char**)configoptions[k].dest);
247 /* figure out the amount of space we need */
248 num=strlen(ptr)+1; /* include terminating zero!*/
249 tmpptr=(char*)malloc(num);
250 memcpy(configoptions[k].dest, &tmpptr, sizeof(tmpptr));
251 num=sscanf(ptr,"%s",tmpptr);
252 DEBUGC(DBCLASS_BABBLE,"STRING=%s",
253 *(char**)configoptions[k].dest);
261 /* figure out the amount of space we need */
263 int used=((stringa_t*)(configoptions[k].dest))->used;
264 // do I hace space left?
265 if (used<=CFG_STRARR_SIZE){
266 num=strlen(ptr)+1; /* include terminating zero!*/
267 tmpptr=(char*)malloc(num);
268 dst=&((stringa_t*)(configoptions[k].dest))->
270 memcpy(dst, &tmpptr, sizeof(tmpptr));
271 num=sscanf(ptr,"%s",tmpptr);
272 DEBUGC(DBCLASS_BABBLE,"STRINGA[%i]=%s", used, (char*) (
273 ((stringa_t*)(configoptions[k].dest))->string[used]) );
274 ((stringa_t*)(configoptions[k].dest))->used++;
276 ERROR("no more space left in config string array %s",
277 configoptions[k].keyword);
286 ERROR("illegal format in config file, line:\"%s\"",buff);
291 } // for configoptions
294 * complain if we hit a unknown keyword
296 if (configoptions[k].keyword == NULL) {
297 ERROR("unknown keyword in config file, line:\"%s\"",buff);
304 int make_default_config(void){
305 memset (&configuration, 0, sizeof(configuration));
306 configuration.sip_listen_port=SIP_PORT;
307 configuration.default_expires=DEFAULT_EXPIRES;