context_p context_alloc(void) { context_p ctx; ctx = pkg_malloc(context_size(CONTEXT_GLOBAL)); if (!ctx) { LM_ERR("no more pkg mem\n"); return NULL; } return ctx; }
inline static void final_response_handler( struct timer_link *fr_tl ) { #define CANCEL_REASON_SIP_480 \ "Reason: SIP;cause=480;text=\"NO_ANSWER\"" CRLF static context_p my_ctx = NULL; context_p old_ctx; struct retr_buf* r_buf; struct cell *t; if (fr_tl==0){ /* or BUG?, ignoring it for now */ LM_CRIT("final_response_handler(0) called\n"); return; } r_buf = get_fr_timer_payload(fr_tl); t=r_buf->my_T; # ifdef EXTRA_DEBUG if (t->damocles) { LM_ERR("transaction %p scheduled for deletion and" " called from FR timer\n",r_buf->my_T); abort(); } # endif reset_timer( &(r_buf->retr_timer) ); /* the transaction is already removed from FR_LIST by the timer */ /* FR for local cancels.... */ if (r_buf->activ_type==TYPE_LOCAL_CANCEL) { LM_DBG("stop retr for Local Cancel\n"); return; } /* FR for replies (negative INVITE replies) */ if (r_buf->activ_type>0) { # ifdef EXTRA_DEBUG if (t->uas.request->REQ_METHOD!=METHOD_INVITE || t->uas.status < 200 ) { LM_ERR("unknown type reply buffer\n"); abort(); } # endif put_on_wait( t ); return; }; /* as this processing is outside the scope of other messages (it is trigger from timer), a processing context must be attached to it */ old_ctx = current_processing_ctx; if (my_ctx==NULL) { my_ctx = context_alloc(CONTEXT_GLOBAL); if (my_ctx==NULL) { LM_ERR("failed to alloc new ctx in pkg\n"); } } memset( my_ctx, 0, context_size(CONTEXT_GLOBAL) ); current_processing_ctx = my_ctx; /* set the T context too */ set_t( t ); /* out-of-lock do the cancel I/O */ if (is_invite(t) && should_cancel_branch(t, r_buf->branch) ) { set_cancel_extra_hdrs( CANCEL_REASON_SIP_480, sizeof(CANCEL_REASON_SIP_480)-1); cancel_branch(t, r_buf->branch ); set_cancel_extra_hdrs( NULL, 0); } /* lock reply processing to determine how to proceed reliably */ LOCK_REPLIES( t ); LM_DBG("Cancel sent out, sending 408 (%p)\n", t); fake_reply(t, r_buf->branch, 408 ); /* flush the context */ if (current_processing_ctx==NULL) my_ctx=NULL; else context_destroy(CONTEXT_GLOBAL, my_ctx); /* switch back to the old context */ current_processing_ctx = old_ctx; /* reset the T context */ init_t(); LM_DBG("done\n"); }
static int hep_udp_read_req(struct socket_info *si, int* bytes_read) { struct receive_info ri; int len; #ifdef DYN_BUF char* buf; #else static char buf [BUF_SIZE+1]; #endif char *tmp; unsigned int fromlen; str msg; struct hep_context *hep_ctx; int ret = 0; context_p ctx=NULL; #ifdef DYN_BUF buf=pkg_malloc(BUF_SIZE+1); if (buf==0){ LM_ERR("could not allocate receive buffer\n"); goto error; } #endif fromlen=sockaddru_len(si->su); len=recvfrom(bind_address->socket, buf, BUF_SIZE,0,&ri.src_su.s,&fromlen); if (len==-1){ if (errno==EAGAIN) return 0; if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED)) return -1; LM_ERR("recvfrom:[%d] %s\n", errno, strerror(errno)); return -2; } if (len<MIN_UDP_PACKET) { LM_DBG("probing packet received len = %d\n", len); return 0; } /* we must 0-term the messages, receive_msg expects it */ buf[len]=0; /* no need to save the previous char */ ri.bind_address = si; ri.dst_port = si->port_no; ri.dst_ip = si->address; ri.proto = si->proto; ri.proto_reserved1 = ri.proto_reserved2 = 0; su2ip_addr(&ri.src_ip, &ri.src_su); ri.src_port=su_getport(&ri.src_su); /* if udp we are sure that version 1 or 2 of the * protocol is used */ if ((hep_ctx = shm_malloc(sizeof(struct hep_context))) == NULL) { LM_ERR("no more shared memory!\n"); return -1; } memset(hep_ctx, 0, sizeof(struct hep_context)); memcpy(&hep_ctx->ri, &ri, sizeof(struct receive_info)); if (len < 4) { LM_ERR("invalid message! too short!\n"); return -1; } if (!memcmp(buf, HEP_HEADER_ID, HEP_HEADER_ID_LEN)) { /* HEPv3 */ if (unpack_hepv3(buf, len, &hep_ctx->h)) { LM_ERR("hepv3 unpacking failed\n"); return -1; } } else { /* HEPv2 */ if (unpack_hepv12(buf, len, &hep_ctx->h)) { LM_ERR("hepv12 unpacking failed\n"); return -1; } } /* set context for receive_msg */ if ((ctx=context_alloc(CONTEXT_GLOBAL)) == NULL) { LM_ERR("failed to allocate new context! skipping...\n"); goto error_free_hep; } memset(ctx, 0, context_size(CONTEXT_GLOBAL)); context_put_ptr(CONTEXT_GLOBAL, ctx, hep_ctx_idx, hep_ctx); update_recv_info(&ri, &hep_ctx->h); /* run hep callbacks; set the current processing context * to hep context; this way callbacks will have all the data * needed */ current_processing_ctx = ctx; ret=run_hep_cbs(); if (ret < 0) { LM_ERR("failed to run hep callbacks\n"); return -1; } current_processing_ctx = NULL; if (hep_ctx->h.version == 3) { /* HEPv3 */ msg.len = hep_ctx->h.u.hepv3.payload_chunk.chunk.length- sizeof(hep_chunk_t); msg.s = hep_ctx->h.u.hepv3.payload_chunk.data; } else { /* HEPv12 */ msg.len = len - hep_ctx->h.u.hepv12.hdr.hp_l; msg.s = buf + hep_ctx->h.u.hepv12.hdr.hp_l; if (hep_ctx->h.u.hepv12.hdr.hp_v == 2) { msg.s += sizeof(struct hep_timehdr); msg.len -= sizeof(struct hep_timehdr); } } if (ri.src_port==0){ tmp=ip_addr2a(&ri.src_ip); LM_INFO("dropping 0 port packet for %s\n", tmp); return 0; } if (ret != HEP_SCRIPT_SKIP) { /* receive_msg must free buf too!*/ receive_msg( msg.s, msg.len, &ri, ctx); } return 0; error_free_hep: shm_free(hep_ctx); return -1; }
static inline int hep_handle_req(struct tcp_req *req, struct tcp_connection *con, int _max_msg_chunks) { struct receive_info local_rcv; char *msg_buf; int msg_len; long size; int ret=0; struct hep_context *hep_ctx; context_p ctx=NULL; if (req->complete){ /* update the timeout - we successfully read the request */ tcp_conn_set_lifetime( con, tcp_con_lifetime); con->timeout=con->lifetime; /* just for debugging use sendipv4 as receiving socket FIXME*/ con->rcv.proto_reserved1=con->id; /* copy the id */ /* prepare for next request */ size=req->pos-req->parsed; msg_buf = req->start; msg_len = req->parsed-req->start; local_rcv = con->rcv; if (!size) { /* did not read any more things - we can release * the connection */ LM_DBG("Nothing more to read on TCP conn %p, currently in state %d \n", con,con->state); if (req != &hep_current_req) { /* we have the buffer in the connection tied buff - * detach it , release the conn and free it afterwards */ con->con_req = NULL; } /* TODO - we could indicate to the TCP net layer to release * the connection -> other worker may read the next available * message on the pipe */ } else { LM_DBG("We still have things on the pipe - " "keeping connection \n"); } if( msg_buf[0] == 'H' && msg_buf[1] == 'E' && msg_buf[2] == 'P' ) { if ((hep_ctx = shm_malloc(sizeof(struct hep_context))) == NULL) { LM_ERR("no more shared memory!\n"); return -1; } memset(hep_ctx, 0, sizeof(struct hep_context)); memcpy(&hep_ctx->ri, &local_rcv, sizeof(struct receive_info)); /* HEP related */ if (unpack_hepv3(msg_buf, msg_len, &hep_ctx->h)) { LM_ERR("failed to unpack hepV3\n"); goto error_free_hep; } update_recv_info(&local_rcv, &hep_ctx->h); /* set context for receive_msg */ if ((ctx=context_alloc(CONTEXT_GLOBAL)) == NULL) { LM_ERR("failed to allocate new context! skipping...\n"); goto error_free_hep; } memset(ctx, 0, context_size(CONTEXT_GLOBAL)); context_put_ptr(CONTEXT_GLOBAL, ctx, hep_ctx_idx, hep_ctx); /* run hep callbacks; set the current processing context * to hep context; this way callbacks will have all the data * needed */ current_processing_ctx = ctx; ret=run_hep_cbs(); if (ret < 0) { LM_ERR("failed to run hep callbacks\n"); goto error_free_hep; } current_processing_ctx = NULL; msg_len = hep_ctx->h.u.hepv3.payload_chunk.chunk.length- sizeof(hep_chunk_t); /* remove the hep header; leave only the payload */ msg_buf = hep_ctx->h.u.hepv3.payload_chunk.data; } /* skip receive msg if we were told so from at least one callback */ if (ret != HEP_SCRIPT_SKIP && receive_msg(msg_buf, msg_len, &local_rcv, ctx) <0) LM_ERR("receive_msg failed \n"); if (!size && req != &hep_current_req) { /* if we no longer need this tcp_req * we can free it now */ pkg_free(req); } if (size) { memmove(req->buf, req->parsed, size); req->pos = req->buf + size; /* anything that was parsed was already processed */ req->parsed = req->buf; } /* if we still have some unparsed bytes, try to parse them too*/ if (size) return 1; } else { /* request not complete - check the if the thresholds are exceeded */ if (con->msg_attempts==0) /* if first iteration, set a short timeout for reading * a whole SIP message */ con->timeout = get_ticks() + tcp_max_msg_time; con->msg_attempts ++; if (con->msg_attempts == _max_msg_chunks) { LM_ERR("Made %u read attempts but message is not complete yet - " "closing connection \n",con->msg_attempts); goto error; } if (req == &hep_current_req) { /* let's duplicate this - most likely another conn will come in */ LM_DBG("We didn't manage to read a full request\n"); con->con_req = pkg_malloc(sizeof(struct tcp_req)); if (con->con_req == NULL) { LM_ERR("No more mem for dynamic con request buffer\n"); goto error; } if (req->pos != req->buf) { /* we have read some bytes */ memcpy(con->con_req->buf,req->buf,req->pos-req->buf); con->con_req->pos = con->con_req->buf + (req->pos-req->buf); } else { con->con_req->pos = con->con_req->buf; } if (req->parsed != req->buf) con->con_req->parsed =con->con_req->buf+(req->parsed-req->buf); else con->con_req->parsed = con->con_req->buf; con->con_req->complete=req->complete; con->con_req->content_len=req->content_len; con->con_req->error = req->error; /* req will be reset on the next usage */ } } /* everything ok */ return 0; error_free_hep: shm_free(hep_ctx); error: /* report error */ return -1; }
/*! \note WARNING: buf must be 0 terminated (buf[len]=0) or some things might * break (e.g.: modules/textops) */ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) { struct sip_msg* msg; struct timeval start; int rc; char *tmp; str in_buff; in_buff.len = len; in_buff.s = buf; /* the raw processing callbacks can change the buffer, further use in_buff.s and at the end try to free in_buff.s if changed by callbacks */ run_pre_raw_processing_cb(PRE_RAW_PROCESSING,&in_buff,NULL); /* update the length for further processing */ len = in_buff.len; msg=pkg_malloc(sizeof(struct sip_msg) + context_size(CONTEXT_MSG)); if (msg==0) { LM_ERR("no pkg mem left for sip_msg\n"); goto error; } msg_no++; /* number of vias parsed -- good for diagnostic info in replies */ via_cnt=0; memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */ /* fill in msg */ msg->buf=in_buff.s; msg->len=len; msg->rcv=*rcv_info; msg->id=msg_no; if (parse_msg(in_buff.s,len, msg)!=0){ tmp=ip_addr2a(&(rcv_info->src_ip)); LM_ERR("Unable to parse msg received from [%s:%d]\n", tmp, rcv_info->src_port); /* if a REQUEST msg was detected (first line was succesfully parsed) we should trigger the error route */ if ( msg->first_line.type==SIP_REQUEST && error_rlist.a!=NULL ) run_error_route(msg, 1); goto parse_error; } LM_DBG("After parse_msg...\n"); start_expire_timer(start,execmsgthreshold); /* ... clear branches from previous message */ clear_branches(); if (msg->first_line.type==SIP_REQUEST) { update_stat( rcv_reqs, 1); /* sanity checks */ if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){ /* no via, send back error ? */ LM_ERR("no via found in request\n"); update_stat( err_reqs, 1); goto parse_error; } /* check if necessary to add receive?->moved to forward_req */ /* check for the alias stuff */ #ifdef USE_TCP if (msg->via1->alias && tcp_accept_aliases && (((rcv_info->proto==PROTO_TCP) && !tcp_disable) #ifdef USE_TLS || ((rcv_info->proto==PROTO_TLS) && !tls_disable) #endif ) ){ if (tcpconn_add_alias(rcv_info->proto_reserved1, msg->via1->port, rcv_info->proto)!=0){ LM_ERR("tcp alias failed\n"); /* continue */ } } #endif LM_DBG("preparing to run routing scripts...\n"); /* set request route type --bogdan*/ set_route_type( REQUEST_ROUTE ); /* execute pre-script callbacks, if any; * if some of the callbacks said not to continue with * script processing, don't do so; * if we are here basic sanity checks are already done * (like presence of at least one via), so you can count * on via1 being parsed in a pre-script callback --andrei */ rc = exec_pre_req_cb(msg); if (rc == SCB_DROP_MSG) { update_stat( drp_reqs, 1); goto end; /* drop the message */ } /* exec the routing script */ if (rc & SCB_RUN_TOP_ROUTE) run_top_route(rlist[DEFAULT_RT].a, msg); /* execute post request-script callbacks */ if (rc & SCB_RUN_POST_CBS) exec_post_req_cb(msg); } else if (msg->first_line.type==SIP_REPLY) { update_stat( rcv_rpls, 1); /* sanity checks */ if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){ /* no via, send back error ? */ LM_ERR("no via found in reply\n"); update_stat( err_rpls, 1); goto parse_error; } /* set reply route type --bogdan*/ set_route_type( ONREPLY_ROUTE ); /* execute pre-script callbacks, if any ; * if some of the callbacks said not to continue with * script processing, don't do so ; * if we are here, basic sanity checks are already done * (like presence of at least one via), so you can count * on via1 being parsed in a pre-script callback --andrei */ rc = exec_pre_rpl_cb(msg); if (rc == SCB_DROP_MSG) { update_stat( drp_rpls, 1); goto end; /* drop the reply */ } /* exec the onreply routing script */ if (rc & SCB_RUN_TOP_ROUTE && onreply_rlist[DEFAULT_RT].a && (run_top_route(onreply_rlist[DEFAULT_RT].a,msg) & ACT_FL_DROP) && msg->REPLY_STATUS < 200) { LM_DBG("dropping provisional reply %d\n", msg->REPLY_STATUS); update_stat( drp_rpls, 1); goto end; /* drop the message */ } else { /* send the msg */ forward_reply(msg); /* TODO - TX reply stat */ } /* execute post reply-script callbacks */ if (rc & SCB_RUN_POST_CBS) exec_post_rpl_cb(msg); } end: stop_expire_timer( start, execmsgthreshold, "msg processing", msg->buf, msg->len, 0); reset_longest_action_list(execmsgthreshold); /* free possible loaded avps -bogdan */ reset_avps(); LM_DBG("cleaning up\n"); free_sip_msg(msg); pkg_free(msg); if (in_buff.s != buf) pkg_free(in_buff.s); return 0; parse_error: exec_parse_err_cb(msg); free_sip_msg(msg); pkg_free(msg); error: if (in_buff.s != buf) pkg_free(in_buff.s); return -1; }