代码拉取完成,页面将自动刷新
/*
* - various general purpose functions
*
* Copyright (C) 2001-2003 FhG Fokus
*
* This file is part of opensips, a free SIP server.
*
* opensips 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
*
* opensips 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef ut_h
#define ut_h
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <limits.h>
#include <unistd.h>
#include <ctype.h>
#include "config.h"
#include "dprint.h"
#include "sr_module.h"
#include "action.h"
#include "str.h"
#include "evi/evi_modules.h"
#include "evi/evi_core.h"
#include "mem/mem.h"
#include "mem/shm_mem.h"
#include "lib/str2const.h"
typedef struct _int_str_t {
union {
int i;
str s;
};
unsigned char is_str;
} int_str_t;
struct sip_msg;
/* the amount of decimals to be displayed for "float" and "double" values */
#define FLOATING_POINT_PRECISION 8
/* zero-string wrapper */
#define ZSW(_c) ((_c)?(_c):"")
/* 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 || is_ws(_c))) \
(_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)
/* right and left space trimming */
#define trim_spaces_lr(_s_) \
do{\
for(;(_s_).s[(_s_).len-1]==' ';(_s_).s[--(_s_).len]=0);\
for(;(_s_).s[0]==' ';(_s_).s=(_s_).s+1,(_s_).len--);\
}while(0);
/* right and left space trimming without '0' padding */
#define str_trim_spaces_lr(_s_) \
do{\
for(;(_s_).s[(_s_).len-1]==' ';--(_s_).len);\
for(;(_s_).s[0]==' ';(_s_).s=(_s_).s+1,(_s_).len--);\
}while(0);
#define translate_pointer( _new_buf , _org_buf , _p) \
( (_p)?(_new_buf + (_p-_org_buf)):(0) )
#define TIMEVAL_MS_DIFF(_tva, _tvb) \
((((_tvb).tv_sec * 1000000UL + (_tvb).tv_usec) - \
((_tva).tv_sec * 1000000UL + (_tva).tv_usec)) / 1000UL)
/**
* _add_last() - Walk the @next_member field of any struct and append last.
* @what: Pointer to the struct that is to be appended.
* @where: Pointer to the list that is to be appended to.
* @next_member: The name of the member used to link to the next ones.
*
* If the list @where is NULL, @what will be assigned to it.
*/
#define _add_last(what, where, next_member) \
do { \
if (!(where)) { \
(where) = (what); \
} else { \
typeof(where) __wit = (where); \
while (__wit->next_member) \
__wit = __wit->next_member; \
__wit->next_member = (what); \
} \
} while (0)
/**
* add_last() - Walk the "->next" field of any struct and append last.
* @what: Pointer to the struct that is to be appended.
* @where: Pointer to the list that is to be appended to.
*
* If the list @where is NULL, @what will be assigned to it.
*/
#define add_last(what, where) \
_add_last(what, where, next)
/**
* pkg_free_all() - pkg_free() each element of the given (circular) list.
* @things: Pointer to the list that is to be freed in succession.
*
* The list is walked using "->next".
*/
#define pkg_free_all(things) \
do { \
typeof(things) pos = NULL, head = (things); \
while ((things) && ((things) != head || !pos)) \
{ pos = (things); (things) = (things)->next; pkg_free(pos); } \
} while (0)
/**
* shm_free_all() - shm_free() each element of the given (circular) list.
* @things: Pointer to the list that is to be freed in succession.
*
* The list is walked using "->next".
*/
#define shm_free_all(things) \
do { \
typeof(things) pos = NULL, head = (things); \
while ((things) && ((things) != head || !pos)) \
{ pos = (things); (things) = (things)->next; shm_free(pos); } \
} while (0)
#define via_len(_via) \
((_via)->bsize-((_via)->name.s-\
((_via)->hdr.s+(_via)->hdr.len)))
#ifdef __GNUC__
#define ALLOW_UNUSED __attribute__ ((unused))
#else
#define ALLOW_UNUSED
#endif
#define PTR_STRING_SIZE 2+16+1
#define PTR_STR_SIZE 2+16
/* 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(const char* s, unsigned int len,
int *err)
{
unsigned short ret;
int i;
unsigned char *limit;
unsigned char *str;
/*init*/
str=(unsigned char*)s;
ret=i=0;
limit=str+len;
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:
LM_DBG("too many letters in [%.*s]\n", (int)len, s);
if (err) *err=1;
return 0;
error_char:
LM_DBG("unexpected char %c in %.*s\n", *str, (int)len, s);
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;
}
static inline int rctostr( char *p, unsigned int 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;
}
/* 2^64~= 16*10^18 => 19+1+1 sign + digits + \0 */
#define INT2STR_MAX_LEN (1+19+1+1)
/* INTeger-TO-Buffer-STRing : converts a 64-bit integer to a string
* IMPORTANT: the provided buffer must be at least INT2STR_MAX_LEN size !! */
static inline char* int2bstr(uint64_t l, char *s, int* len)
{
int i;
i=INT2STR_MAX_LEN-2;
s[INT2STR_MAX_LEN-1]=0; /* null terminate */
do{
s[i]=l%10+'0';
i--;
l/=10;
}while(l && (i>=0));
if (l && (i<0)){
LM_CRIT("overflow error\n");
}
if (len) *len=(INT2STR_MAX_LEN-2)-i;
return &s[i+1];
}
/* INTeger-TO-STRing : convers a 64-bit integer to a string
* returns a pointer to a static buffer containing l in asciiz & sets len */
#define INT2STR_BUF_NO 7
extern unsigned int int2str_buf_index;
extern char int2str_buf[INT2STR_BUF_NO][INT2STR_MAX_LEN];
static inline unsigned int getstrbufindex(void) {
return ((int2str_buf_index++) % INT2STR_BUF_NO);
}
static inline char* int2str(uint64_t l, int* len)
{
return int2bstr( l, int2str_buf[getstrbufindex()], len);
}
/* Signed INTeger-TO-STRing: convers a long to a string
* returns a pointer to a static buffer containing l in asciiz & sets len */
static inline char* sint2str(long l, int* len)
{
int sign;
char *p;
sign = 0;
if(l<0) {
sign = 1;
l = -l;
}
p = int2str((unsigned long)l, len);
if(sign) {
*(--p) = '-';
if (len) (*len)++;
}
return p;
}
#define DOUBLE2STR_MAX_LEN INT2STR_MAX_LEN
static inline char* double2str(double d, int* len)
{
unsigned int buf;
buf = getstrbufindex();
*len = snprintf(int2str_buf[buf], INT2STR_MAX_LEN - 1, "%0.*lf",
FLOATING_POINT_PRECISION, d);
int2str_buf[buf][*len] = '\0';
return int2str_buf[buf];
}
#define BIGINT2STR_MAX_LEN INT2STR_MAX_LEN
static inline char* bigint2str(long long l, int* len)
{
unsigned int buf;
buf = getstrbufindex();
*len = snprintf(int2str_buf[buf], INT2STR_MAX_LEN - 1, "%lld", l);
int2str_buf[buf][*len] = '\0';
return int2str_buf[buf];
}
/* 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 NULL;
}
/* faster memrchr version */
static inline char* q_memrchr(char* p, int c, unsigned int size)
{
char* cursor;
cursor=p+size-1;
for(;cursor>=p;cursor--){
if (*cursor==(unsigned char)c) return cursor;
}
return NULL;
}
inline static int reverse_hex2int( char *c, int len, unsigned int *r)
{
char *pc;
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 0;
}
inline static int int2reverse_hex( char **c, int *size, unsigned 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;
}
/* same functions, higher representation 64 bit*/
/* if unsafe requested when first non numerical character shall be
* met the number shall be returned; avoid giving the
* exact len of the number */
inline static int reverse_hex2int64( char *c, int len, int unsafe, uint64_t *r)
{
char *pc;
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 if (unsafe)
return 0;
else return -1;
}
return 0;
}
inline static int64_t int64_2reverse_hex( char **c, int *size, uint64_t 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;
}
inline static int hexstr2int(char *c, int len, unsigned int *val)
{
char *pc;
int r;
char mychar;
r=0;
for (pc=c; pc<c+len; pc++) {
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;
}
*val = r;
return 0;
}
/* double output length assumed ; does NOT zero-terminate */
inline static int string2hex(
/* input */ const 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) & 0x0f];
hex++;
*hex=fourbits2char[(*str) & 0x0f];
hex++;
len--;
str++;
}
return orig_len * 2;
}
inline static int hex2string(
/* input */ const char *str, int len,
/* output */ char *hex )
{
int i;
for (i = 0; i < len / 2; i++) {
if(str[2*i]>='0' && str[2*i]<='9')
hex[i] = (str[2*i]-'0') << 4;
else if(str[2*i]>='a' && str[2*i]<='f')
hex[i] = (str[2*i]-'a'+10) << 4;
else if(str[2*i]>='A' && str[2*i]<='F')
hex[i] = (str[2*i]-'A'+10) << 4;
else goto error;
if(str[2*i+1]>='0' && str[2*i+1]<='9')
hex[i] += str[2*i+1]-'0';
else if(str[2*i+1]>='a' && str[2*i+1]<='f')
hex[i] += str[2*i+1]-'a'+10;
else if(str[2*i+1]>='A' && str[2*i+1]<='F')
hex[i] += str[2*i+1]-'A'+10;
else goto error;
}
return i;
error:
return -1;
}
/* portable sleep in microseconds (no interrupt handling now) */
inline static void sleep_us( unsigned int nusecs )
{
struct timeval tval;
tval.tv_sec=nusecs/1000000;
tval.tv_usec=nusecs%1000000;
select(0, NULL, NULL, NULL, &tval );
}
/* portable determination of max_path */
inline static int pathmax(void)
{
#ifdef PATH_MAX
static int pathmax=PATH_MAX;
#else
static int pathmax=0;
#endif
if (pathmax==0) { /* init */
pathmax=pathconf("/", _PC_PATH_MAX);
pathmax=(pathmax<=0)?PATH_MAX_GUESS:pathmax+1;
}
return pathmax;
}
/* faster than glibc equivalents */
#define _isdigit(c) ((c) >= '0' && (c) <= '9')
#define _isalpha(c) \
(((c) >= 'a' && (c) <= 'z') || \
((c) >= 'A' && (c) <= 'Z'))
#define _isxdigit(c) \
(((c) >= '0' && (c) <= '9') || \
((c) >= 'a' && (c) <= 'f') || \
((c) >= 'A' && (c) <= 'F'))
#define _isalnum(c) (_isalpha(c) || _isdigit(c))
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 ... */
LM_ERR("'%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 printable characters are permitted
<0 is returned on an unescaping 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) {
LM_CRIT("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) {
LM_ERR("escape sequence too short in"
" '%.*s' @ %d\n",
user->len, user->s, i );
goto error;
}
hi=hex2int(user->s[i + 1]);
if (hi<0) {
LM_ERR(" 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) {
LM_ERR("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) {
LM_ERR("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;
}
static inline void unescape_crlf(str *in_out)
{
char *p, *lim = in_out->s + in_out->len;
if (ZSTR(*in_out))
return;
for (p = in_out->s; p < lim; p++) {
if (*p == '\\' && p + 1 < lim) {
if (*(p + 1) == 'r') {
*p = '\r';
memmove(p + 1, p + 2, lim - (p + 2));
in_out->len--;
} else if (*(p + 1) == 'n') {
*p = '\n';
memmove(p + 1, p + 2, lim - (p + 2));
in_out->len--;
}
}
}
}
/* @max_digits should be just 15, but there are exceptions to this rule! */
static inline int _is_e164(const str* _user, int require_plus, int max_digits)
{
char *d, *start, *end;
if (_user->len < 1)
return -1;
if (_user->s[0] == '+') {
start = _user->s + 1;
} else {
if (require_plus)
return -1;
start = _user->s;
}
end = _user->s + _user->len;
if (end - start < 2 || end - start > max_digits)
return -1;
for (d = start; d < end; d++)
if (!_isdigit(*d))
return -1;
return 1;
}
#define is_e164(_user) _is_e164(_user, 1, 15)
/*
* Convert a string to lower case
*/
static inline void strlower(str* _s)
{
int i;
for(i = 0; i < _s->len; i++) {
_s->s[i] = tolower(_s->s[i]);
}
}
/*
* Convert a str into a short integer
*/
static inline int str2short(str* _s, unsigned short *_r)
{
int i;
if (_s==0 || _s->s == 0 || _s->len == 0 || _r == 0)
return -1;
*_r = 0;
for(i = 0; i < _s->len; i++) {
if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
*_r *= 10;
*_r += _s->s[i] - '0';
} else {
return -1;
}
}
return 0;
}
/*
* Convert a str into integer
*/
static inline int str2int(const str* _s, unsigned int* _r)
{
int i;
if (_s==0 || _s->s == 0 || _s->len == 0 || _r == 0)
return -1;
*_r = 0;
for(i = 0; i < _s->len; i++) {
if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
*_r *= 10;
*_r += _s->s[i] - '0';
} else {
return -1;
}
}
return 0;
}
/*
* Convert a str into a big integer
*/
static inline int str2int64(const str* _s, uint64_t *_r)
{
int i;
if (_s==0 || _s->s == 0 || _s->len == 0 || _r == 0)
return -1;
*_r = 0;
for(i = 0; i < _s->len; i++) {
if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
*_r *= 10;
*_r += _s->s[i] - '0';
} else {
return -1;
}
}
return 0;
}
/*
* Convert a str into signed integer
*/
static inline int str2sint(const str* _s, int* _r)
{
int i;
int s;
if (_s==0 || _s->s == 0 || _s->len == 0 || _r == 0)
return -1;
*_r = 0;
s = 1;
i=0;
if(_s->s[i]=='-') {
s=-1;
i++;
} else if (_s->s[i]=='+') {
i++;
}
for(; i < _s->len; i++) {
if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
*_r *= 10;
*_r += _s->s[i] - '0';
} else {
//Preserve sign for partially converted strings
*_r *= s;
return -1;
}
}
*_r *= s;
return 0;
}
/*
* Convert a str (base 10 or 16) into integer
*/
static inline int strno2int(const str *val, unsigned int *mask )
{
/* hexa or decimal*/
if (val->len>2 && val->s[0]=='0' && val->s[1]=='x') {
return hexstr2int( val->s+2, val->len-2, mask);
} else {
return str2int( val, mask);
}
}
/*
* Make a copy of a str structure using shm_malloc
*
* Return: 0 on success, -1 on failure
*/
#define shm_str_dup(/* str* */_dst_, /* str* */_src_) \
({ \
int __ret__; \
(_dst_)->s = shm_malloc((_src_)->len); \
if (!(_dst_)->s) { \
LM_ERR("no shared memory left\n"); \
(_dst_)->len = 0; \
__ret__ = -1; \
} else { \
memcpy((_dst_)->s, (_src_)->s, (_src_)->len); \
(_dst_)->len = (_src_)->len; \
__ret__ = 0; \
} \
__ret__; \
})
/*
* Make a copy of an str structure using shm_malloc
* + an additional '\0' byte, so you can make use of dst->s
*
* dst == src is allowed!
*/
static inline int shm_nt_str_dup(str* dst, const str* src)
{
const str _src = *src;
if (!_src.s) {
memset(dst, 0, sizeof *dst);
return 0;
}
dst->s = shm_malloc(_src.len + 1);
if (!dst->s) {
LM_ERR("no shared memory left\n");
dst->len = 0;
if (dst == src)
*dst = _src;
return -1;
}
memcpy(dst->s, _src.s, _src.len);
dst->len = _src.len;
dst->s[_src.len] = '\0';
return 0;
}
/*
* Make a copy of an str structure using pkg_malloc
* + an additional '\0' byte, so you can make use of dst->s
*
* dst == src is allowed!
*/
static inline int pkg_nt_str_dup(str* dst, const str* src)
{
const str _src = *src;
if (!_src.s) {
memset(dst, 0, sizeof *dst);
return 0;
}
dst->s = pkg_malloc(_src.len + 1);
if (!dst->s) {
LM_ERR("no private memory left\n");
dst->len = 0;
if (dst == src)
*dst = _src;
return -1;
}
memcpy(dst->s, _src.s, _src.len);
dst->len = _src.len;
dst->s[_src.len] = '\0';
return 0;
}
static inline char *shm_strdup(const char *str)
{
char *rval;
int len;
if (!str)
return NULL;
len = strlen(str) + 1;
rval = shm_malloc(len);
if (!rval)
return NULL;
memcpy(rval, str, len);
return rval;
}
/*
* Ensure the given (str *) points to an SHM buffer of at least "size" bytes
*
* Return: 0 on success, -1 on failure
*/
#define shm_str_extend(/* str* */_in_, /* int */_size_) \
({ \
int __ret__ = 0; \
/* do not check for !in->s here, as it's better \
* to crash sooner on a corrupt @in string (e.g. {NULL, 172}) */ \
if ((_in_)->len < (_size_)) { \
char *_p_ = shm_realloc((_in_)->s, _size_); \
if (!_p_) { \
LM_ERR("oom\n"); \
__ret__ = -1; \
} else { \
(_in_)->s = _p_; \
(_in_)->len = _size_; \
} \
} \
__ret__; \
})
/*
* Ensure "dst" matches the content of "src" without leaking memory
*
* Note: if you just want to dup a string, use "shm_str_dup()" instead
* Return: 0 on success, -1 on failure
*/
#define shm_str_sync(/* str* */_dst_, /* str* */_src_) \
({ \
int __ret__; \
if ((str *)(_src_) == (str *)NULL || !(_src_)->s || (_src_)->len == 0) { \
if ((_dst_)->s) \
shm_free((_dst_)->s); \
memset((_dst_), 0, sizeof *(_dst_)); \
__ret__ = 0; \
} else if (shm_str_extend(_dst_, (_src_)->len) != 0) { \
LM_ERR("oom\n"); \
__ret__ = -1; \
} else { \
memcpy((_dst_)->s, (_src_)->s, (_src_)->len); \
(_dst_)->len = (_src_)->len; \
__ret__ = 0; \
} \
__ret__; \
})
static inline void shm_str_clean(str* dst)
{
if (dst->s)
shm_free(dst->s);
memset(dst, 0, sizeof *dst);
}
/*
* Make a copy of a str structure using pkg_malloc
*/
static inline int pkg_str_dup(str* dst, const str* src)
{
dst->s = pkg_malloc(src->len);
if (!dst->s) {
LM_ERR("no private memory left\n");
dst->len = 0;
return -1;
}
memcpy(dst->s, src->s, src->len);
dst->len = src->len;
return 0;
}
static inline char *pkg_strdup(const char *str)
{
char *rval;
int len;
if (!str)
return NULL;
len = strlen(str) + 1;
rval = pkg_malloc(len);
if (!rval)
return NULL;
memcpy(rval, str, len);
return rval;
}
/* Extend the given buffer only if needed */
static inline int pkg_str_extend(str *in, int size)
{
char *p;
/* do not check for !in->s here, as it's better
* to crash sooner on a corrupt @in string (e.g. {NULL, 172}) */
if (in->len < size) {
p = pkg_realloc(in->s, size);
if (!p) {
LM_ERR("oom\n");
return -1;
}
in->s = p;
in->len = size;
}
return 0;
}
/*
* Ensure "dst" matches the content of "src" without leaking memory
*
* Note: if you just want to dup a string, use "pkg_str_dup()" instead
*/
static inline int pkg_str_sync(str* dst, const str* src)
{
if (ZSTRP(src)) {
if (dst->s)
pkg_free(dst->s);
memset(dst, 0, sizeof *dst);
return 0;
}
if (pkg_str_extend(dst, src->len) != 0) {
LM_ERR("oom\n");
return -1;
}
memcpy(dst->s, src->s, src->len);
dst->len = src->len;
return 0;
}
/*
* test if two str's are equal
*/
static inline int _str_matchCC(const str_const *a, const str_const *b)
{
return a->len == b->len && !memcmp(a->s, b->s, a->len);
}
static inline int _str_matchSS(const str *a, const str *b)
{
return _str_matchCC(str2const(a), str2const(b));
}
static inline int _str_matchSC(const str *a, const str_const *b)
{
return _str_matchCC(str2const(a), b);
}
static inline int _str_matchCS(const str_const *a, const str *b)
{
return _str_matchCC(a, str2const(b));
}
/*
* test if two str's are equal, case-insensitive
*/
static inline int _str_casematchCC(const str_const *a, const str_const *b)
{
const char *p, *q, *end;
if (a->len != b->len)
return 0;
p = a->s;
q = b->s;
if (p == q || a->len == 0)
return 1;
end = p + a->len;
do {
if (tolower(*p) != tolower(*q++))
return 0;
} while (++p < end);
return 1;
}
static inline int _str_casematchSS(const str *a, const str *b)
{
return _str_casematchCC(str2const(a), str2const(b));
}
static inline int _str_casematchSC(const str *a, const str_const *b)
{
return _str_casematchCC(str2const(a), b);
}
static inline int _str_casematchCS(const str_const *a, const str *b)
{
return _str_casematchCC(a, str2const(b));
}
/*
* compare two str's
*/
static inline int _str_strcmpCC(const str_const *stra, const str_const *strb)
{
int i;
int alen;
int blen;
int minlen;
if(stra==NULL || strb==NULL || stra->s ==NULL || strb->s==NULL
|| stra->len<0 || strb->len<0)
{
#ifdef EXTRA_DEBUG
LM_DBG("bad parameters\n");
#endif
return -2;
}
alen = stra->len;
blen = strb->len;
minlen = (alen < blen ? alen : blen);
for (i = 0; i < minlen; i++) {
const char a = stra->s[i];
const char b = strb->s[i];
if (a < b)
return -1;
if (a > b)
return 1;
}
if (alen < blen)
return -1;
else if (alen > blen)
return 1;
else
return 0;
}
static inline int _str_strcmpSS(const str *a, const str *b)
{
return _str_strcmpCC(str2const(a), str2const(b));
}
static inline int _str_strcmpSC(const str *a, const str_const *b)
{
return _str_strcmpCC(str2const(a), b);
}
static inline int _str_strcmpCS(const str_const *a, const str *b)
{
return _str_strcmpCC(a, str2const(b));
}
/*
* compares a str with a const null terminated string
*/
static inline int str_match_nt(const str *a, const char *b)
{
return a->len == strlen(b) && !memcmp(a->s, b, a->len);
}
/*
* compares a str with a const null terminated string, case-insensitive
*/
static inline int str_casematch_nt(const str *a, const char *b)
{
return a->len == strlen(b) && !strncasecmp(a->s, b, a->len);
}
/*
* search @strb in @stra, return pointer to 1st occurrence
*/
static inline char* str_strstr(const str *stra, const str *strb)
{
int i;
int len;
if (stra==NULL || strb==NULL || stra->s==NULL || strb->s==NULL
|| stra->len<=0 || strb->len<=0) {
#ifdef EXTRA_DEBUG
LM_DBG("bad parameters\n");
#endif
return NULL;
}
if (strb->len > stra->len)
return NULL;
len=0;
while (stra->len-len >= strb->len){
if (stra->s[len] != strb->s[0]) {
len++;
continue;
}
for (i=1; i<strb->len; i++)
if (stra->s[len+i]!=strb->s[i]) {
len++;
break;
}
if (i != strb->len)
continue;
return stra->s+len;
}
return NULL;
}
/*
* search @strb in @stra ignoring case of both, return pointer to 1st occurrence
*/
static inline char* str_strcasestr(const str *stra, const str *strb)
{
int i;
int len;
if (stra==NULL || strb==NULL || stra->s==NULL || strb->s==NULL
|| stra->len<=0 || strb->len<=0) {
#ifdef EXTRA_DEBUG
LM_DBG("bad parameters\n");
#endif
return NULL;
}
if (strb->len > stra->len)
return NULL;
len=0;
while (stra->len-len >= strb->len){
if (tolower(stra->s[len]) != tolower(strb->s[0])) {
len++;
continue;
}
for (i=1; i<strb->len; i++)
if (tolower(stra->s[len+i])!=tolower(strb->s[i])) {
len++;
break;
}
if (i != strb->len)
continue;
return stra->s+len;
}
return NULL;
}
/*
* case-insensitive compare n chars of two str's
*/
static inline int str_strncasecmp(const str *stra, const str *strb, int n)
{
int i;
if(stra==NULL || strb==NULL || stra->s ==NULL || strb->s==NULL
|| stra->len<0 || strb->len<0)
{
#ifdef EXTRA_DEBUG
LM_DBG("bad parameters\n");
#endif
return -2;
}
if (stra->len<n || strb->len<n) {
LM_ERR("input strings don't have at least [n=%d] characters\n", n);
return -2;
}
for (i = 0; i < n; i++) {
const char a = tolower(stra->s[i]);
const char b = tolower(strb->s[i]);
if (a < b)
return -1;
if (a > b)
return 1;
}
return 0;
}
/*
* case-insensitive compare two str's
*/
static inline int str_strcasecmp(const str *stra, const str *strb)
{
int i;
int alen;
int blen;
int minlen;
if(stra==NULL || strb==NULL || stra->s ==NULL || strb->s==NULL
|| stra->len<0 || strb->len<0)
{
#ifdef EXTRA_DEBUG
LM_DBG("bad parameters\n");
#endif
return -2;
}
alen = stra->len;
blen = strb->len;
minlen = (alen < blen ? alen : blen);
for (i = 0; i < minlen; i++) {
const char a = tolower(stra->s[i]);
const char b = tolower(strb->s[i]);
if (a < b)
return -1;
if (a > b)
return 1;
}
if (alen < blen)
return -1;
else if (alen > blen)
return 1;
else
return 0;
}
#define start_expire_timer(begin,threshold) \
do { \
if (threshold) \
gettimeofday(&(begin), NULL); \
} while(0) \
#define __stop_expire_timer(begin,threshold,func_info, \
extra_s,extra_len,tcp,_slow_stat) \
do { \
if (threshold) { \
int __usdiff__ = get_time_diff(&(begin)); \
if (__usdiff__ > (threshold)) { \
log_expiry(__usdiff__,(threshold),(func_info), \
(extra_s),(extra_len),tcp); \
if (_slow_stat) \
inc_stat(_slow_stat); \
} \
} \
} while(0)
#define stop_expire_timer(begin,threshold,func_info,extra_s,extra_len,tcp) \
__stop_expire_timer(begin,threshold,func_info, \
extra_s,extra_len,tcp,(stat_var *)NULL)
#define _stop_expire_timer(begin,threshold,func_info,extra_s,extra_len,tcp, \
slow, total) \
do { \
__stop_expire_timer(begin,threshold,func_info, \
extra_s,extra_len,tcp,slow); \
if (total) \
inc_stat(total); \
} while (0)
extern int tcp_timeout_con_get;
extern int tcp_timeout_receive_fd;
extern int tcp_timeout_send;
#define reset_tcp_vars(threshold) \
do { \
if (threshold) \
{ \
tcp_timeout_con_get=0; \
tcp_timeout_receive_fd=0; \
tcp_timeout_send=0; \
} \
} while(0)
#define get_time_difference(begin,threshold,tcp_dbg) \
do { \
if ((threshold)) \
tcp_dbg = get_time_diff(&(begin)); \
} while(0)
/* Note: limited to a max time diff of 2147 * 10^6 useconds! */
static inline int get_time_diff(struct timeval *begin)
{
struct timeval end;
gettimeofday(&end, NULL);
/* difference is returned in microseconds */
return (long long)(end.tv_sec*1000000 + end.tv_usec)
- (long long)(begin->tv_sec*1000000 + begin->tv_usec);
}
static inline unsigned long long get_clock_diff(struct timespec *begin)
{
struct timespec end;
clock_gettime(CLOCK_REALTIME, &end);
return (end.tv_sec - begin->tv_sec) * 1000000000ULL
+ (end.tv_nsec - begin->tv_nsec);
}
#define __clock_check_diff(__loglv__, start_tmspec, maxdf, fmt, ...) \
do { \
unsigned long long _diff_ns = get_clock_diff(start_tmspec); \
if (_diff_ns > (maxdf)) \
LM_GEN(__loglv__, "time spent: %0.*lfs " fmt "\n", 3, \
(_diff_ns)/1e9, __VA_ARGS__); \
} while (0)
#define _clock_check_diff(start_tmspec, maxdf, fmt, ...) \
__clock_check_diff(L_NOTICE, start_tmspec, maxdf, fmt, __VA_ARGS__)
/**
* clock_check_diff() - measure code execution time relative to the @begin
* timespec; print notice msg if the difference was exceeded
* @maxdf (unsigned long long) - the maximum accepted execution time
* @fmt (char *) - extra format string + variable # of arguments
*/
#define clock_check_diff(maxdf, fmt, ...) \
_clock_check_diff(&begin, maxdf, fmt, __VA_ARGS__)
#define reset_longest_action_list(threshold) \
do { \
if ((threshold)) { \
min_action_time=0; \
memset(longest_action,0,LONGEST_ACTION_SIZE*sizeof(action_time)); \
} \
} while (0)
static inline void log_expiry(int time_diff,int expire,
const char *func_info,char *extra_dbg,int dbg_len,int tcp)
{
str param;
evi_params_p list;
static str func_str = str_init("source");
static str time_str = str_init("time");
static str extra_str = str_init("extra");
int i;
if (time_diff > expire)
{
if (tcp) {
LM_WARN("threshold exceeded : tcp took too long : "
"con_get=%d, rcv_fd=%d, send=%d. Source : %.*s\n",
tcp_timeout_con_get,tcp_timeout_receive_fd,
tcp_timeout_send,dbg_len,extra_dbg);
time_diff = tcp_timeout_send + tcp_timeout_receive_fd +
tcp_timeout_con_get;
} else
LM_WARN("threshold exceeded : %s took too long - %d us."
"Source : %.*s\n",func_info,time_diff,dbg_len,extra_dbg);
if (memcmp(func_info,"msg",3) == 0) {
for (i=0;i<LONGEST_ACTION_SIZE;i++) {
if (longest_action[i].a) {
if ((unsigned char)longest_action[i].a->type == CMD_T)
LM_WARN("#%i is a module action : %s - %dus - line %d\n",i+1,
((cmd_export_t*)(longest_action[i].a->elem[0].u.data))->name,
longest_action[i].a_time,longest_action[i].a->line);
else
LM_WARN("#%i is a core action : %d - %dus - line %d\n",i+1,
longest_action[i].a->type,
longest_action[i].a_time,longest_action[i].a->line);
}
}
}
if (evi_probe_event(EVI_THRESHOLD_ID)) {
param.s = (char *)func_info;
param.len = strlen(func_info);
if (!(list = evi_get_params()))
return;
if (evi_param_add_str(list, &func_str, ¶m)) {
LM_ERR("unable to add func parameter\n");
goto error;
}
if (evi_param_add_int(list, &time_str, &time_diff)) {
LM_ERR("unable to add time parameter\n");
goto error;
}
param.s = extra_dbg;
param.len = dbg_len;
if (evi_param_add_str(list, &extra_str, ¶m)) {
LM_ERR("unable to add extra parameter\n");
goto error;
}
if (evi_raise_event(EVI_THRESHOLD_ID, list)) {
LM_ERR("unable to send event\n");
}
} else {
LM_DBG("no event raised\n");
}
}
return;
error:
evi_free_params(list);
}
static inline int get_timestamp(int *sec,int *usec)
{
struct timeval t;
if (gettimeofday(&t,NULL) != 0)
{
LM_ERR("failed to get time of day\n");
return -1;
}
*sec = t.tv_sec;
*usec = t.tv_usec;
return 0;
}
/*
* checks if the string is a token as defined in rfc3261
* returns:
* -1 - if the string is invalid
* 1 - if the string is a token
* 0 - not a token
*/
static inline int str_check_token( str * in)
{
char *p;
if (!in || !in->s || !in->len)
return -1;
p = in->s + in->len;
while (p > in->s) {
p--;
if (!(
/* alphanum */
(*p >= 'a' && *p <= 'z') ||
(*p >= 'A' && *p <= 'Z') ||
(*p >= '0' && *p <= '9') ||
/* other */
*p == '-' || *p == '.' ||
*p == '!' || *p == '%' ||
*p == '*' || *p == '_' ||
*p == '+' || *p == '`' ||
*p == '\'' || *p == '~'
))
return 0;
}
return 1;
}
/*
* l_memmem() returns the location of the first occurrence of data
* pattern b2 of size len2 in memory block b1 of size len1 or
* NULL if none is found. Obtained from NetBSD.
*/
static inline void * l_memmem(const void *b1, const void *b2,
size_t len1, size_t len2)
{
/* Initialize search pointer */
char *sp = (char *) b1;
/* Initialize pattern pointer */
char *pp = (char *) b2;
/* Initialize end of search address space pointer */
char *eos = sp + len1 - len2;
/* Sanity check */
if(!(b1 && b2 && len1 && len2))
return NULL;
while (sp <= eos) {
if (*sp == *pp)
if (memcmp(sp, pp, len2) == 0)
return sp;
sp++;
}
return NULL;
}
/**
* Make any database URL log-friendly by masking its password, if any
* Note: makes use of a single, static buffer -- use accordingly!
*/
char *db_url_escape(const str *url);
static inline char *_db_url_escape(const char *url)
{
return db_url_escape(_str(url));
}
int user2uid(int* uid, int* gid, char* user);
int group2gid(int* gid, char* group);
char * NTcopy_str( str *s );
/* utility function to give each children a unique seed */
void seed_child(unsigned int seed);
int parse_reply_codes( str *options_reply_codes_str,
int **options_reply_codes, int *options_codes_no);
void base64encode(unsigned char *out, unsigned char *in, int inlen);
int base64decode(unsigned char *out,unsigned char *in,int len);
void base64urlencode(unsigned char *out, unsigned char *in, int inlen);
int base64urldecode(unsigned char *out,unsigned char *in,int len);
/*
* "word64" is a combination between:
* - RFC 3261-compatible "word" token characters
* - modulo-64 encoding of base64
*/
void word64encode(unsigned char *out, unsigned char *in, int inlen);
int word64decode(unsigned char *out, unsigned char *in, int len);
void _base32encode(unsigned char *out, unsigned char *in, int inlen,
unsigned char pad_char);
int _base32decode(unsigned char *out, unsigned char *in, int len,
unsigned char pad_char);
#define base32encode(out, in, inlen) _base32encode(out, in, inlen, '=')
/* also accepts lowercase letters as equivalent encoding characters
* of uppercase letters */
#define base32decode(out, in, len) _base32decode(out, in, len, '=')
/* same as base32 but uses '-' instead of '=' as pad character */
#define word32encode(out, in, inlen) _base32encode(out, in, inlen, '-')
#define word32decode(out, in, len) _base32decode(out, in, len, '-')
#define calc_base64_encode_len(_l) (((_l)/3 + ((_l)%3?1:0))*4)
#define calc_max_base64_decode_len(_l) ((_l)*3/4)
#define calc_word64_encode_len calc_base64_encode_len
#define calc_max_word64_decode_len calc_max_base64_decode_len
#define calc_base32_encode_len(_l) (((_l)/5 + ((_l)%5?1:0))*8)
#define calc_max_base32_decode_len(_l) ((_l)*5/8)
#define calc_word32_encode_len calc_base32_encode_len
#define calc_max_word32_decode_len calc_max_base32_decode_len
#ifdef howmany
#undef howmany
#endif
#define howmany(x, y) (sizeof(x) / sizeof(y))
#endif
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。