Exemplo n.º 1
0
static int ws_process_msg(char* tcpbuf, unsigned int len,
		struct receive_info* rcv_info, struct tcp_connection* con)
{
	int ret;
	tcp_event_info_t tev;

	ret = 0;
	LM_DBG("WebSocket Message: [[>>>\n%.*s<<<]]\n", len, tcpbuf);
	if(likely(sr_event_enabled(SREV_TCP_WS_FRAME_IN))) {
		memset(&tev, 0, sizeof(tcp_event_info_t));
		tev.type = SREV_TCP_WS_FRAME_IN;
		tev.buf = tcpbuf;
		tev.len = len;
		tev.rcv = rcv_info;
		tev.con = con;
		ret = sr_event_exec(SREV_TCP_WS_FRAME_IN, (void*)(&tev));
	} else {
		LM_DBG("no callback registering for handling WebSockets - dropping!\n");
	}
	return ret;
}
Exemplo n.º 2
0
static int mod_init(void)
{
	if (sl_load_api(&ws_slb) != 0)
	{
		LM_ERR("binding to SL\n");
		goto error;
	}

	if (sr_event_register_cb(SREV_TCP_WS_FRAME_IN, ws_frame_receive) != 0)
	{
		LM_ERR("registering WebSocket receive call-back\n");
		goto error;
	}

	if (sr_event_register_cb(SREV_TCP_WS_FRAME_OUT, ws_frame_transmit) != 0)
	{
		LM_ERR("registering WebSocket transmit call-back\n");
		goto error;
	}

	if (register_module_stats(exports.name, stats) != 0)
	{
		LM_ERR("registering core statistics\n");
		goto error;
	}

	if (register_mi_mod(exports.name, mi_cmds) != 0)
	{
		LM_ERR("registering MI commands\n");
		goto error;
	}

	if (wsconn_init() < 0)
	{
		LM_ERR("initialising WebSocket connections table\n");
		goto error;
	}

	if (ws_ping_application_data.len < 1
		|| ws_ping_application_data.len > 125)
	{
		ws_ping_application_data.s = DEFAULT_PING_APPLICATION_DATA + 8;
		ws_ping_application_data.len =
					DEFAULT_PING_APPLICATION_DATA_LEN - 8;
	}

	if (ws_keepalive_mechanism != KEEPALIVE_MECHANISM_NONE)
	{
		if (ws_keepalive_timeout < 1 || ws_keepalive_timeout > 3600)
			ws_keepalive_timeout = DEFAULT_KEEPALIVE_TIMEOUT;

		switch(ws_keepalive_mechanism)
		{
		case KEEPALIVE_MECHANISM_PING:
		case KEEPALIVE_MECHANISM_PONG:
			break;
		default:
			ws_keepalive_mechanism = DEFAULT_KEEPALIVE_MECHANISM;
			break;
		}

		if (ws_keepalive_interval < 1 || ws_keepalive_interval > 60)
			ws_keepalive_interval = DEFAULT_KEEPALIVE_INTERVAL;

		if (ws_keepalive_processes < 1 || ws_keepalive_processes > 16)
			ws_keepalive_processes = DEFAULT_KEEPALIVE_PROCESSES;

		/* Add extra process/timer for the keepalive process */
		register_sync_timers(ws_keepalive_processes);
	}

	if (ws_sub_protocols & SUB_PROTOCOL_MSRP
		&& !sr_event_enabled(SREV_TCP_MSRP_FRAME))
		ws_sub_protocols &= ~SUB_PROTOCOL_MSRP;

	if ((ws_sub_protocols & SUB_PROTOCOL_ALL) == 0)
	{
		LM_ERR("no sub-protocols enabled\n");
		goto error;
	}

	if ((ws_sub_protocols | SUB_PROTOCOL_ALL) != SUB_PROTOCOL_ALL)
	{
		LM_ERR("unrecognised sub-protocols enabled\n");
		goto error;
	}

	if (ws_cors_mode < 0 || ws_cors_mode > 2)
	{
		LM_ERR("bad value for cors_mode\n");
		goto error;
	}

	if (cfg_declare("websocket", ws_cfg_def, &default_ws_cfg,
			cfg_sizeof(websocket), &ws_cfg))
	{
		LM_ERR("declaring configuration\n");
		return -1;
	}
	cfg_get(websocket, ws_cfg, keepalive_timeout) = ws_keepalive_timeout;

	if (!module_loaded("xhttp"))
	{
		LM_ERR("\"xhttp\" must be loaded to use WebSocket.\n");
		return -1;
	}

	if (((ws_sub_protocols & SUB_PROTOCOL_SIP) == SUB_PROTOCOL_SIP)
			&& !module_loaded("nathelper")
			&& !module_loaded("outbound"))
	{
		LM_WARN("neither \"nathelper\" nor \"outbound\" modules are"
			" loaded. At least one of these is required for correct"
			" routing of SIP over WebSocket.\n");
	}

	return 0;

error:
	wsconn_destroy();
	return -1;
}
Exemplo n.º 3
0
/** Receive message
 *  WARNING: buf must be 0 terminated (buf[len]=0) or some things might
 * break (e.g.: modules/textops)
 */
int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info)
{
	struct sip_msg* msg;
	struct run_act_ctx ctx;
	int ret;
#ifdef STATS
	int skipped = 1;
	struct timeval tvb, tve;
	struct timezone tz;
	unsigned int diff;
#endif
	str inb;
	sr_net_info_t netinfo;

	if(sr_event_enabled(SREV_NET_DATA_RECV)) {
		if(sip_check_fline(buf, len)==0) {
			memset(&netinfo, 0, sizeof(sr_net_info_t));
			netinfo.data.s = buf;
			netinfo.data.len = len;
			netinfo.rcv = rcv_info;
			sr_event_exec(SREV_NET_DATA_RECV, (void*)&netinfo);
		}
	}

	inb.s = buf;
	inb.len = len;
	sr_event_exec(SREV_NET_DATA_IN, (void*)&inb);
	len = inb.len;

	msg=pkg_malloc(sizeof(struct sip_msg));
	if (msg==0) {
		LM_ERR("no mem for sip_msg\n");
		goto error00;
	}
	msg_no++;
	/* number of vias parsed -- good for diagnostic info in replies */
	via_cnt=0;

	memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */
	/* fill in msg */
	msg->buf=buf;
	msg->len=len;
	/* zero termination (termination of orig message bellow not that
	 * useful as most of the work is done with scratch-pad; -jiri  */
	/* buf[len]=0; */ /* WARNING: zero term removed! */
	msg->rcv=*rcv_info;
	msg->id=msg_no;
	msg->pid=my_pid();
	msg->set_global_address=default_global_address;
	msg->set_global_port=default_global_port;

	if(likely(sr_msg_time==1)) msg_set_time(msg);

	if (parse_msg(buf,len, msg)!=0){
		if(sr_event_exec(SREV_RCV_NOSIP, (void*)msg)!=0) {
			LOG(cfg_get(core, core_cfg, corelog),
				"core parsing of SIP message failed (%s:%d/%d)\n",
				ip_addr2a(&msg->rcv.src_ip), (int)msg->rcv.src_port,
				(int)msg->rcv.proto);
			sr_core_ert_run(msg, SR_CORE_ERT_RECEIVE_PARSE_ERROR);
		}
		goto error02;
	}
	LM_DBG("After parse_msg...\n");

	/* set log prefix */
	log_prefix_set(msg);

	/* ... clear branches from previous message */
	clear_branches();

	if (msg->first_line.type==SIP_REQUEST){
		ruri_mark_new(); /* ruri is usable for forking (not consumed yet) */
		if (!IS_SIP(msg)){
			if ((ret=nonsip_msg_run_hooks(msg))!=NONSIP_MSG_ACCEPT){
				if (unlikely(ret==NONSIP_MSG_ERROR))
					goto error03;
				goto end; /* drop the message */
			}
		}
		/* sanity checks */
		if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
			/* no via, send back error ? */
			LM_ERR("no via found in request\n");
			STATS_BAD_MSG();
			goto error02;
		}
		/* check if necessary to add receive?->moved to forward_req */
		/* check for the alias stuff */
#ifdef USE_TCP
		if (msg->via1->alias && cfg_get(tcp, tcp_cfg, accept_aliases) &&
				(((rcv_info->proto==PROTO_TCP) && !tcp_disable)
#ifdef USE_TLS
					|| ((rcv_info->proto==PROTO_TLS) && !tls_disable)
#endif
				)
			){
			if (tcpconn_add_alias(rcv_info->proto_reserved1, msg->via1->port,
									rcv_info->proto)!=0){
				LM_ERR("tcp alias failed\n");
				/* continue */
			}
		}
#endif

	/*	skip: */
		LM_DBG("preparing to run routing scripts...\n");
#ifdef  STATS
		gettimeofday( & tvb, &tz );
#endif
		/* execute pre-script callbacks, if any; -jiri */
		/* if some of the callbacks said not to continue with
		 * script processing, don't do so
		 * if we are here basic sanity checks are already done
		 * (like presence of at least one via), so you can count
		 * on via1 being parsed in a pre-script callback --andrei
		*/
		if (exec_pre_script_cb(msg, REQUEST_CB_TYPE)==0 )
		{
			STATS_REQ_FWD_DROP();
			goto end; /* drop the request */
		}

		set_route_type(REQUEST_ROUTE);
		/* exec the routing script */
		if (run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0)<0){
			LM_WARN("error while trying script\n");
			goto error_req;
		}

#ifdef STATS
		gettimeofday( & tve, &tz );
		diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
		stats->processed_requests++;
		stats->acc_req_time += diff;
		LM_DBG("successfully ran routing scripts...(%d usec)\n", diff);
		STATS_RX_REQUEST( msg->first_line.u.request.method_value );
#endif

		/* execute post request-script callbacks */
		exec_post_script_cb(msg, REQUEST_CB_TYPE);
	}else if (msg->first_line.type==SIP_REPLY){
		/* sanity checks */
		if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
			/* no via, send back error ? */
			LM_ERR("no via found in reply\n");
			STATS_BAD_RPL();
			goto error02;
		}

#ifdef STATS
		gettimeofday( & tvb, &tz );
		STATS_RX_RESPONSE ( msg->first_line.u.reply.statuscode / 100 );
#endif

		/* execute pre-script callbacks, if any; -jiri */
		/* if some of the callbacks said not to continue with
		 * script processing, don't do so
		 * if we are here basic sanity checks are already done
		 * (like presence of at least one via), so you can count
		 * on via1 being parsed in a pre-script callback --andrei
		*/
		if (exec_pre_script_cb(msg, ONREPLY_CB_TYPE)==0 )
		{
			STATS_RPL_FWD_DROP();
			goto end; /* drop the reply */
		}

		/* exec the onreply routing script */
		if (onreply_rt.rlist[DEFAULT_RT]){
			set_route_type(CORE_ONREPLY_ROUTE);
			ret=run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, &ctx);
#ifndef NO_ONREPLY_ROUTE_ERROR
			if (unlikely(ret<0)){
				LM_WARN("error while trying onreply script\n");
				goto error_rpl;
			}else
#endif /* NO_ONREPLY_ROUTE_ERROR */
			if (unlikely(ret==0 || (ctx.run_flags&DROP_R_F))){
				STATS_RPL_FWD_DROP();
				goto skip_send_reply; /* drop the message, no error */
			}
		}
		/* send the msg */
		forward_reply(msg);
	skip_send_reply:
#ifdef STATS
		gettimeofday( & tve, &tz );
		diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
		stats->processed_responses++;
		stats->acc_res_time+=diff;
		LM_DBG("successfully ran reply processing...(%d usec)\n", diff);
#endif

		/* execute post reply-script callbacks */
		exec_post_script_cb(msg, ONREPLY_CB_TYPE);
	}

end:
#ifdef STATS
	skipped = 0;
#endif
	/* free possible loaded avps -bogdan */
	reset_avps();
#ifdef WITH_XAVP
	xavp_reset_list();
#endif
	LM_DBG("cleaning up\n");
	free_sip_msg(msg);
	pkg_free(msg);
#ifdef STATS
	if (skipped) STATS_RX_DROPS;
#endif
	/* reset log prefix */
	log_prefix_set(NULL);
	return 0;

#ifndef NO_ONREPLY_ROUTE_ERROR
error_rpl:
	/* execute post reply-script callbacks */
	exec_post_script_cb(msg, ONREPLY_CB_TYPE);
	reset_avps();
#ifdef WITH_XAVP
	xavp_reset_list();
#endif
	goto error02;
#endif /* NO_ONREPLY_ROUTE_ERROR */
error_req:
	LM_DBG("error:...\n");
	/* execute post request-script callbacks */
	exec_post_script_cb(msg, REQUEST_CB_TYPE);
error03:
	/* free possible loaded avps -bogdan */
	reset_avps();
#ifdef WITH_XAVP
	xavp_reset_list();
#endif
error02:
	free_sip_msg(msg);
	pkg_free(msg);
error00:
	STATS_RX_DROPS;
	/* reset log prefix */
	log_prefix_set(NULL);
	return -1;
}
Exemplo n.º 4
0
/* reads all headers (until double crlf), & parses the content-length header
 * (WARNING: inefficient, tries to reuse receive_msg but will go through
 * the headers twice [once here looking for Content-Length and for the end
 * of the headers and once in receive_msg]; a more speed efficient version will
 * result in either major code duplication or major changes to the receive code)
 * returns number of bytes read & sets r->state & r->body
 * when either r->body!=0 or r->state==H_BODY =>
 * all headers have been read. It should be called in a while loop.
 * returns < 0 if error or 0 if EOF */
int tcp_read_headers(struct tcp_connection *c, int* read_flags)
{
	int bytes, remaining;
	char *p;
	struct tcp_req* r;
	unsigned int mc;   /* magic cookie */
	unsigned short body_len;

#ifdef READ_MSRP
	char *mfline;
	str mtransid;
#endif

	#define crlf_default_skip_case \
					case '\n': \
						r->state=H_LF; \
						break; \
					default: \
						r->state=H_SKIP
	
	#define content_len_beg_case \
					case ' ': \
					case '\t': \
						if (!TCP_REQ_HAS_CLEN(r)) r->state=H_STARTWS; \
						else r->state=H_SKIP; \
							/* not interested if we already found one */ \
						break; \
					case 'C': \
					case 'c': \
						if(!TCP_REQ_HAS_CLEN(r)) r->state=H_CONT_LEN1; \
						else r->state=H_SKIP; \
						break; \
					case 'l': \
					case 'L': \
						/* short form for Content-Length */ \
						if (!TCP_REQ_HAS_CLEN(r)) r->state=H_L_COLON; \
						else r->state=H_SKIP; \
						break
						
	#define change_state(upper, lower, newstate)\
					switch(*p){ \
						case upper: \
						case lower: \
							r->state=(newstate); break; \
						crlf_default_skip_case; \
					}
	
	#define change_state_case(state0, upper, lower, newstate)\
					case state0: \
							  change_state(upper, lower, newstate); \
							  p++; \
							  break


	r=&c->req;
	/* if we still have some unparsed part, parse it first, don't do the read*/
	if (unlikely(r->parsed<r->pos)){
		bytes=0;
	}else{
#ifdef USE_TLS
		if (unlikely(c->type==PROTO_TLS))
			bytes=tls_read(c, read_flags);
		else
#endif
			bytes=tcp_read(c, read_flags);
		if (bytes<=0) return bytes;
	}
	p=r->parsed;

	while(p<r->pos && r->error==TCP_REQ_OK){
		switch((unsigned char)r->state){
			case H_BODY: /* read the body*/
				remaining=r->pos-p;
				if (remaining>r->bytes_to_go) remaining=r->bytes_to_go;
				r->bytes_to_go-=remaining;
				p+=remaining;
				if (r->bytes_to_go==0){
					r->flags|=F_TCP_REQ_COMPLETE;
					goto skip;
				}
				break;
				
			case H_SKIP:
				/* find lf, we are in this state if we are not interested
				 * in anything till end of line*/
				p=q_memchr(p, '\n', r->pos-p);
				if (p){
#ifdef READ_MSRP
					/* catch if it is MSRP or not with first '\n' */
					if(!((r->flags&F_TCP_REQ_MSRP_NO)
								|| (r->flags&F_TCP_REQ_MSRP_FRAME))) {
						if((r->pos - r->start)>5
									&& strncmp(r->start, "MSRP ", 5)==0)
						{
							r->flags |= F_TCP_REQ_MSRP_FRAME;
						} else {
							r->flags |= F_TCP_REQ_MSRP_NO;
						}
					}
#endif
					p++;
					r->state=H_LF;
				}else{
					p=r->pos;
				}
				break;
				
			case H_LF:
				/* terminate on LF CR LF or LF LF */
				switch (*p){
					case '\r':
						r->state=H_LFCR;
						break;
					case '\n':
						/* found LF LF */
						r->state=H_BODY;
#ifdef READ_HTTP11
						if (cfg_get(tcp, tcp_cfg, accept_no_cl)!=0)
							tcp_http11_continue(c);
#endif
						if (TCP_REQ_HAS_CLEN(r)){
							r->body=p+1;
							r->bytes_to_go=r->content_len;
							if (r->bytes_to_go==0){
								r->flags|=F_TCP_REQ_COMPLETE;
								p++;
								goto skip;
							}
						}else{
							if(cfg_get(tcp, tcp_cfg, accept_no_cl)!=0) {
#ifdef READ_MSRP
								/* if MSRP message */
								if(c->req.flags&F_TCP_REQ_MSRP_FRAME)
								{
									r->body=p+1;
									/* at least 3 bytes: 0\r\n */
									r->bytes_to_go=3;
									p++;
									r->content_len = 0;
									r->state=H_MSRP_BODY;
									break;
								}
#endif

#ifdef READ_HTTP11
								if(TCP_REQ_BCHUNKED(r)) {
									r->body=p+1;
									/* at least 3 bytes: 0\r\n */
									r->bytes_to_go=3;
									p++;
									r->content_len = 0;
									r->state=H_HTTP11_CHUNK_START;
									break;
								}
#endif
								r->body=p+1;
								r->bytes_to_go=0;
								r->flags|=F_TCP_REQ_COMPLETE;
								p++;
								goto skip;
							} else {
								LM_DBG("ERROR: no clen, p=%X\n", *p);
								r->error=TCP_REQ_BAD_LEN;
							}
						}
						break;
					case '-':
						r->state=H_SKIP;
#ifdef READ_MSRP
						/* catch end of MSRP frame without body
						 *     '-------sessid$\r\n'
						 * follows headers wihtout extra CRLF */
						if(r->flags&F_TCP_REQ_MSRP_FRAME) {
							p--;
							r->state=H_MSRP_BODY_END;
						}
#endif
						break;
					content_len_beg_case;
					default: 
						r->state=H_SKIP;
				}
				p++;
				break;
			case H_LFCR:
				if (*p=='\n'){
					/* found LF CR LF */
					r->state=H_BODY;
#ifdef READ_HTTP11
					if (cfg_get(tcp, tcp_cfg, accept_no_cl)!=0)
						tcp_http11_continue(c);
#endif
					if (TCP_REQ_HAS_CLEN(r)){
						r->body=p+1;
						r->bytes_to_go=r->content_len;
						if (r->bytes_to_go==0){
							r->flags|=F_TCP_REQ_COMPLETE;
							p++;
							goto skip;
						}
					}else{
						if (cfg_get(tcp, tcp_cfg, accept_no_cl)!=0) {
#ifdef READ_MSRP
							/* if MSRP message */
							if(c->req.flags&F_TCP_REQ_MSRP_FRAME)
							{
								r->body=p+1;
								/* at least 3 bytes: 0\r\n */
								r->bytes_to_go=3;
								p++;
								r->content_len = 0;
								r->state=H_MSRP_BODY;
								break;
							}
#endif

#ifdef READ_HTTP11
							if(TCP_REQ_BCHUNKED(r)) {
								r->body=p+1;
								/* at least 3 bytes: 0\r\n */
								r->bytes_to_go=3;
								p++;
								r->content_len = 0;
								r->state=H_HTTP11_CHUNK_START;
								break;
							}
#endif
							r->body=p+1;
							r->bytes_to_go=0;
							r->flags|=F_TCP_REQ_COMPLETE;
							p++;
							goto skip;
						} else {
							LM_DBG("ERROR: no clen, p=%X\n", *p);
							r->error=TCP_REQ_BAD_LEN;
						}
					}
				}else r->state=H_SKIP;
				p++;
				break;
				
			case H_STARTWS:
				switch (*p){
					content_len_beg_case;
					crlf_default_skip_case;
				}
				p++;
				break;
			case H_SKIP_EMPTY:
				switch (*p){
					case '\n':
						break;
					case '\r':
						if (cfg_get(tcp, tcp_cfg, crlf_ping)) {
							r->state=H_SKIP_EMPTY_CR_FOUND;
							r->start=p;
						}
						break;
					case ' ':
					case '\t':
						/* skip empty lines */
						break;
					case 'C': 
					case 'c': 
						r->state=H_CONT_LEN1; 
						r->start=p;
						break;
					case 'l':
					case 'L':
						/* short form for Content-Length */
						r->state=H_L_COLON;
						r->start=p;
						break;
					default:
						/* stun test */						
						if (unlikely(sr_event_enabled(SREV_STUN_IN)) && (unsigned char)*p == 0x00) {
							r->state=H_STUN_MSG;
						/* body will used as pointer to the last used byte */
							r->body=p;
							r->content_len = 0;
							LM_DBG("stun msg detected\n");
						} else {
							r->state=H_SKIP;
						}
						r->start=p;
				};
				p++;
				break;

			case H_SKIP_EMPTY_CR_FOUND:
				if (*p=='\n'){
					r->state=H_SKIP_EMPTY_CRLF_FOUND;
					p++;
				}else{
					r->state=H_SKIP_EMPTY;
				}
				break;

			case H_SKIP_EMPTY_CRLF_FOUND:
				if (*p=='\r'){
					r->state = H_SKIP_EMPTY_CRLFCR_FOUND;
					p++;
				}else{
					r->state = H_SKIP_EMPTY;
				}
				break;

			case H_SKIP_EMPTY_CRLFCR_FOUND:
				if (*p=='\n'){
					r->state = H_PING_CRLF;
					r->flags |= F_TCP_REQ_HAS_CLEN |
							F_TCP_REQ_COMPLETE; /* hack to avoid error check */
					p++;
					goto skip;
				}else{
					r->state = H_SKIP_EMPTY;
				}
				break;

			case H_STUN_MSG:
				if ((r->pos - r->body) >= sizeof(struct stun_hdr)) {
					/* copy second short from buffer where should be body 
					 * length 
					 */
					memcpy(&body_len, &r->start[sizeof(unsigned short)], 
						sizeof(unsigned short));
					
					body_len = ntohs(body_len);
					
					/* check if there is valid magic cookie */
					memcpy(&mc, &r->start[sizeof(unsigned int)], 
						sizeof(unsigned int));
					mc = ntohl(mc);
					/* using has_content_len as a flag if there should be
					 * fingerprint or no
					 */
					r->flags |= (mc == MAGIC_COOKIE) ? F_TCP_REQ_HAS_CLEN : 0;
					
					r->body += sizeof(struct stun_hdr);
					p = r->body; 
					
					if (body_len > 0) {
						r->state = H_STUN_READ_BODY;
					}
					else {
						if (is_msg_complete(r) != 0) {
							goto skip;
						}
						else {
							/* set content_len to length of fingerprint */
							body_len = sizeof(struct stun_attr) + 20;
							/* 20 is SHA_DIGEST_LENGTH from openssl/sha.h */
						}
					}
					r->content_len=body_len;
				}
				else {
					p = r->pos; 
				}
				break;
				
			case H_STUN_READ_BODY:
				/* check if the whole body was read */
				body_len=r->content_len;
				if ((r->pos - r->body) >= body_len) {
					r->body += body_len;
					p = r->body;
					if (is_msg_complete(r) != 0) {
						r->content_len=0;
						goto skip;
					}
					else {
						/* set content_len to length of fingerprint */
						body_len = sizeof(struct stun_attr) + 20;
						/* 20 is SHA_DIGEST_LENGTH from openssl/sha.h */
						r->content_len=body_len;
					}
				}
				else {
					p = r->pos;
				}
				break;
				
			case H_STUN_FP:
				/* content_len contains length of fingerprint in this place! */
				body_len=r->content_len;
				if ((r->pos - r->body) >= body_len) {
					r->body += body_len;
					p = r->body;
					r->state = H_STUN_END;
					r->flags |= F_TCP_REQ_COMPLETE |
						F_TCP_REQ_HAS_CLEN; /* hack to avoid error check */
					r->content_len=0;
					goto skip;
				}
				else {
					p = r->pos;
				}
				break;

			change_state_case(H_CONT_LEN1,  'O', 'o', H_CONT_LEN2);
			change_state_case(H_CONT_LEN2,  'N', 'n', H_CONT_LEN3);
			change_state_case(H_CONT_LEN3,  'T', 't', H_CONT_LEN4);
			change_state_case(H_CONT_LEN4,  'E', 'e', H_CONT_LEN5);
			change_state_case(H_CONT_LEN5,  'N', 'n', H_CONT_LEN6);
			change_state_case(H_CONT_LEN6,  'T', 't', H_CONT_LEN7);
			change_state_case(H_CONT_LEN7,  '-', '_', H_CONT_LEN8);
			change_state_case(H_CONT_LEN8,  'L', 'l', H_CONT_LEN9);
			change_state_case(H_CONT_LEN9,  'E', 'e', H_CONT_LEN10);
			change_state_case(H_CONT_LEN10, 'N', 'n', H_CONT_LEN11);
			change_state_case(H_CONT_LEN11, 'G', 'g', H_CONT_LEN12);
			change_state_case(H_CONT_LEN12, 'T', 't', H_CONT_LEN13);
			change_state_case(H_CONT_LEN13, 'H', 'h', H_L_COLON);

			case H_L_COLON:
				switch(*p){
					case ' ':
					case '\t':
						break; /* skip space */
					case ':':
						r->state=H_CONT_LEN_BODY;
						break;
					crlf_default_skip_case;
				};
				p++;
				break;

			case  H_CONT_LEN_BODY:
				switch(*p){
					case ' ':
					case '\t':
						break; /* eat space */
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						r->state=H_CONT_LEN_BODY_PARSE;
						r->content_len=(*p-'0');
						break;
					/*FIXME: content length on different lines ! */
					crlf_default_skip_case;
				}
				p++;
				break;

			case H_CONT_LEN_BODY_PARSE:
				switch(*p){
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						r->content_len=r->content_len*10+(*p-'0');
						break;
					case '\r':
					case ' ':
					case '\t': /* FIXME: check if line contains only WS */
						if(r->content_len<0) {
							LM_ERR("bad Content-Length header value %d in"
									" state %d\n", r->content_len, r->state);
							r->content_len=0;
							r->error=TCP_REQ_BAD_LEN;
							r->state=H_SKIP; /* skip now */
						}
						r->state=H_SKIP;
						r->flags|=F_TCP_REQ_HAS_CLEN;
						break;
					case '\n':
						/* end of line, parse successful */
						if(r->content_len<0) {
							LM_ERR("bad Content-Length header value %d in"
									" state %d\n", r->content_len, r->state);
							r->content_len=0;
							r->error=TCP_REQ_BAD_LEN;
							r->state=H_SKIP; /* skip now */
						}
						r->state=H_LF;
						r->flags|=F_TCP_REQ_HAS_CLEN;
						break;
					default:
						LM_ERR("bad Content-Length header value, unexpected "
								"char %c in state %d\n", *p, r->state);
						r->state=H_SKIP; /* try to find another?*/
				}
				p++;
				break;
			
#ifdef READ_HTTP11
			case H_HTTP11_CHUNK_START: /* start a new body chunk: SIZE\r\nBODY\r\n */
				r->chunk_size = 0;
				r->state = H_HTTP11_CHUNK_SIZE;
				break;
			case H_HTTP11_CHUNK_BODY: /* content of chunnk */
				remaining=r->pos-p;
				if (remaining>r->bytes_to_go) remaining=r->bytes_to_go;
				r->bytes_to_go-=remaining;
				p+=remaining;
				if (r->bytes_to_go==0){
					r->state = H_HTTP11_CHUNK_END;
					/* shift back body content */
					if(r->chunk_size>0 && p-r->chunk_size>r->body) {
						memmove(r->body + r->content_len, p - r->chunk_size,
								r->chunk_size);
						r->content_len += r->chunk_size;
					}
					goto skip;
				}
				break;

			case H_HTTP11_CHUNK_END:
				switch(*p){
					case '\r':
					case ' ':
					case '\t': /* skip */
						break;
					case '\n':
						r->state = H_HTTP11_CHUNK_START;
						break;
					default:
						LM_ERR("bad chunk, unexpected "
								"char %c in state %d\n", *p, r->state);
						r->state=H_SKIP; /* try to find another?*/
				}
				p++;
				break;

			case H_HTTP11_CHUNK_SIZE:
				switch(*p){
					case '0': case '1': case '2': case '3':
					case '4': case '5': case '6': case '7':
					case '8': case '9':
						r->chunk_size <<= 4;
						r->chunk_size += *p - '0';
						break;
					case 'a': case 'b': case 'c': case 'd':
					case 'e': case 'f':
						r->chunk_size <<= 4;
						r->chunk_size += *p - 'a' + 10;
						break;
					case 'A': case 'B': case 'C': case 'D':
					case 'E': case 'F':
						r->chunk_size <<= 4;
						r->chunk_size += *p - 'A' + 10;
						break;
					case '\r':
					case ' ':
					case '\t': /* skip */
						break;
					case '\n':
						/* end of line, parse successful */
						r->state=H_HTTP11_CHUNK_BODY;
						r->bytes_to_go = r->chunk_size;
						if (r->bytes_to_go==0){
							r->state=H_HTTP11_CHUNK_FINISH;
							r->flags|=F_TCP_REQ_COMPLETE;
							p++;
							goto skip;
						}
						break;
					default:
						LM_ERR("bad chunk size value, unexpected "
								"char %c in state %d\n", *p, r->state);
						r->state=H_SKIP; /* try to find another?*/
				}
				p++;
				break;
#endif
#ifdef READ_MSRP
			case H_MSRP_BODY: /* body of msrp frame */
				/* find lf, we are in this state if we are not interested
				 * in anything till end of line*/
				r->flags |= F_TCP_REQ_MSRP_BODY;
				p = q_memchr(p, '\n', r->pos-p);
				if (p) {
					p++;
					r->state=H_MSRP_BODY_LF;
				} else {
					p=r->pos;
				}
				break;
			case H_MSRP_BODY_LF: /* LF in body of msrp frame */
				switch (*p) {
					case '-':
							p--;
							r->state=H_MSRP_BODY_END;
						break;
					default:
						r->state=H_MSRP_BODY;
				}
				p++;
				break;
			case H_MSRP_BODY_END: /* end of body for msrp frame */
				/* find LF and check if it is end-line */
				p = q_memchr(p, '\n', r->pos-p);
				if (p) {
					/* check if it is end line '-------sessid$\r\n' */
					if(r->pos - r->start < 10) {
						LM_ERR("weird situation when reading MSRP frame"
								" - continue reading\n");
						/* *p=='\n' */
						r->state=H_MSRP_BODY_LF;
						p++;
						break;
					}
					if(*(p-1)!='\r') {
						/* not ending in '\r\n' - not end-line */
						/* *p=='\n' */
						r->state=H_MSRP_BODY_LF;
						p++;
						break;
					}
					/* locate transaction id in first line
					 * -- first line exists, that's why we are here */
					mfline =  q_memchr(r->start, '\n', r->pos-r->start);
					mtransid.s = q_memchr(r->start + 5 /* 'MSRP ' */, ' ',
							mfline - r->start);
					mtransid.len = mtransid.s - r->start - 5;
					mtransid.s = r->start + 5;
					trim(&mtransid);
					if(memcmp(mtransid.s,
							p - 1 /*\r*/ - 1 /* '+'|'#'|'$' */ - mtransid.len,
							mtransid.len)!=0) {
						/* no match on session id - not end-line */
						/* *p=='\n' */
						r->state=H_MSRP_BODY_LF;
						p++;
						break;
					}
					if(memcmp(p - 1 /*\r*/ - 1 /* '+'|'#'|'$' */ - mtransid.len
								- 7 /* 7 x '-' */ - 1 /* '\n' */, "\n-------",
								8)!=0) {
						/* no match on "\n-------" - not end-line */
						/* *p=='\n' */
						r->state=H_MSRP_BODY_LF;
						p++;
						break;
					}
					r->state=H_MSRP_FINISH;
					r->flags|=F_TCP_REQ_COMPLETE;
					p++;
					goto skip;

				} else {
					p=r->pos;
				}
				break;
#endif

			default:
				LM_CRIT("unexpected state %d\n", r->state);
				abort();
		}
	}
skip:
	r->parsed=p;
	return bytes;
}
Exemplo n.º 5
0
int msrp_relay(msrp_frame_t *mf)
{
	struct dest_info *dst;
	struct tcp_connection *con = NULL;
	char reqbuf[MSRP_MAX_FRAME_SIZE];
	msrp_hdr_t *tpath;
	msrp_hdr_t *fpath;
	msrp_env_t *env;
	str_array_t *sar;
	char *p;
	char *l;
	int port;

	if(mf->buf.len>=MSRP_MAX_FRAME_SIZE-1)
		return -1;

	tpath = msrp_get_hdr_by_id(mf, MSRP_HDR_TO_PATH);
	if(tpath==NULL)
	{
		LM_ERR("To-Path header not found\n");
		return -1;
	}
	fpath = msrp_get_hdr_by_id(mf, MSRP_HDR_FROM_PATH);
	if(fpath==NULL)
	{
		LM_ERR("From-Path header not found\n");
		return -1;
	}

	l = q_memchr(tpath->body.s, ' ', tpath->body.len);
	if(l==NULL)
	{
		LM_DBG("To-Path has only one URI -- nowehere to forward\n");
		return -1;
	}

	p = reqbuf;

	memcpy(p, mf->buf.s, tpath->body.s - mf->buf.s);
	p += tpath->body.s - mf->buf.s;

	memcpy(p, l + 1, fpath->body.s - l - 1);
	p += fpath->body.s - l - 1;

	memcpy(p, tpath->body.s, l + 1 - tpath->body.s);
	p += l + 1 - tpath->body.s;

	memcpy(p, fpath->name.s + 11, mf->buf.s + mf->buf.len - fpath->name.s - 11);
	p += mf->buf.s + mf->buf.len - fpath->name.s - 11;

	env = msrp_get_env();
	if(env->envflags&MSRP_ENV_DSTINFO)
	{
		dst = &env->dstinfo;
		goto done;
	}
	if(msrp_parse_hdr_to_path(mf)<0)
	{
		LM_ERR("error parsing To-Path header\n");
		return -1;
	}
	sar = (str_array_t*)tpath->parsed.data;
	if(sar==NULL || sar->size<2)
	{
		LM_DBG("To-Path has no next hop URI -- nowehere to forward\n");
		return -1;
	}
	if(msrp_env_set_dstinfo(mf, &sar->list[1], NULL, 0)<0)
	{
		LM_ERR("unable to set destination address\n");
		return -1;
	}
	dst = &env->dstinfo;
done:
	if (dst->send_flags.f & SND_F_FORCE_CON_REUSE)
	{
		port = su_getport(&dst->to);
		if (likely(port))
		{
			ticks_t con_lifetime;
			struct ip_addr ip;

			con_lifetime = cfg_get(tcp, tcp_cfg, con_lifetime);
			su2ip_addr(&ip, &dst->to);
			con = tcpconn_get(dst->id, &ip, port, NULL, con_lifetime);
		}
		else if (likely(dst->id))
		{
			con = tcpconn_get(dst->id, 0, 0, 0, 0);
		}

		if (con == NULL)
		{
			LM_WARN("TCP/TLS connection not found\n");
			return -1;
		}
	
		if (unlikely((con->rcv.proto == PROTO_WS || con->rcv.proto == PROTO_WSS)
				&& sr_event_enabled(SREV_TCP_WS_FRAME_OUT))) {
			ws_event_info_t wsev;

			memset(&wsev, 0, sizeof(ws_event_info_t));
			wsev.type = SREV_TCP_WS_FRAME_OUT;
			wsev.buf = reqbuf;
			wsev.len = p - reqbuf;
			wsev.id = con->id;
			return sr_event_exec(SREV_TCP_WS_FRAME_OUT, (void *) &wsev);
		}
		else if (tcp_send(dst, 0, reqbuf, p - reqbuf) < 0) {
			LM_ERR("forwarding frame failed\n");
			return -1;
		}
	}
	else if (tcp_send(dst, 0, reqbuf, p - reqbuf) < 0) {
			LM_ERR("forwarding frame failed\n");
			return -1;
	}

	return 0;
}
Exemplo n.º 6
0
int msrp_reply(msrp_frame_t *mf, str *code, str *text, str *xhdrs)
{
	char rplbuf[MSRP_MAX_FRAME_SIZE];
	msrp_hdr_t *hdr;
	msrp_env_t *env;
	char *p;
	char *l;

	/* no reply for a reply */
	if(mf->fline.msgtypeid==MSRP_REPLY)
		return 0;

	if(mf->fline.msgtypeid==MSRP_REQ_REPORT)
	{
		/* it does not take replies */
		return 0;
	}

	p = rplbuf;
	memcpy(p, mf->fline.protocol.s, mf->fline.protocol.len);
	p += mf->fline.protocol.len;
	*p = ' '; p++;
	memcpy(p, mf->fline.transaction.s, mf->fline.transaction.len);
	p += mf->fline.transaction.len;
	*p = ' '; p++;
	memcpy(p, code->s, code->len);
	p += code->len;
	*p = ' '; p++;
	memcpy(p, text->s, text->len);
	p += text->len;
	memcpy(p, "\r\n", 2);
	p += 2;
	memcpy(p, "To-Path: ", 9);
	p += 9;
	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_FROM_PATH);
	if(hdr==NULL)
	{
		LM_ERR("From-Path header not found\n");
		return -1;
	}
	if(mf->fline.msgtypeid==MSRP_REQ_SEND)
	{
		l = q_memchr(hdr->body.s, ' ', hdr->body.len);
		if(l==NULL) {
			memcpy(p, hdr->body.s, hdr->body.len + 2);
			p += hdr->body.len + 2;
		} else {
			memcpy(p, hdr->body.s, l - hdr->body.s);
			p += l - hdr->body.s;
			memcpy(p, "\r\n", 2);
			p += 2;
		}
	} else {
		memcpy(p, hdr->body.s, hdr->body.len + 2);
		p += hdr->body.len + 2;
	}
	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_TO_PATH);
	if(hdr==NULL)
	{
		LM_ERR("To-Path header not found\n");
		return -1;
	}
	memcpy(p, "From-Path: ", 11);
	p += 11;
	l = q_memchr(hdr->body.s, ' ', hdr->body.len);
	if(l==NULL) {
		memcpy(p, hdr->body.s, hdr->body.len + 2);
		p += hdr->body.len + 2;
	} else {
		memcpy(p, hdr->body.s, l - hdr->body.s);
		p += l - hdr->body.s;
		memcpy(p, "\r\n", 2);
		p += 2;
	}
	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_MESSAGE_ID);
	if(hdr!=NULL)
	{
		memcpy(p, hdr->buf.s, hdr->buf.len);
		p += hdr->buf.len;
	}

	if(xhdrs!=NULL && xhdrs->s!=NULL)
	{
		memcpy(p, xhdrs->s, xhdrs->len);
		p += xhdrs->len;
	}

	memcpy(p, mf->endline.s, mf->endline.len);
	p += mf->endline.len;
	*(p-3) = '$';

	env = msrp_get_env();

	if (unlikely((env->srcinfo.proto == PROTO_WS
			|| env->srcinfo.proto == PROTO_WSS)
			&& sr_event_enabled(SREV_TCP_WS_FRAME_OUT))) {
		struct tcp_connection *con = tcpconn_get(env->srcinfo.id, 0, 0,
								0, 0);
		ws_event_info_t wsev;

		if (con == NULL)
		{
			LM_WARN("TCP/TLS connection for WebSocket could not be"
				"found\n");
			return -1;
		}

		memset(&wsev, 0, sizeof(ws_event_info_t));
		wsev.type = SREV_TCP_WS_FRAME_OUT;
		wsev.buf = rplbuf;
		wsev.len = p - rplbuf;
		wsev.id = con->id;
		return sr_event_exec(SREV_TCP_WS_FRAME_OUT, (void *) &wsev);
	}
	else 
	if (tcp_send(&env->srcinfo, 0, rplbuf, p - rplbuf) < 0) {
		LM_ERR("sending reply failed\n");
		return -1;
	}

	return 0;
}