int wslay_event_queue_close(wslay_event_context_ptr ctx, uint16_t status_code, const uint8_t *reason, size_t reason_length) { if (!wslay_event_is_msg_queueable(ctx)) { return WSLAY_ERR_NO_MORE_MSG; } else if (reason_length > 123) { return WSLAY_ERR_INVALID_ARGUMENT; } else { uint8_t msg[128]; size_t msg_length; struct wslay_event_msg arg; uint16_t ncode; int r; if (status_code == 0) { msg_length = 0; } else { ncode = htons(status_code); memcpy(msg, &ncode, 2); memcpy(msg + 2, reason, reason_length); msg_length = reason_length + 2; } arg.opcode = WSLAY_CONNECTION_CLOSE; arg.msg = msg; arg.msg_length = msg_length; r = wslay_event_queue_msg(ctx, &arg); if (r == 0) { ctx->close_status |= WSLAY_CLOSE_QUEUED; } return r; } }
int dslink_ws_send(wslay_event_context_ptr ctx, const char *data) { struct wslay_event_msg msg; msg.msg = (const uint8_t *) data; msg.msg_length = strlen(data); msg.opcode = WSLAY_TEXT_FRAME; wslay_event_queue_msg(ctx, &msg); wslay_event_send(ctx); log_debug("Message sent: %s\n", data); return 0; }
void on_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg, void *user_data) { if(!wslay_is_ctrl_frame(arg->opcode)) { struct wslay_event_msg msgarg = { arg->opcode, arg->msg, arg->msg_length }; wslay_event_queue_msg(ctx, &msgarg); } }
void WebSocket::write(const Message& msg) { const String& data = msg.message(); wslay_event_msg wmsg = { static_cast<uint8_t>(msg.opcode()), reinterpret_cast<const uint8_t*>(data.constData()), static_cast<size_t>(data.size()) }; wslay_event_queue_msg(mCtx, &wmsg); wslay_event_send(mCtx); }
static void on_ws_message(h2o_websocket_conn_t *conn, const struct wslay_event_on_msg_recv_arg *arg) { if (arg == NULL) { h2o_websocket_close(conn); return; } if (!wslay_is_ctrl_frame(arg->opcode)) { struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length}; wslay_event_queue_msg(conn->ws_ctx, &msgarg); } }
websocket_return_t websocket_queue_msg(websocket_t *websocket, websocket_frame_t *tx_frame) { if (websocket == NULL || tx_frame == NULL) { WEBSOCKET_DEBUG("NULL parameter\n"); return WEBSOCKET_ALLOCATION_ERROR; } if (websocket->state == WEBSOCKET_STOP) { WEBSOCKET_DEBUG("websocket is not running state.\n"); return WEBSOCKET_INIT_ERROR; } return wslay_event_queue_msg(websocket->ctx, tx_frame); }
static int dslink_ws_send_internal(wslay_event_context_ptr ctx, const char *data, uint8_t resend) { (void) resend; struct wslay_event_msg msg; msg.msg = (const uint8_t *) data; msg.msg_length = strlen(data); msg.opcode = WSLAY_TEXT_FRAME; if (wslay_event_queue_msg(ctx, &msg) != 0) { return 1; } if (wslay_event_send(ctx) != 0) { return 1; } log_debug("Message sent: %s\n", data); return 0; }
websocket_return_t websocket_queue_ping(websocket_t *websocket) { websocket_frame_t tx_frame; if (websocket == NULL) { WEBSOCKET_DEBUG("NULL parameter\n"); return WEBSOCKET_ALLOCATION_ERROR; } if (websocket->state == WEBSOCKET_STOP) { WEBSOCKET_DEBUG("websocket is not running state.\n"); return WEBSOCKET_INIT_ERROR; } tx_frame.opcode = WEBSOCKET_PING; tx_frame.msg = (uint8_t *) "\0"; tx_frame.msg_length = strlen((const char *)tx_frame.msg); return wslay_event_queue_msg(websocket->ctx, &tx_frame); }
static mrb_value mrb_wslay_event_queue_msg(mrb_state *mrb, mrb_value self) { mrb_wslay_user_data *data = (mrb_wslay_user_data *) DATA_PTR(self); mrb_assert(data); mrb_value msg; mrb_sym opcode; mrb_int opc; if (mrb_get_args(mrb, "S|n", &msg, &opcode) == 1) { if (mrb_str_is_utf8(msg)) { opc = WSLAY_TEXT_FRAME; } else { opc = WSLAY_BINARY_FRAME; } } else { opc = mrb_fixnum(MRB_GET_OPCODE(mrb_symbol_value(opcode))); } struct wslay_event_msg msgarg = { opc, (const uint8_t *) RSTRING_PTR(msg), RSTRING_LEN(msg) }; int err = wslay_event_queue_msg(data->ctx, &msgarg); if (err == WSLAY_ERR_NOMEM) { mrb_sys_fail(mrb, "wslay_event_queue_msg"); } else if (err == WSLAY_ERR_NO_MORE_MSG) { mrb_raise(mrb, E_WSLAY_ERROR, "further message queueing is not allowed"); } else if (err == WSLAY_ERR_INVALID_ARGUMENT) { mrb_raise(mrb, E_WSLAY_ERROR, "the given message is invalid"); } else if (err != 0) { return MRB_WSLAY_ERROR(mrb_fixnum_value(err)); } return self; }
void on_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg, void *user_data) { (void)user_data; /* Echo back non-control message */ if(!wslay_is_ctrl_frame(arg->opcode)) { struct wslay_event_msg msgarg; msgarg.opcode = arg->opcode; msgarg.msg = arg->msg; msgarg.msg_length = arg->msg_length; wslay_event_queue_msg(ctx, &msgarg); } #if DBG_PRINT if(1) { char *data = (char*)malloc((arg->msg_length+1)*sizeof(char)); memcpy(data, arg->msg, arg->msg_length); data[arg->msg_length] = '\0'; printf("Msg recv callback, opcode: %d msg: %s\n", arg->opcode, data); } #endif }
int wslay_event_recv(wslay_event_context_ptr ctx) { struct wslay_frame_iocb iocb; ssize_t r; while (ctx->read_enabled) { memset(&iocb, 0, sizeof(iocb)); r = wslay_frame_recv(ctx->frame_ctx, &iocb); if (r >= 0) { int new_frame = 0; /* RSV1 is not allowed on control and continuation frames */ if ((!wslay_event_verify_rsv_bits(ctx, iocb.rsv)) || (wslay_get_rsv1(iocb.rsv) && (wslay_is_ctrl_frame(iocb.opcode) || iocb.opcode == WSLAY_CONTINUATION_FRAME)) || (ctx->server && !iocb.mask) || (!ctx->server && iocb.mask)) { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) { return r; } break; } if (ctx->imsg->opcode == 0xffu) { if (iocb.opcode == WSLAY_TEXT_FRAME || iocb.opcode == WSLAY_BINARY_FRAME || iocb.opcode == WSLAY_CONNECTION_CLOSE || iocb.opcode == WSLAY_PING || iocb.opcode == WSLAY_PONG) { wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode); new_frame = 1; } else { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) { return r; } break; } } else if (ctx->ipayloadlen == 0 && ctx->ipayloadoff == 0) { if (iocb.opcode == WSLAY_CONTINUATION_FRAME) { ctx->imsg->fin = iocb.fin; } else if (iocb.opcode == WSLAY_CONNECTION_CLOSE || iocb.opcode == WSLAY_PING || iocb.opcode == WSLAY_PONG) { ctx->imsg = &ctx->imsgs[1]; wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode); } else { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) { return r; } break; } new_frame = 1; } if (new_frame) { if (ctx->imsg->msg_length + iocb.payload_length > ctx->max_recv_msg_length) { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_MESSAGE_TOO_BIG, NULL, 0)) != 0) { return r; } break; } ctx->ipayloadlen = iocb.payload_length; wslay_event_call_on_frame_recv_start_callback(ctx, &iocb); if (!wslay_event_config_get_no_buffering(ctx) || wslay_is_ctrl_frame(iocb.opcode)) { if ((r = wslay_event_imsg_append_chunk(ctx->imsg, iocb.payload_length)) != 0) { ctx->read_enabled = 0; return r; } } } /* If RSV1 bit is set then it is too early for utf-8 validation */ if ((!wslay_get_rsv1(iocb.rsv) && ctx->imsg->opcode == WSLAY_TEXT_FRAME) || ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) { size_t i; if (ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) { i = 2; } else { i = 0; } for (; i < iocb.data_length; ++i) { uint32_t codep; if (decode(&ctx->imsg->utf8state, &codep, iocb.data[i]) == UTF8_REJECT) { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) { return r; } break; } } } if (ctx->imsg->utf8state == UTF8_REJECT) { break; } wslay_event_call_on_frame_recv_chunk_callback(ctx, &iocb); if (iocb.data_length > 0) { if (!wslay_event_config_get_no_buffering(ctx) || wslay_is_ctrl_frame(iocb.opcode)) { struct wslay_event_byte_chunk *chunk; chunk = wslay_queue_tail(ctx->imsg->chunks); wslay_event_byte_chunk_copy(chunk, ctx->ipayloadoff, iocb.data, iocb.data_length); } ctx->ipayloadoff += iocb.data_length; } if (ctx->ipayloadoff == ctx->ipayloadlen) { if (ctx->imsg->fin && (ctx->imsg->opcode == WSLAY_TEXT_FRAME || ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) && ctx->imsg->utf8state != UTF8_ACCEPT) { if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) { return r; } break; } wslay_event_call_on_frame_recv_end_callback(ctx); if (ctx->imsg->fin) { if (ctx->callbacks.on_msg_recv_callback || ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE || ctx->imsg->opcode == WSLAY_PING || ctx->imsg->opcode == WSLAY_PONG) { struct wslay_event_on_msg_recv_arg arg; uint16_t status_code = 0; uint8_t *msg = NULL; size_t msg_length = 0; if (!wslay_event_config_get_no_buffering(ctx) || wslay_is_ctrl_frame(iocb.opcode)) { msg = wslay_event_flatten_queue(ctx->imsg->chunks, ctx->imsg->msg_length); if (ctx->imsg->msg_length && !msg) { ctx->read_enabled = 0; return WSLAY_ERR_NOMEM; } msg_length = ctx->imsg->msg_length; } if (ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) { const uint8_t *reason; size_t reason_length; if (ctx->imsg->msg_length >= 2) { memcpy(&status_code, msg, 2); status_code = ntohs(status_code); if (!wslay_event_is_valid_status_code(status_code)) { free(msg); if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) { return r; } break; } reason = msg + 2; reason_length = ctx->imsg->msg_length - 2; } else { reason = NULL; reason_length = 0; } ctx->close_status |= WSLAY_CLOSE_RECEIVED; ctx->status_code_recv = status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code; if ((r = wslay_event_queue_close_wrapper(ctx, status_code, reason, reason_length)) != 0) { free(msg); return r; } } else if (ctx->imsg->opcode == WSLAY_PING) { struct wslay_event_msg pong_arg; pong_arg.opcode = WSLAY_PONG; pong_arg.msg = msg; pong_arg.msg_length = ctx->imsg->msg_length; if ((r = wslay_event_queue_msg(ctx, &pong_arg)) && r != WSLAY_ERR_NO_MORE_MSG) { ctx->read_enabled = 0; free(msg); return r; } } else if (ctx->imsg->opcode == WSLAY_PONG) { struct websocket_info_t *info = ctx->user_data; info->data->ping_cnt = 0; } if (ctx->callbacks.on_msg_recv_callback) { arg.rsv = ctx->imsg->rsv; arg.opcode = ctx->imsg->opcode; arg.msg = msg; arg.msg_length = msg_length; arg.status_code = status_code; ctx->error = 0; ctx->callbacks.on_msg_recv_callback(ctx, &arg, ctx->user_data); if (ctx->imsg->opcode != WSLAY_CONNECTION_CLOSE) { free(msg); wslay_event_imsg_reset(ctx->imsg); if (ctx->imsg == &ctx->imsgs[1]) { ctx->imsg = &ctx->imsgs[0]; } ctx->ipayloadlen = ctx->ipayloadoff = 0; break; } } if (ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) { struct websocket_info_t *info = ctx->user_data; if (!wslay_queue_empty(ctx->send_ctrl_queue)) { wslay_event_send(ctx); } websocket_update_state(info->data, WEBSOCKET_STOP); } free(msg); } wslay_event_imsg_reset(ctx->imsg); if (ctx->imsg == &ctx->imsgs[1]) { ctx->imsg = &ctx->imsgs[0]; } } ctx->ipayloadlen = ctx->ipayloadoff = 0; } } else { if (r != WSLAY_ERR_WANT_READ || (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) { if ((r = wslay_event_queue_close_wrapper(ctx, 0, NULL, 0)) != 0) { return r; } return WSLAY_ERR_CALLBACK_FAILURE; } break; } } return 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; }
/** * \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); } } } }
/** * \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); } } } }