reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
ConfigParser.cxx
Go to the documentation of this file.
1#include "ConfigParser.hxx"
2
3#include "AppSubsystem.hxx"
4
5#include <iostream>
6#include <fstream>
7#include <iterator>
8
9#include <rutil/DnsUtil.hxx>
10#include <rutil/Log.hxx>
11#include <rutil/Logger.hxx>
13#include <resip/stack/Tuple.hxx>
14
15using namespace resip;
16using namespace std;
17
18#define RESIPROCATE_SUBSYSTEM AppSubsystem::MOHPARKSERVER
19
20namespace mohparkserver
21{
22
23ConfigParser::ConfigParser(int argc, char** argv) :
24 // Defaults
25 mUdpPort(0),
26 mTcpPort(0),
27 mTlsPort(0),
28 mTlsDomain(DnsUtil::getLocalHostName()),
29 mCertificatePath("./certs"),
30 mKeepAlives(true),
31 mMediaPortRangeStart(50000),
32 mMediaPortRangeSize(100),
33 mHttpPort(5082),
34 mLogLevel("INFO"),
35 mLogFilename("mohparkserver.log"),
36 mLogFileMaxBytes(5000000), // about 5Mb size
37 mSocketFunc(0)
38{
39 //mAddress = DnsUtil::getLocalIpAddress();
40
41 // Parse config file first
42 parseConfigFile("mohparkserver.config");
43
44 // Parse command line options
45 // Note: command line overrides config file setting
46 parseCommandLine(argc, argv);
47}
48
50 // Defaults
51 mUdpPort(0),
52 mTcpPort(0),
53 mTlsPort(0),
54 mTlsDomain(DnsUtil::getLocalHostName()),
55 mCertificatePath("./certs"),
56 mKeepAlives(true),
57 mMediaPortRangeStart(50000),
58 mMediaPortRangeSize(100),
59 mHttpPort(5082),
60 mLogLevel("INFO"),
61 mLogFilename("mohparkserver.log"),
62 mLogFileMaxBytes(5000000), // about 5Mb size
63 mSocketFunc(0)
64{
65}
66
70
71void
72ConfigParser::parseCommandLine(int argc, char** argv)
73{
74 // Loop through command line arguments and process them
75 for(int i = 1; i < argc; i++)
76 {
77 Data commandName(argv[i]);
78
79 // Process all commandNames that don't take values
80 if(isEqualNoCase(commandName, "-?") ||
81 isEqualNoCase(commandName, "--?") ||
82 isEqualNoCase(commandName, "--help") ||
83 isEqualNoCase(commandName, "/?"))
84 {
85 cout << "Command line options are:" << endl;
86 cout << " -a <IP Address> - bind SIP transports to this IP address" << endl;
87 cout << " -d <DNS servers> - comma seperated list of DNS servers, overrides OS detected list" << endl;
88 cout << " -up <port num> - local port number to use for UDP SIP messaging" << endl;
89 cout << " -tp <port num> - local port number to use for TCP SIP messaging" << endl;
90 cout << " -sp <port num> - local port number to use for TLS SIP messaging" << endl;
91 cout << " -td <domain name> - domain name to use for TLS server connections" << endl;
92 cout << " -cp <certificate path> - path to load TLS certificates from" << endl;
93 cout << " -nk - no keepalives, set this to disable sending of keepalives" << endl;
94 cout << " -op <SIP URI> - URI of a proxy server to use a SIP outbound proxy" << endl;
95 cout << " -l <NONE|ERR|WARNING|INFO|DEBUG|STACK> - logging level" << endl;
96 cout << endl;
97 cout << "Sample Command line:" << endl;
98 cout << "MOHParkServer -a 192.168.1.100 -l DEBUG" << endl;
99 exit(0);
100 }
101 else if(isEqualNoCase(commandName, "-nk"))
102 {
103 mKeepAlives = false;
104 }
105 else if(commandName.at(0) == '-')
106 {
107 commandName = commandName.substr(1); // Remove -
108
109 // Process commands that have values
110 Data commandValue(i+1 < argc ? argv[i+1] : Data::Empty);
111 if(commandValue.empty() || commandValue.at(0) == '-')
112 {
113 cerr << "Invalid command line parameters!" << endl;
114 exit(-1);
115 }
116 i++; // increment argument
117
118 //cout << "Command Line Name='" << commandName << "' value='" << commandValue << "'" << endl;
119 if(!processOption(commandName.lowercase(), commandValue))
120 {
121 cerr << "Invalid command line parameters!" << endl;
122 exit(-1);
123 }
124 }
125 else
126 {
127 cerr << "Invalid command line parameters!" << endl;
128 exit(-1);
129 }
130 }
131}
132
133void
134ConfigParser::parseConfigFile(const Data& filename)
135{
136 ifstream configFile(filename.c_str());
137
138 string sline;
139 while(getline(configFile, sline))
140 {
141 Data line(sline);
142 Data name;
143 Data value;
144 ParseBuffer pb(line);
145
146 pb.skipWhitespace();
147 const char * anchor = pb.position();
148 if(pb.eof() || *anchor == '#') continue; // if line is a comment or blank then skip it
149 // Look for =
150 pb.skipToOneOf("= \t");
151 if(!pb.eof())
152 {
153 pb.data(name,anchor);
154 if(*pb.position()!='=')
155 {
156 pb.skipToChar('=');
157 }
158 pb.skipChar('=');
159 pb.skipWhitespace();
160 anchor = pb.position();
161 if(!pb.eof())
162 {
163 pb.skipToEnd();
164 pb.data(value, anchor);
165 }
166 //cout << "Config file Name='" << name << "' value='" << value << "'" << endl;
167 processOption(name.lowercase(), value);
168 }
169 }
170}
171
172bool
173ConfigParser::processOption(const Data& name, const Data& value)
174{
175 bool result = true;
176 if(name.prefix("moh") && name.size() > 4)
177 {
178 unsigned int settingIndex = 0;
179 ParseBuffer pb(name);
180 pb.skipN(3); // skip past "moh"
181 const char* anchor = pb.position();
182 while (!pb.eof() && *pb.position() >= '0' && *pb.position() <= '9')
183 {
184 pb.skipN(1);
185 }
186 if (anchor != pb.position())
187 {
188 settingIndex = pb.data(anchor).convertUnsignedLong();
189 } // else - There were no numbers following "moh" - theses are legacy settings - use a 0 index
190
191 anchor = pb.position();
192 pb.skipToEnd();
193 Data subToken = pb.data(anchor);
194 if (subToken == "uri")
195 {
196 result = assignNameAddr(name, value, mMOHSettingsMap[settingIndex].mUri);
197 }
198 else if (subToken == "password")
199 {
200 mMOHSettingsMap[settingIndex].mPassword = value;
201 }
202 else if (subToken == "registrationtime")
203 {
204 mMOHSettingsMap[settingIndex].mRegistrationTime = value.convertUnsignedLong();
205 }
206 else if (subToken == "outboundproxy")
207 {
208 result = assignNameAddr(name, value, mMOHSettingsMap[settingIndex].mOutboundProxy);
209 }
210 else if (subToken == "filename")
211 {
212 result = assignMusicUrl(name, value, mMOHSettingsMap[settingIndex].mMOHFilenameUrl);
213 }
214 }
215 else if (name.prefix("park") && name.size() > 5)
216 {
217 unsigned int settingIndex = 0;
218 ParseBuffer pb(name);
219 pb.skipN(4); // skip past "park"
220 const char* anchor = pb.position();
221 while (!pb.eof() && *pb.position() >= '0' && *pb.position() <= '9')
222 {
223 pb.skipN(1);
224 }
225 if (anchor != pb.position())
226 {
227 settingIndex = pb.data(anchor).convertUnsignedLong();
228 } // else - There were no numbers following "moh" - theses are legacy settings - use a 0 index
229
230 anchor = pb.position();
231 pb.skipToEnd();
232 Data subToken = pb.data(anchor);
233 if (subToken == "uri")
234 {
235 result = assignNameAddr(name, value, mParkSettingsMap[settingIndex].mUri);
236 }
237 else if (subToken == "password")
238 {
239 mParkSettingsMap[settingIndex].mPassword = value;
240 }
241 else if (subToken == "registrationtime")
242 {
243 mParkSettingsMap[settingIndex].mRegistrationTime = value.convertUnsignedLong();
244 }
245 else if (subToken == "outboundproxy")
246 {
247 result = assignNameAddr(name, value, mParkSettingsMap[settingIndex].mOutboundProxy);
248 }
249 else if (subToken == "mohfilename")
250 {
251 result = assignMusicUrl(name, value, mParkSettingsMap[settingIndex].mMOHFilenameUrl);
252 }
253 else if (subToken == "orbitrangestart")
254 {
255 mParkSettingsMap[settingIndex].mOrbitRangeStart = value.convertUnsignedLong();
256 }
257 else if (subToken == "numorbits")
258 {
259 mParkSettingsMap[settingIndex].mNumOrbits = value.convertUnsignedLong();
260 }
261 else if (subToken == "orbitregistrationtime")
262 {
263 mParkSettingsMap[settingIndex].mOrbitRegistrationTime = value.convertUnsignedLong();
264 }
265 else if (subToken == "orbitpassword")
266 {
267 mParkSettingsMap[settingIndex].mOrbitPassword = value;
268 }
269 else if (subToken == "maxparktime")
270 {
271 mParkSettingsMap[settingIndex].mMaxParkTime = value.convertUnsignedLong();
272 }
273 }
274 else if(name == "maxparktime")
275 {
276 // This is a legacy setting and was renamed to be ParkXMaxTime in newer version. We still read old setting
277 // for back compat purposes.
278 mParkSettingsMap[0].mMaxParkTime = value.convertUnsignedLong();
279 }
280 else if(name == "a" || name == "ipaddress")
281 {
282 if(!value.empty())
283 {
284 mAddress = value;
285 }
286 }
287 else if(name == "d" || name == "dnsservers")
288 {
289 mDnsServers = value;
290 }
291 else if(name == "up" || name == "udpport")
292 {
293 mUdpPort = (unsigned short)value.convertInt();
294 }
295 else if(name == "tp" || name == "tcpport")
296 {
297 mTcpPort = (unsigned short)value.convertInt();
298 }
299 else if(name == "sp" || name == "tlsport")
300 {
301 mTlsPort = (unsigned short)value.convertInt();
302 }
303 else if(name == "td" || name == "tlsdomain")
304 {
305 mTlsDomain = value;
306 }
307 else if (name == "cp" || name == "certificatepath")
308 {
309 mCertificatePath = value;
310 }
311 else if(name == "keepalives")
312 {
313 if(value == "1" || value == "true" || value == "on" || value == "enable")
314 {
315 mKeepAlives = true;
316 }
317 else if(value == "0" || value == "false" || value == "off" || value == "disable")
318 {
319 mKeepAlives = false;
320 }
321 }
322 else if(name == "op" || name == "outboundproxy")
323 {
324 result = assignNameAddr("OutboundProxy", value, mOutboundProxy);
325 }
326 else if(name == "mediaportrangestart")
327 {
328 mMediaPortRangeStart = (unsigned short)value.convertUnsignedLong();
329 }
330 else if(name == "mediaportrangesize")
331 {
332 mMediaPortRangeSize = (unsigned short)value.convertUnsignedLong();
333 }
334 else if(name == "httpport")
335 {
336 mHttpPort = (unsigned short)value.convertUnsignedLong();
337 }
338 else if(name == "sipxlogfilename")
339 {
340 mSipXLogFilename = value;
341 }
342 else if(name == "l" || name == "loglevel")
343 {
344 mLogLevel = value;
345 }
346 else if(name == "logfilename")
347 {
348 mLogFilename = value;
349 }
350 else if(name == "logfilemaxbytes")
351 {
353 }
354 else
355 {
356 result = false;
357 }
358 return result;
359}
360
361bool
362ConfigParser::assignNameAddr(const Data& settingName, const Data& settingValue, NameAddr& nameAddr)
363{
364 if (!settingValue.empty() && settingValue.find("sip:") == Data::npos && settingValue.find("sips:") == Data::npos)
365 {
366 try
367 {
368 NameAddr tempNameAddr(Data("sip:" + settingValue));
369 nameAddr = tempNameAddr;
370 }
371 catch (resip::BaseException& e)
372 {
373 cerr << "Invalid " << settingName << " NameAddr format=" << settingValue << ": " << e << endl;
374 return false;
375 }
376 }
377 else if(!settingValue.empty())
378 {
379 try
380 {
381 NameAddr tempNameAddr(settingValue);
382 nameAddr = tempNameAddr;
383 }
384 catch (resip::BaseException& e)
385 {
386 cerr << "Invalid " << settingName << " NameAddr format=" << settingValue << ": " << e << endl;
387 return false;
388 }
389 }
390 return true;
391}
392
393bool ConfigParser::assignMusicUrl(const resip::Data& settingName, const resip::Data& settingValue, resip::Uri& url)
394{
395 Data urlData;
396 if (settingValue.find("http://") != Data::npos ||
397 settingValue.find("file:") != Data::npos)
398 {
399 // URL was specified - add repeat parameter
400 urlData = settingValue + ";repeat";
401 }
402 else
403 {
404 urlData = "file:" + settingValue + ";repeat";
405 }
406 try
407 {
408 Uri temp(urlData);
409 url = temp;
410 }
411 catch (BaseException& e)
412 {
413 cerr << "Invalid " << settingName << " Uri format=" << settingValue << ": " << e << endl;
414 cerr << "Using " << url << " instead." << endl;
415 url = Uri("file:music.wav;repeat");
416 }
417
418 return true;
419}
420
421}
422
423/* ====================================================================
424
425 Copyright (c) 2010-2016, SIP Spectrum, Inc.
426 All rights reserved.
427
428 Redistribution and use in source and binary forms, with or without
429 modification, are permitted provided that the following conditions are
430 met:
431
432 1. Redistributions of source code must retain the above copyright
433 notice, this list of conditions and the following disclaimer.
434
435 2. Redistributions in binary form must reproduce the above copyright
436 notice, this list of conditions and the following disclaimer in the
437 documentation and/or other materials provided with the distribution.
438
439 3. Neither the name of SIP Spectrum nor the names of its contributors
440 may be used to endorse or promote products derived from this
441 software without specific prior written permission.
442
443 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
444 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
445 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
446 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
447 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
448 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
449 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
450 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
451 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
452 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
453 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
454
455 ==================================================================== */
456
unsigned short mMediaPortRangeSize
unsigned short mMediaPortRangeStart
ParkSettingsMap mParkSettingsMap
The abstract base-class for all exceptions thrown by resip code.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
char & at(size_type p)
Returns the character at the specified position.
Definition Data.cxx:988
unsigned long convertUnsignedLong() const
Definition Data.cxx:1724
bool prefix(const Data &pre) const noexcept
Returns true if this Data starts with the bytes indicated by the passed-in Data.
Definition Data.cxx:1888
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
Data & lowercase()
Converts this Data to lowercase.
Definition Data.cxx:1635
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
size_type find(const Data &match, size_type start=0) const
Finds a specified sequence of bytes in this Data.
Definition Data.cxx:1947
static const size_type npos
Represents an impossible position; returned to indicate failure to find.
Definition Data.hxx:887
int convertInt() const
Takes the contents of the Data and converts them to an integer.
Definition Data.cxx:1684
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
Provides a collection of utility functions for manipulating DNS names and IP addresses and discoverin...
Definition DnsUtil.hxx:29
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
Definition NameAddr.hxx:19
Provides string-parsing functionality with protection from buffer overflow.
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
dcm! – add UnusedChecking(_enum) below;
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116