Ejemplo n.º 1
0
/**
 * \brief WIP: Wslay send callback
 */
ssize_t vs_send_ws_callback_data(wslay_event_context_ptr ctx,
		const uint8_t *data,
		size_t len,
		int flags,
		void *user_data)
{
	struct vContext *C = (struct vContext*)user_data;
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	ssize_t r;
	int sflags = 0;

#ifdef MSG_MORE
if(flags & WSLAY_MSG_MORE) {
	sflags |= MSG_MORE;
}
#endif

	while((r = send(io_ctx->sockfd, data, len, sflags)) == -1 &&
			errno == EINTR);
	if(r == -1) {
		if(errno == EAGAIN || errno == EWOULDBLOCK) {
			wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
		} else {
			wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
		}
	}
	v_print_log(VRS_PRINT_DEBUG_MSG,
			"WS Callback Send Data\n");
	return r;
}
Ejemplo n.º 2
0
/**
 * \brief WIP: Wslay receive callback
 */
ssize_t vs_recv_ws_callback_data(wslay_event_context_ptr ctx,
		uint8_t *buf,
		size_t len,
		int flags,
		void *user_data)
{
	struct vContext *C = (struct vContext*)user_data;
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	ssize_t r;
	(void)flags;

	while((r = recv(io_ctx->sockfd, buf, len, 0)) == -1 &&
			errno == EINTR);
	if(r == -1) {
		if(errno == EAGAIN || errno == EWOULDBLOCK) {
			wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
		} else {
			wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
		}
	} else if(r == 0) {
		/* Unexpected EOF is also treated as an error */
		wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
		r = -1;
	}
	v_print_log(VRS_PRINT_DEBUG_MSG,
			"WS Callback Received Data, len: %ld, flags: %d\n",
			len, flags);
	return r;
}
Ejemplo n.º 3
0
/**
 * \brief Establishing Kerberos connection, verifies clients credentials
 * \param[in]        vContextc *C        The context of verse server
 * \param[out]        char **u_name        user name of client
 * \return        returns 1 if Kerberos authentication was OK 0 if something went wrong
 */
int vs_kerberos_auth(struct vContext *C, char **u_name){
        struct VS_CTX *vs_ctx = CTX_server_ctx(C);
        struct IO_CTX *io_ctx = CTX_io_ctx(C);
        struct VStreamConn *stream_conn = CTX_current_stream_conn(C);
        int flags = 0;
        int len = MAX_PACKET_SIZE;
        unsigned char buffer[MAX_PACKET_SIZE];
        char *client_principal;
        krb5_data packet;
        krb5_error_code krb5err;
        int flag;

        /* Make sure socket is blocking */
        flag = fcntl(stream_conn->io_ctx.sockfd, F_GETFL, 0);
        if ((fcntl(stream_conn->io_ctx.sockfd, F_SETFL, flag & ~O_NONBLOCK))
                        == -1) {
                if (is_log_level(VRS_PRINT_ERROR))
                        v_print_log(VRS_PRINT_ERROR, "fcntl(): %s\n", strerror(errno));
                return 0;
        }

        /* Get KRB_AP_REQ message */
        if ((len = recvfrom(stream_conn->io_ctx.sockfd, (char *) buffer,
                        MAX_PACKET_SIZE, flags,
                        NULL, NULL)) < 0) {
                v_print_log(VRS_PRINT_ERROR, "recvfrom failed.\n");
                return 0;
        }

        packet.length = len;
        packet.data = (krb5_pointer) buffer;

        io_ctx->krb5_auth_ctx = vs_ctx->tcp_io_ctx.krb5_auth_ctx;
        io_ctx->krb5_ctx = vs_ctx->tcp_io_ctx.krb5_ctx;
        io_ctx->krb5_ticket = vs_ctx->tcp_io_ctx.krb5_ticket;
        io_ctx->krb5_keytab = vs_ctx->tcp_io_ctx.krb5_keytab;

        /* Check authentication info */
        if ((krb5err = krb5_rd_req(io_ctx->krb5_ctx,
                        (krb5_auth_context *) &io_ctx->krb5_auth_ctx, &packet,
                        io_ctx->krb5_principal, io_ctx->krb5_keytab,
                        NULL, (krb5_ticket **) &io_ctx->krb5_ticket))) {
                v_print_log(VRS_PRINT_ERROR, "krb5_rd_req %d: %s\n", (int) krb5err,
                                krb5_get_error_message(io_ctx->krb5_ctx, krb5err));
                return 0;
        }
        /* Get user name */
        if ((krb5err = krb5_unparse_name(io_ctx->krb5_ctx,
                        io_ctx->krb5_ticket->enc_part2->client, &client_principal))) {
                v_print_log(VRS_PRINT_ERROR, "krb5_unparse_name %d: %s\n",
                                (int) krb5err,
                                krb5_get_error_message(io_ctx->krb5_ctx, krb5err));
                return 0;
        }
        v_print_log(VRS_PRINT_DEBUG_MSG, "Got authentication info from %s\n", client_principal);
        *u_name = client_principal;

        return 1;
}
Ejemplo n.º 4
0
/**
 * \brief This function handle messages in STREAM OPEN state
 *
 * \param[in] *C The pointer at cpntext
 *
 * \return This function return 1, when it ends successfuly, otherwise it
 * returns 0
 */
int v_STREAM_handle_messages(struct vContext *C)
{
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	int ret = 1, buffer_pos = 0, i;
	struct VMessage *r_message = CTX_r_message(C);
	struct VSession *vsession = CTX_current_session(C);

	/* Make sure, that buffer contains at least Verse message
	 * header. If this condition is not reached, then somebody tries
	 * to do some very bad things! .. Close this connection. */
	if(io_ctx->buf_size < VERSE_MESSAGE_HEADER_SIZE) {
		if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "received buffer too small %d\n",
				io_ctx->buf_size);
		ret = 0;
		goto end;
	}

	/* Reset content of received message */
	memset(r_message, 0, sizeof(struct VMessage));

	/* Unpack Verse message header */
	buffer_pos += v_unpack_message_header(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

	/* Unpack all system commands */
	buffer_pos += v_unpack_message_system_commands(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

	v_print_receive_message(C);

	/* Handle system commands */
	for(i=0;
			i<MAX_SYSTEM_COMMAND_COUNT && r_message->sys_cmd[i].cmd.id != CMD_RESERVED_ID;
			i++)
	{
		if(r_message->sys_cmd[i].cmd.id == CMD_CHANGE_L_ID &&
				r_message->sys_cmd[i].negotiate_cmd.feature == FTR_FPS &&
				r_message->sys_cmd[i].negotiate_cmd.count > 0)
		{
			vsession->fps_host = vsession->fps_peer = r_message->sys_cmd[i].negotiate_cmd.value->real32;
			vsession->tmp_flags |= SYS_CMD_NEGOTIATE_FPS;
		}

		if(r_message->sys_cmd[i].cmd.id == CMD_CONFIRM_L_ID &&
				r_message->sys_cmd[i].negotiate_cmd.feature == FTR_FPS &&
				r_message->sys_cmd[i].negotiate_cmd.count > 0)
		{
			vsession->fps_peer = r_message->sys_cmd[i].negotiate_cmd.value->real32;
		}
	}

	/* Unpack all node commands and put them to the queue of incomming commands */
	buffer_pos += v_cmd_unpack((char*)&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), vsession->in_queue);

end:
	return ret;
}
Ejemplo n.º 5
0
/**
 * \brief do TLS negotiation with client application
 * \param[in]	*C	The context of verse server
 * \return This function returns 1, when TLS connection was established and
 * it returns 0, when TLS was not established.
 */
int vs_TLS_handshake(struct vContext *C)
{
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VStreamConn *stream_conn = CTX_current_stream_conn(C);

	int flag, ret;

	/* Make sure socket is blocking */
	flag = fcntl(stream_conn->io_ctx.sockfd, F_GETFL, 0);
	if( (fcntl(stream_conn->io_ctx.sockfd, F_SETFL, flag & ~O_NONBLOCK)) == -1) {
		if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "fcntl(): %s\n", strerror(errno));
		return 0;
	}

	/* Set up SSL */
	if( (stream_conn->io_ctx.ssl = SSL_new(vs_ctx->tls_ctx)) == NULL) {
		v_print_log(VRS_PRINT_ERROR, "Setting up SSL failed.\n");
		ERR_print_errors_fp(v_log_file());
		SSL_free(stream_conn->io_ctx.ssl);
		stream_conn->io_ctx.ssl = NULL;
		close(io_ctx->sockfd);
		return 0;
	}

	/* Bind socket and SSL */
	if (SSL_set_fd(stream_conn->io_ctx.ssl, io_ctx->sockfd) == 0) {
		v_print_log(VRS_PRINT_ERROR, "Failed binding socket descriptor and SSL.\n");
		ERR_print_errors_fp(v_log_file());
		SSL_free(stream_conn->io_ctx.ssl);
		stream_conn->io_ctx.ssl = NULL;
		close(io_ctx->sockfd);
		return 0;
	}

	SSL_set_mode(stream_conn->io_ctx.ssl, SSL_MODE_AUTO_RETRY);

	/* Do TLS handshake and negotiation */
	if( (ret = SSL_accept(stream_conn->io_ctx.ssl)) != 1) {
		int err = SSL_get_error(stream_conn->io_ctx.ssl, ret);
		v_print_log(VRS_PRINT_ERROR, "SSL handshake failed: %d -> %d\n", ret, err);
		ERR_print_errors_fp(v_log_file());
		SSL_free(stream_conn->io_ctx.ssl);
		stream_conn->io_ctx.ssl = NULL;
		close(io_ctx->sockfd);
		return 0;
	}

	v_print_log(VRS_PRINT_DEBUG_MSG, "SSL handshake succeed.\n");
	return 1;
}
Ejemplo n.º 6
0
int vc_send_packet(struct vContext *C)
{
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VPacket *s_packet = CTX_s_packet(C);
	int error_num;
	struct timeval tv;
	unsigned short buffer_pos = 0;
	int ret;

	v_print_send_packet(C);

	/* Fill buffer */
	buffer_pos += v_pack_packet_header(s_packet, &io_ctx->buf[buffer_pos]);
	buffer_pos += v_pack_dgram_system_commands(s_packet, &io_ctx->buf[buffer_pos]);
	io_ctx->buf_size = buffer_pos;

	/* Send buffer */
	ret = v_send_packet(io_ctx, &error_num);

	if(ret == SEND_PACKET_SUCCESS) {

		/* Update time of sending last packet */
		gettimeofday(&tv, NULL);
		dgram_conn->tv_pay_send.tv_sec = tv.tv_sec;
		dgram_conn->tv_pay_send.tv_usec = tv.tv_usec;

		/* Update counter of sent packets */
		switch(dgram_conn->host_state) {
		case UDP_CLIENT_STATE_REQUEST:
			dgram_conn->count_s_pay = 1;
			dgram_conn->count_s_ack = 0;
			break;
		case UDP_CLIENT_STATE_PARTOPEN:
			dgram_conn->count_s_pay = 2;
			dgram_conn->count_s_ack = 1;
			break;
		case UDP_CLIENT_STATE_OPEN:
			dgram_conn->count_s_pay++;
			dgram_conn->count_s_ack++;
			break;
		case UDP_CLIENT_STATE_CLOSING:
			break;
		case UDP_CLIENT_STATE_CLOSED:
			break;
		}
	}

	return ret;
}
Ejemplo n.º 7
0
void v_print_receive_message(struct vContext *C)
{
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VMessage *r_message = CTX_r_message(C);

	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 34);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Receive message: ");
		v_print_log_simple(VRS_PRINT_DEBUG_MSG, "Socket: %d, ", io_ctx->sockfd);
		v_print_addr_port(VRS_PRINT_DEBUG_MSG, &io_ctx->peer_addr);
		v_print_message_header(VRS_PRINT_DEBUG_MSG, r_message);
		v_print_log_simple(VRS_PRINT_DEBUG_MSG, "\n");
		v_print_message_sys_cmds(VRS_PRINT_DEBUG_MSG, r_message);
		printf("%c[%dm", 27, 0);
	}
}
Ejemplo n.º 8
0
void v_print_send_packet(struct vContext *C)
{
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket *s_packet = CTX_s_packet(C);

	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 32);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Send packet: ");
		v_print_log_simple(VRS_PRINT_DEBUG_MSG, "Socket: %d, ", io_ctx->sockfd);
		v_print_addr_port(VRS_PRINT_DEBUG_MSG, &io_ctx->peer_addr);
		v_print_packet_header(VRS_PRINT_DEBUG_MSG, s_packet);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Shift: %d -> Window: %d\n", dgram_conn->rwin_host_scale, (unsigned int)s_packet->header.window << dgram_conn->rwin_host_scale);
		v_print_packet_sys_cmds(VRS_PRINT_DEBUG_MSG, s_packet);
		printf("%c[%dm", 27, 0);
	}
}
Ejemplo n.º 9
0
/**
 * \brief WSLay send callback
 */
ssize_t vs_send_ws_callback_data(wslay_event_context_ptr ctx,
		const uint8_t *data,
		size_t len,
		int flags,
		void *user_data)
{
	struct vContext *C = (struct vContext*)user_data;
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	ssize_t ret = 0;
	int sflags = 0;

#ifdef MSG_MORE
	if(flags & WSLAY_MSG_MORE) {
		sflags |= MSG_MORE;
	}
#endif

	/* Try to send all data */
	while((ret = send(io_ctx->sockfd, data, len, sflags)) == -1 &&
			errno == EINTR) {
#if DEBUG_WEB_SOCKET
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"WS Callback Send Data, len: %ld, flags: %d -> %ld\n",
				len, sflags, ret);
#endif
	}

#if DEBUG_WEB_SOCKET
	v_print_log(VRS_PRINT_DEBUG_MSG,
			"WS Callback Send Data, len: %ld, flags: %d -> ret: %ld\n",
			len, sflags, ret);
#endif

	if(ret == -1) {
		if(errno == EAGAIN || errno == EWOULDBLOCK) {
			wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
		} else {
			wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
		}
	}

	return ret;
}
Ejemplo n.º 10
0
/**
 * \brief This function is called, when server is in NEGOTIATE newhost state
 */
int vs_NEGOTIATE_newhost_loop(struct vContext *C)
{
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VMessage *r_message = CTX_r_message(C);
	int i, buffer_pos=0;

	/* Reset content of received message */
	memset(r_message, 0, sizeof(struct VMessage));

	/* Unpack Verse message header */
	buffer_pos += v_unpack_message_header(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

	/* Unpack all system commands */
	buffer_pos += v_unpack_message_system_commands(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

	v_print_receive_message(C);

	/* Process all system commands */
	for(i=0; i<MAX_SYSTEM_COMMAND_COUNT && r_message->sys_cmd[i].cmd.id!=CMD_RESERVED_ID; i++) {
		switch(r_message->sys_cmd[i].cmd.id) {
		case CMD_CONFIRM_L_ID:
			if(r_message->sys_cmd[i].negotiate_cmd.feature==FTR_HOST_URL) {
				if(r_message->sys_cmd[i].negotiate_cmd.count == 1) {
					if(vsession->host_url!=NULL &&
							strcmp(vsession->host_url, (char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str) == 0) {
						return 1;
					}
				}
			}
			break;
		}
	}

	return 0;
}
Ejemplo n.º 11
0
/**
 * \brief This function is called, when server is in NEGOTIATE_cookie_ded state
 *
 * This function can create new thread for datagram connection
 */
int vs_NEGOTIATE_cookie_ded_loop(struct vContext *C)
{
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VMessage *r_message = CTX_r_message(C);
	struct VMessage *s_message = CTX_s_message(C);
	int i, j, ret;
	unsigned short buffer_pos = 0;
	int host_url_proposed = 0,
			host_cookie_proposed = 0,
			peer_cookie_confirmed = 0,
			ded_confirmed = 0,
			client_name_proposed = 0,
			client_version_proposed = 0;
	struct timeval tv;
	struct VURL url;

	/* Reset content of received message */
	memset(r_message, 0, sizeof(struct VMessage));

	/* Unpack Verse message header */
	buffer_pos += v_unpack_message_header(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

	/* Unpack all system commands */
	buffer_pos += v_unpack_message_system_commands(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

	v_print_receive_message(C);

	/* Process all received system commands */
	for(i=0;
			i<MAX_SYSTEM_COMMAND_COUNT &&
			r_message->sys_cmd[i].cmd.id!=CMD_RESERVED_ID;
			i++)
	{
		switch(r_message->sys_cmd[i].cmd.id) {
		case CMD_CHANGE_R_ID:
			/* Client has to propose url in this state */
			if(r_message->sys_cmd[i].negotiate_cmd.feature == FTR_HOST_URL) {
				if(r_message->sys_cmd[i].negotiate_cmd.count > 0) {
					if(vsession->host_url!=NULL) {
						free(vsession->host_url);
					}
					/* Only first proposed URL will be used */
					vsession->host_url = strdup((char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str);
					/* Check if proposed URL is correct */
					ret = v_parse_url(vsession->host_url, &url);
					if(ret == 1)
						host_url_proposed = 1;
					else
						host_url_proposed = 0;
				}
			/* Client has to propose host cookie in this state */
			} else if(r_message->sys_cmd[i].negotiate_cmd.feature == FTR_COOKIE) {
				if(r_message->sys_cmd[i].negotiate_cmd.count > 0) {
					if(vsession->host_cookie.str != NULL) {
						free(vsession->host_cookie.str);
					}
					vsession->host_cookie.str = strdup((char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str);
					host_cookie_proposed = 1;
				}
			} else {
				v_print_log(VRS_PRINT_WARNING, "This feature id: %d is not supported in this state\n",
						r_message->sys_cmd[i].negotiate_cmd.feature);
			}
			break;
		case CMD_CHANGE_L_ID:
			/* Client could propose client name and version */
			if(r_message->sys_cmd[i].negotiate_cmd.feature == FTR_CLIENT_NAME) {
				if(r_message->sys_cmd[i].negotiate_cmd.count > 0) {
					/* Only first proposed client name will be used */
					vsession->client_name = strdup((char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str);
					client_name_proposed = 1;
				}
			} else if(r_message->sys_cmd[i].negotiate_cmd.feature == FTR_CLIENT_VERSION) {
				if(r_message->sys_cmd[i].negotiate_cmd.count > 0) {
					/* Only first proposed client name will be used */
					vsession->client_version = strdup((char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str);
					client_version_proposed = 1;
				}
			}
			break;
		case CMD_CONFIRM_R_ID:
			/* Client has to confirm peer cookie in this state */
			if(r_message->sys_cmd[i].negotiate_cmd.feature == FTR_COOKIE) {
				if (r_message->sys_cmd[i].negotiate_cmd.count == 1) {
					if(vsession->peer_cookie.str != NULL &&
						strcmp(vsession->peer_cookie.str, (char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str) == 0)
					{
						gettimeofday(&tv, NULL);
						vsession->peer_cookie.tv.tv_sec = tv.tv_sec;
						vsession->peer_cookie.tv.tv_usec = tv.tv_usec;
						peer_cookie_confirmed = 1;
					}
				}
			} else {
				v_print_log(VRS_PRINT_WARNING, "This feature id: %d is not supported in this state\n",
						r_message->sys_cmd[i].negotiate_cmd.feature);
			}
			break;
		case CMD_CONFIRM_L_ID:
			/* Client has to confirm DED in this state */
			if(r_message->sys_cmd[i].negotiate_cmd.feature == FTR_DED) {
				if(r_message->sys_cmd[i].negotiate_cmd.count == 1) {
					if(vsession->ded.str != NULL &&
							strcmp(vsession->ded.str, (char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str) == 0)
					{
						ded_confirmed = 1;
					} else {
						printf("%s != %s\n", vsession->ded.str, (char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str);
					}
				}
			}
			break;
		default:
			v_print_log(VRS_PRINT_WARNING, "This command id: %d is not supported in this state\n",
					r_message->sys_cmd[i].cmd.id);
			break;
		}
	}


	/* Send response on cookie request */
	if(host_url_proposed==1 &&
			host_cookie_proposed==1 &&
			peer_cookie_confirmed==1 &&
			ded_confirmed==1)
	{
		struct vContext *new_C;
		char trans_proto[4];
		char sec_proto[5];
		int cmd_rank = 0;

		buffer_pos = VERSE_MESSAGE_HEADER_SIZE;

		/* Copy address of peer */
		memcpy(&vsession->peer_address, &io_ctx->peer_addr, sizeof(struct VNetworkAddress));

		/* Do not confirm proposed URL */
		v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CONFIRM_R_ID, FTR_HOST_URL, NULL);

		/* Find first unused port from port range */
		for(i=vs_ctx->port_low, j=0; i<vs_ctx->port_high; i++, j++) {
			if(!(vs_ctx->port_list[j].flag & SERVER_PORT_USED)) {
				vsession->dgram_conn->io_ctx.host_addr.port = vs_ctx->port_list[j].port_number;
				vs_ctx->port_list[j].flag |= SERVER_PORT_USED;
				break;
			}
		}

		/* Do not allow unsecure TCP data connection */
		if(url.transport_protocol == VRS_TP_TCP) {
			url.security_protocol = VRS_SEC_DATA_TLS;
		}

		/* Copy settings about data connection to the session */
		vsession->flags |= url.security_protocol;
		vsession->flags |= url.transport_protocol;

		if(vsession->flags & VRS_TP_UDP) {
			strncpy(trans_proto, "udp", 3);
			trans_proto[3] = '\0';

			/* Create copy of new Verse context for new thread */
			new_C = (struct vContext*)calloc(1, sizeof(struct vContext));
			memcpy(new_C, C, sizeof(struct vContext));

			/* Try to create new thread */
			if((ret = pthread_create(&vsession->udp_thread, NULL, vs_main_dgram_loop, (void*)new_C)) != 0) {
				if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "pthread_create(): %s\n", strerror(errno));
				ret = 0;
				goto end;
			}

			/* Wait for datagram thread to be in LISTEN state */
			while(vsession->dgram_conn->host_state != UDP_SERVER_STATE_LISTEN) {
				/* Sleep 1 milisecond */
				usleep(1000);
			}
		} else if(vsession->flags & VRS_TP_TCP) {
			strncpy(trans_proto, "tcp", 3);
			trans_proto[3] = '\0';
		} else if(vsession->flags & VRS_TP_WEBSOCKET) {
			strncpy(trans_proto, "wss", 3);
			trans_proto[3] = '\0';
		}

#if (defined WITH_OPENSSL) && OPENSSL_VERSION_NUMBER>=0x10000000
		if(url.security_protocol==VRS_SEC_DATA_NONE ||
				!(vs_ctx->security_protocol & VRS_SEC_DATA_TLS))
		{
			strncpy(sec_proto, "none", 4);
			sec_proto[4] = '\0';
		} else if(url.security_protocol==VRS_SEC_DATA_TLS) {
			if(vsession->flags & VRS_TP_UDP) {
				strncpy(sec_proto, "dtls", 4);
				sec_proto[4] = '\0';
			} else if((vsession->flags & VRS_TP_TCP) ||
					(vsession->flags & VRS_TP_WEBSOCKET))
			{
				strncpy(sec_proto, "tls", 3);
				sec_proto[3] = '\0';
			}
		} else {
			strncpy(sec_proto, "none", 4);
			sec_proto[4] = '\0';
		}
#else
		strncpy(sec_proto, "none", 4);
		sec_proto[4] = '\0';
#endif

		/* Free proposed and now obsolete URL */
		if(vsession->host_url != NULL) {
			free(vsession->host_url);
			vsession->host_url = NULL;
		}

		/* Set right host URL */
		vsession->host_url = calloc(UCHAR_MAX, sizeof(char));
		if(url.ip_ver==IPV6) {
			sprintf(vsession->host_url, "verse-%s-%s://[%s]:%d",
					trans_proto,
					sec_proto,
					url.node,
					vsession->dgram_conn->io_ctx.host_addr.port);
		} else {
			sprintf(vsession->host_url, "verse-%s-%s://%s:%d",
					trans_proto,
					sec_proto,
					url.node,
					vsession->dgram_conn->io_ctx.host_addr.port);
		}
		v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CHANGE_L_ID, FTR_HOST_URL, vsession->host_url, NULL);

		/* Set time for the host cookie */
		gettimeofday(&tv, NULL);
		vsession->host_cookie.tv.tv_sec = tv.tv_sec;
		vsession->host_cookie.tv.tv_usec = tv.tv_usec;

		/* Send confirmation about host cookie */
		v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CONFIRM_R_ID, FTR_COOKIE,
				vsession->host_cookie.str, NULL);

		/* Send confirmation about client name */
		if(client_name_proposed == 1) {
			v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CONFIRM_L_ID, FTR_CLIENT_NAME,
					vsession->client_name, NULL);
		}

		/* Send confirmation about client version only in situation, when
		 * client proposed client name too */
		if(client_version_proposed == 1) {
			if(client_name_proposed == 1) {
				v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CONFIRM_L_ID, FTR_CLIENT_VERSION,
						vsession->client_version, NULL);
			} else {
				/* Client version without client name is not allowed */
				v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CONFIRM_L_ID, FTR_CLIENT_VERSION,
						NULL);
			}
		}

		/* Pack all system commands to the buffer */
		buffer_pos += v_pack_stream_system_commands(s_message, &io_ctx->buf[buffer_pos]);

		/* Update length of message in the header (data in buffer) */
		s_message->header.version = VRS_VERSION;
		s_message->header.len = io_ctx->buf_size = buffer_pos;

		/* Pack header to the beginning of the buffer */
		v_pack_message_header(s_message, io_ctx->buf);

		v_print_send_message(C);

		ret = 1;
	} else {
		ret = 0;
	}

end:
	v_clear_url(&url);

	return ret;
}
Ejemplo n.º 12
0
/**
 * \brief This function try to pack message that is going to be
 * sent in STREAM OPEN state
 *
 * \param[in] *C The pointer at context
 *
 * \return This function return 1, when there is something to send,
 * it returns -1, when there is nothing to send and it returns 0, when
 * there is some error
 */
int v_STREAM_pack_message(struct vContext *C)
{
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VStreamConn *conn = CTX_current_stream_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VMessage *s_message = CTX_s_message(C);
	struct Generic_Cmd *cmd, *fake_cmd;
	int ret = -1, queue_size = 0, buffer_pos = 0, prio_cmd_count, cmd_rank=0;
	int8 cmd_share;
	int16 prio, max_prio, min_prio;
	uint16 cmd_count, cmd_len, prio_win, swin, sent_size, tot_cmd_size;
	real32 prio_sum_high, prio_sum_low, r_prio;
	int is_fake_cmd_received = 0;

	/* Is here something to send? */
	if((v_out_queue_get_count(vsession->out_queue) > 0) ||
			(vsession->tmp_flags & SYS_CMD_NEGOTIATE_FPS))
	{

		/* Get current size of data in TCP outgoing buffer */
#ifdef __linux__
		if( ioctl(io_ctx->sockfd, SIOCOUTQ, &queue_size) == -1 ) {
			v_print_log(VRS_PRINT_ERROR,
					"ioctl(%d, SIOCOUTQ, ...): %s\n",
					io_ctx->sockfd,
					strerror(errno));
			return 0;
		}
#endif

		/* Compute, how many data could be added to the TCP stack? */
		swin = conn->socket_buffer_size - queue_size;

		buffer_pos = VERSE_MESSAGE_HEADER_SIZE;

		s_message->sys_cmd[0].cmd.id = CMD_RESERVED_ID;

		/* When negotiated and used FPS is different, then pack negotiate command
		 * for FPS */
		if(vsession->fps_host != vsession->fps_peer) {
			cmd_rank += v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank,
					CMD_CHANGE_L_ID, FTR_FPS, &vsession->fps_host, NULL);
		} else {
			if(vsession->tmp_flags & SYS_CMD_NEGOTIATE_FPS) {
				cmd_rank += v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank,
						CMD_CONFIRM_L_ID, FTR_FPS, &vsession->fps_peer, NULL);
				/* Send confirmation only once for received system command */
				vsession->tmp_flags &= ~SYS_CMD_NEGOTIATE_FPS;
			}
		}

		buffer_pos += v_pack_stream_system_commands(s_message, &io_ctx->buf[buffer_pos]);

		max_prio = v_out_queue_get_max_prio(vsession->out_queue);
		min_prio = v_out_queue_get_min_prio(vsession->out_queue);

		prio_sum_high = v_out_queue_get_prio_sum_high(vsession->out_queue);
		prio_sum_low = v_out_queue_get_prio_sum_low(vsession->out_queue);

		v_print_log(VRS_PRINT_DEBUG_MSG, "Packing prio queues, cmd count: %d\n",
				v_out_queue_get_count(vsession->out_queue));

		/* Go through all priorities and pick commands from priority queues */
		for(prio = max_prio; prio >= min_prio; prio--)
		{
			prio_cmd_count = v_out_queue_get_count_prio(vsession->out_queue, prio);

			if(prio_cmd_count > 0) {

				r_prio = v_out_queue_get_prio(vsession->out_queue, prio);

				/* Compute size of buffer that could be occupied by
				 * commands from this queue */
				if(prio >= VRS_DEFAULT_PRIORITY) {
					prio_win = ((swin - buffer_pos)*r_prio)/prio_sum_high;
				} else {
					prio_win = ((swin - buffer_pos)*r_prio)/prio_sum_low;
				}

				/* Debug print */
				v_print_log(VRS_PRINT_DEBUG_MSG, "Queue: %d, count: %d, r_prio: %6.3f, prio_win: %d\n",
						prio, prio_cmd_count, r_prio, prio_win);

				/* Get total size of commands that were stored in queue (sent_size) */
				sent_size = 0;
				tot_cmd_size = 0;

				while(prio_cmd_count > 0) {
					cmd_share = 0;
					cmd_count = 0;
					cmd_len = prio_win - sent_size;

					/* Pack commands from queues with high priority to the buffer */
					cmd = v_out_queue_pop(vsession->out_queue, prio, &cmd_count, &cmd_share, &cmd_len);
					if(cmd != NULL) {

						/* Is this command fake command? */
						if(cmd->id < MIN_CMD_ID) {
							if(cmd->id == FAKE_CMD_CONNECT_TERMINATE) {
								/* Close connection */
								struct VS_CTX *vs_ctx = CTX_server_ctx(C);
								if(vs_ctx != NULL) {
									vsession->stream_conn->host_state = TCP_SERVER_STATE_CLOSING;
								} else {
									vsession->stream_conn->host_state = TCP_CLIENT_STATE_CLOSING;
								}
							} else if(cmd->id == FAKE_CMD_FPS) {
								struct Fps_Cmd *fps_cmd = (struct Fps_Cmd*)cmd;
								/* Change value of FPS. It will be sent in negotiate command
								 * until it is confirmed be the peer (server) */
								vsession->fps_host = fps_cmd->fps;
							}
						} else {
							buffer_pos += tot_cmd_size = v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, v_cmd_size(cmd), 0);
							if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
								printf("%c[%d;%dm", 27, 1, 32);
								v_cmd_print(VRS_PRINT_DEBUG_MSG, cmd);
								printf("%c[%dm", 27, 0);
							}
							sent_size += tot_cmd_size;
						}

						fake_cmd = v_cmd_fake_ack(cmd);

						if(fake_cmd != NULL) {
							is_fake_cmd_received = 1;
							/* Push command to the queue of incoming commands */
							v_in_queue_push(vsession->in_queue, fake_cmd);
							/* Print content of fake command */
							v_fake_cmd_print(VRS_PRINT_DEBUG_MSG, fake_cmd);
						}

						/* It is not necessary to put cmd to history of sent commands,
						 * when TCP is used. */
						v_cmd_destroy(&cmd);
						prio_cmd_count--;
					} else {
						break;
					}
				}
			}
		}

		s_message->header.len = io_ctx->buf_size = buffer_pos;
		s_message->header.version = VRS_VERSION;

		/* Pack header to the beginning of the buffer */
		v_pack_message_header(s_message, io_ctx->buf);

		/* Debug print of command to be send */
		if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
			v_print_send_message(C);
		}

		/* When pure ack packet caused adding some fake commands to the queue, then
		 * poke server data thread */
		if( (vs_ctx != NULL) && (is_fake_cmd_received == 1)) {
			sem_post(vs_ctx->data.sem);
		}

		ret = 1;

	}

	return ret;
}
Ejemplo n.º 13
0
/* Generic receiving and handling of packet */
int vc_receive_and_handle_packet(struct vContext *C, int handle_packet(struct vContext *C))
{
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VPacket *r_packet = CTX_r_packet(C);
	int ret, error_num;
	long int sec = 0, usec = 0;
	fd_set set;
	struct timeval tv;

	/* Initialize set */
	FD_ZERO(&set);
	FD_SET(dgram_conn->io_ctx.sockfd, &set);

	switch(dgram_conn->host_state) {
		case UDP_CLIENT_STATE_REQUEST:
		case UDP_CLIENT_STATE_PARTOPEN:
		case UDP_CLIENT_STATE_CLOSING:
			sec = INIT_TIMEOUT + (int) (v_exponential_backoff(dgram_conn->state[dgram_conn->host_state].attempts) * (rand() / (RAND_MAX + 1.0)));
			usec = 0;
			break;
		case UDP_CLIENT_STATE_OPEN:
			sec = 0;
			usec = 10000;
			break;
	}

	/* Initialize time value */
	tv.tv_sec = sec;
	tv.tv_usec = usec;

	/* Wait on response from server */
	if( (ret = select(io_ctx->sockfd+1, &set, NULL, NULL, &tv)) == -1 ) {
		if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "%s:%s():%d select(): %s\n", __FILE__, __FUNCTION__,  __LINE__, strerror(errno));
		return RECEIVE_PACKET_ERROR;
	}
	/* Check if the event occurred on sockfd */
	else if(ret>0 && FD_ISSET(io_ctx->sockfd, &set)) {
		/* Try to receive packet from server */
		if(v_receive_packet(io_ctx, &error_num) == -1) {
			switch(error_num) {
				case ECONNREFUSED:	/* A remote host refused this connection */
					return RECEIVE_PACKET_ERROR;
				case EAGAIN:
				case EBADF:
				case EFAULT:
				case EINTR:
				case EINVAL:
				case ENOMEM:
				case ENOTCONN:
				case ENOTSOCK:
					break;
			}
		/* Address of received packet has to be same as address of server, when
		 * connection is not connected */
		} else if((io_ctx->flags & SOCKET_CONNECTED) ||
				v_compare_addr_and_port(&dgram_conn->peer_address, &dgram_conn->io_ctx.peer_addr))
		{
			/* The size of buffer must be bigger then zero */
			if(dgram_conn->io_ctx.buf_size>0) {
				int buffer_pos = 0;

				/* Get time of receiving packet */
				gettimeofday(&tv, NULL);

				/* Extract verse header from packet */
				ret = v_unpack_packet_header(io_ctx->buf,
						io_ctx->buf_size,
						r_packet);
				if(ret != VERSE_PACKET_HEADER_SIZE)
					return RECEIVE_PACKET_CORRUPTED;

				/* Check for right packet header version number */
				if(r_packet->header.version != VRS_VERSION) {
					if(is_log_level(VRS_PRINT_WARNING)) v_print_log(VRS_PRINT_WARNING, "Packet with unsupported version: %d was dropped.\n",
							r_packet->header.version);
					return RECEIVE_PACKET_CORRUPTED;
				}

				/* Compute RWIN */
				dgram_conn->rwin_peer = r_packet->header.window << dgram_conn->rwin_peer_scale;

				/* Extract system commands from packet */
				buffer_pos += v_unpack_packet_system_commands(io_ctx->buf,
						io_ctx->buf_size,
						r_packet);

				/* Are there some node commands in the buffer? */
				if(io_ctx->buf_size > buffer_pos) {
					/* Set pointer to not proceeded buffer */
					r_packet->data = (uint8*)&io_ctx->buf[buffer_pos];
					/* Set size of not proceeded buffer */
					r_packet->data_size = io_ctx->buf_size - buffer_pos;
				} else {
					r_packet->data = NULL;
					r_packet->data_size = 0;
				}

				/* When important things are done, then print content of the
				 * command (in debug mode) */
				v_print_receive_packet(C);

				/* Handle received packet and its data */
				ret = handle_packet(C);

				if(ret == RECEIVE_PACKET_SUCCESS) {
					/* Update information about last received packet payload
					 * packet */
					if(r_packet->header.flags & PAY_FLAG) {
						dgram_conn->last_r_pay = r_packet->header.payload_id;
						/* Update time of last received payload packet */
						dgram_conn->tv_pay_recv.tv_sec = tv.tv_sec;
						dgram_conn->tv_pay_recv.tv_usec = tv.tv_usec;
					}
					/* Update information about last received packet acknowledgment
					 * packet */
					if(r_packet->header.flags & ACK_FLAG) {
						dgram_conn->last_r_ack = r_packet->header.ack_nak_id;
					}
				}

				return ret;

			} else {
				if(is_log_level(VRS_PRINT_WARNING)) v_print_log(VRS_PRINT_WARNING, "Packet with zero size was dropped.\n");
				return RECEIVE_PACKET_CORRUPTED;
			}
		} else {
			/* When some 'bad' packet is received on this port, then do not increase counter
			 * of connection attempts (packet was received from address, that does not belong
			 * to the server) */
			if(is_log_level(VRS_PRINT_WARNING))
				v_print_log(VRS_PRINT_WARNING, "Packet from unknown address was dropped.\n");

			return RECEIVE_PACKET_FAKED;	/* This should not happen, because connect() function is used */
		}
	}

	return RECEIVE_PACKET_TIMEOUT;
}
Ejemplo n.º 14
0
/**
 * \brief The function with websocket infinite loop
 */
void *vs_websocket_loop(void *arg)
{
	/* The vContext is passed as *user_data* in callback functions. */
	struct vContext *C = (struct vContext*)arg;
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VStreamConn *stream_conn = CTX_current_stream_conn(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VMessage *r_message=NULL, *s_message=NULL;
	wslay_event_context_ptr wslay_ctx;
	fd_set read_set, write_set;
	struct timeval tv;
	int ret, flags;
	unsigned int int_size;

	struct wslay_event_callbacks callbacks = {
			vs_recv_ws_callback_data,
			vs_send_ws_callback_data,
			NULL,
			NULL,
			NULL,
			NULL,
			vs_ws_recv_msg_callback
	};

	/* Set socket blocking */
	flags = fcntl(io_ctx->sockfd, F_GETFL, 0);
	fcntl(io_ctx->sockfd, F_SETFL, flags & ~O_NONBLOCK);

	http_handshake(io_ctx->sockfd);

	/* Try to get size of TCP buffer */
	int_size = sizeof(int_size);
	getsockopt(io_ctx->sockfd, SOL_SOCKET, SO_RCVBUF,
			(void *)&stream_conn->socket_buffer_size, &int_size);

	r_message = (struct VMessage*)calloc(1, sizeof(struct VMessage));
	s_message = (struct VMessage*)calloc(1, sizeof(struct VMessage));
	CTX_r_message_set(C, r_message);
	CTX_s_message_set(C, s_message);

	stream_conn->host_state = TCP_SERVER_STATE_RESPOND_METHODS;

	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 31);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: RESPOND_methods\n");
		printf("%c[%dm", 27, 0);
	}

	/* Set non-blocking */
	flags = fcntl(io_ctx->sockfd, F_GETFL, 0);
	fcntl(io_ctx->sockfd, F_SETFL, flags | O_NONBLOCK);

	wslay_event_context_server_init(&wslay_ctx, &callbacks, C);

	/* "Never ending" loop */
	while(vsession->stream_conn->host_state != TCP_SERVER_STATE_CLOSED)
	{
		if(vs_ctx->state != SERVER_STATE_READY) {
			vsession->stream_conn->host_state = TCP_SERVER_STATE_CLOSING;
			/* Try to close connection with websocket client */
			wslay_event_queue_close(wslay_ctx,
					WSLAY_CODE_GOING_AWAY,
					(uint8_t*)"Server shutdown",	/* Close message */
					15);	/* The length of close message s*/
		}

		/* Initialize read set */
		FD_ZERO(&read_set);
		FD_SET(io_ctx->sockfd, &read_set);

		/* Initialize write set */
		FD_ZERO(&write_set);
		FD_SET(io_ctx->sockfd, &write_set);

		/* Set timeout for select() */
		if(stream_conn->host_state == TCP_SERVER_STATE_STREAM_OPEN) {
			/* Use negotiated FPS */
			tv.tv_sec = 0;
			tv.tv_usec = 1000000/vsession->fps_host;
		} else {
			/* User have to send something in 30 seconds */
			tv.tv_sec = VRS_TIMEOUT;
			tv.tv_usec = 0;
		}

		if( (ret = select(io_ctx->sockfd+1,
				&read_set,
				&write_set,
				NULL,			/* Exception*/
				&tv)) == -1) {
			if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "%s:%s():%d select(): %s\n",
					__FILE__, __FUNCTION__,  __LINE__, strerror(errno));
			goto end;
			/* Was event on the listen socket */
		} else if(ret>0){
			if(FD_ISSET(io_ctx->sockfd, &read_set)) {
				if( wslay_event_recv(wslay_ctx) != 0 ) {
					goto end;
				}
			} else if (FD_ISSET(io_ctx->sockfd, &write_set)) {
				if( wslay_event_send(wslay_ctx) != 0 ) {
					goto end;
				}
			}
		}

		if(stream_conn->host_state == TCP_SERVER_STATE_STREAM_OPEN) {
			/* Check if there is any command in outgouing queue
			 * and eventually pack these commands to buffer */
			if((ret = v_STREAM_pack_message(C)) == 0 ) {
				goto end;
			}

			/* When at least one command was packed to buffer, then
			 * queue this buffer to WebSocket layer */
			if(ret == 1) {
				struct wslay_event_msg msgarg;
			    msgarg.opcode = WSLAY_BINARY_FRAME;
			    msgarg.msg = (uint8_t*)io_ctx->buf;
			    msgarg.msg_length = io_ctx->buf_size;
			    wslay_event_queue_msg(wslay_ctx, &msgarg);
			}
		}
	}

end:
	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 31);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: CLOSING\n");
		printf("%c[%dm", 27, 0);
	}

	/* Set up TCP CLOSING state (non-blocking) */
	vs_CLOSING(C);

	/* Receive and Send messages are not neccessary any more */
	if(r_message!=NULL) {
		free(r_message);
		r_message = NULL;
		CTX_r_message_set(C, NULL);
	}
	if(s_message!=NULL) {
		free(s_message);
		s_message = NULL;
		CTX_s_message_set(C, NULL);
	}

	/* TCP connection is considered as CLOSED, but it is not possible to use
	 * this connection for other client */
	stream_conn->host_state = TCP_SERVER_STATE_CLOSED;

	/* NULL pointer at stream connection */
	CTX_current_stream_conn_set(C, NULL);

	/* Set TCP connection to CLOSED */
	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 31);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: CLOSED\n");
		printf("%c[%dm", 27, 0);
	}


	pthread_mutex_lock(&vs_ctx->data.mutex);
	/* Unsubscribe this session (this avatar) from all nodes */
	vs_node_free_avatar_reference(vs_ctx, vsession);
	/* Try to destroy avatar node */
	vs_node_destroy_avatar_node(vs_ctx, vsession);
	pthread_mutex_unlock(&vs_ctx->data.mutex);

	/* This session could be used again for authentication */
	stream_conn->host_state=TCP_SERVER_STATE_LISTEN;

	/* Clear session flags */
	vsession->flags = 0;

	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 31);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: LISTEN\n");
		printf("%c[%dm", 27, 0);
	}

	free(C);
	C = NULL;

	pthread_exit(NULL);
	return NULL;
}
Ejemplo n.º 15
0
/**
 * \brief WebSocket callback function for recived message
 */
void vs_ws_recv_msg_callback(wslay_event_context_ptr ctx,
		const struct wslay_event_on_msg_recv_arg *arg,
		void *user_data)
{
	struct vContext *C = (struct vContext*)user_data;
	struct VSession *session = CTX_current_session(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);

	(void)ctx;

	if(!wslay_is_ctrl_frame(arg->opcode)) {
		/* Verse server uses binary message for communication */
		if(arg->opcode == WSLAY_BINARY_FRAME) {
		    struct wslay_event_msg msgarg;

			v_print_log(VRS_PRINT_DEBUG_MSG,
					"WS Callback received binary message\n");

			/* Copy received data to IO context */
			memcpy(io_ctx->buf,	arg->msg, arg->msg_length);
			io_ctx->buf_size = arg->msg_length;

			if(session->stream_conn->host_state == TCP_SERVER_STATE_STREAM_OPEN) {
				if(v_STREAM_handle_messages(C) == 0) {
					/* TODO: end connection */
					return;
				}
			} else {

				if( vs_handle_handshake(C, NULL) == -1 ) {
					/* TODO: end connection */
					return;
				}

			    msgarg.opcode = WSLAY_BINARY_FRAME;
			    msgarg.msg = (uint8_t*)io_ctx->buf;
			    msgarg.msg_length = io_ctx->buf_size;
			    wslay_event_queue_msg(ctx, &msgarg);
			}

		} else if(arg->opcode == WSLAY_TEXT_FRAME) {
			v_print_log(VRS_PRINT_ERROR, "WebSocket text frame is not supported\n");
			return;
		}

	} else {
		/* Print opcode of control message */
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"WS Callback Received Ctrl Message: opcode: %d\n",
				arg->opcode);
		/* Is it closing message? */
		if(arg->opcode & WSLAY_CONNECTION_CLOSE) {
			v_print_log(VRS_PRINT_DEBUG_MSG,
					"Close message with code: %d, message: %s\n",
					arg->status_code,
					arg->msg);
			if(session->stream_conn->host_state == TCP_SERVER_STATE_CLOSING) {
				session->stream_conn->host_state = TCP_SERVER_STATE_CLOSED;
			} else {
				session->stream_conn->host_state = TCP_SERVER_STATE_CLOSING;
				wslay_event_queue_close(ctx,
						WSLAY_CODE_NORMAL_CLOSURE,
						(uint8_t*)"Closing connection",
						15);
			}
		}
	}

}
Ejemplo n.º 16
0
/**
 * \brief WebSocket callback function for received message
 */
void vs_ws_recv_msg_callback(wslay_event_context_ptr wslay_ctx,
		const struct wslay_event_on_msg_recv_arg *arg,
		void *user_data)
{
	struct vContext *C = (struct vContext*)user_data;
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct VSession *session = CTX_current_session(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	int ret;

	if(!wslay_is_ctrl_frame(arg->opcode)) {

		/* Verse server uses only binary message for communication */
		if(arg->opcode == WSLAY_BINARY_FRAME) {
		    struct wslay_event_msg msgarg;

#if DEBUG_WEB_SOCKET
		    unsigned int i;

			v_print_log(VRS_PRINT_DEBUG_MSG,
					"WS Callback received binary message\n");

			v_print_log(VRS_PRINT_DEBUG_MSG,
					"Binary dump\n");

			/* Print dump of received data */
			for(i=0; i<arg->msg_length; i++) {
				v_print_log_simple(VRS_PRINT_DEBUG_MSG, "%d,", arg->msg[i]);
			}
			v_print_log_simple(VRS_PRINT_DEBUG_MSG, "\n");
#endif

			/* Copy received data to IO context */
			memcpy(io_ctx->buf,	arg->msg, arg->msg_length);
			io_ctx->buf_size = arg->msg_length;

			if(session->stream_conn->host_state == TCP_SERVER_STATE_STREAM_OPEN) {
				if(v_STREAM_handle_messages(C) != 0) {
					/* When some payload data were received, then poke data thread */
					sem_post(vs_ctx->data.sem);
				} else {
					/* End connection */
					session->stream_conn->host_state = TCP_SERVER_STATE_CLOSING;

					/* Try to close connection with WebSocket client */
					wslay_event_queue_close(wslay_ctx,
							WSLAY_CODE_PROTOCOL_ERROR,
							(uint8_t*)"Wrong command",	/* Close message */
							13);	/* The length of close message */
					return;
				}
			} else {
				if( vs_handle_handshake(C) == -1 ) {
					/* End connection */
					session->stream_conn->host_state = TCP_SERVER_STATE_CLOSING;

					/* Try to close connection with WebSocket client */
					wslay_event_queue_close(wslay_ctx,
							WSLAY_CODE_PROTOCOL_ERROR,
							(uint8_t*)"Wrong command",	/* Close message */
							13);	/* The length of close message */
					return;
				}

				/* During handshake send response immediately. */

				/* TODO: optionally send message fragmented, when it is needed using:
				 * wslay_event_queue_fragmented_msg() */
				msgarg.opcode = WSLAY_BINARY_FRAME;
				msgarg.msg = (uint8_t*)io_ctx->buf;
				msgarg.msg_length = io_ctx->buf_size;

				/* Queue message for sending */
				if((ret = wslay_event_queue_msg(wslay_ctx, &msgarg)) != 0) {
					v_print_log(VRS_PRINT_ERROR,
							"Unable to queue message to WebSocket: %d\n", ret);
					return;
				} else {
					v_print_log(VRS_PRINT_DEBUG_MSG,
							"WebSocket message successfully queued\n");
				}
			}

		} else if(arg->opcode == WSLAY_TEXT_FRAME) {
			v_print_log(VRS_PRINT_ERROR, "WebSocket text frame is not supported\n");
			return;
		}

	} else {
		/* Print opcode of control message */
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"WS Callback Received Ctrl Message: opcode: %d\n",
				arg->opcode);

		/* Is it closing message? */
		if(arg->opcode & WSLAY_CONNECTION_CLOSE) {

			v_print_log(VRS_PRINT_DEBUG_MSG,
					"Close message with code: %d, message: %s\n",
					arg->status_code,
					arg->msg);

			/* When this control message was received at second time, then
			 * switch to the state CLOSED. Otherwise switch to the state
			 * CLOSING */
			if(session->stream_conn->host_state == TCP_SERVER_STATE_CLOSING) {
				session->stream_conn->host_state = TCP_SERVER_STATE_CLOSED;
			} else {
				session->stream_conn->host_state = TCP_SERVER_STATE_CLOSING;
				/* When server wasn't in the state closing, then send
				 * confirmation to the client, that this connection will be
				 * closed */
				wslay_event_queue_close(wslay_ctx,
						WSLAY_CODE_NORMAL_CLOSURE,
						(uint8_t*)"Closing connection",
						15);
			}
		}
	}
}
Ejemplo n.º 17
0
/**
 * \brief This function packs and compress command to the packet from one
 * priority queue.
 *
 * \param[in]	*C	The verse context
 * \param[in]	*sent_packet	The pointer at structure with send packet
 * \param[in]	buffer_pos		The curent size of buffer of sent packet
 * \param[in]	prio			The priority of sub queue
 * \param[in]	prio_win		The window size of current prio queue
 * \param[out]	tot_cmd_size	The total size of commands that were poped from prio queue
 */
static int pack_prio_queue(struct vContext *C,
		struct VSent_Packet *sent_packet,
		int buffer_pos,
		uint8 prio,
		uint16 prio_win,
		uint16 *tot_cmd_size)
{
	struct VSession *vsession = CTX_current_session(C);
	struct VDgramConn *vconn = CTX_current_dgram_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct Generic_Cmd *cmd;
	int ret, last_cmd_count = 0;
	uint16 cmd_count, cmd_len, cmd_size, sum_len=0;
	int8 cmd_share;
	uint8  last_cmd_id = CMD_RESERVED_ID;

	while( (v_out_queue_get_count_prio(vsession->out_queue, prio) > 0) &&
			(sum_len < prio_win) &&
			(buffer_pos < vconn->io_ctx.mtu))
	{
		cmd_count = 0;
		cmd_share = 0;

		/* Compute how many commands could be compressed to the packet
		 * and compute right length of compressed commands. */
		cmd_len = ((prio_win - sum_len)<(vconn->io_ctx.mtu - buffer_pos)) ?
				(prio_win - sum_len) :
				(vconn->io_ctx.mtu - buffer_pos);

		/* Remove command from queue */
		cmd = v_out_queue_pop(vsession->out_queue, prio, &cmd_count, &cmd_share, &cmd_len);

		/* When it is not possible to pop more commands from queue, then break
		 * while loop */
		if(cmd == NULL) {
			break;
		}

		/* Is this command fake command? */
		if(cmd->id < MIN_CMD_ID) {
			if(cmd->id == FAKE_CMD_CONNECT_TERMINATE) {
				struct VS_CTX *vs_ctx = CTX_server_ctx(C);
				if(vs_ctx != NULL) {
					vconn->host_state = UDP_SERVER_STATE_CLOSEREQ;
				} else {
					vconn->host_state = UDP_CLIENT_STATE_CLOSING;
				}
			} else if(cmd->id == FAKE_CMD_FPS) {
				struct Fps_Cmd *fps_cmd = (struct Fps_Cmd*)cmd;
				/* Change value of FPS. It will be sent in negotiate command
				 * until it is confirmed be the peer (server) */
				vsession->fps_host = fps_cmd->fps;
			}
			v_cmd_destroy(&cmd);
		} else {

			/* What was size of command in queue */
			cmd_size = v_cmd_size(cmd);

			if(!(buffer_pos < (vconn->io_ctx.mtu - cmd_size))) {
				/* When there is not enough space for other command,
				 * then push command back to the beginning of queue. */
				v_out_queue_push_head(vsession->out_queue, prio, cmd);
				break;
			} else {

				/* Update total size of commands that were poped from queue */
				*tot_cmd_size += cmd_size;

				/* When compression is not allowed, then add this command as is */
				if( vconn->host_cmd_cmpr == CMPR_NONE) {
					cmd_count = 0;
					cmd_len = cmd_size;
					/* Debug print */
					v_print_log(VRS_PRINT_DEBUG_MSG, "Cmd: %d, count: %d, length: %d\n",
							cmd->id, cmd_count, cmd_len);
					/* Add command to the buffer */
					buffer_pos += v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, cmd_len, 0);
				} else {
					/* When command compression is allowed and was ID of command changed? */
					if( (cmd->id != last_cmd_id) || (last_cmd_count <= 0) )	{
						/* When this command is alone, then use default command size */
						if(cmd_count == 0) {
							cmd_len = cmd_size;
						} else {
							/* FIXME: do not recompute command length here, but do it right,
							 * when command is added to the queue */
							cmd_len = v_cmds_len(cmd, cmd_count, cmd_share, cmd_len);
						}
						/* Debug print */
						v_print_log(VRS_PRINT_DEBUG_MSG, "Cmd: %d, count: %d, length: %d\n",
								cmd->id, cmd_count, cmd_len);
						/* Add command to the buffer */
						buffer_pos += v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, cmd_len, cmd_share);
						/* Set up current count of commands in the line */
						last_cmd_count = cmd_count;
						/* Update summary of commands length */
						sum_len += cmd_len;
					} else {
						buffer_pos += v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, 0, cmd_share);
					}
				}

				/* Print command */
				v_cmd_print(VRS_PRINT_DEBUG_MSG, cmd);

				/* TODO: remove command alias here (layer value set/unset) */

				/* Add command to the packet history */
				ret = v_packet_history_add_cmd(&vconn->packet_history, sent_packet, cmd, prio);
				assert(ret==1);

				/* Update last command id */
				last_cmd_id = cmd->id;
				/* Decrement counter of commands in queue */
				last_cmd_count--;
			}
		}
	}

	return buffer_pos;
}
Ejemplo n.º 18
0
static int vs_RESPOND_krb_auth_loop(struct vContext *C, const char *u_name) {
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VMessage *r_message = CTX_r_message(C);
	struct VMessage *s_message = CTX_s_message(C);
	int i, cmd_rank = 0, client_name_proposed = 0, client_version_proposed = 0;
	unsigned short buffer_pos = 0;
	int user_id;

    /* Reset content of received message */
    memset(r_message, 0, sizeof(struct VMessage));

    /* Unpack Verse message header */
    buffer_pos += v_unpack_message_header(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

    /* Unpack all system commands */
    buffer_pos += v_unpack_message_system_commands(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

    v_print_receive_message(C);

    for(i=0; i<MAX_SYSTEM_COMMAND_COUNT && r_message->sys_cmd[i].cmd.id!=CMD_RESERVED_ID; i++) {
            switch(r_message->sys_cmd[i].cmd.id) {
            case CMD_CHANGE_L_ID:
                    /* Client could propose client name and version */
                    if(r_message->sys_cmd[i].negotiate_cmd.feature == FTR_CLIENT_NAME) {
                            if(r_message->sys_cmd[i].negotiate_cmd.count > 0) {
                                    /* Only first proposed client name will be used */
                                    vsession->client_name = strdup((char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str);
                                    client_name_proposed = 1;
                            }
                    } else if(r_message->sys_cmd[i].negotiate_cmd.feature == FTR_CLIENT_VERSION) {
                            if(r_message->sys_cmd[i].negotiate_cmd.count > 0) {
                                    /* Only first proposed client name will be used */
                                    vsession->client_version = strdup((char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str);
                                    client_version_proposed = 1;
                            }
                    }
                    break;
            default:
                    v_print_log(VRS_PRINT_WARNING,
                                    "This command id: %d is not supported in this state\n",
                                    r_message->sys_cmd[i].cmd.id);
                    break;
            }
    }

    buffer_pos = VERSE_MESSAGE_HEADER_SIZE;

	/* Send confirmation about client name */
	if (client_name_proposed == 1) {
		v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CONFIRM_L_ID,
				FTR_CLIENT_NAME, vsession->client_name, NULL);
	}

	/* Send confirmation about client version only in situation, when
	 * client proposed client name too */
	if (client_version_proposed == 1) {
		if (client_name_proposed == 1) {
			v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++,
					CMD_CONFIRM_L_ID, FTR_CLIENT_VERSION,
					vsession->client_version, NULL);
		} else {
			/* Client version without client name is not allowed */
			v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++,
					CMD_CONFIRM_L_ID, FTR_CLIENT_VERSION,
					NULL);
		}
	}

	/* Do user authentication */
	if ((user_id = vs_krb_make_user(C, u_name)) != -1) {
        long int avatar_id;

        pthread_mutex_lock(&vs_ctx->data.mutex);
        avatar_id = vs_create_avatar_node(vs_ctx, vsession, user_id);
        pthread_mutex_unlock(&vs_ctx->data.mutex);

        if(avatar_id == -1) {
                v_print_log(VRS_PRINT_ERROR, "Failed to create avatar node\n");
                return 0;
        }

        /* Save user_id to the session and send it in
         * connect_accept command */
        vsession->user_id = user_id;
        vsession->avatar_id = avatar_id;

        s_message->sys_cmd[cmd_rank].ua_succ.id = CMD_USER_AUTH_SUCCESS;
        s_message->sys_cmd[cmd_rank].ua_succ.user_id = user_id;
        s_message->sys_cmd[cmd_rank].ua_succ.avatar_id = avatar_id;
        cmd_rank++;

        /* Generate random string for coockie */
        vsession->peer_cookie.str = (char*)calloc((COOKIE_SIZE+1), sizeof(char));
        for(i=0; i<COOKIE_SIZE; i++) {
                /* Generate only printable characters (debug prints) */
                vsession->peer_cookie.str[i] = 32 + (char)((float)rand()*94.0/RAND_MAX);
        }
        vsession->peer_cookie.str[COOKIE_SIZE] = '\0';
        /* Set up negotiate command of the host cookie */
        v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CHANGE_R_ID, FTR_COOKIE,
                        vsession->peer_cookie.str, NULL);

        /* Load DED from configuration and save it to the session */
        vsession->ded.str = strdup(vs_ctx->ded);
        v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CHANGE_L_ID, FTR_DED,
                        vsession->ded.str, NULL);

        buffer_pos += v_pack_stream_system_commands(s_message, &io_ctx->buf[buffer_pos]);

        s_message->header.len = io_ctx->buf_size = buffer_pos;
        s_message->header.version = VRS_VERSION;
        /* Pack header to the beginning of the buffer */
        v_pack_message_header(s_message, io_ctx->buf);

        v_print_send_message(C);

        return 1;
	} else {

		s_message->sys_cmd[0].ua_fail.id = CMD_USER_AUTH_FAILURE;
		s_message->sys_cmd[0].ua_fail.count = 0;

		s_message->sys_cmd[1].cmd.id = CMD_RESERVED_ID;

		buffer_pos += v_pack_stream_system_commands(s_message,
				&io_ctx->buf[buffer_pos]);

		s_message->header.len = io_ctx->buf_size = buffer_pos;
		s_message->header.version = VRS_VERSION;
		/* Pack header to the beginning of the buffer */
		v_pack_message_header(s_message, io_ctx->buf);

		v_print_send_message(C);

		return 1;
	}
	return 0;
}
Ejemplo n.º 19
0
/**
 * \brief This function process received message and send respond to the client
 * if client sent CMD_USER_AUTH_REQUEST with method type UA_METHOD_NONE. The
 * response contains list of supported authentication methods (only Password
 * method is supported now)
 * \param[in]	*C	The pointer at Verse context
 * \return		The function returns 1, when response was sent to the client
 * and it returns 0, when all needs were not meet or error occurred.
 */
int vs_RESPOND_methods_loop(struct vContext *C)
{
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VMessage *r_message = CTX_r_message(C);
	struct VMessage *s_message = CTX_s_message(C);
	int i, auth_req = 0,
			client_name_proposed = 0,
			client_version_proposed = 0;
	unsigned short buffer_pos = 0;

	/* Reset content of received message */
	memset(r_message, 0, sizeof(struct VMessage));

	/* Unpack Verse message header */
	buffer_pos += v_unpack_message_header(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

	/* Unpack all system commands */
	buffer_pos += v_unpack_message_system_commands(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

	v_print_receive_message(C);

	for(i=0; i<MAX_SYSTEM_COMMAND_COUNT && r_message->sys_cmd[i].cmd.id!=CMD_RESERVED_ID; i++) {
		switch(r_message->sys_cmd[i].cmd.id) {
		case CMD_USER_AUTH_REQUEST:
			if(r_message->sys_cmd[i].ua_req.method_type == VRS_UA_METHOD_NONE) {
				auth_req = 1;
			} else {
				v_print_log(VRS_PRINT_WARNING,
						"This auth method id: %d is not supported in this state\n",
						r_message->sys_cmd[i].ua_req.method_type);
			}
			break;
		case CMD_CHANGE_L_ID:
			/* Client could propose client name and version */
			if(r_message->sys_cmd[i].negotiate_cmd.feature == FTR_CLIENT_NAME) {
				if(r_message->sys_cmd[i].negotiate_cmd.count > 0) {
					/* Only first proposed client name will be used */
					vsession->client_name = strdup((char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str);
					client_name_proposed = 1;
				}
			} else if(r_message->sys_cmd[i].negotiate_cmd.feature == FTR_CLIENT_VERSION) {
				if(r_message->sys_cmd[i].negotiate_cmd.count > 0) {
					/* Only first proposed client name will be used */
					vsession->client_version = strdup((char*)r_message->sys_cmd[i].negotiate_cmd.value[0].string8.str);
					client_version_proposed = 1;
				}
			}
			break;
		default:
			v_print_log(VRS_PRINT_WARNING,
					"This command id: %d is not supported in this state\n",
					r_message->sys_cmd[i].cmd.id);
			break;
		}
	}

	if(auth_req == 1) {
		int cmd_rank = 0;
		/* VRS_UA_METHOD_NONE is not supported method. Send list of
		 * supported methods. Current implementation supports
		 * only PASSWORD method now. */

		s_message->sys_cmd[cmd_rank].ua_fail.id = CMD_USER_AUTH_FAILURE;
		/* List of supported methods */
		s_message->sys_cmd[cmd_rank].ua_fail.count = 1;
		s_message->sys_cmd[cmd_rank].ua_fail.method[0] = VRS_UA_METHOD_PASSWORD;
		cmd_rank++;

		/* Send confirmation about client name */
		if(client_name_proposed == 1) {
			v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CONFIRM_L_ID, FTR_CLIENT_NAME,
					vsession->client_name, NULL);
		}

		/* Send confirmation about client version only in situation, when
		 * client proposed client name too */
		if(client_version_proposed == 1) {
			if(client_name_proposed == 1) {
				v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CONFIRM_L_ID, FTR_CLIENT_VERSION,
						vsession->client_version, NULL);
			} else {
				/* Client version without client name is not allowed */
				v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CONFIRM_L_ID, FTR_CLIENT_VERSION,
						NULL);
			}
		}

		buffer_pos = VERSE_MESSAGE_HEADER_SIZE;

		/* Pack system commands to the buffer */
		buffer_pos += v_pack_stream_system_commands(s_message,&io_ctx->buf[buffer_pos]);

		s_message->header.len = io_ctx->buf_size = buffer_pos;
		s_message->header.version = VRS_VERSION;
		/* Pack header to the beginning of the buffer */
		v_pack_message_header(s_message, io_ctx->buf);

		/* Debug print of command to be send */
		if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
			v_print_send_message(C);
		}

		return 1;
	}

	return 0;
}
Ejemplo n.º 20
0
/**
 * \brief Main function for new thread. This thread is created for new
 * connection with client. This thread will try to authenticate new user
 * and negotiate new udp port. */
void *vs_tcp_conn_loop(void *arg)
{
	struct vContext *C = (struct vContext*)arg;
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VStreamConn *stream_conn = CTX_current_stream_conn(C);
	struct VMessage *r_message=NULL, *s_message=NULL;
	struct timeval tv;
	fd_set set;
	int error, ret;
	void *udp_thread_result;
	unsigned int int_size;

	/* Try to get size of TCP buffer */
	int_size = sizeof(int_size);
	getsockopt(io_ctx->sockfd, SOL_SOCKET, SO_RCVBUF,
			(void *)&stream_conn->socket_buffer_size, &int_size);

#ifdef WITH_OPENSSL
	/* Try to do TLS handshake with client */
	if(vs_TLS_handshake(C)!=1) {
		goto end;
	}
#endif

	r_message = (struct VMessage*)calloc(1, sizeof(struct VMessage));
	s_message = (struct VMessage*)calloc(1, sizeof(struct VMessage));
	CTX_r_message_set(C, r_message);
	CTX_s_message_set(C, s_message);

	stream_conn->host_state = TCP_SERVER_STATE_RESPOND_METHODS;

	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 31);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: RESPOND_methods\n");
		printf("%c[%dm", 27, 0);
	}

	/* "Never ending" loop */
	while(1)
	{
		FD_ZERO(&set);
		FD_SET(io_ctx->sockfd, &set);

		tv.tv_sec = VRS_TIMEOUT;	/* User have to send something in 30 seconds */
		tv.tv_usec = 0;

		if( (ret = select(io_ctx->sockfd+1, &set, NULL, NULL, &tv)) == -1) {
			if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "%s:%s():%d select(): %s\n",
					__FILE__, __FUNCTION__,  __LINE__, strerror(errno));
			goto end;
			/* Was event on the listen socket */
		} else if(ret>0 && FD_ISSET(io_ctx->sockfd, &set)) {

			/* Try to receive data through TCP connection */
			if( v_tcp_read(io_ctx, &error) <= 0 ) {
				goto end;
			}

			/* Handle verse handshake at TCP connection */
			if( (ret = vs_handle_handshake(C)) == -1) {
				goto end;
			}

			/* When there is something to send, then send it to peer */
			if( ret == 1 ) {
				/* Send response message to the client */
				if( (ret = v_tcp_write(io_ctx, &error)) <= 0) {
					goto end;
				}
			}

		} else {
			if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "No response in %d seconds\n", VRS_TIMEOUT);
			goto end;
		}
	}

end:
	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 31);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: CLOSING\n");
		printf("%c[%dm", 27, 0);
	}

	/* Set up TCP CLOSING state (non-blocking) */
	vs_CLOSING(C);

	/* Receive and Send messages are not neccessary any more */
	if(r_message != NULL) {
		free(r_message);
		r_message = NULL;
		CTX_r_message_set(C, NULL);
	}
	if(s_message != NULL) {
		free(s_message);
		s_message = NULL;
		CTX_s_message_set(C, NULL);
	}

	/* TCP connection is considered as CLOSED, but it is not possible to use
	 * this connection for other client */
	stream_conn->host_state = TCP_SERVER_STATE_CLOSED;

	/* NULL pointer at stream connection */
	CTX_current_stream_conn_set(C, NULL);

	/* Set TCP connection to CLOSED */
	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 31);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: CLOSED\n");
		printf("%c[%dm", 27, 0);
	}

	/* Was udp thread created? */
	if(vsession->udp_thread != 0 ) {
		/* Wait for UDP thread (this is blocking operation) */
		v_print_log(VRS_PRINT_DEBUG_MSG, "Waiting for join with UDP thread ...\n");
		if(pthread_join(vsession->udp_thread, &udp_thread_result) != 0) {
			v_print_log(VRS_PRINT_DEBUG_MSG, "UDP thread was not joined\n");
		}
	}

	pthread_mutex_lock(&vs_ctx->data.mutex);
	/* Unsubscribe this session (this avatar) from all nodes */
	vs_node_free_avatar_reference(vs_ctx, vsession);
	/* Try to destroy avatar node */
	vs_node_destroy_avatar_node(vs_ctx, vsession);
	pthread_mutex_unlock(&vs_ctx->data.mutex);

	/* This session could be used again for authentication */
	stream_conn->host_state = TCP_SERVER_STATE_LISTEN;

	/* Clear session flags */
	vsession->flags = 0;

	if(vsession->peer_cookie.str != NULL) {
		free(vsession->peer_cookie.str);
		vsession->peer_cookie.str = NULL;
	}
	if(vsession->ded.str != NULL) {
		free(vsession->ded.str);
		vsession->ded.str = NULL;
	}
	if(vsession->client_name != NULL) {
		free(vsession->client_name);
		vsession->client_name = NULL;
	}
	if(vsession->client_version != NULL) {
		free(vsession->client_version);
		vsession->client_version = NULL;
	}

	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 31);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: LISTEN\n");
		printf("%c[%dm", 27, 0);
	}

	free(C);
	C = NULL;

	pthread_exit(NULL);
	return NULL;
}
Ejemplo n.º 21
0
/**
 * \brief This function send packets in OPEN and CLOSEREQ state.
 */
int send_packet_in_OPEN_CLOSEREQ_state(struct vContext *C)
{
	struct VDgramConn *vconn = CTX_current_dgram_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VPacket *s_packet = CTX_s_packet(C);
	struct VSent_Packet *sent_packet = NULL;
	unsigned short buffer_pos = 0;
	struct timeval tv;
	int ret, keep_alive_packet = -1, full_packet = 0;
	int error_num;
	uint16 swin, prio_win, sent_size = 0;
	uint32 rwin;
	int cmd_rank = 0;

	/* Verse packet header */
	s_packet->header.version = 1;

	/* Clear header flags */
	s_packet->header.flags = 0;

	/* Check if it is necessary to send payload packet */
	ret = check_pay_flag(C);
	if(ret!=0) {
		s_packet->header.flags |= PAY_FLAG;
		if(ret==2) {
			keep_alive_packet = 1;
		}
	}

	/* When server is in CLOSEREQ state, then FIN flag should be set up */
	if(vconn->host_state == UDP_SERVER_STATE_CLOSEREQ) {
		s_packet->header.flags |= FIN_FLAG;
	}

	/* Check if it is necessary to send acknowledgment of received payload
	 * packet */
	ret = check_ack_nak_flag(C);
	if(ret==1) {
		s_packet->header.flags |= ACK_FLAG;

		/* Update last acknowledged Payload packet */
		vconn->last_acked_pay = vconn->last_r_pay;

		/* Add ACK and NAK commands from the list of ACK and NAK commands to the
		 * packet (only max count of ACK and NAK commands could be added to
		 * the packet) */
		for(cmd_rank = 0;
				cmd_rank < vconn->ack_nak.count &&
				cmd_rank < MAX_SYSTEM_COMMAND_COUNT;
				cmd_rank++)
		{
			s_packet->sys_cmd[cmd_rank].ack_cmd.id = vconn->ack_nak.cmds[cmd_rank].id;
			s_packet->sys_cmd[cmd_rank].ack_cmd.pay_id = vconn->ack_nak.cmds[cmd_rank].pay_id;
		}
		s_packet->sys_cmd[cmd_rank].cmd.id = CMD_RESERVED_ID;

	}

	/* If there is no need to send Payload or AckNak packet, then cancel
	 * sending of packet */
	if(! ((s_packet->header.flags & PAY_FLAG) ||
			(s_packet->header.flags & ACK_FLAG)) ) return SEND_PACKET_CANCELED;

	s_packet->header.flags |= ANK_FLAG;
	s_packet->header.ank_id = vconn->ank_id;

	/* Compute current windows for flow control and congestion control */
	set_host_rwin(C);
	set_host_cwin(C);

	/* Set window of flow control that will sent to receiver */
	rwin = vconn->rwin_host >> vconn->rwin_host_scale;
	s_packet->header.window = (unsigned short)(rwin > 0xFFFF) ? 0xFFFF : rwin;
	/*printf("\t---real window: %d---\n", s_packet->header.window);*/

	/* Compute how many data could be sent to not congest receiver */
	rwin = vconn->rwin_peer - vconn->sent_size;

	/* Select smallest window for sending (congestion control window or flow control window)*/
	swin = (vconn->cwin < rwin) ? vconn->cwin : rwin;

	/* Set up Payload ID, when there is need to send payload packet */
	if(s_packet->header.flags & PAY_FLAG)
		s_packet->header.payload_id = vconn->host_id + vconn->count_s_pay;
	else
		s_packet->header.payload_id  = 0;

	/* Set up AckNak ID, when there are some ACK or NAK command in the packet */
	if(s_packet->header.flags & ACK_FLAG)
		s_packet->header.ack_nak_id = vconn->count_s_ack;
	else
		s_packet->header.ack_nak_id = 0;

	/* When negotiated and used FPS is different, then pack negotiate command
	 * for FPS */
	if(vsession->fps_host != vsession->fps_peer) {
		cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
				CMD_CHANGE_L_ID, FTR_FPS, &vsession->fps_host, NULL);
	} else {
		if(vsession->tmp_flags & SYS_CMD_NEGOTIATE_FPS) {
			cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
					CMD_CONFIRM_L_ID, FTR_FPS, &vsession->fps_peer, NULL);
			/* Send confirmation only once for received system command */
			vsession->tmp_flags &= ~SYS_CMD_NEGOTIATE_FPS;
		}
	}

	v_print_send_packet(C);

	/* Fill buffer */
	buffer_pos += v_pack_packet_header(s_packet, &io_ctx->buf[buffer_pos]);
	buffer_pos += v_pack_dgram_system_commands(s_packet, &io_ctx->buf[buffer_pos]);

	/* When this is not pure keep alive packet */
	if(s_packet->header.flags & PAY_FLAG) {

		sent_packet = v_packet_history_add_packet(&vconn->packet_history, s_packet->header.payload_id);

		assert(sent_packet != NULL);

		if(keep_alive_packet != 1) {
			real32 prio_sum_high, prio_sum_low, r_prio;
			uint32 prio_count;
			int16 prio, max_prio, min_prio;
			uint16 tot_cmd_size;

			/* Print outgoing command with green color */
			if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
				printf("%c[%d;%dm", 27, 1, 32);
			}

			max_prio = v_out_queue_get_max_prio(vsession->out_queue);
			min_prio = v_out_queue_get_min_prio(vsession->out_queue);

			prio_sum_high = v_out_queue_get_prio_sum_high(vsession->out_queue);
			prio_sum_low = v_out_queue_get_prio_sum_low(vsession->out_queue);

			v_print_log(VRS_PRINT_DEBUG_MSG, "Packing prio queues, cmd count: %d\n", v_out_queue_get_count(vsession->out_queue));

			/* Go through all priorities and pick commands from priority queues */
			for(prio = max_prio; prio >= min_prio; prio--)
			{
				/* TODO: Add better check here */
				if(prio <= VRS_DEFAULT_PRIORITY && buffer_pos >= vconn->io_ctx.mtu) {
					break;
				}

				prio_count = v_out_queue_get_count_prio(vsession->out_queue, prio);

				if(prio_count > 0) {
					r_prio = v_out_queue_get_prio(vsession->out_queue, prio);

					/* Compute size of buffer that could be occupied by
					 * commands from this queue */
					if(prio >= VRS_DEFAULT_PRIORITY) {
						prio_win = ((swin - buffer_pos)*r_prio)/prio_sum_high;
					} else {
						prio_win = ((swin - buffer_pos)*r_prio)/prio_sum_low;
					}

					/* Debug print */
					v_print_log(VRS_PRINT_DEBUG_MSG, "Queue: %d, count: %d, r_prio: %6.3f, prio_win: %d\n",
							prio, prio_count, r_prio, prio_win);

					/* Get total size of commands that were stored in queue (sent_size) */
					tot_cmd_size = 0;
					/* Pack commands from queues with high priority to the buffer */
					buffer_pos = pack_prio_queue(C, sent_packet, buffer_pos, prio, prio_win, &tot_cmd_size);
					sent_size += tot_cmd_size;
				}
			}

			/* Use default color for output */
			if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
				printf("%c[%dm", 27, 0);
			}
		} else {
			if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
				printf("%c[%d;%dm", 27, 1, 32);
				v_print_log(VRS_PRINT_DEBUG_MSG, "Keep alive packet\n");
				printf("%c[%dm", 27, 0);
			}
		}
	}

	/* Update sent_size */
	vconn->sent_size += sent_size;

	io_ctx->buf_size = buffer_pos;

	/* Send buffer */
	ret = v_send_packet(io_ctx, &error_num);

	if(ret==SEND_PACKET_SUCCESS) {
		gettimeofday(&tv, NULL);

		/* Update time of sending last payload packet */
		if(s_packet->header.flags & PAY_FLAG) {
			vconn->tv_pay_send.tv_sec = tv.tv_sec;
			vconn->tv_pay_send.tv_usec = tv.tv_usec;
			/* Store time of sending packet in history of sent packets. It is
			 * used for computing RTT and SRTT */
			if(sent_packet != NULL) {
				sent_packet->tv.tv_sec = tv.tv_sec;
				sent_packet->tv.tv_usec = tv.tv_usec;
			}
		}

		/* Update time of sending last acknowledgment packet */
		if(s_packet->header.flags & ACK_FLAG) {
			vconn->tv_ack_send.tv_sec = tv.tv_sec;
			vconn->tv_ack_send.tv_usec = tv.tv_usec;
		}

		/* Update counter of sent packets */
		if(s_packet->header.flags & PAY_FLAG) vconn->count_s_pay++;
		if(s_packet->header.flags & ACK_FLAG) vconn->count_s_ack++;

		/* If the packet was sent full and there are some pending data to send
		 * then modify returned value*/
		if(full_packet == 1) {
			ret = SEND_PACKET_FULL;
		}
	} else {
		/* When packet wasn't sent, then remove this packet from history */
		if(sent_packet != NULL) {
			v_packet_history_rem_packet(C, s_packet->header.payload_id);
		}
	}

	/*v_print_packet_history(&vconn->packet_history);*/

	return ret;
}
Ejemplo n.º 22
0
/**
 * \brief This function is never ending loop of server state STREAM_OPEN.
 * This loop is used, when Verse server uses TCP for data exchange (not
 * UDP nor WebSocket)
 */
int vs_STREAM_OPEN_tcp_loop(struct vContext *C)
{
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct timeval tv;
	fd_set set;
	int flag, ret, error;

	/* Set socket non-blocking */
	flag = fcntl(io_ctx->sockfd, F_GETFL, 0);
	if( (fcntl(io_ctx->sockfd, F_SETFL, flag | O_NONBLOCK)) == -1) {
		if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "fcntl(): %s\n", strerror(errno));
		return -1;
	}

	/* "Never ending" loop */
	while(1)
	{
		FD_ZERO(&set);
		FD_SET(io_ctx->sockfd, &set);

		/* Use negotiated FPS */
		tv.tv_sec = 0;
		tv.tv_usec = 1000000/vsession->fps_host;

		/* Wait for recieved data */
		if( (ret = select(io_ctx->sockfd+1, &set, NULL, NULL, &tv)) == -1) {
			if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "%s:%s():%d select(): %s\n",
					__FILE__, __FUNCTION__,  __LINE__, strerror(errno));
			goto end;
			/* Was event on the listen socket */
		} else if(ret>0 && FD_ISSET(io_ctx->sockfd, &set)) {

			/* Try to receive data through SSL connection */
			if( v_tcp_read(io_ctx, &error) <= 0 ) {
				goto end;
			}

			if(v_STREAM_handle_messages(C) == 0) {
				goto end;
			}

			/* When some payload data were received, then poke data thread */
			sem_post(vs_ctx->data.sem);
		}

		if( (ret = v_STREAM_pack_message(C)) == 0 ) {
			goto end;
		}

		/* Send command to the client */
		if(ret == 1) {
			if( v_tcp_write(io_ctx, &error) <= 0) {
				goto end;
			}
		}
	}
end:

	/* Set socket blocking again */
	flag = fcntl(io_ctx->sockfd, F_GETFL, 0);
	if( (fcntl(io_ctx->sockfd, F_SETFL, flag & ~O_NONBLOCK)) == -1) {
		if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "fcntl(): %s\n", strerror(errno));
		return -1;
	}

	return 0;
}
Ejemplo n.º 23
0
/**
 * \brief This function handles messages received during verse handshake
 * and it can create new thread for datagram connection.
 */
int vs_handle_handshake(struct vContext *C, char *u_name)
{
	struct VSession *vsession = CTX_current_session(C);
	struct VStreamConn *stream_conn = CTX_current_stream_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	int ret;

	/* Make sure, that buffer contains at least Verse message
	 * header. If this condition is not reached, then somebody tries
	 * to do some very bad things! .. Close this connection. */
	if(io_ctx->buf_size < VERSE_MESSAGE_HEADER_SIZE) {
		if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "received buffer too small %d\n",
				io_ctx->buf_size);
		return -1;
	}

	switch(stream_conn->host_state) {
	case TCP_SERVER_STATE_RESPOND_METHODS:
		ret = vs_RESPOND_methods_loop(C);
		if(ret==1) {
			stream_conn->host_state = TCP_SERVER_STATE_RESPOND_USRAUTH;
			if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
				printf("%c[%d;%dm", 27, 1, 31);
				v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: RESPOND_userauth\n");
				printf("%c[%dm", 27, 0);
			}
		} else {
			return -1;
		}
		break;
	case TCP_SERVER_STATE_RESPOND_USRAUTH:
		ret = vs_RESPOND_userauth_loop(C);
		if(ret==1) {
			stream_conn->host_state = TCP_SERVER_STATE_NEGOTIATE_COOKIE_DED;

			if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
				printf("%c[%d;%dm", 27, 1, 31);
				v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: NEGOTIATE_cookie_ded\n");
				printf("%c[%dm", 27, 0);
			}
		} else {
			vsession->usr_auth_att++;
			if(vsession->usr_auth_att >= MAX_USER_AUTH_ATTEMPTS) {
				return -1;
			}
		}
		break;
#ifdef WITH_KERBEROS
	case TCP_SERVER_STATE_RESPOND_KRB_AUTH:
		ret = vs_RESPOND_krb_auth_loop(C, u_name);
		if (ret == 1) {
			stream_conn->host_state = TCP_SERVER_STATE_NEGOTIATE_COOKIE_DED;

			if (is_log_level(VRS_PRINT_DEBUG_MSG)) {
				printf("%c[%d;%dm", 27, 1, 31);
				v_print_log(VRS_PRINT_DEBUG_MSG,
						"Server TCP state: NEGOTIATE_cookie_ded\n");
				printf("%c[%dm", 27, 0);
			}
		} else {
			return -1;
		}
		break;
#endif
	case TCP_SERVER_STATE_NEGOTIATE_COOKIE_DED:
		ret = vs_NEGOTIATE_cookie_ded_loop(C);
		if(ret==1) {
			stream_conn->host_state = TCP_SERVER_STATE_NEGOTIATE_NEWHOST;

			if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
				printf("%c[%d;%dm", 27, 1, 31);
				v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: NEGOTIATE_newhost\n");
				printf("%c[%dm", 27, 0);
			}
		} else {
			return -1;
		}
		break;
	case TCP_SERVER_STATE_NEGOTIATE_NEWHOST:
		/* Wait VERSE_TIMEOT seconds to confirming proposed URL */
		ret = vs_NEGOTIATE_newhost_loop(C);
		if(ret == 1) {
			if(vsession->flags & VRS_TP_UDP) {
				/* When URL was confirmed, then go to the end state */
				return -1;
			} else if(vsession->flags & VRS_TP_TCP) {
				stream_conn->host_state = TCP_SERVER_STATE_STREAM_OPEN;

				if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
					printf("%c[%d;%dm", 27, 1, 31);
					v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: STREAM_OPEN\n");
					printf("%c[%dm", 27, 0);
				}

				vs_STREAM_OPEN_tcp_loop(C);
				return -1;
			} else if(vsession->flags & VRS_TP_WEBSOCKET) {
				stream_conn->host_state = TCP_SERVER_STATE_STREAM_OPEN;

				if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
					printf("%c[%d;%dm", 27, 1, 31);
					v_print_log(VRS_PRINT_DEBUG_MSG, "Server TCP state: STREAM_OPEN\n");
					printf("%c[%dm", 27, 0);
				}
			}
		} else {
			/* When thread was not confirmed, then try to cancel
			 * UDP thread*/
			if(pthread_cancel(vsession->udp_thread) != 0) {
				v_print_log(VRS_PRINT_DEBUG_MSG, "UDP thread was not canceled\n");
			}
			return -1;
		}
		break;

	}

	return 1;
}
Ejemplo n.º 24
0
int vs_RESPOND_userauth_loop(struct vContext *C)
{
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VMessage *r_message = CTX_r_message(C);
	struct VMessage *s_message = CTX_s_message(C);
	int i, cmd_rank = 0;
	unsigned short buffer_pos = 0;

	/* Reset content of received message */
	memset(r_message, 0, sizeof(struct VMessage));

	/* Unpack Verse message header */
	buffer_pos += v_unpack_message_header(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

	/* Unpack all system commands */
	buffer_pos += v_unpack_message_system_commands(&io_ctx->buf[buffer_pos], (io_ctx->buf_size - buffer_pos), r_message);

	v_print_receive_message(C);

	for(i=0; i<MAX_SYSTEM_COMMAND_COUNT && r_message->sys_cmd[i].cmd.id!=CMD_RESERVED_ID; i++) {
		if(r_message->sys_cmd[i].cmd.id == CMD_USER_AUTH_REQUEST) {
			if(r_message->sys_cmd[i].ua_req.method_type == VRS_UA_METHOD_PASSWORD) {
				int user_id;

				/* Do user authentication */
				if((user_id = vs_user_auth(C,
						r_message->sys_cmd[i].ua_req.username,
						r_message->sys_cmd[i].ua_req.data)) != -1)
				{
					long int avatar_id;

					pthread_mutex_lock(&vs_ctx->data.mutex);
					avatar_id = vs_create_avatar_node(vs_ctx, vsession, user_id);
					pthread_mutex_unlock(&vs_ctx->data.mutex);

					if(avatar_id == -1) {
						v_print_log(VRS_PRINT_ERROR, "Failed to create avatar node\n");
						return 0;
					}

					buffer_pos = VERSE_MESSAGE_HEADER_SIZE;

					/* Save user_id to the session and send it in
					 * connect_accept command */
					vsession->user_id = user_id;
					vsession->avatar_id = avatar_id;

					s_message->sys_cmd[cmd_rank].ua_succ.id = CMD_USER_AUTH_SUCCESS;
					s_message->sys_cmd[cmd_rank].ua_succ.user_id = user_id;
					s_message->sys_cmd[cmd_rank].ua_succ.avatar_id = avatar_id;
					cmd_rank++;

					/* Generate random string for coockie */
					vsession->peer_cookie.str = (char*)calloc((COOKIE_SIZE+1), sizeof(char));
					for(i=0; i<COOKIE_SIZE; i++) {
						/* Generate only printable characters (debug prints) */
						vsession->peer_cookie.str[i] = 32 + (char)((float)rand()*94.0/RAND_MAX);
					}
					vsession->peer_cookie.str[COOKIE_SIZE] = '\0';
					/* Set up negotiate command of the host cookie */
					v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CHANGE_R_ID, FTR_COOKIE,
							vsession->peer_cookie.str, NULL);

					/* Load DED from configuration and save it to the session */
					vsession->ded.str = strdup(vs_ctx->ded);
					v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank++, CMD_CHANGE_L_ID, FTR_DED,
							vsession->ded.str, NULL);

					buffer_pos += v_pack_stream_system_commands(s_message, &io_ctx->buf[buffer_pos]);

					s_message->header.len = io_ctx->buf_size = buffer_pos;
					s_message->header.version = VRS_VERSION;
					/* Pack header to the beginning of the buffer */
					v_pack_message_header(s_message, io_ctx->buf);

					v_print_send_message(C);

					return 1;
				} else {

					buffer_pos = VERSE_MESSAGE_HEADER_SIZE;

					s_message->sys_cmd[0].ua_fail.id = CMD_USER_AUTH_FAILURE;
					s_message->sys_cmd[0].ua_fail.count = 0;

					s_message->sys_cmd[1].cmd.id = CMD_RESERVED_ID;

					buffer_pos += v_pack_stream_system_commands(s_message, &io_ctx->buf[buffer_pos]);

					s_message->header.len = io_ctx->buf_size = buffer_pos;
					s_message->header.version = VRS_VERSION;
					/* Pack header to the beginning of the buffer */
					v_pack_message_header(s_message, io_ctx->buf);

					v_print_send_message(C);

					return 1;
				}
			}
		}
	}
	return 0;
}
Ejemplo n.º 25
0
/**
 * \brief This connection tries to handle new connection attempt. When this
 * attempt is successful, then it creates new thread
 */
static int vs_new_stream_conn(struct vContext *C, void *(*conn_loop)(void*))
{
	VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VSession *current_session = NULL;
	socklen_t addr_len;
	int ret, i;
	static uint32 last_session_id = 0;

	/* Try to find free session */
	for(i=0; i< vs_ctx->max_sessions; i++) {
		if(vs_ctx->vsessions[i]->stream_conn->host_state == TCP_SERVER_STATE_LISTEN) {
			/* TODO: lock mutex here */
			current_session = vs_ctx->vsessions[i];
			current_session->stream_conn->host_state = TCP_SERVER_STATE_RESPOND_METHODS;
			current_session->session_id = last_session_id++;
			/* TODO: unlock mutex here */
			break;
		}
	}

	if(current_session != NULL) {
		struct vContext *new_C;
		int flag;

		/* Try to accept client connection (do TCP handshake) */
		if(io_ctx->host_addr.ip_ver==IPV4) {
			/* Prepare IPv4 variables for TCP handshake */
			struct sockaddr_in *client_addr4 = &current_session->stream_conn->io_ctx.peer_addr.addr.ipv4;
			current_session->stream_conn->io_ctx.peer_addr.ip_ver = IPV4;
			addr_len = sizeof(current_session->stream_conn->io_ctx.peer_addr.addr.ipv4);

			/* Try to do TCP handshake */
			if( (current_session->stream_conn->io_ctx.sockfd = accept(io_ctx->sockfd, (struct sockaddr*)client_addr4, &addr_len)) == -1) {
				if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "accept(): %s\n", strerror(errno));
				return 0;
			}

			/* Save the IPv4 of the client as string in verse session */
			inet_ntop(AF_INET, &client_addr4->sin_addr, current_session->peer_hostname, INET_ADDRSTRLEN);
		} else if(io_ctx->host_addr.ip_ver==IPV6) {
			/* Prepare IPv6 variables for TCP handshake */
			struct sockaddr_in6 *client_addr6 = &current_session->stream_conn->io_ctx.peer_addr.addr.ipv6;
			current_session->stream_conn->io_ctx.peer_addr.ip_ver = IPV6;
			addr_len = sizeof(current_session->stream_conn->io_ctx.peer_addr.addr.ipv6);

			/* Try to do TCP handshake */
			if( (current_session->stream_conn->io_ctx.sockfd = accept(io_ctx->sockfd, (struct sockaddr*)client_addr6, &addr_len)) == -1) {
				if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "accept(): %s\n", strerror(errno));
				return 0;
			}

			/* Save the IPv6 of the client as string in verse session */
			inet_ntop(AF_INET6, &client_addr6->sin6_addr, current_session->peer_hostname, INET6_ADDRSTRLEN);
		}

		/* Set to this socket flag "no delay" */
		flag = 1;
		if(setsockopt(current_session->stream_conn->io_ctx.sockfd,
				IPPROTO_TCP, TCP_NODELAY, &flag, (socklen_t)sizeof(flag)) == -1)
		{
			if(is_log_level(VRS_PRINT_ERROR)) {
				v_print_log(VRS_PRINT_ERROR,
						"setsockopt: TCP_NODELAY: %d\n",
						strerror(errno));
			}
			return -1;;
		}

		CTX_current_session_set(C, current_session);
		CTX_current_stream_conn_set(C, current_session->stream_conn);
		CTX_io_ctx_set(C, &current_session->stream_conn->io_ctx);

		if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
			v_print_log(VRS_PRINT_DEBUG_MSG, "New connection from: ");
			v_print_addr_port(VRS_PRINT_DEBUG_MSG, &(current_session->stream_conn->io_ctx.peer_addr));
			v_print_log_simple(VRS_PRINT_DEBUG_MSG, "\n");
		}

		/* Duplicate verse context for new thread */
		new_C = (struct vContext*)calloc(1, sizeof(struct vContext));
		memcpy(new_C, C, sizeof(struct vContext));

		/* Try to initialize thread attributes */
		if( (ret = pthread_attr_init(&current_session->tcp_thread_attr)) !=0 ) {
			if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "pthread_attr_init(): %s\n", strerror(errno));
			return 0;
		}

		/* Try to set thread attributes as detached */
		if( (ret = pthread_attr_setdetachstate(&current_session->tcp_thread_attr, PTHREAD_CREATE_DETACHED)) != 0) {
			if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "pthread_attr_setdetachstate(): %s\n", strerror(errno));
			return 0;
		}

		/* Try to create new thread */
		if((ret = pthread_create(&current_session->tcp_thread, &current_session->tcp_thread_attr, conn_loop, (void*)new_C)) != 0) {
			if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "pthread_create(): %s\n", strerror(errno));
		}

		/* Destroy thread attributes */
		pthread_attr_destroy(&current_session->tcp_thread_attr);
	} else {
		int tmp_sockfd;
		v_print_log(VRS_PRINT_DEBUG_MSG, "Number of session slot: %d reached\n", vs_ctx->max_sessions);
		/* TODO: return some error. Not only accept and close connection. */
		/* Try to accept client connection (do TCP handshake) */
		if(io_ctx->host_addr.ip_ver == IPV4) {
			/* Prepare IP6 variables for TCP handshake */
			struct sockaddr_in client_addr4;

			addr_len = sizeof(client_addr4);

			/* Try to do TCP handshake */
			if( (tmp_sockfd = accept(io_ctx->sockfd, (struct sockaddr*)&client_addr4, &addr_len)) == -1) {
				if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "accept(): %s\n", strerror(errno));
				return 0;
			}
			/* Close connection (no more free session slots) */
			close(tmp_sockfd);
		} else if(io_ctx->host_addr.ip_ver == IPV6) {
			/* Prepare IP6 variables for TCP handshake */
			struct sockaddr_in6 client_addr6;
			addr_len = sizeof(client_addr6);

			/* Try to do TCP handshake */
			if( (tmp_sockfd = accept(io_ctx->sockfd, (struct sockaddr*)&client_addr6, &addr_len)) == -1) {
				if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "accept(): %s\n", strerror(errno));
				return 0;
			}
			/* Close connection (no more free session slots) */
			close(tmp_sockfd);
		}
		/* TODO: Fix this */
		sleep(1);
	}

	return 1;
}