static int cpl_run_script(struct sip_msg* msg, char* str1, char* str2) { str buf_msg; if (resp_buf) { pkg_free(resp_buf); resp_buf = 0; } buf_msg.s = build_req_buf_from_sip_req( msg, (unsigned int*)&(buf_msg.len), sock_info, msg->rcv.proto); if (!buf_msg.s || !buf_msg.len) { LOG(L_ERR,"ERROR: cpl_run_script: cannot build buffer from request\n"); goto error; } resp_code =executeCPLForSIPMessage( buf_msg.s, buf_msg.len, cpl_server, cpl_port, &resp_buf, (int*) &resp_len); pkg_free(buf_msg.s); if (!resp_code) { LOG( L_ERR , "ERROR : cpl_run_script : cpl running failed!\n"); goto error; } DBG("DEBUG : cpl_run_script : response received -> %d\n",resp_code); return 1; error: return -1; }
/* be aware and use it *all* the time between pre_* and post_* functions! */ static inline char *print_uac_request(struct sip_msg *i_req, unsigned int *len, struct socket_info *send_sock, enum sip_protos proto ) { char *buf, *shbuf; shbuf=0; /* build the shm buffer now */ buf=build_req_buf_from_sip_req( i_req, len, send_sock, proto ); if (!buf) { LOG(L_ERR, "ERROR:tm:print_uac_request: no pkg_mem\n"); ser_error=E_OUT_OF_MEM; goto error01; } shbuf=(char *)shm_malloc(*len); if (!shbuf) { ser_error=E_OUT_OF_MEM; LOG(L_ERR, "ERROR:tm:print_uac_request: no shmem\n"); goto error02; } memcpy( shbuf, buf, *len ); error02: pkg_free( buf ); error01: return shbuf; }
char *update_msg(sip_msg_t *msg, unsigned int *len) { struct dest_info dst; init_dest_info(&dst); dst.proto = PROTO_UDP; return build_req_buf_from_sip_req(msg, len, &dst, BUILD_NO_LOCAL_VIA | BUILD_NO_VIA1_UPDATE); }
char *print_uac_request( struct cell *t, struct sip_msg *i_req, int branch, str *uri, unsigned int *len, struct socket_info *send_sock, enum sip_protos proto ) { char *buf, *shbuf; shbuf=0; /* ... we calculate branch ... */ if (!t_calc_branch(t, branch, i_req->add_to_branch_s, &i_req->add_to_branch_len )) { LOG(L_ERR, "ERROR: print_uac_request: branch computation failed\n"); goto error01; } /* ... update uri ... */ i_req->new_uri=*uri; /* run the specific callbacks for this transaction */ run_trans_callbacks( TMCB_REQUEST_FWDED , t, i_req, 0, -i_req->REQ_METHOD); /* ... and build it now */ buf=build_req_buf_from_sip_req( i_req, len, send_sock, proto ); #ifdef DBG_MSG_QA if (buf[*len-1]==0) { LOG(L_ERR, "ERROR: print_uac_request: sanity check failed\n"); abort(); } #endif if (!buf) { LOG(L_ERR, "ERROR: print_uac_request: no pkg_mem\n"); ser_error=E_OUT_OF_MEM; goto error01; } /* clean Via's we created now -- they would accumulate for other branches and for shmem i_req they would mix up shmem with pkg_mem */ free_via_clen_lump(&i_req->add_rm); shbuf=(char *)shm_malloc(*len); if (!shbuf) { ser_error=E_OUT_OF_MEM; LOG(L_ERR, "ERROR: print_uac_request: no shmem\n"); goto error02; } memcpy( shbuf, buf, *len ); error02: pkg_free( buf ); error01: return shbuf; }
/* be aware and use it *all* the time between pre_* and post_* functions! */ static inline char *print_uac_request(struct sip_msg *i_req, unsigned int *len, struct socket_info *send_sock, enum sip_protos proto ) { char *buf; /* build the shm buffer now */ buf=build_req_buf_from_sip_req( i_req, len, send_sock, proto, MSG_TRANS_SHM_FLAG); if (!buf) { LM_ERR("no more shm_mem\n"); ser_error=E_OUT_OF_MEM; return NULL; } return buf; }
/* be aware and use it *all* the time between pre_* and post_* functions! */ static inline char *print_uac_request(struct sip_msg *i_req, unsigned int *len, struct socket_info *send_sock, enum sip_protos proto ) { char *buf; str *cid = NULL; if (1/* TODO: check if the cid should be used */) cid = tm_via_cid(); /* build the shm buffer now */ buf=build_req_buf_from_sip_req( i_req, len, send_sock, proto, cid, MSG_TRANS_SHM_FLAG); if (!buf) { LM_ERR("no more shm_mem\n"); ser_error=E_OUT_OF_MEM; return NULL; } return buf; }
/* forwards a request to dst * parameters: * msg - sip msg * dst - destination name, if non-null it will be resolved and * send_info updated with the ip/port. Even if dst is non * null send_info must contain the protocol and if a non * default port or non srv. lookup is desired, the port must * be !=0 * port - used only if dst!=0 (else the port in send_info->to is used) * send_info - value/result partially filled dest_info structure: * - send_info->proto and comp are used * - send_info->to will be filled (dns) * - send_info->send_flags is filled from the message * - if the send_socket member is null, a send_socket will be * chosen automatically * WARNING: don't forget to zero-fill all the unused members (a non-zero * random id along with proto==PROTO_TCP can have bad consequences, same for * a bogus send_socket value) */ int forward_request(struct sip_msg* msg, str* dst, unsigned short port, struct dest_info* send_info) { unsigned int len; char* buf; char md5[MD5_LEN]; struct socket_info* orig_send_sock; /* initial send_sock */ int ret; struct ip_addr ip; /* debugging only */ char proto; #ifdef USE_DNS_FAILOVER struct socket_info* prev_send_sock; int err; struct dns_srv_handle dns_srv_h; prev_send_sock=0; err=0; #endif buf=0; orig_send_sock=send_info->send_sock; proto=send_info->proto; ret=0; if(dst){ #ifdef USE_DNS_FAILOVER if (cfg_get(core, core_cfg, use_dns_failover)){ dns_srv_handle_init(&dns_srv_h); err=dns_sip_resolve2su(&dns_srv_h, &send_info->to, dst, port, &proto, dns_flags); if (err!=0){ LOG(L_ERR, "ERROR: forward_request: resolving \"%.*s\"" " failed: %s [%d]\n", dst->len, ZSW(dst->s), dns_strerror(err), err); ret=E_BAD_ADDRESS; goto error; } }else #endif if (sip_hostport2su(&send_info->to, dst, port, &proto)<0){ LOG(L_ERR, "ERROR: forward_request: bad host name %.*s," " dropping packet\n", dst->len, ZSW(dst->s)); ret=E_BAD_ADDRESS; goto error; } }/* dst */ send_info->send_flags=msg->fwd_send_flags; /* calculate branch for outbound request; if syn_branch is turned off, calculate is from transaction key, i.e., as an md5 of From/To/CallID/ CSeq exactly the same way as TM does; good for reboot -- than messages belonging to transaction lost due to reboot will still be forwarded with the same branch parameter and will be match-able downstream if it is turned on, we don't care about reboot; we simply put a simple value in there; better for performance */ if (syn_branch ) { memcpy(msg->add_to_branch_s, "z9hG4bKcydzigwkX", 16); msg->add_to_branch_len=16; } else { if (!char_msg_val( msg, md5 )) { /* parses transaction key */ LOG(L_ERR, "ERROR: forward_request: char_msg_val failed\n"); ret=E_UNSPEC; goto error; } msg->hash_index=hash( msg->callid->body, get_cseq(msg)->number); if (!branch_builder( msg->hash_index, 0, md5, 0 /* 0-th branch */, msg->add_to_branch_s, &msg->add_to_branch_len )) { LOG(L_ERR, "ERROR: forward_request: branch_builder failed\n"); ret=E_UNSPEC; goto error; } } /* try to send the message until success or all the ips are exhausted * (if dns lookup is performed && the dns cache used ) */ #ifdef USE_DNS_FAILOVER do{ #endif if (orig_send_sock==0) /* no forced send_sock => find it **/ send_info->send_sock=get_send_socket(msg, &send_info->to, proto); if (send_info->send_sock==0){ LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d, proto %d " "no corresponding listening socket\n", send_info->to.s.sa_family, proto); ret=ser_error=E_NO_SOCKET; #ifdef USE_DNS_FAILOVER /* continue, maybe we find a socket for some other ip */ continue; #else goto error; #endif } #ifdef USE_DNS_FAILOVER if (prev_send_sock!=send_info->send_sock){ /* rebuild the message only if the send_sock changed */ prev_send_sock=send_info->send_sock; #endif if (buf) pkg_free(buf); send_info->proto=proto; buf = build_req_buf_from_sip_req(msg, &len, send_info, 0); if (!buf){ LOG(L_ERR, "ERROR: forward_request: building failed\n"); ret=E_OUT_OF_MEM; /* most probable */ goto error; } #ifdef USE_DNS_FAILOVER } #endif /* send it! */ DBG("Sending:\n%.*s.\n", (int)len, buf); DBG("orig. len=%d, new_len=%d, proto=%d\n", msg->len, len, send_info->proto ); if (run_onsend(msg, send_info, buf, len)==0){ su2ip_addr(&ip, &send_info->to); LOG(L_INFO, "forward_request: request to %s:%d(%d) dropped" " (onsend_route)\n", ip_addr2a(&ip), su_getport(&send_info->to), send_info->proto); ser_error=E_OK; /* no error */ ret=E_ADM_PROHIBITED; #ifdef USE_DNS_FAILOVER continue; /* try another ip */ #else goto error; /* error ? */ #endif } #ifdef USE_DST_BLACKLIST if (cfg_get(core, core_cfg, use_dst_blacklist)){ if (dst_is_blacklisted(send_info, msg)){ su2ip_addr(&ip, &send_info->to); LOG(L_DBG, "DEBUG: blacklisted destination:%s:%d (%d)\n", ip_addr2a(&ip), su_getport(&send_info->to), send_info->proto); ret=ser_error=E_SEND; #ifdef USE_DNS_FAILOVER continue; /* try another ip */ #else goto error; #endif } } #endif if (msg_send(send_info, buf, len)<0){ ret=ser_error=E_SEND; #ifdef USE_DST_BLACKLIST (void)dst_blacklist_add(BLST_ERR_SEND, send_info, msg); #endif #ifdef USE_DNS_FAILOVER continue; /* try another ip */ #else goto error; #endif }else{ ret=ser_error=E_OK; /* sent requests stats */ STATS_TX_REQUEST( msg->first_line.u.request.method_value ); /* exit succcesfully */ goto end; } #ifdef USE_DNS_FAILOVER }while(dst && cfg_get(core, core_cfg, use_dns_failover) && dns_srv_handle_next(&dns_srv_h, err) && ((err=dns_sip_resolve2su(&dns_srv_h, &send_info->to, dst, port, &proto, dns_flags))==0)); if ((err!=0) && (err!=-E_DNS_EOR)){ LOG(L_ERR, "ERROR: resolving %.*s host name in uri" " failed: %s [%d] (dropping packet)\n", dst->len, ZSW(dst->s), dns_strerror(err), err); ret=ser_error=E_BAD_ADDRESS; goto error; } #endif error: STATS_TX_DROPS; end: #ifdef USE_DNS_FAILOVER if (dst && cfg_get(core, core_cfg, use_dns_failover)){ dns_srv_handle_put(&dns_srv_h); } #endif if (buf) pkg_free(buf); /* received_buf & line_buf will be freed in receive_msg by free_lump_list*/ #if defined STATS_REQ_FWD_OK || defined STATS_REQ_FWD_DROP if(ret==0) STATS_REQ_FWD_OK(); else STATS_REQ_FWD_DROP(); #endif /* STATS_REQ_FWD_* */ return ret; }
/* * Send a request using data from the dialog structure */ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp,release_tmcb_param release_func) { union sockaddr_union to_su, new_to_su; struct cell *new_cell; struct cell *backup_cell; struct retr_buf *request; static struct sip_msg *req; struct usr_avp **backup; char *buf, *buf1; int buf_len, buf_len1; int ret, flags, sflag_bk; int backup_route_type; int sip_msg_len; unsigned int hi; struct socket_info *new_send_sock; str h_to, h_from, h_cseq, h_callid; struct proxy_l *proxy, *new_proxy; unsigned short dst_changed; ret=-1; /*** added by dcm * - needed by external ua to send a request within a dlg */ if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0) goto error3; if(dialog->obp.s) dialog->hooks.next_hop = &dialog->obp; LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); /* calculate the socket corresponding to next hop */ proxy = uri2proxy( dialog->hooks.next_hop, dialog->send_sock ? dialog->send_sock->proto : PROTO_NONE ); if (proxy==0) { ret=E_BAD_ADDRESS; goto error3; } /* use the first address */ hostent2su( &to_su, &proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT); /* check/discover the send socket */ if (dialog->send_sock) { /* if already set, the protocol of send sock must have the the same type as the proto required by destination URI */ if (proxy->proto != dialog->send_sock->proto) dialog->send_sock = NULL; } if (dialog->send_sock==NULL) { /* get the send socket */ dialog->send_sock = get_send_socket( NULL/*msg*/, &to_su, proxy->proto); if (!dialog->send_sock) { LM_ERR("no corresponding socket for af %d\n", to_su.s.sa_family); ser_error = E_NO_SOCKET; goto error2; } } LM_DBG("sending socket is %.*s \n", dialog->send_sock->name.len,dialog->send_sock->name.s); /* ***** Create TRANSACTION and all related ***** */ new_cell = build_cell( NULL/*msg*/, 1/*full UAS clone*/); if (!new_cell) { ret=E_OUT_OF_MEM; LM_ERR("short of cell shmem\n"); goto error2; } /* pass the transaction flags from dialog to transaction */ new_cell->flags |= dialog->T_flags; /* add the callback the transaction for LOCAL_COMPLETED event */ flags = TMCB_LOCAL_COMPLETED; /* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */ if (pass_provisional_replies || pass_provisional(new_cell)) flags |= TMCB_LOCAL_RESPONSE_OUT; if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,release_func)!=1){ ret=E_OUT_OF_MEM; LM_ERR("short of tmcb shmem\n"); goto error2; } if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0) new_cell->flags |= T_IS_INVITE_FLAG; new_cell->flags |= T_IS_LOCAL_FLAG; request = &new_cell->uac[0].request; if (dialog->forced_to_su.s.sa_family == AF_UNSPEC) request->dst.to = to_su; else request->dst.to = dialog->forced_to_su; request->dst.send_sock = dialog->send_sock; request->dst.proto = dialog->send_sock->proto; request->dst.proto_reserved1 = 0; hi=dlg2hash(dialog); LOCK_HASH(hi); insert_into_hash_table_unsafe(new_cell, hi); UNLOCK_HASH(hi); /* copy AVPs into transaction */ new_cell->user_avps = dialog->avps; dialog->avps = NULL; /* ***** Create the message buffer ***** */ buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len); if (!buf) { LM_ERR("failed to build message\n"); ret=E_OUT_OF_MEM; goto error1; } if (local_rlist.a) { LM_DBG("building sip_msg from buffer\n"); req = buf_to_sip_msg(buf, buf_len, dialog); if (req==NULL) { LM_ERR("failed to build sip_msg from buffer\n"); } else { /* set this transaction as active one */ backup_cell = get_t(); set_t( new_cell ); /* set transaction AVP list */ backup = set_avp_list( &new_cell->user_avps ); /* backup script flags */ sflag_bk = getsflags(); /* disable parallel forking */ set_dset_state( 0 /*disable*/); /* run the route */ swap_route_type( backup_route_type, LOCAL_ROUTE); run_top_route( local_rlist.a, req); set_route_type( backup_route_type ); /* transfer current message context back to t */ new_cell->uac[0].br_flags = getb0flags(req); /* restore the prevoius active transaction */ set_t( backup_cell ); set_dset_state( 1 /*enable*/); setsflagsval(sflag_bk); set_avp_list( backup ); /* check for changes - if none, do not regenerate the buffer */ dst_changed = 1; if (req->new_uri.s || req->force_send_socket!=dialog->send_sock || req->dst_uri.len != dialog->hooks.next_hop->len || memcmp(req->dst_uri.s,dialog->hooks.next_hop->s,req->dst_uri.len) || (dst_changed=0)==0 || req->add_rm || req->body_lumps){ new_send_sock = NULL; /* do we also need to change the destination? */ if (dst_changed) { /* calculate the socket corresponding to next hop */ new_proxy = uri2proxy( req->dst_uri.s ? &(req->dst_uri) : &req->new_uri, PROTO_NONE ); if (new_proxy==0) goto abort_update; /* use the first address */ hostent2su( &new_to_su, &new_proxy->host, new_proxy->addr_idx, new_proxy->port ? new_proxy->port:SIP_PORT); /* get the send socket */ new_send_sock = get_send_socket( req, &new_to_su, new_proxy->proto); if (!new_send_sock) { free_proxy( new_proxy ); pkg_free( new_proxy ); LM_ERR("no socket found for the new destination\n"); goto abort_update; } } /* if interface change, we need to re-build the via */ if (new_send_sock && new_send_sock != dialog->send_sock) { LM_DBG("Interface change in local route -> " "rebuilding via\n"); if (!del_lump(req,req->h_via1->name.s - req->buf, req->h_via1->len,0)) { LM_ERR("Failed to remove initial via \n"); goto abort_update; } memcpy(req->add_to_branch_s,req->via1->branch->value.s, req->via1->branch->value.len); req->add_to_branch_len = req->via1->branch->value.len; /* update also info about new destination and send sock */ dialog->send_sock = new_send_sock; free_proxy( proxy ); pkg_free( proxy ); proxy = new_proxy; request->dst.send_sock = new_send_sock; request->dst.proto = new_send_sock->proto; request->dst.proto_reserved1 = 0; /* build the shm buffer now */ set_init_lump_flags(LUMPFLAG_BRANCH); buf1 = build_req_buf_from_sip_req(req, (unsigned int*)&buf_len1, new_send_sock, new_send_sock->proto, MSG_TRANS_SHM_FLAG); reset_init_lump_flags(); del_flaged_lumps( &req->add_rm, LUMPFLAG_BRANCH); } else { LM_DBG("Change in local route -> rebuilding buffer\n"); /* build the shm buffer now */ buf1 = build_req_buf_from_sip_req(req, (unsigned int*)&buf_len1, dialog->send_sock, dialog->send_sock->proto, MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG); /* now as it used, hide the original VIA header */ del_lump(req,req->h_via1->name.s - req->buf, req->h_via1->len, 0); } if (!buf1) { LM_ERR("no more shm mem\n"); /* keep original buffer */ goto abort_update; } /* update shortcuts */ if(!req->add_rm && !req->new_uri.s) { /* headers are not affected, simply tranlate */ new_cell->from.s = new_cell->from.s - buf + buf1; new_cell->to.s = new_cell->to.s - buf + buf1; new_cell->callid.s = new_cell->callid.s - buf + buf1; new_cell->cseq_n.s = new_cell->cseq_n.s - buf + buf1; } else { /* use heavy artilery :D */ if (extract_ftc_hdrs( buf1, buf_len1, &h_from, &h_to, &h_cseq, &h_callid)!=0 ) { LM_ERR("failed to update shortcut pointers\n"); shm_free(buf1); goto abort_update; } new_cell->from = h_from; new_cell->to = h_to; new_cell->callid = h_callid; new_cell->cseq_n = h_cseq; } /* here we rely on how build_uac_req() builds the first line */ new_cell->uac[0].uri.s = buf1 + req->first_line.u.request.method.len + 1; new_cell->uac[0].uri.len = GET_RURI(req)->len; /* update also info about new destination and send sock */ if (new_send_sock) request->dst.to = new_to_su; shm_free(buf); buf = buf1; buf_len = buf_len1; /* use new buffer */ } else { /* no changes over the message, buffer is already generated, just hide the original VIA for potential further branches */ del_lump(req,req->h_via1->name.s-req->buf,req->h_via1->len,0); } abort_update: /* save the SIP message into transaction */ new_cell->uas.request = sip_msg_cloner( req, &sip_msg_len, 1); if (new_cell->uas.request==NULL) { /* reset any T triggering */ new_cell->on_negative = 0; new_cell->on_reply = 0; } else { new_cell->uas.end_request= ((char*)new_cell->uas.request)+sip_msg_len; } /* no parallel support in UAC transactions */ new_cell->on_branch = 0; free_sip_msg(req); } } /* for DNS based failover, copy the DNS proxy into transaction */ if (!disable_dns_failover) { new_cell->uac[0].proxy = shm_clone_proxy( proxy, 1/*do_free*/); if (new_cell->uac[0].proxy==NULL) LM_ERR("failed to store DNS info -> no DNS based failover\n"); } new_cell->method.s = buf; new_cell->method.len = method->len; request->buffer.s = buf; request->buffer.len = buf_len; new_cell->nr_of_outgoings++; if(last_localT) { *last_localT = new_cell; REF_UNSAFE(new_cell); } if (SEND_BUFFER(request) == -1) { LM_ERR("attempt to send to '%.*s' failed\n", dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); } if (method->len==ACK_LEN && memcmp(method->s, ACK, ACK_LEN)==0 ) { t_release_transaction(new_cell); } else { start_retr(request); } free_proxy( proxy ); pkg_free( proxy ); return 1; error1: LOCK_HASH(hi); remove_from_hash_table_unsafe(new_cell); UNLOCK_HASH(hi); free_cell(new_cell); error2: free_proxy( proxy ); pkg_free( proxy ); error3: return ret; }
static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2) { struct dest_info dst; str obuf; sip_msg_t tmp; if(msg->first_line.type!=SIP_REPLY && get_route_type()!=REQUEST_ROUTE) { LM_ERR("invalid usage - not in request route\n"); return -1; } init_dest_info(&dst); dst.proto = PROTO_UDP; if(msg->first_line.type == SIP_REPLY) { obuf.s = generate_res_buf_from_sip_res(msg, (unsigned int*)&obuf.len, BUILD_NO_VIA1_UPDATE); } else { if(msg->msg_flags & FL_RR_ADDED) { LM_ERR("cannot apply msg changes after adding record-route" " header - it breaks conditional 2nd header\n"); return -1; } obuf.s = build_req_buf_from_sip_req(msg, (unsigned int*)&obuf.len, &dst, BUILD_NO_PATH|BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE); } if(obuf.s == NULL) { LM_ERR("couldn't update msg buffer content\n"); return -1; } if(obuf.len>=BUF_SIZE) { LM_ERR("new buffer overflow (%d)\n", obuf.len); pkg_free(obuf.s); return -1; } /* temporary copy */ memcpy(&tmp, msg, sizeof(sip_msg_t)); /* reset dst uri and path vector to avoid freeing - restored later */ if(msg->dst_uri.s!=NULL) { msg->dst_uri.s = NULL; msg->dst_uri.len = 0; } if(msg->path_vec.s!=NULL) { msg->path_vec.s = NULL; msg->path_vec.len = 0; } /* free old msg structure */ free_sip_msg(msg); memset(msg, 0, sizeof(sip_msg_t)); /* restore msg fields */ msg->buf = tmp.buf; msg->id = tmp.id; msg->rcv = tmp.rcv; msg->set_global_address = tmp.set_global_address; msg->set_global_port = tmp.set_global_port; msg->flags = tmp.flags; msg->msg_flags = tmp.msg_flags; msg->hash_index = tmp.hash_index; msg->force_send_socket = tmp.force_send_socket; msg->fwd_send_flags = tmp.fwd_send_flags; msg->rpl_send_flags = tmp.rpl_send_flags; msg->dst_uri = tmp.dst_uri; msg->path_vec = tmp.path_vec; memcpy(msg->buf, obuf.s, obuf.len); msg->len = obuf.len; msg->buf[msg->len] = '\0'; /* free new buffer - copied in the static buffer from old sip_msg_t */ pkg_free(obuf.s); /* reparse the message */ LM_DBG("SIP message content updated - reparsing\n"); if (parse_msg(msg->buf, msg->len, msg)!=0){ LM_ERR("parsing new sip message failed\n"); return -1; } return 1; }
int forward_request( struct sip_msg* msg, struct proxy_l * p) { union sockaddr_union to; unsigned int len; char* buf; struct socket_info* send_sock; struct socket_info* last_sock; str *branch; buf=0; /* calculate branch for outbound request - if the branch buffer is already * set (maybe by an upper level as TM), used it; otherwise computes * the branch for stateless fwd. . According to the latest discussions * on the topic, you should reuse the latest statefull branch * --bogdan */ if ( msg->add_to_branch_len==0 ) { branch = get_sl_branch(msg); if (branch==0) { LM_ERR("unable to compute branch\n"); goto error; } msg->add_to_branch_len = branch->len; memcpy( msg->add_to_branch_s, branch->s, branch->len); } msg_callback_process(msg, REQ_PRE_FORWARD, (void *)p); hostent2su( &to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT); last_sock = 0; if (getb0flags() & tcp_no_new_conn_bflag) tcp_no_new_conn = 1; do { send_sock=get_send_socket( msg, &to, p->proto); if (send_sock==0){ LM_ERR("cannot forward to af %d, proto %d no corresponding" "listening socket\n", to.s.sa_family, p->proto); ser_error=E_NO_SOCKET; continue; } if ( last_sock!=send_sock ) { if (buf) pkg_free(buf); buf = build_req_buf_from_sip_req(msg, &len, send_sock, p->proto, 0); if (!buf){ LM_ERR("building req buf failed\n"); tcp_no_new_conn = 0; goto error; } last_sock = send_sock; } if (check_blacklists( p->proto, &to, buf, len)) { LM_DBG("blocked by blacklists\n"); ser_error=E_IP_BLOCKED; continue; } /* send it! */ LM_DBG("sending:\n%.*s.\n", (int)len, buf); LM_DBG("orig. len=%d, new_len=%d, proto=%d\n", msg->len, len, p->proto ); if (msg_send(send_sock, p->proto, &to, 0, buf, len)<0){ ser_error=E_SEND; continue; } run_fwd_callbacks( msg, buf, len, send_sock, p->proto, &to); ser_error = 0; break; }while( get_next_su( p, &to, (ser_error==E_IP_BLOCKED)?0:1)==0 ); tcp_no_new_conn = 0; if (ser_error) { update_stat( drp_reqs, 1); goto error; } /* sent requests stats */ update_stat( fwd_reqs, 1); pkg_free(buf); /* received_buf & line_buf will be freed in receive_msg by free_lump_list*/ return 0; error: if (buf) pkg_free(buf); return -1; }
/** * dump current SIP message and a diff lump list * part of the code taken from msg_apply_changes_f */ static int w_dbg_sip_msg(struct sip_msg* msg, char *level, char *facility) { int ilevel = cfg_get(core, core_cfg, debug); int ifacility= cfg_get(core, core_cfg, log_facility); int flag = FLAG_MSG_LUMPS_ONLY; // copy lumps only, not the whole message unsigned int new_buf_offs=0, orig_offs = 0; char *hdr_lumps = NULL; char *bdy_lumps = NULL; const char *start_txt = "------------------------- START OF SIP message debug --------------------------\n"; const char *hdr_txt = "------------------------------ SIP header diffs -------------------------------\n"; const char *bdy_txt = "------------------------------- SIP body diffs --------------------------------\n"; const char *end_txt = "-------------------------- END OF SIP message debug ---------------------------\n\n"; struct dest_info send_info; str obuf; if (msg->first_line.type != SIP_REPLY && get_route_type() != REQUEST_ROUTE) { LM_ERR("invalid usage - not in request route\n"); return -1; } if (level != NULL) { /* substract L_OFFSET previously added */ ilevel = (int)(long)level - L_OFFSET; } if (facility != NULL) { ifacility = (int)(long)facility; } /* msg_apply_changes_f code needed to get the current msg */ init_dest_info(&send_info); send_info.proto = PROTO_UDP; if(msg->first_line.type == SIP_REPLY) { obuf.s = generate_res_buf_from_sip_res(msg, (unsigned int*)&obuf.len, BUILD_NO_VIA1_UPDATE); } else { obuf.s = build_req_buf_from_sip_req(msg, (unsigned int*)&obuf.len, &send_info, BUILD_NO_PATH|BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE); } if(obuf.s == NULL) { LM_ERR("couldn't update msg buffer content\n"); return -1; } if(obuf.len >= BUF_SIZE) { LM_ERR("new buffer overflow (%d)\n", obuf.len); pkg_free(obuf.s); return -1; } /* skip original uri */ if(msg->first_line.type == SIP_REQUEST) { if(msg->new_uri.s) { orig_offs = msg->first_line.u.request.uri.s - msg->buf; orig_offs += msg->first_line.u.request.uri.len; } } /* alloc private mem and copy lumps */ hdr_lumps = pkg_malloc(BUF_SIZE); bdy_lumps = pkg_malloc(BUF_SIZE); new_buf_offs = 0; process_lumps(msg, msg->add_rm, hdr_lumps, &new_buf_offs, &orig_offs, &send_info, flag); new_buf_offs = 0; process_lumps(msg, msg->body_lumps, bdy_lumps, &new_buf_offs, &orig_offs, &send_info, flag); /* do the print */ if (_dbg_sip_msg_cline < 0 ) { LOG_FC(ifacility, ilevel, "CONFIG LINE unknown\n%s%.*s%s%s%s%s%s", start_txt, obuf.len, obuf.s, hdr_txt, hdr_lumps, bdy_txt, bdy_lumps, end_txt); } else { LOG_FC(ifacility, ilevel, "CONFIG LINE %d\n%s%.*s%s%s%s%s%s", _dbg_sip_msg_cline, start_txt, obuf.len, obuf.s, hdr_txt, hdr_lumps, bdy_txt, bdy_lumps, end_txt); } /* free lumps */ if (hdr_lumps) { pkg_free(hdr_lumps); } if (bdy_lumps) { pkg_free(bdy_lumps); } return 1; }
/* WARNING: - dst_cell contains the created cell, but it is un-referenced * (before using it make sure you REF() it first) * - if ACK (method==ACK), a cell will be created but it will not * be added in the hash table (should be either deleted by the * caller) */ static inline int t_uac_prepare(uac_req_t *uac_r, struct retr_buf **dst_req, struct cell **dst_cell) { struct dest_info dst; struct cell *new_cell; struct retr_buf *request; char* buf; int buf_len, ret; unsigned int hi; int is_ack; ticks_t lifetime; #ifdef USE_DNS_FAILOVER struct dns_srv_handle dns_h; #endif long nhtype; #ifdef WITH_EVENT_LOCAL_REQUEST struct cell *backup_t; int backup_branch; unsigned int backup_msgid; static struct sip_msg lreq; char *buf1; int buf_len1; int sflag_bk; int backup_route_type; #endif snd_flags_t snd_flags; tm_xlinks_t backup_xd; tm_xdata_t local_xd; ret=-1; hi=0; /* make gcc happy */ /*if (dst_req) *dst_req = NULL;*/ is_ack = (((uac_r->method->len == 3) && (memcmp("ACK", uac_r->method->s, 3)==0)) ? 1 : 0); /*** added by dcm * - needed by external ua to send a request within a dlg */ if ((nhtype = w_calculate_hooks(uac_r->dialog)) < 0) /* if err's returned, the message is incorrect */ goto error2; if (!uac_r->dialog->loc_seq.is_set) { /* this is the first request in the dialog, set cseq to default value now - Miklos */ uac_r->dialog->loc_seq.value = DEFAULT_CSEQ; uac_r->dialog->loc_seq.is_set = 1; } DBG("DEBUG:tm:t_uac: next_hop=<%.*s>\n",uac_r->dialog->hooks.next_hop->len, uac_r->dialog->hooks.next_hop->s); /* new message => take the dialog send_socket if set, or the default send_socket if not*/ SND_FLAGS_INIT(&snd_flags); #ifdef USE_DNS_FAILOVER if (cfg_get(core, core_cfg, use_dns_failover)){ dns_srv_handle_init(&dns_h); if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock, snd_flags, uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) || (dst.send_sock==0)){ dns_srv_handle_put(&dns_h); ser_error = E_NO_SOCKET; ret=ser_error; LOG(L_ERR, "t_uac: no socket found\n"); goto error2; } dns_srv_handle_put(&dns_h); /* not needed anymore */ }else{ if ((uri2dst2(0, &dst, uac_r->dialog->send_sock, snd_flags, uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) || (dst.send_sock==0)){ ser_error = E_NO_SOCKET; ret=ser_error; LOG(L_ERR, "t_uac: no socket found\n"); goto error2; } } #else /* USE_DNS_FAILOVER */ if ((uri2dst2(&dst, uac_r->dialog->send_sock, snd_flags, uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) || (dst.send_sock==0)){ ser_error = E_NO_SOCKET; ret=ser_error; LOG(L_ERR, "t_uac: no socket found\n"); goto error2; } #endif /* USE_DNS_FAILOVER */ /* build cell sets X/AVP lists to new transaction structure * => bakup in a tmp struct and restore afterwards */ memset(&local_xd, 0, sizeof(tm_xdata_t)); tm_xdata_replace(&local_xd, &backup_xd); new_cell = build_cell(0); tm_xdata_replace(0, &backup_xd); if (!new_cell) { ret=E_OUT_OF_MEM; LOG(L_ERR, "t_uac: short of cell shmem\n"); goto error2; } if (uac_r->method->len==INVITE_LEN && memcmp(uac_r->method->s, INVITE, INVITE_LEN)==0){ new_cell->flags |= T_IS_INVITE_FLAG; new_cell->flags|=T_AUTO_INV_100 & (!cfg_get(tm, tm_cfg, tm_auto_inv_100) -1); #ifdef WITH_AS_SUPPORT if (uac_r->cb_flags & TMCB_DONT_ACK) new_cell->flags |= T_NO_AUTO_ACK; #endif lifetime=cfg_get(tm, tm_cfg, tm_max_inv_lifetime); }else lifetime=cfg_get(tm, tm_cfg, tm_max_noninv_lifetime); new_cell->flags |= T_IS_LOCAL_FLAG; /* init timers hack, new_cell->fr_timer and new_cell->fr_inv_timer * must be set, or else the fr will happen immediately * we can't call init_new_t() because we don't have a sip msg * => we'll ignore t_set_fr() or avp timer value and will use directly the * module params fr_inv_timer and fr_timer -- andrei */ new_cell->fr_timeout=cfg_get(tm, tm_cfg, fr_timeout); new_cell->fr_inv_timeout=cfg_get(tm, tm_cfg, fr_inv_timeout); new_cell->end_of_life=get_ticks_raw()+lifetime; #ifdef TM_DIFF_RT_TIMEOUT /* same as above for retransmission intervals */ new_cell->rt_t1_timeout_ms = cfg_get(tm, tm_cfg, rt_t1_timeout_ms); new_cell->rt_t2_timeout_ms = cfg_get(tm, tm_cfg, rt_t2_timeout_ms); #endif set_kr(REQ_FWDED); request = &new_cell->uac[0].request; request->dst = dst; request->flags |= nhtype; if (!is_ack) { #ifdef TM_DEL_UNREF INIT_REF(new_cell, 1); /* ref'ed only from the hash */ #endif hi=dlg2hash(uac_r->dialog); LOCK_HASH(hi); insert_into_hash_table_unsafe(new_cell, hi); UNLOCK_HASH(hi); } buf = build_uac_req(uac_r->method, uac_r->headers, uac_r->body, uac_r->dialog, 0, new_cell, &buf_len, &dst); if (!buf) { LOG(L_ERR, "t_uac: Error while building message\n"); ret=E_OUT_OF_MEM; goto error1; } #ifdef WITH_EVENT_LOCAL_REQUEST if (unlikely(goto_on_local_req>=0)) { DBG("executing event_route[tm:local-request]\n"); if(likely(build_sip_msg_from_buf(&lreq, buf, buf_len, inc_msg_no()) == 0)) { /* fill some field in sip_msg */ if (unlikely(set_dst_uri(&lreq, uac_r->dialog->hooks.next_hop))) { LM_ERR("failed to set dst_uri"); free_sip_msg(&lreq); } else { struct onsend_info onsnd_info; lreq.force_send_socket = uac_r->dialog->send_sock; lreq.rcv.proto = dst.send_sock->proto; lreq.rcv.src_ip = dst.send_sock->address; lreq.rcv.src_port = dst.send_sock->port_no; lreq.rcv.dst_port = su_getport(&dst.to); su2ip_addr(&lreq.rcv.dst_ip, &dst.to); lreq.rcv.src_su=dst.send_sock->su; lreq.rcv.bind_address=dst.send_sock; #ifdef USE_COMP lreq.rcv.comp=dst.comp; #endif /* USE_COMP */ sflag_bk = getsflags(); tm_xdata_swap(new_cell, &backup_xd, 0); onsnd_info.to=&dst.to; onsnd_info.send_sock=dst.send_sock; onsnd_info.buf=buf; onsnd_info.len=buf_len; p_onsend=&onsnd_info; /* run the route */ backup_route_type = get_route_type(); set_route_type(LOCAL_ROUTE); /* set T to the current transaction */ backup_t=get_t(); backup_branch=get_t_branch(); backup_msgid=global_msg_id; /* fake transaction and message id */ global_msg_id=lreq.id; set_t(new_cell, T_BR_UNDEFINED); run_top_route(event_rt.rlist[goto_on_local_req], &lreq, 0); /* restore original environment */ set_t(backup_t, backup_branch); global_msg_id=backup_msgid; set_route_type( backup_route_type ); p_onsend=0; /* restore original environment */ tm_xdata_swap(new_cell, &backup_xd, 1); setsflagsval(sflag_bk); if (unlikely(lreq.new_uri.s)) { pkg_free(lreq.new_uri.s); lreq.new_uri.s=0; lreq.new_uri.len=0; } if (unlikely(lreq.dst_uri.s)) { pkg_free(lreq.dst_uri.s); lreq.dst_uri.s=0; lreq.dst_uri.len=0; } if (unlikely(lreq.add_rm || lreq.body_lumps)) { LM_DBG("apply new updates to sip msg\n"); buf1 = build_req_buf_from_sip_req(&lreq, (unsigned int*)&buf_len1, &dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE| BUILD_IN_SHM); if (likely(buf1)){ shm_free(buf); buf = buf1; buf_len = buf_len1; /* a possible change of the method is not handled! */ } } lreq.buf=0; /* covers the obsolete DYN_BUF */ free_sip_msg(&lreq); } } } #endif new_cell->method.s = buf; new_cell->method.len = uac_r->method->len; request->buffer = buf; request->buffer_len = buf_len; new_cell->nr_of_outgoings++; /* Register the callbacks after everything is successful and nothing can fail. Otherwise the callback parameter would be freed twise, once from TMCB_DESTROY, and again because of the negative return code. */ if(uac_r->cb && insert_tmcb(&(new_cell->tmcb_hl), uac_r->cb_flags, *(uac_r->cb), uac_r->cbp, NULL)!=1){ ret=E_OUT_OF_MEM; LOG(L_ERR, "t_uac: short of tmcb shmem\n"); goto error1; } if (has_local_reqin_tmcbs()) run_local_reqin_callbacks(new_cell, 0, 0); #ifdef DIALOG_CALLBACKS run_trans_dlg_callbacks(uac_r->dialog, new_cell, request); #endif /* DIALOG_CALLBACKS */ if (dst_req) *dst_req = request; if (dst_cell) *dst_cell = new_cell; else if(is_ack && dst_req==0){ free_cell(new_cell); } return 1; error1: if (!is_ack) { LOCK_HASH(hi); remove_from_hash_table_unsafe(new_cell); UNLOCK_HASH(hi); #ifdef TM_DEL_UNREF UNREF_FREE(new_cell); }else #else } #endif free_cell(new_cell); error2: return ret; }
static inline char *dlg_th_rebuild_req(struct sip_msg *msg,int *len) { return build_req_buf_from_sip_req(msg,(unsigned int*)len, NULL,PROTO_NONE,MSG_TRANS_NOVIA_FLAG); }
/* * Send a request using data from the dialog structure */ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp,release_tmcb_param release_func) { union sockaddr_union to_su; struct cell *new_cell; struct retr_buf *request; static struct sip_msg *req; struct usr_avp **backup; char *buf, *buf1; int buf_len, buf_len1; int ret, flags, sflag_bk; int backup_route_type; unsigned int hi; struct socket_info* send_sock; ret=-1; /*** added by dcm * - needed by external ua to send a request within a dlg */ if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0) goto error2; if(dialog->obp.s) dialog->hooks.next_hop = &dialog->obp; LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); /* calculate the socket corresponding to next hop */ send_sock = uri2sock(0, dialog->hooks.next_hop, &to_su, PROTO_NONE); if (send_sock==0) { ret=ser_error; LM_ERR("no socket found\n"); goto error2; } /* if a send socket defined verify if the same protocol */ if(dialog->send_sock) { if(send_sock->proto != dialog->send_sock->proto) { dialog->send_sock = send_sock; } } else { dialog->send_sock = send_sock; } new_cell = build_cell(0); if (!new_cell) { ret=E_OUT_OF_MEM; LM_ERR("short of cell shmem\n"); goto error2; } /* pass the transaction flags from dialog to transaction */ new_cell->flags |= dialog->T_flags; /* add the callback the transaction for LOCAL_COMPLETED event */ flags = TMCB_LOCAL_COMPLETED; /* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */ if (pass_provisional_replies || pass_provisional(new_cell)) flags |= TMCB_LOCAL_RESPONSE_OUT; if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,release_func)!=1){ ret=E_OUT_OF_MEM; LM_ERR("short of tmcb shmem\n"); goto error2; } if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0) new_cell->flags |= T_IS_INVITE_FLAG; new_cell->flags |= T_IS_LOCAL_FLAG; request = &new_cell->uac[0].request; request->dst.to = to_su; request->dst.send_sock = dialog->send_sock; request->dst.proto = dialog->send_sock->proto; request->dst.proto_reserved1 = 0; hi=dlg2hash(dialog); LOCK_HASH(hi); insert_into_hash_table_unsafe(new_cell, hi); UNLOCK_HASH(hi); buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len); if (!buf) { LM_ERR("failed to build message\n"); ret=E_OUT_OF_MEM; goto error1; } if (local_rlist.a) { LM_DBG("building sip_msg from buffer\n"); req = buf_to_sip_msg(buf, buf_len, dialog); if (req==NULL) { LM_ERR("failed to build sip_msg from buffer"); } else { /* set transaction AVP list */ backup = set_avp_list( &new_cell->user_avps ); /* backup script flags */ sflag_bk = getsflags(); /* disable parallel forking */ set_dset_state( 0 /*disable*/); /* transfer current message context back to t */ new_cell->uac[0].br_flags = req->flags; /* run the route */ swap_route_type( backup_route_type, LOCAL_ROUTE); run_top_route( local_rlist.a, req); set_route_type( backup_route_type ); set_dset_state( 1 /*enable*/); setsflagsval(sflag_bk); set_avp_list( backup ); /* check for changes - if none, do not regenerate the buffer * we ignore any change on RURI and DSTURI and they should not * be changed -bogdan */ if (req->new_uri.s) { pkg_free(req->new_uri.s); req->new_uri.s=0; req->new_uri.len=0; } if (req->dst_uri.s) { pkg_free(req->dst_uri.s); req->dst_uri.s=0; req->dst_uri.len=0; } if (req->add_rm || req->body_lumps) { LM_DBG("re-building the buffer (sip_msg changed) - lumps are" "%p %p\n",req->add_rm, req->body_lumps); /* build the shm buffer now */ buf1 = build_req_buf_from_sip_req(req,(unsigned int*)&buf_len1, dialog->send_sock, dialog->send_sock->proto, MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG ); if (!buf1) { LM_ERR("no more shm mem\n"); /* keep original buffer */ } else { shm_free(buf); buf = buf1; buf_len = buf_len1; /* use new buffer */ } } free_sip_msg(req); } } new_cell->method.s = buf; new_cell->method.len = method->len; request->buffer.s = buf; request->buffer.len = buf_len; new_cell->nr_of_outgoings++; if(last_localT) { *last_localT = new_cell; REF_UNSAFE(new_cell); } if (SEND_BUFFER(request) == -1) { LM_ERR("attempt to send to '%.*s' failed\n", dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); } if (method->len==ACK_LEN && memcmp(method->s, ACK, ACK_LEN)==0 ) { t_release_transaction(new_cell); } else { start_retr(request); } return 1; error1: LOCK_HASH(hi); remove_from_hash_table_unsafe(new_cell); UNLOCK_HASH(hi); free_cell(new_cell); error2: return ret; }