コード例 #1
0
ファイル: tcpops.c プロジェクト: TheGrandWazoo/kamailio
/**
 * Request the fd corresponding to the given connection id to the TCP main process.
 * You may want to close() the fd after use.
 *
 * @param conid - connection id
 * @param fd - placeholder to return the fd
 * @return 1 on success, 0 on failure
 *
 */
int tcpops_acquire_fd_from_tcpmain(int conid, int *fd)
{
	struct tcp_connection *s_con, *tmp;
	long msg[2];
	int n;

	if (unlikely((s_con = tcpconn_get(conid, 0, 0, 0, 0)) == NULL)) {
		LM_ERR("invalid connection id %d, (must be a TCP connid)\n", conid);
		return 0;
	}

	msg[0] = (long)s_con;
	msg[1] = CONN_GET_FD;

	n = send_all(unix_tcp_sock, msg, sizeof(msg));
	if (unlikely(n <= 0)){
		LM_ERR("failed to send fd request: %s (%d)\n", strerror(errno), errno);
		goto error_release;
	}

	n = receive_fd(unix_tcp_sock, &tmp, sizeof(tmp), fd, MSG_WAITALL);
	if (unlikely(n <= 0)){
		LM_ERR("failed to get fd (receive_fd): %s (%d)\n", strerror(errno), errno);
		goto error_release;
	}
	tcpconn_put(s_con);
	return 1;

error_release:
	tcpconn_put(s_con);
	return 0;
}
コード例 #2
0
ファイル: ws_conn.c プロジェクト: SipSeb/kamailio
static int ws_rpc_add_node(rpc_t* rpc, void* ctx, void* ih, ws_connection_t *wsc)
{
	int interval;
	char *src_proto, *dst_proto, *pong, *sub_protocol;
	char src_ip[IP6_MAX_STR_SIZE + 1], dst_ip[IP6_MAX_STR_SIZE + 1];
	struct tcp_connection *con = tcpconn_get(wsc->id, 0, 0, 0, 0);
	char rplbuf[512];

	if (con)
	{
		src_proto = (con->rcv.proto== PROTO_WS) ? "ws" : "wss";
		memset(src_ip, 0, IP6_MAX_STR_SIZE + 1);
		ip_addr2sbuf(&con->rcv.src_ip, src_ip, IP6_MAX_STR_SIZE);

		dst_proto = (con->rcv.proto == PROTO_WS) ? "ws" : "wss";
		memset(dst_ip, 0, IP6_MAX_STR_SIZE + 1);
		ip_addr2sbuf(&con->rcv.dst_ip, dst_ip, IP6_MAX_STR_SIZE);

		pong = wsc->awaiting_pong ? "awaiting Pong, " : "";

		interval = (int)time(NULL) - wsc->last_used;
		if (wsc->sub_protocol == SUB_PROTOCOL_SIP)
			sub_protocol = "sip";
		else if (wsc->sub_protocol == SUB_PROTOCOL_MSRP)
			sub_protocol = "msrp";
		else
			sub_protocol = "**UNKNOWN**";

		if (snprintf(rplbuf, 512,
					"%d: %s:%s:%hu -> %s:%s:%hu (state: %s"
					", %s last used %ds ago"
					", sub-protocol: %s)",
					wsc->id,
					src_proto,
					strlen(src_ip) ? src_ip : "*",
					con->rcv.src_port,
					dst_proto,
					strlen(dst_ip) ? dst_ip : "*",
					con->rcv.dst_port,
					wsconn_state_str[wsc->state],
					pong,
					interval,
					sub_protocol) < 0) {
			tcpconn_put(con);
			rpc->fault(ctx, 500, "Failed to print connection details");
			return -1;
		}
		if (rpc->array_add(ih, "s", rplbuf)<0)
		{
			tcpconn_put(con);
			rpc->fault(ctx, 500, "Failed to add to response");
			return -1;
		}

		tcpconn_put(con);
		return 1;
	}
	else
		return 0;
}
コード例 #3
0
ファイル: ws_conn.c プロジェクト: AlessioCasco/kamailio
static int add_node(struct mi_root *tree, ws_connection_t *wsc)
{
	int interval;
	char *src_proto, *dst_proto, *pong, *sub_protocol;
	char src_ip[IP6_MAX_STR_SIZE + 1], dst_ip[IP6_MAX_STR_SIZE + 1];
	struct tcp_connection *con = tcpconn_get(wsc->id, 0, 0, 0, 0);

	if (con)
	{
		src_proto = (con->rcv.proto== PROTO_WS) ? "ws" : "wss";
		memset(src_ip, 0, IP6_MAX_STR_SIZE + 1);
		ip_addr2sbuf(&con->rcv.src_ip, src_ip, IP6_MAX_STR_SIZE);

		dst_proto = (con->rcv.proto == PROTO_WS) ? "ws" : "wss";
		memset(dst_ip, 0, IP6_MAX_STR_SIZE + 1);
		ip_addr2sbuf(&con->rcv.dst_ip, dst_ip, IP6_MAX_STR_SIZE);

		pong = wsc->awaiting_pong ? "awaiting Pong, " : "";

		interval = (int)time(NULL) - wsc->last_used;
		if (wsc->sub_protocol == SUB_PROTOCOL_SIP)
			sub_protocol = "sip";
		else if (wsc->sub_protocol == SUB_PROTOCOL_MSRP)
			sub_protocol = "msrp";
		else
			sub_protocol = "**UNKNOWN**";

		if (addf_mi_node_child(&tree->node, 0, 0, 0,
					"%d: %s:%s:%hu -> %s:%s:%hu (state: %s"
					", %s last used %ds ago"
					", sub-protocol: %s)",
					wsc->id,
					src_proto,
					strlen(src_ip) ? src_ip : "*",
					con->rcv.src_port,
					dst_proto,
					strlen(dst_ip) ? dst_ip : "*",
					con->rcv.dst_port,
					wsconn_state_str[wsc->state],
					pong,
					interval,
					sub_protocol) == 0)
		{
			tcpconn_put(con);
			return -1;
		}

		tcpconn_put(con);
		return 1;
	}
	else
		return 0;
}
コード例 #4
0
ファイル: tcpops.c プロジェクト: TheGrandWazoo/kamailio
/**
 * gets the fd of the current message source connection
 *
 * @param conid - connection id
 * @param fd - placeholder to return the fd
 * @return 1 on success, 0 on failure
 *
 */
int tcpops_get_current_fd(int conid, int *fd)
{
	struct tcp_connection *s_con;
	if (unlikely((s_con = tcpconn_get(conid, 0, 0, 0, 0)) == NULL)) {
		LM_ERR("invalid connection id %d, (must be a TCP connid)\n", conid);
		return 0;
	}
	LM_DBG("got fd=%d from id=%d\n", s_con->fd, conid);

	*fd = s_con->fd;
	tcpconn_put(s_con);
	return 1;
}
コード例 #5
0
ファイル: tls_select.c プロジェクト: Drooids/openser-xmlrpc
struct tcp_connection* get_cur_connection(struct sip_msg* msg)
{
	struct tcp_connection* c;

	if (msg->rcv.proto != PROTO_TLS) {
		LM_ERR("transport protocol is not TLS (bug in config)\n");
		return 0;
	}

	c = tcpconn_get(msg->rcv.proto_reserved1, 0, 0, tcp_con_lifetime);
	if (c && c->type != PROTO_TLS) {
		LM_ERR("connection found but is not TLS (bug in config)\n");
		tcpconn_put(c);
		return 0;
	}
	return c;
}
コード例 #6
0
ファイル: ws_conn.c プロジェクト: SipSeb/kamailio
void wsconn_close_now(ws_connection_t *wsc)
{
	struct tcp_connection *con = tcpconn_get(wsc->id, 0, 0, 0, 0);

	if (wsconn_rm(wsc, WSCONN_EVENTROUTE_YES) < 0)
		LM_ERR("removing WebSocket connection\n");

	if (con == NULL)
	{
		LM_ERR("getting TCP/TLS connection\n");
		return;
	}

	tcpconn_put(con);
	con->send_flags.f |= SND_F_CON_CLOSE;
	con->state = S_CONN_BAD;
	con->timeout = get_ticks_raw();
}
コード例 #7
0
ファイル: tls_select.c プロジェクト: alezzandro/kamailio
struct tcp_connection* get_cur_connection(struct sip_msg* msg)
{
	struct tcp_connection* c;

	if(_tls_pv_con != 0)
		return _tls_pv_con;

	if (msg->rcv.proto != PROTO_TLS) {
		ERR("Transport protocol is not TLS (bug in config)\n");
		return 0;
	}

	c = tcpconn_get(msg->rcv.proto_reserved1, 0, 0, 0,
					cfg_get(tls, tls_cfg, con_lifetime));
	if (c && c->type != PROTO_TLS) {
		ERR("Connection found but is not TLS\n");
		tcpconn_put(c);
		return 0;
	}
	return c;
}
コード例 #8
0
ファイル: tls_mod.c プロジェクト: AlessioCasco/kamailio
static int is_peer_verified(struct sip_msg* msg, char* foo, char* foo2)
{
	struct tcp_connection *c;
	SSL *ssl;
	long ssl_verify;
	X509 *x509_cert;

	DBG("started...\n");
	if (msg->rcv.proto != PROTO_TLS) {
		ERR("proto != TLS --> peer can't be verified, return -1\n");
		return -1;
	}

	DBG("trying to find TCP connection of received message...\n");

	c = tcpconn_get(msg->rcv.proto_reserved1, 0, 0, 0,
					cfg_get(tls, tls_cfg, con_lifetime));
	if (!c) {
		ERR("connection no longer exits\n");
		return -1;
	}

	if(c->type != PROTO_TLS) {
		ERR("Connection found but is not TLS\n");
		tcpconn_put(c);
		return -1;
	}

	if (!c->extra_data) {
		LM_ERR("no extra_data specified in TLS/TCP connection found."
				" This should not happen... return -1\n");
		tcpconn_put(c);
		return -1;
	}

	ssl = ((struct tls_extra_data*)c->extra_data)->ssl;

	ssl_verify = SSL_get_verify_result(ssl);
	if ( ssl_verify != X509_V_OK ) {
		LM_WARN("verification of presented certificate failed... return -1\n");
		tcpconn_put(c);
		return -1;
	}

	/* now, we have only valid peer certificates or peers without certificates.
	 * Thus we have to check for the existence of a peer certificate
	 */
	x509_cert = SSL_get_peer_certificate(ssl);
	if ( x509_cert == NULL ) {
		LM_INFO("tlsops:is_peer_verified: WARNING: peer did not present "
			"a certificate. Thus it could not be verified... return -1\n");
		tcpconn_put(c);
		return -1;
	}

	X509_free(x509_cert);

	tcpconn_put(c);

	LM_DBG("tlsops:is_peer_verified: peer is successfully verified"
		"...done\n");
	return 1;
}
コード例 #9
0
/* finds a tcpconn & sends on it */
int tcp_send(int type, char* buf, unsigned len, union sockaddr_union* to,
				int id)
{
	struct tcp_connection *c;
	struct tcp_connection *tmp;
	struct ip_addr ip;
	int port;
	int fd;
	long response[2];
	int n;
	
	port=0;
	if (to){
		su2ip_addr(&ip, to);
		port=su_getport(to);
		c=tcpconn_get(id, &ip, port, TCP_CON_SEND_TIMEOUT); 
	}else if (id){
		c=tcpconn_get(id, 0, 0, TCP_CON_SEND_TIMEOUT);
	}else{
		LOG(L_CRIT, "BUG: tcp_send called with null id & to\n");
		return -1;
	}
	
	if (id){
		if (c==0) {
			if (to){
				/* try again w/o id */
				c=tcpconn_get(0, &ip, port, TCP_CON_SEND_TIMEOUT);
				goto no_id;
			}else{
				LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n",
						id);
				return -1;
			}
		}else goto get_fd;
	}
no_id:
		if (c==0){
			DBG("tcp_send: no open tcp connection found, opening new one\n");
			/* create tcp connection */
			if ((c=tcpconn_connect(to, type))==0){
				LOG(L_ERR, "ERROR: tcp_send: connect failed\n");
				return -1;
			}
			c->refcnt++; /* safe to do it w/o locking, it's not yet
							available to the rest of the world */
			fd=c->s;
			
			/* send the new tcpconn to "tcp main" */
			response[0]=(long)c;
			response[1]=CONN_NEW;
			n=send_all(unix_tcp_sock, response, sizeof(response));
			if (n<=0){
				LOG(L_ERR, "BUG: tcp_send: failed write: %s (%d)\n",
						strerror(errno), errno);
				n=-1;
				goto end;
			}	
			n=send_fd(unix_tcp_sock, &c, sizeof(c), c->s);
			if (n<=0){
				LOG(L_ERR, "BUG: tcp_send: failed send_fd: %s (%d)\n",
						strerror(errno), errno);
				n=-1;
				goto end;
			}
			goto send_it;
		}
get_fd:
			/* todo: see if this is not the same process holding
			 *  c  and if so send directly on c->fd */
			DBG("tcp_send: tcp connection found (%p), acquiring fd\n", c);
			/* get the fd */
			response[0]=(long)c;
			response[1]=CONN_GET_FD;
			n=send_all(unix_tcp_sock, response, sizeof(response));
			if (n<=0){
				LOG(L_ERR, "BUG: tcp_send: failed to get fd(write):%s (%d)\n",
						strerror(errno), errno);
				n=-1;
				goto release_c;
			}
			DBG("tcp_send, c= %p, n=%d\n", c, n);
			tmp=c;
			n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd);
			if (n<=0){
				LOG(L_ERR, "BUG: tcp_send: failed to get fd(receive_fd):"
							" %s (%d)\n", strerror(errno), errno);
				n=-1;
				goto release_c;
			}
			if (c!=tmp){
				LOG(L_CRIT, "BUG: tcp_send: get_fd: got different connection:"
						"  %p (id= %d, refcnt=%d state=%d != "
						"  %p (id= %d, refcnt=%d state=%d (n=%d)\n",
						  c,   c->id,   c->refcnt,   c->state,
						  tmp, tmp->id, tmp->refcnt, tmp->state, n
				   );
				n=-1; /* fail */
				goto end;
			}
			DBG("tcp_send: after receive_fd: c= %p n=%d fd=%d\n",c, n, fd);
		
	
	
send_it:
	DBG("tcp_send: sending...\n");
	lock_get(&c->write_lock);
#ifdef USE_TLS
	if (c->type==PROTO_TLS)
		n=tls_blocking_write(c, fd, buf, len);
	else
#endif
		n=tcp_blocking_write(c, fd, buf, len);
	lock_release(&c->write_lock);
	DBG("tcp_send: after write: c= %p n=%d fd=%d\n",c, n, fd);
	DBG("tcp_send: buf=\n%.*s\n", (int)len, buf);
	if (n<0){
		LOG(L_ERR, "ERROR: tcp_send: failed to send\n");
		/* error on the connection , mark it as bad and set 0 timeout */
		c->state=S_CONN_BAD;
		c->timeout=0;
		/* tell "main" it should drop this (optional it will t/o anyway?)*/
		response[0]=(long)c;
		response[1]=CONN_ERROR;
		n=send_all(unix_tcp_sock, response, sizeof(response));
		/* CONN_ERROR will auto-dec refcnt => we must not call tcpconn_put !!*/
		if (n<=0){
			LOG(L_ERR, "BUG: tcp_send: error return failed (write):%s (%d)\n",
					strerror(errno), errno);
			n=-1;
		}
		close(fd);
		return n; /* error return, no tcpconn_put */
	}
end:
	close(fd);
release_c:
	tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */
	return n;
}
コード例 #10
0
ファイル: ws_handshake.c プロジェクト: aallamaa/kamailio
int ws_handle_handshake(struct sip_msg *msg)
{
	str key = {0, 0}, headers = {0, 0}, reply_key = {0, 0}, origin = {0, 0};
	unsigned char sha1[SHA_DIGEST_LENGTH];
	unsigned int hdr_flags = 0, sub_protocol = 0;
	int version = 0;
	struct hdr_field *hdr = msg->headers;
	struct tcp_connection *con;
	ws_connection_t *wsc;

	/* Make sure that the connection is closed after the response _and_
	   the existing connection (from the request) is reused for the
	   response.  The close flag will be unset later if the handshake is
	   successful. */
	msg->rpl_send_flags.f |= SND_F_CON_CLOSE;
	msg->rpl_send_flags.f |= SND_F_FORCE_CON_REUSE;

	if (cfg_get(websocket, ws_cfg, enabled) == 0)
	{
		LM_INFO("disabled: bouncing handshake\n");
		ws_send_reply(msg, 503, &str_status_service_unavailable,
				NULL);
		return 0;
	}

	/* Retrieve TCP/TLS connection */
	if ((con = tcpconn_get(msg->rcv.proto_reserved1, 0, 0, 0, 0)) == NULL)
	{
		LM_ERR("retrieving connection\n");
		ws_send_reply(msg, 500, &str_status_internal_server_error,
				NULL);
		return 0;
	}

	if (con->type != PROTO_TCP && con->type != PROTO_TLS)
	{
		LM_ERR("unsupported transport: %d", con->type);
		goto end;
	}

	if (parse_headers(msg, HDR_EOH_F, 0) < 0)
	{
		LM_ERR("error parsing headers\n");
		ws_send_reply(msg, 500, &str_status_internal_server_error,
				NULL);
		goto end;
	}

	/* Process HTTP headers */
	while (hdr != NULL)
	{
		/* Decode and validate Connection */
		if (cmp_hdrname_strzn(&hdr->name,
				str_hdr_connection.s,
				str_hdr_connection.len) == 0)
		{
			strlower(&hdr->body);
			if (str_search(&hdr->body, &str_upgrade) != NULL)
			{
				LM_DBG("found %.*s: %.*s\n",

					hdr->name.len, hdr->name.s,
					hdr->body.len, hdr->body.s);
				hdr_flags |= CONNECTION;
			}
		}
		/* Decode and validate Upgrade */
		else if (cmp_hdrname_strzn(&hdr->name,
				str_hdr_upgrade.s,
				str_hdr_upgrade.len) == 0)
		{
			strlower(&hdr->body);
			if (str_search(&hdr->body, &str_websocket) != NULL)
			{
				LM_DBG("found %.*s: %.*s\n",
					hdr->name.len, hdr->name.s,
					hdr->body.len, hdr->body.s);
				hdr_flags |= UPGRADE;
			}
		}
		/* Decode and validate Sec-WebSocket-Key */
		else if (cmp_hdrname_strzn(&hdr->name,
				str_hdr_sec_websocket_key.s, 
				str_hdr_sec_websocket_key.len) == 0) 
		{
			if (hdr_flags & SEC_WEBSOCKET_KEY)
			{
				LM_WARN("%.*s found multiple times\n",
					hdr->name.len, hdr->name.s);
				ws_send_reply(msg, 400,
						&str_status_bad_request,
						NULL);
				goto end;
			}

			LM_DBG("found %.*s: %.*s\n",
				hdr->name.len, hdr->name.s,
				hdr->body.len, hdr->body.s);
			key = hdr->body;
			hdr_flags |= SEC_WEBSOCKET_KEY;
		}
		/* Decode and validate Sec-WebSocket-Protocol */
		else if (cmp_hdrname_strzn(&hdr->name,
				str_hdr_sec_websocket_protocol.s,
				str_hdr_sec_websocket_protocol.len) == 0)
		{
			strlower(&hdr->body);
			if (str_search(&hdr->body, &str_sip) != NULL)
			{
				LM_DBG("found %.*s: %.*s\n",
					hdr->name.len, hdr->name.s,
					hdr->body.len, hdr->body.s);
				hdr_flags |= SEC_WEBSOCKET_PROTOCOL;
				sub_protocol |= SUB_PROTOCOL_SIP;
			}
			if (str_search(&hdr->body, &str_msrp) != NULL)
			{
				LM_DBG("found %.*s: %.*s\n",
					hdr->name.len, hdr->name.s,
					hdr->body.len, hdr->body.s);
				hdr_flags |= SEC_WEBSOCKET_PROTOCOL;
				sub_protocol |= SUB_PROTOCOL_MSRP;
			}
		}
		/* Decode and validate Sec-WebSocket-Version */
		else if (cmp_hdrname_strzn(&hdr->name,
				str_hdr_sec_websocket_version.s,
				str_hdr_sec_websocket_version.len) == 0)
		{
			if (hdr_flags & SEC_WEBSOCKET_VERSION)
			{
				LM_WARN("%.*s found multiple times\n",
					hdr->name.len, hdr->name.s);
				ws_send_reply(msg, 400,
						&str_status_bad_request,
						NULL);
				goto end;
			}

			str2sint(&hdr->body, &version);

			if (version != WS_VERSION)
			{
				LM_WARN("Unsupported protocol version %.*s\n",
					hdr->body.len, hdr->body.s);
				headers.s = headers_buf;
				headers.len = snprintf(headers.s, HDR_BUF_LEN,
					"%.*s: %d\r\n",
					str_hdr_sec_websocket_version.len,
					str_hdr_sec_websocket_version.s,
					WS_VERSION);
				ws_send_reply(msg, 426,
						&str_status_upgrade_required,
						&headers);
				goto end;
			}

			LM_DBG("found %.*s: %.*s\n",
				hdr->name.len, hdr->name.s,
				hdr->body.len, hdr->body.s);
			hdr_flags |= SEC_WEBSOCKET_VERSION;
		}
		/* Decode Origin */
		else if (cmp_hdrname_strzn(&hdr->name,
				str_hdr_origin.s,
				str_hdr_origin.len) == 0)
		{
			if (hdr_flags & ORIGIN)
			{
				LM_WARN("%.*s found multiple times\n",
					hdr->name.len, hdr->name.s);
				ws_send_reply(msg, 400,
						&str_status_bad_request,
						NULL);
				goto end;
			}

			LM_DBG("found %.*s: %.*s\n",
				hdr->name.len, hdr->name.s,
				hdr->body.len, hdr->body.s);
			origin = hdr->body;
			hdr_flags |= ORIGIN;
		}

		hdr = hdr->next;
	}

	/* Final check that all required headers/values were found */
	sub_protocol &= ws_sub_protocols;
	if ((hdr_flags & REQUIRED_HEADERS) != REQUIRED_HEADERS
			|| sub_protocol == 0)
	{

		LM_WARN("required headers not present\n");
		headers.s = headers_buf;
		headers.len = 0;

		if (ws_sub_protocols & SUB_PROTOCOL_SIP)
			headers.len += snprintf(headers.s + headers.len,
						HDR_BUF_LEN - headers.len,
						"%.*s: %.*s\r\n",
					str_hdr_sec_websocket_protocol.len,
					str_hdr_sec_websocket_protocol.s,
					str_sip.len, str_sip.s);

		if (ws_sub_protocols & SUB_PROTOCOL_MSRP)
			headers.len += snprintf(headers.s + headers.len,
						HDR_BUF_LEN - headers.len,
						"%.*s: %.*s\r\n",
					str_hdr_sec_websocket_protocol.len,
					str_hdr_sec_websocket_protocol.s,
					str_msrp.len, str_msrp.s);

		headers.len += snprintf(headers.s + headers.len,
					HDR_BUF_LEN - headers.len,
					"%.*s: %d\r\n",
					str_hdr_sec_websocket_version.len,
					str_hdr_sec_websocket_version.s,
					WS_VERSION);
		ws_send_reply(msg, 400, &str_status_bad_request, &headers);
		goto end;
	}

	/* Construct reply_key */
	reply_key.s = (char *) pkg_malloc(
				(key.len + str_ws_guid.len) * sizeof(char)); 
	if (reply_key.s == NULL)
	{
		LM_ERR("allocating pkg memory\n");
		ws_send_reply(msg, 500, &str_status_internal_server_error,
				NULL);
		goto end;
	}
	memcpy(reply_key.s, key.s, key.len);
	memcpy(reply_key.s + key.len, str_ws_guid.s, str_ws_guid.len);
	reply_key.len = key.len + str_ws_guid.len;
	SHA1((const unsigned char *) reply_key.s, reply_key.len, sha1);
	pkg_free(reply_key.s);
	reply_key.s = key_buf;
	reply_key.len = base64_enc(sha1, SHA_DIGEST_LENGTH,
				(unsigned char *) reply_key.s,
				base64_enc_len(SHA_DIGEST_LENGTH));

	/* Add the connection to the WebSocket connection table */
	wsconn_add(msg->rcv, sub_protocol);

	/* Make sure Kamailio core sends future messages on this connection
	   directly to this module */
	if (con->type == PROTO_TLS)
		con->type = con->rcv.proto = PROTO_WSS;
	else
		con->type = con->rcv.proto = PROTO_WS;

	/* Now Kamailio is ready to receive WebSocket frames build and send a
	   101 reply */
	headers.s = headers_buf;
	headers.len = 0;

	if (ws_cors_mode == CORS_MODE_ANY)
		headers.len += snprintf(headers.s + headers.len,
					HDR_BUF_LEN - headers.len,
					"%.*s: *\r\n",
					str_hdr_access_control_allow_origin.len,
					str_hdr_access_control_allow_origin.s);
	else if (ws_cors_mode == CORS_MODE_ORIGIN && origin.len > 0)
		headers.len += snprintf(headers.s + headers.len,
					HDR_BUF_LEN - headers.len,
					"%.*s: %.*s\r\n",
					str_hdr_access_control_allow_origin.len,
					str_hdr_access_control_allow_origin.s,
					origin.len,
					origin.s);

	if (sub_protocol & SUB_PROTOCOL_SIP)
		headers.len += snprintf(headers.s + headers.len,
					HDR_BUF_LEN - headers.len,
					"%.*s: %.*s\r\n",
					str_hdr_sec_websocket_protocol.len,
					str_hdr_sec_websocket_protocol.s,
					str_sip.len, str_sip.s);
	else if (sub_protocol & SUB_PROTOCOL_MSRP)
		headers.len += snprintf(headers.s + headers.len,
					HDR_BUF_LEN - headers.len,
					"%.*s: %.*s\r\n",
					str_hdr_sec_websocket_protocol.len,
					str_hdr_sec_websocket_protocol.s,
					str_msrp.len, str_msrp.s);

	headers.len += snprintf(headers.s + headers.len,
				HDR_BUF_LEN - headers.len,
				"%.*s: %.*s\r\n"
				"%.*s: %.*s\r\n"
				"%.*s: %.*s\r\n",
				str_hdr_upgrade.len, str_hdr_upgrade.s,
				str_websocket.len, str_websocket.s,
				str_hdr_connection.len, str_hdr_connection.s,
				str_upgrade.len, str_upgrade.s,
				str_hdr_sec_websocket_accept.len,
				str_hdr_sec_websocket_accept.s, reply_key.len,
				reply_key.s);
	msg->rpl_send_flags.f &= ~SND_F_CON_CLOSE;
	if (ws_send_reply(msg, 101, &str_status_switching_protocols,
				&headers) < 0)
	{
		if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) != NULL)
			wsconn_rm(wsc, WSCONN_EVENTROUTE_NO);

		goto end;
	}
	else
	{
		if (sub_protocol & SUB_PROTOCOL_SIP)
			update_stat(ws_sip_successful_handshakes, 1);
		else if (sub_protocol & SUB_PROTOCOL_MSRP)
			update_stat(ws_msrp_successful_handshakes, 1);
	}

	tcpconn_put(con);
	return 1;
end:
	if (con)
		tcpconn_put(con);
	return 0;
}
コード例 #11
0
ファイル: tcp_main.c プロジェクト: ryzhov/ATS0
/*! \brief Finds a tcpconn & sends on it */
int tcp_send(struct socket_info* send_sock, int type, char* buf, unsigned len,
			union sockaddr_union* to, int id)
{
	struct tcp_connection *c;
	struct tcp_connection *tmp;
	struct ip_addr ip;
	int port;
	int fd;
	long response[2];
	int n;
	struct timeval get,rcv,snd;
	
	port=0;

	reset_tcp_vars(tcpthreshold);
	start_expire_timer(get,tcpthreshold);

	if (to){
		su2ip_addr(&ip, to);
		port=su_getport(to);
		c=tcpconn_get(id, &ip, port, tcp_con_lifetime); 
	}else if (id){
		c=tcpconn_get(id, 0, 0, tcp_con_lifetime);
	}else{
		LM_CRIT("tcp_send called with null id & to\n");
		get_time_difference(get,tcpthreshold,tcp_timeout_con_get);
		return -1;
	}
	
	if (id){
		if (c==0) {
			if (to){
				/* try again w/o id */
				c=tcpconn_get(0, &ip, port, tcp_con_lifetime);
				goto no_id;
			}else{
				LM_ERR("id %d not found, dropping\n", id);
				get_time_difference(get,tcpthreshold,tcp_timeout_con_get);
				return -1;
			}
		}else goto get_fd;
	}
no_id:
		if (c==0){
			if (tcp_no_new_conn) {
				return -1;
			}
			LM_DBG("no open tcp connection found, opening new one\n");
			/* create tcp connection */
			if ((c=tcpconn_connect(send_sock, to, type))==0){
				LM_ERR("connect failed\n");
				get_time_difference(get,tcpthreshold,tcp_timeout_con_get);
				return -1;
			}
			c->refcnt++; /* safe to do it w/o locking, it's not yet
							available to the rest of the world */
			fd=c->s;
			
			/* send the new tcpconn to "tcp main" */
			response[0]=(long)c;
			response[1]=CONN_NEW;
			n=send_fd(unix_tcp_sock, response, sizeof(response), c->s);
			get_time_difference(get,tcpthreshold,tcp_timeout_con_get);
			if (n<=0){
				LM_ERR("failed send_fd: %s (%d)\n",	strerror(errno), errno);
				n=-1;
				goto end;
			}	
			goto send_it;
		}
get_fd:
		get_time_difference(get,tcpthreshold,tcp_timeout_con_get);
			/* todo: see if this is not the same process holding
			 *  c  and if so send directly on c->fd */
			LM_DBG("tcp connection found (%p), acquiring fd\n", c);
			/* get the fd */
			response[0]=(long)c;
			response[1]=CONN_GET_FD;
			start_expire_timer(rcv,tcpthreshold);
			n=send_all(unix_tcp_sock, response, sizeof(response));
			if (n<=0){
				LM_ERR("failed to get fd(write):%s (%d)\n",	
						strerror(errno), errno);
				n=-1;
				get_time_difference(rcv,tcpthreshold,tcp_timeout_receive_fd);
				goto release_c;
			}
			LM_DBG("c= %p, n=%d\n", c, n);
			tmp=c;
			n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd, MSG_WAITALL);
			get_time_difference(rcv,tcpthreshold,tcp_timeout_receive_fd);
			if (n<=0){
				LM_ERR("failed to get fd(receive_fd):"
							" %s (%d)\n", strerror(errno), errno);
				n=-1;
				goto release_c;
			}
			if (c!=tmp){
				LM_CRIT("got different connection:"
						"  %p (id= %d, refcnt=%d state=%d != "
						"  %p (id= %d, refcnt=%d state=%d (n=%d)\n",
						  c,   c->id,   c->refcnt,   c->state,
						  tmp, tmp->id, tmp->refcnt, tmp->state, n
				   );
				n=-1; /* fail */
				goto end;
			}
			LM_DBG("after receive_fd: c= %p n=%d fd=%d\n",c, n, fd);
		
	
	
send_it:
	LM_DBG("sending...\n");
	lock_get(&c->write_lock);
#ifdef USE_TLS
	if (c->type==PROTO_TLS)
		n=tls_blocking_write(c, fd, buf, len);
	else
#endif
		/* n=tcp_blocking_write(c, fd, buf, len); */
		start_expire_timer(snd,tcpthreshold);
		n=tsend_stream(fd, buf, len, tcp_send_timeout*1000); 
		get_time_difference(snd,tcpthreshold,tcp_timeout_send);
	
		stop_expire_timer(get,tcpthreshold,0,buf,(int)len,1);
	lock_release(&c->write_lock);
	LM_DBG("after write: c= %p n=%d fd=%d\n",c, n, fd);
	LM_DBG("buf=\n%.*s\n", (int)len, buf);
	if (n<0){
		LM_ERR("failed to send\n");
		/* error on the connection , mark it as bad and set 0 timeout */
		c->state=S_CONN_BAD;
		c->timeout=0;
		/* tell "main" it should drop this (optional it will t/o anyway?)*/
		response[0]=(long)c;
		response[1]=CONN_ERROR;
		n=send_all(unix_tcp_sock, response, sizeof(response));
		/* CONN_ERROR will auto-dec refcnt => we must not call tcpconn_put !!*/
		if (n<=0){
			LM_ERR("return failed (write):%s (%d)\n",
					strerror(errno), errno);
		}
		close(fd);
		return -1; /* error return, no tcpconn_put */
	}
end:
	close(fd);
release_c:
	tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */
	return n;
}
コード例 #12
0
ファイル: tlsops.c プロジェクト: Drooids/openser-xmlrpc
static int is_peer_verified(struct sip_msg* msg, char* foo, char* foo2)
{
	struct tcp_connection *c;
	SSL *ssl;
	long ssl_verify;
	X509 *x509_cert;

	LM_DBG("started...\n");
	if (msg->rcv.proto != PROTO_TLS) {
		LM_ERR("proto != TLS --> peer can't be verified, return -1\n");
		return -1;
	}

	LM_DBG("trying to find TCP connection of received message...\n");
	/* what if we have multiple connections to the same remote socket? e.g. we can have 
	     connection 1: localIP1:localPort1 <--> remoteIP:remotePort
	     connection 2: localIP2:localPort2 <--> remoteIP:remotePort
	   but I think the is very unrealistic */
	c=tcpconn_get(0, &(msg->rcv.src_ip), msg->rcv.src_port, tcp_con_lifetime);
	if (!c) {
		LM_ERR("no corresponding TLS/TCP connection found."
				" This should not happen... return -1\n");
		return -1;
	}
	LM_DBG("corresponding TLS/TCP connection found. s=%d, fd=%d, id=%d\n",
			c->s, c->fd, c->id);

	if (!c->extra_data) {
		LM_ERR("no extra_data specified in TLS/TCP connection found."
				" This should not happen... return -1\n");
		tcpconn_put(c);
		return -1;
	}

	ssl = (SSL *) c->extra_data;		

	ssl_verify = SSL_get_verify_result(ssl);
	if ( ssl_verify != X509_V_OK ) {
		LM_WARN("verification of presented certificate failed... return -1\n");
		tcpconn_put(c);
		return -1;
	}
	
	/* now, we have only valid peer certificates or peers without certificates.
	 * Thus we have to check for the existence of a peer certificate
	 */
	x509_cert = SSL_get_peer_certificate(ssl);
	if ( x509_cert == NULL ) {
		LM_WARN("tlsops:is_peer_verified: WARNING: peer did not presented "
			"a certificate. Thus it could not be verified... return -1\n");
		tcpconn_put(c);
		return -1;
	}
	
	X509_free(x509_cert);
	
	tcpconn_put(c);
	
	LM_DBG("tlsops:is_peer_verified: peer is successfuly verified"
		"...done\n");
	return 1;
}
コード例 #13
0
ファイル: msrp_netio.c プロジェクト: 4N7HR4X/kamailio
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;
}
コード例 #14
0
ファイル: msrp_netio.c プロジェクト: 4N7HR4X/kamailio
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;
}