1 /*
2 * Copyright (C) 2002-2003 Fhg Fokus
3 *
4 * This file is part of SEMS, a free SIP media server.
5 *
6 * SEMS 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. This program is released under
10 * the GPL with the additional exemption that compiling, linking,
11 * and/or using OpenSSL is allowed.
12 *
13 * For a license to use the SEMS 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 * SEMS 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28 /** @file AmUtils.cpp */
29
30 #include "AmUtils.h"
31 #include "AmThread.h"
32 #include "AmConfig.h"
33 #include "log.h"
34 #include "AmSipMsg.h"
35 #include "sip/resolver.h"
36 #include "sip/ip_util.h"
37
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <netdb.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <assert.h>
47
48 #include <sys/socket.h>
49 #include <sys/un.h>
50
51 #include <regex.h>
52 #include <algorithm>
53
54 #include <fstream>
55
56
57 static char _int2str_lookup[] = { '0', '1', '2', '3', '4', '5', '6' , '7', '8', '9' };
58
59
int2str(unsigned int val)60 string int2str(unsigned int val)
61 {
62 char buffer[64] = {0};
63 int i=62;
64 lldiv_t d;
65
66 d.quot = val;
67 do{
68 d = lldiv(d.quot,10);
69 buffer[i] = _int2str_lookup[d.rem];
70 }while(--i && d.quot);
71
72 return string((char*)(buffer+i+1));
73 }
74
75 template<class T, class DT>
signed2str(T val,T (* abs_func)(T),DT (* div_func)(T,T))76 string signed2str(T val, T (*abs_func) (T), DT (*div_func) (T, T))
77 {
78 char buffer[64] = {0,0};
79 int i=62;
80 DT d;
81
82 d.quot = abs_func(val);
83 do{
84 d = div_func(d.quot,10);
85 buffer[i] = _int2str_lookup[d.rem];
86 }while(--i && d.quot);
87
88 if (i && (val<0)) {
89 buffer[i]='-';
90 i--;
91 }
92
93 return string((char*)(buffer+i+1));
94 }
95
int2str(int val)96 string int2str(int val) { return signed2str<int, div_t>(val, abs, div); }
long2str(long int val)97 string long2str(long int val) { return signed2str<long, ldiv_t>(val, labs, ldiv); }
longlong2str(long long int val)98 string longlong2str(long long int val) { return signed2str<long long, lldiv_t>(val, llabs, lldiv); }
99
100 static char _int2hex_lookup[] = { '0', '1', '2', '3', '4', '5', '6' , '7', '8', '9','A','B','C','D','E','F' };
101 static char _int2hex_lookup_l[] = { '0', '1', '2', '3', '4', '5', '6' , '7', '8', '9','a','b','c','d','e','f' };
102
char2hex(unsigned char val,bool lowercase)103 string char2hex(unsigned char val, bool lowercase)
104 {
105 string res;
106 if (lowercase) {
107 res += _int2hex_lookup_l[val >> 4];
108 res += _int2hex_lookup_l[val & 0x0f];
109 } else {
110 res += _int2hex_lookup[val >> 4];
111 res += _int2hex_lookup[val & 0x0f];
112 }
113 return res;
114 }
115
int2hex(unsigned int val,bool lowercase)116 string int2hex(unsigned int val, bool lowercase)
117 {
118 unsigned int digit=0;
119
120 char buffer[2*sizeof(int)+1] = {0};
121 int i,j=0;
122
123 for(i=0; i<int(2*sizeof(int)); i++){
124 digit = val >> 4*(2*sizeof(int)-1);
125 val = val << 4;
126 buffer[j++] = lowercase ?
127 _int2hex_lookup_l[(unsigned char)digit] : _int2hex_lookup[(unsigned char)digit];
128 }
129
130 return string((char*)buffer);
131 }
132
long2hex(unsigned long val)133 string long2hex(unsigned long val)
134 {
135 unsigned int digit=0;
136
137 char buffer[2*sizeof(long)+1] = {0};
138 int i,j=0;
139
140 for(i=0; i<int(2*sizeof(long)); i++){
141 digit = val >> 4*(2*sizeof(long)-1);
142 val = val << 4;
143 buffer[j++] = _int2hex_lookup[(unsigned char)digit];
144 }
145
146 return string((char*)buffer);
147 }
148
149 /** Convert a double to a string. (from jsoncpp) */
double2str(double val)150 string double2str(double val) {
151 char buffer[32];
152 sprintf(buffer, "%#.16g", val);
153 char* ch = buffer + strlen(buffer) - 1;
154 if (*ch != '0') return buffer; // nothing to truncate, so save time
155 while(ch > buffer && *ch == '0'){
156 --ch;
157 }
158 char* last_nonzero = ch;
159 while(ch >= buffer){
160 switch(*ch){
161 case '0':
162 case '1':
163 case '2':
164 case '3':
165 case '4':
166 case '5':
167 case '6':
168 case '7':
169 case '8':
170 case '9':
171 --ch;
172 continue;
173 case '.':
174 // Truncate zeroes to save bytes in output, but keep one.
175 *(last_nonzero+2) = '\0';
176 return string(buffer);
177 default:
178 return string(buffer);
179 }
180 }
181 return string(buffer);
182 }
183
184 /**
185 * Convert a reversed hex string to uint.
186 * @param str [in] string to convert.
187 * @param result [out] result integer.
188 * @return true if failed.
189 */
reverse_hex2int(const string & str,unsigned int & result)190 bool reverse_hex2int(const string& str, unsigned int& result)
191 {
192 result=0;
193 char mychar;
194
195 for (string::const_reverse_iterator pc = str.rbegin();
196 pc != str.rend(); ++pc) {
197
198 result <<= 4;
199 mychar=*pc;
200
201 if ( mychar >='0' && mychar <='9')
202 result += mychar -'0';
203 else if (mychar >='a' && mychar <='f')
204 result += mychar -'a'+10;
205 else if (mychar >='A' && mychar <='F')
206 result += mychar -'A'+10;
207 else
208 return true;
209 }
210
211 return false;
212 }
213
str2i(const string & str,unsigned int & result)214 bool str2i(const string& str, unsigned int& result)
215 {
216 char* s = (char*)str.c_str();
217 return str2i(s,result);
218 }
219
str2i(char * & str,unsigned int & result,char sep)220 bool str2i(char*& str, unsigned int& result, char sep)
221 {
222 unsigned int ret=0;
223 int i=0;
224 char* init = str;
225
226 for(; (*str != '\0') && (*str == ' '); str++);
227
228 for(; *str != '\0';str++){
229 if ( (*str <= '9' ) && (*str >= '0') ){
230 ret=ret*10+*str-'0';
231 i++;
232 if (i>10) goto error_digits;
233 } else {
234
235 bool eol = false;
236 switch(*str){
237 case 0xd:
238 case 0xa:
239 case 0x0:
240 eol = true;
241 }
242
243 if( (*str != sep) && !eol )
244 goto error_char;
245
246 break;
247 }
248 }
249
250 result = ret;
251 return false;
252
253 error_digits:
254 DBG("str2i: too many letters in [%s]\n", init);
255 return true;
256 error_char:
257 DBG("str2i: unexpected char 0x%x in %s\n", *str, init);
258 return true;
259 }
260
str2int(const string & str,int & result)261 bool str2int(const string& str, int& result)
262 {
263 char* s = (char*)str.c_str();
264 return str2int(s,result);
265 }
266
str2int(char * & str,int & result,char sep)267 bool str2int(char*& str, int& result, char sep)
268 {
269 int ret=0;
270 int i=0;
271 char* init = str;
272 int sign = 1;
273
274 for(; (*str != '\0') && (*str == ' '); str++);
275
276 if (*str == '-') {
277 sign = -1;
278 str++;
279 for(; (*str != '\0') && (*str == ' '); str++);
280 }
281
282 for(; *str != '\0';str++){
283 if ( (*str <= '9' ) && (*str >= '0') ){
284 ret=ret*10+*str-'0';
285 i++;
286 if (i>10) goto error_digits;
287 } else {
288
289 bool eol = false;
290 switch(*str){
291 case 0xd:
292 case 0xa:
293 case 0x0:
294 eol = true;
295 }
296
297 if( (*str != sep) && !eol )
298 goto error_char;
299
300 break;
301 }
302 }
303
304 result = ret * sign;
305 return true;
306
307 error_digits:
308 DBG("str2int: too many digits in [%s]\n", init);
309 return false;
310 error_char:
311 DBG("str2i: unexpected char 0x%x in %s\n", *str, init);
312 return false;
313 }
314
315 // long int could probably be the same size as int
str2long(const string & str,long & result)316 bool str2long(const string& str, long& result)
317 {
318 char* s = (char*)str.c_str();
319 return str2long(s,result);
320 }
321
str2long(char * & str,long & result,char sep)322 bool str2long(char*& str, long& result, char sep)
323 {
324 long ret=0;
325 int i=0;
326 char* init = str;
327 long sign = 1;
328
329 for(; (*str != '\0') && (*str == ' '); str++);
330
331 if (*str == '-') {
332 sign = -1;
333 str++;
334 for(; (*str != '\0') && (*str == ' '); str++);
335 }
336
337 for(; *str != '\0';str++){
338 if ( (*str <= '9' ) && (*str >= '0') ){
339 ret=ret*10+*str-'0';
340 i++;
341 if (i>20) goto error_digits;
342 } else {
343
344 bool eol = false;
345 switch(*str){
346 case 0xd:
347 case 0xa:
348 case 0x0:
349 eol = true;
350 }
351
352 if( (*str != sep) && !eol )
353 goto error_char;
354
355 break;
356 }
357 }
358
359 result = ret * sign;
360 return true;
361
362 error_digits:
363 DBG("str2long: too many digits in [%s]\n", init);
364 return false;
365 error_char:
366 DBG("str2long: unexpected char 0x%x in %s\n", *str, init);
367 return false;
368 }
369
str2bool(const string & s,bool & dst)370 bool str2bool(const string &s, bool &dst)
371 {
372 // TODO: optimize
373 if ((s == "yes") || (s == "true") || (s == "1")) {
374 dst = true;
375 return true;
376 }
377 if ((s == "no") || (s == "false") || (s == "0")) {
378 dst = false;
379 return true;
380 }
381 return false;
382 }
383
URL_decode(const std::string & s)384 std::string URL_decode(const std::string& s) {
385 enum {
386 uSNormal= 0, // start
387 uSH1,
388 uSH2
389 };
390
391 int st = uSNormal;
392 string res;
393 for (size_t pos = 0; pos < s.length(); pos++) {
394 switch (st) {
395 case uSNormal: {
396 if (s[pos] == '%')
397 st = uSH1;
398 else
399 res+=s[pos];
400
401 }; break;
402
403 case uSH1: {
404 if (s[pos] == '%') {
405 res+='%';
406 st = uSNormal;
407 } else {
408 st = uSH2;
409 }
410 }; break;
411
412 case uSH2: {
413 char c = 0;
414
415 if ( s[pos] >='0' && s[pos] <='9')
416 c += s[pos] -'0';
417 else if (s[pos] >='a' && s[pos] <='f')
418 c += s[pos] -'a'+10;
419 else if (s[pos] >='A' && s[pos] <='F')
420 c += s[pos] -'A'+10;
421 else {
422 st = uSNormal;
423 DBG("error in escaped string: %%%c%c\n", s[pos-1], s[pos]);
424 continue;
425 }
426
427 if ( s[pos-1] >='0' && s[pos-1] <='9')
428 c += (s[pos-1] -'0') << 4;
429 else if (s[pos-1] >='a' && s[pos-1] <='f')
430 c += (s[pos-1] -'a'+10) << 4;
431 else if (s[pos-1] >='A' && s[pos-1] <='F')
432 c += (s[pos-1] -'A'+10 ) << 4;
433 else {
434 st = uSNormal;
435 DBG("error in escaped string: %%%c%c\n", s[pos-1], s[pos]);
436 continue;
437 }
438 res +=c;
439 st = uSNormal;
440 } break;
441 }
442 }
443
444 return res;
445 }
446
URL_encode(const std::string & s)447 std::string URL_encode(const std::string &s)
448 {
449 const std::string unreserved = "-_.~";
450
451 std::string escaped="";
452 for(size_t i=0; i<s.length(); i++)
453 {
454
455 //RFC 3986 section 2.3 Unreserved Characters (January 2005)
456 if ((s[i] >= 'A' && s[i] <= 'Z')
457 || (s[i] >= 'a' && s[i] <= 'z')
458 || (s[i] >= '0' && s[i] <= '9')
459 || (s[i] == '-') || (s[i] == '_') || (s[i] == '.') || (s[i] == '~') )
460 {
461 escaped.push_back(s[i]);
462 }
463 else
464 {
465 escaped.append("%");
466 char buf[3];
467 sprintf(buf, "%.2X", s[i]);
468 escaped.append(buf);
469 }
470 }
471 return escaped;
472 }
473
parse_return_code(const char * lbuf,unsigned int & res_code,string & res_msg)474 int parse_return_code(const char* lbuf, unsigned int& res_code, string& res_msg )
475 {
476 char res_code_str[4] = {'\0'};
477 const char* cur=lbuf;
478
479 // parse xxx code
480 for( int i=0; i<3; i++ ){
481 if( (*cur >= '0') && (*cur <= '9') )
482 res_code_str[i] = *cur;
483 else
484 goto error;
485 cur++;
486 }
487
488 if( (*cur != ' ') && (*cur != '\t') && (*cur !='-') ){
489 ERROR("expected 0x%x or 0x%x or 0x%x, found 0x%x\n",' ','\t','-',*cur);
490 goto error;
491 }
492
493 if(sscanf(res_code_str,"%u",&res_code) != 1){
494 ERROR("wrong code (%s)\n",res_code_str);
495 goto error;
496 }
497
498 // wrap spaces and tabs
499 while( (*cur == ' ') || (*cur == '\t') || (*cur =='-'))
500 cur++;
501
502 res_msg = cur;
503 return 0;
504
505 error:
506 ERROR("while parsing response\n");
507 return -1;
508 }
509
file_exists(const string & name)510 bool file_exists(const string& name)
511 {
512 FILE* test_fp = fopen(name.c_str(),"r");
513 if(test_fp){
514 fclose(test_fp);
515 return true;
516 }
517 return false;
518 }
519
filename_from_fullpath(const string & path)520 string filename_from_fullpath(const string& path)
521 {
522 string::size_type pos = path.rfind('/');
523 if(pos != string::npos)
524 return path.substr(pos+1);
525 return "";
526 }
527
get_addr_str(const sockaddr_storage * addr)528 string get_addr_str(const sockaddr_storage* addr)
529 {
530 char host[NI_MAXHOST] = "";
531 return am_inet_ntop(addr,host,NI_MAXHOST);
532 }
533
get_addr_str_sip(const sockaddr_storage * addr)534 string get_addr_str_sip(const sockaddr_storage* addr)
535 {
536 char host[NI_MAXHOST] = "";
537 return am_inet_ntop_sip(addr,host,NI_MAXHOST);
538 }
539
file_extension(const string & path)540 string file_extension(const string& path)
541 {
542 string::size_type pos = path.rfind('.');
543 if(pos == string::npos){
544 pos = path.rfind("%2E");
545
546 if(pos == string::npos)
547 return "";
548 return path.substr(pos+3,string::npos);
549 }
550
551 return path.substr(pos+1,string::npos);
552 }
553
add2path(const string & path,int n_suffix,...)554 string add2path( const string& path, int n_suffix, ...)
555 {
556 va_list ap;
557 string outpath = path;
558
559 va_start(ap,n_suffix);
560
561 for(int i=0; i<n_suffix; i++){
562
563 const char* s = va_arg(ap,const char*);
564
565 if(!outpath.empty() && (outpath[outpath.length()-1] != '/'))
566 outpath += '/';
567
568 outpath += s;
569 }
570
571 va_end(ap);
572
573 return outpath;
574 }
575
get_local_addr_for_dest(sockaddr_storage * remote_ip,sockaddr_storage * local)576 int get_local_addr_for_dest(sockaddr_storage* remote_ip, sockaddr_storage* local)
577 {
578 int temp_sock = socket(remote_ip->ss_family, SOCK_DGRAM, 0 );
579 if (temp_sock == -1) {
580 ERROR("socket() failed: %s\n",
581 strerror(errno));
582 return -1;
583 }
584
585 socklen_t len=sizeof(sockaddr_storage);
586 if (connect(temp_sock, (sockaddr*)remote_ip,
587 remote_ip->ss_family == AF_INET ?
588 sizeof(sockaddr_in) : sizeof(sockaddr_in6))==-1) {
589
590 ERROR("connect failed: %s\n",
591 strerror(errno));
592 goto error;
593 }
594
595 if (getsockname(temp_sock, (sockaddr*)local, &len)==-1) {
596 ERROR("getsockname failed: %s\n",
597 strerror(errno));
598 goto error;
599 }
600
601 close(temp_sock);
602 return 0;
603
604 error:
605 close(temp_sock);
606 return -1;
607 }
608
get_local_addr_for_dest(const string & remote_ip,string & local)609 int get_local_addr_for_dest(const string& remote_ip, string& local)
610 {
611 sockaddr_storage remote_ip_ss;
612 sockaddr_storage local_ss;
613
614 int err = inet_pton(AF_INET,remote_ip.c_str(),&((sockaddr_in*)&remote_ip_ss)->sin_addr);
615 if(err == 1){
616 remote_ip_ss.ss_family = AF_INET;
617 }
618 else if(err == 0){
619 err = inet_pton(AF_INET6,remote_ip.c_str(),&((sockaddr_in6*)&remote_ip_ss)->sin6_addr);
620 if(err == 1){
621 remote_ip_ss.ss_family = AF_INET6;
622 }
623 }
624
625 if(err == 0){
626 // not an IP... try a name.
627 dns_handle dh;
628 err = resolver::instance()->resolve_name(remote_ip.c_str(),&dh,&remote_ip_ss,IPv4);
629 }
630
631 if(err == -1){
632 ERROR("While converting address: '%s'",remote_ip.c_str());
633 return -1;
634 }
635
636 if(remote_ip_ss.ss_family==AF_INET){
637 #if defined(BSD44SOCKETS)
638 ((sockaddr_in*)&remote_ip_ss)->sin_len = sizeof(sockaddr_in);
639 #endif
640 ((sockaddr_in*)&remote_ip_ss)->sin_port = htons(5060); // fake port number
641 }
642 else {
643 #if defined(BSD44SOCKETS)
644 ((sockaddr_in6*)&remote_ip_ss)->sin6_len = sizeof(sockaddr_in6);
645 #endif
646 ((sockaddr_in6*)&remote_ip_ss)->sin6_port = htons(5060); // fake port number
647 }
648
649 err = get_local_addr_for_dest(&remote_ip_ss, &local_ss);
650 if(err < 0){
651 return -1;
652 }
653
654 char tmp_addr[NI_MAXHOST];
655 if(am_inet_ntop(&local_ss,tmp_addr,NI_MAXHOST) != NULL){
656 local = tmp_addr;
657 return 0;
658 }
659
660 return -1;
661 }
662
extract_tag(const string & addr)663 string extract_tag(const string& addr)
664 {
665 string::size_type p = addr.find(";tag=");
666 if(p == string::npos)
667 return "";
668
669 p += 5/*sizeof(";tag=")*/;
670 string::size_type p_end = p;
671 while(p_end < addr.length()){
672 if( addr[p_end] == '>'
673 || addr[p_end] == ';' )
674 break;
675 p_end++;
676 }
677 return addr.substr(p,p_end-p);
678 }
679
key_in_list(const string & s_list,const string & key,char list_delim)680 bool key_in_list(const string& s_list, const string& key,
681 char list_delim)
682 {
683 size_t pos = 0;
684 size_t pos2 = 0;
685 size_t pos_n = 0;
686 while (pos < s_list.length()) {
687 pos_n = pos2 = s_list.find(list_delim, pos);
688 if (pos2==string::npos)
689 pos2 = s_list.length()-1;
690 while ((pos2>0)&&
691 ((s_list[pos2] == ' ')||(s_list[pos2] == list_delim)
692 ||(s_list[pos2] == '\n')))
693 pos2--;
694 if (s_list.substr(pos, pos2-pos+1)==key)
695 return true;
696 if (pos_n == string::npos)
697 return false;
698 while ((pos_n<s_list.length()) &&
699 ((s_list[pos_n] == ' ')||(s_list[pos_n] == list_delim)||
700 (s_list[pos_n] == '\n')))
701 pos_n++;
702 if (pos_n == s_list.length())
703 return false;
704 pos = pos_n;
705 }
706 return false;
707 }
708
strip_header_params(const string & hdr_string)709 string strip_header_params(const string& hdr_string)
710 {
711 size_t val_begin = 0; // skip trailing ' '
712 for (;(val_begin<hdr_string.length()) &&
713 hdr_string[val_begin]==' ';val_begin++);
714 // strip parameters
715 size_t val_end = hdr_string.find(';', val_begin);
716 if (val_end == string::npos)
717 val_end=hdr_string.length();
718 return hdr_string.substr(val_begin, val_end-val_begin);
719 }
720
get_header_param(const string & hdr_string,const string & param_name)721 string get_header_param(const string& hdr_string,
722 const string& param_name)
723 {
724 size_t pos = 0;
725 while (pos<hdr_string.length()) {
726 pos = hdr_string.find(';',pos);
727 if (pos == string::npos)
728 return "";
729 if ((hdr_string.length()>pos+param_name.length()+1)
730 && hdr_string.substr(++pos, param_name.length())==param_name
731 && hdr_string[pos+param_name.length()] == '=') {
732 size_t pos2 = pos+param_name.length()+1;
733 while(pos2<hdr_string.length()){
734
735 switch(hdr_string[pos2]) {
736 case ';':
737 case '\n':
738 case '\r':
739 break;
740
741 default:
742 pos2++;
743 continue;
744 }
745
746 break;
747 }
748 return hdr_string.substr(pos + param_name.length() + 1, // skip 'param='
749 pos2 - pos - param_name.length() - 1);
750 }
751 pos +=param_name.length();
752 }
753 return "";
754 }
755
756 /** get the value of key @param short_name or @param name or from the list param_hdr*/
get_header_keyvalue(const string & param_hdr,const string & short_name,const string & name)757 string get_header_keyvalue(const string& param_hdr, const string& short_name, const string& name) {
758 string res = get_header_keyvalue(param_hdr, short_name);
759 if (res.length())
760 return res;
761
762 return get_header_keyvalue(param_hdr, name);
763 }
764
765 /**
766 * get value from parameter header with the name @param name
767 * while skipping escaped values
768 */
get_header_keyvalue(const string & param_hdr,const string & name)769 string get_header_keyvalue(const string& param_hdr, const string& name) {
770 vector <string> parts = explode(param_hdr, ",");
771 vector<string>::iterator vit;
772 string part;
773 for ( vit=parts.begin() ; vit < parts.end(); vit++ )
774 {
775 part = get_header_keyvalue_single(*vit, name);
776 if(!part.empty()) break;
777 }
778 return part;
779 }
780
get_header_keyvalue_single(const string & param_hdr,const string & name)781 string get_header_keyvalue_single(const string& param_hdr, const string& name) {
782 // ugly, but we need escaping
783 #define ST_FINDBGN 0
784 #define ST_FB_ESC 1
785 #define ST_BEGINKEY 2
786 #define ST_CMPKEY 3
787 #define ST_FINDEQ 4
788 #define ST_FINDVAL 5
789 #define ST_VALUE 6
790 #define ST_VAL_ESC 7
791
792 size_t p=0, k_begin=0, corr=0,
793 v_begin=0, v_end=0;
794
795 char last = ' ';
796 char esc_char = ' ';
797
798 unsigned int st = ST_BEGINKEY;
799
800 while (p<param_hdr.length() && !v_end) {
801 char curr = param_hdr[p];
802 // DBG("curr %c, st=%d, corr=%d\n", curr, st, corr);
803 switch(st) {
804 case ST_FINDBGN: {
805 switch(curr) {
806 case '"':
807 case '\'':
808 {
809 st = ST_FB_ESC;
810 esc_char = curr;
811 } break;
812 case ';':
813 st = ST_BEGINKEY;
814 break;
815 default: break;
816 } break;
817 } break;
818
819 case ST_FB_ESC: {
820 if (curr == esc_char && last != '\\') {
821 st = ST_FINDBGN;
822 }
823 } break;
824
825 case ST_BEGINKEY: {
826 switch (curr) {
827 case ' ': // spaces before the key
828 case '\t':
829 case ';': // semicolons before the key
830 break;
831 default:
832 if (curr==tolower(name[0]) || curr==toupper(name[0])) {
833 if (name.length() == 1)
834 st = ST_FINDEQ;
835 else
836 st = ST_CMPKEY;
837 k_begin = p;
838 corr = 1;
839 } else {
840 st = ST_FINDBGN;
841 }
842 }
843 } break;
844
845 case ST_CMPKEY: {
846 if (curr==tolower(name[corr]) || curr==toupper(name[corr])) {
847 corr++;
848 if (corr == name.length()) {
849 st = ST_FINDEQ;
850 }
851 } else {
852 st = ST_FINDBGN;
853 corr=0;
854 p=k_begin; // will continue searching one after k_begin
855 }
856 } break;
857
858 case ST_FINDEQ: {
859 switch (curr) {
860 case ' ':
861 case '\t':
862 break;
863 case '=':
864 st = ST_FINDVAL; break;
865 default: {
866 st = ST_FINDBGN;
867 corr=0;
868 p=k_begin; // will continue searching one after k_begin
869 } break;
870 }
871 } break;
872
873 case ST_FINDVAL: {
874 switch (curr) {
875 case ' ':
876 case '\t':
877 break;
878
879 case '"':
880 case '\'': {
881 st = ST_VAL_ESC;
882 esc_char = curr;
883 v_begin=p;
884 } break;
885 default:
886 st = ST_VALUE;
887 v_begin=p;
888 }
889 } break;
890
891 case ST_VALUE: {
892 switch (curr) {
893 case '"':
894 case '\'': {
895 st = ST_VAL_ESC;
896 esc_char = curr;
897 } break;
898 case ';':
899 v_end = p;
900 break;
901 default: break;
902 }
903 } break;
904
905
906 case ST_VAL_ESC: {
907 if (curr == esc_char && last != '\\') {
908 st = ST_VALUE;
909 }
910 } break;
911 }
912
913 p++;
914 last = curr;
915 }
916
917 if (!v_end && (st == ST_VALUE || st == ST_VAL_ESC))
918 v_end = p;
919
920 if (v_begin && v_end) {
921 if ((v_end - v_begin > 1) &&
922 (param_hdr[v_begin] == param_hdr[v_end-1]) &&
923 ((param_hdr[v_begin] == '\'') || (param_hdr[v_begin] == '"')))
924 return param_hdr.substr(v_begin+1, v_end-v_begin-2); // whole value quoted
925
926 return param_hdr.substr(v_begin, v_end-v_begin);
927 } else
928 return "";
929 }
930
931 /** get the value of key @param name from \ref PARAM_HDR header in hdrs */
get_session_param(const string & hdrs,const string & name)932 string get_session_param(const string& hdrs, const string& name) {
933 string iptel_app_param = getHeader(hdrs, PARAM_HDR, true);
934 if (!iptel_app_param.length()) {
935 // DBG("call parameters header PARAM_HDR not found "
936 // "(need to configure ser's tw_append?).\n");
937 return "";
938 }
939
940 return get_header_keyvalue(iptel_app_param, name);
941 }
942
parse_app_params(const string & hdrs,map<string,string> & app_params)943 void parse_app_params(const string& hdrs, map<string,string>& app_params)
944 {
945 // TODO: use real parser with quoting and optimize
946 vector<string> items = explode(getHeader(hdrs, PARAM_HDR, true), ";");
947 for (vector<string>::iterator it=items.begin();
948 it != items.end(); it++) {
949 vector<string> kv = explode(*it, "=");
950 if (kv.size() == 2) {
951 app_params.insert(make_pair(kv[0], kv[1]));
952 } else {
953 if (kv.size() == 1) {
954 app_params.insert(make_pair(*it, string()));
955 }
956 }
957 }
958 }
959
960
961 // support for thread-safe pseudo-random numbers
962 static unsigned int _s_rand=0;
963 static AmMutex _s_rand_mut;
964
init_random()965 void init_random()
966 {
967 int seed=0;
968 FILE* fp_rand = fopen("/dev/urandom","r");
969 if(fp_rand){
970 if (fread(&seed,sizeof(int),1,fp_rand) != 1) {
971 DBG("/dev/urandom could not be read, rng probably not initialized.\n");
972 }
973 fclose(fp_rand);
974 }
975 seed += getpid();
976 seed += time(0);
977 _s_rand = seed;
978 }
979
get_random()980 unsigned int get_random()
981 {
982 _s_rand_mut.lock();
983 unsigned int r = rand_r(&_s_rand);
984 _s_rand_mut.unlock();
985
986 return r;
987 }
988
989 // Explode string by a separator to a vector
990 // see http://stackoverflow.com/questions/236129/c-how-to-split-a-string
explode(const string & s,const string & delim,const bool keep_empty)991 std::vector<string> explode(const string& s, const string& delim,
992 const bool keep_empty) {
993 vector<string> result;
994 if (delim.empty()) {
995 result.push_back(s);
996 return result;
997 }
998 string::const_iterator substart = s.begin(), subend;
999 while (true) {
1000 subend = search(substart, s.end(), delim.begin(), delim.end());
1001 string temp(substart, subend);
1002 if (keep_empty || !temp.empty()) {
1003 result.push_back(temp);
1004 }
1005 if (subend == s.end()) {
1006 break;
1007 }
1008 substart = subend + delim.size();
1009 }
1010 return result;
1011 }
1012
1013
1014
1015 // Warning: static var is not mutexed
1016 // Call this func only in init code.
1017 //
add_env_path(const char * name,const string & path)1018 void add_env_path(const char* name, const string& path)
1019 {
1020 string var(path);
1021 char* old_path=0;
1022
1023 regex_t path_reg;
1024
1025 assert(name);
1026 if((old_path = getenv((char*)name)) != 0) {
1027 if(strlen(old_path)){
1028
1029 if(regcomp(&path_reg,("[:|^]" + path + "[:|$]").c_str(),REG_NOSUB)){
1030 ERROR("could not compile regex\n");
1031 return;
1032 }
1033
1034 if(!regexec(&path_reg,old_path,0,0,0)) { // match
1035 regfree(&path_reg);
1036 return; // do nothing
1037 }
1038 regfree(&path_reg);
1039 var += ":" + string(old_path);
1040 }
1041 }
1042
1043 DBG("setting %s to: '%s'\n",name,var.c_str());
1044 #ifndef BSD_COMP
1045 setenv(name,var.c_str(),1);
1046 #else
1047 string sol_putenv = name + string("=") + var;
1048 putenv(sol_putenv.c_str());
1049 #endif
1050 }
1051
1052 /** skip to the end of a string enclosed in round brackets, skipping more
1053 bracketed items, too */
skip_to_end_of_brackets(const string & s,size_t start)1054 size_t skip_to_end_of_brackets(const string& s, size_t start) {
1055 size_t res = start;
1056 char last_c = ' ';
1057 int num_brackets = 0;
1058 while (res < s.size() &&
1059 (s[res] != ')' || num_brackets || last_c == '\\')) {
1060 if (last_c != '\\') {
1061 if (s[res]==')' && num_brackets)
1062 num_brackets--;
1063 else if (s[res]=='(')
1064 num_brackets++;
1065 }
1066 last_c = s[res];
1067 res++;
1068 }
1069 return res;
1070 }
1071
read_regex_mapping(const string & fname,const char * sep,const char * dbg_type,RegexMappingVector & result)1072 bool read_regex_mapping(const string& fname, const char* sep,
1073 const char* dbg_type,
1074 RegexMappingVector& result) {
1075 std::ifstream appcfg(fname.c_str());
1076 if (!appcfg.good()) {
1077 ERROR("could not load %s file at '%s'\n",
1078 dbg_type, fname.c_str());
1079 return false;
1080 } else {
1081 while (!appcfg.eof()) {
1082 string entry;
1083 getline (appcfg,entry);
1084 if (!entry.length())
1085 continue;
1086 size_t non_wsp_pos = entry.find_first_not_of(" \t");
1087 if (non_wsp_pos != string::npos && entry[non_wsp_pos] == '#')
1088 continue;
1089
1090 vector<string> re_v = explode(entry, sep);
1091 if (re_v.size() != 2) {
1092 ERROR("Incorrect line '%s' in %s: expected format 'regexp%sstring'\n",
1093 entry.c_str(), fname.c_str(), sep);
1094 return false;
1095 }
1096 regex_t app_re;
1097 if (regcomp(&app_re, re_v[0].c_str(), REG_EXTENDED)) {
1098 ERROR("compiling regex '%s' in %s.\n",
1099 re_v[0].c_str(), fname.c_str());
1100 return false;
1101 }
1102 DBG("adding %s '%s' => '%s'\n",
1103 dbg_type, re_v[0].c_str(),re_v[1].c_str());
1104 result.push_back(make_pair(app_re, re_v[1]));
1105 }
1106 }
1107 return true;
1108 }
1109
ReplaceStringInPlace(std::string & subject,const std::string & search,const std::string & replace)1110 void ReplaceStringInPlace(std::string& subject, const std::string& search,
1111 const std::string& replace) {
1112 size_t pos = 0;
1113 while ((pos = subject.find(search, pos)) != std::string::npos) {
1114 subject.replace(pos, search.length(), replace);
1115 pos += replace.length();
1116 }
1117 }
1118
1119 #define MAX_GROUPS 9
1120
run_regex_mapping(const RegexMappingVector & mapping,const char * test_s,string & result)1121 bool run_regex_mapping(const RegexMappingVector& mapping, const char* test_s,
1122 string& result) {
1123 regmatch_t groups[MAX_GROUPS];
1124 for (RegexMappingVector::const_iterator it = mapping.begin();
1125 it != mapping.end(); it++) {
1126 if (!regexec(&it->first, test_s, MAX_GROUPS, groups, 0)) {
1127 result = it->second;
1128 string soh(1, char(1));
1129 ReplaceStringInPlace(result, "\\\\", soh);
1130 unsigned int g = 0;
1131 for (g = 1; g < MAX_GROUPS; g++) {
1132 if (groups[g].rm_so == (int)(size_t)-1) break;
1133 DBG("group %u: [%2u-%2u]: %.*s\n",
1134 g, (unsigned int)groups[g].rm_so, (unsigned int)groups[g].rm_eo,
1135 (int)(groups[g].rm_eo - groups[g].rm_so), test_s + groups[g].rm_so);
1136 std::string match(test_s + groups[g].rm_so,
1137 groups[g].rm_eo - groups[g].rm_so);
1138 ReplaceStringInPlace(result, "\\" + int2str(g), match);
1139 }
1140 ReplaceStringInPlace(result, soh, "\\");
1141 return true;
1142 }
1143 }
1144 return false;
1145 }
1146
1147 // These function comes basically from ser's uac module
cvt_hex(HASH bin,HASHHEX hex)1148 void cvt_hex(HASH bin, HASHHEX hex)
1149 {
1150 unsigned short i;
1151 unsigned char j;
1152
1153 for (i = 0; i<HASHLEN; i++)
1154 {
1155 j = (bin[i] >> 4) & 0xf;
1156 if (j <= 9)
1157 {
1158 hex[i * 2] = (j + '0');
1159 } else {
1160 hex[i * 2] = (j + 'a' - 10);
1161 }
1162
1163 j = bin[i] & 0xf;
1164
1165 if (j <= 9)
1166 {
1167 hex[i * 2 + 1] = (j + '0');
1168 } else {
1169 hex[i * 2 + 1] = (j + 'a' - 10);
1170 }
1171 };
1172
1173 hex[HASHHEXLEN] = '\0';
1174 }
1175
1176 /** get an MD5 hash of a string */
calculateMD5(const string & input)1177 string calculateMD5(const string& input) {
1178 MD5_CTX Md5Ctx;
1179 HASH H;
1180 HASHHEX HH;
1181
1182 MD5Init(&Md5Ctx);
1183 MD5Update(&Md5Ctx, (unsigned char*)input.c_str(), input.length());
1184 MD5Final(H, &Md5Ctx);
1185 cvt_hex(H, HH);
1186 return string((const char*)HH);
1187 }
1188