281 lines
10 KiB
C++
281 lines
10 KiB
C++
|
|
#include "V8WSSv.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <thread>
|
|
#include <mutex>
|
|
|
|
|
|
namespace laya {
|
|
|
|
struct vhdinfo {
|
|
struct lws_context *context;
|
|
struct lws_vhost *vhost;
|
|
int *interrupted;
|
|
int *options;
|
|
};
|
|
|
|
/*
|
|
参照 https://github.com/warmcat/libwebsockets/tree/master/minimal-examples/ws-server/minimal-ws-server-echo
|
|
需要切换版本。
|
|
*/
|
|
|
|
per_session_data__v8dbg* pCurPss = nullptr;
|
|
DebuggerAgent* gpDbgAgent = nullptr;
|
|
static int callback_def(
|
|
struct lws *wsi, enum lws_callback_reasons reason,
|
|
void *user, void *in, size_t len) {
|
|
|
|
int n;
|
|
int sendMsgLen = 0;
|
|
per_session_data__v8dbg *pss = (per_session_data__v8dbg *)user;
|
|
|
|
switch (reason) {
|
|
case LWS_CALLBACK_PROTOCOL_INIT:
|
|
break;
|
|
case LWS_CALLBACK_ESTABLISHED: //有人连进来了
|
|
printf("connection established\n");
|
|
pss->pRecvBuff = nullptr;
|
|
pss->index = 0;
|
|
pss->nRecvLen = -1;
|
|
pss->pDbgAgent = gpDbgAgent;
|
|
new (&pss->pTaskLock) std::recursive_mutex();
|
|
new (&pss->pSendTask) std::deque<std::string>();
|
|
//new (&pss->pSendTask) std::vector<std::string>();
|
|
gpDbgAgent->onAcceptNewFrontend(pss);
|
|
pCurPss = pss;
|
|
break;
|
|
|
|
case LWS_CALLBACK_SERVER_WRITEABLE: //可以发送了
|
|
//缺省的是继续发送。例如上一次可能只发送了一部分
|
|
n = LWS_WRITE_CONTINUATION;
|
|
if (!pss->continuation) {
|
|
//如果是新的任务,就设置文本或者二进制。
|
|
if (pss->binary)
|
|
n = LWS_WRITE_BINARY;
|
|
else
|
|
n = LWS_WRITE_TEXT;
|
|
pss->continuation = 1;
|
|
}
|
|
if (!pss->final)
|
|
n |= LWS_WRITE_NO_FIN;
|
|
|
|
//pss->tx += pss->len;
|
|
pss->pTaskLock.lock();
|
|
//一次处理一个
|
|
if (pss->pSendTask.size() > 0) {
|
|
std::string& t1 = pss->pSendTask.front();
|
|
//printf("send:%s\n", t1.substr(0,200).c_str());
|
|
sendMsgLen = t1.length();
|
|
if (pss->pSendBuff) {
|
|
delete[] pss->pSendBuff;
|
|
}
|
|
pss->pSendBuff = new unsigned char[sendMsgLen + LWS_PRE];
|
|
memcpy(pss->pSendBuff + LWS_PRE, t1.c_str(), sendMsgLen);
|
|
//删掉第一个
|
|
pss->pSendTask.pop_front();
|
|
}
|
|
pss->pTaskLock.unlock();
|
|
if (sendMsgLen > 0) {
|
|
n = lws_write(wsi, &pss->pSendBuff[LWS_PRE], sendMsgLen, (lws_write_protocol)n);
|
|
if (n < 0) {
|
|
lwsl_err("ERROR %d writing to socket, hanging up\n", n);
|
|
return 1;
|
|
}
|
|
if (n < (int)sendMsgLen) {
|
|
lwsl_err("Partial write\n");
|
|
//这里不知道怎么处理,按理说部分发送的情况不用管。下次LWS_CALLBACK_SERVER_WRITEABLE的时候应该已经全部发送了。
|
|
//所以pss->continuation应该还是=0
|
|
//这里直接返回,这样pss->continuation就是1了,是故意的么
|
|
return -1;
|
|
}
|
|
}
|
|
if (pss->final)
|
|
pss->continuation = 0;
|
|
/* 这会导致websocket报错,写返回-1
|
|
//一次全部处理
|
|
pss->pTaskLock.lock();
|
|
if (pss->pSendTask.size() > 0) {
|
|
for (std::string& t1 : pss->pSendTask) {
|
|
printf("send:%s\n", t1.c_str());
|
|
sendMsgLen = t1.length();
|
|
if (pss->pSendBuff) {
|
|
delete[] pss->pSendBuff;//TODO 优化
|
|
}
|
|
pss->pSendBuff = new unsigned char[sendMsgLen + LWS_PRE];
|
|
memcpy(pss->pSendBuff + LWS_PRE, t1.c_str(), sendMsgLen);
|
|
n = lws_write(wsi, &pss->pSendBuff[LWS_PRE], sendMsgLen, (lws_write_protocol)n);
|
|
if (n < 0) {
|
|
lwsl_err("ERROR %d writing to socket, hanging up\n", n);
|
|
return 1;
|
|
}
|
|
if (n < (int)sendMsgLen) {
|
|
lwsl_err("Partial write\n");
|
|
//这里不知道怎么处理,按理说部分发送的情况不用管。下次LWS_CALLBACK_SERVER_WRITEABLE的时候应该已经全部发送了。
|
|
//所以pss->continuation应该还是=0
|
|
//这里直接返回,这样pss->continuation就是1了,是故意的么
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
pss->pTaskLock.unlock();
|
|
*/
|
|
//lws_rx_flow_control(wsi, 1); //允许在此连接上接收数据。
|
|
lws_callback_on_writable(wsi);//一旦有机会,触发写回调
|
|
break;
|
|
case LWS_CALLBACK_RECEIVE: { // 可以接收了。
|
|
// Create a buffer to hold our response
|
|
// it has to have some pre and post padding.
|
|
// You don't need to care what comes there, libwebsockets
|
|
// will do everything for you. For more info see
|
|
// http://git.warmcat.com/cgi-bin/cgit/libwebsockets/tree/lib/libwebsockets.h#n597
|
|
|
|
//amsg.first = lws_is_first_fragment(wsi);
|
|
pss->final = lws_is_final_fragment(wsi); //是否是最后一个信息。
|
|
pss->binary = lws_frame_is_binary(wsi); //是否是二进制的。
|
|
const size_t remaining = lws_remaining_packet_payload(wsi);
|
|
//lwsl_info("+++ test-echo: RX len %ld final %ld, pss->len=%ld\n",(long)len, (long)pss->final, (long)pss->len);
|
|
|
|
if (in && len > 0) {
|
|
if (remaining > 0) {
|
|
//帧不完整。 TODO
|
|
*(int*)0 = 1;
|
|
}
|
|
else {
|
|
if (len+LWS_PRE > sizeof(pss->RecvBuf)) {
|
|
*(int*)0 = 1;//TODO
|
|
}
|
|
memcpy(&pss->RecvBuf[LWS_PRE], in, len);
|
|
pss->RecvBuf[LWS_PRE + len] = 0;
|
|
pss->nRecvLen = (unsigned int)len;
|
|
pss->rx += len;
|
|
pss->pDbgAgent->onDbgMsg((char*)(pss->RecvBuf + LWS_PRE), len);
|
|
}
|
|
}
|
|
|
|
//lws_rx_flow_control(wsi, 0);//禁止在此连接上接收数据。
|
|
lws_callback_on_writable(wsi);//一旦有机会,触发写回调
|
|
break;
|
|
}
|
|
|
|
case LWS_CALLBACK_CLOSED:
|
|
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
|
lwsl_debug("closed\n");
|
|
pCurPss = nullptr;
|
|
if (gpDbgAgent) {
|
|
gpDbgAgent->onFrontEndClose();
|
|
}
|
|
//state = 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define RING_DEPTH 4096
|
|
|
|
static struct lws_protocols protocols[] = {
|
|
/* first protocol must always be HTTP handler */
|
|
{
|
|
"http-only", // name
|
|
callback_def, // callback
|
|
sizeof(per_session_data__v8dbg), // per_session_data_size
|
|
MAX_V8DBG_PAYLOAD
|
|
},
|
|
{
|
|
NULL, NULL, 0 /* End of list */
|
|
}
|
|
};
|
|
|
|
std::thread* wssvth = nullptr;
|
|
bool interrupted = false;
|
|
|
|
void wsserver_run(lws_context* context) {
|
|
int n = 0;
|
|
while (n >= 0 && !interrupted) {
|
|
//nWSSVSleep 是 timeout_ms: 等待超时时间,即没有找到需要处理的连接需要等待的时间,为0则立即返回;
|
|
//这个会一通过回调处理消息。
|
|
int nSleep = 10;
|
|
if (pCurPss) {
|
|
pCurPss->pTaskLock.lock();
|
|
if (pCurPss->pSendTask.size() > 0) {
|
|
nSleep = 0;
|
|
}
|
|
pCurPss->pTaskLock.unlock();
|
|
}
|
|
n = lws_service(context, nSleep);
|
|
}
|
|
lws_context_destroy(context);
|
|
}
|
|
|
|
void startWSSV(int port, DebuggerAgent* pDbgAgent) {
|
|
gpDbgAgent = pDbgAgent;
|
|
interrupted = false;
|
|
struct lws_context *context;
|
|
// we're not using ssl
|
|
const char *cert_path = NULL;
|
|
const char *key_path = NULL;
|
|
// no special options
|
|
int opts = 0;
|
|
|
|
static const struct lws_http_mount mount = {
|
|
/* .mount_next */ NULL, /* linked-list "next" */
|
|
/* .mountpoint */ "/", /* mountpoint URL */
|
|
/* .origin */ ".", /* serve from dir */
|
|
/* .def */ "index.html", /* default filename */
|
|
/* .protocol */ NULL,
|
|
/* .cgienv */ NULL,
|
|
/* .extra_mimetypes */ NULL,
|
|
/* .interpret */ NULL,
|
|
/* .cgi_timeout */ 0,
|
|
/* .cache_max_age */ 0,
|
|
/* .auth_mask */ 0,
|
|
/* .cache_reusable */ 0,
|
|
/* .cache_revalidate */ 0,
|
|
/* .cache_intermediaries */ 0,
|
|
/* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */
|
|
/* .mountpoint_len */ 1, /* char count */
|
|
/* .basic_auth_login_file */ NULL,
|
|
};
|
|
|
|
lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER/* | LLL_INFO */ /* | LLL_DEBUG */, NULL);
|
|
|
|
lws_context_creation_info cinfo;
|
|
memset(&cinfo, 0, sizeof(cinfo));
|
|
cinfo.port = port;
|
|
cinfo.mounts = &mount;
|
|
cinfo.protocols = protocols;
|
|
cinfo.extensions = lws_get_internal_extensions();
|
|
//if (!use_ssl) {
|
|
cinfo.ssl_cert_filepath = NULL;
|
|
cinfo.ssl_private_key_filepath = NULL;
|
|
//} else {
|
|
// info.ssl_cert_filepath = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
|
|
// info.ssl_private_key_filepath = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
|
|
//}
|
|
cinfo.gid = -1;
|
|
cinfo.uid = -1;
|
|
|
|
// create libwebsocket context representing this server
|
|
context = lws_create_context( &cinfo);
|
|
|
|
if (context == NULL) {
|
|
fprintf(stderr, "libwebsocket init failed\n");
|
|
return ;
|
|
}
|
|
|
|
printf("starting server...\n");
|
|
wssvth = new std::thread(std::bind(wsserver_run, context));;
|
|
}
|
|
|
|
void stopWSSV() {
|
|
interrupted = true;
|
|
if (wssvth != NULL)
|
|
{
|
|
wssvth->join();
|
|
}
|
|
}
|
|
} |