int w_is_first_hop(sip_msg_t *msg, char *p1, char *p2) { int ret; rr_t* r = NULL; sip_uri_t puri; struct ip_addr *ip; if(msg==NULL) return -1; if(msg->first_line.type == SIP_REQUEST) { if (parse_headers( msg, HDR_VIA2_F, 0 )<0 || (msg->via2==0) || (msg->via2->error!=PARSE_OK)) { /* sip request: if more than one via, then not first hop */ /* no second via or error */ LM_DBG("no 2nd via found - first hop\n"); return 1; } return -1; } else if(msg->first_line.type == SIP_REPLY) { /* sip reply: if top record-route is myself * and not received from myself (loop), then is first hop */ if (parse_headers( msg, HDR_EOH_F, 0 )<0) { LM_DBG("error parsing headers\n"); return -1; } if(msg->record_route==NULL) { LM_DBG("no record-route header - first hop\n"); return 1; } if(parse_rr(msg->record_route)<0) { LM_DBG("failed to parse first record-route header\n"); return -1; } r = (rr_t*)msg->record_route->parsed; if(parse_uri(r->nameaddr.uri.s, r->nameaddr.uri.len, &puri)<0) { LM_DBG("failed to parse uri in first record-route header\n"); return -1; } if (((ip = str2ip(&(puri.host))) == NULL) && ((ip = str2ip6(&(puri.host))) == NULL)) { LM_DBG("uri host is not an ip address\n"); return -1; } ret = check_self(&puri.host, (puri.port.s)?puri.port_no:0, (puri.transport_val.s)?puri.proto:0); if(ret!=1) { LM_DBG("top record route uri is not myself\n"); return -1; } if (ip_addr_cmp(ip, &(msg->rcv.src_ip)) && ((msg->rcv.src_port == puri.port_no) || ((puri.port.len == 0) && (msg->rcv.src_port == 5060))) && (puri.proto==msg->rcv.proto || (puri.proto==0 && msg->rcv.proto==PROTO_UDP)) ) { LM_DBG("source address matches top record route uri - loop\n"); return -1; } /* todo - check spirals */ return 1; } else { return -1; } }
/* Returns 0 - nothing found * 1 - T found */ int t_reply_matching( struct sip_msg *p_msg , int *p_branch ) { struct cell* p_cell; unsigned int hash_index = 0; unsigned int entry_label = 0; unsigned int branch_id = 0; char *hashi, *branchi, *p, *n; int hashl, branchl; int scan_space; str cseq_method; str req_method; char *loopi; int loopl; char *syni; int synl; short is_cancel; /* make compiler warnings happy */ loopi=0; loopl=0; syni=0; synl=0; /* split the branch into pieces: loop_detection_check(ignored), hash_table_id, synonym_id, branch_id */ if (!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s)) goto nomatch2; /* we do RFC 3261 tid matching and want to see first if there is * magic cookie in branch */ if (p_msg->via1->branch->value.len<=MCOOKIE_LEN) goto nomatch2; if (memcmp(p_msg->via1->branch->value.s, MCOOKIE, MCOOKIE_LEN)!=0) goto nomatch2; p=p_msg->via1->branch->value.s+MCOOKIE_LEN; scan_space=p_msg->via1->branch->value.len-MCOOKIE_LEN; /* hash_id */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR); hashl=n-p; scan_space-=hashl; if (!hashl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; hashi=p; p=n+1;scan_space--; if (!syn_branch) { /* md5 value */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR ); loopl = n-p; scan_space-= loopl; if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; loopi=p; p=n+1; scan_space--; } else { /* synonym id */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR); synl=n-p; scan_space-=synl; if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; syni=p; p=n+1;scan_space--; } /* branch id - should exceed the scan_space */ n=eat_token_end( p, p+scan_space ); branchl=n-p; if (!branchl ) goto nomatch2; branchi=p; /* sanity check */ if (reverse_hex2int(hashi, hashl, &hash_index)<0 ||hash_index>=TABLE_ENTRIES || reverse_hex2int(branchi, branchl, &branch_id)<0 ||branch_id>=MAX_BRANCHES || (syn_branch ? (reverse_hex2int(syni, synl, &entry_label))<0 : loopl!=MD5_LEN ) ) { DBG("DEBUG: t_reply_matching: poor reply labels %d label %d " "branch %d\n", hash_index, entry_label, branch_id ); goto nomatch2; } DBG("DEBUG: t_reply_matching: hash %d label %d branch %d\n", hash_index, entry_label, branch_id ); /* search the hash table list at entry 'hash_index'; lock the entry first */ cseq_method=get_cseq(p_msg)->method; is_cancel=cseq_method.len==CANCEL_LEN && memcmp(cseq_method.s, CANCEL, CANCEL_LEN)==0; LOCK_HASH(hash_index); for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell; p_cell=p_cell->next_cell) { /* first look if branch matches */ if (syn_branch) { if (p_cell->label != entry_label) continue; } else { if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0) continue; } /* sanity check ... too high branch ? */ if ( branch_id>=p_cell->nr_of_outgoings ) continue; /* does method match ? (remember -- CANCELs have the same branch as canceled transactions) */ req_method=p_cell->method; if ( /* method match */ ! ((cseq_method.len==req_method.len && memcmp( cseq_method.s, req_method.s, cseq_method.len )==0) /* or it is a local cancel */ || (is_cancel && is_invite(p_cell) /* commented out -- should_cancel_branch set it to BUSY_BUFFER to avoid collisions with replies; thus, we test here by buffer size */ /* && p_cell->uac[branch_id].local_cancel.buffer ))) */ && p_cell->uac[branch_id].local_cancel.buffer_len ))) continue; /* we passed all disqualifying factors .... the transaction has been matched ! */ set_t(p_cell); *p_branch =(int) branch_id; REF_UNSAFE( T ); UNLOCK_HASH(hash_index); DBG("DEBUG: t_reply_matching: reply matched (T=%p)!\n",T); /* if this is a 200 for INVITE, we will wish to store to-tags to be * able to distinguish retransmissions later and not to call * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are * enabled -- except callback customers, nobody cares about * retransmissions of multiple 200/INV or ACK/200s */ if (is_invite(p_cell) && p_msg->REPLY_STATUS>=200 && p_msg->REPLY_STATUS<300 && ( (!is_local(p_cell) && has_tran_tmcbs(p_cell,TMCB_RESPONSE_OUT|TMCB_E2EACK_IN) ) || (is_local(p_cell)&&has_tran_tmcbs(p_cell,TMCB_LOCAL_COMPLETED)) )) { if (parse_headers(p_msg, HDR_TO_F, 0)==-1) { LOG(L_ERR, "ERROR: t_reply_matching: to parsing failed\n"); } } if (!is_local(p_cell)) { run_trans_callbacks( TMCB_RESPONSE_IN, T, T->uas.request, p_msg, p_msg->REPLY_STATUS); } return 1; } /* for cycle */ /* nothing found */ UNLOCK_HASH(hash_index); DBG("DEBUG: t_reply_matching: no matching transaction exists\n"); nomatch2: DBG("DEBUG: t_reply_matching: failure to match a transaction\n"); *p_branch = -1; set_t(0); return -1; }
/** * extract the node list from the body of a notification request SIP message * the SIP request will look something like: * KDMQ sip:10.0.0.0:5062 * To: ... * From: ... * Max-Forwards: ... * Content-Length: 22 * * sip:host1:port1;param1=value1 * sip:host2:port2;param2=value2 * ... */ int extract_node_list(dmq_node_list_t* update_list, struct sip_msg* msg) { int content_length, total_nodes = 0; str body; str tmp_uri; dmq_node_t *cur = NULL; dmq_node_t *ret, *find; char *tmp, *end, *match; if(!msg->content_length && (parse_headers(msg,HDR_CONTENTLENGTH_F,0)<0 || !msg->content_length)) { LM_ERR("no content length header found\n"); return -1; } content_length = get_content_length(msg); if(!content_length) { LM_DBG("content length is 0\n"); return total_nodes; } body.s = get_body(msg); body.len = content_length; tmp = body.s; end = body.s + body.len; /* acquire big list lock */ lock_get(&update_list->lock); while(tmp < end) { match = q_memchr(tmp, '\n', end - tmp); if(match) { match++; } else { /* for the last line - take all of it */ match = end; } /* create the orig_uri from the parsed uri line and trim it */ tmp_uri.s = tmp; tmp_uri.len = match - tmp - 1; tmp = match; /* trim the \r, \n and \0's */ trim_r(tmp_uri); find = build_dmq_node(&tmp_uri, 0); if(find==NULL) return -1; ret = find_dmq_node(update_list, find); if (!ret) { LM_DBG("found new node %.*s\n", STR_FMT(&tmp_uri)); cur = build_dmq_node(&tmp_uri, 1); if(!cur) { LM_ERR("error creating new dmq node\n"); goto error; } cur->next = update_list->nodes; update_list->nodes = cur; update_list->count++; total_nodes++; } else if (find->params && ret->status != find->status) { LM_DBG("updating status on %.*s from %d to %d\n", STR_FMT(&tmp_uri), ret->status, find->status); ret->status = find->status; total_nodes++; } destroy_dmq_node(find, 0); } /* release big list lock */ lock_release(&update_list->lock); return total_nodes; error: lock_release(&update_list->lock); return -1; }
int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) { struct to_body *pto, *pfrom = NULL; subs_t subs; pres_ev_t* event= NULL; str* contact= NULL; xmlDocPtr doc= NULL; xmlNodePtr service_node= NULL; unsigned int hash_code= 0; event_t* parsed_event; param_t* ev_param= NULL; int init_req; int reply_code; str reply_str; /*** filter: 'For me or for presence server?' */ reply_code = 400; reply_str = pu_400_rpl; memset(&subs, 0, sizeof(subs_t)); if ( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("parsing headers\n"); goto error; } /* check for Support: eventlist header */ if(!msg->supported) { LM_DBG("no supported header found\n"); return to_presence_code; } if(parse_supported(msg) < 0) { LM_ERR("failed to parse supported headers\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if(!(get_supported(msg) & F_SUPPORTED_EVENTLIST)) { LM_DBG("No 'Support: eventlist' header found\n"); return to_presence_code; } /* inspecting the Event header field */ if(msg->event && msg->event->body.len > 0) { if (!msg->event->parsed && (parse_event(msg->event) < 0)) { LM_ERR("cannot parse Event header\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if(! ( ((event_t*)msg->event->parsed)->parsed & rls_events) ) { return to_presence_code; } } else { goto bad_event; } /* search event in the list */ parsed_event= (event_t*)msg->event->parsed; event= pres_search_event(parsed_event); if(event== NULL) { goto bad_event; } subs.event= event; /* extract the id if any*/ ev_param= parsed_event->params; while(ev_param) { if(ev_param->name.len== 2 && strncasecmp(ev_param->name.s, "id", 2)== 0) { subs.event_id= ev_param->body; break; } ev_param= ev_param->next; } pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("parsing 'To' header failed\n"); goto error; } if(parse_from_uri(msg)<0) { LM_ERR("failed to parse From header\n"); goto error; } pfrom = (struct to_body*)msg->from->parsed; if(pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); goto error; } /* verify if the presentity URI is a resource list */ if(pto->tag_value.s== NULL || pto->tag_value.len==0) /* if an initial Subscribe */ { struct sip_uri fu = ((struct to_body*)msg->from->parsed)->parsed_uri; if( parse_sip_msg_uri(msg)< 0) { LM_ERR("parsing Request URI failed\n"); goto error; } /*verify if Request URI represents a list by asking xcap server*/ if(uandd_to_uri(msg->parsed_uri.user, msg->parsed_uri.host, &subs.pres_uri)< 0) { LM_ERR("while constructing uri from user and domain\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if( get_resource_list(&subs.pres_uri, fu.user, fu.host, &service_node, &doc) < 0) { LM_ERR("failed to get resource list document\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if(doc== NULL|| service_node==NULL) { LM_DBG("list not found - search for uri = %.*s\n",subs.pres_uri.len, subs.pres_uri.s); pkg_free(subs.pres_uri.s); return to_presence_code; } } else /* if request inside a dialog */ { if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot parse callid header\n"); goto error; } /* search if a stored dialog */ hash_code= core_hash(&msg->callid->body, &pto->tag_value, hash_size); lock_get(&rls_table[hash_code].lock); if(pres_search_shtable(rls_table,msg->callid->body, pto->tag_value, pfrom->tag_value, hash_code)== NULL) { lock_release(&rls_table[hash_code].lock); /* reply with Call/Transaction Does Not Exist */ LM_DBG("No dialog match found\n"); return to_presence_code; } lock_release(&rls_table[hash_code].lock); } /* extract dialog information from message headers */ if(pres_extract_sdialog_info(&subs, msg, rls_max_expires, &init_req, server_address)< 0) { LM_ERR("bad Subscribe request\n"); goto error; } reply_code = 500; reply_str = pu_500_rpl; if(init_req) /* if an initial subscribe */ { /** reply with 200 OK*/ if(reply_200(msg, &subs.local_contact, subs.expires, &subs.to_tag)< 0) goto error_free; hash_code= core_hash(&subs.callid, &subs.to_tag, hash_size); subs.local_cseq= 0; if(subs.expires!= 0) { subs.version= 1; if(pres_insert_shtable(rls_table, hash_code, &subs)< 0) { LM_ERR("while adding new subscription\n"); goto error_free; } } } else { if(update_rlsubs(&subs, hash_code, &reply_code, &reply_str) < 0) { LM_ERR("while updating resource list subscription\n"); goto error; } if(get_resource_list(&subs.pres_uri, subs.from_user, subs.from_domain, &service_node, &doc)< 0) { LM_ERR("when getting resource list\n"); goto error; } if(doc== NULL || service_node== NULL) { LM_DBG("list not found( in-dialog request)- search for uri = %.*s\n", subs.pres_uri.len, subs.pres_uri.s); reply_code = 404; reply_str = pu_404_rpl; goto error; } /** reply with 200 OK*/ if(reply_200(msg, &subs.local_contact, subs.expires, 0)< 0) goto error_free; } /*** send Subscribe requests for all in the list */ /* call sending Notify with full state */ if(send_full_notify(&subs, service_node, subs.version, &subs.pres_uri,hash_code)< 0) { LM_ERR("while sending full state Notify\n"); goto error_free; } if(resource_subscriptions(&subs, service_node)< 0) { LM_ERR("while sending Subscribe requests to resources in a list\n"); goto error_free; } if(contact) { if(contact->s) pkg_free(contact->s); pkg_free(contact); } pkg_free(subs.pres_uri.s); if(subs.record_route.s) pkg_free(subs.record_route.s); xmlFreeDoc(doc); return 1; bad_event: if(reply_489(msg)< 0) LM_ERR("failed to send 489 reply\n"); goto error_free; error: if (rls_sigb.reply(msg, reply_code, &reply_str, 0) == -1) { LM_ERR("failed to send 400 reply\n"); return -1; } error_free: if(contact) { if(contact->s) pkg_free(contact->s); pkg_free(contact); } if(subs.pres_uri.s) pkg_free(subs.pres_uri.s); if(subs.record_route.s) pkg_free(subs.record_route.s); if(doc) xmlFreeDoc(doc); return -1; }
int Notify2Xmpp(struct sip_msg* msg, char* s1, char* s2) { struct to_body *pto, *pfrom= NULL; str to_uri; str from_uri={0, 0}; struct hdr_field* hdr= NULL; str body; xmlDocPtr doc= NULL; int is_terminated= 0; str id; ua_pres_t dialog; int event_flag= 0; char buf_to[256]; memset(&dialog, 0, sizeof(ua_pres_t)); LM_DBG("start...\n\n"); if( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("parsing headers\n"); return -1; } if((!msg->event ) ||(msg->event->body.len<=0)) { LM_ERR("Missing event header field value\n"); return -1; } if( msg->to==NULL || msg->to->body.s==NULL) { LM_ERR("cannot parse TO header\n"); return -1; } pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("failed to parse TO header\n"); return -1; } dialog.watcher_uri= &pto->uri; URI_ADD_NULL_TERM(to_uri, buf_to, dialog.watcher_uri); if (pto->tag_value.s==NULL || pto->tag_value.len==0 ) { LM_ERR("to tag value not parsed\n"); goto error; } id= pto->tag_value; dialog.from_tag= id; if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot parse callid header\n"); goto error; } dialog.call_id = msg->callid->body; if (!msg->from || !msg->from->body.s) { LM_ERR("ERROR cannot find 'from' header!\n"); goto error; } if (msg->from->parsed == NULL) { /* parsing from header */ if ( parse_from_header( msg )<0 ) { LM_ERR("ERROR cannot parse From header\n"); goto error; } } pfrom = (struct to_body*)msg->from->parsed; dialog.pres_uri= &pfrom->uri; from_uri.s = xmpp_uri_sip2xmpp(dialog.pres_uri); if(from_uri.s == 0) { LM_ERR("Failed to translate uri from sip to xmpp [%.*s]\n", dialog.pres_uri->len, dialog.pres_uri->s); goto error; } from_uri.len= strlen(from_uri.s); if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); goto error; } dialog.to_tag= pfrom->tag_value; dialog.flag|= XMPP_SUBSCRIBE; if(msg->event->body.len== 8 && (strncasecmp(msg->event->body.s,"presence",8 )==0)) event_flag|= PRESENCE_EVENT; else if(msg->event->body.len== 14 && (strncasecmp(msg->event->body.s,"presence.winfo",14 )==0)) event_flag|= PWINFO_EVENT; else { LM_ERR("wrong event\n"); goto error; } dialog.event= event_flag; if(pua_is_dialog(&dialog)< 0) // verify if within a stored dialog { LM_ERR("Notify in a non existing dialog\n"); goto error; } /*constructing the xml body*/ if(get_content_length(msg) == 0 ) { body.s= NULL; body.len= 0; } else { if ( get_body(msg,&body)!=0 || body.len==0) { LM_ERR("cannot extract body from msg\n"); goto error; } } /* treat the two cases: event= presence & event=presence.winfo */ if(event_flag & PRESENCE_EVENT) { LM_DBG("PRESENCE\n"); hdr = get_header_by_static_name( msg, "Subscription-State" ); if(hdr && strncasecmp(hdr->body.s,"terminated", 10)== 0) { /* chack if reason timeout => don't send notification */ if(strncasecmp(hdr->body.s+11,"reason=timeout", 14)== 0) { LM_DBG("Received Notification with state" "terminated; reason= timeout=> don't send notification\n"); return 1; } is_terminated= 1; } if(build_xmpp_content(&to_uri, &from_uri, &body, &id, is_terminated)< 0) { LM_ERR("in function build_xmpp_content\n"); goto error; } xmlFreeDoc(doc); } else { if(event_flag & PWINFO_EVENT) { LM_DBG("PRESENCE.WINFO\n"); hdr = get_header_by_static_name( msg, "Subscription-State" ); if(hdr && strncasecmp(hdr->body.s,"terminated", 10)== 0) { LM_DBG("Notify for presence.winfo with" " Subscription-State terminated- should not translate\n"); goto error; } if(winfo2xmpp(&to_uri, &body, &id)< 0) { LM_ERR("while sending subscription\n"); goto error; } } else { LM_ERR("Missing or unsupported event header field value\n"); goto error; } } return 1; error: if(doc) xmlFreeDoc(doc); return 0; }
/* * Find credentials with given realm in a SIP message header */ inline int ims_find_credentials(struct sip_msg* _m, str* _realm, hdr_types_t _hftype, struct hdr_field** _h) { struct hdr_field** hook, *ptr, *prev; hdr_flags_t hdr_flags; int res; str* r; LM_DBG("Searching credentials in realm [%.*s]\n", _realm->len, _realm->s); /* * Determine if we should use WWW-Authorization or * Proxy-Authorization header fields, this parameter * is set in www_authorize and proxy_authorize */ switch (_hftype) { case HDR_AUTHORIZATION_T: hook = &(_m->authorization); hdr_flags = HDR_AUTHORIZATION_F; break; case HDR_PROXYAUTH_T: hook = &(_m->proxy_auth); hdr_flags = HDR_PROXYAUTH_F; break; default: hook = &(_m->authorization); hdr_flags = HDR_T2F(_hftype); break; } /* * If the credentials haven't been parsed yet, do it now */ if (*hook == 0) { /* No credentials parsed yet */ LM_DBG("*hook == 0, No credentials parsed yet\n"); if (parse_headers(_m, hdr_flags, 0) == -1) { LM_ERR("Error while parsing headers\n"); return -1; } } ptr = *hook; LM_DBG("*hook = %p\n", ptr); /* * Iterate through the credentials in the message and * find credentials with given realm */ while (ptr) { res = parse_credentials(ptr); if (res < 0) { LM_ERR("Error while parsing credentials\n"); return (res == -1) ? -2 : -3; } else if (res == 0) { LM_DBG("Credential parsed successfully\n"); if (_realm->len) { r = &(((auth_body_t*) (ptr->parsed))->digest.realm); LM_DBG("Comparing realm <%.*s> and <%.*s>\n", _realm->len, _realm->s, r->len, r->s); if (r->len == _realm->len) { if (!strncasecmp(_realm->s, r->s, r->len)) { *_h = ptr; return 0; } } } else { *_h = ptr; return 0; } } prev = ptr; if (parse_headers(_m, hdr_flags, 1) == -1) { LM_ERR("Error while parsing headers\n"); return -4; } else { if (prev != _m->last_header) { if (_m->last_header->type == _hftype) ptr = _m->last_header; else break; } else break; } } /* * Credentials with given realm not found */ LM_DBG("Credentials with given realm not found\n"); return 1; }
static void __dialog_sendpublish(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) { str tag = {0,0}; struct to_body from; str peer_uri= {0, 0}; char flag = DLG_PUB_AB; str flag_str; struct to_body peer_to_body; str entity_uri= {0, 0}; int buf_len = 255; flag_str.s = &flag; flag_str.len = 1; memset(&from, 0, sizeof(struct to_body)); memset(&peer_to_body, 0, sizeof(struct to_body)); from.uri = dlg->from_uri; peer_uri.len = buf_len; peer_uri.s = (char*)pkg_malloc(buf_len); if(peer_uri.s == NULL) { LM_ERR("No more memory\n"); goto error; } /* extract the peer_uri */ if(dlg_api.fetch_dlg_value(dlg, &peer_dlg_var, &peer_uri, 1) < 0 || peer_uri.len==0) { LM_ERR("Failed to fetch peer uri dialog variable\n"); goto error; } LM_DBG("peer_uri = %.*s\n", peer_uri.len, peer_uri.s); parse_to(peer_uri.s, peer_uri.s+peer_uri.len, &peer_to_body); if(peer_to_body.error != PARSE_OK) { LM_ERR("Failed to peer uri [%.*s]\n", peer_uri.len, peer_uri.s); goto error; } /* try to extract the flag */ dlg_api.fetch_dlg_value(dlg, &flag_dlg_var, &flag_str, 1); LM_DBG("flag = %c\n", flag); entity_uri.len = buf_len; entity_uri.s = (char*)pkg_malloc(buf_len); if(entity_uri.s == NULL) { LM_ERR("No more memory\n"); goto error; } /* check if entity is also custom */ if(dlg_api.fetch_dlg_value(dlg, &entity_dlg_var, &entity_uri, 1) == 0) { /* overwrite from with this value */ parse_to(entity_uri.s, entity_uri.s + entity_uri.len, &from); if(from.error != PARSE_OK) { LM_ERR("Wrong format for entity body\n"); goto error; } LM_DBG("entity_uri = %.*s\n", entity_uri.len, entity_uri.s); LM_DBG("from uri = %.*s\n", from.uri.len, from.uri.s); } switch (type) { case DLGCB_FAILED: case DLGCB_TERMINATED: case DLGCB_EXPIRED: LM_DBG("dialog over, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); if(flag == DLG_PUB_AB || flag == DLG_PUB_A) dialog_publish("terminated", &from, &peer_to_body, &(dlg->callid), 1, 0, 0, 0); if(flag == DLG_PUB_AB || flag == DLG_PUB_B) dialog_publish("terminated", &peer_to_body, &from, &(dlg->callid), 0, 0, 0, 0); break; case DLGCB_CONFIRMED: case DLGCB_REQ_WITHIN: LM_DBG("dialog confirmed, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); if(flag == DLG_PUB_AB || flag == DLG_PUB_A) dialog_publish("confirmed", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, 0, 0); if(flag == DLG_PUB_AB || flag == DLG_PUB_B) dialog_publish("confirmed", &peer_to_body, &from, &(dlg->callid), 0, dlg->lifetime, 0, 0); break; case DLGCB_EARLY: LM_DBG("dialog is early, from=%.*s\n", from.uri.len, from.uri.s); if (include_tags) { /* get to tag*/ if ( !_params->msg->to && ((parse_headers(_params->msg, HDR_TO_F,0)<0) || !_params->msg->to) ) { LM_ERR("bad reply or missing TO hdr :-/\n"); tag.s = 0; tag.len = 0; } else { tag = get_to(_params->msg)->tag_value; if (tag.s==0 || tag.len==0) { LM_ERR("missing TAG param in TO hdr :-/\n"); tag.s = 0; tag.len = 0; } } if(flag == DLG_PUB_AB || flag == DLG_PUB_A) { if (caller_confirmed) { dialog_publish("confirmed", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, &(dlg->legs[DLG_CALLER_LEG].tag), &tag); } else { dialog_publish("early", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, &(dlg->legs[DLG_CALLER_LEG].tag), &tag); } } if(flag == DLG_PUB_AB || flag == DLG_PUB_B) { dialog_publish("early", &peer_to_body, &from, &(dlg->callid), 0, dlg->lifetime, &tag, &(dlg->legs[DLG_CALLER_LEG].tag)); } } else { if(flag == DLG_PUB_AB || flag == DLG_PUB_A) { if (caller_confirmed) { dialog_publish("confirmed", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, 0, 0); } else { dialog_publish("early", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, 0, 0); } } if(flag == DLG_PUB_AB || flag == DLG_PUB_B) { dialog_publish("early", &peer_to_body, &from, &(dlg->callid), 0, dlg->lifetime, 0, 0); } } break; default: LM_ERR("unhandled dialog callback type %d received, from=%.*s\n", type, dlg->from_uri.len, dlg->from_uri.s); if(flag == DLG_PUB_AB || flag == DLG_PUB_A) dialog_publish("terminated", &from, &peer_to_body, &(dlg->callid), 1, 0, 0, 0); if(flag == DLG_PUB_AB || flag == DLG_PUB_B) dialog_publish("terminated", &peer_to_body, &from, &(dlg->callid), 0, 0, 0, 0); } error: if(peer_uri.s) pkg_free(peer_uri.s); if(entity_uri.s) pkg_free(entity_uri.s); if (peer_to_body.param_lst) free_to_params(&peer_to_body); if (from.param_lst) free_to_params(&from); }
int decode_contact_header (struct sip_msg *msg,char *unused1,char *unused2) { contact_body_t *cb; contact_t *c; str uri; str newUri; char separator; int res; #ifdef DEBUG str* ruri; fprintf (stdout,"---START--------DECODE CONTACT HEADER-----------------\n"); #endif if ((msg->contact == NULL)&&((parse_headers(msg,HDR_CONTACT_F,0) == -1) || (msg->contact== NULL) )) { LM_ERR("no Contact header present\n"); return -1; } separator = DEFAULT_SEPARATOR[0]; if (contact_flds_separator != NULL) if (strlen(contact_flds_separator)>=1) separator = contact_flds_separator[0]; #ifdef DEBUG fprintf (stdout,"Using separator %c\n",separator); ruri = GET_RURI(msg); fprintf (stdout,"[len = %d]New uri is->%.*s\n", ruri->len,ruri->len,ruri->s); ruri = &msg->first_line.u.request.uri; fprintf (stdout, "INITIAL.s=[%.*s]\n", ruri->len, ruri->s); #endif if (msg->contact->parsed == NULL) parse_contact (msg->contact); if (msg->contact->parsed != NULL) { cb = (contact_body_t *) msg->contact->parsed; c = cb->contacts; // we visit each contact if (c != NULL) { uri = c->uri; res = decode_uri (uri, separator, &newUri); #ifdef DEBUG fprintf (stdout, "newuri.s=[%.*s]\n", newUri.len, newUri.s); #endif if (res != 0) { LM_ERR("failed decoding contact.Code %d\n", res); #ifdef STRICT_CHECK return res; #endif } else if (patch (msg, uri.s, uri.len, newUri.s, newUri.len) < 0) { LM_ERR("lumping failed in mangling port \n"); return -2; } #ifdef DECODE_ALL_CONTACTS while (c->next != NULL) { c = c->next; uri = c->uri; res = decode_uri (uri, separator, &newUri); if (res != 0) { LM_ERR("failed decoding contact.Code %d\n",res); #ifdef STRICT_CHECK return res; #endif } else if (patch (msg, uri.s, uri.len, newUri.s, newUri.len) < 0) { LM_ERR("lumping failed in mangling port \n"); return -3; } } // end while #endif } // if c!= NULL } // end if else // after parsing still NULL { LM_ERR("unable to parse Contact header\n"); return -4; } #ifdef DEBUG fprintf (stdout,"---END--------DECODE CONTACT HEADER-----------------\n");fflush(stdout); #endif return 1; }
//#define DEBUG int encode_contact (struct sip_msg *msg, char *encoding_prefix,char *public_ip) { contact_body_t *cb; contact_t *c; str uri; str newUri; int res; char separator; /* * I have a list of contacts in contact->parsed which is of type contact_body_t * inside i have a contact->parsed->contact which is the head of the list of contacts * inside it is a * str uri; * struct contact *next; * I just have to visit each uri and encode each uri according to a scheme */ if ((msg->contact == NULL)&&((parse_headers(msg,HDR_CONTACT_F,0) == -1) || (msg->contact == NULL) )) { LM_ERR("no Contact header present\n"); return -1; } separator = DEFAULT_SEPARATOR[0]; if (contact_flds_separator != NULL) if (strlen(contact_flds_separator)>=1) separator = contact_flds_separator[0]; if (msg->contact->parsed == NULL) parse_contact (msg->contact); if (msg->contact->parsed != NULL) { cb = (contact_body_t *) msg->contact->parsed; c = cb->contacts; /* we visit each contact */ if (c != NULL) { uri = c->uri; res = encode_uri (uri, encoding_prefix, public_ip,separator, &newUri); if (res != 0) { LM_ERR("failed encoding contact.Code %d\n", res); #ifdef STRICT_CHECK return res; #endif } else if (patch (msg, uri.s, uri.len, newUri.s, newUri.len) < 0) { LM_ERR("lumping failed in mangling port \n"); return -2; } /* encoding next contacts too?*/ #ifdef ENCODE_ALL_CONTACTS while (c->next != NULL) { c = c->next; uri = c->uri; res = encode_uri (uri, encoding_prefix,public_ip,separator,&newUri); if (res != 0) { LM_ERR("failed encode_uri.Code %d\n",res); #ifdef STRICT_CHECK return res; #endif } else if (patch (msg, uri.s, uri.len, newUri.s, newUri.len)< 0) { LM_ERR("lumping failed in mangling port \n"); return -3; } } /* while */ #endif /* ENCODE_ALL_CONTACTS */ } /* if c != NULL */ } /* end if */ else /* after parsing still NULL */ { LM_ERR("unable to parse Contact header\n"); return -4; } return 1; }
int sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip) { int i, oldContentLength, newContentLength, diff, oldlen,len,off,ret,needToDealocate; unsigned int mask, address, locatedIp; struct lump *l; regmatch_t pmatch; regex_t *re; char *s, *pos,*begin,*key; char buffer[16]; /* 123.456.789.123\0 */ #ifdef DEBUG fprintf (stdout,"---START--------MANGLE IP-----------------\n"); #endif key = IP_REGEX; /* * Checking if msg has a payload */ if (msg == NULL) { LOG(L_ERR,"ERROR: sdp_mangle_ip: Received NULL for msg\n"); return -1; } if ((msg->content_length==0) && ((parse_headers(msg,HDR_CONTENTLENGTH,0)==-1) || (msg->content_length==0) )){ LOG(L_ERR,"ERROR: sdp_mangle_port: bad or missing " "Content-Length \n"); return -2; } oldContentLength = get_content_length(msg); if (oldContentLength <= 0) { LOG(L_ERR,"ERROR: sdp_mangle_ip: Received <= for Content-Length\n"); return -2; } /* checking oldip */ if (oldip == NULL) { LOG(L_ERR,"ERROR: sdp_mangle_ip: Received NULL for oldip\n"); return -3; } /* checking newip */ if (newip == NULL) { LOG(L_ERR,"ERROR: sdp_mangle_ip: Received NULL for newip\n"); return -4; } i = parse_ip_netmask (oldip, &pos, &mask); if (i == -1) { /* invalid value for the netmask specified in oldip */ LOG(L_ERR,"ERROR: sdp_mangle_ip: invalid value for the netmask specified in oldip\n"); return -5; } else { i = parse_ip_address (pos, &address); if (pos != NULL) free (pos); if (i == 0) { LOG(L_ERR,"ERROR: sdp_mangle_ip: invalid value for the ip specified in oldip\n"); return -6; /* parse error in ip */ } } /* now we have in address/netmask binary values */ begin = get_body(msg);//msg->buf + msg->first_line.len; // inlocuiesc cu begin = getbody */ ret = -1; len = strlen (newip); /* try to use precompiled expressions */ needToDealocate = 0; if (ipExpression != NULL) { re = ipExpression; #ifdef DEBUG fprintf(stdout,"Using PRECOMPILED expression for ip ...\n"); #endif } else /* we are not using precompiled expressions */ { re = pkg_malloc(sizeof(regex_t)); if (re == NULL) { LOG(L_ERR,"ERROR: sdp_mangle_ip: Unable to allocate re\n"); return -7; } needToDealocate = 1; if ((regcomp (re, key, REG_EXTENDED)) != 0) { LOG(L_ERR,"ERROR: sdp_mangle_ip: Unable to compile %s \n",key); return -8; } #ifdef DEBUG fprintf(stdout,"Using ALLOCATED expression for ip ...\n"); #endif } diff = 0; while ((begin < msg->buf + msg->len) && (regexec (re, begin, 1, &pmatch, 0) == 0)) { off = begin - msg->buf; if (pmatch.rm_so == -1) { LOG (L_ERR,"ERROR: sdp_mangler_ip: offset unknown\n"); return -9; } #ifdef STRICT_CHECK pmatch.rm_eo --; /* return with one space,\n,\r */ #endif /* for BSD and Solaris we avoid memrchr pos = (char *) memrchr (begin + pmatch.rm_so, ' ',pmatch.rm_eo - pmatch.rm_so); */ pos = begin+pmatch.rm_eo; do pos--; while (*pos != ' '); /* we should find ' ' because we matched c=IN IP4 ip */ pos++; /* jumping over space */ oldlen = (pmatch.rm_eo - pmatch.rm_so) - (pos - (begin + pmatch.rm_so)); /* ip length */ if (oldlen > 15) { LOG(L_WARN,"WARNING: sdp_mangle_ip: Silent fail because oldlen > 15\n"); #ifdef STRICT_CHECK return -10; #else goto continue2; /* silent fail return -10; invalid ip format ,probably like 1000.3.12341.2 */ #endif } buffer[0] = '\0'; strncat ((char *) buffer, pos, oldlen); buffer[oldlen] = '\0'; i = parse_ip_address (buffer, &locatedIp); if (i == 0) { LOG(L_WARN,"WARNING: sdp_mangle_ip: Silent fail on parsing matched address \n"); #ifdef STRICT_CHECK return -11; #else goto continue2; #endif } if (same_net (locatedIp, address, mask) == 0) { LOG(L_WARN,"WARNING: sdp_mangle_ip: Silent fail because matched address is not in network\n"); #ifdef DEBUG fprintf(stdout,"Extracted ip is %s and not mangling \n",buffer); #endif goto continue2; /* not in the same net, skiping */ } #ifdef DEBUG fprintf(stdout,"Extracted ip is %s and mangling to %s\n",buffer,newip); #endif /* replacing ip */ /* deleting old ip */ if ((l = del_lump (msg,pmatch.rm_so + off + (pos - (begin + pmatch.rm_so)),oldlen, 0)) == 0) { LOG (L_ERR,"ERROR: sdp_mangle_ip: del_lump failed\n"); return -12; } s = pkg_malloc (len); if (s == 0) { LOG (L_ERR,"ERROR: sdp_mangle_ip: mem. allocation failure\n"); return -13; } memcpy (s, newip, len); if (insert_new_lump_after (l, s, len, 0) == 0) { LOG (L_ERR, "ERROR: sdp_mangle_ip: could not insert new lump\n"); pkg_free (s); return -14; } diff = diff + len /*new length */ - oldlen; /* new cycle */ ret++; continue2: begin = begin + pmatch.rm_eo; } /* while */ if (needToDealocate) { regfree (re); /* if I am going to use precompiled expressions to be removed */ pkg_free(re); #ifdef DEBUG fprintf(stdout,"Dealocating expression for ip ...\n"); #endif } if (diff != 0) { newContentLength = oldContentLength + diff; patch_content_length (msg, newContentLength); } #ifdef DEBUG fprintf (stdout,"---END--------MANGLE IP-----------------\n"); #endif return ret+2; }
int sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) { int oldContentLength, newContentLength, oldlen, err, oldPort, newPort, diff, offsetValue,len,off,ret,needToDealocate; struct lump *l; regmatch_t pmatch; regex_t *re; char *s, *pos,*begin,*key; char buf[6]; key = PORT_REGEX; /* * Checking if msg has a payload */ if (msg == NULL) { LOG(L_ERR,"ERROR: sdp_mangle_port: Received NULL for msg \n"); return -1; } if ((msg->content_length==0) && ((parse_headers(msg,HDR_CONTENTLENGTH,0)==-1) || (msg->content_length==0) )){ LOG(L_ERR,"ERROR: sdp_mangle_port: bad or missing " "Content-Length \n"); return -2; } oldContentLength = get_content_length(msg); if (oldContentLength <= 0) { LOG(L_ERR,"ERROR: sdp_mangle_port: Received <= 0 for Content-Length \n"); return -2; } if (offset == NULL) return -14; if (sscanf (offset, "%d", &offsetValue) != 1) { LOG(L_ERR,"ERROR: sdp_mangle_port: Invalid value for offset \n"); return -13; } //offsetValue = (int)offset; #ifdef DEBUG fprintf (stdout,"---START--------MANGLE PORT-----------------\n"); fprintf(stdout,"===============OFFSET = %d\n",offsetValue); #endif if ((offsetValue < MIN_OFFSET_VALUE) || (offsetValue > MAX_OFFSET_VALUE)) { LOG(L_ERR,"ERROR: sdp_mangle_port: Invalid value %d for offset \n",offsetValue); return -3; } begin = get_body(msg); //msg->buf + msg->first_line.len; // inlocuiesc cu begin = getbody */ ret = -1; /* try to use precompiled expressions */ needToDealocate = 0; if (portExpression != NULL) { re = portExpression; #ifdef DEBUG fprintf(stdout,"Using PRECOMPILED expression for port ...\n"); #endif } else /* we are not using precompiled expressions */ { re = pkg_malloc(sizeof(regex_t)); if (re == NULL) { LOG(L_ERR,"ERROR: sdp_mangle_port: Unable to allocate re\n"); return -4; } needToDealocate = 1; if ((regcomp (re, key, REG_EXTENDED)) != 0) { LOG(L_ERR,"ERROR: sdp_mangle_port: Unable to compile %s \n",key); return -5; } #ifdef DEBUG fprintf(stdout,"Using ALLOCATED expression for port ...\n"); #endif } diff = 0; while ((begin < msg->buf + msg->len) && (regexec (re, begin, 1, &pmatch, 0) == 0)) { off = begin - msg->buf; if (pmatch.rm_so == -1) { LOG (L_ERR, "ERROR: sdp_mangle_port: offset unknown\n"); return -6; } #ifdef STRICT_CHECK pmatch.rm_eo --; /* return with one space */ #endif /* for BSD and Solaris we avoid memrchr pos = (char *) memrchr (begin + pmatch.rm_so, ' ',pmatch.rm_eo - pmatch.rm_so); */ pos = begin+pmatch.rm_eo; #ifdef DEBUG printf("begin=%c pos=%c rm_so=%d rm_eo=%d\n",*begin,*pos,pmatch.rm_so,pmatch.rm_eo); #endif do pos--; while (*pos != ' '); /* we should find ' ' because we matched m=audio port */ pos++; /* jumping over space */ oldlen = (pmatch.rm_eo - pmatch.rm_so) - (pos - (begin + pmatch.rm_so)); /* port length */ /* convert port to int */ oldPort = str2s (pos, oldlen, &err); #ifdef DEBUG printf("port to convert [%.*s] to int\n",oldlen,pos); #endif if (err) { LOG(L_ERR,"ERROR: sdp_mangle_port: Error converting [%.*s] to int\n",oldlen,pos); #ifdef STRICT_CHECK return -7; #else goto continue1; #endif } if ((oldPort < MIN_ORIGINAL_PORT) || (oldPort > MAX_ORIGINAL_PORT)) /* we silently fail,we ignore this match or return -11 */ { #ifdef DEBUG printf("WARNING: sdp_mangle_port: Silent fail for not matching old port %d\n",oldPort); #endif LOG(L_WARN,"WARNING: sdp_mangle_port: Silent fail for not matching old port %d\n",oldPort); #ifdef STRICT_CHECK return -8; #else goto continue1; #endif } if ((offset[0] != '+')&&(offset[0] != '-')) newPort = offsetValue;//fix value else newPort = oldPort + offsetValue; /* new port is between 1 and 65536, or so should be */ if ((newPort < MIN_MANGLED_PORT) || (newPort > MAX_MANGLED_PORT)) /* we silently fail,we ignore this match */ { #ifdef DEBUG printf("WARNING: sdp_mangle_port: Silent fail for not matching new port %d\n",newPort); #endif LOG(L_WARN,"WARNING: sdp_mangle_port: Silent fail for not matching new port %d\n",newPort); #ifdef STRICT_CHECK return -9; #else goto continue1; #endif } #ifdef DEBUG fprintf(stdout,"Extracted port is %d and mangling to %d\n",oldPort,newPort); #endif /* len = 1; while ((newPort = (newPort / 10)) != 0) len++; newPort = oldPort + offsetValue; */ if (newPort >= 10000) len = 5; else if (newPort >= 1000) len = 4; else if (newPort >= 100) len = 3; else if (newPort >= 10) len = 2; else len = 1; /* replaced five div's + 1 add with most probably 1 comparison or 2 */ /* deleting old port */ if ((l = del_lump (msg,pmatch.rm_so + off + (pos -(begin + pmatch.rm_so)),oldlen, 0)) == 0) { LOG (L_ERR,"ERROR: sdp_mangle_port: del_lump failed\n"); return -10; } s = pkg_malloc (len); if (s == 0) { LOG (L_ERR,"ERROR: sdp_mangle_port : memory allocation failure\n"); return -11; } snprintf (buf, len + 1, "%u", newPort); /* converting to string */ memcpy (s, buf, len); if (insert_new_lump_after (l, s, len, 0) == 0) { LOG (L_ERR, "ERROR: sdp_mangle_port: could not insert new lump\n"); pkg_free (s); return -12; } diff = diff + len /*new length */ - oldlen; /* new cycle */ ret++; #ifndef STRICT_CHECK continue1: #endif begin = begin + pmatch.rm_eo; } /* while */ if (needToDealocate) { regfree (re); pkg_free(re); #ifdef DEBUG fprintf(stdout,"Dealocating expression for port ...\n"); #endif } if (diff != 0) { newContentLength = oldContentLength + diff; patch_content_length (msg, newContentLength); } #ifdef DEBUG fprintf (stdout,"---END--------MANGLE PORT-----------------\n"); #endif return ret+2; }
/** * manage SIP message */ int xjab_manage_sipmsg(struct sip_msg *msg, int type) { str body, dst, from_uri; xj_sipmsg jsmsg; int pipe, fl; t_xj_jkey jkey, *p; int mime; body.s=0; /* fixes gcc 4.0 warning */ body.len=0; // extract message body - after that whole SIP MESSAGE is parsed if (type==XJ_SEND_MESSAGE) { /* get the message's body */ body.s = get_body( msg ); if(body.s==0) { LOG(L_ERR,"XJAB:xjab_manage_sipmsg: ERROR cannot extract body from" " msg\n"); goto error; } /* content-length (if present) must be already parsed */ if(!msg->content_length) { LOG(L_ERR,"XJAB:xjab_manage_sipmsg: ERROR no Content-Length" " header found!\n"); goto error; } body.len = get_content_length(msg); /* parse the content-type header */ if((mime=parse_content_type_hdr(msg))<1) { LOG(L_ERR,"XJAB:xjab_manage_sipmsg: ERROR cannot parse" " Content-Type header\n"); goto error; } /* check the content-type value */ if(mime!=(TYPE_TEXT<<16)+SUBTYPE_PLAIN && mime!=(TYPE_MESSAGE<<16)+SUBTYPE_CPIM) { LOG(L_ERR,"XJAB:xjab_manage_sipmsg: ERROR invalid content-type for" " a message request! type found=%d\n", mime); goto error; } } // check for TO and FROM headers - if is not SIP MESSAGE if(parse_headers( msg, HDR_TO_F|HDR_FROM_F, 0)==-1 || !msg->to || !msg->from) { LOG(L_ERR,"XJAB:xjab_manage_sipmsg: cannot find TO or FROM HEADERS!\n"); goto error; } /* parsing from header */ if ( parse_from_header( msg )==-1 || msg->from->parsed==NULL) { DBG("ERROR:xjab_manage_sipmsg: cannot get FROM header\n"); goto error; } from_uri.s = ((struct to_body*)msg->from->parsed)->uri.s; from_uri.len = ((struct to_body*)msg->from->parsed)->uri.len; if(xj_extract_aor(&from_uri, 0)) { DBG("ERROR:xjab_manage_sipmsg: cannot get AoR from FROM header\n"); goto error; } jkey.hash = xj_get_hash(&from_uri, NULL); jkey.id = &from_uri; // get the communication pipe with the worker switch(type) { case XJ_SEND_MESSAGE: case XJ_JOIN_JCONF: case XJ_GO_ONLINE: if((pipe = xj_wlist_get(jwl, &jkey, &p)) < 0) { DBG("XJAB:xjab_manage_sipmsg: cannot find pipe of the worker!\n"); goto error; } break; case XJ_EXIT_JCONF: case XJ_GO_OFFLINE: if((pipe = xj_wlist_check(jwl, &jkey, &p)) < 0) { DBG("XJAB:xjab_manage_sipmsg: no open Jabber session for" " <%.*s>!\n", from_uri.len, from_uri.s); goto error; } break; default: DBG("XJAB:xjab_manage_sipmsg: ERROR:strange SIP msg type!\n"); goto error; } // if is for going ONLINE/OFFLINE we do not need the destination if(type==XJ_GO_ONLINE || type==XJ_GO_OFFLINE) goto prepare_job; // determination of destination // - try to get it from new_uri, r-uri or to hdr, but check it against // jdomain and aliases dst.len = 0; if( msg->new_uri.len > 0) { dst.s = msg->new_uri.s; dst.len = msg->new_uri.len; if(xj_wlist_check_aliases(jwl, &dst)) dst.len = 0; #ifdef XJ_EXTRA_DEBUG else DBG("XJAB:xjab_manage_sipmsg: using NEW URI for destination\n"); #endif } if (dst.len == 0 && msg->first_line.u.request.uri.s != NULL && msg->first_line.u.request.uri.len > 0 ) { dst.s = msg->first_line.u.request.uri.s; dst.len = msg->first_line.u.request.uri.len; if(xj_wlist_check_aliases(jwl, &dst)) dst.len = 0; #ifdef XJ_EXTRA_DEBUG else DBG("XJAB:xjab_manage_sipmsg: using R-URI for destination\n"); #endif } if(dst.len == 0 && msg->to->parsed) { dst.s = ((struct to_body*)msg->to->parsed)->uri.s; dst.len = ((struct to_body*)msg->to->parsed)->uri.len; if(dst.s == NULL || xj_wlist_check_aliases(jwl, &dst)) dst.len = 0; #ifdef XJ_EXTRA_DEBUG else DBG("XJAB:xjab_manage_sipmsg: using TO-URI for destination\n"); #endif } if(dst.len == 0) { DBG("XJAB:xjab_manage_sipmsg: destination not found in SIP message\n"); goto error; } /** skip 'sip:' and parameters in destination address */ if(xj_extract_aor(&dst, 1)) { DBG("ERROR:xjab_manage_sipmsg: cannot get AoR for destination\n"); goto error; } #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xjab_manage_sipmsg: DESTINATION after correction [%.*s].\n", dst.len, dst.s); #endif prepare_job: //putting the SIP message parts in share memory to be accessible by workers jsmsg = (xj_sipmsg)shm_malloc(sizeof(t_xj_sipmsg)); memset(jsmsg, 0, sizeof(t_xj_sipmsg)); if(jsmsg == NULL) return -1; switch(type) { case XJ_SEND_MESSAGE: jsmsg->msg.len = body.len; if((jsmsg->msg.s = (char*)shm_malloc(jsmsg->msg.len+1)) == NULL) { shm_free(jsmsg); goto error; } strncpy(jsmsg->msg.s, body.s, jsmsg->msg.len); break; case XJ_GO_ONLINE: case XJ_GO_OFFLINE: dst.len = 0; dst.s = 0; case XJ_JOIN_JCONF: case XJ_EXIT_JCONF: jsmsg->msg.len = 0; jsmsg->msg.s = NULL; break; default: DBG("XJAB:xjab_manage_sipmsg: this SHOULD NOT appear\n"); shm_free(jsmsg); goto error; } if(dst.len>0) { jsmsg->to.len = dst.len; if((jsmsg->to.s = (char*)shm_malloc(jsmsg->to.len+1))==NULL) { if(type == XJ_SEND_MESSAGE) shm_free(jsmsg->msg.s); shm_free(jsmsg); goto error; } strncpy(jsmsg->to.s, dst.s, jsmsg->to.len); } else { jsmsg->to.len = 0; jsmsg->to.s = 0; } jsmsg->jkey = p; jsmsg->type = type; //jsmsg->jkey->hash = jkey.hash; DBG("XJAB:xjab_manage_sipmsg:%d: sending <%p> to worker through <%d>\n", getpid(), jsmsg, pipe); // sending the SHM pointer of SIP message to the worker fl = write(pipe, &jsmsg, sizeof(jsmsg)); if(fl != sizeof(jsmsg)) { DBG("XJAB:xjab_manage_sipmsg: error when writing to worker pipe!\n"); if(type == XJ_SEND_MESSAGE) shm_free(jsmsg->msg.s); shm_free(jsmsg->to.s); shm_free(jsmsg); goto error; } return 1; error: return -1; }
/* returns 0 if ok, -1 for errors */ int parse_msg(char* buf, unsigned int len, struct sip_msg* msg) { char *tmp; char* rest; struct msg_start *fl; int offset; hdr_flags_t flags; /* eat crlf from the beginning */ for (tmp=buf; (*tmp=='\n' || *tmp=='\r')&& (unsigned int)(tmp-buf) < len ; tmp++); offset=tmp-buf; fl=&(msg->first_line); rest=parse_first_line(tmp, len-offset, fl); offset+=rest-tmp; tmp=rest; switch(fl->type){ case SIP_INVALID: LM_DBG("invalid message\n"); /* if failed to parse the first line, we simply consider that the whole buffer was parsed, so that nothing is left to be parsed :) - this will do the trick and make "msg" struct acceptable for following parsing attempts */ msg->unparsed = msg->buf + msg->len; goto error; break; case SIP_REQUEST: LM_DBG("SIP Request:\n"); LM_DBG(" method: <%.*s>\n",fl->u.request.method.len, ZSW(fl->u.request.method.s)); LM_DBG(" uri: <%.*s>\n",fl->u.request.uri.len, ZSW(fl->u.request.uri.s)); LM_DBG(" version: <%.*s>\n",fl->u.request.version.len, ZSW(fl->u.request.version.s)); flags=HDR_VIA_F; break; case SIP_REPLY: LM_DBG("SIP Reply (status):\n"); LM_DBG(" version: <%.*s>\n",fl->u.reply.version.len, ZSW(fl->u.reply.version.s)); LM_DBG(" status: <%.*s>\n", fl->u.reply.status.len, ZSW(fl->u.reply.status.s)); LM_DBG(" reason: <%.*s>\n", fl->u.reply.reason.len, ZSW(fl->u.reply.reason.s)); flags=HDR_VIA_F; break; default: LM_DBG("unknown type %d\n",fl->type); goto error; } msg->unparsed=tmp; /*find first Via: */ if (parse_headers(msg, flags, 0)==-1) goto error; #ifdef EXTRA_DEBUG /* dump parsed data */ if (msg->via1){ LM_DBG(" first via: <%.*s/%.*s/%.*s> <%.*s:%.*s(%d)>", msg->via1->name.len, ZSW(msg->via1->name.s), msg->via1->version.len, ZSW(msg->via1->version.s), msg->via1->transport.len, ZSW(msg->via1->transport.s), msg->via1->host.len, ZSW(msg->via1->host.s), msg->via1->port_str.len, ZSW(msg->via1->port_str.s), msg->via1->port); if (msg->via1->params.s) LM_DBG(";<%.*s>", msg->via1->params.len, ZSW(msg->via1->params.s)); if (msg->via1->comment.s) LM_DBG(" <%.*s>", msg->via1->comment.len, ZSW(msg->via1->comment.s)); LM_DBG ("\n"); } if (msg->via2){ LM_DBG(" first via: <%.*s/%.*s/%.*s> <%.*s:%.*s(%d)>", msg->via2->name.len, ZSW(msg->via2->name.s), msg->via2->version.len, ZSW(msg->via2->version.s), msg->via2->transport.len, ZSW(msg->via2->transport.s), msg->via2->host.len, ZSW(msg->via2->host.s), msg->via2->port_str.len, ZSW(msg->via2->port_str.s), msg->via2->port); if (msg->via2->params.s) LM_DBG(";<%.*s>", msg->via2->params.len, ZSW(msg->via2->params.s)); if (msg->via2->comment.s) LM_DBG(" <%.*s>", msg->via2->comment.len, ZSW(msg->via2->comment.s)); LM_DBG ("\n"); } #endif #ifdef EXTRA_DEBUG LM_DBG("exiting\n"); #endif return 0; error: /* more debugging, msg->orig is/should be null terminated*/ LM_ERR("message=<%.*s>\n", (int)len, ZSW(buf)); return -1; }
/* removes first via & sends msg to the second * - mode param controls if modules sip response callbacks are executed */ static int do_forward_reply(struct sip_msg* msg, int mode) { char* new_buf; struct dest_info dst; unsigned int new_len; int r; #ifdef USE_TCP char* s; int len; #endif init_dest_info(&dst); new_buf=0; /*check if first via host = us */ if (check_via){ if (check_self(&msg->via1->host, msg->via1->port?msg->via1->port:SIP_PORT, msg->via1->proto)!=1){ LOG(L_NOTICE, "ERROR: forward_reply: host in first via!=me :" " %.*s:%d\n", msg->via1->host.len, msg->via1->host.s, msg->via1->port); /* send error msg back? */ goto error; } } /* check modules response_f functions */ if(likely(mode==0)) { for (r=0; r<mod_response_cbk_no; r++) if (mod_response_cbks[r](msg)==0) goto skip; } /* we have to forward the reply stateless, so we need second via -bogdan*/ if (parse_headers( msg, HDR_VIA2_F, 0 )==-1 || (msg->via2==0) || (msg->via2->error!=PARSE_OK)) { /* no second via => error */ LOG(L_DBG, "reply cannot be forwarded - no 2nd via\n"); goto error; } new_buf = build_res_buf_from_sip_res( msg, &new_len); if (!new_buf){ LOG(L_ERR, "ERROR: forward_reply: building failed\n"); goto error; } dst.proto=msg->via2->proto; SND_FLAGS_OR(&dst.send_flags, &msg->fwd_send_flags, &msg->rpl_send_flags); if (update_sock_struct_from_via( &dst.to, msg, msg->via2 )==-1) goto error; #ifdef USE_COMP dst.comp=msg->via2->comp_no; #endif #if defined USE_TCP || defined USE_SCTP if ( #ifdef USE_TCP dst.proto==PROTO_TCP || dst.proto==PROTO_WS #ifdef USE_TLS || dst.proto==PROTO_TLS || dst.proto==PROTO_WSS #endif #ifdef USE_SCTP || #endif /* USE_SCTP */ #endif /* USE_TCP */ #ifdef USE_SCTP dst.proto==PROTO_SCTP #endif /* USE_SCTP */ ){ /* find id in i param if it exists */ if (msg->via1->i && msg->via1->i->value.s){ s=msg->via1->i->value.s; len=msg->via1->i->value.len; DBG("forward_reply: i=%.*s\n",len, ZSW(s)); if (reverse_hex2int(s, len, (unsigned int*)&dst.id)<0){ LOG(L_ERR, "ERROR: forward_reply: bad via i param \"%.*s\"\n", len, ZSW(s)); dst.id=0; } } } #endif apply_force_send_socket(&dst, msg); if (msg_send(&dst, new_buf, new_len)<0) { STATS_RPL_FWD_DROP(); goto error; } /* call onsend_route */ if(dst.send_sock == NULL) { dst.send_sock=get_send_socket(msg, &dst.to, dst.proto); if (dst.send_sock==0){ LOG(L_ERR, "forward_reply: ERROR: cannot forward reply\n"); goto done; } } run_onsend(msg, &dst, new_buf, new_len); done: #ifdef STATS STATS_TX_RESPONSE( (msg->first_line.u.reply.statuscode/100) ); #endif DBG(" reply forwarded to %.*s:%d\n", msg->via2->host.len, msg->via2->host.s, (unsigned short) msg->via2->port); STATS_RPL_FWD_OK(); pkg_free(new_buf); skip: return 0; error: if (new_buf) pkg_free(new_buf); return -1; }
/*! \brief removes first via & sends msg to the second */ int forward_reply(struct sip_msg* msg) { char* new_buf; union sockaddr_union* to; unsigned int new_len; struct sr_module *mod; int proto; int id; /* used only by tcp*/ struct socket_info *send_sock; #ifdef USE_TCP char* s; int len; #endif to=0; id=0; new_buf=0; /*check if first via host = us */ if (check_via){ if (check_self(&msg->via1->host, msg->via1->port?msg->via1->port:SIP_PORT, msg->via1->proto)!=1){ LM_ERR("host in first via!=me : %.*s:%d\n", msg->via1->host.len, msg->via1->host.s, msg->via1->port); /* send error msg back? */ goto error; } } /* quick hack, slower for multiple modules*/ for (mod=modules;mod;mod=mod->next){ if ((mod->exports) && (mod->exports->response_f)){ LM_DBG("found module %s, passing reply to it\n", mod->exports->name); if (mod->exports->response_f(msg)==0) goto skip; } } /* if stateless fwd was disabled, we cannot have stateless replies here*/ if (sl_fwd_disabled) goto skip; /* we have to forward the reply stateless, so we need second via -bogdan*/ if (parse_headers( msg, HDR_VIA2_F, 0 )==-1 || (msg->via2==0) || (msg->via2->error!=PARSE_OK)) { /* no second via => error */ LM_ERR("no 2nd via found in reply from %s:%d <%.*s>\n", ip_addr2a(&msg->rcv.src_ip),msg->rcv.src_port, msg->len,msg->buf ); goto error; } to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("out of pkg memory\n"); goto error; } proto=msg->via2->proto; if (update_sock_struct_from_via( to, msg, msg->via2 )==-1) goto error; #ifdef USE_TCP if (proto==PROTO_TCP #ifdef USE_TLS || proto==PROTO_TLS #endif ){ /* find id in i param if it exists */ if (msg->via1->i&&msg->via1->i->value.s){ s=msg->via1->i->value.s; len=msg->via1->i->value.len; id=reverse_hex2int(s, len); } } #endif send_sock = get_send_socket(msg, to, proto); new_buf = build_res_buf_from_sip_res( msg, &new_len, send_sock); if (!new_buf){ LM_ERR("failed to build rpl from req failed\n"); goto error; } if (msg_send(send_sock, proto, to, id, new_buf, new_len)<0) { update_stat( drp_rpls, 1); goto error0; } update_stat( fwd_rpls, 1); /* * If no port is specified in the second via, then this * message output a wrong port number - zero. Despite that * the correct port is choosen in update_sock_struct_from_via, * as its visible with su_getport(to); . */ LM_DBG("reply forwarded to %.*s:%d\n", msg->via2->host.len, msg->via2->host.s, (unsigned short) msg->via2->port); pkg_free(new_buf); pkg_free(to); skip: return 0; error: update_stat( err_rpls, 1); error0: if (new_buf) pkg_free(new_buf); if (to) pkg_free(to); return -1; }
int select_anyheader(str* res, select_t* s, struct sip_msg* msg) { struct hdr_field *hf, *hf0; int hi; char c; struct hdr_field hdr; if(msg==NULL) { if (res!=NULL) return -1; /* "fixup" call, res & msg are NULL */ if (s->n <3) return -1; if (s->params[2].type==SEL_PARAM_STR) { /* replace _ with - (for P-xxx headers) */ for (hi=s->params[2].v.s.len-1; hi>0; hi--) if (s->params[2].v.s.s[hi]=='_') s->params[2].v.s.s[hi]='-'; /* if header name is parseable, parse it and set SEL_PARAM_DIV */ c=s->params[2].v.s.s[s->params[2].v.s.len]; s->params[2].v.s.s[s->params[2].v.s.len]=':'; if (parse_hname2(s->params[2].v.s.s,s->params[2].v.s.s+(s->params[2].v.s.len<3?4:s->params[2].v.s.len+1), &hdr)==0) { ERR("select_anyhdr:fixup_call:parse error\n"); return -1; } s->params[2].v.s.s[s->params[2].v.s.len]=c; if (hdr.type!=HDR_OTHER_T && hdr.type!=HDR_ERROR_T) { /* pkg_free(s->params[1].v.s.s); */ /* don't free it (the mem can leak only once at startup) * the parsed string can live inside larger string block * e.g. when xlog's select is parsed */ s->params[2].type = SEL_PARAM_DIV; s->params[2].v.i = hdr.type; } } return 1; } hf0 = NULL; /* extract header index if present */ if (s->param_offset[s->lvl+1] == 4) { if (s->params[3].type == SEL_PARAM_INT) { hi = s->params[3].v.i; } else { hi = -1; } } else { hi = 1; } /* we need to be sure we have parsed all headers */ if (!msg->eoh && (parse_headers(msg,HDR_EOH_F,0)==-1 || !msg->eoh)) { ERR("bad msg while parsing to EOH \n"); return -1; } for (hf=msg->headers; hf; hf=hf->next) { if(s->params[2].type==SEL_PARAM_DIV) { if (s->params[2].v.i!=hf->type) continue; } else if(s->params[2].type==SEL_PARAM_STR) { if (s->params[2].v.s.len!=hf->name.len) continue; if (strncasecmp(s->params[2].v.s.s, hf->name.s, hf->name.len)!=0) continue; } hf0 = hf; hi--; if (!hi) break; } if(hf0==NULL || hi>0) return 1; res->s = hf0->body.s; res->len = hf0->body.len; trim(res); return 0; }
void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) { struct sip_msg* msg= NULL; int lexpire= 0; unsigned int cseq; ua_pres_t* presentity= NULL, *hentity= NULL; struct to_body *pto = NULL, TO = {0}, *pfrom = NULL; int size= 0; unsigned int hash_code; int flag ; str record_route= {0, 0}; int rt; str contact; int initial_request = 0; int end_transaction = 1; if( ps->param== NULL || *ps->param== NULL ) { LM_ERR("null callback parameter\n"); return; } if (dbmode == PUA_DB_ONLY && pua_dbf.start_transaction) { if (pua_dbf.start_transaction(pua_db) < 0) { LM_ERR("in start_transaction\n"); goto error; } } LM_DBG("completed with status %d\n",ps->code) ; hentity= (ua_pres_t*)(*ps->param); hash_code= core_hash(hentity->pres_uri,hentity->watcher_uri, HASH_SIZE); flag= hentity->flag; if(hentity->flag & XMPP_INITIAL_SUBS) hentity->flag= XMPP_SUBSCRIBE; /* get dialog information from reply message: callid, to_tag, from_tag */ msg= ps->rpl; if(msg == NULL) { LM_ERR("no reply message found\n "); goto error; } if(msg== FAKED_REPLY) { struct hdr_field *callid = NULL, *from = NULL; struct to_body FROM = {0}; callid = (struct hdr_field *) pkg_malloc(sizeof(struct hdr_field)); if (callid == NULL) { LM_ERR("Out of memory\n"); goto faked_error; } memset(callid, 0, sizeof(struct hdr_field)); get_hdr_field(t->callid.s, t->callid.s + t->callid.len, callid); hentity->call_id = callid->body; from = (struct hdr_field *) pkg_malloc(sizeof(struct hdr_field)); if (from == NULL) { LM_ERR("Out of memory\n"); goto faked_error; } memset(from, 0, sizeof(struct hdr_field)); get_hdr_field(t->from.s, t->from.s + t->from.len, from); parse_to(from->body.s, from->body.s + from->body.len + 1, &FROM); if(FROM.uri.len <= 0) { LM_ERR("'From' header NOT parsed\n"); goto faked_error; } hentity->call_id = callid->body; hentity->from_tag = (&FROM)->tag_value; hentity->to_tag.s = NULL; hentity->to_tag.len = 0; find_and_delete_dialog(hentity, hash_code); faked_error: if (callid) pkg_free(callid); free_to_params(&FROM); if (from) pkg_free(from); goto done; } if ( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("when parsing headers\n"); goto error; } if(ps->rpl->expires && msg->expires->body.len > 0) { if (!msg->expires->parsed && (parse_expires(msg->expires) < 0)) { LM_ERR("cannot parse Expires header\n"); goto error; } lexpire = ((exp_body_t*)msg->expires->parsed)->val; LM_DBG("lexpire= %d\n", lexpire); } /*if initial request */ if(hentity->call_id.s== NULL) { initial_request = 1; if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot parse callid header\n"); goto error; } if (!msg->from || !msg->from->body.s) { LM_ERR("cannot find 'from' header!\n"); goto error; } if (msg->from->parsed == NULL) { if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); goto error; } } pfrom = (struct to_body*)msg->from->parsed; if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); goto error; } hentity->call_id= msg->callid->body; hentity->from_tag= pfrom->tag_value; if(ps->code >= 300 || lexpire == 0) { hentity->to_tag.s = NULL; hentity->to_tag.len = 0; find_and_delete_dialog(hentity, hash_code); goto done; } if( msg->to==NULL || msg->to->body.s==NULL) { LM_ERR("cannot parse TO header\n"); goto error; } if(msg->to->parsed != NULL) { pto = (struct to_body*)msg->to->parsed; LM_DBG("'To' header ALREADY PARSED: <%.*s>\n",pto->uri.len,pto->uri.s); } else { parse_to(msg->to->body.s,msg->to->body.s + msg->to->body.len + 1, &TO); if(TO.uri.len <= 0) { LM_ERR("'To' header NOT parsed\n"); goto error; } pto = &TO; } if( pto->tag_value.s ==NULL || pto->tag_value.len == 0) { LM_ERR("no to tag value present\n"); goto error; } hentity->to_tag= pto->tag_value; } if(ps->code >= 300 ) { /* if an error code and a stored dialog delete it and try to send a subscription with type= INSERT_TYPE, else return*/ subs_info_t subs; hentity->to_tag.s = NULL; hentity->to_tag.len = 0; find_and_delete_dialog(hentity, hash_code); if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction) { if (pua_dbf.end_transaction(pua_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } end_transaction = 0; /* Redirect if the response 3XX */ memset(&subs, 0, sizeof(subs_info_t)); subs.pres_uri= hentity->pres_uri; subs.watcher_uri= hentity->watcher_uri; subs.contact= &hentity->contact; if(hentity->remote_contact.s) subs.remote_target= &hentity->remote_contact; if(hentity->desired_expires== 0) subs.expires= -1; else if(hentity->desired_expires< (int)time(NULL)) subs.expires= 0; else subs.expires= hentity->desired_expires- (int)time(NULL)+ 3; subs.flag= INSERT_TYPE; subs.source_flag= flag; subs.event= hentity->event; subs.id= hentity->id; subs.outbound_proxy= hentity->outbound_proxy; subs.extra_headers= hentity->extra_headers; subs.cb_param= hentity->cb_param; if(send_subscribe(&subs)< 0) { LM_ERR("when trying to send SUBSCRIBE\n"); goto error; } goto done; } if(lexpire== 0 ) { LM_DBG("lexpire= 0 Delete from hash table"); find_and_delete_dialog(hentity, hash_code); goto done; } /* extract the contact */ if(msg->contact== NULL || msg->contact->body.s== NULL) { LM_ERR("no contact header found"); goto error; } if( parse_contact(msg->contact) <0 ) { LM_ERR(" cannot parse contact header\n"); goto error; } if(msg->contact->parsed == NULL) { LM_ERR("cannot parse contact header\n"); goto error; } contact = ((contact_body_t* )msg->contact->parsed)->contacts->uri; if( msg->cseq==NULL || msg->cseq->body.s==NULL) { LM_ERR("cannot parse cseq header\n"); goto error; } if( str2int( &(get_cseq(msg)->number), &cseq)< 0) { LM_ERR("while converting str to int\n"); goto error; } if(initial_request == 0) { hentity->cseq = cseq; find_and_update_dialog(hentity, hash_code, lexpire, &contact); goto done; } /*process record route and add it to a string*/ if (msg->record_route!=NULL) { rt = print_rr_body(msg->record_route, &record_route, 1, 0); if(rt != 0) { LM_ERR("parsing record route [%d]\n", rt); record_route.s=NULL; record_route.len=0; } } size= sizeof(ua_pres_t)+ 2*sizeof(str)+( pto->uri.len+ pfrom->uri.len+ pto->tag_value.len+ pfrom->tag_value.len +msg->callid->body.len+ record_route.len+ hentity->contact.len+ hentity->id.len )*sizeof(char); if(hentity->extra_headers) size+= sizeof(str)+ hentity->extra_headers->len*sizeof(char); presentity= (ua_pres_t*)shm_malloc(size); if(presentity== NULL) { LM_ERR("no more share memory\n"); goto error; } memset(presentity, 0, size); size= sizeof(ua_pres_t); presentity->pres_uri= (str*)( (char*)presentity+ size); size+= sizeof(str); presentity->pres_uri->s= (char*)presentity+ size; memcpy(presentity->pres_uri->s, pto->uri.s, pto->uri.len); presentity->pres_uri->len= pto->uri.len; size+= pto->uri.len; presentity->watcher_uri= (str*)( (char*)presentity+ size); size+= sizeof(str); presentity->watcher_uri->s= (char*)presentity+ size; memcpy(presentity->watcher_uri->s, pfrom->uri.s, pfrom->uri.len); presentity->watcher_uri->len= pfrom->uri.len; size+= pfrom->uri.len; presentity->call_id.s= (char*)presentity + size; memcpy(presentity->call_id.s,msg->callid->body.s, msg->callid->body.len); presentity->call_id.len= msg->callid->body.len; size+= presentity->call_id.len; presentity->to_tag.s= (char*)presentity + size; memcpy(presentity->to_tag.s,pto->tag_value.s, pto->tag_value.len); presentity->to_tag.len= pto->tag_value.len; size+= pto->tag_value.len; presentity->from_tag.s= (char*)presentity + size; memcpy(presentity->from_tag.s,pfrom->tag_value.s, pfrom->tag_value.len); presentity->from_tag.len= pfrom->tag_value.len; size+= pfrom->tag_value.len; if(record_route.len && record_route.s) { presentity->record_route.s= (char*)presentity + size; memcpy(presentity->record_route.s, record_route.s, record_route.len); presentity->record_route.len= record_route.len; size+= record_route.len; pkg_free(record_route.s); } presentity->contact.s= (char*)presentity + size; memcpy(presentity->contact.s, hentity->contact.s, hentity->contact.len); presentity->contact.len= hentity->contact.len; size+= hentity->contact.len; if(hentity->id.s) { presentity->id.s=(char*)presentity+ size; memcpy(presentity->id.s, hentity->id.s, hentity->id.len); presentity->id.len= hentity->id.len; size+= presentity->id.len; } if(hentity->extra_headers) { presentity->extra_headers= (str*)((char*)presentity+ size); size+= sizeof(str); presentity->extra_headers->s=(char*)presentity+ size; memcpy(presentity->extra_headers->s, hentity->extra_headers->s, hentity->extra_headers->len); presentity->extra_headers->len= hentity->extra_headers->len; size+= hentity->extra_headers->len; } /* write the remote contact filed */ presentity->remote_contact.s= (char*)shm_malloc(contact.len* sizeof(char)); if(presentity->remote_contact.s==NULL) { ERR_MEM(SHARE_MEM); } memcpy(presentity->remote_contact.s, contact.s, contact.len); presentity->remote_contact.len= contact.len; presentity->event|= hentity->event; presentity->flag= hentity->flag; presentity->etag.s= NULL; presentity->cseq= cseq; presentity->desired_expires= hentity->desired_expires; presentity->expires= lexpire+ (int)time(NULL); if(BLA_SUBSCRIBE & presentity->flag) { LM_DBG("BLA_SUBSCRIBE FLAG inserted\n"); } LM_DBG("record for subscribe from %.*s to %.*s inserted in datatbase\n", presentity->watcher_uri->len, presentity->watcher_uri->s, presentity->pres_uri->len, presentity->pres_uri->s); if (dbmode==PUA_DB_ONLY) { if (convert_temporary_dialog_puadb(presentity) < 0) { LM_ERR("Could not convert temporary dialog into a dialog\n"); goto error; } } else { if (convert_temporary_dialog(presentity) < 0) { LM_ERR("Could not convert temporary dialog into a dialog\n"); goto error; } } done: if(hentity->ua_flag == REQ_OTHER) { hentity->flag= flag; run_pua_callbacks( hentity, msg); } if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction && end_transaction) { if (pua_dbf.end_transaction(pua_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } goto end; error: if (presentity) { if (presentity->remote_contact.s) shm_free(presentity->remote_contact.s); shm_free(presentity); } if(record_route.s) pkg_free(record_route.s); if (dbmode == PUA_DB_ONLY && pua_dbf.abort_transaction) { if (pua_dbf.abort_transaction(pua_db) < 0) LM_ERR("in abort_transaction\n"); } end: if(hentity) { shm_free(hentity); hentity= NULL; } free_to_params(&TO); return; }
/* authentication service return value: -1: error -2: message out of time -3: Date header field does not match validity period of cert 1: success */ static int authservice_(struct sip_msg* msg, char* str1, char* str2) { time_t dateHFValue = -1; int retval = 0; char dateHF[MAX_TIME] = "\0"; long dateDelta = -1; /* parse all headers */ if (parse_headers(msg, HDR_EOH_F, 0)!=0) { LM_ERR("failed to parse headers\n"); return -1; } retval = getDate(dateHF, &dateHFValue, msg); switch(retval) { case 1: /* Date header field exists */ dateDelta = getDateDelta(dateHFValue); if((dateDelta >= MAXDATEDELTA_AUTH) || dateDelta < 0) { return -2; } break; case 0: /* Date header field does not exist */ if(!addDate(dateHF, &dateHFValue, msg)) { LM_ERR("addDate failed\n"); return -1; } break; case -1: LM_ERR("error reading Date header field\n"); return -1; break; } if(!authCertMatchesDate(dateHFValue)) { return -3; } /* is content len hdr found ? if(msg->content_length) { if(!addContentLength(msg)) { LM_ERR("addContentLength failed\n"); return -1; } }*/ if(!addIdentity(dateHF, msg)) { LM_ERR("addIdentity failed\n"); return -1; } if(!addIdentityInfo(msg)) { LM_ERR("addIdentityInfo failed\n"); return -1; } return 1; }
static void __dialog_cbtest(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) { str tag; LM_DBG("dialog callback received, from=%.*s, to=%.*s\n", dlg->from_uri.len, dlg->from_uri.s, dlg->to_uri.len, dlg->to_uri.s); if (dlg->tag[0].len && dlg->tag[0].s ) { LM_DBG("dialog callback: tag[0] = %.*s\n", dlg->tag[0].len, dlg->tag[0].s); } if (dlg->tag[0].len && dlg->tag[1].s ) { LM_DBG("dialog callback: tag[1] = %.*s\n", dlg->tag[1].len, dlg->tag[1].s); } if (_params->msg && _params->msg!=FAKED_REPLY && type != DLGCB_DESTROY) { /* get to tag*/ if ( !_params->msg->to) { /* to header not defined, parse to header */ LM_DBG("to header not defined, parse to header\n"); if (parse_headers(_params->msg, HDR_TO_F,0)<0) { /* parser error */ LM_ERR("parsing of to-header failed\n"); tag.s = 0; tag.len = 0; } else if (!_params->msg->to) { /* to header still not defined */ LM_ERR("no to although to-header is parsed: bad reply " "or missing TO hdr :-/\n"); tag.s = 0; tag.len = 0; } else tag = get_to(_params->msg)->tag_value; } else { tag = get_to(_params->msg)->tag_value; if (tag.s==0 || tag.len==0) { LM_DBG("missing TAG param in TO hdr :-/\n"); tag.s = 0; tag.len = 0; } } if (tag.s) { LM_DBG("dialog callback: _params->msg->to->parsed->tag_value " "= %.*s\n", tag.len, tag.s); } } switch (type) { case DLGCB_FAILED: LM_DBG("dialog callback type 'DLGCB_FAILED' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_CONFIRMED: LM_DBG("dialog callback type 'DLGCB_CONFIRMED' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_REQ_WITHIN: LM_DBG("dialog callback type 'DLGCB_REQ_WITHIN' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_TERMINATED: LM_DBG("dialog callback type 'DLGCB_TERMINATED' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_EXPIRED: LM_DBG("dialog callback type 'DLGCB_EXPIRED' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_EARLY: LM_DBG("dialog callback type 'DLGCB_EARLY' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_RESPONSE_FWDED: LM_DBG("dialog callback type 'DLGCB_RESPONSE_FWDED' received, " "from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_RESPONSE_WITHIN: LM_DBG("dialog callback type 'DLGCB_RESPONSE_WITHIN' received, " "from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_MI_CONTEXT: LM_DBG("dialog callback type 'DLGCB_MI_CONTEXT' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_DESTROY: LM_DBG("dialog callback type 'DLGCB_DESTROY' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; default: LM_DBG("dialog callback type 'unknown' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); } }
void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) { struct sip_msg* msg= NULL; int lexpire= 0; unsigned int cseq; ua_pres_t* presentity= NULL, *hentity= NULL; struct to_body *pto= NULL, *pfrom = NULL; int size= 0; int flag ; str record_route= {0, 0}; int rt; str contact; int initial_request = 0; if(ps==NULL || ps->param== NULL || *ps->param== NULL ) { LM_ERR("null callback parameter\n"); return; } LM_DBG("completed with status %d\n",ps->code) ; hentity= (ua_pres_t*)(*ps->param); flag= hentity->flag; if(hentity->flag & XMPP_INITIAL_SUBS) hentity->flag= XMPP_SUBSCRIBE; /* get dialog information from reply message: callid, to_tag, from_tag */ msg= ps->rpl; if(msg == NULL) { LM_ERR("no reply message found\n "); goto error; } if(msg== FAKED_REPLY) { /* delete record from hash_table and call registered functions */ if(hentity->call_id.s== NULL) /* if a new requets failed-> do nothing*/ { LM_DBG("initial Subscribe request failed\n"); goto done; } lock_get(&HashT->p_records[hentity->hash_index].lock); presentity = get_htable_safe(hentity->hash_index, hentity->local_index); if(presentity) { delete_htable_safe(presentity, hentity->hash_index); lock_release(&HashT->p_records[hentity->hash_index].lock); } lock_release(&HashT->p_records[hentity->hash_index].lock); goto done; } if ( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("when parsing headers\n"); goto done; } /*if initial request */ if(hentity->call_id.s== NULL) { initial_request = 1; if(ps->code>= 300) { LM_DBG("initial Subscribe request failed\n"); goto done; } if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot parse callid header\n"); goto done; } if (!msg->from || !msg->from->body.s) { LM_ERR("cannot find 'from' header!\n"); goto done; } if (msg->from->parsed == NULL) { if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); goto done; } } pfrom = (struct to_body*)msg->from->parsed; if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); goto done; } if( msg->to==NULL || msg->to->body.s==NULL) { LM_ERR("cannot parse TO header\n"); goto done; } pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("failed to parse TO header\n"); goto done; } if( pto->tag_value.s ==NULL || pto->tag_value.len == 0) { LM_ERR("no to tag value present\n"); goto done; } hentity->call_id= msg->callid->body; hentity->to_tag= pto->tag_value; hentity->from_tag= pfrom->tag_value; } /* extract the other necesary information for inserting a new record */ if(ps->rpl->expires && msg->expires->body.len > 0) { if (!msg->expires->parsed && (parse_expires(msg->expires) < 0)) { LM_ERR("cannot parse Expires header\n"); goto done; } lexpire = ((exp_body_t*)msg->expires->parsed)->val; LM_DBG("lexpire= %d\n", lexpire); } if(ps->code >= 300 ) { /* if an error code and a stored dialog delete it and try to send a subscription with type= INSERT_TYPE, else return*/ if(!initial_request) { subs_info_t subs; lock_get(&HashT->p_records[hentity->hash_index].lock); presentity = get_htable_safe(hentity->hash_index, hentity->local_index); if(presentity) { hentity->event= presentity->event; delete_htable_safe(presentity, hentity->hash_index); lock_release(&HashT->p_records[hentity->hash_index].lock); } lock_release(&HashT->p_records[hentity->hash_index].lock); memset(&subs, 0, sizeof(subs_info_t)); subs.pres_uri= hentity->pres_uri; subs.to_uri = hentity->to_uri; subs.watcher_uri= hentity->watcher_uri; subs.contact= &hentity->contact; if(hentity->remote_contact.s) subs.remote_target= &hentity->remote_contact; if(hentity->desired_expires== 0) subs.expires= -1; else if(hentity->desired_expires< (int)time(NULL)) subs.expires= 0; else subs.expires= hentity->desired_expires- (int)time(NULL)+ 3; subs.flag= INSERT_TYPE; subs.source_flag= flag; subs.event= hentity->event; subs.id= hentity->id; subs.outbound_proxy= hentity->outbound_proxy; subs.extra_headers= &hentity->extra_headers; subs.cb_param= hentity->cb_param; if(send_subscribe(&subs)< 0) { LM_ERR("when trying to send SUBSCRIBE\n"); goto done; } } goto done; } /*if a 2XX reply handle the two cases- an existing dialog and a new one*/ /* extract the contact */ if(msg->contact== NULL || msg->contact->body.s== NULL) { LM_ERR("no contact header found"); goto error; } if( parse_contact(msg->contact) <0 ) { LM_ERR(" cannot parse contact header\n"); goto error; } if(msg->contact->parsed == NULL) { LM_ERR("cannot parse contact header\n"); goto error; } contact = ((contact_body_t* )msg->contact->parsed)->contacts->uri; if(!initial_request) { /* do not delete the dialog - allow Notifies to be recognized as * inside a known dialog */ if (lexpire == 0) lexpire = 5; LM_DBG("*** Update expires\n"); update_htable(hentity->hash_index, hentity->local_index, lexpire, NULL, &contact); goto done; } /* if a new dialog -> insert */ if(lexpire== 0) { LM_DBG("expires= 0: no not insert\n"); goto done; } if( msg->cseq==NULL || msg->cseq->body.s==NULL) { LM_ERR("cannot parse cseq header\n"); goto done; } if( str2int( &(get_cseq(msg)->number), &cseq)< 0) { LM_ERR("while converting str to int\n"); goto done; } /*process record route and add it to a string*/ if (msg->record_route!=NULL) { rt = print_rr_body(msg->record_route, &record_route, 1, 0); if(rt != 0) { LM_ERR("parsing record route [%d]\n", rt); record_route.s=NULL; record_route.len=0; } } size= sizeof(ua_pres_t)+ 2*sizeof(str)+(hentity->pres_uri->len+ pto->uri.len+ pfrom->uri.len+ pto->tag_value.len+ pfrom->tag_value.len +msg->callid->body.len+ record_route.len+ hentity->contact.len+ hentity->id.len )*sizeof(char); presentity= (ua_pres_t*)shm_malloc(size); if(presentity== NULL) { LM_ERR("no more share memory\n"); if(record_route.s) pkg_free(record_route.s); goto done; } memset(presentity, 0, size); size= sizeof(ua_pres_t); presentity->pres_uri= (str*)( (char*)presentity+ size); size+= sizeof(str); presentity->pres_uri->s= (char*)presentity+ size; memcpy(presentity->pres_uri->s, hentity->pres_uri->s, hentity->pres_uri->len); presentity->pres_uri->len= hentity->pres_uri->len; size+= hentity->pres_uri->len; presentity->to_uri.s= (char*)presentity+ size; memcpy(presentity->to_uri.s, pto->uri.s, pto->uri.len); presentity->to_uri.len= pto->uri.len; size+= pto->uri.len; presentity->watcher_uri= (str*)( (char*)presentity+ size); size+= sizeof(str); presentity->watcher_uri->s= (char*)presentity+ size; memcpy(presentity->watcher_uri->s, pfrom->uri.s, pfrom->uri.len); presentity->watcher_uri->len= pfrom->uri.len; size+= pfrom->uri.len; presentity->call_id.s= (char*)presentity + size; memcpy(presentity->call_id.s,msg->callid->body.s, msg->callid->body.len); presentity->call_id.len= msg->callid->body.len; size+= presentity->call_id.len; presentity->to_tag.s= (char*)presentity + size; memcpy(presentity->to_tag.s,pto->tag_value.s, pto->tag_value.len); presentity->to_tag.len= pto->tag_value.len; size+= pto->tag_value.len; presentity->from_tag.s= (char*)presentity + size; memcpy(presentity->from_tag.s,pfrom->tag_value.s, pfrom->tag_value.len); presentity->from_tag.len= pfrom->tag_value.len; size+= pfrom->tag_value.len; if(record_route.len && record_route.s) { presentity->record_route.s= (char*)presentity + size; memcpy(presentity->record_route.s, record_route.s, record_route.len); presentity->record_route.len= record_route.len; size+= record_route.len; pkg_free(record_route.s); } presentity->contact.s= (char*)presentity + size; memcpy(presentity->contact.s, hentity->contact.s, hentity->contact.len); presentity->contact.len= hentity->contact.len; size+= hentity->contact.len; if(hentity->id.s) { presentity->id.s=(char*)presentity+ size; memcpy(presentity->id.s, hentity->id.s, hentity->id.len); presentity->id.len= hentity->id.len; size+= presentity->id.len; } if(hentity->extra_headers.s && hentity->extra_headers.len) { presentity->extra_headers.s= (char*)shm_malloc(hentity->extra_headers.len* sizeof(char)); if(presentity->extra_headers.s== NULL) { ERR_MEM(SHARE_MEM); } memcpy(presentity->extra_headers.s, hentity->extra_headers.s, hentity->extra_headers.len); presentity->extra_headers.len= hentity->extra_headers.len; } /* write the remote contact filed */ presentity->remote_contact.s= (char*)shm_malloc(contact.len* sizeof(char)); if(presentity->remote_contact.s== NULL) { ERR_MEM(SHARE_MEM); } memcpy(presentity->remote_contact.s, contact.s, contact.len); presentity->remote_contact.len= contact.len; presentity->event|= hentity->event; presentity->flag= hentity->flag; presentity->etag.s= NULL; presentity->cseq= cseq; presentity->desired_expires= hentity->desired_expires; presentity->expires= lexpire+ (int)time(NULL); if(BLA_SUBSCRIBE & presentity->flag) { LM_DBG("BLA_SUBSCRIBE FLAG inserted\n"); } LM_DBG("record for subscribe from %.*s to %.*s inserted in datatbase\n", presentity->watcher_uri->len, presentity->watcher_uri->s, presentity->pres_uri->len, presentity->pres_uri->s); insert_htable(presentity); done: if(hentity->ua_flag == REQ_OTHER) { hentity->flag= flag; run_pua_callbacks( hentity, msg); } error: if(hentity) { if(presentity->extra_headers.s) shm_free(presentity->extra_headers.s); if(presentity->remote_contact.s) shm_free(presentity->remote_contact.s); shm_free(hentity); hentity= NULL; } return; }
/* * Add the sdp carried by the given SIP message into the qos context. */ void add_sdp(qos_ctx_t *qos_ctx, unsigned int dir, struct sip_msg *_m, unsigned int role, unsigned int other_role) { qos_sdp_t *qos_sdp; sdp_session_cell_t *recv_session; str *cseq_number, *cseq_method; int cseq_method_id, sdp_match; if ( (!_m->cseq && parse_headers(_m,HDR_CSEQ_F,0)<0) || !_m->cseq || !_m->cseq->parsed) { LM_ERR("bad sip message or missing CSeq hdr\n"); return; } cseq_number = &((get_cseq(_m))->number); cseq_method = &((get_cseq(_m))->method); cseq_method_id = (get_cseq(_m))->method_id; LM_DBG("cseq=`%.*s' `%.*s' and dir=%d\n", cseq_number->len, cseq_number->s, cseq_method->len, cseq_method->s, dir); /* Let's iterate through all the received sessions */ recv_session = ((sdp_info_t*)_m->body)->sessions; while(recv_session) { qos_sdp = NULL; sdp_match = find_qos_sdp(qos_ctx, dir, other_role, cseq_number, cseq_method_id, recv_session, _m, &qos_sdp); switch (sdp_match) { case NO_INVITE_REQ_MATCH: if (0!=add_pending_sdp_session( qos_ctx, dir, cseq_number, cseq_method, cseq_method_id, role, N_INVITE_200OK, recv_session, _m)) { LM_ERR("Unable to add new sdp session\n"); goto error; } break; case NO_INVITE_RESP_MATCH: if (0!=add_pending_sdp_session( qos_ctx, dir, cseq_number, cseq_method, cseq_method_id, role, N_200OK_ACK, recv_session, _m)) { LM_ERR("Unable to add new sdp session\n"); goto error; } break; case ERROR_MATCH: case NO_ACK_REQ_MATCH: case NO_UPDATE_REQ_MATCH: case NO_UPDATE_RESP_MATCH: LM_ERR("error match: %d\n", sdp_match); break; case PENDING_MATCH: LM_DBG("we have a pending match: %p\n", qos_sdp); /* Let's save the received session */ qos_sdp->sdp_session[role] = clone_sdp_session_cell(recv_session); if (qos_sdp->sdp_session[role] == NULL) { LM_ERR("PENDING_MATCH:oom: Unable to add new sdp session\n"); return; } /* Negotiation completed, need to move the established SDP into the negotiated_sdp */ /* removing qos_sdp from qos_ctx->pending_sdp list */ unlink_pending_qos_sdp(qos_ctx, qos_sdp); /* inserting qos_sdp into the qos_ctx->negotiated_sdp list */ link_negotiated_qos_sdp_and_run_cb(qos_ctx, qos_sdp, role, _m); break; case NEGOTIATED_MATCH: LM_DBG("we have a negotiated match: %p\n", qos_sdp); /* some sanity checks */ if (qos_sdp->sdp_session[role]) { free_cloned_sdp_session(qos_sdp->sdp_session[role]); } else { LM_ERR("missing sdp_session for %s\n", (role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE"); } /* Let's save the received session */ qos_sdp->sdp_session[role] = clone_sdp_session_cell(recv_session); if (qos_sdp->sdp_session[role] == NULL) { LM_ERR("NEGOTIATED_MATCH:oom: Unable to add new sdp session\n"); return; } LM_DBG("run_qos_callbacks(QOSCB_UPDATE_SDP, qos_ctx=%p, qos_sdp=%p, role=%d, _m=%p)\n", qos_ctx, qos_sdp, role, _m); run_qos_callbacks(QOSCB_UPDATE_SDP, qos_ctx, qos_sdp, role, _m); break; default: LM_CRIT("Undefined return code from find_qos_sdp(): %d\n", sdp_match); } recv_session = recv_session->next; } return; error: shm_free(qos_sdp); LM_DBG("free qos_sdp: %p\n", qos_sdp); return; }
/** * Force Service routes (upon request) */ int force_service_routes(struct sip_msg* _m, udomain_t* _d) { struct hdr_field *it; int i; str new_route_header; struct lump* lmp = NULL; char * buf; pcontact_t * c = getContactP(_m, _d); char srcip[20]; str received_host; // Contact not found => not following service-routes if (c == NULL) return -1; /* we need to be sure we have seen all HFs */ parse_headers(_m, HDR_EOH_F, 0); /* Save current buffer */ buf = _m->buf; // Delete old Route headers: if (_m->route) { for (it = _m->route; it; it = it->next) { if (it->type == HDR_ROUTE_T) { if ((lmp = del_lump(_m, it->name.s - buf, it->len, HDR_ROUTE_T)) == 0) { LM_ERR("del_lump failed \n"); return -1; } } } } /* Reset dst_uri if previously set either by loose route or manually */ if (_m->dst_uri.s && _m->dst_uri.len) { pkg_free(_m->dst_uri.s); _m->dst_uri.s = NULL; _m->dst_uri.len = 0; } received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); received_host.s = srcip; /* Lock this record while working with the data: */ ul.lock_udomain(_d, &c->aor, &received_host, _m->rcv.src_port); if (c->num_service_routes > 0) { /* Create anchor for new Route-Header: */ lmp = anchor_lump(_m, _m->headers->name.s - buf,0,0); if (lmp == 0) { LM_ERR("Failed to get anchor lump\n"); goto error; } /* Calculate the length: */ new_route_header.len = route_start.len + route_end.len + (c->num_service_routes-1) * route_sep.len; for(i=0; i< c->num_service_routes; i++) new_route_header.len+=c->service_routes[i].len; /* Allocate the memory for this new header: */ new_route_header.s = pkg_malloc(new_route_header.len); if (!new_route_header.s) { LM_ERR("Error allocating %d bytes\n", new_route_header.len); goto error; } /* Construct new header */ new_route_header.len = 0; STR_APPEND(new_route_header, route_start); for(i=0; i < c->num_service_routes; i++) { if (i) STR_APPEND(new_route_header, route_sep); STR_APPEND(new_route_header, c->service_routes[i]); } STR_APPEND(new_route_header, route_end); LM_DBG("Setting route header to <%.*s> \n", new_route_header.len, new_route_header.s); if ((lmp = insert_new_lump_after(lmp, new_route_header.s, new_route_header.len, HDR_ROUTE_T)) == 0) { LM_ERR("Error inserting new route set\n"); pkg_free(new_route_header.s); goto error; } LM_DBG("Setting dst_uri to <%.*s> \n", c->service_routes[0].len, c->service_routes[0].s); if (set_dst_uri(_m, &c->service_routes[0]) !=0 ) { LM_ERR("Error setting new dst uri\n"); goto error; } } /* Unlock domain */ ul.unlock_udomain(_d, &c->aor, &received_host, _m->rcv.src_port); return 1; error: /* Unlock domain */ ul.unlock_udomain(_d, &c->aor, &received_host, _m->rcv.src_port); return -1; }
int ws_handle_handshake(struct sip_msg *msg) { str key = {0, 0}, headers = {0, 0}, reply_key = {0, 0}, origin = {0, 0}; unsigned char sha1[SHA_DIGEST_LENGTH]; unsigned int hdr_flags = 0, sub_protocol = 0; int version = 0; struct hdr_field *hdr = msg->headers; struct tcp_connection *con; ws_connection_t *wsc; /* Make sure that the connection is closed after the response _and_ the existing connection (from the request) is reused for the response. The close flag will be unset later if the handshake is successful. */ msg->rpl_send_flags.f |= SND_F_CON_CLOSE; msg->rpl_send_flags.f |= SND_F_FORCE_CON_REUSE; if (cfg_get(websocket, ws_cfg, enabled) == 0) { LM_INFO("disabled: bouncing handshake\n"); ws_send_reply(msg, 503, &str_status_service_unavailable, NULL); return 0; } /* Retrieve TCP/TLS connection */ if ((con = tcpconn_get(msg->rcv.proto_reserved1, 0, 0, 0, 0)) == NULL) { LM_ERR("retrieving connection\n"); ws_send_reply(msg, 500, &str_status_internal_server_error, NULL); return 0; } if (con->type != PROTO_TCP && con->type != PROTO_TLS) { LM_ERR("unsupported transport: %d", con->type); goto end; } if (parse_headers(msg, HDR_EOH_F, 0) < 0) { LM_ERR("error parsing headers\n"); ws_send_reply(msg, 500, &str_status_internal_server_error, NULL); goto end; } /* Process HTTP headers */ while (hdr != NULL) { /* Decode and validate Connection */ if (cmp_hdrname_strzn(&hdr->name, str_hdr_connection.s, str_hdr_connection.len) == 0) { strlower(&hdr->body); if (str_search(&hdr->body, &str_upgrade) != NULL) { LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, hdr->body.len, hdr->body.s); hdr_flags |= CONNECTION; } } /* Decode and validate Upgrade */ else if (cmp_hdrname_strzn(&hdr->name, str_hdr_upgrade.s, str_hdr_upgrade.len) == 0) { strlower(&hdr->body); if (str_search(&hdr->body, &str_websocket) != NULL) { LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, hdr->body.len, hdr->body.s); hdr_flags |= UPGRADE; } } /* Decode and validate Sec-WebSocket-Key */ else if (cmp_hdrname_strzn(&hdr->name, str_hdr_sec_websocket_key.s, str_hdr_sec_websocket_key.len) == 0) { if (hdr_flags & SEC_WEBSOCKET_KEY) { LM_WARN("%.*s found multiple times\n", hdr->name.len, hdr->name.s); ws_send_reply(msg, 400, &str_status_bad_request, NULL); goto end; } LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, hdr->body.len, hdr->body.s); key = hdr->body; hdr_flags |= SEC_WEBSOCKET_KEY; } /* Decode and validate Sec-WebSocket-Protocol */ else if (cmp_hdrname_strzn(&hdr->name, str_hdr_sec_websocket_protocol.s, str_hdr_sec_websocket_protocol.len) == 0) { strlower(&hdr->body); if (str_search(&hdr->body, &str_sip) != NULL) { LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, hdr->body.len, hdr->body.s); hdr_flags |= SEC_WEBSOCKET_PROTOCOL; sub_protocol |= SUB_PROTOCOL_SIP; } if (str_search(&hdr->body, &str_msrp) != NULL) { LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, hdr->body.len, hdr->body.s); hdr_flags |= SEC_WEBSOCKET_PROTOCOL; sub_protocol |= SUB_PROTOCOL_MSRP; } } /* Decode and validate Sec-WebSocket-Version */ else if (cmp_hdrname_strzn(&hdr->name, str_hdr_sec_websocket_version.s, str_hdr_sec_websocket_version.len) == 0) { if (hdr_flags & SEC_WEBSOCKET_VERSION) { LM_WARN("%.*s found multiple times\n", hdr->name.len, hdr->name.s); ws_send_reply(msg, 400, &str_status_bad_request, NULL); goto end; } str2sint(&hdr->body, &version); if (version != WS_VERSION) { LM_WARN("Unsupported protocol version %.*s\n", hdr->body.len, hdr->body.s); headers.s = headers_buf; headers.len = snprintf(headers.s, HDR_BUF_LEN, "%.*s: %d\r\n", str_hdr_sec_websocket_version.len, str_hdr_sec_websocket_version.s, WS_VERSION); ws_send_reply(msg, 426, &str_status_upgrade_required, &headers); goto end; } LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, hdr->body.len, hdr->body.s); hdr_flags |= SEC_WEBSOCKET_VERSION; } /* Decode Origin */ else if (cmp_hdrname_strzn(&hdr->name, str_hdr_origin.s, str_hdr_origin.len) == 0) { if (hdr_flags & ORIGIN) { LM_WARN("%.*s found multiple times\n", hdr->name.len, hdr->name.s); ws_send_reply(msg, 400, &str_status_bad_request, NULL); goto end; } LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, hdr->body.len, hdr->body.s); origin = hdr->body; hdr_flags |= ORIGIN; } hdr = hdr->next; } /* Final check that all required headers/values were found */ sub_protocol &= ws_sub_protocols; if ((hdr_flags & REQUIRED_HEADERS) != REQUIRED_HEADERS || sub_protocol == 0) { LM_WARN("required headers not present\n"); headers.s = headers_buf; headers.len = 0; if (ws_sub_protocols & SUB_PROTOCOL_SIP) headers.len += snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n", str_hdr_sec_websocket_protocol.len, str_hdr_sec_websocket_protocol.s, str_sip.len, str_sip.s); if (ws_sub_protocols & SUB_PROTOCOL_MSRP) headers.len += snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n", str_hdr_sec_websocket_protocol.len, str_hdr_sec_websocket_protocol.s, str_msrp.len, str_msrp.s); headers.len += snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, "%.*s: %d\r\n", str_hdr_sec_websocket_version.len, str_hdr_sec_websocket_version.s, WS_VERSION); ws_send_reply(msg, 400, &str_status_bad_request, &headers); goto end; } /* Construct reply_key */ reply_key.s = (char *) pkg_malloc( (key.len + str_ws_guid.len) * sizeof(char)); if (reply_key.s == NULL) { LM_ERR("allocating pkg memory\n"); ws_send_reply(msg, 500, &str_status_internal_server_error, NULL); goto end; } memcpy(reply_key.s, key.s, key.len); memcpy(reply_key.s + key.len, str_ws_guid.s, str_ws_guid.len); reply_key.len = key.len + str_ws_guid.len; SHA1((const unsigned char *) reply_key.s, reply_key.len, sha1); pkg_free(reply_key.s); reply_key.s = key_buf; reply_key.len = base64_enc(sha1, SHA_DIGEST_LENGTH, (unsigned char *) reply_key.s, base64_enc_len(SHA_DIGEST_LENGTH)); /* Add the connection to the WebSocket connection table */ wsconn_add(msg->rcv, sub_protocol); /* Make sure Kamailio core sends future messages on this connection directly to this module */ if (con->type == PROTO_TLS) con->type = con->rcv.proto = PROTO_WSS; else con->type = con->rcv.proto = PROTO_WS; /* Now Kamailio is ready to receive WebSocket frames build and send a 101 reply */ headers.s = headers_buf; headers.len = 0; if (ws_cors_mode == CORS_MODE_ANY) headers.len += snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, "%.*s: *\r\n", str_hdr_access_control_allow_origin.len, str_hdr_access_control_allow_origin.s); else if (ws_cors_mode == CORS_MODE_ORIGIN && origin.len > 0) headers.len += snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n", str_hdr_access_control_allow_origin.len, str_hdr_access_control_allow_origin.s, origin.len, origin.s); if (sub_protocol & SUB_PROTOCOL_SIP) headers.len += snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n", str_hdr_sec_websocket_protocol.len, str_hdr_sec_websocket_protocol.s, str_sip.len, str_sip.s); else if (sub_protocol & SUB_PROTOCOL_MSRP) headers.len += snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n", str_hdr_sec_websocket_protocol.len, str_hdr_sec_websocket_protocol.s, str_msrp.len, str_msrp.s); headers.len += snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n" "%.*s: %.*s\r\n" "%.*s: %.*s\r\n", str_hdr_upgrade.len, str_hdr_upgrade.s, str_websocket.len, str_websocket.s, str_hdr_connection.len, str_hdr_connection.s, str_upgrade.len, str_upgrade.s, str_hdr_sec_websocket_accept.len, str_hdr_sec_websocket_accept.s, reply_key.len, reply_key.s); msg->rpl_send_flags.f &= ~SND_F_CON_CLOSE; if (ws_send_reply(msg, 101, &str_status_switching_protocols, &headers) < 0) { if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) != NULL) { wsconn_rm(wsc, WSCONN_EVENTROUTE_NO); wsconn_put(wsc); } goto end; } else { if (sub_protocol & SUB_PROTOCOL_SIP) update_stat(ws_sip_successful_handshakes, 1); else if (sub_protocol & SUB_PROTOCOL_MSRP) update_stat(ws_msrp_successful_handshakes, 1); } tcpconn_put(con); return 1; end: if (con) tcpconn_put(con); return 0; }
boost::optional<http_request_header> http_header_parser::parse_request_header(std::string::const_iterator begin, std::string::const_iterator end) { auto iter = begin; auto tmp = iter; for (;iter != end && *iter != ' ' && *iter != '\r'; ++iter) ; if (iter == tmp || iter == end || *iter != ' ') return nullptr; http_request_header header; header._method = std::string(tmp, iter); tmp = ++iter; for (;iter != end && *iter != ' ' && *iter != '\r'; ++iter) ; if (iter == tmp || iter == end || *iter != ' ') return nullptr; auto request_uri = std::string(tmp, iter); if (header.method() == "CONNECT") { boost::regex regex("(.+?):(\\d+)"); boost::match_results<std::string::iterator> match_results; if (!boost::regex_match(request_uri.begin(), request_uri.end(), match_results, regex)) { return nullptr; } header._host = match_results[1]; try { header._port = static_cast<unsigned short>(std::stoul(std::string(match_results[2]))); } catch (const std::exception&) { return nullptr; } } else { boost::regex regex("(.+?)://(.+?)(:(\\d+))?(/.*)"); boost::match_results<std::string::iterator> match_results; if (!boost::regex_match(request_uri.begin(), request_uri.end(), match_results, regex)) { return nullptr; } header._scheme = match_results[1]; header._host = match_results[2]; if (match_results[4].matched) { try { header._port = static_cast<unsigned short>(std::stoul(std::string(match_results[4]))); } catch (const std::exception&) { return nullptr; } } header._path_and_query = match_results[5]; } tmp = ++iter; for (;iter != end && *iter != '\r'; ++iter) ; // HTTP/x.y if (iter == end || std::distance(tmp, iter) < 6 || !std::equal(tmp, tmp + 5, "HTTP/")) return nullptr; header._http_version = std::string(tmp + 5, iter); ++iter; if (iter == end || *iter != '\n') return nullptr; ++iter; try { header._headers_map = parse_headers(iter, end); } catch (const std::exception&) { return nullptr; } return header; }
/* atomic "new_tran" construct; it returns: <0 on error +1 if a request did not match a transaction - it that was an ack, the calling function shall forward statelessly - otherwise it means, a new transaction was introduced and the calling function shall reply/relay/whatever_appropriate 0 on retransmission */ int t_newtran( struct sip_msg* p_msg ) { int lret, my_err; int canceled; /* is T still up-to-date ? */ DBG("DEBUG: t_newtran: msg id=%d , global msg id=%d ," " T on entrance=%p\n",p_msg->id,global_msg_id,T); if ( T && T!=T_UNDEFINED ) { /* ERROR message moved to w_t_newtran */ DBG("DEBUG: t_newtran: " "transaction already in process %p\n", T ); return E_SCRIPT; } global_msg_id = p_msg->id; T = T_UNDEFINED; /* first of all, parse everything -- we will store in shared memory and need to have all headers ready for generating potential replies later; parsing later on demand is not an option since the request will be in shmem and applying parse_headers to it would intermix shmem with pkg_mem */ if (parse_headers(p_msg, HDR_EOH_F, 0 )) { LOG(L_ERR, "ERROR: t_newtran: parse_headers failed\n"); return E_BAD_REQ; } if ((p_msg->parsed_flag & HDR_EOH_F)!=HDR_EOH_F) { LOG(L_ERR, "ERROR: t_newtran: EoH not parsed\n"); return E_OUT_OF_MEM; } /* t_lookup_requests attempts to find the transaction; it also calls check_transaction_quadruple -> it is safe to assume we have from/callid/cseq/to */ lret = t_lookup_request( p_msg, 1 /* leave locked if not found */, &canceled ); /* on error, pass the error in the stack ... nothing is locked yet if 0 is returned */ if (lret==0) return E_BAD_TUPEL; /* transaction found, it's a retransmission */ if (lret>0) { if (p_msg->REQ_METHOD==METHOD_ACK) { t_release_transaction(T); } else { t_retransmit_reply(T); } /* things are done -- return from script */ return 0; } /* from now on, be careful -- hash table is locked */ if (lret==-2) { /* was it an e2e ACK ? if so, trigger a callback */ /* no callbacks? complete quickly */ if ( !has_tran_tmcbs(t_ack,TMCB_E2EACK_IN) ) { UNLOCK_HASH(p_msg->hash_index); return 1; } REF_UNSAFE(t_ack); UNLOCK_HASH(p_msg->hash_index); /* we don't call from within REPLY_LOCK -- that introduces * a race condition; however, it is so unlikely and the * impact is so small (callback called multiple times of * multiple ACK/200s received in parallel), that we do not * better waste time in locks */ if (unmatched_totag(t_ack, p_msg)) { run_trans_callbacks( TMCB_E2EACK_IN , t_ack, p_msg, 0, -p_msg->REQ_METHOD ); } UNREF(t_ack); return 1; } /* transaction not found, it's a new request (lret<0, lret!=-2); establish a new transaction ... */ if (p_msg->REQ_METHOD==METHOD_ACK) { /* ... unless it is in ACK */ my_err=1; goto new_err; } my_err=new_t(p_msg); if (my_err<0) { LOG(L_ERR, "ERROR: t_newtran: new_t failed\n"); goto new_err; } if (canceled) T->flags|=T_CANCELED; /* mark it for future ref. */ UNLOCK_HASH(p_msg->hash_index); /* now, when the transaction state exists, check if there is a meaningful Via and calculate it; better do it now than later: state is established so that subsequent retransmissions will be absorbed and will not possibly block during Via DNS resolution; doing it later would only burn more CPU as if there is an error, we cannot relay later whatever comes out of the the transaction */ if (!init_rb( &T->uas.response, p_msg)) { LOG(L_ERR, "ERROR: t_newtran: unresolvable via1\n"); put_on_wait( T ); t_unref(p_msg); return E_BAD_VIA; } return 1; new_err: UNLOCK_HASH(p_msg->hash_index); return my_err; }
int ac_cancel(as_p the_as,unsigned char processor_id,unsigned int flags,char *action,int len) { unsigned int ret,cancelled_hashIdx,cancelled_label,i; struct sip_msg *my_msg; struct as_uac_param *the_param; struct cell* t_invite; int k,retval,uac_id; str headers,body; body.s=headers.s=NULL; my_msg=NULL; the_param=NULL; i=k=0; net2hostL(uac_id,action,k); net2hostL(cancelled_hashIdx,action,k); net2hostL(cancelled_label,action,k); if(!(headers.s=pkg_malloc(MAX_HEADER))){ LM_ERR("Out of Memory!!"); goto error; } headers.len=0; if(!(my_msg=pkg_malloc(sizeof(struct sip_msg)))){ LM_ERR("out of memory!\n"); goto error; } memset(my_msg,0,sizeof(struct sip_msg)); my_msg->buf=action+k; my_msg->len=len-k; LM_DBG("Action UAC Message: uac_id:%d processor_id=%d, message:[%.*s]\n", uac_id,processor_id,len-4,&action[4]); if(parse_msg(action+k,len-k,my_msg)<0){ LM_ERR("parsing sip_msg"); goto error; } if(my_msg->first_line.type==SIP_REPLY){ LM_ERR("trying to create a UAC with a SIP response!!\n"); goto error; } if(parse_headers(my_msg,HDR_EOH_F,0)==-1){ LM_ERR("parsing headers\n"); goto error; } if(0>(headers.len=extract_allowed_headers(my_msg,1,-1,HDR_CONTENTLENGTH_F|HDR_ROUTE_F|HDR_TO_F|HDR_FROM_F|HDR_CALLID_F|HDR_CSEQ_F,headers.s,MAX_HEADER))) { LM_ERR("Unable to extract allowed headers!!\n"); goto error; } if(flags & SPIRAL_FLAG){ memcpy(headers.s+headers.len,SPIRAL_HDR CRLF,SPIRAL_HDR_LEN + CRLF_LEN); headers.len+=SPIRAL_HDR_LEN+CRLF_LEN; /*headers.s[headers.len]=0; fake_uri.s=pkg_malloc(200); fake_uri.len=print_local_uri(the_as,processor_id,fake_uri.s,200); if(fake_uri.len<0){ SLM_ERR("printing local uri\n"); goto error; } my_dlg->hooks.next_hop=&fake_uri;*/ } headers.s[headers.len]=0; /*let's get the body*/ i=(unsigned int)get_content_length(my_msg); if(i!=0){ if(!(body.s=pkg_malloc(i))){ LM_ERR("Out of Memory!"); goto error; } memcpy(body.s,get_body(my_msg),i); body.len=i; LM_DBG("Trying to construct a Sip Request with: body:%d[%s]" " headers:%d[%s]\n", body.len,body.s,headers.len,headers.s); }else{ body.s=NULL; body.len=0; } if(!(the_param=shm_malloc(sizeof(struct as_uac_param)))){ LM_ERR("no more share memory\n"); goto error; } if(seas_f.tmb.t_lookup_ident(&t_invite,cancelled_hashIdx,cancelled_label)<0){ LM_ERR("failed to t_lookup_ident hash_idx=%d," "label=%d\n", cancelled_hashIdx,cancelled_label); goto error; } seas_f.tmb.unref_cell(t_invite); the_param->who=my_as; the_param->uac_id=uac_id; the_param->processor_id=processor_id; the_param->destroy_cb_set=0; /* registers TMCB_RESPONSE_IN|TMCB_LOCAL_COMPLETED tm callbacks */ ret=seas_f.tmb.t_cancel_uac(&headers,&body,cancelled_hashIdx,cancelled_label,uac_cb,(void*)the_param); if (ret == 0) { LM_ERR( "t_cancel_uac failed\n"); as_action_fail_resp(uac_id,SE_CANCEL,SE_CANCEL_MSG,SE_CANCEL_MSG_LEN); goto error; }else{ the_param->label=ret; } seas_f.tmb.unref_cell(t_invite); retval=0; goto exit; error: retval = -1; if(the_param) shm_free(the_param); exit: if(headers.s) pkg_free(headers.s); if(body.s) pkg_free(body.s); if(my_msg){ if(my_msg->headers) free_hdr_field_lst(my_msg->headers); pkg_free(my_msg); } return retval; }
/* Determine current transaction * * Found Not Found Error (e.g. parsing) * Return Value 1 0 -1 * T ptr 0 T_UNDEFINED */ int t_check( struct sip_msg* p_msg , int *param_branch ) { int local_branch; int canceled; /* is T still up-to-date ? */ DBG("DEBUG: t_check: msg id=%d global id=%d T start=%p\n", p_msg->id,global_msg_id,T); if ( p_msg->id != global_msg_id || T==T_UNDEFINED ) { global_msg_id = p_msg->id; T = T_UNDEFINED; /* transaction lookup */ if ( p_msg->first_line.type==SIP_REQUEST ) { /* force parsing all the needed headers*/ if (parse_headers(p_msg, HDR_EOH_F, 0 )==-1) { LOG(L_ERR, "ERROR: t_check: parsing error\n"); return -1; } /* in case, we act as UAS for INVITE and reply with 200, * we will need to run dialog-matching for subsequent * ACK, for which we need From-tag; We also need from-tag * in case people want to have proxied e2e ACKs accounted */ if (p_msg->REQ_METHOD==METHOD_INVITE && parse_from_header(p_msg)==-1) { LOG(L_ERR, "ERROR: t_check: from parsing failed\n"); return -1; } t_lookup_request( p_msg , 0 /* unlock before returning */, &canceled); } else { /* we need Via for branch and Cseq method to distinguish replies with the same branch/cseqNr (CANCEL) and we need all the WWW/Proxy Authenticate headers for 401 & 407 replies */ if (tm_aggregate_auth && (p_msg->REPLY_STATUS==401 || p_msg->REPLY_STATUS==407)){ if (parse_headers(p_msg, HDR_EOH_F,0)==-1){ LOG(L_WARN, "WARNING: the reply cannot be " "completely parsed\n"); /* try to continue, via1 & cseq are checked below */ } }else if ( parse_headers(p_msg, HDR_VIA1_F|HDR_CSEQ_F, 0 )==-1) { LOG(L_ERR, "ERROR: reply cannot be parsed\n"); return -1; } if ((p_msg->via1==0) || (p_msg->cseq==0)){ LOG(L_ERR, "ERROR: reply doesn't have a via or cseq header\n"); return -1; } /* if that is an INVITE, we will also need to-tag for later ACK matching */ if ( get_cseq(p_msg)->method.len==INVITE_LEN && memcmp( get_cseq(p_msg)->method.s, INVITE, INVITE_LEN )==0 ) { if (parse_headers(p_msg, HDR_TO_F, 0)==-1 || !p_msg->to) { LOG(L_ERR, "ERROR: INVITE reply cannot be parsed\n"); return -1; } } t_reply_matching( p_msg , param_branch!=0?param_branch:&local_branch ); } #ifdef EXTRA_DEBUG if ( T && T!=T_UNDEFINED && T->flags & (T_IN_AGONY)) { LOG( L_ERR, "ERROR: transaction %p scheduled for deletion " "and called from t_check (flags=%x)\n", T, T->flags); abort(); } #endif DBG("DEBUG: t_check: msg id=%d global id=%d T end=%p\n", p_msg->id,global_msg_id,T); } else { if (T) DBG("DEBUG: t_check: T already found!\n"); else DBG("DEBUG: t_check: T previously sought and not found\n"); } return T ? (T==T_UNDEFINED ? -1 : 1 ) : 0; }
/*Actions are composed as follows: * (the action length and type as always= 5 bytes) * 4:uac_id * * int request(str* method, str* req_uri, str* to, str* from, str* headers, str* body, transaction_cb c, void* cp) * TODO performance speedup: instead of using * dynamically allocated memory for headers,body,totag,reason and my_msg * use static buffers. * */ int ac_uac_req(as_p the_as,unsigned char processor_id,unsigned int flags,char *action,int len) { unsigned int cseq; char err_buf[MAX_REASON_LEN]; struct sip_msg *my_msg; struct to_body *fb,*tb; struct cseq_body *cseqb; struct as_uac_param *the_param; dlg_t *my_dlg; int k,retval,uac_id,sip_error,ret,err_ret; long clen; str headers,body,fake_uri; uac_req_t uac_r; headers.s=body.s=fake_uri.s=NULL; my_dlg=NULL; my_msg=NULL; the_param=NULL; k=clen=0; net2hostL(uac_id,action,k); if(!(headers.s=pkg_malloc(MAX_HEADER))){ LM_ERR("Out of Memory!!"); goto error; } headers.len=0; LM_DBG("Action UAC Message: uac_id:%d processor_id=%d\n",uac_id,processor_id); if (!(my_msg = parse_ac_msg(HDR_EOH_F,action+k,len-k))) { LM_ERR("out of memory!\n"); goto error; } if(my_msg->first_line.type==SIP_REPLY){ LM_ERR("trying to create a UAC with a SIP response!!\n"); goto error; } if(parse_headers(my_msg,HDR_EOH_F,0)==-1){ LM_ERR("ERROR:seas:ac_uac_req:parsing headers\n"); goto error; } if(parse_from_header(my_msg)<0){ LM_ERR("parsing from header ! \n"); goto error; } if(check_transaction_quadruple(my_msg)==0){ as_action_fail_resp(uac_id,SE_UAC,"Headers missing (to,from,call-id,cseq)?",0); LM_ERR("Headers missing (to,from,call-id,cseq)?"); goto error; } if(!(get_from(my_msg)) || !(get_from(my_msg)->tag_value.s) || !(get_from(my_msg)->tag_value.len)){ as_action_fail_resp(uac_id,SE_UAC,"From tag missing",0); LM_ERR("From tag missing"); goto error; } fb=my_msg->from->parsed; tb=my_msg->to->parsed; cseqb=my_msg->cseq->parsed; if(0!=(str2int(&cseqb->number,&cseq))){ LM_DBG("unable to parse CSeq\n"); goto error; } if(my_msg->first_line.u.request.method_value != METHOD_ACK && my_msg->first_line.u.request.method_value != METHOD_CANCEL) { /** we trick req_within */ cseq--; } if(seas_f.tmb.new_dlg_uac(&(my_msg->callid->body),&(fb->tag_value),cseq,\ &(fb->uri),&(tb->uri),&my_dlg) < 0) { as_action_fail_resp(uac_id,SE_UAC,"Error creating new dialog",0); LM_ERR("Error while creating new dialog\n"); goto error; } if(seas_f.tmb.dlg_add_extra(my_dlg,&(fb->display),&(tb->display)) < 0 ) { as_action_fail_resp(uac_id,SE_UAC, "Error adding the display names to the new dialog",0); LM_ERR("failed to add display names to the new dialog\n"); goto error; } if(tb->tag_value.s && tb->tag_value.len) shm_str_dup(&my_dlg->id.rem_tag,&tb->tag_value); /**Awful hack: to be able to set our own CSeq, from_tag and call-ID we have * to use req_within instead of req_outside (it sets it's own CSeq,Call-ID * and ftag), so we have to simulate that the dialog is already in completed * state so... */ server_signature=0; my_dlg->state = DLG_CONFIRMED; if(0>(headers.len=extract_allowed_headers(my_msg,1,-1,HDR_CONTENTLENGTH_F|HDR_ROUTE_F|HDR_TO_F|HDR_FROM_F|HDR_CALLID_F|HDR_CSEQ_F,headers.s,MAX_HEADER))) { LM_ERR("Unable to extract allowed headers!!\n"); goto error; } headers.s[headers.len]=0; /*let's get the body*/ if(my_msg->content_length) clen=(long)get_content_length(my_msg); if(clen!=0){ if(!(body.s=pkg_malloc(clen))){ LM_ERR("Out of Memory!"); goto error; } memcpy(body.s,get_body(my_msg),clen); body.len=clen; body.s[clen]=0; LM_DBG("Trying to construct a Sip Request with: body:%d[%.*s] headers:%d[%.*s]\n",\ body.len,body.len,body.s,headers.len,headers.len,headers.s); /*t_reply_with_body un-ref-counts the transaction, so dont use it anymore*/ }else{ body.s=NULL; body.len=0; } /*Now... create the UAC !! * it would be great to know the hash_index and the label that have been assigned * to our newly created cell, but t_uac does not leave any way for us to know... * only that when that transaction transitions its state (ie. a response is received, * a timeout is reached, etc...) the callback will be called with the given parameter. * * So the only way we have to know who we are, is passing as a parameter a structure with * 2 pointers: one to the app_server and the other, the identifier of the UAC (uac_id). * */ if(!(the_param=shm_malloc(sizeof(struct as_uac_param)))){ LM_ERR("out of shared memory\n"); goto error; } the_param->who=my_as; the_param->uac_id=uac_id; the_param->processor_id=processor_id; the_param->destroy_cb_set=0; shm_str_dup(&my_dlg->rem_target,&my_msg->first_line.u.request.uri); if (my_msg->route) { if (parse_rr(my_msg->route) < 0) { LM_ERR( "Error while parsing Route body\n"); goto error; } /* TODO route_set should be a shm copy of my_msg->route->parsed */ my_dlg->route_set=(rr_t*)my_msg->route->parsed; /** this SHOULD be: shm_duplicate_rr(&my_dlg->route_set,my_msg->route->parsed); * but it will last more... */ } calculate_hooks(my_dlg); if(flags & SPIRAL_FLAG){ memcpy(headers.s+headers.len,SPIRAL_HDR CRLF,SPIRAL_HDR_LEN + CRLF_LEN); headers.len+=SPIRAL_HDR_LEN+CRLF_LEN; headers.s[headers.len]=0; fake_uri.s=pkg_malloc(200); fake_uri.len=print_local_uri(the_as,processor_id,fake_uri.s,200); if(fake_uri.len<0){ LM_ERR("printing local uri\n"); goto error; } my_dlg->hooks.next_hop=&fake_uri; } /* Kamailio and OpenSIPs seem to have diverged quite a bit on flags and events notified to UACs. Let's see if kamailio gets it right by now, if not this is a TODO: check PASS_PROVISIONAL my_dlg->T_flags=T_NO_AUTO_ACK|T_PASS_PROVISIONAL_FLAG ; this is the same as (TMCB_DONT_ACK|TMCB_LOCAL_RESPONSE_OUT) in Kamailio */ set_uac_req(&uac_r, &(my_msg->first_line.u.request.method), &headers, &body, my_dlg,TMCB_DONT_ACK|TMCB_LOCAL_RESPONSE_OUT, uac_cb, (void*)the_param); ret=seas_f.tmb.t_request_within(&uac_r); /** now undo all the fakes we have put in my_dlg*/ /*because my_dlg->route_set should be shm but we fake it (its pkg_mem)*/ my_dlg->route_set=(rr_t *)0; if (ret < 0) { err_ret = err2reason_phrase(ret,&sip_error,err_buf, sizeof(err_buf), "SEAS/UAC"); LM_ERR("failed to send the [%.*s] request\n",uac_r.method->len,uac_r.method->s); LM_ERR("Error on request_within %s\n",err_buf ); if(err_ret > 0) { as_action_fail_resp(uac_id,ret,err_buf,0); }else{ as_action_fail_resp(uac_id,E_UNSPEC,"500 SEAS/UAC error",0); } goto error; } retval=0; goto exit; error: retval = -1; if(the_param) shm_free(the_param); exit: seas_f.tmb.free_dlg(my_dlg); if(headers.s) pkg_free(headers.s); if(body.s) pkg_free(body.s); if(fake_uri.s) pkg_free(fake_uri.s); if(my_msg){ if(my_msg->headers) free_hdr_field_lst(my_msg->headers); pkg_free(my_msg); } return retval; }
/* * determines the permission of the call * return values: * -1: deny * 1: allow */ static int check_routing(struct sip_msg* msg, int idx) { struct hdr_field *from; int len, q; static char from_str[EXPRESSION_LENGTH+1]; static char ruri_str[EXPRESSION_LENGTH+1]; char* uri_str; str branch; int br_idx; /* turn off control, allow any routing */ if ((!allow[idx].rules) && (!deny[idx].rules)) { LM_DBG("no rules => allow any routing\n"); return 1; } /* looking for FROM HF */ if ((!msg->from) && (parse_headers(msg, HDR_FROM_F, 0) == -1)) { LM_ERR("failed to parse message\n"); return -1; } if (!msg->from) { LM_ERR("FROM header field not found\n"); return -1; } /* we must call parse_from_header explicitly */ if ((!(msg->from)->parsed) && (parse_from_header(msg) < 0)) { LM_ERR("failed to parse From body\n"); return -1; } from = msg->from; len = ((struct to_body*)from->parsed)->uri.len; if (len > EXPRESSION_LENGTH) { LM_ERR("From header field is too long: %d chars\n", len); return -1; } strncpy(from_str, ((struct to_body*)from->parsed)->uri.s, len); from_str[len] = '\0'; /* looking for request URI */ if (parse_sip_msg_uri(msg) < 0) { LM_ERR("uri parsing failed\n"); return -1; } len = msg->parsed_uri.user.len + msg->parsed_uri.host.len + 5; if (len > EXPRESSION_LENGTH) { LM_ERR("Request URI is too long: %d chars\n", len); return -1; } strcpy(ruri_str, "sip:"); memcpy(ruri_str + 4, msg->parsed_uri.user.s, msg->parsed_uri.user.len); ruri_str[msg->parsed_uri.user.len + 4] = '@'; memcpy(ruri_str + msg->parsed_uri.user.len + 5, msg->parsed_uri.host.s, msg->parsed_uri.host.len); ruri_str[len] = '\0'; LM_DBG("looking for From: %s Request-URI: %s\n", from_str, ruri_str); /* rule exists in allow file */ if (search_rule(allow[idx].rules, from_str, ruri_str)) { if (check_all_branches) goto check_branches; LM_DBG("allow rule found => routing is allowed\n"); return 1; } /* rule exists in deny file */ if (search_rule(deny[idx].rules, from_str, ruri_str)) { LM_DBG("deny rule found => routing is denied\n"); return -1; } if (!check_all_branches) { LM_DBG("neither allow nor deny rule found => routing is allowed\n"); return 1; } check_branches: for( br_idx=0 ; (branch.s=get_branch(br_idx,&branch.len,&q,0,0,0,0,0,0,0))!=0 ; br_idx++ ) { uri_str = get_plain_uri(&branch); if (!uri_str) { LM_ERR("failed to extract plain URI\n"); return -1; } LM_DBG("looking for From: %s Branch: %s\n", from_str, uri_str); if (search_rule(allow[idx].rules, from_str, uri_str)) { continue; } if (search_rule(deny[idx].rules, from_str, uri_str)) { LM_DBG("deny rule found for one of branches => routing" "is denied\n"); return -1; } } LM_DBG("check of branches passed => routing is allowed\n"); return 1; }
/** * Updates dialog on reply message * @param msg - the SIP message * @param d - dialog to modify * @returns 1 on success or 0 on error */ int update_dialog_on_reply(struct sip_msg *msg, s_dialog *d) { struct hdr_field *h_req; struct hdr_field *h=0; int res=0; time_t t_time=0; str ses_exp = {0,0}; str refresher = {0,0}; str new_ses_exp = {0,0}; str new_ext = {0,0}; ses_exp = cscf_get_session_expires_body(msg, &h); t_time = cscf_get_session_expires(ses_exp, &refresher); if (!t_time) //i.e not session-expires header in response { if (!d->uac_supp_timer || !d->lr_session_expires) { d->expires = d_act_time()+scscf_dialogs_expiration_time; } else// uac supports timer, but no session-expires header found in response { new_ses_exp.len = 11/*int value*/ + str_se.len+s_refresher.len+8; new_ses_exp.s = pkg_malloc(new_ses_exp.len+1); if (!new_ses_exp.s) { LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ses_exp.len); goto error; } new_ses_exp.len = snprintf(new_ses_exp.s, new_ses_exp.len, "%.*s %d; %.*suac\r\n",str_se.len, str_se.s, (int)d->lr_session_expires ,s_refresher.len, s_refresher.s); cscf_add_header(msg, &new_ses_exp, HDR_OTHER_T); if (!requires_extension(msg, &str_ext_timer)) //must have require timer extenstion { /* walk through all Require headers to find first require header*/ res = parse_headers(msg, HDR_EOH_F, 0); if (res == -1) { ERR("Error while parsing headers (%d)\n", res); return 0; /* what to return here ? */ } h_req = msg->require; while (h_req) { if (h_req->type == HDR_REQUIRE_T) { if (h_req->body.s[new_ext.len-1]=='\n') { new_ext.len = str_require.len + 1/* */+h_req->body.len + 7;/*, timer*/ new_ext.s = pkg_malloc(new_ext.len); if (!new_ext.s) { LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ext.len); goto error; } new_ext.len = snprintf(new_ext.s, str_require.len, "%.*s %.*s, timer\r\n", str_require.len, str_require.s, h_req->body.len-2, h_req->body.s); } else { new_ext.len = str_require.len + 1/*space*/ + h_req->body.len + 9;/*, timer\r\n*/ new_ext.s = pkg_malloc(new_ext.len); if (!new_ext.s) { LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ext.len); goto error; } new_ext.len = snprintf(new_ext.s, str_require.len, "%.*s %.*s, timer\r\n", str_require.len, str_require.s, h_req->body.len, h_req->body.s); } cscf_del_header(msg, h_req); cscf_add_header(msg, &new_ext, HDR_REQUIRE_T); break; } h_req = h_req->next; } } } } return 1; error: if (new_ses_exp.s) pkg_free(new_ses_exp.s); if (new_ext.s) pkg_free(new_ext.s); return 0; }