123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- /*
- *$Id$
- *
- * - various general purpose functions
- *
- * Copyright (C) 2001-2003 Fhg Fokus
- *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * History
- * ------
- * 2003-01-18 un_escape function introduced for convenience of code needing
- * the complex&slow feature of unescaping
- */
- #ifndef ut_h
- #define ut_h
- #include <sys/types.h>
- #include <sys/time.h>
- #include <unistd.h>
- #include "dprint.h"
- #include "str.h"
- struct sip_msg;
- /* returns string beginning and length without insignificant chars */
- #define trim_len( _len, _begin, _mystr ) \
- do{ static char _c; \
- (_len)=(_mystr).len; \
- while ((_len) && ((_c=(_mystr).s[(_len)-1])==0 || _c=='\r' || \
- _c=='\n' || _c==' ' || _c=='\t' )) \
- (_len)--; \
- (_begin)=(_mystr).s; \
- while ((_len) && ((_c=*(_begin))==' ' || _c=='\t')) { \
- (_len)--;\
- (_begin)++; \
- } \
- }while(0)
- #define trim_r( _mystr ) \
- do{ static char _c; \
- while( ((_mystr).len) && ( ((_c=(_mystr).s[(_mystr).len-1]))==0 ||\
- _c=='\r' || _c=='\n' ) \
- ) \
- (_mystr).len--; \
- }while(0)
- #define translate_pointer( _new_buf , _org_buf , _p) \
- ( (_p)?(_new_buf + (_p-_org_buf)):(0) )
- #define via_len(_via) \
- ((_via)->bsize-((_via)->name.s-\
- ((_via)->hdr.s+(_via)->hdr.len)))
- #define via_s(_via,_p_msg) \
- translate_pointer((_p_msg)->orig,(_p_msg)->buf,(_via)->name.s)
- /* char to hex conversion table */
- static char fourbits2char[16] = { '0', '1', '2', '3', '4', '5',
- '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- /* converts a str to an u. short, returns the u. short and sets *err on
- * error and if err!=null
- */
- static inline unsigned short str2s(unsigned char* str, unsigned int len,
- int *err)
- {
- unsigned short ret;
- int i;
- unsigned char *limit;
- unsigned char *init;
- /*init*/
- ret=i=0;
- limit=str+len;
- init=str;
- for(;str<limit ;str++){
- if ( (*str <= '9' ) && (*str >= '0') ){
- ret=ret*10+*str-'0';
- i++;
- if (i>5) goto error_digits;
- }else{
- //error unknown char
- goto error_char;
- }
- }
- if (err) *err=0;
- return ret;
- error_digits:
- DBG("str2s: ERROR: too many letters in [%.*s]\n", (int)len, init);
- if (err) *err=1;
- return 0;
- error_char:
- DBG("str2s: ERROR: unexpected char %c in %.*s\n", *str, (int)len, init);
- if (err) *err=1;
- return 0;
- }
- static inline int btostr( char *p, unsigned char val)
- {
- unsigned int a,b,i =0;
- if ( (a=val/100)!=0 )
- *(p+(i++)) = a+'0'; /*first digit*/
- if ( (b=val%100/10)!=0 || a)
- *(p+(i++)) = b+'0'; /*second digit*/
- *(p+(i++)) = '0'+val%10; /*third digit*/
- return i;
- }
- /* faster memchr version */
- static inline char* q_memchr(char* p, int c, unsigned int size)
- {
- char* end;
- end=p+size;
- for(;p<end;p++){
- if (*p==(unsigned char)c) return p;
- }
- return 0;
- }
-
- inline static int reverse_hex2int( char *c, int len )
- {
- char *pc;
- int r;
- char mychar;
- r=0;
- for (pc=c+len-1; len>0; pc--, len--) {
- r <<= 4 ;
- mychar=*pc;
- if ( mychar >='0' && mychar <='9') r+=mychar -'0';
- else if (mychar >='a' && mychar <='f') r+=mychar -'a'+10;
- else if (mychar >='A' && mychar <='F') r+=mychar -'A'+10;
- else return -1;
- }
- return r;
- }
- inline static int int2reverse_hex( char **c, int *size, int nr )
- {
- unsigned short digit;
- if (*size && nr==0) {
- **c = '0';
- (*c)++;
- (*size)--;
- return 1;
- }
- while (*size && nr ) {
- digit = nr & 0xf ;
- **c= digit >= 10 ? digit + 'a' - 10 : digit + '0';
- nr >>= 4;
- (*c)++;
- (*size)--;
- }
- return nr ? -1 /* number not processed; too little space */ : 1;
- }
- /* double output length assumed ; does NOT zero-terminate */
- inline static int string2hex(
- /* input */ unsigned char *str, int len,
- /* output */ char *hex )
- {
- int orig_len;
- if (len==0) {
- *hex='0';
- return 1;
- }
- orig_len=len;
- while ( len ) {
- *hex=fourbits2char[(*str) >> 4];
- hex++;
- *hex=fourbits2char[(*str) & 0xf];
- hex++;
- len--;
- str++;
- }
- return orig_len-len;
- }
- /* portable sleep in microseconds (no interrupt handling now) */
- inline static void sleep_us( unsigned int nusecs )
- {
- struct timeval tval;
- tval.tv_sec=nusecs/100000;
- tval.tv_usec=nusecs%1000000;
- select(0, NULL, NULL, NULL, &tval );
- }
- inline static int hex2int(char hex_digit)
- {
- if (hex_digit>='0' && hex_digit<='9')
- return hex_digit-'0';
- if (hex_digit>='a' && hex_digit<='f')
- return hex_digit-'a'+10;
- if (hex_digit>='A' && hex_digit<='F')
- return hex_digit-'A'+10;
- /* no valid hex digit ... */
- LOG(L_ERR, "ERROR: hex2int: '%c' is no hex char\n", hex_digit );
- return -1;
- }
- /* Un-escape URI user -- it takes a pointer to original user
- str, as well as the new, unescaped one, which MUST have
- an allocated buffer linked to the 'str' structure ;
- (the buffer can be allocated with the same length as
- the original string -- the output string is always
- shorter (if escaped characters occur) or same-long
- as the original one).
- only printeable characters are permitted
- <0 is returned on an uneascaping error, length of the
- unescaped string otherwise
- */
- inline static int un_escape(str *user, str *new_user )
- {
- int i, j, value;
- int hi, lo;
- if( new_user==0 || new_user->s==0) {
- LOG(L_CRIT, "BUG: un_escape: called with invalid param\n");
- return -1;
- }
- new_user->len = 0;
- j = 0;
- for (i = 0; i < user->len; i++) {
- if (user->s[i] == '%') {
- if (i + 2 >= user->len) {
- LOG(L_ERR, "ERROR: un_escape: escape sequence too short in"
- " '%.*s' @ %d\n",
- user->len, user->s, i );
- goto error;
- }
- hi=hex2int(user->s[i + 1]);
- if (hi<0) {
- LOG(L_ERR, "ERROR: un_escape: non-hex high digit in an escape sequence in"
- " '%.*s' @ %d\n",
- user->len, user->s, i+1 );
- goto error;
- }
- lo=hex2int(user->s[i + 2]);
- if (lo<0) {
- LOG(L_ERR, "ERROR: non-hex low digit in an escape sequence in "
- "'%.*s' @ %d\n",
- user->len, user->s, i+2 );
- goto error;
- }
- value=(hi<<4)+lo;
- if (value < 32 || value > 126) {
- LOG(L_ERR, "ERROR: non-ASCII escaped character in '%.*s' @ %d\n",
- user->len, user->s, i );
- goto error;
- }
- new_user->s[j] = value;
- i+=2; /* consume the two hex digits, for cycle will move to the next char */
- } else {
- new_user->s[j] = user->s[i];
- }
- j++; /* good -- we translated another character */
- }
- new_user->len = j;
- return j;
- error:
- new_user->len = j;
- return -1;
- }
- #endif
|