Revert "Revert "and added files""
[bcm963xx.git] / userapps / opensource / siproxd / src / readconf.c
1 /*
2     Copyright (C) 2002-2005  Thomas Ries <tries@gmx.net>
3
4     This file is part of Siproxd.
5     
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.
10     
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.
15     
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 
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
29
30 #include <osipparser2/osip_parser.h>
31
32 #include "siproxd.h"
33 #include "log.h"
34
35 static char const ident[]="$Id: readconf.c,v 1.30 2005/01/08 10:05:12 hb9xar Exp $";
36
37 /* configuration storage */
38 extern struct siproxd_config configuration;
39
40 /* prototypes used locally only */
41 static int parse_config (FILE *configfile);
42
43
44 /* try to open (whichever is found first):
45  *      <name>
46  *      $HOME/.<name>rc
47  *      /etc/<name>.conf
48  *      /usr/etc/<name>.conf
49  *      /usr/local/etc/<name>.conf
50  *
51  * RETURNS
52  *      STS_SUCCESS on success
53  *      STS_FAILURE on error
54  */
55 int read_config(char *name, int search) {
56    int sts;
57    FILE *configfile=NULL;
58    int i;
59    char tmp[256];
60    const char *completion[] = {
61         "%s/.%src",             /* this one is special... (idx=0)*/
62         SIPROXDCONFPATH "/%s.conf",
63         "/etc/%s.conf",
64         "/usr/etc/%s.conf",
65         "/usr/local/etc/%s.conf",
66         NULL };
67
68
69    DEBUGC(DBCLASS_CONFIG,"trying to read config file");
70
71    /* shall I search the config file myself ? */
72    if (search != 0) {
73       /* yup, try to find it */
74       for (i=0; completion[i]!=NULL; i++) {
75          switch (i) {
76          case 0:
77             sprintf(tmp,completion[i],getenv("HOME"),name);
78             break;
79          default:
80             sprintf(tmp,completion[i],name);
81             break;
82          }
83          DEBUGC(DBCLASS_CONFIG,"... trying %s",tmp);
84          configfile = fopen(tmp,"r");
85          if (configfile==NULL) continue;
86          break; /* got config file */
87       }
88    } else {
89          /* don't search it, just try the one given file */
90          DEBUGC(DBCLASS_CONFIG,"... trying %s",name);
91          configfile = fopen(name,"r");
92    }
93
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));
97       return STS_FAILURE;
98    }
99
100    sts = parse_config(configfile);
101    fclose(configfile);
102
103    /*
104     * Post-process configuration variables that have conditions that
105     * must be met; warn if we have to adjust any.
106     */
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);
112    }
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);
120    }
121
122    return sts;
123 }
124
125
126 /*
127  * parse configuration file
128  *
129  * RETURNS
130  *      STS_SUCCESS on success
131  *      STS_FAILURE on error
132  */
133 static int parse_config (FILE *configfile) {
134    char buff[1024];
135    char *ptr;
136    int i;
137    int k;
138    int num;
139    char *tmpptr;
140
141    struct cfgopts {
142       char *keyword;
143       enum type {TYP_INT4, TYP_STRING, TYP_FLOAT, TYP_STRINGA} type;
144       void *dest;
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 },
177       {0, 0, 0}
178    };
179
180
181    while (fgets(buff,sizeof(buff),configfile) != NULL) {
182       /* life insurance */
183       buff[sizeof(buff)-1]='\0';
184
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';
189          }
190       }
191
192       /* strip emtpy lines */
193       if (strlen(buff) == 0) continue;
194
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);
199          break;
200       }
201       if (i == strlen(buff)) continue;
202
203       DEBUGC(DBCLASS_CONFIG,"pc:\"%s\"",buff);
204
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);
211
212             /* check for argument separated by '=' */
213             if ((ptr=strchr(ptr,'=')) == NULL) {;
214                ERROR("argument missing to config parameter %s",
215                      configoptions[k].keyword);
216                break;
217             }
218             do {ptr++;} while (*ptr == ' '); /* skip spaces after '=' */
219             
220             DEBUGC(DBCLASS_CONFIG,"got argument:\"%s\"",ptr);
221
222             num=0;
223             if (strlen(ptr) <= 0) {
224                WARN("empty argument in config file, line:\"%s\"",buff);
225                break;
226             }
227
228             switch (configoptions[k].type) {
229
230             //
231             // Integer4
232             //
233             case TYP_INT4:
234                  num=sscanf(ptr,"%i",(int*)configoptions[k].dest);
235                  DEBUGC(DBCLASS_BABBLE,"INT4=%i",*(int*)configoptions[k].dest);
236               break;        
237
238             //
239             // String
240             //
241             case TYP_STRING:
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);
245                   */
246
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);
254               break;        
255
256             //
257             // String array
258             //
259             case TYP_STRINGA:
260             {
261                  /* figure out the amount of space we need */
262                  char **dst;
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))->
269                          string[used];
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++;
275                  } else {
276                     ERROR("no more space left in config string array %s",
277                           configoptions[k].keyword);
278                  }
279               break;
280             }
281
282             default:
283               break;
284             }
285             if (num == 0) {
286                ERROR("illegal format in config file, line:\"%s\"",buff);
287             }
288
289             break;
290          }
291       } // for configoptions
292
293       /*
294        * complain if we hit a unknown keyword
295        */
296        if (configoptions[k].keyword == NULL) {
297           ERROR("unknown keyword in config file, line:\"%s\"",buff);
298        }
299    } // while
300    return STS_SUCCESS;
301 }
302
303
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;
308
309    return STS_SUCCESS;
310 }