示例#1
0
/**
 * \brief Teardown TLS connection with client
 * \param[in]	*C	The context of verse server
 * \return This function returns 1, when TLS teardown was successfull, otherwise
 * it returns 0.
 */
int vs_TLS_teardown(struct vContext *C)
{
	struct VStreamConn *stream_conn = CTX_current_stream_conn(C);
	int ret;

	v_print_log(VRS_PRINT_DEBUG_MSG, "Try to shut down SSL connection.\n");

	ret = SSL_shutdown(stream_conn->io_ctx.ssl);
	if(ret!=1) {
		ret = SSL_shutdown(stream_conn->io_ctx.ssl);
	}

	switch(ret) {
	case 1:
		/* SSL was successfully closed */
		v_print_log(VRS_PRINT_DEBUG_MSG, "SSL connection was shut down.\n");
		break;
	case 0:
	case -1:
	default:
		/* some error occured */
		v_print_log(VRS_PRINT_DEBUG_MSG, "SSL connection was not able to shut down.\n");
		break;
	}

	SSL_free(stream_conn->io_ctx.ssl);

	return 1;
}
示例#2
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;
}
示例#3
0
/**
 * \brief This function do TLS teardown, when it is reuired and it
 * closes socket.
 */
void vs_CLOSING(struct vContext *C)
{
	struct VStreamConn *stream_conn = CTX_current_stream_conn(C);

#ifdef WITH_OPENSSL
	if(stream_conn->io_ctx.ssl!=NULL) vs_TLS_teardown(C);
#endif

	close(stream_conn->io_ctx.sockfd);
}
示例#4
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;
}
示例#5
0
文件: v_stream.c 项目: laishi/verse
/**
 * \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;
}
示例#6
0
void* vc_main_dgram_loop(void *arg)
{
	struct vContext *C = (struct vContext*)arg;
	struct VSession *vsession = CTX_current_session(C);
	struct VDgramConn *dgram_conn = vsession->dgram_conn;
	struct VStreamConn *stream_conn = CTX_current_stream_conn(C);
	struct VPacket *r_packet, *s_packet;
	char error = 0;
	const uint8 *ret_val = 0;

	if(dgram_conn==NULL) {
		/* Create new datagrame connection */
		if((dgram_conn = vc_create_client_dgram_conn(C))==NULL) {
			goto finish;
		}
		vsession->dgram_conn = dgram_conn;
	}

	CTX_current_dgram_conn_set(C, dgram_conn);
	CTX_io_ctx_set(C, &dgram_conn->io_ctx);

#if (defined WITH_OPENSSL) && OPENSSL_VERSION_NUMBER>=0x10000000
	/* If negotiated security is DTLS, then try to do DTLS handshake */
	if(dgram_conn->io_ctx.flags & SOCKET_SECURED) {
		if(vc_create_dtls_connection(C) == 0) {
			CTX_current_dgram_conn_set(C, NULL);
			CTX_io_ctx_set(C, NULL);
			free(dgram_conn);
			ret_val = &vrs_conn_term_error;
			goto finish;
		}
	}
#endif

	/* Packet structure for receiving */
	r_packet = (struct VPacket*)malloc(sizeof(struct VPacket));
	CTX_r_packet_set(C, r_packet);

	/* Packet structure for sending */
	s_packet = (struct VPacket*)malloc(sizeof(struct VPacket));
	CTX_s_packet_set(C, s_packet);

	/* Run loop of the first phase of the handshake */
	if((error = vc_REQUEST_loop(C)) == STATE_EXIT_ERROR) {
		/* Do not confirm proposed URL, when client was not able to connect
		 * to the server */
		CTX_io_ctx_set(C, &stream_conn->io_ctx);
		vc_NEGOTIATE_newhost(C, NULL);
		CTX_io_ctx_set(C, &dgram_conn->io_ctx);
		ret_val = &vrs_conn_term_error;
		goto end;
	}

	/* When server responded in the first phase of the handshake, then run loop of the second
	 * phase of the handshake */
	if((error = vc_PARTOPEN_loop(C)) ==  STATE_EXIT_ERROR) {
		/* Do not confirm proposed URL, when client was not able to connect
		 * to the server */
		CTX_io_ctx_set(C, &stream_conn->io_ctx);
		vc_NEGOTIATE_newhost(C, NULL);
		CTX_io_ctx_set(C, &dgram_conn->io_ctx);
		ret_val = &vrs_conn_term_error;
		goto end;
	} else {
		struct Connect_Accept_Cmd *conn_accept;

		/* Put connect accept command to queue -> call callback function */
		conn_accept = v_Connect_Accept_create(vsession->avatar_id, vsession->user_id);
		v_in_queue_push(vsession->in_queue, (struct Generic_Cmd*)conn_accept);

		/* Send confirmation of the URL to the server */
		CTX_io_ctx_set(C, &stream_conn->io_ctx);
		vc_NEGOTIATE_newhost(C, vsession->host_url);
		CTX_io_ctx_set(C, &dgram_conn->io_ctx);

		/* TCP connection could be closed now */
		vsession->stream_conn->host_state = TCP_CLIENT_STATE_CLOSING;
	}

	/* Main loop for data exchange */
	if((error = vc_OPEN_loop(C)) == STATE_EXIT_ERROR) {
		ret_val = &vrs_conn_term_error;
		goto end;
	}

	/* Closing loop */
	if((error = vc_CLOSING_loop(C)) == STATE_EXIT_ERROR) {
		ret_val = &vrs_conn_term_error;
		goto end;
	}

	/* TODO: distinguish between terminating connection by server and client */
	ret_val = &vrs_conn_term_server;

end:

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

	free(r_packet);
	free(s_packet);

#if (defined WITH_OPENSSL) && OPENSSL_VERSION_NUMBER>=0x10000000
	if(dgram_conn->io_ctx.flags & SOCKET_SECURED) {
		vc_destroy_dtls_connection(C);
	}
#endif

	v_conn_dgram_destroy(dgram_conn);

	CTX_current_dgram_conn_set(C, NULL);

finish:
	pthread_exit((void*)ret_val);
	return NULL;
}
示例#7
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;
}
示例#8
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;
}
示例#9
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;
}