/** Receive message * WARNING: buf must be 0 terminated (buf[len]=0) or some things might * break (e.g.: modules/textops) */ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) { struct sip_msg* msg; struct run_act_ctx ctx; struct run_act_ctx *bctx; int ret; #ifdef STATS int skipped = 1; int stats_on = 1; #else int stats_on = 0; #endif struct timeval tvb, tve; struct timezone tz; unsigned int diff = 0; str inb; sr_net_info_t netinfo; sr_kemi_eng_t *keng = NULL; if(sr_event_enabled(SREV_NET_DATA_RECV)) { if(sip_check_fline(buf, len)==0) { memset(&netinfo, 0, sizeof(sr_net_info_t)); netinfo.data.s = buf; netinfo.data.len = len; netinfo.rcv = rcv_info; sr_event_exec(SREV_NET_DATA_RECV, (void*)&netinfo); } } inb.s = buf; inb.len = len; sr_event_exec(SREV_NET_DATA_IN, (void*)&inb); len = inb.len; msg=pkg_malloc(sizeof(struct sip_msg)); if (msg==0) { LM_ERR("no mem for sip_msg\n"); goto error00; } msg_no++; /* number of vias parsed -- good for diagnostic info in replies */ via_cnt=0; memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */ /* fill in msg */ msg->buf=buf; msg->len=len; /* zero termination (termination of orig message bellow not that * useful as most of the work is done with scratch-pad; -jiri */ /* buf[len]=0; */ /* WARNING: zero term removed! */ msg->rcv=*rcv_info; msg->id=msg_no; msg->pid=my_pid(); msg->set_global_address=default_global_address; msg->set_global_port=default_global_port; if(likely(sr_msg_time==1)) msg_set_time(msg); if (parse_msg(buf,len, msg)!=0){ if(sr_event_exec(SREV_RCV_NOSIP, (void*)msg)!=0) { LOG(cfg_get(core, core_cfg, corelog), "core parsing of SIP message failed (%s:%d/%d)\n", ip_addr2a(&msg->rcv.src_ip), (int)msg->rcv.src_port, (int)msg->rcv.proto); sr_core_ert_run(msg, SR_CORE_ERT_RECEIVE_PARSE_ERROR); } goto error02; } LM_DBG("After parse_msg...\n"); /* set log prefix */ log_prefix_set(msg); /* ... clear branches from previous message */ clear_branches(); if (msg->first_line.type==SIP_REQUEST){ ruri_mark_new(); /* ruri is usable for forking (not consumed yet) */ if (!IS_SIP(msg)){ if ((ret=nonsip_msg_run_hooks(msg))!=NONSIP_MSG_ACCEPT){ if (unlikely(ret==NONSIP_MSG_ERROR)) goto error03; goto end; /* drop the message */ } } /* sanity checks */ if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){ /* no via, send back error ? */ LM_ERR("no via found in request\n"); STATS_BAD_MSG(); goto error02; } /* check if necessary to add receive?->moved to forward_req */ /* check for the alias stuff */ #ifdef USE_TCP if (msg->via1->alias && cfg_get(tcp, tcp_cfg, accept_aliases) && (((rcv_info->proto==PROTO_TCP) && !tcp_disable) #ifdef USE_TLS || ((rcv_info->proto==PROTO_TLS) && !tls_disable) #endif ) ){ if (tcpconn_add_alias(rcv_info->proto_reserved1, msg->via1->port, rcv_info->proto)!=0){ LM_ERR("tcp alias failed\n"); /* continue */ } } #endif /* skip: */ LM_DBG("preparing to run routing scripts...\n"); if(is_printable(cfg_get(core, core_cfg, latency_cfg_log)) || stats_on==1) { gettimeofday( & tvb, &tz ); } /* execute pre-script callbacks, if any; -jiri */ /* if some of the callbacks said not to continue with * script processing, don't do so * if we are here basic sanity checks are already done * (like presence of at least one via), so you can count * on via1 being parsed in a pre-script callback --andrei */ if (exec_pre_script_cb(msg, REQUEST_CB_TYPE)==0 ) { STATS_REQ_FWD_DROP(); goto end; /* drop the request */ } set_route_type(REQUEST_ROUTE); /* exec the routing script */ if(unlikely(main_rt.rlist[DEFAULT_RT]==NULL)) { keng = sr_kemi_eng_get(); if(keng==NULL) { LM_ERR("no config routing engine registered\n"); goto error_req; } if(keng->froute(msg, REQUEST_ROUTE, NULL)<0) { LM_NOTICE("negative return code from engine function\n"); } } else { if (run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0)<0){ LM_WARN("error while trying script\n"); goto error_req; } } if(is_printable(cfg_get(core, core_cfg, latency_cfg_log)) || stats_on==1) { gettimeofday( & tve, &tz ); diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec); LOG(cfg_get(core, core_cfg, latency_cfg_log), "request-route executed in: %d usec\n", diff); #ifdef STATS stats->processed_requests++; stats->acc_req_time += diff; STATS_RX_REQUEST( msg->first_line.u.request.method_value ); #endif } /* execute post request-script callbacks */ exec_post_script_cb(msg, REQUEST_CB_TYPE); }else if (msg->first_line.type==SIP_REPLY){ /* sanity checks */ if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){ /* no via, send back error ? */ LM_ERR("no via found in reply\n"); STATS_BAD_RPL(); goto error02; } if(is_printable(cfg_get(core, core_cfg, latency_cfg_log)) || stats_on==1) { gettimeofday( & tvb, &tz ); } #ifdef STATS STATS_RX_RESPONSE ( msg->first_line.u.reply.statuscode / 100 ); #endif /* execute pre-script callbacks, if any; -jiri */ /* if some of the callbacks said not to continue with * script processing, don't do so * if we are here basic sanity checks are already done * (like presence of at least one via), so you can count * on via1 being parsed in a pre-script callback --andrei */ if (exec_pre_script_cb(msg, ONREPLY_CB_TYPE)==0 ) { STATS_RPL_FWD_DROP(); goto end; /* drop the reply */ } /* exec the onreply routing script */ keng = sr_kemi_eng_get(); if (onreply_rt.rlist[DEFAULT_RT]!=NULL || keng!=NULL){ set_route_type(CORE_ONREPLY_ROUTE); ret = 1; if(unlikely(keng!=NULL)) { bctx = sr_kemi_act_ctx_get(); init_run_actions_ctx(&ctx); sr_kemi_act_ctx_set(&ctx); ret = keng->froute(msg, CORE_ONREPLY_ROUTE, NULL); sr_kemi_act_ctx_set(bctx); } else { ret=run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, &ctx); } #ifndef NO_ONREPLY_ROUTE_ERROR if (unlikely(ret<0)){ LM_WARN("error while trying onreply script\n"); goto error_rpl; }else #endif /* NO_ONREPLY_ROUTE_ERROR */ if (unlikely(ret==0 || (ctx.run_flags&DROP_R_F))){ STATS_RPL_FWD_DROP(); goto skip_send_reply; /* drop the message, no error */ } } /* send the msg */ forward_reply(msg); skip_send_reply: if(is_printable(cfg_get(core, core_cfg, latency_cfg_log)) || stats_on==1) { gettimeofday( & tve, &tz ); diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec); LOG(cfg_get(core, core_cfg, latency_cfg_log), "reply-route executed in: %d usec\n", diff); #ifdef STATS stats->processed_responses++; stats->acc_res_time+=diff; #endif } /* execute post reply-script callbacks */ exec_post_script_cb(msg, ONREPLY_CB_TYPE); } end: #ifdef STATS skipped = 0; #endif /* free possible loaded avps -bogdan */ reset_avps(); #ifdef WITH_XAVP xavp_reset_list(); #endif LM_DBG("cleaning up\n"); free_sip_msg(msg); pkg_free(msg); #ifdef STATS if (skipped) STATS_RX_DROPS; #endif /* reset log prefix */ log_prefix_set(NULL); return 0; #ifndef NO_ONREPLY_ROUTE_ERROR error_rpl: /* execute post reply-script callbacks */ exec_post_script_cb(msg, ONREPLY_CB_TYPE); reset_avps(); #ifdef WITH_XAVP xavp_reset_list(); #endif goto error02; #endif /* NO_ONREPLY_ROUTE_ERROR */ error_req: LM_DBG("error:...\n"); /* execute post request-script callbacks */ exec_post_script_cb(msg, REQUEST_CB_TYPE); error03: /* free possible loaded avps -bogdan */ reset_avps(); #ifdef WITH_XAVP xavp_reset_list(); #endif error02: free_sip_msg(msg); pkg_free(msg); error00: STATS_RX_DROPS; /* reset log prefix */ log_prefix_set(NULL); return -1; }
/*! \brief * Lookup contact in the database and rewrite Request-URI * \return: -1 : not found * -2 : found but method not allowed * -3 : error */ int lookup(struct sip_msg* _m, char* _t, char* _f, char* _s) { unsigned int flags; urecord_t* r; str aor, uri; ucontact_t* ptr,*it; int res; int ret; str path_dst; str flags_s; char* ua = NULL; char* re_end = NULL; int re_len = 0; char tmp; regex_t ua_re; int regexp_flags = 0; regmatch_t ua_match; pv_value_t val; int_str istr; str sip_instance = {0,0},call_id = {0,0}; /* branch index */ int idx; /* temporary branch values*/ int tlen; char *turi; qvalue_t tq; flags = 0; if (_f && _f[0]!=0) { if (fixup_get_svalue( _m, (gparam_p)_f, &flags_s)!=0) { LM_ERR("invalid owner uri parameter"); return -1; } for( res=0 ; res< flags_s.len ; res++ ) { switch (flags_s.s[res]) { case 'm': flags |= REG_LOOKUP_METHODFILTER_FLAG; break; case 'b': flags |= REG_LOOKUP_NOBRANCH_FLAG; break; case 'r': flags |= REG_BRANCH_AOR_LOOKUP_FLAG; break; case 'u': if (flags_s.s[res+1] != '/') { LM_ERR("no regexp after 'u' flag"); break; } res++; if ((re_end = strrchr(flags_s.s+res+1, '/')) == NULL) { LM_ERR("no regexp after 'u' flag"); break; } res++; re_len = re_end-flags_s.s-res; if (re_len == 0) { LM_ERR("empty regexp"); break; } ua = flags_s.s+res; flags |= REG_LOOKUP_UAFILTER_FLAG; LM_DBG("found regexp /%.*s/", re_len, ua); res += re_len; break; case 'i': regexp_flags |= REG_ICASE; break; case 'e': regexp_flags |= REG_EXTENDED; break; default: LM_WARN("unsupported flag %c \n",flags_s.s[res]); } } } if (flags®_BRANCH_AOR_LOOKUP_FLAG) { /* extract all the branches for further usage */ nbranches = 0; while ( (turi=get_branch(nbranches, &tlen, &tq, NULL, NULL, NULL, NULL)) ) { /* copy uri */ branch_uris[nbranches].s = urimem[nbranches]; if (tlen) { memcpy(branch_uris[nbranches].s, turi, tlen); branch_uris[nbranches].len = tlen; } else { *branch_uris[nbranches].s = '\0'; branch_uris[nbranches].len = 0; } nbranches++; } clear_branches(); idx=0; } if (_s) { if (pv_get_spec_value( _m, (pv_spec_p)_s, &val)!=0) { LM_ERR("failed to get PV value\n"); return -1; } if ( (val.flags&PV_VAL_STR)==0 ) { LM_ERR("PV vals is not string\n"); return -1; } uri = val.rs; } else { if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; } if (extract_aor(&uri, &aor,&sip_instance,&call_id) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } get_act_time(); ul.lock_udomain((udomain_t*)_t, &aor); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain((udomain_t*)_t, &aor); return -1; } if (flags & REG_LOOKUP_UAFILTER_FLAG) { tmp = *(ua+re_len); *(ua+re_len) = '\0'; if (regcomp(&ua_re, ua, regexp_flags) != 0) { LM_ERR("bad regexp '%s'\n", ua); *(ua+re_len) = tmp; return -1; } *(ua+re_len) = tmp; } ptr = r->contacts; ret = -1; /* look first for an un-expired and suported contact */ search_valid_contact: while ( (ptr) && !(VALID_CONTACT(ptr,act_time) && (ret=-2) && allowed_method(_m,ptr,flags))) ptr = ptr->next; if (ptr==0) { /* nothing found */ LM_DBG("nothing found !\n"); goto done; } ua_re_check( ret = -1; ptr = ptr->next; goto search_valid_contact ); if (sip_instance.len && sip_instance.s) { LM_DBG("ruri has gruu in lookup\n"); /* uri has GRUU */ if (ptr->instance.len-2 != sip_instance.len || memcmp(ptr->instance.s+1,sip_instance.s,sip_instance.len)) { LM_DBG("no match to sip instace - [%.*s] - [%.*s]\n",ptr->instance.len-2,ptr->instance.s+1, sip_instance.len,sip_instance.s); /* not the targeted instance, search some more */ ptr = ptr->next; goto search_valid_contact; } LM_DBG("matched sip instace\n"); } if (call_id.len && call_id.s) { /* decide whether GRUU is expired or not * * first - match call-id */ if (ptr->callid.len != call_id.len || memcmp(ptr->callid.s,call_id.s,call_id.len)) { LM_DBG("no match to call id - [%.*s] - [%.*s]\n",ptr->callid.len,ptr->callid.s, call_id.len,call_id.s); ptr = ptr->next; goto search_valid_contact; } /* matched call-id, check if there are newer contacts with * same sip instace bup newer last_modified */ it = ptr->next; while ( it ) { if (VALID_CONTACT(it,act_time)) { if (it->instance.len-2 == sip_instance.len && sip_instance.s && memcmp(it->instance.s+1,sip_instance.s,sip_instance.len) == 0) if (it->last_modified > ptr->last_modified) { /* same instance id, but newer modified -> expired GRUU, no match at all */ break; } } it=it->next; } if (it != NULL) { ret = -1; goto done; } } LM_DBG("found a complete match\n"); ret = 1; if (ptr) { LM_DBG("setting as ruri <%.*s>\n",ptr->c.len,ptr->c.s); if (set_ruri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* If a Path is present, use first path-uri in favour of * received-uri because in that case the last hop towards the uac * has to handle NAT. - agranig */ if (ptr->path.s && ptr->path.len) { if (get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); ret = -3; goto done; } if (set_path_vector(_m, &ptr->path) < 0) { LM_ERR("failed to set path vector\n"); ret = -3; goto done; } if (set_dst_uri(_m, &path_dst) < 0) { LM_ERR("failed to set dst_uri of Path\n"); ret = -3; goto done; } } else if (ptr->received.s && ptr->received.len) { if (set_dst_uri(_m, &ptr->received) < 0) { ret = -3; goto done; } } set_ruri_q( _m, ptr->q); setbflag( _m, 0, ptr->cflags); if (ptr->sock) _m->force_send_socket = ptr->sock; /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } ptr = ptr->next; } /* Append branches if enabled */ /* If we got to this point and the URI had a ;gr parameter and it was matched * to a contact. No point in branching */ if ( flags®_LOOKUP_NOBRANCH_FLAG || (sip_instance.len && sip_instance.s) ) goto done; LM_DBG("looking for branches\n"); do { for( ; ptr ; ptr = ptr->next ) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m,ptr,flags)) { path_dst.len = 0; if(ptr->path.s && ptr->path.len && get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); continue; } ua_re_check(continue); /* The same as for the first contact applies for branches * regarding path vs. received. */ LM_DBG("setting branch <%.*s>\n",ptr->c.len,ptr->c.s); if (append_branch(_m,&ptr->c,path_dst.len?&path_dst:&ptr->received, &ptr->path, ptr->q, ptr->cflags, ptr->sock) == -1) { LM_ERR("failed to append a branch\n"); /* Also give a chance to the next branches*/ continue; } /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } } } /* 0 branches condition also filled; idx initially -1*/ if (!(flags®_BRANCH_AOR_LOOKUP_FLAG) || idx == nbranches) goto done; /* relsease old aor lock */ ul.unlock_udomain((udomain_t*)_t, &aor); ul.release_urecord(r, 0); /* idx starts from -1 */ uri = branch_uris[idx]; if (extract_aor(&uri, &aor, NULL, &call_id) < 0) { LM_ERR("failed to extract address of record for branch uri\n"); return -3; } /* release old urecord */ /* get lock on new aor */ LM_DBG("getting contacts from aor [%.*s]" "in branch %d\n", aor.len, aor.s, idx); ul.lock_udomain((udomain_t*)_t, &aor); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); goto done; } idx++; ptr = r->contacts; } while (1);
/* function returns: * 1 - forward successfull * -1 - error during forward */ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , struct proxy_l * proxy, int proto) { str backup_uri; int branch_ret, lowest_ret; str current_uri; branch_bm_t added_branches; int first_branch; int i; struct cell *t_invite; int success_branch; int try_new; /* make -Wall happy */ current_uri.s=0; set_kr(REQ_FWDED); if (p_msg->REQ_METHOD==METHOD_CANCEL) { t_invite=t_lookupOriginalT( p_msg ); if (t_invite!=T_NULL_CELL) { e2e_cancel( p_msg, t, t_invite ); UNREF(t_invite); return 1; } } /* backup current uri ... add_uac changes it */ backup_uri = p_msg->new_uri; /* if no more specific error code is known, use this */ lowest_ret=E_BUG; /* branches added */ added_branches=0; /* branch to begin with */ first_branch=t->nr_of_outgoings; /* on first-time forwarding, use current uri, later only what is in additional branches (which may be continuously refilled */ if (first_branch==0) { try_new=1; branch_ret=add_uac( t, p_msg, GET_RURI(p_msg), GET_NEXT_HOP(p_msg), proxy, proto ); if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; } else try_new=0; init_branch_iterator(); while((current_uri.s=next_branch( ¤t_uri.len))) { try_new++; branch_ret=add_uac( t, p_msg, ¤t_uri, (p_msg->dst_uri.len) ? (&p_msg->dst_uri) : ¤t_uri, proxy, proto); /* pick some of the errors in case things go wrong; note that picking lowest error is just as good as any other algorithm which picks any other negative branch result */ if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; } /* consume processed branches */ clear_branches(); /* restore original URI */ p_msg->new_uri=backup_uri; /* don't forget to clear all branches processed so far */ /* things went wrong ... no new branch has been fwd-ed at all */ if (added_branches==0) { if (try_new==0) { LOG(L_ERR, "ERROR: t_forward_nonack: no branched for fwding\n"); return -1; } LOG(L_ERR, "ERROR: t_forward_nonack: failure to add branches\n"); return lowest_ret; } /* store script processing value of failure route to transactional context; if currently 0, this forwarding attempt will no longer result in failure_route on error */ t->on_negative=get_on_negative(); /* send them out now */ success_branch=0; for (i=first_branch; i<t->nr_of_outgoings; i++) { if (added_branches & (1<<i)) { if (SEND_BUFFER( &t->uac[i].request)==-1) { LOG(L_ERR, "ERROR: t_forward_nonack: sending request failed\n"); if (proxy) { proxy->errors++; proxy->ok=0; } } else { success_branch++; } start_retr( &t->uac[i].request ); } } if (success_branch<=0) { ser_error=E_SEND; return -1; } return 1; }