Example #1
0
/*!
 * \brief Convert database values into ucontact_info
 *
 * Convert database values into ucontact_info, 
 * expects 12 rows (contact, expirs, q, callid, cseq, flags,
 * ua, received, path, socket, methods, last_modified)
 * \param vals database values
 * \param contact contact
 * \return pointer to the ucontact_info on success, 0 on failure
 */
static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact)
{
	static ucontact_info_t ci;
	static str callid, ua, received, host, path;
	int port, proto;
	char *p;

	memset( &ci, 0, sizeof(ucontact_info_t));

	contact->s = (char*)VAL_STRING(vals);
	if (VAL_NULL(vals) || contact->s==0 || contact->s[0]==0) {
		LM_CRIT("bad contact\n");
		return 0;
	}
	contact->len = strlen(contact->s);

	if (VAL_NULL(vals+1)) {
		LM_CRIT("empty expire\n");
		return 0;
	}
	ci.expires = VAL_TIME(vals+1);

	if (VAL_NULL(vals+2)) {
		LM_CRIT("empty q\n");
		return 0;
	}
	ci.q = double2q(VAL_DOUBLE(vals+2));

	if (VAL_NULL(vals+4)) {
		LM_CRIT("empty cseq_nr\n");
		return 0;
	}
	ci.cseq = VAL_INT(vals+4);

	callid.s = (char*)VAL_STRING(vals+3);
	if (VAL_NULL(vals+3) || !callid.s || !callid.s[0]) {
		LM_CRIT("bad callid\n");
		return 0;
	}
	callid.len  = strlen(callid.s);
	ci.callid = &callid;

	if (VAL_NULL(vals+5)) {
		LM_CRIT("empty flag\n");
		return 0;
	}
	ci.flags  = VAL_BITMAP(vals+5);

	if (VAL_NULL(vals+6)) {
		LM_CRIT("empty cflag\n");
		return 0;
	}
	ci.cflags  = VAL_BITMAP(vals+6);

	ua.s  = (char*)VAL_STRING(vals+7);
	if (VAL_NULL(vals+7) || !ua.s || !ua.s[0]) {
		ua.s = 0;
		ua.len = 0;
	} else {
		ua.len = strlen(ua.s);
	}
	ci.user_agent = &ua;

	received.s  = (char*)VAL_STRING(vals+8);
	if (VAL_NULL(vals+8) || !received.s || !received.s[0]) {
		received.len = 0;
		received.s = 0;
	} else {
		received.len = strlen(received.s);
	}
	ci.received = received;
	
	path.s  = (char*)VAL_STRING(vals+9);
		if (VAL_NULL(vals+9) || !path.s || !path.s[0]) {
			path.len = 0;
			path.s = 0;
		} else {
			path.len = strlen(path.s);
		}
	ci.path= &path;

	/* socket name */
	p  = (char*)VAL_STRING(vals+10);
	if (VAL_NULL(vals+10) || p==0 || p[0]==0){
		ci.sock = 0;
	} else {
		if (parse_phostport( p, &host.s, &host.len,
				&port, &proto)!=0){
			LM_ERR("bad socket <%s>\n", p);
			return 0;
		}
		ci.sock = grep_sock_info( &host, (unsigned short)port, proto);
		if (ci.sock==0) {
			LM_INFO("non-local socket <%s>...ignoring\n", p);
		}
	}

	/* supported methods */
	if (VAL_NULL(vals+11)) {
		ci.methods = ALL_METHODS;
	} else {
		ci.methods = VAL_BITMAP(vals+11);
	}

	/* last modified time */
	if (!VAL_NULL(vals+12)) {
		ci.last_modified = VAL_TIME(vals+12);
	}

	/* record internal uid */
	if (!VAL_NULL(vals+13)) {
		ci.ruid.s = (char*)VAL_STRING(vals+13);
		ci.ruid.len = strlen(ci.ruid.s);
	}

	/* sip instance */
	if (!VAL_NULL(vals+14)) {
		ci.instance.s = (char*)VAL_STRING(vals+14);
		ci.instance.len = strlen(ci.instance.s);
	}

	/* reg-id */
	if (!VAL_NULL(vals+15)) {
		ci.reg_id = VAL_UINT(vals+15);
	}

	return &ci;
}
Example #2
0
/* buf= pointer to beginning of uri (sip:[email protected]:5060;a=b?h=i)
 * len= len of uri
 * returns: fills uri & returns <0 on error or 0 if ok
 */
int parse_uri(char* buf, int len, struct sip_uri* uri)
{
	enum states  {	URI_INIT, URI_USER, URI_PASSWORD, URI_PASSWORD_ALPHA,
					URI_HOST, URI_HOST_P,
					URI_HOST6_P, URI_HOST6_END, URI_PORT,
					URI_PARAM, URI_PARAM_P, URI_PARAM_VAL_P,
					URI_VAL_P, URI_HEADERS,
					/* param states */
					/* transport */
					PT_T, PT_R, PT_A, PT_N, PT_S, PT_P, PT_O, PT_R2, PT_T2,
					PT_eq,
					/* ttl */
					PTTL_T2, PTTL_L, PTTL_eq,
					/* user */
					PU_U, PU_S, PU_E, PU_R, PU_eq,
					/* method */
					PM_M, PM_E, PM_T, PM_H, PM_O, PM_D, PM_eq,
					/* maddr */
					PMA_A, PMA_D, PMA_D2, PMA_R, PMA_eq,
					/* lr */
					PLR_L, PLR_R_FIN, PLR_eq,
					/* gr */
					PG_G, PG_G_FIN, PG_eq,
					/* r2 */
					PR2_R, PR2_2_FIN, PR2_eq,
					/* transport values */
					/* udp */
					VU_U, VU_D, VU_P_FIN,
					/* tcp */
					VT_T, VT_C, VT_P_FIN,
					/* tls */
					VTLS_L, VTLS_S_FIN,
					/* sctp */
					VS_S, VS_C, VS_T, VS_P_FIN,
					/* ws */
					VW_W, VW_S, VW_S_FIN, VWS_S_FIN
	};
	register enum states state;
	char* s;
	char* b; /* param start */
	char *v; /* value start */
	str* param; /* current param */
	str* param_val; /* current param val */
	str user;
	str password;
	int port_no;
	register char* p;
	char* end;
	char* pass;
	int found_user;
	int error_headers;
	unsigned int scheme;
	uri_type backup;
#ifdef EXTRA_DEBUG
	int i;
#endif

#define SIP_SCH			0x3a706973
#define SIPS_SCH		0x73706973
#define TEL_SCH			0x3a6c6574
#define URN_SERVICE_SCH		0x3a6e7275
#define URN_SERVICE_STR 	":service:"
#define URN_SERVICE_STR_LEN	(sizeof(URN_SERVICE_STR) - 1)

#define case_port( ch, var) \
	case ch: \
			 (var)=(var)*10+ch-'0'; \
			 break

#define still_at_user  \
						if (found_user==0){ \
							user.s=uri->host.s; \
							if (pass){\
								user.len=pass-user.s; \
								password.s=pass+1; \
								password.len=p-password.s; \
							}else{ \
								user.len=p-user.s; \
							}\
							/* save the uri type/scheme */ \
							backup=uri->type; \
							/* everything else is 0 */ \
							memset(uri, 0, sizeof(struct sip_uri)); \
							/* restore the scheme, copy user & pass */ \
							uri->type=backup; \
							uri->user=user; \
							if (pass)	uri->passwd=password;  \
							s=p+1; \
							found_user=1;\
							error_headers=0; \
							state=URI_HOST; \
						}else goto error_bad_char

#define check_host_end \
					case ':': \
						/* found the host */ \
						uri->host.s=s; \
						uri->host.len=p-s; \
						state=URI_PORT; \
						s=p+1; \
						break; \
					case ';': \
						uri->host.s=s; \
						uri->host.len=p-s; \
						state=URI_PARAM; \
						s=p+1; \
						break; \
					case '?': \
						uri->host.s=s; \
						uri->host.len=p-s; \
						state=URI_HEADERS; \
						s=p+1; \
						break; \
					case '&': \
					case '@': \
						goto error_bad_char


#define param_set(t_start, v_start) \
					param->s=(t_start);\
					param->len=(p-(t_start));\
					param_val->s=(v_start); \
					param_val->len=(p-(v_start))

#define u_param_set(t_start, v_start) \
			if (uri->u_params_no < URI_MAX_U_PARAMS){ \
				if((v_start)>(t_start)){ \
					uri->u_name[uri->u_params_no].s=(t_start); \
					uri->u_name[uri->u_params_no].len=((v_start)-(t_start)-1); \
					if(p>(v_start)) { \
						uri->u_val[uri->u_params_no].s=(v_start); \
						uri->u_val[uri->u_params_no].len=(p-(v_start)); \
					} \
				} else { \
					uri->u_name[uri->u_params_no].s=(t_start); \
					uri->u_name[uri->u_params_no].len=(p-(t_start)); \
				} \
				uri->u_params_no++; \
			} else { \
				LM_ERR("unknown URI param list excedeed\n"); \
			}

#define semicolon_case \
					case';': \
						if (pass){ \
							found_user=1;/* no user, pass cannot contain ';'*/ \
							pass=0; \
						} \
						state=URI_PARAM   /* new param */

#define question_case \
					case '?': \
						uri->params.s=s; \
						uri->params.len=p-s; \
						state=URI_HEADERS; \
						s=p+1; \
						if (pass){ \
							found_user=1;/* no user, pass cannot contain '?'*/ \
							pass=0; \
						}

#define colon_case \
					case ':': \
						if (found_user==0){ \
							/*might be pass but only if user not found yet*/ \
							if (pass){ \
								found_user=1; /* no user */ \
								pass=0; \
							}else{ \
								pass=p; \
							} \
						} \
						state=URI_PARAM_P /* generic param */

#define param_common_cases \
					case '@': \
						/* ughhh, this is still the user */ \
						still_at_user; \
						break; \
					semicolon_case; \
						break; \
					question_case; \
						break; \
					colon_case; \
						break

#define u_param_common_cases \
					case '@': \
						/* ughhh, this is still the user */ \
						still_at_user; \
						break; \
					semicolon_case; \
						u_param_set(b, v); \
						break; \
					question_case; \
						u_param_set(b, v); \
						break; \
					colon_case; \
						break

#define value_common_cases \
					case '@': \
						/* ughhh, this is still the user */ \
						still_at_user; \
						break; \
					semicolon_case; \
						param_set(b, v); \
						break; \
					question_case; \
						param_set(b, v); \
						break; \
					colon_case; \
						state=URI_VAL_P; \
						break

#define param_switch(old_state, c1, c2, new_state) \
			case old_state: \
				switch(*p){ \
					case c1: \
					case c2: \
						state=(new_state); \
						break; \
					u_param_common_cases; \
					default: \
						state=URI_PARAM_P; \
				} \
				break
#define param_switch1(old_state, c1, new_state) \
			case old_state: \
				switch(*p){ \
					case c1: \
						state=(new_state); \
						break; \
					param_common_cases; \
					default: \
						state=URI_PARAM_P; \
				} \
				break
#define param_switch_big(old_state, c1, c2, d1, d2, new_state_c, new_state_d) \
			case old_state : \
				switch(*p){ \
					case c1: \
					case c2: \
						state=(new_state_c); \
						break; \
					case d1: \
					case d2: \
						state=(new_state_d); \
						break; \
					u_param_common_cases; \
					default: \
						state=URI_PARAM_P; \
				} \
				break
#define value_switch(old_state, c1, c2, new_state) \
			case old_state: \
				switch(*p){ \
					case c1: \
					case c2: \
						state=(new_state); \
						break; \
					value_common_cases; \
					default: \
						state=URI_VAL_P; \
				} \
				break
#define value_switch_big(old_state, c1, c2, d1, d2, new_state_c, new_state_d) \
			case old_state: \
				switch(*p){ \
					case c1: \
					case c2: \
						state=(new_state_c); \
						break; \
					case d1: \
					case d2: \
						state=(new_state_d); \
						break; \
					value_common_cases; \
					default: \
						state=URI_VAL_P; \
				} \
				break

#define transport_fin(c_state, proto_no) \
			case c_state: \
				switch(*p){ \
					case '@': \
						still_at_user; \
						break; \
					semicolon_case; \
						param_set(b, v); \
						uri->proto=(proto_no); \
						break; \
					question_case; \
						param_set(b, v); \
						uri->proto=(proto_no); \
						break; \
					colon_case;  \
					default: \
						state=URI_VAL_P; \
						break; \
				} \
				break



	/* init */
	end=buf+len;
	p=buf+4;
	found_user=0;
	error_headers=0;
	b=v=0;
	param=param_val=0;
	pass=0;
	password.s = 0;
	password.len = 0;
	port_no=0;
	state=URI_INIT;
	memset(uri, 0, sizeof(struct sip_uri)); /* zero it all, just to be sure*/
	/*look for sip:, sips: or tel:*/
	if (len<5) goto error_too_short;
	scheme=buf[0]+(buf[1]<<8)+(buf[2]<<16)+(buf[3]<<24);
	scheme|=0x20202020;
	if (scheme==SIP_SCH){
		uri->type=SIP_URI_T;
	}else if(scheme==SIPS_SCH){
		if(buf[4]==':'){ p++; uri->type=SIPS_URI_T;}
		else goto error_bad_uri;
	}else if (scheme==TEL_SCH){
		uri->type=TEL_URI_T;
	}else if (scheme==URN_SERVICE_SCH){
		if (memcmp(buf+3,URN_SERVICE_STR,URN_SERVICE_STR_LEN) == 0) {
			p+= URN_SERVICE_STR_LEN-1;
			uri->type=URN_SERVICE_URI_T;
		} else goto error_bad_uri;
	}else goto error_bad_uri;

	s=p;
	for(;p<end; p++){
		switch((unsigned char)state){
			case URI_INIT:
				switch(*p){
					case '[':
						/* uri =  [ipv6address]... */
						state=URI_HOST6_P;
						s=p;
						break;
					case ']':
						/* invalid, no uri can start with ']' */
					case ':':
						/* the same as above for ':' */
						goto error_bad_char;
					case '@': /* error no user part */
						goto error_bad_char;
					default:
						state=URI_USER;
				}
				break;
			case URI_USER:
				switch(*p){
					case '@':
						/* found the user*/
						uri->user.s=s;
						uri->user.len=p-s;
						state=URI_HOST;
						found_user=1;
						s=p+1; /* skip '@' */
						break;
					case ':':
						/* found the user, or the host? */
						uri->user.s=s;
						uri->user.len=p-s;
						state=URI_PASSWORD;
						s=p+1; /* skip ':' */
						break;
					case ';':
						/* this could be still the user or
						 * params?*/
						uri->host.s=s;
						uri->host.len=p-s;
						state=URI_PARAM;
						s=p+1;
						break;
					case '?': /* still user or headers? */
						uri->host.s=s;
						uri->host.len=p-s;
						state=URI_HEADERS;
						s=p+1;
						break;
						/* almost anything permitted in the user part */
					case '[':
					case ']': /* the user part cannot contain "[]" */
						goto error_bad_char;
				}
				break;
			case URI_PASSWORD: /* this can also be the port (missing user)*/
				switch(*p){
					case '@':
						/* found the password*/
						uri->passwd.s=s;
						uri->passwd.len=p-s;
						port_no=0;
						state=URI_HOST;
						found_user=1;
						s=p+1; /* skip '@' */
						break;
					case ';':
						/* upps this is the port */
						uri->port.s=s;
						uri->port.len=p-s;
						uri->port_no=port_no;
						/* user contains in fact the host */
						uri->host.s=uri->user.s;
						uri->host.len=uri->user.len;
						uri->user.s=0;
						uri->user.len=0;
						state=URI_PARAM;
						found_user=1; /*  there is no user part */
						s=p+1;
						break;
					case '?':
						/* upps this is the port */
						uri->port.s=s;
						uri->port.len=p-s;
						uri->port_no=port_no;
						/* user contains in fact the host */
						uri->host.s=uri->user.s;
						uri->host.len=uri->user.len;
						uri->user.s=0;
						uri->user.len=0;
						state=URI_HEADERS;
						found_user=1; /*  there is no user part */
						s=p+1;
						break;
					case_port('0', port_no);
					case_port('1', port_no);
					case_port('2', port_no);
					case_port('3', port_no);
					case_port('4', port_no);
					case_port('5', port_no);
					case_port('6', port_no);
					case_port('7', port_no);
					case_port('8', port_no);
					case_port('9', port_no);
					case '[':
					case ']':
					case ':':
						goto error_bad_char;
					default:
						/* it can't be the port, non number found */
						port_no=0;
						state=URI_PASSWORD_ALPHA;
				}
				break;
			case URI_PASSWORD_ALPHA:
				switch(*p){
					case '@':
						/* found the password*/
						uri->passwd.s=s;
						uri->passwd.len=p-s;
						state=URI_HOST;
						found_user=1;
						s=p+1; /* skip '@' */
						break;
					case ';': /* contains non-numbers => cannot be port no*/
					case '?':
						goto error_bad_port;
					case '[':
					case ']':
					case ':':
						goto error_bad_char;
				}
				break;
			case URI_HOST:
				switch(*p){
					case '[':
						state=URI_HOST6_P;
						break;
					case ':':
					case ';':
					case '?': /* null host name ->invalid */
					case '&':
					case '@': /*chars not allowed in hosts names */
						goto error_bad_host;
					default:
						state=URI_HOST_P;
				}
				break;
			case URI_HOST_P:
				switch(*p){
					check_host_end;
				}
				break;
			case URI_HOST6_END:
				switch(*p){
					check_host_end;
					default: /*no chars allowed after [ipv6] */
						goto error_bad_host;
				}
				break;
			case URI_HOST6_P:
				switch(*p){
					case ']':
						state=URI_HOST6_END;
						break;
					case '[':
					case '&':
					case '@':
					case ';':
					case '?':
						goto error_bad_host;
				}
				break;
			case URI_PORT:
				switch(*p){
					case ';':
						uri->port.s=s;
						uri->port.len=p-s;
						uri->port_no=port_no;
						state=URI_PARAM;
						s=p+1;
						break;
					case '?':
						uri->port.s=s;
						uri->port.len=p-s;
						uri->port_no=port_no;
						state=URI_HEADERS;
						s=p+1;
						break;
					case_port('0', port_no);
					case_port('1', port_no);
					case_port('2', port_no);
					case_port('3', port_no);
					case_port('4', port_no);
					case_port('5', port_no);
					case_port('6', port_no);
					case_port('7', port_no);
					case_port('8', port_no);
					case_port('9', port_no);
					case '&':
					case '@':
					case ':':
					default:
						goto error_bad_port;
				}
				break;
			case URI_PARAM: /* beginning of a new param */
				switch(*p){
					param_common_cases;
					/* recognized params */
					case 't':
					case 'T':
						b=p;
						state=PT_T;
						break;
					case 'u':
					case 'U':
						b=p;
						state=PU_U;
						break;
					case 'm':
					case 'M':
						b=p;
						state=PM_M;
						break;
					case 'l':
					case 'L':
						b=p;
						state=PLR_L;
						break;
					case 'g':
					case 'G':
						b=p;
						state=PG_G;
						break;
					case 'r':
					case 'R':
						b=p;
						state=PR2_R;
						break;
					default:
						b=p;
						state=URI_PARAM_P;
				}
				break;
			case URI_PARAM_P: /* ignore current param */
				/* supported params:
				 *  maddr, transport, ttl, lr, user, method, r2  */
				switch(*p){
					u_param_common_cases;
					case '=':
						v=p + 1;
						state=URI_PARAM_VAL_P;
						break;
				};
				break;
			case URI_PARAM_VAL_P: /* value of the ignored current param */
				switch(*p){
					u_param_common_cases;
				};
				break;
			/* ugly but fast param names parsing */
			/*transport */
			param_switch_big(PT_T,  'r', 'R', 't', 'T', PT_R, PTTL_T2);
			param_switch(PT_R,  'a', 'A', PT_A);
			param_switch(PT_A,  'n', 'N', PT_N);
			param_switch(PT_N,  's', 'S', PT_S);
			param_switch(PT_S,  'p', 'P', PT_P);
			param_switch(PT_P,  'o', 'O', PT_O);
			param_switch(PT_O,  'r', 'R', PT_R2);
			param_switch(PT_R2, 't', 'T', PT_T2);
			param_switch1(PT_T2, '=',  PT_eq);
			/* value parsing */
			case PT_eq:
				param=&uri->transport;
				param_val=&uri->transport_val;
				uri->proto = PROTO_OTHER;
				switch (*p){
					param_common_cases;
					case 'u':
					case 'U':
						v=p;
						state=VU_U;
						break;
					case 't':
					case 'T':
						v=p;
						state=VT_T;
						break;
					case 's':
					case 'S':
						v=p;
						state=VS_S;
						break;
					case 'w':
					case 'W':
						v=p;
						state=VW_W;
						break;
					default:
						v=p;
						state=URI_VAL_P;
				}
				break;
				/* generic value */
			case URI_VAL_P:
				switch(*p){
					value_common_cases;
				}
				break;
			/* udp */
			value_switch(VU_U,  'd', 'D', VU_D);
			value_switch(VU_D,  'p', 'P', VU_P_FIN);
			transport_fin(VU_P_FIN, PROTO_UDP);
			/* tcp */
			value_switch_big(VT_T,  'c', 'C', 'l', 'L', VT_C, VTLS_L);
			value_switch(VT_C,  'p', 'P', VT_P_FIN);
			transport_fin(VT_P_FIN, PROTO_TCP);
			/* tls */
			value_switch(VTLS_L, 's', 'S', VTLS_S_FIN);
			transport_fin(VTLS_S_FIN, PROTO_TLS);
			/* sctp */
			value_switch(VS_S, 'c', 'C', VS_C);
			value_switch(VS_C, 't', 'T', VS_T);
			value_switch(VS_T, 'p', 'P', VS_P_FIN);
			transport_fin(VS_P_FIN, PROTO_SCTP);
			/* ws */
			value_switch(VW_W, 's', 'S', VW_S);
			case VW_S:
				if (*p == 's' || *p == 'S') {
					state=(VWS_S_FIN);
					break;
				}
				/* if not a 's' transiting to VWS_S_FIN, fallback
				 * to testing as existing VW_S_FIN (NOTE the missing break) */
				state=(VW_S_FIN);
			transport_fin(VW_S_FIN, PROTO_WS);
			transport_fin(VWS_S_FIN, PROTO_WSS);

			/* ttl */
			param_switch(PTTL_T2,  'l', 'L', PTTL_L);
			param_switch1(PTTL_L,  '=', PTTL_eq);
			case PTTL_eq:
				param=&uri->ttl;
				param_val=&uri->ttl_val;
				switch(*p){
					param_common_cases;
					default:
						v=p;
						state=URI_VAL_P;
				}
				break;

			/* user param */
			param_switch(PU_U, 's', 'S', PU_S);
			param_switch(PU_S, 'e', 'E', PU_E);
			param_switch(PU_E, 'r', 'R', PU_R);
			param_switch1(PU_R, '=', PU_eq);
			case PU_eq:
				param=&uri->user_param;
				param_val=&uri->user_param_val;
				switch(*p){
					param_common_cases;
					default:
						v=p;
						state=URI_VAL_P;
				}
				break;

			/* method*/
			param_switch_big(PM_M, 'e', 'E', 'a', 'A', PM_E, PMA_A);
			param_switch(PM_E, 't', 'T', PM_T);
			param_switch(PM_T, 'h', 'H', PM_H);
			param_switch(PM_H, 'o', 'O', PM_O);
			param_switch(PM_O, 'd', 'D', PM_D);
			param_switch1(PM_D, '=', PM_eq);
			case PM_eq:
				param=&uri->method;
				param_val=&uri->method_val;
				switch(*p){
					param_common_cases;
					default:
						v=p;
						state=URI_VAL_P;
				}
				break;

			/*maddr*/
			param_switch(PMA_A,  'd', 'D', PMA_D);
			param_switch(PMA_D,  'd', 'D', PMA_D2);
			param_switch(PMA_D2, 'r', 'R', PMA_R);
			param_switch1(PMA_R, '=', PMA_eq);
			case PMA_eq:
				param=&uri->maddr;
				param_val=&uri->maddr_val;
				switch(*p){
					param_common_cases;
					default:
						v=p;
						state=URI_VAL_P;
				}
				break;

			/* lr */
			param_switch(PLR_L,  'r', 'R', PLR_R_FIN);
			case PLR_R_FIN:
				switch(*p){
					case '@':
						still_at_user;
						break;
					case '=':
						state=PLR_eq;
						break;
					semicolon_case;
						uri->lr.s=b;
						uri->lr.len=(p-b);
						break;
					question_case;
						uri->lr.s=b;
						uri->lr.len=(p-b);
						break;
					colon_case;
						break;
					default:
						state=URI_PARAM_P;
				}
				break;
				/* handle lr=something case */
			case PLR_eq:
				param=&uri->lr;
				param_val=&uri->lr_val;
				switch(*p){
					param_common_cases;
					default:
						v=p;
						state=URI_VAL_P;
				}
				break;

			/* r2 */
			param_switch1(PR2_R,  '2', PR2_2_FIN);
			case PR2_2_FIN:
				switch(*p){
					case '@':
						still_at_user;
						break;
					case '=':
						state=PR2_eq;
						break;
					semicolon_case;
						uri->r2.s=b;
						uri->r2.len=(p-b);
						break;
					question_case;
						uri->r2.s=b;
						uri->r2.len=(p-b);
						break;
					colon_case;
						break;
					default:
						state=URI_PARAM_P;
				}
				break;
				/* handle lr=something case */
			case PR2_eq:
				param=&uri->r2;
				param_val=&uri->r2_val;
				switch(*p){
					param_common_cases;
					default:
						v=p;
						state=URI_VAL_P;
				}
				break;


			/* gr */
			param_switch(PG_G,  'r', 'R', PG_G_FIN);
			case PG_G_FIN:
				switch(*p){
					case '@':
						still_at_user;
						break;
					case '=':
						state=PG_eq;
						break;
					semicolon_case;
						uri->gr.s=b;
						uri->gr.len=(p-b);
						break;
					question_case;
						uri->gr.s=b;
						uri->gr.len=(p-b);
						break;
					colon_case;
						break;
					default:
						state=URI_PARAM_P;
				}
				break;
				/* handle gr=something case */
			case PG_eq:
				param=&uri->gr;
				param_val=&uri->gr_val;
				switch(*p){
					param_common_cases;
					default:
						v=p;
						state=URI_VAL_P;
				}
				break;


			case URI_HEADERS:
				/* for now nobody needs them so we completely ignore the
				 * headers (they are not allowed in request uri) --andrei */
				switch(*p){
					case '@':
						/* yak, we are still at user */
						still_at_user;
						break;
					case ';':
						/* we might be still parsing user, try it */
						if (found_user) goto error_bad_char;
						error_headers=1; /* if this is not the user
											we have an error */
						/* if pass is set => it cannot be user:pass
						 * => error (';') is illegal in a header */
						if (pass) goto error_headers;
						break;
					case ':':
						if (found_user==0){
							/*might be pass but only if user not found yet*/
							if (pass){
								found_user=1; /* no user */
								pass=0;
							}else{
								pass=p;
							}
						}
						break;
					case '?':
						if (pass){
							found_user=1; /* no user, pass cannot contain '?'*/
							pass=0;
						}
						break;
				}
				break;
			default:
				goto error_bug;
		}
	}

	/*end of uri */
	switch (state){
		case URI_INIT: /* error empty uri */
			goto error_too_short;
		case URI_USER:
			/* this is the host, it can't be the user */
			if (found_user) goto error_bad_uri;
			uri->host.s=s;
			uri->host.len=p-s;
			state=URI_HOST;
			break;
		case URI_PASSWORD:
			/* this is the port, it can't be the passwd */
			if (found_user) goto error_bad_port;
			uri->port.s=s;
			uri->port.len=p-s;
			uri->port_no=port_no;
			uri->host=uri->user;
			uri->user.s=0;
			uri->user.len=0;
			break;
		case URI_PASSWORD_ALPHA:
			/* this is the port, it can't be the passwd */
			goto error_bad_port;
		case URI_HOST_P:
		case URI_HOST6_END:
			uri->host.s=s;
			uri->host.len=p-s;
			break;
		case URI_HOST: /* error: null host */
		case URI_HOST6_P: /* error: unterminated ipv6 reference*/
			goto error_bad_host;
		case URI_PORT:
			uri->port.s=s;
			uri->port.len=p-s;
			uri->port_no=port_no;
			break;
		case URI_PARAM:
		case URI_PARAM_P:
		case URI_PARAM_VAL_P:
			u_param_set(b, v);
		/* intermediate param states */
		case PT_T: /* transport */
		case PT_R:
		case PT_A:
		case PT_N:
		case PT_S:
		case PT_P:
		case PT_O:
		case PT_R2:
		case PT_T2:
		case PT_eq: /* ignore empty transport params */
		case PTTL_T2: /* ttl */
		case PTTL_L:
		case PTTL_eq:
		case PU_U:  /* user */
		case PU_S:
		case PU_E:
		case PU_R:
		case PU_eq:
		case PM_M: /* method */
		case PM_E:
		case PM_T:
		case PM_H:
		case PM_O:
		case PM_D:
		case PM_eq:
		case PLR_L: /* lr */
		case PR2_R:  /* r2 */
		case PG_G: /* gr */
			uri->params.s=s;
			uri->params.len=p-s;
			break;
		/* fin param states */
		case PLR_R_FIN:
		case PLR_eq:
			uri->params.s=s;
			uri->params.len=p-s;
			uri->lr.s=b;
			uri->lr.len=p-b;
			break;
		case PR2_2_FIN:
		case PR2_eq:
			uri->params.s=s;
			uri->params.len=p-s;
			uri->r2.s=b;
			uri->r2.len=p-b;
			break;
		case PG_G_FIN:
		case PG_eq:
			uri->params.s=s;
			uri->params.len=p-s;
			uri->gr.s=b;
			uri->gr.len=p-b;
			break;
		case URI_VAL_P:
		/* intermediate value states */
		case VU_U:
		case VU_D:
		case VT_T:
		case VT_C:
		case VTLS_L:
		case VS_S:
		case VS_C:
		case VW_W:
		case VS_T:
			uri->params.s=s;
			uri->params.len=p-s;
			param_set(b, v);
			break;
		/* fin value states */
		case VU_P_FIN:
			uri->params.s=s;
			uri->params.len=p-s;
			param_set(b, v);
			uri->proto=PROTO_UDP;
			break;
		case VT_P_FIN:
			uri->params.s=s;
			uri->params.len=p-s;
			param_set(b, v);
			uri->proto=PROTO_TCP;
			break;
		case VTLS_S_FIN:
			uri->params.s=s;
			uri->params.len=p-s;
			param_set(b, v);
			uri->proto=PROTO_TLS;
			break;
		case VS_P_FIN:
			uri->params.s=s;
			uri->params.len=p-s;
			param_set(b, v);
			uri->proto=PROTO_SCTP;
			break;
		case VW_S:
		case VW_S_FIN:
			uri->params.s=s;
			uri->params.len=p-s;
			param_set(b, v);
			uri->proto=PROTO_WS;
			break;
		case VWS_S_FIN:
			uri->params.s=s;
			uri->params.len=p-s;
			param_set(b, v);
			uri->proto=PROTO_WSS;
			break;
		/* headers */
		case URI_HEADERS:
			uri->headers.s=s;
			uri->headers.len=p-s;
			if (error_headers) goto error_headers;
			break;
		default:
			goto error_bug;
	}
	switch(uri->type){
		case SIP_URI_T:
			if ((uri->user_param_val.len == 5) &&
				(strncasecmp(uri->user_param_val.s, "phone", 5) == 0)) {
				uri->type = TEL_URI_T;
				/* move params from user into uri->params */
				p=q_memchr(uri->user.s, ';', uri->user.len);
				if (p){
					uri->params.s=p+1;
					uri->params.len=uri->user.s+uri->user.len-uri->params.s;
					uri->user.len=p-uri->user.s;
				}
			}
			break;
		case SIPS_URI_T:
			if ((uri->user_param_val.len == 5) &&
				(strncasecmp(uri->user_param_val.s, "phone", 5) == 0)) {
				uri->type = TELS_URI_T;
				p=q_memchr(uri->user.s, ';', uri->user.len);
				if (p){
					uri->params.s=p+1;
					uri->params.len=uri->user.s+uri->user.len-uri->params.s;
					uri->user.len=p-uri->user.s;
				}
			}
			break;
		case TEL_URI_T:
		case TELS_URI_T:
			/* fix tel uris, move the number in uri and empty the host */
			uri->user=uri->host;
			uri->host.s="";
			uri->host.len=0;
			break;
		case URN_SERVICE_URI_T:
			/* leave the actual service name in the URI domain part */
			break;
		case ERROR_URI_T:
			LM_ERR("unexpected error (BUG?)\n");
			goto error_bad_uri;
			break; /* do nothing, avoids a compilation warning */
	}
#ifdef EXTRA_DEBUG
	/* do stuff */
	LM_DBG("parsed uri:\n type=%d user=<%.*s>(%d)\n passwd=<%.*s>(%d)\n"
			" host=<%.*s>(%d)\n port=<%.*s>(%d): %d\n params=<%.*s>(%d)\n"
			" headers=<%.*s>(%d)\n",
			uri->type,
			uri->user.len, ZSW(uri->user.s), uri->user.len,
			uri->passwd.len, ZSW(uri->passwd.s), uri->passwd.len,
			uri->host.len, ZSW(uri->host.s), uri->host.len,
			uri->port.len, ZSW(uri->port.s), uri->port.len, uri->port_no,
			uri->params.len, ZSW(uri->params.s), uri->params.len,
			uri->headers.len, ZSW(uri->headers.s), uri->headers.len
		);
	LM_DBG(" uri params:\n   transport=<%.*s>, val=<%.*s>, proto=%d\n",
			uri->transport.len, ZSW(uri->transport.s), uri->transport_val.len,
			ZSW(uri->transport_val.s), uri->proto);
	LM_DBG("   user-param=<%.*s>, val=<%.*s>\n",
			uri->user_param.len, ZSW(uri->user_param.s),
			uri->user_param_val.len, ZSW(uri->user_param_val.s));
	LM_DBG("   method=<%.*s>, val=<%.*s>\n",
			uri->method.len, ZSW(uri->method.s),
			uri->method_val.len, ZSW(uri->method_val.s));
	LM_DBG("   ttl=<%.*s>, val=<%.*s>\n",
			uri->ttl.len, ZSW(uri->ttl.s),
			uri->ttl_val.len, ZSW(uri->ttl_val.s));
	LM_DBG("   maddr=<%.*s>, val=<%.*s>\n",
			uri->maddr.len, ZSW(uri->maddr.s),
			uri->maddr_val.len, ZSW(uri->maddr_val.s));
	LM_DBG("   lr=<%.*s>, val=<%.*s>\n", uri->lr.len, ZSW(uri->lr.s),
			uri->lr_val.len, ZSW(uri->lr_val.s));
	LM_DBG("   r2=<%.*s>, val=<%.*s>\n", uri->r2.len, ZSW(uri->r2.s),
			uri->r2_val.len, ZSW(uri->r2_val.s));
	for(i=0; i<URI_MAX_U_PARAMS && uri->u_name[i].s; i++)
		LM_DBG("uname=[%p]-><%.*s> uval=[%p]-><%.*s>\n",
			uri->u_name[i].s, uri->u_name[i].len, uri->u_name[i].s,
			uri->u_val[i].s, uri->u_val[i].len, uri->u_val[i].s);
	if (i!=uri->u_params_no)
		LM_ERR("inconsisten # of u_name:[%d]!=[%d]\n", i, uri->u_params_no);
#endif
	return 0;

error_too_short:
	LM_ERR("uri too short: <%.*s> (%d)\n",
			len, ZSW(buf), len);
	goto error_exit;
error_bad_char:
	LM_ERR("bad char '%c' in state %d"
			" parsed: <%.*s> (%d) / <%.*s> (%d)\n",
			*p, state, (int)(p-buf), ZSW(buf), (int)(p-buf),
			len, ZSW(buf), len);
	goto error_exit;
error_bad_host:
	LM_ERR("bad host in uri (error at char %c in"
			" state %d) parsed: <%.*s>(%d) /<%.*s> (%d)\n",
			*p, state, (int)(p-buf), ZSW(buf), (int)(p-buf),
			len, ZSW(buf), len);
	goto error_exit;
error_bad_port:
	LM_ERR("bad port in uri (error at char %c in"
			" state %d) parsed: <%.*s>(%d) /<%.*s> (%d)\n",
			*p, state, (int)(p-buf), ZSW(buf), (int)(p-buf),
			len, ZSW(buf), len);
	goto error_exit;
error_bad_uri:
	LM_ERR("bad uri, state %d parsed: <%.*s> (%d) / <%.*s> (%d)\n",
			 state, (int)(p-buf), ZSW(buf), (int)(p-buf), len,
			 ZSW(buf), len);
	goto error_exit;
error_headers:
	LM_ERR("bad uri headers: <%.*s>(%d) / <%.*s>(%d)\n",
			uri->headers.len, ZSW(uri->headers.s), uri->headers.len,
			len, ZSW(buf), len);
	goto error_exit;
error_bug:
	LM_CRIT("bad state %d parsed: <%.*s> (%d) / <%.*s> (%d)\n",
			 state, (int)(p-buf), ZSW(buf), (int)(p-buf), len, ZSW(buf), len);
error_exit:
	ser_error=E_BAD_URI;
	uri->type=ERROR_URI_T;
	update_stat(bad_URIs, 1);
	return E_BAD_URI;
}
Example #3
0
/*!
 * \brief sigio specific init
 * \param h IO handle
 * \param rsig real time signal
 * \return returns -1 on error, 0 on success
 */
static int init_sigio(io_wait_h* h, int rsig)
{
	int r;
	int n;
	int signo;
	int start_sig;
	sigset_t oldset;

	if (!_sigio_init){
		_sigio_init=1;
		_sigio_crt_rtsig=SIGRTMIN;
		sigemptyset(&_sigio_rtsig_used);
	}
	h->signo=0;

	if (rsig==0){
		start_sig=_sigio_crt_rtsig;
		n=SIGRTMAX-SIGRTMIN;
	}else{
		if ((rsig < SIGRTMIN) || (rsig >SIGRTMAX)){
			LM_CRIT("real time signal %d out of"
				" range  [%d, %d]\n", rsig, SIGRTMIN, SIGRTMAX);
			goto error;
		}
		start_sig=rsig;
		n=0;
	}

	sigemptyset(&h->sset);
	sigemptyset(&oldset);
retry1:
	/* get current block mask */
	if (sigprocmask(SIG_BLOCK, &h->sset, &oldset )==-1){
		if (errno==EINTR) goto retry1;
		LM_ERR("1st sigprocmask failed: %s [%d]\n",
				strerror(errno), errno);
		/* try to continue */
	}

	for (r=start_sig; r<=(n+start_sig); r++){
		signo=(r>SIGRTMAX)?r-SIGRTMAX+SIGRTMIN:r;
		if (! sigismember(&_sigio_rtsig_used, signo) &&
			! sigismember(&oldset, signo)){
			sigaddset(&_sigio_rtsig_used, signo);
			h->signo=signo;
			_sigio_crt_rtsig=(signo<SIGRTMAX)?signo+1:SIGRTMIN;
			break;
		}
	}

	if (h->signo==0){
			LM_CRIT("init_sigio: %s\n",
					rsig?"could not assign requested real-time signal":
						 "out of real-time signals");
			goto error;
	}

	LM_DBG("trying signal %d... \n", h->signo);

	if (sigaddset(&h->sset, h->signo)==-1){
		LM_ERR("sigaddset failed for %d: %s [%d]\n",
				h->signo, strerror(errno), errno);
		goto error;
	}
	if (sigaddset(&h->sset, SIGIO)==-1){
		LM_ERR("sigaddset failed for %d: %s [%d]\n",
				SIGIO, strerror(errno), errno);
		goto error;
	}
retry:
	if (sigprocmask(SIG_BLOCK, &h->sset, 0)==-1){
		if (errno==EINTR) goto retry;
		LM_ERR("sigprocmask failed: %s [%d]\n",
				strerror(errno), errno);
		goto error;
	}
	return 0;
error:
	h->signo=0;
	sigemptyset(&h->sset);
	return -1;
}
Example #4
0
int uac_auth(sip_msg_t *msg)
{
	static struct authenticate_body auth;
	struct uac_credential *crd;
	int code, branch;
	struct sip_msg *rpl;
	struct cell *t;
	struct hdr_field *hdr;
	HASHHEX response;
	str *new_hdr;
	sr_cfgenv_t *cenv = NULL;

	/* get transaction */
	t = uac_tmb.t_gett();
	if (t==T_UNDEFINED || t==T_NULL_CELL)
	{
		LM_CRIT("no current transaction found\n");
		goto error;
	}

	/* get the selected branch */
	branch = uac_tmb.t_get_picked_branch();
	if (branch<0) {
		LM_CRIT("no picked branch (%d)\n",branch);
		goto error;
	}

	rpl = t->uac[branch].reply;
	code = t->uac[branch].last_received;
	LM_DBG("picked reply is %p, code %d\n",rpl,code);

	if (rpl==0)
	{
		LM_CRIT("empty reply on picked branch\n");
		goto error;
	}
	if (rpl==FAKED_REPLY)
	{
		LM_ERR("cannot process a FAKED reply\n");
		goto error;
	}

	hdr = get_autenticate_hdr( rpl, code);
	if (hdr==0)
	{
		LM_ERR("failed to extract authenticate hdr\n");
		goto error;
	}

	LM_DBG("header found; body=<%.*s>\n",
		hdr->body.len, hdr->body.s);

	if (parse_authenticate_body( &hdr->body, &auth)<0)
	{
		LM_ERR("failed to parse auth hdr body\n");
		goto error;
	}

	/* can we authenticate this realm? */
	crd = 0;
	/* first look into AVP, if set */
	if ( auth_realm_spec.type!=PVT_NONE )
		crd = get_avp_credential( msg, &auth.realm );
	/* if not found, look into predefined credentials */
	if (crd==0)
		crd = lookup_realm( &auth.realm );
	/* found? */
	if (crd==0)
	{
		LM_DBG("no credential for realm \"%.*s\"\n",
			auth.realm.len, auth.realm.s);
		goto error;
	}

	/* do authentication */
	do_uac_auth( &msg->first_line.u.request.method,
			&t->uac[branch].uri, crd, &auth, response);

	/* build the authorization header */
	new_hdr = build_authorization_hdr( code, &t->uac[branch].uri,
		crd, &auth, response);
	if (new_hdr==0)
	{
		LM_ERR("failed to build authorization hdr\n");
		goto error;
	}

	/* so far, so good -> add the header and set the proper RURI */
	if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 )
	{
		LM_ERR("failed to apply changes\n");
		goto error;
	}

	/* mark request in T with uac auth for increase of cseq via dialog
	 * - this function is executed in failure route, msg_flags will be
	 *   reset afterwards by tm fake env */
	if(t->uas.request) {
		t->uas.request->msg_flags |= FL_UAC_AUTH;
		cenv = sr_cfgenv_get();
		if(cenv->cseq_update == 1) {
			sr_hdr_add_zz(msg, "P-K-Auth-CSeq", "yes");
		}
	}

	return 0;
error:
	return -1;
}
Example #5
0
/*!
 * \brief Update a dialog state according a event and the old state
 *
 * This functions implement the main state machine that update a dialog
 * state according a processed event and the current state. If necessary
 * it will delete the processed dialog. The old and new state are also
 * saved for reference.
 * \param dlg updated dialog
 * \param event current event
 * \param old_state old dialog state
 * \param new_state new dialog state
 * \param unref set to 1 when the dialog was deleted, 0 otherwise
 */
void next_state_dlg(dlg_cell_t *dlg, int event,
		int *old_state, int *new_state, int *unref)
{
	dlg_entry_t *d_entry;

	d_entry = &(d_table->entries[dlg->h_entry]);

	*unref = 0;

	dlg_lock( d_table, d_entry);

	*old_state = dlg->state;

	switch (event) {
		case DLG_EVENT_TDEL:
			switch (dlg->state) {
				case DLG_STATE_UNCONFIRMED:
				case DLG_STATE_EARLY:
					dlg->state = DLG_STATE_DELETED;
					unref_dlg_unsafe(dlg,1,d_entry);
					*unref = 1;
					break;
				case DLG_STATE_CONFIRMED_NA:
				case DLG_STATE_CONFIRMED:
					unref_dlg_unsafe(dlg,1,d_entry);
					break;
				case DLG_STATE_DELETED:
					*unref = 1;
					break;
				default:
					log_next_state_dlg(event, dlg);
			}
			break;
		case DLG_EVENT_RPL1xx:
			switch (dlg->state) {
				case DLG_STATE_UNCONFIRMED:
				case DLG_STATE_EARLY:
					dlg->state = DLG_STATE_EARLY;
					break;
				default:
					log_next_state_dlg(event, dlg);
			}
			break;
		case DLG_EVENT_RPL3xx:
			switch (dlg->state) {
				case DLG_STATE_UNCONFIRMED:
				case DLG_STATE_EARLY:
					dlg->state = DLG_STATE_DELETED;
					*unref = 1;
					break;
				default:
					log_next_state_dlg(event, dlg);
			}
			break;
		case DLG_EVENT_RPL2xx:
			switch (dlg->state) {
				case DLG_STATE_DELETED:
					if (dlg->dflags&DLG_FLAG_HASBYE) {
						LM_CRIT("bogus event %d in state %d (with BYE) "
							"for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n",
							event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
							dlg->callid.len, dlg->callid.s,
							dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
							dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
						break;
					}
					ref_dlg_unsafe(dlg,1);
				case DLG_STATE_UNCONFIRMED:
				case DLG_STATE_EARLY:
					dlg->state = DLG_STATE_CONFIRMED_NA;
					break;
				case DLG_STATE_CONFIRMED_NA:
				case DLG_STATE_CONFIRMED:
					break;
				default:
					log_next_state_dlg(event, dlg);
			}
			break;
		case DLG_EVENT_REQACK:
			switch (dlg->state) {
				case DLG_STATE_CONFIRMED_NA:
					dlg->state = DLG_STATE_CONFIRMED;
					break;
				case DLG_STATE_CONFIRMED:
					break;
				case DLG_STATE_DELETED:
					break;
				default:
					log_next_state_dlg(event, dlg);
			}
			break;
		case DLG_EVENT_REQBYE:
			switch (dlg->state) {
				case DLG_STATE_CONFIRMED_NA:
				case DLG_STATE_CONFIRMED:
					dlg->dflags |= DLG_FLAG_HASBYE;
					dlg->state = DLG_STATE_DELETED;
					*unref = 1;
					break;
				case DLG_STATE_EARLY:
				case DLG_STATE_DELETED:
					break;
				default:
					log_next_state_dlg(event, dlg);
			}
			break;
		case DLG_EVENT_REQPRACK:
			switch (dlg->state) {
				case DLG_STATE_EARLY:
				case DLG_STATE_CONFIRMED_NA:
				case DLG_STATE_DELETED:
					break;
				default:
					log_next_state_dlg(event, dlg);
			}
			break;
		case DLG_EVENT_REQ:
			switch (dlg->state) {
				case DLG_STATE_EARLY:
				case DLG_STATE_CONFIRMED_NA:
				case DLG_STATE_CONFIRMED:
				case DLG_STATE_DELETED:
					break;
				default:
					log_next_state_dlg(event, dlg);
			}
			break;
		default:
			LM_CRIT("unknown event %d in state %d "
				"for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n",
				event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
				dlg->callid.len, dlg->callid.s,
				dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
				dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
	}
	*new_state = dlg->state;

	dlg_unlock( d_table, d_entry);

	LM_DBG("dialog %p changed from state %d to "
		"state %d, due event %d (ref %d)\n", dlg, *old_state, *new_state, event,
		dlg->ref);
}
Example #6
0
/*
 * Initialize data structures
 */
int init_addresses(void)
{
	if (!db_url.s) {
		LM_INFO("db_url parameter of permissions module not set, "
				"disabling allow_address\n");
		return 0;
	} else {
		if (db_bind_mod(&db_url, &perm_dbf) < 0) {
			LM_ERR("load a database support module\n");
			return -1;
		}

		if (!DB_CAPABILITY(perm_dbf, DB_CAP_QUERY)) {
			LM_ERR("database module does not implement 'query' function\n");
			return -1;
		}
	}

	addr_hash_table_1 = addr_hash_table_2 = 0;
	addr_hash_table = 0;

	db_handle = perm_dbf.init(&db_url);
	if (!db_handle) {
		LM_ERR("unable to connect database\n");
		return -1;
	}

	if(db_check_table_version(&perm_dbf, db_handle, &address_table, TABLE_VERSION) < 0) {
		LM_ERR("error during table version check.\n");
		perm_dbf.close(db_handle);
		return -1;
	}

	addr_hash_table_1 = new_addr_hash_table();
	if (!addr_hash_table_1) return -1;

	addr_hash_table_2  = new_addr_hash_table();
	if (!addr_hash_table_2) goto error;

	addr_hash_table = (struct addr_list ***)shm_malloc
		(sizeof(struct addr_list **));
	if (!addr_hash_table) {
		LM_ERR("no more shm memory for addr_hash_table\n");
		goto error;
	}

	*addr_hash_table = addr_hash_table_1;

	subnet_table_1 = new_subnet_table();
	if (!subnet_table_1) goto error;

	subnet_table_2 = new_subnet_table();
	if (!subnet_table_2) goto error;

	subnet_table = (struct subnet **)shm_malloc(sizeof(struct subnet *));
	if (!subnet_table) {
		LM_ERR("no more shm memory for subnet_table\n");
		goto error;
	}

	*subnet_table = subnet_table_1;

	domain_list_table_1 = new_domain_name_table();
	if (!domain_list_table_1) goto error;

	domain_list_table_2 = new_domain_name_table();
	if (!domain_list_table_2) goto error;

	domain_list_table = (struct domain_name_list ***)shm_malloc(sizeof(struct domain_name_list **));
	if (!domain_list_table) {
		LM_ERR("no more shm memory for domain name table\n");
		goto error;
	}

	*domain_list_table = domain_list_table_1;


	if (reload_address_table() == -1) {
		LM_CRIT("reload of address table failed\n");
		goto error;
	}

	perm_dbf.close(db_handle);
	db_handle = 0;

	return 0;

error:
	if (addr_hash_table_1) {
		free_addr_hash_table(addr_hash_table_1);
		addr_hash_table_1 = 0;
	}
	if (addr_hash_table_2) {
		free_addr_hash_table(addr_hash_table_2);
		addr_hash_table_2 = 0;
	}
	if (addr_hash_table) {
		shm_free(addr_hash_table);
		addr_hash_table = 0;
	}
	if (subnet_table_1) {
		free_subnet_table(subnet_table_1);
		subnet_table_1 = 0;
	}
	if (subnet_table_2) {
		free_subnet_table(subnet_table_2);
		subnet_table_2 = 0;
	}
	if (subnet_table) {
		shm_free(subnet_table);
		subnet_table = 0;
	}

	if (domain_list_table_1) {
		free_domain_name_table(domain_list_table_1);
		domain_list_table_1 = 0;
	}
	if (domain_list_table_2) {
		free_domain_name_table(domain_list_table_2);
		domain_list_table_2 = 0;
	}
	if (domain_list_table) {
		shm_free(domain_list_table);
		domain_list_table = 0;
	}

	perm_dbf.close(db_handle);
	db_handle = 0;
	return -1;
}
Example #7
0
/**
 * init module function
 */
static int mod_init(void)
{
	m_tree_t *pt = NULL;

	if(mtree_init_rpc()!=0)
	{
		LM_ERR("failed to register RPC commands\n");
		return -1;
	}

	if(pv_parse_spec(&value_param, &pv_value)<00
			|| !(pv_is_w(&pv_value)))
	{
		LM_ERR("cannot parse value pv or is read only\n");
		return -1;
	}

	if (pv_parse_spec(&values_param, &pv_values) <0
			|| pv_values.type != PVT_AVP) {
		LM_ERR("cannot parse values avp\n");
		return -1;
	}

	if(pv_parse_spec(&dstid_param, &pv_dstid)<0
			|| pv_dstid.type!=PVT_AVP)
	{
		LM_ERR("cannot parse dstid avp\n");
		return -1;
	}

	if(pv_parse_spec(&weight_param, &pv_weight)<0
			|| pv_weight.type!=PVT_AVP)
	{
		LM_ERR("cannot parse dstid avp\n");
		return -1;
	}

	if(pv_parse_spec(&count_param, &pv_count)<0
			|| !(pv_is_w(&pv_weight)))
	{
		LM_ERR("cannot parse count pv or is read-only\n");
		return -1;
	}

	if(mt_fetch_rows<=0)
		mt_fetch_rows = 1000;

	if(mt_char_list.len<=0)
	{
		LM_ERR("invalid prefix char list\n");
		return -1;
	}
	LM_DBG("mt_char_list=%s \n", mt_char_list.s);
	mt_char_table_init();

	/* binding to mysql module */
	if(db_bind_mod(&db_url, &mt_dbf))
	{
		LM_ERR("database module not found\n");
		return -1;
	}

	if (!DB_CAPABILITY(mt_dbf, DB_CAP_ALL))
	{
		LM_ERR("database module does not "
				"implement all functions needed by the module\n");
		return -1;
	}

	/* open a connection with the database */
	db_con = mt_dbf.init(&db_url);
	if(db_con==NULL)
	{
		LM_ERR("failed to connect to the database\n");
		return -1;
	}

	LM_DBG("database connection opened successfully\n");

	if ( (mt_lock=lock_alloc())==0) {
		LM_CRIT("failed to alloc lock\n");
		goto error1;
	}
	if (lock_init(mt_lock)==0 ) {
		LM_CRIT("failed to init lock\n");
		goto error1;
	}

	if(mt_defined_trees())
	{
		LM_DBG("static trees defined\n");

		pt = mt_get_first_tree();

		while(pt!=NULL)
		{
			LM_DBG("loading from tree <%.*s>\n",
					pt->tname.len, pt->tname.s);

			/* loading all information from database */
			if(mt_load_db(pt)!=0)
			{
				LM_ERR("cannot load info from database\n");
				goto error1;
			}
			pt = pt->next;
		}
		/* reset db_table value */
		db_table.s = "";
		db_table.len = 0;
	} else {
		if(db_table.len<=0)
		{
			LM_ERR("no trees table defined\n");
			goto error1;
		}
		if(mt_init_list_head()<0)
		{
			LM_ERR("unable to init trees list head\n");
			goto error1;
		}
		/* loading all information from database */
		if(mt_load_db_trees()!=0)
		{
			LM_ERR("cannot load trees from database\n");
			goto error1;
		}
	}
	mt_dbf.close(db_con);
	db_con = 0;

#if 0
	mt_print_tree(mt_get_first_tree());
#endif

	/* success code */
	return 0;

error1:
	if (mt_lock)
	{
		lock_destroy( mt_lock );
		lock_dealloc( mt_lock );
		mt_lock = 0;
	}
	mt_destroy_trees();

	if(db_con!=NULL)
		mt_dbf.close(db_con);
	db_con = 0;
	return -1;
}
Example #8
0
/**
 * init module function
 */
static int mod_init(void)
{
	LM_INFO("initializing...\n");

	init_db_url( db_url , 0 /*cannot be null*/);
	db_table.len = strlen(db_table.s);
	sdomain_column.len = strlen(sdomain_column.s);
	prefix_column.len = strlen(prefix_column.s);
	domain_column.len = strlen(domain_column.s);
	prefix.len = strlen(prefix.s);

	pdt_char_list.len = strlen(pdt_char_list.s);
	if(pdt_char_list.len<=0)
	{
		LM_ERR("invalid pdt char list\n");
		return -1;
	}
	LM_INFO("pdt_char_list=%s \n",pdt_char_list.s);

	/* binding to mysql module */
	if(db_bind_mod(&db_url, &pdt_dbf))
	{
		LM_ERR("database module not found\n");
		return -1;
	}

	if (!DB_CAPABILITY(pdt_dbf, DB_CAP_ALL))
	{
		LM_ERR("database module does not "
		    "implement all functions needed by the module\n");
		return -1;
	}

	/* open a connection with the database */
	db_con = pdt_dbf.init(&db_url);
	if(db_con==NULL)
	{
		LM_ERR("failed to connect to the database\n");        
		return -1;
	}
	
	if (pdt_dbf.use_table(db_con, &db_table) < 0)
	{
		LM_ERR("failed to use_table\n");
		goto error1;
	}
	LM_DBG("database connection opened successfully\n");
	
	/* create & init lock */
	if ((pdt_lock = lock_init_rw()) == NULL) {
		LM_CRIT("failed to init lock\n");
		goto error1;
	}
	
	/* tree pointer in shm */
	_ptree = (pdt_tree_t**)shm_malloc( sizeof(pdt_tree_t*) );
	if (_ptree==0) {
		LM_ERR("out of shm mem for pdtree\n");
		goto error1;
	}
	*_ptree=0;

	/* loading all information from database */
	if(pdt_load_db()!=0)
	{
		LM_ERR("cannot load info from database\n");	
		goto error1;
	}
		
	pdt_dbf.close(db_con);
	db_con = 0;

#if 0
	pdt_print_tree(*_ptree);
#endif

	/* success code */
	return 0;

error1:
	if (pdt_lock)
	{
		lock_destroy_rw( pdt_lock );
		pdt_lock = 0;
	}
	if(_ptree!=0)
		shm_free(_ptree);

	if(db_con!=NULL)
	{
		pdt_dbf.close(db_con);
		db_con = 0;
	}
	return -1;
}
Example #9
0
/**
 * Initialize children
 */
static int child_init(int rank)
{
	if (rank==PROC_INIT || rank==PROC_TCP_MAIN)
		return 0;

	if (rank==PROC_MAIN && dbmode == RLS_DB_ONLY)
	{
		int i;

		for (i = 0; i < rls_notifier_processes; i++)
		{
			char tmp[16];
			snprintf(tmp, 16, "RLS NOTIFIER %d", i);
			rls_notifier_id[i] = i;

			if (fork_basic_utimer(PROC_TIMER, tmp, 1,
						timer_send_notify,
						&rls_notifier_id[i],
						1000000/rls_notifier_poll_rate) < 0)
			{
				LM_ERR("Failed to start RLS NOTIFIER %d\n", i);
				return -1;
			}
		}

		return 0;
	}

	LM_DBG("child [%d]  pid [%d]\n", rank, getpid());

	if (rls_dbf.init==0)
	{
		LM_CRIT("database not bound\n");
		return -1;
	}
	/* In DB only mode do not pool the connections where possible. */
	if (dbmode == RLS_DB_ONLY && rls_dbf.init2)
		rls_db = rls_dbf.init2(&db_url, DB_POOLING_NONE);
	else
		rls_db = rls_dbf.init(&db_url);
	if (!rls_db)
	{
		LM_ERR("child %d: Error while connecting database\n",
				rank);
		return -1;
	}
	else
	{
		if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0)  
		{
			LM_ERR("child %d: Error in use_table rlsubs_table\n", rank);
			return -1;
		}

		LM_DBG("child %d: Database connection opened successfully\n", rank);
	}

	if (rlpres_dbf.init==0)
	{
		LM_CRIT("database not bound\n");
		return -1;
	}
	/* In DB only mode do not pool the connections where possible. */
	if (dbmode == RLS_DB_ONLY && rlpres_dbf.init2)
		rlpres_db = rlpres_dbf.init2(&db_url, DB_POOLING_NONE);
	else
		rlpres_db = rlpres_dbf.init(&db_url);
	if (!rlpres_db)
	{
		LM_ERR("child %d: Error while connecting database\n",
				rank);
		return -1;
	}
	else
	{
		if (rlpres_dbf.use_table(rlpres_db, &rlpres_table) < 0)  
		{
			LM_ERR("child %d: Error in use_table rlpres_table\n", rank);
			return -1;
		}

		LM_DBG("child %d: Database connection opened successfully\n", rank);
	}

	if (rls_xcap_dbf.init==0)
	{
		LM_CRIT("database not bound\n");
		return -1;
	}
	rls_xcap_db = rls_xcap_dbf.init(&xcap_db_url);
	if (!rls_xcap_db)
	{
		LM_ERR("child %d: Error while connecting database\n", rank);
		return -1;
	}
	else
	{
		if (rls_xcap_dbf.use_table(rls_xcap_db, &rls_xcap_table) < 0)  
		{
			LM_ERR("child %d: Error in use_table rls_xcap_table\n", rank);
			return -1;
		}

		LM_DBG("child %d: Database connection opened successfully\n", rank);
	}

	return 0;
}
Example #10
0
File: tm.c Project: Danfx/opensips
int pv_set_tm_branch_avp(struct sip_msg *msg, pv_param_t *param, int op,
		pv_value_t *val)
{
	int avp_name;
	int_str avp_val;
	int flags, res=0;
	unsigned short name_type;
	int idx, idxf;
	struct usr_avp **old_list=NULL;
	struct usr_avp **avp_list=NULL;

	if (!msg || !val)
		goto error;

	avp_list = get_bavp_list();
	if (!avp_list) {
		pv_get_null(msg, param, val);
		goto success;
	}

	if (!param) {
		LM_ERR("bad parameters\n");
		goto error;
	}

	if (pv_get_avp_name(msg, param, &avp_name, &name_type)) {
		LM_ALERT("BUG in getting bavp name\n");
		goto error;
	}

	/* get the index */
	if(pv_get_spec_index(msg, param, &idx, &idxf)!=0) {
		LM_ERR("invalid index\n");
		goto error;
	}

	/* setting the avp head */
	old_list = set_avp_list(avp_list);
	if (!old_list) {
		LM_CRIT("no bavp head list found\n");
		goto error;
	}

	if(val == NULL) {
		if(op == COLONEQ_T || idxf == PV_IDX_ALL)
			destroy_avps(name_type, avp_name, 1);
		else {
			if(idx < 0) {
				LM_ERR("index with negative value\n");
				goto error;
			}
			destroy_index_avp(name_type, avp_name, idx);
		}
		/* restoring head */
		goto success;
	}

	if(op == COLONEQ_T || idxf == PV_IDX_ALL)
		destroy_avps(name_type, avp_name, 1);

	flags = name_type;
	if(val->flags&PV_TYPE_INT) {
		avp_val.n = val->ri;
	} else {
		avp_val.s = val->rs;
		flags |= AVP_VAL_STR;
	}

	if(idxf == PV_IDX_INT || idxf == PV_IDX_PVAR) {
		if(replace_avp(flags, avp_name, avp_val, idx)< 0) {
			LM_ERR("failed to replace bavp\n");
			goto error;
		}
	} else {
		if (add_avp(flags, avp_name, avp_val)<0) {
			LM_ERR("error - cannot add bavp\n");
			goto error;
		}
	}
	goto success;

error:
	res = -1;
success:
	if (old_list)
		set_avp_list(old_list);
	return res;
}
Example #11
0
File: tm.c Project: Danfx/opensips
static int mod_init(void)
{
	unsigned int timer_sets,set;
	unsigned int roundto_init;

	LM_INFO("TM - initializing...\n");

	/* checking if we have sufficient bitmap capacity for given
	   maximum number of  branches */
	if (MAX_BRANCHES+1>31) {
		LM_CRIT("Too many max UACs for UAC branch_bm_t bitmap: %d\n",
			MAX_BRANCHES );
		return -1;
	}

	fix_flag_name(minor_branch_flag_str, minor_branch_flag);

	minor_branch_flag =
		get_flag_id_by_name(FLAG_TYPE_BRANCH, minor_branch_flag_str);

	if (minor_branch_flag!=-1) {
		if (minor_branch_flag > (8*sizeof(int)-1)) {
			LM_CRIT("invalid minor branch flag\n");
			return -1;
		}
		minor_branch_flag = 1<<minor_branch_flag;
	} else {
		minor_branch_flag = 0;
	}

	/* if statistics are disabled, prevent their registration to core */
	if (tm_enable_stats==0)
#ifdef STATIC_TM
		tm_exports.stats = 0;
#else
		exports.stats = 0;
#endif

	if (init_callid() < 0) {
		LM_CRIT("Error while initializing Call-ID generator\n");
		return -1;
	}

	/* how many timer sets do we need to create? */
	timer_sets = (timer_partitions<=1)?1:timer_partitions ;

	/* try first allocating all the structures needed for syncing */
	if (lock_initialize( timer_sets )==-1)
		return -1;

	/* building the hash table*/
	if (!init_hash_table( timer_sets )) {
		LM_ERR("initializing hash_table failed\n");
		return -1;
	}

	/* init static hidden values */
	init_t();

	if (!tm_init_timers( timer_sets ) ) {
		LM_ERR("timer init failed\n");
		return -1;
	}

	/* the ROUNDTO macro taken from the locking interface */
#ifdef ROUNDTO
	roundto_init = ROUNDTO;
#else
	roundto_init = sizeof(void *);
#endif
	while (roundto_init != 1) {
		tm_timer_shift++;
		roundto_init >>= 1;
	}

	LM_DBG("timer set shift is %d\n", tm_timer_shift);


	/* register the timer functions */
	for ( set=0 ; set<timer_sets ; set++ ) {
		if (register_timer( "tm-timer", timer_routine,
		(void*)(long)set, 1, TIMER_FLAG_DELAY_ON_DELAY) < 0 ) {
			LM_ERR("failed to register timer for set %d\n",set);
			return -1;
		}
		if (register_utimer( "tm-utimer", utimer_routine,
		(void*)(long)set, 100*1000, TIMER_FLAG_DELAY_ON_DELAY)<0) {
			LM_ERR("failed to register utimer for set %d\n",set);
			return -1;
		}
	}

	if (uac_init()==-1) {
		LM_ERR("uac_init failed\n");
		return -1;
	}

	if (init_tmcb_lists()!=1) {
		LM_CRIT("failed to init tmcb lists\n");
		return -1;
	}

	tm_init_tags();
	init_twrite_lines();
	if (init_twrite_sock() < 0) {
		LM_ERR("failed to create socket\n");
		return -1;
	}

	/* register post-script clean-up function */
	if (register_script_cb( do_t_cleanup, POST_SCRIPT_CB|REQ_TYPE_CB, 0)<0 ) {
		LM_ERR("failed to register POST request callback\n");
		return -1;
	}
	if (register_script_cb( script_init, PRE_SCRIPT_CB|REQ_TYPE_CB , 0)<0 ) {
		LM_ERR("failed to register PRE request callback\n");
		return -1;
	}

	if(register_pv_context("request", tm_pv_context_request)< 0) {
		LM_ERR("Failed to register pv contexts\n");
		return -1;
	}

	if(register_pv_context("reply", tm_pv_context_reply)< 0) {
		LM_ERR("Failed to register pv contexts\n");
		return -1;
	}

	if ( parse_avp_spec( &uac_ctx_avp, &uac_ctx_avp_id)<0 ) {
		LM_ERR("failed to register AVP name <%s>\n",uac_ctx_avp.s);
		return -1;
	}

	if ( register_async_handlers( t_handle_async, t_resume_async )<0 ) {
		LM_ERR("failed to register async handler to core \n");
		return -1;
	}

	return 0;
}
Example #12
0
File: tm.c Project: Danfx/opensips
int pv_get_tm_branch_avp(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *val)
{
	int avp_name;
	int_str avp_value;
	unsigned short name_type;
	int idx, idxf, res=0;
	struct usr_avp **old_list=NULL;
	struct usr_avp **avp_list=NULL;
	struct usr_avp *avp;
	int_str avp_value0;
	struct usr_avp *avp0;
	int n=0;
	char *p;

	if (!msg || !val)
		goto error;

	avp_list = get_bavp_list();
	if (!avp_list) {
		pv_get_null(msg, param, val);
		goto success;
	}

	if (!param) {
		LM_ERR("bad parameters\n");
		goto error;
	}

	if (pv_get_avp_name(msg, param, &avp_name, &name_type)) {
		LM_ALERT("BUG in getting bavp name\n");
		goto error;
	}

	/* get the index */
	if(pv_get_spec_index(msg, param, &idx, &idxf)!=0) {
		LM_ERR("invalid index\n");
		goto error;
	}

	/* setting the avp head */
	old_list = set_avp_list(avp_list);
	if (!old_list) {
		LM_CRIT("no bavp head list found\n");
		goto error;
	}

	if ((avp=search_first_avp(name_type, avp_name, &avp_value, 0))==0) {
		pv_get_null(msg, param, val);
		goto success;
	}
	val->flags = PV_VAL_STR;
	if ( (idxf==0 || idxf==PV_IDX_INT) && idx==0) {
		if(avp->flags & AVP_VAL_STR) {
			val->rs = avp_value.s;
		} else {
			val->rs.s = sint2str(avp_value.n, &val->rs.len);
			val->ri = avp_value.n;
			val->flags |= PV_VAL_INT|PV_TYPE_INT;
		}
		goto success;
	}
	if(idxf==PV_IDX_ALL) {
		p = pv_local_buf;
		do {
			if(avp->flags & AVP_VAL_STR) {
				val->rs = avp_value.s;
			} else {
				val->rs.s = sint2str(avp_value.n, &val->rs.len);
			}

			if(p-pv_local_buf+val->rs.len+1>PV_LOCAL_BUF_SIZE) {
				LM_ERR("local buffer length exceeded!\n");
				pv_get_null(msg, param, val);
				goto success;
			}
			memcpy(p, val->rs.s, val->rs.len);
			p += val->rs.len;
			if(p-pv_local_buf+PV_FIELD_DELIM_LEN+1>PV_LOCAL_BUF_SIZE) {
				LM_ERR("local buffer length exceeded\n");
				pv_get_null(msg, param, val);
				goto success;
			}
			memcpy(p, PV_FIELD_DELIM, PV_FIELD_DELIM_LEN);
			p += PV_FIELD_DELIM_LEN;
		} while ((avp=search_first_avp(name_type, avp_name,
						&avp_value, avp))!=0);
		*p = 0;
		val->rs.s = pv_local_buf;
		val->rs.len = p - pv_local_buf;
		goto success;
	}

	/* we have a numeric index */
	if(idx<0) {
		n = 1;
		avp0 = avp;
		while ((avp0=search_first_avp(name_type, avp_name,
						&avp_value0, avp0))!=0) n++;
		idx = -idx;
		if(idx>n) {
			LM_DBG("index out of range\n");
			pv_get_null(msg, param, val);
			goto success;
		}
		idx = n - idx;
		if(idx==0) {
			if(avp->flags & AVP_VAL_STR) {
				val->rs = avp_value.s;
			} else {
				val->rs.s = sint2str(avp_value.n, &val->rs.len);
				val->ri = avp_value.n;
				val->flags |= PV_VAL_INT|PV_TYPE_INT;
			}
			goto success;
		}
	}
	n=0;
	while(n<idx &&
			(avp=search_first_avp(name_type, avp_name, &avp_value, avp))!=0)
		n++;

	if(avp!=0) {
		if(avp->flags & AVP_VAL_STR) {
			val->rs = avp_value.s;
		} else {
			val->rs.s = sint2str(avp_value.n, &val->rs.len);
			val->ri = avp_value.n;
			val->flags |= PV_VAL_INT|PV_TYPE_INT;
		}
	}

	goto success;

error:
	res = -1;
success:
	if (old_list)
		set_avp_list(old_list);
	return res;
}
Example #13
0
int dp_can_connect_str(str *domain, int rec_level) {
    struct rdata* head;
    struct rdata* l;
    struct naptr_rdata* naptr;
    struct naptr_rdata* next_naptr;
    int	   ret;
    str	   newdomain;
    char   uri[MAX_URI_SIZE];
    struct avp_stack stack;
    int    last_order = -1;
    int    failed = 0;
    int    found_anything = 0;

    str pattern, replacement, result;

    stack_reset(&stack);
    /* If we're in a recursive call, set the domain-replacement */
    if ( rec_level > 0 ) {
	stack_push(&stack, domain_replacement_avp.s, domain->s);
	stack.succeeded = 0;
    }

    if (rec_level > MAX_DDDS_RECURSIONS) {
    	LM_ERR("too many indirect NAPTRs. Aborting at %.*s.\n", domain->len,
				ZSW(domain->s));
		return(DP_DDDS_RET_DNSERROR);
    }

    LM_INFO("looking up Domain itself: %.*s\n",domain->len, ZSW(domain->s));
    ret = check_rule(domain,"D2P+sip:dom", 11, &stack);

    if (ret == 1) {
	LM_INFO("found a match on domain itself\n");
	stack_to_avp(&stack);
	return(DP_DDDS_RET_POSITIVE);
    } else if (ret == 0) {
	LM_INFO("no match on domain itself.\n");
	stack_reset(&stack);
	/* If we're in a recursive call, set the domain-replacement */
	if ( rec_level > 0 ) {
	    stack_push(&stack, domain_replacement_avp.s, (char *) domain->s);
	    stack.succeeded = 0;
	}
    } else {
	return(DP_DDDS_RET_DNSERROR);	/* actually: DB error */
    }

    LM_INFO("doing DDDS with %.*s\n",domain->len, ZSW(domain->s));
    head = get_record(domain->s, T_NAPTR);
    if (head == 0) {
    	LM_NOTICE("no NAPTR record found for %.*s.\n", 
				domain->len, ZSW(domain->s));
    	return(DP_DDDS_RET_NOTFOUND);
    }

    LM_DBG("found the following NAPTRs: \n");
    for (l = head; l; l = l->next) {
	if (l->type != T_NAPTR) {
	    LM_DBG("found non-NAPTR record.\n");
	    continue; /*should never happen*/
	}
	naptr = (struct naptr_rdata*)l->rdata;
	if (naptr == 0) {
		LM_CRIT("null rdata\n");
		continue;
	}
	LM_DBG("order %u, pref %u, flen %u, flags '%.*s', slen %u, "
	    "services '%.*s', rlen %u, regexp '%.*s', repl '%s'\n", 
		naptr->order, naptr->pref,
	    naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags),
	    naptr->services_len,
	    (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
	    (int)(naptr->regexp_len), ZSW(naptr->regexp),
	    ZSW(naptr->repl)
	    );
    }


    LM_DBG("sorting...\n");
    naptr_sort(&head);

    for (l = head; l; l = l->next) {

	if (l->type != T_NAPTR) continue; /*should never happen*/
	naptr = (struct naptr_rdata*)l->rdata;
	if (naptr == 0) {
		LM_CRIT("null rdata\n");
		continue;
	}

	LM_DBG("considering order %u, pref %u, flen %u, flags '%.*s', slen %u, "
	    "services '%.*s', rlen %u, regexp '%.*s', repl '%s'\n", 
		naptr->order, naptr->pref,
	    naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags),
	    naptr->services_len,
	    (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
	    (int)(naptr->regexp_len), ZSW(naptr->regexp),
	    ZSW(naptr->repl)
	    );

	/*
	 * New order? then we check whether the had success during the last one.
	 * If yes, we can leave the loop.
	 */
	if (last_order != naptr->order) {
	    	last_order = naptr->order;
		failed = 0;

		if (stack_succeeded(&stack)) {
    		LM_INFO("we don't need to consider further orders "
						"(starting with %d).\n",last_order);
		    break;
		}
	} else if (failed) {
	    LM_INFO("order %d has already failed.\n",last_order);
	    continue;
	}


	/*
	 * NAPTRs we don't care about
	 */
	if (!IS_D2PNAPTR(naptr)) 
	    continue;

	/*
	 * once we've been here, don't return DP_DDDS_RET_NOTFOUND
	 */
	found_anything = 1;

	next_naptr = NULL;
	if (l->next && (l->next->type == T_NAPTR)) {
	     next_naptr = (struct naptr_rdata*)l->next->rdata;
	}

	/*
	 * Non-terminal?
	 */
	if ((naptr->services_len == 7) && !strncasecmp("D2P+SIP", naptr->services,7) && (naptr->flags_len == 0)){
	    LM_INFO("found non-terminal NAPTR\n");

	    /*
	     * This needs to be the only record with this order.
	     */
	    if (next_naptr && (next_naptr->order == naptr->order) && IS_D2PNAPTR(next_naptr)) {
	    	LM_ERR("non-terminal NAPTR needs to be the only one "
					"with this order %.*s.\n", domain->len, ZSW(domain->s));

		return(DP_DDDS_RET_DNSERROR);
	    }

	    newdomain.s = naptr->repl;
	    newdomain.len = strlen(naptr->repl);

	    ret = dp_can_connect_str(&newdomain, rec_level + 1);

	    if (ret == DP_DDDS_RET_POSITIVE)	/* succeeded, we're done. */
		return(ret);

	    if (ret == DP_DDDS_RET_NEGATIVE)	/* found rules, did not work */
		continue;			/* look for more rules */

	    if (ret == DP_DDDS_RET_DNSERROR)	/* errors during lookup */
		return(ret);			/* report them */

	    if (ret == DP_DDDS_RET_NOTFOUND)	/* no entries in linked domain? */
		return(ret);			/* ok, fine. go with that */

	    continue; /* not reached */
	}

	/*
	 * wrong kind of terminal
	 */
	if ((naptr->flags_len != 1) || (tolower(naptr->flags[0]) != 'u')) {
	    LM_ERR("terminal NAPTR needs flag = 'u' and not '%.*s'.\n",
					(int)naptr->flags_len, ZSW(naptr->flags));
		/*
		 * It's not that clear what we should do now: Ignore this records or regard it as failed.
		 * We go with "ignore" for now.
		 */
		continue;
	}

	if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len,
			       &pattern, &replacement) < 0) {
		LM_ERR("parsing of NAPTR regexp failed\n");
		continue;
	}
	result.s = &(uri[0]);
	result.len = MAX_URI_SIZE;

	/* Avoid making copies of pattern and replacement */
	pattern.s[pattern.len] = (char)0;
	replacement.s[replacement.len] = (char)0;
	if (reg_replace(pattern.s, replacement.s, domain->s,
			&result) < 0) {
		pattern.s[pattern.len] = '!';
		replacement.s[replacement.len] = '!';
		LM_ERR("regexp replace failed\n");
		continue;
	}
	LM_INFO("resulted in replacement: '%.*s'\n", result.len, ZSW(result.s));
	pattern.s[pattern.len] = '!';
	replacement.s[replacement.len] = '!';

	ret = check_rule(&result,naptr->services,naptr->services_len, &stack);

	if (ret == 1) {
	    LM_INFO("positive return\n");
	} else if (ret == 0) {
	    LM_INFO("check_rule failed.\n");
	    stack_reset(&stack);
	    /* If we're in a recursive call, set the domain-replacement */
	    if ( rec_level > 0 ) {
		stack_push(&stack, domain_replacement_avp.s, (char *) domain->s);
		stack.succeeded = 0;
	    }
	    failed = 1;
	} else {
	    return(DP_DDDS_RET_DNSERROR);
    	}
    }

    if (stack_succeeded(&stack)) {
        LM_INFO("calling stack_to_avp.\n");
		stack_to_avp(&stack);
		return(DP_DDDS_RET_POSITIVE);
    }

    LM_INFO("returning %d.\n", 
	    (found_anything ? DP_DDDS_RET_NEGATIVE : DP_DDDS_RET_NOTFOUND));
    return(  found_anything ? DP_DDDS_RET_NEGATIVE : DP_DDDS_RET_NOTFOUND );
}
Example #14
0
/*!
 * \brief Loads from DB all contacts for a RUID
 * \param _c database connection
 * \param _d domain
 * \param _aor address of record
 * \return pointer to the record on success, 0 on errors or if nothing is found
 */
urecord_t* db_load_urecord_by_ruid(udomain_t* _d, str *_ruid)
{
	ucontact_info_t *ci;
	db_key_t columns[18];
	db_key_t keys[1];
	db_key_t order;
	db_val_t vals[1];
	db1_res_t* res = NULL;
	db_row_t *row;
	str contact;
	str aor;
	char aorbuf[512];
	str domain;

	urecord_t* r;
	ucontact_t* c;

	keys[0] = &ruid_col;
	vals[0].type = DB1_STR;
	vals[0].nul = 0;
	vals[0].val.str_val = *_ruid;

	columns[0] = &contact_col;
	columns[1] = &expires_col;
	columns[2] = &q_col;
	columns[3] = &callid_col;
	columns[4] = &cseq_col;
	columns[5] = &flags_col;
	columns[6] = &cflags_col;
	columns[7] = &user_agent_col;
	columns[8] = &received_col;
	columns[9] = &path_col;
	columns[10] = &sock_col;
	columns[11] = &methods_col;
	columns[12] = &last_mod_col;
	columns[13] = &ruid_col;
	columns[14] = &instance_col;
	columns[15] = &reg_id_col;
	columns[16] = &user_col;
	columns[17] = &domain_col;

	if (desc_time_order)
		order = &last_mod_col;
	else
		order = &q_col;

	if (ul_db_layer_query(_d,  &vals[0].val.str_val,  &vals[1].val.str_val, keys, 0, vals, columns, 1, 18, order,
				&res) < 0) {
		LM_ERR("db_query failed\n");
		return 0;
	}

	if (RES_ROW_N(res) == 0) {
		LM_DBG("aor %.*s not found in table %.*s\n",_ruid->len, _ruid->s,
				_d->name->len, _d->name->s);
		ul_db_layer_free_result(_d, res);
		return 0;
	}

	r = 0;

	/* use first row - shouldn't be more */
	row = RES_ROWS(res);

	ci = dbrow2info(ROW_VALUES(RES_ROWS(res)), &contact);
	if (ci==0) {
		LM_ERR("skipping record for %.*s in table %s\n",
				_ruid->len, _ruid->s, _d->name->s);
		goto done;
	}

	aor.s = (char*)VAL_STRING(ROW_VALUES(row) + 15);
	aor.len = strlen(aor.s);

	if (use_domain) {
		domain.s = (char*)VAL_STRING(ROW_VALUES(row) + 17);
		if (VAL_NULL(ROW_VALUES(row)+17) || domain.s==0 || domain.s[0]==0){
			LM_CRIT("empty domain record for user %.*s...skipping\n",
					aor.len, aor.s);
			goto done;
		}
		domain.len = strlen(domain.s);
		if(aor.len + domain.len + 2 >= 512) {
			LM_ERR("AoR is too big\n");
			goto done;
		}
		memcpy(aorbuf, aor.s, aor.len);
		aorbuf[aor.len] = '@';
		memcpy(aorbuf + aor.len + 1, domain.s, domain.len);
		aor.len += 1 + domain.len;
		aor.s = aorbuf;
		aor.s[aor.len] = '\0';
	}
	get_static_urecord( _d, &aor, &r);

	if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
		LM_ERR("mem_insert failed\n");
		free_urecord(r);
		ul_db_layer_free_result(_d, res);
		return 0;
	}

	/* We have to do this, because insert_ucontact sets state to CS_NEW
	 * and we have the contact in the database already */
	c->state = CS_SYNC;

done:
	ul_db_layer_free_result(_d, res);
	;
	return r;
}
Example #15
0
/**
 * Signal handler for the server.
 */
void handle_sigs(void)
{
	pid_t  chld;
	int    chld_status,overall_status=0;
	int    i;
	int    do_exit;
	const unsigned int shutdown_time = 60; /* one minute close timeout */

	switch(sig_flag){
		case 0: break; /* do nothing*/
		case SIGPIPE:
				/* SIGPIPE might be rarely received on use of
				   exec module; simply ignore it
				 */
				LM_WARN("SIGPIPE received and ignored\n");
				break;
		case SIGINT:
		case SIGTERM:
			/* we end the program in all these cases */
			if (sig_flag==SIGINT)
				LM_DBG("INT received, program terminates\n");
			else
				LM_DBG("SIGTERM received, program terminates\n");
				
			/* first of all, kill the children also */
			kill_all_children(SIGTERM);
			if (signal(SIGALRM, sig_alarm_kill) == SIG_ERR ) {
				LM_ERR("could not install SIGALARM handler\n");
				/* continue, the process will die anyway if no
				 * alarm is installed which is exactly what we want */
			}
			alarm(shutdown_time);
			while(wait(0) > 0); /* Wait for all the children to terminate */
			signal(SIGALRM, sig_alarm_abort);

			cleanup(1); /* cleanup & show status*/
			alarm(0);
			signal(SIGALRM, SIG_IGN);
			dprint("Thank you for flying " NAME "\n");
			exit(0);
			break;
			
		case SIGUSR1:
#ifdef PKG_MALLOC
			LM_GEN1(memdump, "Memory status (pkg):\n");
			pkg_status();
#endif
#ifdef SHM_MEM
			LM_GEN1(memdump, "Memory status (shm):\n");
			shm_status();
#endif
			break;
			
		case SIGUSR2:
#ifdef PKG_MALLOC
			set_pkg_stats( get_pkg_status_holder(process_no) );
#endif
			break;
			
		case SIGCHLD:
			do_exit = 0;
			while ((chld=waitpid( -1, &chld_status, WNOHANG ))>0) {
				/* is it a process we know about? */
				for( i=0 ; i<counted_processes ; i++ )
					if (pt[i].pid==chld) break;
				if (i==counted_processes) {
					LM_DBG("unkown child process %d ended. Ignoring\n",chld);
					continue;
				}
				do_exit = 1;
				/* process the signal */
				overall_status |= chld_status;
				LM_DBG("status = %d\n",overall_status);

				if (WIFEXITED(chld_status)) 
					LM_INFO("child process %d exited normally,"
							" status=%d\n", chld, 
							WEXITSTATUS(chld_status));
				else if (WIFSIGNALED(chld_status)) {
					LM_INFO("child process %d exited by a signal"
							" %d\n", chld, WTERMSIG(chld_status));
#ifdef WCOREDUMP
					LM_INFO("core was %sgenerated\n",
							 WCOREDUMP(chld_status) ?  "" : "not " );
#endif
				}else if (WIFSTOPPED(chld_status)) 
					LM_INFO("child process %d stopped by a"
								" signal %d\n", chld,
								 WSTOPSIG(chld_status));
			}
			if (!do_exit)
				break;
			LM_INFO("terminating due to SIGCHLD\n");
			/* exit */
			kill_all_children(SIGTERM);
			if (signal(SIGALRM, sig_alarm_kill) == SIG_ERR ) {
				LM_ERR("could not install SIGALARM handler\n");
				/* continue, the process will die anyway if no
				 * alarm is installed which is exactly what we want */
			}
			alarm(shutdown_time);
			while(wait(0) > 0); /* wait for all the children to terminate*/
			signal(SIGALRM, sig_alarm_abort);
			cleanup(1); /* cleanup & show status*/
			alarm(0);
			signal(SIGALRM, SIG_IGN);
			LM_DBG("terminating due to SIGCHLD\n");
			exit(overall_status ? -1 : 0);
			break;
		
		case SIGHUP: /* ignoring it*/
			LM_DBG("SIGHUP received, ignoring it\n");
			break;
		default:
			LM_CRIT("unhandled signal %d\n", sig_flag);
	}
	sig_flag=0;
}
Example #16
0
static int mi_child_init(void)
{
	if (rls_dbf.init==0)
	{
		LM_CRIT("database not bound\n");
		return -1;
	}
	/* In DB only mode do not pool the connections where possible. */
	if (dbmode == RLS_DB_ONLY && rls_dbf.init2)
		rls_db = rls_dbf.init2(&db_url, DB_POOLING_NONE);
	else
		rls_db = rls_dbf.init(&db_url);
	if (!rls_db)
	{
		LM_ERR("Error while connecting database\n");
		return -1;
	}
	else
	{
		if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0)  
		{
			LM_ERR("Error in use_table rlsubs_table\n");
			return -1;
		}

		LM_DBG("Database connection opened successfully\n");
	}

	if (rlpres_dbf.init==0)
	{
		LM_CRIT("database not bound\n");
		return -1;
	}
	/* In DB only mode do not pool the connections where possible. */
	if (dbmode == RLS_DB_ONLY && rlpres_dbf.init2)
		rlpres_db = rlpres_dbf.init2(&db_url, DB_POOLING_NONE);
	else
		rlpres_db = rlpres_dbf.init(&db_url);
	if (!rlpres_db)
	{
		LM_ERR("Error while connecting database\n");
		return -1;
	}
	else
	{
		if (rlpres_dbf.use_table(rlpres_db, &rlpres_table) < 0)  
		{
			LM_ERR("Error in use_table rlpres_table\n");
			return -1;
		}

		LM_DBG("Database connection opened successfully\n");
	}

	if (rls_xcap_dbf.init==0)
	{
		LM_CRIT("database not bound\n");
		return -1;
	}
	rls_xcap_db = rls_xcap_dbf.init(&xcap_db_url);
	if (!rls_xcap_db)
	{
		LM_ERR("Error while connecting database\n");
		return -1;
	}
	else
	{
		if (rls_xcap_dbf.use_table(rls_xcap_db, &rls_xcap_table) < 0)  
		{
			LM_ERR("Error in use_table rls_xcap_table\n");
			return -1;
		}

		LM_DBG("Database connection opened successfully\n");
	}

	return 0;

}
Example #17
0
/**
 * Main loop, forks the children, bind to addresses,
 * handle signals.
 * \return don't return on sucess, -1 on error
 */
static int main_loop(void)
{
	static int chd_rank;
	int  i,rc;
	pid_t pid;
	struct socket_info* si;
	int* startup_done = NULL;
	stat_var *load_p = NULL;

	chd_rank=0;

	if (dont_fork){

		if (create_status_pipe() < 0) {
			LM_ERR("failed to create status pipe");
			goto error;
		}

		if (udp_listen==0){
			LM_ERR("no fork mode requires at least one"
					" udp listen address, exiting...\n");
			goto error;
		}
		/* only one address, we ignore all the others */
		if (udp_init(udp_listen)==-1) goto error;
		bind_address=udp_listen;
		sendipv4=bind_address;
		sendipv6=bind_address; /*FIXME*/
		if (udp_listen->next){
			LM_WARN("using only the first listen address (no fork)\n");
		}

		/* try to drop privileges */
		if (do_suid(uid, gid)==-1)
			goto error;

		if (start_module_procs()!=0) {
			LM_ERR("failed to fork module processes\n");
			goto error;
		}

		/* we need another process to act as the timer*/
		if (start_timer_processes()!=0) {
			LM_CRIT("cannot start timer process(es)\n");
			goto error;
		}

		/* main process, receive loop */
		set_proc_attrs("stand-alone SIP receiver %.*s", 
			 bind_address->sock_str.len, bind_address->sock_str.s );

		/* We will call child_init even if we
		 * do not fork - and it will be called with rank 1 because
		 * in fact we behave like a child, not like main process */
		if (init_child(1) < 0) {
			LM_ERR("init_child failed in don't fork\n");
			goto error;
		}

		if (startup_rlist.a)
			run_startup_route();

		is_main=1;

		if (register_udp_load_stat(&udp_listen->sock_str,
		&pt[process_no].load, 1)!=0) {
			LM_ERR("failed to init udp load statistics\n");
			goto error;
		}

		clean_write_pipeend();
		LM_DBG("waiting for status code from children\n");
		rc = wait_for_all_children();
		if (rc < 0) {
			LM_ERR("failed to succesfully init children\n");
			return rc;
		}

		return udp_rcv_loop();
	} else {  /* don't fork */

		for(si=udp_listen;si;si=si->next){
			/* create the listening socket (for each address)*/
			/* udp */
			if (udp_init(si)==-1) goto error;
			/* get first ipv4/ipv6 socket*/
			if ((si->address.af==AF_INET)&&
					((sendipv4==0)||(sendipv4->flags&SI_IS_LO)))
				sendipv4=si;
			#ifdef USE_IPV6
			if((sendipv6==0)&&(si->address.af==AF_INET6))
				sendipv6=si;
			#endif
		}
		#ifdef USE_TCP
		if (!tcp_disable){
			for(si=tcp_listen; si; si=si->next){
				/* same thing for tcp */
				if (tcp_init(si)==-1)  goto error;
				/* get first ipv4/ipv6 socket*/
				if ((si->address.af==AF_INET)&
						((sendipv4_tcp==0)||(sendipv4_tcp->flags&SI_IS_LO)))
					sendipv4_tcp=si;
				#ifdef USE_IPV6
				if((sendipv6_tcp==0)&&(si->address.af==AF_INET6))
					sendipv6_tcp=si;
				#endif
			}
		}
		#ifdef USE_TLS
		if (!tls_disable){
			for(si=tls_listen; si; si=si->next){
				/* same as for tcp*/
				if (tls_init(si)==-1)  goto error;
				/* get first ipv4/ipv6 socket*/
				if ((si->address.af==AF_INET)&&
						((sendipv4_tls==0)||(sendipv4_tls->flags&SI_IS_LO)))
					sendipv4_tls=si;
				#ifdef USE_IPV6
				if((sendipv6_tls==0)&&(si->address.af==AF_INET6))
					sendipv6_tls=si;
				#endif
			}
		}
		#endif /* USE_TLS */
		#endif /* USE_TCP */
		#ifdef USE_SCTP
		if (!sctp_disable){
			for(si=sctp_listen; si; si=si->next){
				/* same thing for sctp */
				if (sctp_server_init(si)==-1)  goto error;
				/* get first ipv4/ipv6 socket*/
				if ((si->address.af==AF_INET)&&
						((sendipv4_sctp==0)||(sendipv4_sctp->flags&SI_IS_LO)))
					sendipv4_sctp=si;
			#ifdef USE_IPV6
				if((sendipv6_sctp==0)&&(si->address.af==AF_INET6))
					sendipv6_sctp=si;
			#endif
			}
		}
		#endif /* USE_SCTP */

		/* all processes should have access to all the sockets (for sending)
		 * so we open all first*/
		if (do_suid(uid, gid)==-1) goto error; /* try to drop privileges */

		if (start_module_procs()!=0) {
			LM_ERR("failed to fork module processes\n");
			goto error;
		}

		if(startup_rlist.a) {/* if a startup route was defined */
			startup_done = (int*)shm_malloc(sizeof(int));
			if(startup_done == NULL) {
				LM_ERR("No more shared memory\n");
				goto error;
			}
			*startup_done = 0;
		}

		/* udp processes */
		for(si=udp_listen; si; si=si->next){

			if(register_udp_load_stat(&si->sock_str,&load_p,si->children)!=0){
				LM_ERR("failed to init load statistics\n");
				goto error;
			}

			for(i=0;i<si->children;i++){
				chd_rank++;
				if ( (pid=internal_fork( "UDP receiver"))<0 ) {
					LM_CRIT("cannot fork UDP process\n");
					goto error;
				} else {
					if (pid==0) {
						/* new UDP process */
						/* set a more detailed description */
						set_proc_attrs("SIP receiver %.*s ",
							si->sock_str.len, si->sock_str.s);
						bind_address=si; /* shortcut */
						if (init_child(chd_rank) < 0) {
							LM_ERR("init_child failed for UDP listener\n");
							if (send_status_code(-1) < 0)
								LM_ERR("failed to send status code\n");
							clean_write_pipeend();
							if (chd_rank == 1 && startup_done)
								*startup_done = -1;
							exit(-1);
						}

						/* first UDP proc runs statup_route (if defined) */
						if(chd_rank == 1 && startup_done!=NULL) {
							LM_DBG("runing startup for first UDP\n");
							if(run_startup_route()< 0) {
								if (send_status_code(-1) < 0)
									LM_ERR("failed to send status code\n");
								clean_write_pipeend();
								*startup_done = -1;
								LM_ERR("Startup route processing failed\n");
								exit(-1);
							}
							*startup_done = 1;
						}

						if (!no_daemon_mode && send_status_code(0) < 0)
							LM_ERR("failed to send status code\n");
						clean_write_pipeend();


						/* all UDP listeners on same interface
						 * have same SHM load pointer */
						pt[process_no].load = load_p;
						udp_rcv_loop();
						exit(-1);
					}
					else {
						/* wait for first proc to finish the startup route */
						if(chd_rank == 1 && startup_done!=NULL)
							while( !(*startup_done) ) usleep(5);
					}
				}
			}
			/*parent*/
			/*close(udp_sock)*/; /*if it's closed=>sendto invalid fd errors?*/
		}
	}

	#ifdef USE_SCTP
	if(!sctp_disable){
		for(si=sctp_listen; si; si=si->next){
			for(i=0;i<si->children;i++){
				chd_rank++;
				if ( (pid=internal_fork( "SCTP receiver"))<0 ) {
					LM_CRIT("cannot fork SCTP process\n");
					goto error;
				} else if (pid==0){
					/* new SCTP process */
					/* set a more detailed description */
					set_proc_attrs("SIP receiver %.*s ",
						si->sock_str.len, si->sock_str.s);
					bind_address=si; /* shortcut */
					if (init_child(chd_rank) < 0) {
						LM_ERR("init_child failed\n");
						if (send_status_code(-1) < 0)
							LM_ERR("failed to send status code\n");
						clean_write_pipeend();
						if( (si==sctp_listen && i==0) && startup_done)
							*startup_done = -1;
						exit(-1);
					}

					/* was startup route executed so far ? if not, run it only by the 
					 * first SCTP proc (first proc from first interface) */
					if( (si==sctp_listen && i==0) && startup_done!=NULL && *startup_done==0) {
						LM_DBG("runing startup for first SCTP\n");
						if(run_startup_route()< 0) {
							LM_ERR("Startup route processing failed\n");
							if (send_status_code(-1) < 0)
								LM_ERR("failed to send status code\n");
							clean_write_pipeend();
							*startup_done = -1;
							exit(-1);
						}
						*startup_done = 1;
					}

					if (!no_daemon_mode && send_status_code(0) < 0)
						LM_ERR("failed to send status code\n");
					clean_write_pipeend();

					sctp_server_rcv_loop();
					exit(-1);
				} else {
					/* wait for first proc to finish the startup route */
					if( (si==sctp_listen && i==0) && startup_done!=NULL)
						while( !(*startup_done) ) usleep(5);
				}
			}
		}
	}
	#endif /* USE_SCTP */

	/* this is the main process -> it shouldn't send anything */
	bind_address=0;

	/* fork for the timer process*/
	if (start_timer_processes()!=0) {
		LM_CRIT("cannot start timer process(es)\n");
		goto error;
	}

	#ifdef USE_TCP
	if (!tcp_disable){
		/* start tcp  & tls receivers */
		if (tcp_init_children(&chd_rank, startup_done)<0) goto error;
		/* wait for the startup route to be executed */
		if( startup_done!=NULL)
			while( !(*startup_done) ) usleep(5);
		/* start tcp+tls master proc */
		if ( (pid=internal_fork( "TCP main"))<0 ) {
			LM_CRIT("cannot fork tcp main process\n");
			goto error;
		}else if (pid==0){
			/* child */
			/* close the TCP inter-process sockets */
			close(unix_tcp_sock);
			unix_tcp_sock = -1;
			close(pt[process_no].unix_sock);
			pt[process_no].unix_sock = -1;
			/* init modules */
			if (init_child(PROC_TCP_MAIN) < 0) {
				LM_ERR("error in init_child for tcp main\n");
				if (send_status_code(-1) < 0)
					LM_ERR("failed to send status code\n");
				clean_write_pipeend();

				exit(-1);
			}

			if (!no_daemon_mode && send_status_code(0) < 0)
				LM_ERR("failed to send status code\n");
			clean_write_pipeend();

			tcp_main_loop();
			exit(-1);
		}
	}
	#endif

	if (startup_done) {
		if (*startup_done==0)
			LM_CRIT("BUG: startup route defined, but not run :( \n");
		shm_free(startup_done);
	}

	/* main process left */
	is_main=1;
	set_proc_attrs("attendant");

	if (init_child(PROC_MAIN) < 0) {
		if (send_status_code(-1) < 0)
			LM_ERR("failed to send status code\n");
		clean_write_pipeend();
		LM_ERR("error in init_child for PROC_MAIN\n");
		goto error;
	}

	if (!no_daemon_mode && send_status_code(0) < 0)
		LM_ERR("failed to send status code\n");
	clean_write_pipeend();

	for(;;){
			handle_sigs();
			pause();
	}

	/*return 0; */
error:
	is_main=1;  /* if we are here, we are the "main process",
				  any forked children should exit with exit(-1) and not
				  ever use return */
	if (!dont_fork && send_status_code(-1) < 0)
		LM_ERR("failed to send status code\n");
	clean_write_pipeend();

	return -1;

}
Example #18
0
/**
 * Receive a file descriptor from another process
 * @param pipe_fd - pipe to read from
 * @param fd - file descriptor to fill
 * @param p - optional pipe to fill
 * @returns 1 on success or 0 on failure
 */
static int receive_fd(int pipe_fd, int* fd,peer **p)
{
	struct msghdr msg;
	struct iovec iov[1];
	int new_fd;
	int ret;

#ifdef HAVE_MSGHDR_MSG_CONTROL
	struct cmsghdr* cmsg;
	union{
		struct cmsghdr cm;
		char control[CMSG_SPACE(sizeof(new_fd))];
	}control_un;

	msg.msg_control=control_un.control;
	msg.msg_controllen=sizeof(control_un.control);
#else
	msg.msg_accrights=(caddr_t) &new_fd;
	msg.msg_accrightslen=sizeof(int);
#endif

	msg.msg_name=0;
	msg.msg_namelen=0;

	iov[0].iov_base=p;
	iov[0].iov_len=sizeof(peer*);
	msg.msg_iov=iov;
	msg.msg_iovlen=1;

again:
	ret=recvmsg(pipe_fd, &msg, MSG_DONTWAIT|MSG_WAITALL);
	if (ret<0){
		if (errno==EINTR) goto again;
		if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) goto error;
		LM_CRIT( "receive_fd: recvmsg on %d failed: %s\n",
				pipe_fd, strerror(errno));
		goto error;
	}
	if (ret==0){
		/* EOF */
		LM_CRIT( "receive_fd: EOF on %d\n", pipe_fd);
		goto error;
	}
	if (ret!=sizeof(peer *)){
		LM_WARN("receive_fd: different number of bytes received than expected (%d from %ld)"
				    "trying to fix...\n", ret, (long int)sizeof(peer*));
		goto error;
	}

#ifdef HAVE_MSGHDR_MSG_CONTROL
	cmsg=CMSG_FIRSTHDR(&msg);
	if ((cmsg!=0) && (cmsg->cmsg_len==CMSG_LEN(sizeof(new_fd)))){
		if (cmsg->cmsg_type!= SCM_RIGHTS){
			LM_ERR("receive_fd: msg control type != SCM_RIGHTS\n");
			goto error;
		}
		if (cmsg->cmsg_level!= SOL_SOCKET){
			LM_ERR("receive_fd: msg level != SOL_SOCKET\n");
			goto error;
		}
		*fd=*((int*) CMSG_DATA(cmsg));
	}else{
		if(!cmsg)
			LM_ERR("receive_fd: no descriptor passed, empty control message");
		else
			LM_ERR("receive_fd: no descriptor passed, cmsg=%p,"
				"len=%d\n", cmsg, (unsigned)cmsg->cmsg_len);
		*fd=-1;
		*p=0;
		/* it's not really an error */
	}
#else
	if (msg.msg_accrightslen==sizeof(int)){
		*fd=new_fd;
	}else{
		LM_ERR("receive_fd: no descriptor passed,"
				" accrightslen=%d\n", msg.msg_accrightslen);
		*fd=-1;
	}
#endif

	return 1;
error:
	return 0;
}
Example #19
0
static int mod_init(void)
{
    LM_DBG("initializing\n");
	
    if (register_mi_mod(exports.name, mi_cmds) != 0) {
	LM_ERR("failed to register MI commands\n");
	return -1;
    }
    if (domain_init_rpc() != 0) {
	LM_ERR("failed to register RPC commands\n");
	return -1;
    }

    if (domain_reg_myself !=0 ) {
	if (register_check_self_func(domain_check_self) <0 ) {
	    LM_ERR("failed to register check self function\n");
	    return -1;
	}
    }

    /* Bind database */
    if (domain_db_bind(&db_url)) {
	LM_DBG("Usign db_url [%.*s]\n", db_url.len, db_url.s);
	LM_ERR("no database module found. Have you configure thed \"db_url\" modparam properly?\n");
	return -1;
    }

    /* Check table versions */
    if (domain_db_init(&db_url) < 0) {
	LM_ERR("unable to open database connection\n");
	return -1;
    }
    if (domain_db_ver(&domain_table, DOMAIN_TABLE_VERSION) < 0) {
	LM_ERR("error during check of domain table version\n");
	domain_db_close();
	goto error;
    }
    if (domain_db_ver(&domain_attrs_table, DOMAIN_ATTRS_TABLE_VERSION) < 0) {
	LM_ERR("error during check of domain_attrs table version\n");
	domain_db_close();
	goto error;
    }
    domain_db_close();

    /* Initializing hash tables and hash table variable */
    hash_table = (struct domain_list ***)shm_malloc
	(sizeof(struct domain_list *));
    hash_table_1 = (struct domain_list **)shm_malloc
	(sizeof(struct domain_list *) * (DOM_HASH_SIZE + 1));
    hash_table_2 = (struct domain_list **)shm_malloc
	(sizeof(struct domain_list *) * (DOM_HASH_SIZE + 1));
    if ((hash_table == 0) || (hash_table_1 == 0) || (hash_table_2 == 0)) {
	LM_ERR("no memory for hash table\n");
	goto error;
    }
    memset(hash_table_1, 0, sizeof(struct domain_list *) *
	   DOM_HASH_SIZE + 1);
    memset(hash_table_2, 0, sizeof(struct domain_list *) *
	   DOM_HASH_SIZE + 1);
    *hash_table = hash_table_1;

    /* Allocate and initialize locks */
    reload_lock = lock_alloc();
    if (reload_lock == NULL) {
	LM_ERR("cannot allocate reload_lock\n");
	goto error;
    }
    if (lock_init(reload_lock) == NULL) {
	LM_ERR("cannot init reload_lock\n");
	goto error;
    }

    /* First reload */
    lock_get(reload_lock);
    if (reload_tables() == -1) {
	lock_release(reload_lock);
	LM_CRIT("domain reload failed\n");
	goto error;
    }
    lock_release(reload_lock);

    return 0;

error:
    destroy();
    return -1;
}
Example #20
0
void* fm_realloc(struct fm_block* qm, void* p, unsigned long size)
#endif
{
	struct fm_frag *f;
	unsigned long diff;
	unsigned long orig_size;
	struct fm_frag *n;
	void *ptr;


	#ifdef DBG_F_MALLOC
	LM_DBG("params(%p, %p, %lu), called from %s: %s(%d)\n", qm, p, size,
			file, func, line);
	if ((p)&&(p>(void*)qm->last_frag || p<(void*)qm->first_frag)){
		LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p);
		abort();
	}
	#endif
	if (size==0) {
		if (p)
	#ifdef DBG_F_MALLOC
			fm_free(qm, p, file, func, line);
	#else
			fm_free(qm, p);
	#endif
		pkg_threshold_check();
		return 0;
	}
	if (p==0)
	#ifdef DBG_F_MALLOC
		return fm_malloc(qm, size, file, func, line);
	#else
		return fm_malloc(qm, size);
	#endif
	f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
	#ifdef DBG_F_MALLOC
	LM_DBG("realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
			f, f->file, f->func, f->line);
	#endif
	size=ROUNDUP(size);
	orig_size=f->size;
	if (f->size > size){
		/* shrink */
		#ifdef DBG_F_MALLOC
		LM_DBG("shrinking from %lu to %lu\n", f->size, size);
		fm_split_frag(qm, f, size, file, "frag. from fm_realloc", line);
		#else
		fm_split_frag(qm, f, size);
		#endif

	}else if (f->size<size){
		/* grow */

		#ifdef DBG_F_MALLOC
		LM_DBG("growing from %lu to %lu\n", f->size, size);
		#endif

		diff=size-f->size;
		n=FRAG_NEXT(f);

		if (((char*)n < (char*)qm->last_frag) &&  n->prev &&
		 ((n->size+FRAG_OVERHEAD)>=diff)){

			fm_remove_free(qm,n);
			/* join */
			f->size += n->size + FRAG_OVERHEAD;

			#if defined(DBG_F_MALLOC) || defined(STATISTICS)
			//qm->real_used -= FRAG_OVERHEAD;
			qm->used += FRAG_OVERHEAD;
			#endif

			/* split it if necessary */
			if (f->size > size){
				#ifdef DBG_F_MALLOC
				fm_split_frag(qm, f, size, file, "fragm. from fm_realloc",
						line);
				#else
				fm_split_frag(qm, f, size);
				#endif
			}
		}else{
			/* could not join => realloc */
			#ifdef DBG_F_MALLOC
			ptr=fm_malloc(qm, size, file, func, line);
			#else
			ptr = fm_malloc(qm, size);
			#endif
			if (ptr) {
				/* copy, need by libssl */
				memcpy(ptr, p, orig_size);
				#ifdef DBG_F_MALLOC
				fm_free(qm, p, file, func, line);
				#else
				fm_free(qm, p);
				#endif
			}
			p = ptr;
		}
	}else{
		/* do nothing */
	#ifdef DBG_F_MALLOC
		LM_DBG("doing nothing, same size: %lu - %lu\n", f->size, size);
	#endif
	}
	#ifdef DBG_F_MALLOC
	LM_DBG("returning %p\n", p);
	#endif

	#if defined(DBG_F_MALLOC) || defined(STATISTICS)
	if (qm->max_real_used<qm->real_used)
		qm->max_real_used=qm->real_used;
	#endif

	pkg_threshold_check();
	return p;
}
Example #21
0
/*! \brief
 * Init module function
 */
static int mod_init(void)
{
	
	LM_INFO("initializing module...\n");
	
	/* Group matching feature */
	if (file == NULL) {
		LM_NOTICE("'file' parameter is not set, group matching disabled\n");
	} else {
		/* Create and init the lock */
		reload_lock = lock_alloc();
		if (reload_lock == NULL) {
			LM_ERR("cannot allocate reload_lock\n");
			goto err;
		}
		if (lock_init(reload_lock) == NULL) {
			LM_ERR("cannot init the reload_lock\n");
			lock_dealloc(reload_lock);
			goto err;
		}
		
		/* PCRE options */
		if (pcre_caseless != 0) {
			LM_DBG("PCRE CASELESS enabled\n");
			pcre_options = pcre_options | PCRE_CASELESS;
		}
		if (pcre_multiline != 0) {
			LM_DBG("PCRE MULTILINE enabled\n");
			pcre_options = pcre_options | PCRE_MULTILINE;
		}
		if (pcre_dotall != 0) {
			LM_DBG("PCRE DOTALL enabled\n");
			pcre_options = pcre_options | PCRE_DOTALL;
		}
		if (pcre_extended != 0) {
			LM_DBG("PCRE EXTENDED enabled\n");
			pcre_options = pcre_options | PCRE_EXTENDED;
		}
		LM_DBG("PCRE options: %i\n", pcre_options);
		
		/* Pointer to pcres */
		if ((pcres_addr = shm_malloc(sizeof(pcre **))) == 0) {
			LM_ERR("no memory for pcres_addr\n");
			goto err;
		}
		
		/* Integer containing the number of pcres */
		if ((num_pcres = shm_malloc(sizeof(int))) == 0) {
			LM_ERR("no memory for num_pcres\n");
			goto err;
		}
		
		/* Load the pcres */
		LM_NOTICE("loading pcres...\n");
		if (load_pcres(START)) {
			LM_CRIT("failed to load pcres\n");
			goto err;
		}
	}
	
	return 0;
	
err:
	free_shared_memory();
	return -1;
}
Example #22
0
/**
 * Main loop, forks the children, bind to addresses,
 * handle signals.
 * \return don't return on sucess, -1 on error
 */
static int main_loop(void)
{
	static int chd_rank;
	int* startup_done = NULL;

	chd_rank=0;

	if (start_module_procs()!=0) {
		LM_ERR("failed to fork module processes\n");
		goto error;
	}

	if(startup_rlist.a) {/* if a startup route was defined */
		startup_done = (int*)shm_malloc(sizeof(int));
		if(startup_done == NULL) {
			LM_ERR("No more shared memory\n");
			goto error;
		}
		*startup_done = 0;
	}

	/* fork for the timer process*/
	if (start_timer_processes()!=0) {
		LM_CRIT("cannot start timer process(es)\n");
		goto error;
	}

	/* fork all processes required by UDP network layer */
	if (udp_start_processes( &chd_rank, startup_done)<0) {
		LM_CRIT("cannot start TCP processes\n");
		goto error;
	}

	/* fork all processes required by TCP network layer */
	if (tcp_start_processes( &chd_rank, startup_done)<0) {
		LM_CRIT("cannot start TCP processes\n");
		goto error;
	}

	/* this is the main process -> it shouldn't send anything */
	bind_address=0;

	if (startup_done) {
		if (*startup_done==0)
			LM_CRIT("BUG: startup route defined, but not run :( \n");
		shm_free(startup_done);
	}

	/* main process left */
	is_main=1;
	set_proc_attrs("attendant");

	if (init_child(PROC_MAIN) < 0) {
		LM_ERR("error in init_child for PROC_MAIN\n");
		report_failure_status();
		goto error;
	}

	report_conditional_status( (!no_daemon_mode), 0);

	for(;;){
			handle_sigs();
			pause();
	}

	/*return 0; */
error:
	is_main=1;  /* if we are here, we are the "main process",
				  any forked children should exit with exit(-1) and not
				  ever use return */
	report_failure_status();
	return -1;

}
Example #23
0
/*!
 * \brief Destroy a dialog, run callbacks and free memory
 * \param dlg destroyed dialog
 */
inline void destroy_dlg(struct dlg_cell *dlg)
{
	int ret = 0;
	struct dlg_var *var;

	LM_DBG("destroying dialog %p (ref %d)\n", dlg, dlg->ref);

	ret = remove_dialog_timer(&dlg->tl);
	if (ret < 0) {
		LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
			"with clid '%.*s' and tags '%.*s' '%.*s'\n",
			dlg, dlg->h_entry, dlg->h_id,
			dlg->callid.len, dlg->callid.s,
			dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
			dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
	} else if (ret > 0) {
		LM_DBG("removed timer for dlg %p [%u:%u] "
			"with clid '%.*s' and tags '%.*s' '%.*s'\n",
			dlg, dlg->h_entry, dlg->h_id,
			dlg->callid.len, dlg->callid.s,
			dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
			dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
	}

	run_dlg_callbacks( DLGCB_DESTROY , dlg, NULL, NULL, DLG_DIR_NONE, 0);


	/* delete the dialog from DB*/
	if (dlg_db_mode)
		remove_dialog_from_db(dlg);

	if (dlg->cbs.first)
		destroy_dlg_callbacks_list(dlg->cbs.first);

	if (dlg->profile_links)
		destroy_linkers(dlg->profile_links);

	if (dlg->tag[DLG_CALLER_LEG].s)
		shm_free(dlg->tag[DLG_CALLER_LEG].s);

	if (dlg->tag[DLG_CALLEE_LEG].s)
		shm_free(dlg->tag[DLG_CALLEE_LEG].s);

	if (dlg->cseq[DLG_CALLER_LEG].s)
		shm_free(dlg->cseq[DLG_CALLER_LEG].s);

	if (dlg->cseq[DLG_CALLEE_LEG].s)
		shm_free(dlg->cseq[DLG_CALLEE_LEG].s);

	if (dlg->toroute_name.s)
		shm_free(dlg->toroute_name.s);

	
	while (dlg->vars) {
		var = dlg->vars;
		dlg->vars = dlg->vars->next;
		shm_free(var->key.s);
		shm_free(var->value.s);
		shm_free(var);
	}


	shm_free(dlg);
	dlg = 0;
}
Example #24
0
/**
 * Main routine, start of the program execution.
 * \param argc the number of arguments
 * \param argv pointer to the arguments array
 * \return don't return on sucess, -1 on error
 * \see main_loop
 */
int main(int argc, char** argv)
{
	/* configure by default logging to syslog */
	int cfg_log_stderr = 1;
	FILE* cfg_stream;
	int c,r;
	char *tmp;
	int tmp_len;
	int port;
	int proto;
	char *options;
	int ret;
	unsigned int seed;
	int rfd;

	/*init*/
	ret=-1;
	my_argc=argc; my_argv=argv;

	/* process pkg mem size from command line */
	opterr=0;
	options="f:cCm:M:b:l:n:N:rRvdDFETSVhw:t:u:g:P:G:W:o:";

	while((c=getopt(argc,argv,options))!=-1){
		switch(c){
			case 'M':
					pkg_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
					if (tmp &&(*tmp)){
						LM_ERR("bad pkgmem size number: -m %s\n", optarg);
						goto error00;
					};

					break;
		}
	}
	/*init pkg mallocs (before parsing cfg but after parsing cmd line !)*/
	if (init_pkg_mallocs()==-1)
		goto error00;

	init_route_lists();

	/* process command line (get port no, cfg. file path etc) */
	/* first reset getopt */
	optind = 1;
	while((c=getopt(argc,argv,options))!=-1){
		switch(c){
			case 'f':
					cfg_file=optarg;
					break;
			case 'C':
					config_check |= 2;
			case 'c':
					if (config_check==3)
						break;
					config_check |= 1;
					cfg_log_stderr=1; /* force stderr logging */
					break;
			case 'm':
					shm_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
					if (tmp &&(*tmp)){
						LM_ERR("bad shmem size number: -m %s\n", optarg);
						goto error00;
					};
					break;
			case 'M':
					/* ignoring it, parsed previously */
					break;
			case 'b':
					maxbuffer=strtol(optarg, &tmp, 10);
					if (tmp &&(*tmp)){
						LM_ERR("bad max buffer size number: -b %s\n", optarg);
						goto error00;
					}
					break;
			case 'l':
					if (parse_phostport(optarg, strlen(optarg), &tmp, &tmp_len,
											&port, &proto)<0){
						LM_ERR("bad -l address specifier: %s\n", optarg);
						goto error00;
					}
					tmp[tmp_len]=0; /* null terminate the host */
					/* add a new addr. to our address list */
					if (add_cmd_listener(tmp, port, proto)!=0){
						LM_ERR("failed to add new listen address\n");
						goto error00;
					}
					break;
			case 'n':
					children_no=strtol(optarg, &tmp, 10);
					if ((tmp==0) ||(*tmp)){
						LM_ERR("bad process number: -n %s\n", optarg);
						goto error00;
					}
					break;
			case 'v':
					check_via=1;
					break;
			case 'r':
					received_dns|=DO_DNS;
					break;
			case 'R':
					received_dns|=DO_REV_DNS;
				    break;
			case 'd':
					*log_level = debug_mode ? L_DBG : (*log_level)+1;
					break;
			case 'D':
					debug_mode=1;
					*log_level = L_DBG;
					break;
			case 'F':
					no_daemon_mode=1;
					break;
			case 'E':
					cfg_log_stderr=1;
					break;
			case 'N':
					tcp_children_no=strtol(optarg, &tmp, 10);
					if ((tmp==0) ||(*tmp)){
						LM_ERR("bad process number: -N %s\n", optarg);
						goto error00;
					}
					break;
			case 'W':
					io_poll_method=get_poll_type(optarg);
					if (io_poll_method==POLL_NONE){
						LM_ERR("bad poll method name: -W %s\ntry "
							"one of %s.\n", optarg, poll_support);
						goto error00;
					}
					break;
			case 'V':
					printf("version: %s\n", version);
					printf("flags: %s\n", flags );
					print_ct_constants();
					printf("%s compiled on %s with %s\n", __FILE__,
							compiled, COMPILER );
					exit(0);
					break;
			case 'h':
					printf("version: %s\n", version);
					printf("%s",help_msg);
					exit(0);
					break;
			case 'w':
					working_dir=optarg;
					break;
			case 't':
					chroot_dir=optarg;
					break;
			case 'u':
					user=optarg;
					break;
			case 'g':
					group=optarg;
					break;
			case 'P':
					pid_file=optarg;
					break;
			case 'G':
					pgid_file=optarg;
					break;
			case 'o':
					if (add_arg_var(optarg) < 0)
						LM_ERR("cannot add option %s\n", optarg);
					break;
			case '?':
					if (isprint(optopt))
						LM_ERR("Unknown option `-%c`.\n", optopt);
					else
						LM_ERR("Unknown option character `\\x%x`.\n", optopt);
					goto error00;
			case ':':
					LM_ERR("Option `-%c` requires an argument.\n", optopt);
					goto error00;
			default:
					abort();
		}
	}

	log_stderr = cfg_log_stderr;

	/* fill missing arguments with the default values*/
	if (cfg_file==0) cfg_file=CFG_FILE;

	/* load config file or die */
	cfg_stream=fopen (cfg_file, "r");
	if (cfg_stream==0){
		LM_ERR("loading config file(%s): %s\n", cfg_file,
				strerror(errno));
		goto error00;
	}

	/* seed the prng, try to use /dev/urandom if possible */
	/* no debugging information is logged, because the standard
	   log level prior the config file parsing is L_NOTICE */
	seed=0;
	if ((rfd=open("/dev/urandom", O_RDONLY))!=-1){
try_again:
		if (read(rfd, (void*)&seed, sizeof(seed))==-1){
			if (errno==EINTR) goto try_again; /* interrupted by signal */
			LM_WARN("could not read from /dev/urandom (%d)\n", errno);
		}
		LM_DBG("initialize the pseudo random generator from "
			"/dev/urandom\n");
		LM_DBG("read %u from /dev/urandom\n", seed);
			close(rfd);
	}else{
		LM_WARN("could not open /dev/urandom (%d)\n", errno);
		LM_WARN("using a unsafe seed for the pseudo random number generator");
	}
	seed+=getpid()+time(0);
	LM_DBG("seeding PRNG with %u\n", seed);
	srand(seed);
	LM_DBG("test random number %u\n", rand());

	/*register builtin  modules*/
	register_builtin_modules();

	/* init avps */
	if (init_global_avps() != 0) {
		LM_ERR("error while initializing avps\n");
		goto error;
	}

	/* used for parser debugging */
#ifdef DEBUG_PARSER
	yydebug = 1;
#endif

	/*
	 * initializes transport interfaces - we initialize them here because we
	 * can have listening interfaces declared in the command line
	 */
	if (trans_init() < 0) {
		LM_ERR("cannot initialize transport interface\n");
		goto error;
	}

		/* get uid/gid */
	if (user){
		if (user2uid(&uid, &gid, user)<0){
			LM_ERR("bad user name/uid number: -u %s\n", user);
			goto error00;
		}
	}
	if (group){
		if (group2gid(&gid, group)<0){
			LM_ERR("bad group name/gid number: -u %s\n", group);
			goto error00;
		}
	}

		/*init shm mallocs
	 *  this must be here
	 *     -to allow setting shm mem size from the command line
	 *     -it must be also before init_timer and init_tcp
	 *     -it must be after we know uid (so that in the SYSV sems case,
	 *        the sems will have the correct euid)
	 * --andrei */
	if (init_shm_mallocs()==-1)
		goto error;

	if (init_stats_collector() < 0) {
		LM_ERR("failed to initialize statistics\n");
		goto error;
	}

	/* parse the config file, prior to this only default values
	   e.g. for debugging settings will be used */
	yyin=cfg_stream;
	if ((yyparse()!=0)||(cfg_errors)){
		LM_ERR("bad config file (%d errors)\n", cfg_errors);
		goto error00;
	}

	if (config_check>1 && check_rls()!=0) {
		LM_ERR("bad function call in config file\n");
		return ret;
	}

	if (solve_module_dependencies(modules) != 0) {
		LM_ERR("failed to solve module dependencies\n");
		return -1;
	}

	/* init the resolver, before fixing the config */
	resolv_init();

	fix_poll_method( &io_poll_method );

	/* fix temporary listeners added in the cmd line */
	if (fix_cmd_listeners() < 0) {
		LM_ERR("cannot add temproray listeners\n");
		return ret;
	}

	/* load transport protocols */
	if (trans_load() < 0) {
		LM_ERR("cannot load transport protocols\n");
		goto error;
	}

	/* fix parameters */
	if (working_dir==0) working_dir="/";

	if (fix_all_socket_lists()!=0){
		LM_ERR("failed to initialize list addresses\n");
		goto error00;
	}
	/* print all the listen addresses */
	printf("Listening on \n");
	print_all_socket_lists();
	printf("Aliases: \n");
	/*print_aliases();*/
	print_aliases();
	printf("\n");

	if (config_check){
		LM_NOTICE("config file ok, exiting...\n");
		return 0;
	}

	time(&startup_time);

	/* Init statistics */
	init_shm_statistics();

	/*init UDP networking layer*/
	if (udp_init()<0){
		LM_CRIT("could not initialize tcp\n");
		goto error;
	}
	/*init TCP networking layer*/
	if (tcp_init()<0){
		LM_CRIT("could not initialize tcp\n");
		goto error;
	}

	if (create_status_pipe() < 0) {
		LM_ERR("failed to create status pipe\n");
		goto error;
	}

	if (debug_mode) {

		LM_NOTICE("DEBUG MODE activated\n");
		if (no_daemon_mode==0) {
			LM_NOTICE("disabling daemon mode (found enabled)\n");
			no_daemon_mode = 1;
		}
		if (log_stderr==0) {
			LM_NOTICE("enabling logging to standard error (found disabled)\n");
			log_stderr = 1;
		}
		if (*log_level<L_DBG) {
			LM_NOTICE("setting logging to debug level (found on %d)\n",
				*log_level);
			*log_level = L_DBG;
		}
		if (disable_core_dump) {
			LM_NOTICE("enabling core dumping (found off)\n");
			disable_core_dump = 0;
		}
		if (udp_count_processes()!=0) {
			if (children_no!=2) {
				LM_NOTICE("setting UDP children to 2 (found %d)\n",
					children_no);
				children_no = 2;
			}
		}
		if (tcp_count_processes()!=0) {
			if (tcp_children_no!=2) {
				LM_NOTICE("setting TCP children to 2 (found %d)\n",
					tcp_children_no);
				tcp_children_no = 2;
			}
		}

	} else { /* debug_mode */

		/* init_daemon */
		if ( daemonize((log_name==0)?argv[0]:log_name, &own_pgid) <0 )
			goto error;

	}

	/* install signal handlers */
	if (install_sigs() != 0){
		LM_ERR("could not install the signal handlers\n");
		goto error;
	}

	if (disable_core_dump) set_core_dump(0, 0);
	else set_core_dump(1, shm_mem_size+pkg_mem_size+4*1024*1024);
	if (open_files_limit>0) {
		if(set_open_fds_limit()<0){
			LM_ERR("ERROR: error could not increase file limits\n");
			goto error;
		}
	}

	/* print OpenSIPS version to log for history tracking */
	LM_NOTICE("version: %s\n", version);

	/* print some data about the configuration */
	LM_INFO("using %ld Mb shared memory\n", ((shm_mem_size/1024)/1024));
	LM_INFO("using %ld Mb private memory per process\n",
		((pkg_mem_size/1024)/1024));

	/* init async reactor */
	if (init_reactor_size()<0) {
		LM_CRIT("failed to init internal reactor, exiting...\n");
		goto error;
	}

	/* init timer */
	if (init_timer()<0){
		LM_CRIT("could not initialize timer, exiting...\n");
		goto error;
	}

	/* init serial forking engine */
	if (init_serialization()!=0) {
		LM_ERR("failed to initialize serialization\n");
		goto error;
	}
	/* Init MI */
	if (init_mi_core()<0) {
		LM_ERR("failed to initialize MI core\n");
		goto error;
	}

	/* Register core events */
	if (evi_register_core() != 0) {
		LM_ERR("failed register core events\n");
		goto error;
	}

	/* init black list engine */
	if (init_black_lists()!=0) {
		LM_CRIT("failed to init blacklists\n");
		goto error;
	}
	/* init resolver's blacklist */
	if (resolv_blacklist_init()!=0) {
		LM_CRIT("failed to create DNS blacklist\n");
		goto error;
	}

	/* init modules */
	if (init_modules() != 0) {
		LM_ERR("error while initializing modules\n");
		goto error;
	}

	/* register route timers */
	if(register_route_timers() < 0) {
		LM_ERR("Failed to register timer\n");
		goto error;
	}

	/* check pv context list */
	if(pv_contextlist_check() != 0) {
		LM_ERR("used pv context that was not defined\n");
		goto error;
	}

	/* init query list now in shm
	 * so all processes that will be forked from now on
	 * will have access to it
	 *
	 * if it fails, give it a try and carry on */
	if (init_ql_support() != 0) {
		LM_ERR("failed to initialise buffering query list\n");
		query_buffer_size = 0;
		*query_list = NULL;
	}

	/* init multi processes support */
	if (init_multi_proc_support()!=0) {
		LM_ERR("failed to init multi-proc support\n");
		goto error;
	}

	#ifdef PKG_MALLOC
	/* init stats support for pkg mem */
	if (init_pkg_stats(counted_processes)!=0) {
		LM_ERR("failed to init stats for pkg\n");
		goto error;
	}
	#endif

	/* init avps */
	if (init_extra_avps() != 0) {
		LM_ERR("error while initializing avps\n");
		goto error;
	}

	/* fix routing lists */
	if ( (r=fix_rls())!=0){
		LM_ERR("failed to fix configuration with err code %d\n", r);
		goto error;
	}

	if (init_log_level() != 0) {
		LM_ERR("failed to init logging levels\n");
		goto error;
	}

	if (trans_init_all_listeners()<0) {
		LM_ERR("failed to init all SIP listeners, aborting\n");
		goto error;
	}

	/* all processes should have access to all the sockets (for sending)
	 * so we open all first*/
	if (do_suid(uid, gid)==-1)
		goto error;

	ret = main_loop();

error:
	/*kill everything*/
	kill_all_children(SIGTERM);
	/*clean-up*/
	cleanup(0);
error00:
	LM_NOTICE("Exiting....\n");
	return ret;
}
Example #25
0
void async_cdp_callback(int is_timeout, void *param, AAAMessage *maa, long elapsed_msecs) {
    int i, j;
    int rc = -1, experimental_rc = -1;
    saved_transaction_t* data = (saved_transaction_t*) param;
    struct cell *t = 0;
    int result = CSCF_RETURN_TRUE;
    int sip_number_auth_items;
    int items_found = 0;
    struct auth_data_item_list *adi_list = 0;
    AAA_AVP *auth_data;
	AAA_AVP* avp;
    auth_data = 0;
    int item_number;
    str authenticate = {0, 0}, authorization2 = {0, 0}, ck = {0, 0}, ik = {0, 0}, ip = {0, 0}, ha1 = {0, 0};
    str line_identifier = {0, 0};
    str response_auth = {0, 0}, digest_realm = {0, 0};
    auth_vector *av = 0, **avlist = 0;
    HASHHEX ha1_hex;
    HASHHEX result_hex;
    str etsi_nonce = {0, 0};
    str private_identity = {0,0};
	str public_identity = {0,0};
    str algorithm;

    if (is_timeout) {
    	update_stat(stat_mar_timeouts, 1);
        LM_ERR("Transaction timeout - did not get MAA\n");
        result = CSCF_RETURN_ERROR;
        goto error;
    }
    if (!maa) {
        LM_ERR("Error sending message via CDP\n");
        result = CSCF_RETURN_ERROR;
        goto error;
    }

    update_stat(mar_replies_received, 1);
    update_stat(mar_replies_response_time, elapsed_msecs);

    if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
        LM_ERR("t_continue: transaction not found\n");
        result = CSCF_RETURN_ERROR;
        goto error1;
    }

    /* get the private_identity */
	/* private_identity = cscf_get_private_identity(t->uas.request, data->realm);*/
	private_identity = cxdx_get_user_name(maa);
	if (!private_identity.len) {
        LM_ERR("No private identity specified (Authorization: username)\n");
        stateful_request_reply_async(t, t->uas.request, 403, MSG_403_NO_PRIVATE);
        result = CSCF_RETURN_FALSE;
        goto error;
    }

	    /* get the public_identity */
	    /*public_identity = cscf_get_public_identity(t->uas.request);*/
	
	avp = cxdx_get_next_public_identity(maa, 0, AVP_IMS_Public_Identity,IMS_vendor_id_3GPP,__FUNCTION__);
	if (avp) {
		public_identity = avp->data;
	}
	if (!public_identity.len) {
        LM_ERR("No public identity specified (To:)\n");
        stateful_request_reply_async(t, t->uas.request, 403, MSG_403_NO_PUBLIC);
        result = CSCF_RETURN_FALSE;
        goto error;
    }
	

    //get each individual element from the MAA
    cxdx_get_result_code(maa, &rc);
    cxdx_get_experimental_result_code(maa, &experimental_rc);

    if (!cxdx_get_sip_number_auth_items(maa, &sip_number_auth_items)) {
       sip_number_auth_items = 0;
    }

    if (sip_number_auth_items > 0) {
	    //now assign the auth_data_item elements
	    //there can be many of these in the MAA
	    struct auth_data_item *adi;
	    int adi_len;
	    char *p;
	    while ((cxdx_get_auth_data_item_answer(maa, &auth_data, &item_number,
		    &algorithm, &authenticate, &authorization2,
		    &ck, &ik,
		    &ip,
		    &ha1, &response_auth, &digest_realm,
		    &line_identifier))) {

		//create an auth_data_item for each entry in the MAA
		adi_len = sizeof (struct auth_data_item) +authenticate.len + authorization2.len + ck.len + ik.len + ip.len + ha1.len + line_identifier.len + response_auth.len + digest_realm.len + algorithm.len;
		adi = (struct auth_data_item*) shm_malloc(adi_len);
		if (!adi) {
		    LM_CRIT("Out of memory!\n");
		    result = CSCF_RETURN_ERROR;
		    goto done;
		}

		memset(adi, 0, adi_len);

		//put all elements in the auth_data_item entry
		p = (char*) (adi + 1);

		adi->authenticate.s = p;
		adi->authenticate.len = authenticate.len;
		memcpy(p, authenticate.s, authenticate.len);
		p += authenticate.len;

		adi->authorization.s = p;
		adi->authorization.len = authorization2.len;
		memcpy(p, authorization2.s, authorization2.len);
		p += authorization2.len;

		adi->auth_scheme.s = p;
		adi->auth_scheme.len = algorithm.len;
		memcpy(p, algorithm.s, algorithm.len);
		p += algorithm.len;

		adi->ck.s = p;
		adi->ck.len = ck.len;
		memcpy(p, ck.s, ck.len);
		p += ck.len;

		adi->ik.s = p;
		adi->ik.len = ik.len;
		memcpy(p, ik.s, ik.len);
		p += ik.len;

		adi->ip.s = p;
		adi->ip.len = ip.len;
		memcpy(p, ip.s, ip.len);
		p += ip.len;

		adi->ha1.s = p;
		adi->ha1.len = ha1.len;
		memcpy(p, ha1.s, ha1.len);
		p += ha1.len;

		adi->line_identifier.s = p;
		adi->line_identifier.len = line_identifier.len;
		memcpy(p, line_identifier.s, line_identifier.len);
		p += line_identifier.len;

		adi->response_auth.s = p;
		adi->response_auth.len = response_auth.len;
		memcpy(p, response_auth.s, response_auth.len);
		p += response_auth.len;

		adi->digest_realm.s = p;
		adi->digest_realm.len = digest_realm.len;
		memcpy(p, digest_realm.s, digest_realm.len);
		p += digest_realm.len;

		if (p != (((char*) adi) + adi_len)) {
		    LM_CRIT("buffer overflow\n");
		    shm_free(adi);
		    adi = 0;
		    result = CSCF_RETURN_ERROR;
		    goto done;
		}
		auth_data->code = -auth_data->code;
		adi->item_number = item_number;

		int len = sizeof (struct auth_data_item_list);
		adi_list = (struct auth_data_item_list*) shm_malloc(len);
		memset(adi_list, 0, len);

		if (adi_list->first == 0) {
		    adi_list->first = adi_list->last = adi;
		} else {
		    adi_list->last->next = adi;
		    adi->previous = adi_list->last;
		    adi_list->last = adi;
		}
	
		items_found++;
	    }
    }   

    if (!(rc) && !(experimental_rc)) {
        stateful_request_reply_async(t, t->uas.request, 480, MSG_480_DIAMETER_MISSING_AVP);
        result = CSCF_RETURN_FALSE;
        goto done;
    }

    switch (rc) {
        case -1:
            switch (experimental_rc) {
                case RC_IMS_DIAMETER_ERROR_USER_UNKNOWN:
                    stateful_request_reply_async(t, t->uas.request, 403, MSG_403_USER_UNKNOWN);
                    result = CSCF_RETURN_FALSE;
                    break;
                case RC_IMS_DIAMETER_ERROR_IDENTITIES_DONT_MATCH:
                    stateful_request_reply_async(t, t->uas.request, 403, MSG_403_IDENTITIES_DONT_MATCH);
                    result = CSCF_RETURN_FALSE;
                    break;
                case RC_IMS_DIAMETER_ERROR_AUTH_SCHEME_NOT_SUPPORTED:
                    stateful_request_reply_async(t, t->uas.request, 403, MSG_403_AUTH_SCHEME_UNSOPPORTED);
                    result = CSCF_RETURN_FALSE;
                    break;

                default:
                    stateful_request_reply_async(t, t->uas.request, 403, MSG_403_UNKOWN_EXPERIMENTAL_RC);
                    result = CSCF_RETURN_FALSE;
            }
            break;

        case AAA_UNABLE_TO_COMPLY:
            stateful_request_reply_async(t, t->uas.request, 403, MSG_403_UNABLE_TO_COMPLY);
            result = CSCF_RETURN_FALSE;
            break;

        case AAA_SUCCESS:
            goto success;
            break;

        default:
            stateful_request_reply_async(t, t->uas.request, 403, MSG_403_UNKOWN_RC);
            result = CSCF_RETURN_FALSE;
    }

    goto done;

success:

    if (!sip_number_auth_items || !items_found) {
        stateful_request_reply_async(t, t->uas.request, 403, MSG_403_NO_AUTH_DATA);
        result = CSCF_RETURN_FALSE;
        goto done;
    }

    avlist = shm_malloc(sizeof (auth_vector *) * sip_number_auth_items);
    if (!avlist) {
        stateful_request_reply_async(t, t->uas.request, 403, MSG_480_HSS_ERROR);
        result = CSCF_RETURN_FALSE;
        goto done;
    }

    sip_number_auth_items = 0;

    struct auth_data_item *tmp;
    tmp = adi_list->first;

    while (tmp) {

        if (tmp->ip.len)
            av = new_auth_vector(tmp->item_number, tmp->auth_scheme, empty_s,
                tmp->ip, empty_s, empty_s);
        else if (tmp->line_identifier.len)
            av = new_auth_vector(tmp->item_number, tmp->auth_scheme, empty_s,
                line_identifier, empty_s, empty_s);
        else if (tmp->ha1.len) {
            if (tmp->response_auth.len) //HSS check
            {
                memset(ha1_hex, 0, HASHHEXLEN + 1);
                memcpy(ha1_hex, tmp->ha1.s,
                        tmp->ha1.len > HASHHEXLEN ? 32 : tmp->ha1.len);

                etsi_nonce.len = tmp->authenticate.len / 2;
                etsi_nonce.s = pkg_malloc(etsi_nonce.len);
                if (!etsi_nonce.s) {
                    LM_ERR("error allocating %d bytes\n", etsi_nonce.len);
                    goto done;
                }
                etsi_nonce.len = base16_to_bin(tmp->authenticate.s,
                        tmp->authenticate.len, etsi_nonce.s);

                calc_response(ha1_hex, &etsi_nonce, &empty_s, &empty_s,
                        &empty_s, 0, &(t->uas.request->first_line.u.request.method),
                        &scscf_name_str, 0, result_hex);
                pkg_free(etsi_nonce.s);

                if (!tmp->response_auth.len == 32
                        || strncasecmp(tmp->response_auth.s, result_hex, 32)) {
                    LM_ERR("The HSS' Response-Auth is different from what we compute locally!\n"
                            " BUT! If you sent an MAR with auth scheme unknown (HSS-Selected Authentication), this is normal.\n"
                            "HA1=\t|%s|\nNonce=\t|%.*s|\nMethod=\t|%.*s|\nuri=\t|%.*s|\nxresHSS=\t|%.*s|\nxresSCSCF=\t|%s|\n",
                            ha1_hex,
                            tmp->authenticate.len, tmp->authenticate.s,
                            t->uas.request->first_line.u.request.method.len, t->uas.request->first_line.u.request.method.s,
                            scscf_name_str.len, scscf_name_str.s,
                            tmp->response_auth.len, tmp->response_auth.s,
                            result_hex);
                    //stateful_register_reply(msg,514,MSG_514_HSS_AUTH_FAILURE);
                    //goto done;
                }
            }
            av = new_auth_vector(tmp->item_number, tmp->auth_scheme,
                    tmp->authenticate, tmp->ha1, empty_s, empty_s);
        } else
            av = new_auth_vector(tmp->item_number, tmp->auth_scheme,
                tmp->authenticate, tmp->authorization, tmp->ck, tmp->ik);

        if (sip_number_auth_items == 0)
            avlist[sip_number_auth_items++] = av;
        else {
            i = sip_number_auth_items;
            while (i > 0 && avlist[i - 1]->item_number > av->item_number)
                i--;
            for (j = sip_number_auth_items; j > i; j--)
                avlist[j] = avlist[j - 1];
            avlist[i] = av;
            sip_number_auth_items++;
        }

        //TODO need to confirm that removing this has done no problems
        //tmp->auth_data->code = -tmp->auth_data->code;

        tmp = tmp->next;
    }

    //MAA returns a whole list of av! Which should we use?
    //right now we take the first and put the rest in the AV queue
    //then we use the first one and then add it to the queue as sent!

    for (i = 1; i < sip_number_auth_items; i++) {
        if (!add_auth_vector(private_identity, public_identity, avlist[i]))
            free_auth_vector(avlist[i]);
    }

    if (!data->is_resync) {
		if (!pack_challenge(t->uas.request, data->realm, avlist[0], data->is_proxy_auth)) {
			stateful_request_reply_async(t, t->uas.request, 500, MSG_500_PACK_AV);
			result = CSCF_RETURN_FALSE;
			goto done;
		}

		if (data->is_proxy_auth)
			stateful_request_reply_async(t, t->uas.request, 407, MSG_407_CHALLENGE);
		else
			stateful_request_reply_async(t, t->uas.request, 401, MSG_401_CHALLENGE);
    }

done:

	if (avlist) {
		if (!data->is_resync)	//only start the timer if we used the vector above - we dont use it resync mode
		start_reg_await_timer(avlist[0]); //start the timer to remove stale or unused Auth Vectors

		//now we add it to the queue as sent as we have already sent the challenge and used it and set the status to SENT
		if (!add_auth_vector(private_identity, public_identity, avlist[0]))
			free_auth_vector(avlist[0]);
	}

    //free memory
    if (maa) cdpb.AAAFreeMessage(&maa);
    if (avlist) {
        shm_free(avlist);
        avlist = 0;
    }

    if (adi_list) {
        struct auth_data_item *tmp1 = adi_list->first;
        while (tmp1) {
            struct auth_data_item *tmp2 = tmp1->next;
            shm_free(tmp1);
            tmp1 = tmp2;
        }
        shm_free(adi_list);
        adi_list = 0;
    }

    LM_DBG("DBG:UAR Async CDP callback: ... Done resuming transaction\n");
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);

    //make sure we delete any private lumps we created
    create_return_code(result);
    if (t) {
        del_nonshm_lump_rpl(&t->uas.request->reply_lump);
        tmb.unref_cell(t);
    }
    tmb.t_continue(data->tindex, data->tlabel, data->act);
    free_saved_transaction_data(data);
    return;

error:
    //don't need to set result code as by default it is ERROR!

    if (t) {
        del_nonshm_lump_rpl(&t->uas.request->reply_lump);
        tmb.unref_cell(t);
    }
    tmb.t_continue(data->tindex, data->tlabel, data->act);
    
error1:    
    free_saved_transaction_data(data);
}
Example #26
0
/**
 * Main routine, start of the program execution.
 * \param argc the number of arguments
 * \param argv pointer to the arguments array
 * \return don't return on sucess, -1 on error
 * \see main_loop
 */
int main(int argc, char** argv)
{
	/* configure by default logging to syslog */
	int cfg_log_stderr = 0;
	FILE* cfg_stream;
	int c,r;
	char *tmp;
	int tmp_len;
	int port;
	int proto;
	char *options;
	int ret;
	unsigned int seed;
	int rfd;

	/*init*/
	ret=-1;
	my_argc=argc; my_argv=argv;

	/* process pkg mem size from command line */
	opterr=0;
	options="f:cCm:M:b:l:n:N:rRvdDFETSVhw:t:u:g:P:G:W:o:";

	while((c=getopt(argc,argv,options))!=-1){
		switch(c){
			case 'M':
					pkg_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
					if (tmp &&(*tmp)){
						LM_ERR("bad pkgmem size number: -m %s\n", optarg);
						goto error00;
					};

					break;
		}
	}
	/*init pkg mallocs (before parsing cfg but after parsing cmd line !)*/
	if (init_pkg_mallocs()==-1)
		goto error00;

	init_route_lists();
	/* process command line (get port no, cfg. file path etc) */
	/* first reset getopt */
	optind = 1;
	while((c=getopt(argc,argv,options))!=-1){
		switch(c){
			case 'f':
					cfg_file=optarg;
					break;
			case 'C':
					config_check |= 2;
			case 'c':
					if (config_check==3)
						break;
					config_check |= 1;
					cfg_log_stderr=1; /* force stderr logging */
					break;
			case 'm':
					shm_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
					if (tmp &&(*tmp)){
						LM_ERR("bad shmem size number: -m %s\n", optarg);
						goto error00;
					};

					break;
			case 'M':
					/* ignoring it, parsed previously */

					break;
			case 'b':
					maxbuffer=strtol(optarg, &tmp, 10);
					if (tmp &&(*tmp)){
						LM_ERR("bad max buffer size number: -b %s\n", optarg);
						goto error00;
					}
					break;
			case 'l':
					if (parse_phostport(optarg, strlen(optarg), &tmp, &tmp_len,
											&port, &proto)<0){
						LM_ERR("bad -l address specifier: %s\n", optarg);
						goto error00;
					}
					tmp[tmp_len]=0; /* null terminate the host */
					/* add a new addr. to our address list */
					if (add_listen_iface(tmp, port, proto, 0, 0, 0,0 )!=0){
						LM_ERR("failed to add new listen address\n");
						goto error00;
					}
					break;
			case 'n':
					children_no=strtol(optarg, &tmp, 10);
					if ((tmp==0) ||(*tmp)){
						LM_ERR("bad process number: -n %s\n", optarg);
						goto error00;
					}
					break;
			case 'v':
					check_via=1;
					break;
			case 'r':
					received_dns|=DO_DNS;
					break;
			case 'R':
					received_dns|=DO_REV_DNS;
			case 'd':
#ifdef CHANGEABLE_DEBUG_LEVEL
					(*debug)++;
#else
					debug++;
#endif
					break;
			case 'D':
					dont_fork=1;
					break;
			case 'F':
					no_daemon_mode=1;
					break;
			case 'E':
					cfg_log_stderr=1;
					break;
			case 'T':
#ifdef USE_TCP
					tcp_disable=1;
#else
					LM_WARN("tcp support not compiled in\n");
#endif
					break;
			case 'S':
#ifdef USE_SCTP
					sctp_disable=1;
#else
					LM_WARN("sctp support not compiled in\n");
#endif
			break;
			case 'N':
#ifdef USE_TCP
					tcp_children_no=strtol(optarg, &tmp, 10);
					if ((tmp==0) ||(*tmp)){
						LM_ERR("bad process number: -N %s\n", optarg);
						goto error00;
					}
#else
					LM_WARN("tcp support not compiled in\n");
#endif
					break;
			case 'W':
#ifdef USE_TCP
					tcp_poll_method=get_poll_type(optarg);
					if (tcp_poll_method==POLL_NONE){
						LM_ERR("bad poll method name: -W %s\ntry "
							"one of %s.\n", optarg, poll_support);
						goto error00;
					}
#else
					LM_WARN("tcp support not compiled in\n");
#endif
					break;
			case 'V':
					printf("version: %s\n", version);
					printf("flags: %s\n", flags );
					print_ct_constants();
					printf("%s\n",id);
					printf("%s compiled on %s with %s\n", __FILE__,
							compiled, COMPILER );
					
					exit(0);
					break;
			case 'h':
					printf("version: %s\n", version);
					printf("%s",help_msg);
					exit(0);
					break;
			case 'w':
					working_dir=optarg;
					break;
			case 't':
					chroot_dir=optarg;
					break;
			case 'u':
					user=optarg;
					break;
			case 'g':
					group=optarg;
					break;
			case 'P':
					pid_file=optarg;
					break;
			case 'G':
					pgid_file=optarg;
					break;
			case 'o':
					if (add_arg_var(optarg) < 0)
						LM_ERR("cannot add option %s\n", optarg);
					break;
			case '?':
					if (isprint(optopt))
						LM_ERR("Unknown option `-%c`.\n", optopt);
					else
						LM_ERR("Unknown option character `\\x%x`.\n", optopt);
					goto error00;
			case ':':
					LM_ERR("Option `-%c` requires an argument.\n", optopt);
					goto error00;
			default:
					abort();
		}
	}

	log_stderr = cfg_log_stderr;

	/* fill missing arguments with the default values*/
	if (cfg_file==0) cfg_file=CFG_FILE;

	/* load config file or die */
	cfg_stream=fopen (cfg_file, "r");
	if (cfg_stream==0){
		LM_ERR("loading config file(%s): %s\n", cfg_file,
				strerror(errno));
		goto error00;
	}

	/* seed the prng, try to use /dev/urandom if possible */
	/* no debugging information is logged, because the standard
	   log level prior the config file parsing is L_NOTICE */
	seed=0;
	if ((rfd=open("/dev/urandom", O_RDONLY))!=-1){
try_again:
		if (read(rfd, (void*)&seed, sizeof(seed))==-1){
			if (errno==EINTR) goto try_again; /* interrupted by signal */
			LM_WARN("could not read from /dev/urandom (%d)\n", errno);
		}
		LM_DBG("initialize the pseudo random generator from "
			"/dev/urandom\n");
		LM_DBG("read %u from /dev/urandom\n", seed);
			close(rfd);
	}else{
		LM_WARN("could not open /dev/urandom (%d)\n", errno);
		LM_WARN("using a unsafe seed for the pseudo random number generator");
	}
	seed+=getpid()+time(0);
	LM_DBG("seeding PRNG with %u\n", seed);
	srand(seed);
	LM_DBG("test random number %u\n", rand());

	/*register builtin  modules*/
	register_builtin_modules();

#ifdef USE_TLS
	/* initialize default TLS domains,
	   must be done before reading the config */
	if (pre_init_tls()<0){
		LM_CRIT("could not pre_init_tls, exiting...\n");
		goto error00;
	}
#endif /* USE_TLS */

	if (preinit_black_lists()!=0) {
		LM_CRIT("failed to alloc black list's anchor\n");
		goto error00;
	}

	/* init avps */
	if (init_global_avps() != 0) {
		LM_ERR("error while initializing avps\n");
		goto error;
	}


	/* parse the config file, prior to this only default values
	   e.g. for debugging settings will be used */
	yyin=cfg_stream;
	if ((yyparse()!=0)||(cfg_errors)){
		LM_ERR("bad config file (%d errors)\n", cfg_errors);
		goto error00;
	}

	if (config_check>1 && check_rls()!=0) {
		LM_ERR("bad function call in config file\n");
		return ret;
	}
#ifdef EXTRA_DEBUG
	print_rl();
#endif

	if (no_daemon_mode+dont_fork > 1) {
		LM_ERR("cannot use -D (fork=no) and -F together\n");
		return ret;
	}

	/* init the resolver, before fixing the config */
	resolv_init();

	/* fix parameters */
	if (port_no<=0) port_no=SIP_PORT;
#ifdef USE_TLS
	if (tls_port_no<=0) tls_port_no=SIPS_PORT;
#endif
	
	
	if (children_no<=0) children_no=CHILD_NO;
#ifdef USE_TCP
	if (!tcp_disable){
		if (tcp_children_no<=0) tcp_children_no=children_no;
	}
#endif
	
	if (working_dir==0) working_dir="/";

	/* get uid/gid */
	if (user){
		if (user2uid(&uid, &gid, user)<0){
			LM_ERR("bad user name/uid number: -u %s\n", user);
			goto error00;
		}
	}
	if (group){
		if (group2gid(&gid, group)<0){
			LM_ERR("bad group name/gid number: -u %s\n", group);
			goto error00;
		}
	}
	if (fix_all_socket_lists()!=0){
		LM_ERR("failed to initialize list addresses\n");
		goto error00;
	}
	/* print all the listen addresses */
	printf("Listening on \n");
	print_all_socket_lists();
	printf("Aliases: \n");
	/*print_aliases();*/
	print_aliases();
	printf("\n");
	
	if (dont_fork){
		LM_WARN("no fork mode %s\n", 
				(udp_listen)?(
				(udp_listen->next)?" and more than one listen address found"
				"(will use only the first one)":""
				):"and no udp listen address found" );
	}
	if (config_check){
		LM_NOTICE("config file ok, exiting...\n");
		return 0;
	}


	time(&startup_time);

	/*init shm mallocs
	 *  this must be here 
	 *     -to allow setting shm mem size from the command line
	 *       => if shm_mem should be settable from the cfg file move
	 *       everything after
	 *     -it must be also before init_timer and init_tcp
	 *     -it must be after we know uid (so that in the SYSV sems case,
	 *        the sems will have the correct euid)
	 * --andrei */
	if (init_shm_mallocs()==-1)
		goto error;
	/*init timer, before parsing the cfg!*/
	if (init_timer()<0){
		LM_CRIT("could not initialize timer, exiting...\n");
		goto error;
	}
	
#ifdef USE_TCP
	if (!tcp_disable){
		/*init tcp*/
		if (init_tcp()<0){
			LM_CRIT("could not initialize tcp, exiting...\n");
			goto error;
		}
	}
#ifdef USE_TLS
	if (!tls_disable){
		/* init tls*/
		if (init_tls()<0){
			LM_CRIT("could not initialize tls, exiting...\n");
			goto error;
		}
	}
#endif /* USE_TLS */
#endif /* USE_TCP */

	/* init_daemon? */
	if (!dont_fork){
		if ( daemonize((log_name==0)?argv[0]:log_name, &own_pgid) <0 )
			goto error;
	}

	/* install signal handlers */
	if (install_sigs() != 0){
		LM_ERR("could not install the signal handlers\n");
		goto error;
	}

#ifdef CHANGEABLE_DEBUG_LEVEL
#ifdef SHM_MEM
	debug=shm_malloc(sizeof(int));
	if (debug==0) {
		LM_ERR("ERROR: out of memory\n");
		goto error;
	}
	*debug = debug_init;
#else
	LM_WARN("no shm mem support compiled -> changeable debug "
		"level turned off\n");
#endif
#endif

	if (disable_core_dump) set_core_dump(0, 0);
	else set_core_dump(1, shm_mem_size+pkg_mem_size+4*1024*1024);
	if (open_files_limit>0){
		if(increase_open_fds(open_files_limit)<0){ 
			LM_ERR("ERROR: error could not increase file limits\n");
			goto error;
		}
	}

	/* print OpenSIPS version to log for history tracking */
	LM_NOTICE("version: %s\n", version);
	
	/* print some data about the configuration */
#ifdef SHM_MEM
	LM_INFO("using %ld Mb shared memory\n", ((shm_mem_size/1024)/1024));
#endif
	LM_INFO("using %ld Mb private memory per process\n", ((pkg_mem_size/1024)/1024));

	/* init serial forking engine */
	if (init_serialization()!=0) {
		LM_ERR("failed to initialize serialization\n");
		goto error;
	}
	/* Init statistics */
	if (init_stats_collector()<0) {
		LM_ERR("failed to initialize statistics\n");
		goto error;
	}
	/* Init MI */
	if (init_mi_core()<0) {
		LM_ERR("failed to initialize MI core\n");
		goto error;
	}

	/* Register core events */
	if (evi_register_core() != 0) {
		LM_ERR("failed register core events\n");
		goto error;
	}

	/* init black list engine */
	if (init_black_lists()!=0) {
		LM_CRIT("failed to init black lists\n");
		goto error;
	}
	/* init resolver's blacklist */
	if (resolv_blacklist_init()!=0) {
		LM_CRIT("failed to create DNS blacklist\n");
		goto error;
	}

	/* init modules */
	if (init_modules() != 0) {
		LM_ERR("error while initializing modules\n");
		goto error;
	}

	/* register route timers */
	if(register_route_timers() < 0) {
		LM_ERR("Failed to register timer\n");
		goto error;
	}

	/* check pv context list */
	if(pv_contextlist_check() != 0) {
		LM_ERR("used pv context that was not defined\n");
		goto error;
	}

	/* init query list now in shm
	 * so all processes that will be forked from now on
	 * will have access to it 
	 *
	 * if it fails, give it a try and carry on */
	if (init_ql_support() != 0) {
		LM_ERR("failed to initialise buffering query list\n");
		query_buffer_size = 0;
		*query_list = NULL;
	}

	/* init multi processes support */
	if (init_multi_proc_support()!=0) {
		LM_ERR("failed to init multi-proc support\n");
		goto error;
	}

	#ifdef PKG_MALLOC
	/* init stats support for pkg mem */
	if (init_pkg_stats(counted_processes)!=0) {
		LM_ERR("failed to init stats for pkg\n");
		goto error;
	}
	#endif

	/* init avps */
	if (init_extra_avps() != 0) {
		LM_ERR("error while initializing avps\n");
		goto error;
	}

	/* fix routing lists */
	if ( (r=fix_rls())!=0){
		LM_ERR("failed to fix configuration with err code %d\n", r);
		goto error;
	};

	ret=main_loop();

error:

	/*kill everything*/
	kill_all_children(SIGTERM);
	/*clean-up*/
	cleanup(0);
error00:
	return ret;
}
Example #27
0
/*!
 * \brief initializes the static vars/arrays
 * \param  h - pointer to the io_wait_h that will be initialized
 * \param  max_fd - maximum allowed fd number
 * \param  poll_method - poll method (0 for automatic best fit)
 */
int init_io_wait(io_wait_h* h, char *name, int max_fd,
									enum poll_types poll_method, int async)
{
	char * poll_err;

	memset(h, 0, sizeof(*h));
	h->name = name;
	h->max_fd_no=max_fd;
#ifdef HAVE_EPOLL
	h->epfd=-1;
#endif
#ifdef HAVE_KQUEUE
	h->kq_fd=-1;
#endif
#ifdef HAVE_DEVPOLL
	h->dpoll_fd=-1;
#endif
	poll_err=check_poll_method(poll_method);

	/* set an appropiate poll method */
	if (poll_err || (poll_method==0)){
		poll_method=choose_poll_method();
		if (poll_err){
			LM_ERR("%s, using %s instead\n",
					poll_err, poll_method_str[poll_method]);
		}else{
			LM_INFO("using %s as the io watch method"
					" (auto detected)\n", poll_method_str[poll_method]);
		}
	}

	h->poll_method=poll_method;

	if (h->poll_method != POLL_POLL && h->poll_method != POLL_EPOLL_LT &&
		h->poll_method != POLL_EPOLL_ET) {
		if (async)
			LM_WARN("Tried to enable async polling but current poll method is %d."
				" Currently we only support POLL and EPOLL \n",h->poll_method);
		async=0;
	}

	/* common stuff, everybody has fd_hash */
	h->fd_hash=local_malloc(sizeof(*(h->fd_hash))*h->max_fd_no);
	if (h->fd_hash==0){
		LM_CRIT("could not alloc fd hashtable (%ld bytes)\n",
					(long)sizeof(*(h->fd_hash))*h->max_fd_no );
		goto error;
	}
	memset((void*)h->fd_hash, 0, sizeof(*(h->fd_hash))*h->max_fd_no);

	switch(poll_method){
		case POLL_POLL:
#ifdef HAVE_SELECT
		case POLL_SELECT:
#endif
#ifdef HAVE_SIGIO_RT
		case POLL_SIGIO_RT:
#endif
#ifdef HAVE_DEVPOLL
		case POLL_DEVPOLL:
#endif
			h->fd_array=local_malloc(sizeof(*(h->fd_array))*h->max_fd_no);
			if (h->fd_array==0){
				LM_CRIT("could not alloc fd array (%ld bytes)\n",
							(long)sizeof(*(h->fd_hash))*h->max_fd_no);
				goto error;
			}
			memset((void*)h->fd_array, 0, sizeof(*(h->fd_array))*h->max_fd_no);
#ifdef HAVE_SIGIO_RT
			if ((poll_method==POLL_SIGIO_RT) && (init_sigio(h, 0)<0)){
				LM_CRIT("sigio init failed\n");
				goto error;
			}
#endif
#ifdef HAVE_DEVPOLL
			if ((poll_method==POLL_DEVPOLL) && (init_devpoll(h)<0)){
				LM_CRIT("/dev/poll init failed\n");
				goto error;
			}
#endif
#ifdef HAVE_SELECT
			if ((poll_method==POLL_SELECT) && (init_select(h)<0)){
				LM_CRIT("select init failed\n");
				goto error;
			}
#endif

			break;
#ifdef HAVE_EPOLL
		case POLL_EPOLL_LT:
		case POLL_EPOLL_ET:
			h->ep_array=local_malloc(sizeof(*(h->ep_array))*h->max_fd_no);
			if (h->ep_array==0){
				LM_CRIT("could not alloc epoll array\n");
				goto error;
			}
			memset((void*)h->ep_array, 0, sizeof(*(h->ep_array))*h->max_fd_no);
			if (init_epoll(h)<0){
				LM_CRIT("epoll init failed\n");
				goto error;
			}
			break;
#endif
#ifdef HAVE_KQUEUE
		case POLL_KQUEUE:
			h->kq_array=local_malloc(sizeof(*(h->kq_array))*h->max_fd_no);
			if (h->kq_array==0){
				LM_CRIT("could not alloc kqueue event array\n");
				goto error;
			}
			h->kq_changes_size=KQ_CHANGES_ARRAY_SIZE;
			h->kq_changes=local_malloc(sizeof(*(h->kq_changes))*
										h->kq_changes_size);
			if (h->kq_changes==0){
				LM_CRIT("could not alloc kqueue changes array\n");
				goto error;
			}
			h->kq_nchanges=0;
			memset((void*)h->kq_array, 0, sizeof(*(h->kq_array))*h->max_fd_no);
			memset((void*)h->kq_changes, 0,
						sizeof(*(h->kq_changes))* h->kq_changes_size);
			if (init_kqueue(h)<0){
				LM_CRIT("kqueue init failed\n");
				goto error;
			}
			break;
#endif
		default:
			LM_CRIT("unknown/unsupported poll method %s (%d)\n",
						poll_method_str[poll_method], poll_method);
			goto error;
	}
	return 0;
error:
	return -1;
}
Example #28
0
/**
 * Timeout handler during wait for children exit. 
 * like sig_alarm_kill, but the timeout has occured when cleaning up,
 * try to leave a core for future diagnostics
 * \param signo signal for killing the children
 * \see sig_alarm_kill
 */
static void sig_alarm_abort(int signo)
{
	/* LOG is not signal safe, but who cares, we are abort-ing anyway :-) */
	LM_CRIT("BUG - shutdown timeout triggered, dying...");
	abort();
}
Example #29
0
void resume_ro_session_ontimeout(struct interim_ccr *i_req) {
	time_t now = time(0);
	time_t used_secs;
	struct ro_session_entry *ro_session_entry = NULL;

	if (!i_req) {
		LM_ERR("This is so wrong: i_req is NULL\n");
		return;
	}

	LM_DBG("credit=%d credit_valid_for=%d", i_req->new_credit, i_req->credit_valid_for);

	used_secs = now - i_req->ro_session->last_event_timestamp;

	/* check to make sure diameter server is giving us sane values */
	if (i_req->new_credit > i_req->credit_valid_for) {
		LM_WARN("That's weird, Diameter server gave us credit with a lower validity period :D. Setting reserved time to validity perioud instead \n");
		i_req->new_credit = i_req->credit_valid_for;
	}

	if (i_req->new_credit > 0) {
		//now insert the new timer
		i_req->ro_session->last_event_timestamp = time(0);
		i_req->ro_session->event_type = answered;
		i_req->ro_session->valid_for = i_req->credit_valid_for;

		int ret = 0;
		if (i_req->is_final_allocation) {
			LM_DBG("This is a final allocation and call will end in %i seconds\n", i_req->new_credit);
			i_req->ro_session->event_type = no_more_credit;
			ret = insert_ro_timer(&i_req->ro_session->ro_tl, i_req->new_credit);
		}
		else {
			int timer_timeout = i_req->new_credit;

			if (i_req->new_credit > ro_timer_buffer /*TIMEOUTBUFFER*/) {

				// We haven't finished using our 1st block of units, and we need to set the timer to
				// (new_credit - ro_timer_buffer[5 secs]) to ensure we get new credit before our previous
				// reservation is exhausted. This will only be done the first time, because the timer
				// will always be fired 5 seconds before we run out of time thanks to this operation

				if ((now - i_req->ro_session->start_time) /* call time */ < i_req->ro_session->reserved_secs)
					timer_timeout = i_req->new_credit - ro_timer_buffer;
				else
					timer_timeout = i_req->new_credit;
			}

			ret = insert_ro_timer(&i_req->ro_session->ro_tl, timer_timeout);

		}

		// update to the new block of units we got
		i_req->ro_session->reserved_secs = i_req->new_credit;

		if (ret != 0) {
			LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
					i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
		}
		else {
			ref_ro_session_unsafe(i_req->ro_session, 1);
		}
	}
	else {
		/* just put the timer back in with however many seconds are left (if any!!! in which case we need to kill */
		/* also update the event type to no_more_credit to save on processing the next time we get here */
		i_req->ro_session->event_type = no_more_credit;
		int whatsleft = i_req->ro_session->reserved_secs - used_secs;
		if (whatsleft <= 0) {
			LM_WARN("Immediately killing call due to no more credit\n");
			dlgb.lookup_terminate_dlg(i_req->ro_session->dlg_h_entry, i_req->ro_session->dlg_h_id, NULL );
		}
		else {
			LM_DBG("No more credit for user - letting call run out of money in [%i] seconds", whatsleft);
			int ret = insert_ro_timer(&i_req->ro_session->ro_tl, whatsleft);
			if (ret != 0) {
				LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
						i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
			}
			else {
				ref_ro_session_unsafe(i_req->ro_session, 1);
			}
		}
	}

	ro_session_entry = &(ro_session_table->entries[i_req->ro_session->h_entry]);

	unref_ro_session_unsafe(i_req->ro_session, 1, ro_session_entry);//unref from the initial timer that fired this event.
	ro_session_unlock(ro_session_table, ro_session_entry);

	shm_free(i_req);
	LM_DBG("Exiting async ccr interim nicely");
}
Example #30
0
int split_frag(struct qm_block* qm, struct qm_frag* f, unsigned long new_size)
#endif
{
	unsigned long rest;
	struct qm_frag* n;
	struct qm_frag_end* end;

	rest=f->size-new_size;
#ifdef MEM_FRAG_AVOIDANCE
	if ((rest> (FRAG_OVERHEAD+QM_MALLOC_OPTIMIZE))||
		(rest>=(FRAG_OVERHEAD+new_size))){/* the residue fragm. is big enough*/
#else
	if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
#endif
		f->size=new_size;
		/*split the fragment*/
		end=FRAG_END(f);
		end->size=new_size;
		n=(struct qm_frag*)((char*)end+sizeof(struct qm_frag_end));
		n->size=rest-FRAG_OVERHEAD;
		FRAG_END(n)->size=n->size;
		FRAG_CLEAR_USED(n); /* never used */
		qm->used-=FRAG_OVERHEAD;
#ifdef DBG_QM_MALLOC
		end->check1=END_CHECK_PATTERN1;
		end->check2=END_CHECK_PATTERN2;
		/* frag created by malloc, mark it*/
		n->file=file;
		n->func=func;
		n->line=line;
		n->check=ST_CHECK_PATTERN;
#endif
		/* reinsert n in free list*/
		qm_insert_free(qm, n);
		return 0;
	}else{
			/* we cannot split this fragment any more */
		return -1;
	}
}



#ifdef DBG_QM_MALLOC
void* qm_malloc(struct qm_block* qm, unsigned long size,
					const char* file, const char* func, unsigned int line)
#else
void* qm_malloc(struct qm_block* qm, unsigned long size)
#endif
{
	struct qm_frag* f;
	int hash;

#ifdef DBG_QM_MALLOC
	unsigned int list_cntr;

	list_cntr = 0;
	LM_GEN1( memlog, "params (%p, %lu), called from %s: %s(%d)\n",
		qm, size, file, func, line);
#endif
	/*size must be a multiple of 8*/
	size=ROUNDUP(size);
	if (size>(qm->size-qm->real_used)) {
		pkg_threshold_check();
		return 0;
	}

	/*search for a suitable free frag*/
#ifdef DBG_QM_MALLOC
	if ((f=qm_find_free(qm, size, &hash, &list_cntr))!=0){
#else
	if ((f=qm_find_free(qm, size, &hash))!=0){
#endif
		/* we found it!*/
		/*detach it from the free list*/
#ifdef DBG_QM_MALLOC
			qm_debug_frag(qm, f);
#endif
		qm_detach_free(qm, f);
		/*mark it as "busy"*/
		f->u.is_free=0;
		qm->free_hash[hash].no--;
		/* we ignore split return */
#ifdef DBG_QM_MALLOC
		split_frag(qm, f, size, file, "fragm. from qm_malloc", line);
#else
		split_frag(qm, f, size);
#endif
		if (qm->max_real_used<qm->real_used)
			qm->max_real_used=qm->real_used;
#ifdef DBG_QM_MALLOC
		f->file=file;
		f->func=func;
		f->line=line;
		f->check=ST_CHECK_PATTERN;
		/*  FRAG_END(f)->check1=END_CHECK_PATTERN1;
			FRAG_END(f)->check2=END_CHECK_PATTERN2;*/
		LM_GEN1( memlog, "params (%p, %lu), returns address %p frag. %p "
			"(size=%lu) on %d -th hit\n",
			 qm, size, (char*)f+sizeof(struct qm_frag), f, f->size, list_cntr );
#endif
		pkg_threshold_check();
		return (char*)f+sizeof(struct qm_frag);
	}
	pkg_threshold_check();
	return 0;
}



#ifdef DBG_QM_MALLOC
void qm_free(struct qm_block* qm, void* p, const char* file, const char* func,
				unsigned int line)
#else
void qm_free(struct qm_block* qm, void* p)
#endif
{
	struct qm_frag* f;
	struct qm_frag* prev;
	struct qm_frag* next;
	unsigned long size;

#ifdef DBG_QM_MALLOC
	LM_GEN1( memlog, "params(%p, %p), called from %s: %s(%d)\n",
		qm, p, file, func, line);
	if (p>(void*)qm->last_frag_end || p<(void*)qm->first_frag){
		LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p);
		abort();
	}
#endif
	if (p==0) {
		LM_WARN("free(0) called\n");
		return;
	}
	f=(struct qm_frag*) ((char*)p-sizeof(struct qm_frag));
#ifdef DBG_QM_MALLOC
	qm_debug_frag(qm, f);
	if (f->u.is_free){
		LM_CRIT("freeing already freed pointer,"
				" first free: %s: %s(%ld) - aborting\n",
				f->file, f->func, f->line);
		abort();
	}
	LM_GEN1( memlog, "freeing frag. %p alloc'ed from %s: %s(%ld)\n",
			f, f->file, f->func, f->line);
#endif

	size=f->size;
	/* join packets if possible*/
	prev=next=0;
	next=FRAG_NEXT(f);
	if (((char*)next < (char*)qm->last_frag_end) &&( next->u.is_free)){
		/* join */
#ifdef DBG_QM_MALLOC
		qm_debug_frag(qm, next);
#endif
		qm_detach_free(qm, next);
		size+=next->size+FRAG_OVERHEAD;
		qm->used+=FRAG_OVERHEAD;
		qm->free_hash[GET_HASH(next->size)].no--; /* FIXME slow */
	}

	if (f > qm->first_frag){
		prev=FRAG_PREV(f);
		/*	(struct qm_frag*)((char*)f - (struct qm_frag_end*)((char*)f-
								sizeof(struct qm_frag_end))->size);*/
#ifdef DBG_QM_MALLOC
		qm_debug_frag(qm, prev);
#endif
		if (prev->u.is_free){
			/*join*/
			qm_detach_free(qm, prev);
			size+=prev->size+FRAG_OVERHEAD;
			qm->used+=FRAG_OVERHEAD;
			qm->free_hash[GET_HASH(prev->size)].no--; /* FIXME slow */
			f=prev;
		}
	}
	f->size=size;
	FRAG_END(f)->size=f->size;
#ifdef DBG_QM_MALLOC
	f->file=file;
	f->func=func;
	f->line=line;
#endif
	qm_insert_free(qm, f);
	pkg_threshold_check();
}



#ifdef DBG_QM_MALLOC
void* qm_realloc(struct qm_block* qm, void* p, unsigned long size,
					const char* file, const char* func, unsigned int line)
#else
void* qm_realloc(struct qm_block* qm, void* p, unsigned long size)
#endif
{
	struct qm_frag* f;
	unsigned long diff;
	unsigned long orig_size;
	struct qm_frag* n;
	void* ptr;


#ifdef DBG_QM_MALLOC
	LM_GEN1( memlog, "params (%p, %p, %lu), called from %s: %s(%d)\n",
		qm, p, size, file, func, line);
	if ((p)&&(p>(void*)qm->last_frag_end || p<(void*)qm->first_frag)){
		LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p);
		abort();
	}
#endif

	if (size==0) {
		if (p)
#ifdef DBG_QM_MALLOC
			qm_free(qm, p, file, func, line);
#else
			qm_free(qm, p);
#endif
		pkg_threshold_check();
		return 0;
	}
	if (p==0)
#ifdef DBG_QM_MALLOC
		return qm_malloc(qm, size, file, func, line);
#else
		return qm_malloc(qm, size);
#endif
	f=(struct qm_frag*) ((char*)p-sizeof(struct qm_frag));
#ifdef DBG_QM_MALLOC
	qm_debug_frag(qm, f);
	LM_GEN1( memlog, "realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
			f, f->file, f->func, f->line);
	if (f->u.is_free){
		LM_CRIT("trying to realloc an already freed "
				"pointer %p , fragment %p -- aborting\n", p, f);
		abort();
	}
#endif
	/* find first acceptable size */
	size=ROUNDUP(size);
	if (f->size > size){
		orig_size=f->size;
		/* shrink */
#ifdef DBG_QM_MALLOC
		LM_GEN1(memlog,"shrinking from %lu to %lu\n", f->size, size);
		if(split_frag(qm, f, size, file, "fragm. from qm_realloc", line)!=0){
		LM_GEN1(memlog,"shrinked successful\n");
		}
#else
		split_frag(qm, f, size);
#endif

	}else if (f->size < size){
		/* grow */
#ifdef DBG_QM_MALLOC
		LM_GEN1( memlog, "growing from %lu to %lu\n", f->size, size);
#endif
			orig_size=f->size;
			diff=size-f->size;
			n=FRAG_NEXT(f);
			if (((char*)n < (char*)qm->last_frag_end) &&
					(n->u.is_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
				/* join  */
				qm_detach_free(qm, n);
				qm->free_hash[GET_HASH(n->size)].no--; /*FIXME: slow*/
				f->size+=n->size+FRAG_OVERHEAD;
				qm->used+=FRAG_OVERHEAD;
				FRAG_END(f)->size=f->size;
				/* end checks should be ok */
				/* split it if necessary */
				if (f->size > size ){
	#ifdef DBG_QM_MALLOC
					split_frag(qm, f, size, file, "fragm. from qm_realloc",
										line);
	#else
					split_frag(qm, f, size);
	#endif
				}
			}else{
				/* could not join => realloc */
	#ifdef DBG_QM_MALLOC
				ptr=qm_malloc(qm, size, file, func, line);
	#else
				ptr=qm_malloc(qm, size);
	#endif
				if (ptr) {
					/* copy, need by libssl */
					memcpy(ptr, p, orig_size);
	#ifdef DBG_QM_MALLOC
					qm_free(qm, p, file, func, line);
	#else
					qm_free(qm, p);
	#endif
				}
				p=ptr;
			}
	}else{
		/* do nothing */
#ifdef DBG_QM_MALLOC
		LM_GEN1(memlog,"doing nothing, same size: %lu - %lu\n", f->size, size);
#endif
	}
#ifdef DBG_QM_MALLOC
	LM_GEN1(memlog,"returning %p\n", p);
#endif
	pkg_threshold_check();
	return p;
}




void qm_status(struct qm_block* qm)
{
	struct qm_frag* f;
	int i,j;
	int h;
	int unused;

	LM_GEN1(memdump, "qm_status (%p):\n", qm);
	if (!qm) return;

	LM_GEN1(memdump, " heap size= %lu\n", qm->size);
	LM_GEN1(memdump, " used= %lu, used+overhead=%lu, free=%lu\n",
			qm->used, qm->real_used, qm->size-qm->real_used);
	LM_GEN1(memdump, " max used (+overhead)= %lu\n", qm->max_real_used);

	LM_GEN1(memdump, "dumping all alloc'ed. fragments:\n");
	for (f=qm->first_frag, i=0;(char*)f<(char*)qm->last_frag_end;f=FRAG_NEXT(f)
			,i++){
		if (! f->u.is_free){
			LM_GEN1(memdump,"    %3d. %c  address=%p frag=%p size=%lu used=%d\n",
				i,
				(f->u.is_free)?'a':'N',
				(char*)f+sizeof(struct qm_frag), f, f->size, FRAG_WAS_USED(f));
#ifdef DBG_QM_MALLOC
			LM_GEN1(memdump, "            %s from %s: %s(%ld)\n",
				(f->u.is_free)?"freed":"alloc'd", f->file, f->func, f->line);
			LM_GEN1(memdump, "        start check=%lx, end check= %lx, %lx\n",
				f->check, FRAG_END(f)->check1, FRAG_END(f)->check2);
#endif
		}
	}
	LM_GEN1(memdump, "dumping free list stats :\n");
	for(h=0,i=0;h<QM_HASH_SIZE;h++){
		unused=0;
		for (f=qm->free_hash[h].head.u.nxt_free,j=0;
				f!=&(qm->free_hash[h].head); f=f->u.nxt_free, i++, j++){
				if (!FRAG_WAS_USED(f)){
					unused++;
#ifdef DBG_QM_MALLOC
					LM_GEN1(memdump, "unused fragm.: hash = %3d, fragment %p,"
						" address %p size %lu, created from %s: %s(%lu)\n",
					    h, f, (char*)f+sizeof(struct qm_frag), f->size,
						f->file, f->func, f->line);
#endif
				}
		}

		if (j) LM_GEN1(memdump, "hash= %3d. fragments no.: %5d, unused: %5d\n"
					"\t\t bucket size: %9lu - %9ld (first %9lu)\n",
					h, j, unused, UN_HASH(h),
					((h<=QM_MALLOC_OPTIMIZE/ROUNDTO)?1:2)*UN_HASH(h),
					qm->free_hash[h].head.u.nxt_free->size
				);
		if (j!=qm->free_hash[h].no){
			LM_CRIT("different free frag. count: %d!=%lu"
				" for hash %3d\n", j, qm->free_hash[h].no, h);
		}

	}
	LM_GEN1(memdump, "-----------------------------\n");
}


/* fills a malloc info structure with info about the block
 * if a parameter is not supported, it will be filled with 0 */
void qm_info(struct qm_block* qm, struct mem_info* info)
{
	int r;
	long total_frags;

	total_frags=0;
	memset(info,0, sizeof(*info));
	info->total_size=qm->size;
	info->min_frag=MIN_FRAG_SIZE;
	info->free=qm->size-qm->real_used;
	info->used=qm->used;
	info->real_used=qm->real_used;
	info->max_used=qm->max_real_used;
	for(r=0;r<QM_HASH_SIZE; r++){
		total_frags+=qm->free_hash[r].no;
	}
	info->total_frags=total_frags;
}

int qm_mem_check(struct qm_block *qm)
{
	struct qm_frag *f;
	int i = 0;

	for (f = qm->first_frag; (char *)f < (char *)qm->last_frag_end;
	     f = FRAG_NEXT(f), i++) {

		qm_debug_frag(qm, f);
	}

	LM_DBG("fragments: %d\n", i);

	return i;
}