/*! * \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; }
/* 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; }
/*! * \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; }
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; }
/*! * \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); }
/* * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
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; }
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; }
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; }
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 ); }
/*! * \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] = ®_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; }
/** * 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; }
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; }
/** * 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; }
/** * 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; }
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; }
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; }
/*! \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; }
/** * 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; }
/*! * \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; }
/** * 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; }
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); }
/** * 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; }
/*! * \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; }
/** * 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(); }
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"); }
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; }