/** * \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; }
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; }
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; }
/** * \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; }
/** * \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; }