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