Пример #1
0
int wslay_event_queue_msg(wslay_event_context_ptr ctx,
                          const struct wslay_event_msg *arg)
{
  int r;
  struct wslay_event_omsg *omsg;
  if(!wslay_event_is_msg_queueable(ctx)) {
    return WSLAY_ERR_NO_MORE_MSG;
  }
  if(wslay_is_ctrl_frame(arg->opcode) && arg->msg_length > 125) {
    return WSLAY_ERR_INVALID_ARGUMENT;
  }
  if((r = wslay_event_omsg_non_fragmented_init
      (&omsg, arg->opcode, arg->msg, arg->msg_length)) != 0) {
    return r;
  }
  if(wslay_is_ctrl_frame(arg->opcode)) {
    if((r = wslay_queue_push(ctx->send_ctrl_queue, omsg)) != 0) {
      return r;
    }
  } else {
    if((r = wslay_queue_push(ctx->send_queue, omsg)) != 0) {
      return r;
    }
  }
  ++ctx->queued_msg_count;
  ctx->queued_msg_length += arg->msg_length;
  return 0;
}
Пример #2
0
int wslay_event_queue_msg_ex(wslay_event_context_ptr ctx, const struct wslay_event_msg *arg, uint8_t rsv)
{
	int r;
	struct wslay_event_omsg *omsg;
	if (!wslay_event_is_msg_queueable(ctx)) {
		return WSLAY_ERR_NO_MORE_MSG;
	}
	/* RSV1 is not allowed for control frames */
	if ((wslay_is_ctrl_frame(arg->opcode) && (arg->msg_length > 125 || wslay_get_rsv1(rsv)))
		|| !wslay_event_verify_rsv_bits(ctx, rsv)) {
		return WSLAY_ERR_INVALID_ARGUMENT;
	}
	if ((r = wslay_event_omsg_non_fragmented_init(&omsg, arg->opcode, rsv, arg->msg, arg->msg_length)) != 0) {
		return r;
	}
	if (wslay_is_ctrl_frame(arg->opcode)) {
		if ((r = wslay_queue_push(ctx->send_ctrl_queue, omsg)) != 0) {
			return r;
		}
	} else {
		if ((r = wslay_queue_push(ctx->send_queue, omsg)) != 0) {
			return r;
		}
	}
	++ctx->queued_msg_count;
	ctx->queued_msg_length += arg->msg_length;
	return 0;
}
Пример #3
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);
  }
}
Пример #4
0
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);
    }
}
Пример #5
0
int wslay_event_queue_fragmented_msg_ex(wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg, uint8_t rsv)
{
	int r;
	struct wslay_event_omsg *omsg;
	if (!wslay_event_is_msg_queueable(ctx)) {
		return WSLAY_ERR_NO_MORE_MSG;
	}
	if (wslay_is_ctrl_frame(arg->opcode) || !wslay_event_verify_rsv_bits(ctx, rsv)) {
		return WSLAY_ERR_INVALID_ARGUMENT;
	}
	if ((r = wslay_event_omsg_fragmented_init(&omsg, arg->opcode, rsv, arg->source, arg->read_callback)) != 0) {
		return r;
	}
	if ((r = wslay_queue_push(ctx->send_queue, omsg)) != 0) {
		return r;
	}
	++ctx->queued_msg_count;
	return 0;
}
Пример #6
0
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
}
Пример #7
0
int wslay_event_send(wslay_event_context_ptr ctx)
{
	struct wslay_frame_iocb iocb;
	ssize_t r;

	while (ctx->write_enabled && (!wslay_queue_empty(ctx->send_queue) || !wslay_queue_empty(ctx->send_ctrl_queue) || ctx->omsg)) {
		if (!ctx->omsg) {
			if (wslay_queue_empty(ctx->send_ctrl_queue)) {
				ctx->omsg = wslay_queue_top(ctx->send_queue);
				wslay_queue_pop(ctx->send_queue);
			} else {
				ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
				if (ctx->omsg == NULL) {
					break;
				}
			}
			if (ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
				wslay_event_on_non_fragmented_msg_popped(ctx);
			}
		} else if (!wslay_is_ctrl_frame(ctx->omsg->opcode) && ctx->frame_ctx->ostate == PREP_HEADER && !wslay_queue_empty(ctx->send_ctrl_queue)) {
			if ((r = wslay_queue_push_front(ctx->send_queue, ctx->omsg)) != 0) {
				ctx->write_enabled = 0;
				return r;
			}
			ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
			if (ctx->omsg == NULL) {
				break;
			}
			/* ctrl message has WSLAY_NON_FRAGMENTED */
			wslay_event_on_non_fragmented_msg_popped(ctx);
		}
		if (ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
			memset(&iocb, 0, sizeof(iocb));
			iocb.fin = 1;
			iocb.opcode = ctx->omsg->opcode;
			iocb.rsv = ctx->omsg->rsv;
			iocb.mask = ctx->server ^ 1;
			iocb.data = ctx->omsg->data + ctx->opayloadoff;
			iocb.data_length = ctx->opayloadlen - ctx->opayloadoff;
			iocb.payload_length = ctx->opayloadlen;
			r = wslay_frame_send(ctx->frame_ctx, &iocb);
			if (r >= 0) {
				ctx->opayloadoff += r;
				if (ctx->opayloadoff == ctx->opayloadlen) {
					--ctx->queued_msg_count;
					ctx->queued_msg_length -= ctx->omsg->data_length;
					if (ctx->omsg->opcode == WSLAY_CONNECTION_CLOSE) {
						uint16_t status_code = 0;
						ctx->write_enabled = 0;
						ctx->close_status |= WSLAY_CLOSE_SENT;
						if (ctx->omsg->data_length >= 2) {
							memcpy(&status_code, ctx->omsg->data, 2);
							status_code = ntohs(status_code);
						}
						ctx->status_code_sent = status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
					}
					wslay_event_omsg_free(ctx->omsg);
					ctx->omsg = NULL;
				} else {
					break;
				}
			} else {
				if (r != WSLAY_ERR_WANT_WRITE || (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
					ctx->write_enabled = 0;
					return WSLAY_ERR_CALLBACK_FAILURE;
				}
				break;
			}
		} else {
			if (ctx->omsg->fin == 0 && ctx->obuflimit == ctx->obufmark) {
				int eof = 0;
				r = ctx->omsg->read_callback(ctx, ctx->obuf, sizeof(ctx->obuf), &ctx->omsg->source, &eof, ctx->user_data);
				if (r == 0) {
					break;
				} else if (r < 0) {
					ctx->write_enabled = 0;
					return WSLAY_ERR_CALLBACK_FAILURE;
				}
				ctx->obuflimit = ctx->obuf + r;
				if (eof) {
					ctx->omsg->fin = 1;
				}
				ctx->opayloadlen = (uint64_t)r;
				ctx->opayloadoff = 0;
			}
			memset(&iocb, 0, sizeof(iocb));
			iocb.fin = ctx->omsg->fin;
			iocb.opcode = ctx->omsg->opcode;
			iocb.rsv = ctx->omsg->rsv;
			iocb.mask = ctx->server ? 0 : 1;
			iocb.data = ctx->obufmark;
			iocb.data_length = ctx->obuflimit - ctx->obufmark;
			iocb.payload_length = ctx->opayloadlen;
			r = wslay_frame_send(ctx->frame_ctx, &iocb);
			if (r >= 0) {
				ctx->obufmark += r;
				if (ctx->obufmark == ctx->obuflimit) {
					ctx->obufmark = ctx->obuflimit = ctx->obuf;
					if (ctx->omsg->fin) {
						--ctx->queued_msg_count;
						wslay_event_omsg_free(ctx->omsg);
						ctx->omsg = NULL;
						break;
					} else {
						ctx->omsg->opcode = WSLAY_CONTINUATION_FRAME;
						/* RSV1 is not set on continuation frames */
						ctx->omsg->rsv = ctx->omsg->rsv & ~WSLAY_RSV1_BIT;
					}
				} else {
					break;
				}
			} else {
				if (r != WSLAY_ERR_WANT_WRITE || (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
					ctx->write_enabled = 0;
					return WSLAY_ERR_CALLBACK_FAILURE;
				}
				break;
			}
		}
	}
	return 0;
}
Пример #8
0
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;
}
Пример #9
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);
			}
		}
	}

}
Пример #10
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);
			}
		}
	}
}