Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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");
}
Exemplo n.º 3
0
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;

}
Exemplo n.º 4
0
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;

}
Exemplo n.º 5
0
/*! \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;
}