#include "V8WSSv.h" #include #include #include #include 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(); //new (&pss->pSendTask) std::vector(); 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(); } } }