Example #1
0
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;
	}
}
Example #2
0
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;
}
Example #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);
  }
}
Example #4
0
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);
}
Example #5
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);
    }
}
Example #6
0
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);
}
Example #7
0
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;
}
Example #8
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);
}
Example #9
0
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;
}
Example #10
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
}
Example #11
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;
}
Example #12
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;
}
Example #13
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);
			}
		}
	}

}
Example #14
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);
			}
		}
	}
}