sdk-hwV1.3/lichee/xr806/appos/project/common/cmd/cmd_lws.c

492 lines
12 KiB
C
Executable File

/*
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if PRJCONF_NET_EN
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cmd_util.h"
#include "kernel/os/os_time.h"
#include "net/libwebsockets/libwebsockets.h"
typedef enum {
LWS_CMD_CREATE,
LWS_CMD_CONNECT,
LWS_CMD_SEND,
LWS_CMD_DISCONNECT,
LWS_CMD_EXIT
} LWS_CMD;
struct lws_msg {
LWS_CMD type;
void *data;
int data_len;
};
struct cmd_lws_common {
struct lws_context *context;
struct lws *conn;
int ssl;
int port;
char host[128];
char address[128];
char path[128];
OS_Thread_t thread;
OS_Queue_t queue;
};
static struct cmd_lws_common cmd_lws;
static int lws_callback(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
static struct lws_protocols protocols[] = {
{
"dumb-increment-protocol,fake-nonexistant-protocol",
lws_callback,
0,
1024 * 2
},
{
NULL, NULL, 0, 0 /* end */
}
};
static int lws_callback(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
switch (reason) {
case LWS_CALLBACK_CLIENT_ESTABLISHED:
CMD_LOG(1, "------ connection established success ------\n");
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
CMD_LOG(1, "------ connection error ------\n");
break;
case LWS_CALLBACK_CLOSED:
CMD_LOG(1, "------ connection closed ------\n");
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
CMD_LOG(1, "------ receive msg from server: %s ------\n", (char *)in);
break;
case LWS_CALLBACK_CLIENT_WRITEABLE:
CMD_LOG(1, "------ connection writeable ------\n");
break;
default:
break;
}
return 0;
}
static int lws_cmd_create_handler(void *data, int data_len)
{
struct lws_context_creation_info *info;
info = (struct lws_context_creation_info *)data;
cmd_lws.context = lws_create_context(info);
if (cmd_lws.context == NULL) {
CMD_ERR("libwebsocket context create fail\n");
return -1;
}
CMD_DBG("libwebsocket context create success\n");
return 0;
}
static int lws_cmd_connect_handler(void *data, int data_len)
{
struct lws_client_connect_info *connect_info;
connect_info = (struct lws_client_connect_info *)data;
connect_info->context = cmd_lws.context;
cmd_lws.conn = lws_client_connect_via_info(connect_info);
if (cmd_lws.conn == NULL) {
CMD_ERR("libwebsocket connect fail\n");
return -1;
}
CMD_DBG("libwebsocket connect success\n");
return 0;
}
static int lws_cmd_send_handler(void *data, int data_len)
{
unsigned char *buffer;
buffer = cmd_malloc(data_len + LWS_PRE);
if (buffer == NULL) {
return -1;
}
cmd_memcpy(buffer + LWS_PRE, data, data_len);
lws_write(cmd_lws.conn, (buffer + LWS_PRE), data_len, LWS_WRITE_TEXT);
cmd_free(buffer);
return 0;
}
static int lws_cmd_disconnect_handler(void *data, int data_len)
{
lws_context_destroy(cmd_lws.context);
cmd_lws.context = NULL;
cmd_lws.conn = NULL;
return 0;
}
static void lws_client_task(void *arg)
{
int exit = 0;
int connected = 0;
OS_Status status;
struct lws_msg *msg;
while (!exit) {
status = OS_MsgQueueReceive(&cmd_lws.queue, (void **)&msg, 0);
if (status != OS_OK) {
if (connected) {
lws_service(cmd_lws.context, 50);
}
OS_MSleep(50);
continue;
}
CMD_DBG("msg type:%d\n", msg->type);
switch (msg->type) {
case LWS_CMD_CREATE:
lws_cmd_create_handler(msg->data, msg->data_len);
break;
case LWS_CMD_CONNECT:
lws_cmd_connect_handler(msg->data, msg->data_len);
connected = 1;
break;
case LWS_CMD_SEND:
lws_cmd_send_handler(msg->data, msg->data_len);
break;
case LWS_CMD_DISCONNECT:
lws_cmd_disconnect_handler(msg->data, msg->data_len);
connected = 0;
break;
case LWS_CMD_EXIT:
exit = 1;
break;
default:
break;
}
cmd_free(msg->data);
cmd_free(msg);
}
OS_ThreadDelete(&cmd_lws.thread);
}
static enum cmd_status cmd_lws_init_exec(char *cmd)
{
if (OS_MsgQueueCreate(&cmd_lws.queue, 4) != OS_OK) {
CMD_ERR("create queue failed\n");
return CMD_STATUS_FAIL;
}
if (OS_ThreadCreate(&cmd_lws.thread,
"lws client",
lws_client_task,
NULL,
OS_THREAD_PRIO_APP,
(8 * 1024)) != OS_OK) {
CMD_ERR("create thread failed\n");
OS_MsgQueueDelete(&cmd_lws.queue);
return CMD_STATUS_FAIL;
}
return CMD_STATUS_OK;
}
static enum cmd_status cmd_lws_deinit_exec(char *cmd)
{
OS_Status status;
struct lws_msg *msg;
msg = cmd_malloc(sizeof(struct lws_msg));
if (msg == NULL) {
return CMD_STATUS_FAIL;
}
cmd_memset(msg, 0, sizeof(struct lws_msg));
msg->type = LWS_CMD_EXIT;
msg->data_len = 0;
msg->data = NULL;
status = OS_MsgQueueSend(&cmd_lws.queue, msg, OS_WAIT_FOREVER);
if (status != OS_OK) {
cmd_free(msg);
return CMD_STATUS_FAIL;
}
while (OS_ThreadIsValid(&cmd_lws.thread)) {
OS_MSleep(10);
}
OS_MsgQueueDelete(&cmd_lws.queue);
cmd_memset(&cmd_lws, 0, sizeof(struct cmd_lws_common));
return CMD_STATUS_OK;
}
static int websocket_url_parser(char *url)
{
char *pos;
char *colon;
if (url == NULL) {
return -1;
}
CMD_DBG("connect url: %s\n", url);
cmd_memset(cmd_lws.host, 0, sizeof(cmd_lws.host));
cmd_memset(cmd_lws.address, 0, sizeof(cmd_lws.address));
cmd_memset(cmd_lws.path, 0, sizeof(cmd_lws.path));
pos = url;
if (cmd_strncmp(pos, "wss://", 6) == 0) {
cmd_lws.ssl = 1;
pos += 6;
} else if (cmd_strncmp(pos, "ws://", 5) == 0) {
cmd_lws.ssl = 0;
pos += 5;
} else {
return -1;
}
colon = cmd_strchr(pos, ':');
if (colon) {
int host_len = colon - pos;
if ((host_len + 1 > sizeof(cmd_lws.host))
|| (host_len + 1 > sizeof(cmd_lws.address))) {
return -1;
}
cmd_memcpy(cmd_lws.host, pos, host_len);
cmd_lws.host[host_len] = '\0';
cmd_memcpy(cmd_lws.address, pos, host_len);
cmd_lws.address[host_len] = '\0';
pos += (host_len + 1);
} else {
return -1;
}
cmd_lws.port = cmd_atoi(pos);
if (cmd_lws.port == 0) {
return -1;
}
colon = cmd_strchr(pos, '/');
if (colon) {
cmd_strlcpy(cmd_lws.path, colon, sizeof(cmd_lws.path));
} else {
cmd_strlcpy(cmd_lws.path, "/", sizeof(cmd_lws.path));
}
return 0;
}
static int cmd_lws_create(void)
{
OS_Status status;
struct lws_msg *msg;
struct lws_context_creation_info *info;
info = cmd_malloc(sizeof(struct lws_context_creation_info));
if (info == NULL) {
return -1;
}
cmd_memset(info, 0, sizeof(struct lws_context_creation_info));
info->port = CONTEXT_PORT_NO_LISTEN;
info->protocols = protocols;
info->gid = -1;
info->uid = -1;
if (cmd_lws.ssl) {
info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
}
msg = cmd_malloc(sizeof(struct lws_msg));
if (msg == NULL) {
cmd_free(info);
return -1;
}
cmd_memset(msg, 0, sizeof(struct lws_msg));
msg->type = LWS_CMD_CREATE;
msg->data = info;
msg->data_len = sizeof(struct lws_context_creation_info);
status = OS_MsgQueueSend(&cmd_lws.queue, msg, OS_WAIT_FOREVER);
if (status != OS_OK) {
cmd_free(info);
cmd_free(msg);
return -1;
}
return 0;
}
static int cmd_lws_connect(void)
{
OS_Status status;
struct lws_msg *msg;
struct lws_client_connect_info *connect_info;
connect_info = cmd_malloc(sizeof(struct lws_client_connect_info));
if (connect_info == NULL) {
return -1;
}
cmd_memset(connect_info, 0, sizeof(struct lws_client_connect_info));
connect_info->ssl_connection = cmd_lws.ssl;
connect_info->host = cmd_lws.host;
connect_info->address = cmd_lws.address;
connect_info->port = cmd_lws.port;
connect_info->path = cmd_lws.path;
connect_info->origin = NULL;
connect_info->protocol = protocols[0].name;
msg = cmd_malloc(sizeof(struct lws_msg));
if (msg == NULL) {
cmd_free(connect_info);
return -1;
}
cmd_memset(msg, 0, sizeof(struct lws_msg));
msg->type = LWS_CMD_CONNECT;
msg->data = connect_info;
msg->data_len = sizeof(struct lws_client_connect_info);
status = OS_MsgQueueSend(&cmd_lws.queue, msg, OS_WAIT_FOREVER);
if (status != OS_OK) {
cmd_free(connect_info);
cmd_free(msg);
return -1;
}
return 0;
}
static enum cmd_status cmd_lws_connect_exec(char *cmd)
{
int ret;
ret = websocket_url_parser(cmd);
if (ret != 0) {
CMD_ERR("websocket url parser fail.\n");
return CMD_STATUS_FAIL;
}
ret = cmd_lws_create();
if (ret != 0) {
return CMD_STATUS_FAIL;
}
ret = cmd_lws_connect();
if (ret != 0) {
return CMD_STATUS_FAIL;
}
return CMD_STATUS_OK;
}
static enum cmd_status cmd_lws_send_exec(char *cmd)
{
void *data;
int data_len;
OS_Status status;
struct lws_msg *msg;
if (cmd == NULL) {
return CMD_STATUS_INVALID_ARG;
}
data_len = cmd_strlen(cmd) + 1;
data = cmd_malloc(data_len);
if (data == NULL) {
return CMD_STATUS_FAIL;
}
cmd_memcpy(data, cmd, data_len);
msg = cmd_malloc(sizeof(struct lws_msg));
if (msg == NULL) {
cmd_free(data);
return CMD_STATUS_FAIL;
}
cmd_memset(msg, 0, sizeof(struct lws_msg));
msg->type = LWS_CMD_SEND;
msg->data_len = data_len;
msg->data = data;
status = OS_MsgQueueSend(&cmd_lws.queue, msg, OS_WAIT_FOREVER);
if (status != OS_OK) {
cmd_free(data);
cmd_free(msg);
return CMD_STATUS_FAIL;
}
return CMD_STATUS_OK;
}
static enum cmd_status cmd_lws_disconnect_exec(char *cmd)
{
OS_Status status;
struct lws_msg *msg;
msg = cmd_malloc(sizeof(struct lws_msg));
if (msg == NULL) {
return CMD_STATUS_FAIL;
}
cmd_memset(msg, 0, sizeof(struct lws_msg));
msg->type = LWS_CMD_DISCONNECT;
msg->data_len = 0;
msg->data = NULL;
status = OS_MsgQueueSend(&cmd_lws.queue, msg, OS_WAIT_FOREVER);
if (status != OS_OK) {
cmd_free(msg);
return CMD_STATUS_FAIL;
}
return CMD_STATUS_OK;
}
static enum cmd_status cmd_lws_help_exec(char *cmd);
static const struct cmd_data g_lws_cmds[] = {
{ "init", cmd_lws_init_exec, CMD_DESC("init. format:net lws init") },
{ "deinit", cmd_lws_deinit_exec, CMD_DESC("deinit. format:net lws deinit") },
{ "connect", cmd_lws_connect_exec, CMD_DESC("connect server. format: lws connect <url>") },
{ "send", cmd_lws_send_exec, CMD_DESC("send message to server. format: lws send <TEXT>") },
{ "disconnect", cmd_lws_disconnect_exec, CMD_DESC("disconnect. format: lws disconnect") },
{ "help", cmd_lws_help_exec, CMD_DESC(CMD_HELP_DESC) },
};
static enum cmd_status cmd_lws_help_exec(char *cmd)
{
return cmd_help_exec(g_lws_cmds, cmd_nitems(g_lws_cmds), 8);
}
enum cmd_status cmd_lws_exec(char *cmd)
{
return cmd_exec(cmd, g_lws_cmds, cmd_nitems(g_lws_cmds));
}
#endif /* PRJCONF_NET_EN */