1902 lines
69 KiB
Diff
1902 lines
69 KiB
Diff
From 3d5ad2160b9fe779433cce497bfa0cb0146bdcb3 Mon Sep 17 00:00:00 2001
|
|
From: wujing <wujing50@huawei.com>
|
|
Date: Sat, 4 Dec 2021 21:20:25 +0800
|
|
Subject: [PATCH] Optimize websocket streaming service code
|
|
|
|
Signed-off-by: wujing <wujing50@huawei.com>
|
|
---
|
|
.../cri/cri_container_manager_service_impl.cc | 28 +-
|
|
src/daemon/entry/cri/request_cache.cc | 123 ++-----
|
|
src/daemon/entry/cri/request_cache.h | 32 +-
|
|
.../cri/websocket/service/attach_serve.cc | 102 +++---
|
|
.../cri/websocket/service/attach_serve.h | 28 +-
|
|
.../entry/cri/websocket/service/exec_serve.cc | 158 +++++----
|
|
.../entry/cri/websocket/service/exec_serve.h | 27 +-
|
|
.../service/route_callback_register.cc | 80 +++++
|
|
.../service/route_callback_register.h | 61 ++--
|
|
.../cri/websocket/service/stream_server.cc | 6 +-
|
|
.../cri/websocket/service/stream_server.h | 4 +-
|
|
.../entry/cri/websocket/service/ws_server.cc | 300 +++++++++++-------
|
|
.../entry/cri/websocket/service/ws_server.h | 174 +++-------
|
|
13 files changed, 542 insertions(+), 581 deletions(-)
|
|
create mode 100644 src/daemon/entry/cri/websocket/service/route_callback_register.cc
|
|
|
|
diff --git a/src/daemon/entry/cri/cri_container_manager_service_impl.cc b/src/daemon/entry/cri/cri_container_manager_service_impl.cc
|
|
index 2e65ab51..b160ce31 100644
|
|
--- a/src/daemon/entry/cri/cri_container_manager_service_impl.cc
|
|
+++ b/src/daemon/entry/cri/cri_container_manager_service_impl.cc
|
|
@@ -376,7 +376,8 @@ ContainerManagerServiceImpl::GenerateCreateContainerRequest(const std::string &r
|
|
hostconfig->cgroup_parent = util_strdup_s(podSandboxConfig.linux().cgroup_parent().c_str());
|
|
}
|
|
|
|
- custom_config = GenerateCreateContainerCustomConfig(cname, realPodSandboxID, containerConfig, podSandboxConfig, error);
|
|
+ custom_config =
|
|
+ GenerateCreateContainerCustomConfig(cname, realPodSandboxID, containerConfig, podSandboxConfig, error);
|
|
if (error.NotEmpty()) {
|
|
goto cleanup;
|
|
}
|
|
@@ -409,11 +410,10 @@ cleanup:
|
|
return request;
|
|
}
|
|
|
|
-std::string ContainerManagerServiceImpl::CreateContainer(
|
|
- const std::string &podSandboxID,
|
|
- const runtime::v1alpha2::ContainerConfig &containerConfig,
|
|
- const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig,
|
|
- Errors &error)
|
|
+std::string ContainerManagerServiceImpl::CreateContainer(const std::string &podSandboxID,
|
|
+ const runtime::v1alpha2::ContainerConfig &containerConfig,
|
|
+ const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig,
|
|
+ Errors &error)
|
|
{
|
|
std::string response_id;
|
|
std::string podSandboxRuntime;
|
|
@@ -1305,10 +1305,16 @@ void ContainerManagerServiceImpl::Exec(const runtime::v1alpha2::ExecRequest &req
|
|
if (ValidateExecRequest(req, error) != 0) {
|
|
return;
|
|
}
|
|
+ auto execReq = new (std::nothrow) runtime::v1alpha2::ExecRequest(req);
|
|
+ if (execReq == nullptr) {
|
|
+ error.SetError("out of memory");
|
|
+ return;
|
|
+ }
|
|
RequestCache *cache = RequestCache::GetInstance();
|
|
- std::string token = cache->InsertExecRequest(req);
|
|
+ std::string token = cache->InsertRequest(req.container_id(), execReq);
|
|
if (token.empty()) {
|
|
error.SetError("failed to get a unique token!");
|
|
+ delete execReq;
|
|
return;
|
|
}
|
|
std::string url = BuildURL("exec", token);
|
|
@@ -1350,10 +1356,16 @@ void ContainerManagerServiceImpl::Attach(const runtime::v1alpha2::AttachRequest
|
|
error.SetError("Empty attach response arguments");
|
|
return;
|
|
}
|
|
+ auto attachReq = new (std::nothrow) runtime::v1alpha2::AttachRequest(req);
|
|
+ if (attachReq == nullptr) {
|
|
+ error.SetError("out of memory");
|
|
+ return;
|
|
+ }
|
|
RequestCache *cache = RequestCache::GetInstance();
|
|
- std::string token = cache->InsertAttachRequest(req);
|
|
+ std::string token = cache->InsertRequest(req.container_id(), attachReq);
|
|
if (token.empty()) {
|
|
error.SetError("failed to get a unique token!");
|
|
+ delete attachReq;
|
|
return;
|
|
}
|
|
std::string url = BuildURL("attach", token);
|
|
diff --git a/src/daemon/entry/cri/request_cache.cc b/src/daemon/entry/cri/request_cache.cc
|
|
index 4ff284ab..312a8071 100644
|
|
--- a/src/daemon/entry/cri/request_cache.cc
|
|
+++ b/src/daemon/entry/cri/request_cache.cc
|
|
@@ -1,5 +1,5 @@
|
|
/******************************************************************************
|
|
- * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved.
|
|
* iSulad licensed under the Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
@@ -8,8 +8,8 @@
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
* PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
- * Author: tanyifeng
|
|
- * Create: 2017-11-22
|
|
+ * Author: wujing
|
|
+ * Create: 2019-01-02
|
|
* Description: provide request cache function definition
|
|
*********************************************************************************/
|
|
#include "request_cache.h"
|
|
@@ -19,15 +19,25 @@
|
|
#include <thread>
|
|
#include <mutex>
|
|
#include <cmath>
|
|
-#include "isula_libutils/log.h"
|
|
+#include <isula_libutils/log.h>
|
|
#include "utils.h"
|
|
#include "utils_base64.h"
|
|
|
|
std::atomic<RequestCache *> RequestCache::m_instance;
|
|
std::mutex RequestCache::m_mutex;
|
|
+
|
|
+void CacheEntry::SetValue(const std::string &t, const std::string &id, ::google::protobuf::Message *request,
|
|
+ std::chrono::system_clock::time_point et)
|
|
+{
|
|
+ token = t;
|
|
+ containerID = id;
|
|
+ req = request;
|
|
+ expireTime = et;
|
|
+}
|
|
+
|
|
RequestCache *RequestCache::GetInstance() noexcept
|
|
{
|
|
- RequestCache *cache = m_instance.load(std::memory_order_relaxed);
|
|
+ auto *cache = m_instance.load(std::memory_order_relaxed);
|
|
std::atomic_thread_fence(std::memory_order_acquire);
|
|
if (cache == nullptr) {
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
@@ -41,25 +51,7 @@ RequestCache *RequestCache::GetInstance() noexcept
|
|
return cache;
|
|
}
|
|
|
|
-std::string RequestCache::InsertExecRequest(const runtime::v1alpha2::ExecRequest &req)
|
|
-{
|
|
- std::lock_guard<std::mutex> lock(m_mutex);
|
|
- // Remove expired entries.
|
|
- GarbageCollection();
|
|
- // If the cache is full, reject the request.
|
|
- if (m_ll.size() == MaxInFlight) {
|
|
- ERROR("too many cache in flight!");
|
|
- return "";
|
|
- }
|
|
- auto token = UniqueToken();
|
|
- CacheEntry tmp;
|
|
- tmp.SetValue(token, &req, nullptr, std::chrono::system_clock::now() + std::chrono::minutes(1));
|
|
- m_ll.push_front(tmp);
|
|
- m_tokens.insert(std::make_pair(token, tmp));
|
|
- return token;
|
|
-}
|
|
-
|
|
-std::string RequestCache::InsertAttachRequest(const runtime::v1alpha2::AttachRequest &req)
|
|
+std::string RequestCache::InsertRequest(const std::string &containerID, ::google::protobuf::Message *req)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
// Remove expired entries.
|
|
@@ -71,7 +63,7 @@ std::string RequestCache::InsertAttachRequest(const runtime::v1alpha2::AttachReq
|
|
}
|
|
auto token = UniqueToken();
|
|
CacheEntry tmp;
|
|
- tmp.SetValue(token, nullptr, &req, std::chrono::system_clock::now() + std::chrono::minutes(1));
|
|
+ tmp.SetValue(token, containerID, req, std::chrono::system_clock::now() + std::chrono::minutes(1));
|
|
m_ll.push_front(tmp);
|
|
m_tokens.insert(std::make_pair(token, tmp));
|
|
return token;
|
|
@@ -81,10 +73,14 @@ void RequestCache::GarbageCollection()
|
|
{
|
|
auto now = std::chrono::system_clock::now();
|
|
while (!m_ll.empty()) {
|
|
- CacheEntry oldest = m_ll.back();
|
|
+ auto oldest = m_ll.back();
|
|
if (now < oldest.expireTime) {
|
|
return;
|
|
}
|
|
+ if (oldest.req != nullptr) {
|
|
+ delete oldest.req;
|
|
+ oldest.req = nullptr;
|
|
+ }
|
|
m_ll.pop_back();
|
|
m_tokens.erase(oldest.token);
|
|
}
|
|
@@ -103,15 +99,15 @@ std::string RequestCache::UniqueToken()
|
|
continue;
|
|
}
|
|
|
|
- char *b64_encode_buf = nullptr;
|
|
- if (util_base64_encode((unsigned char *)rawToken, strlen(rawToken), &b64_encode_buf) < 0) {
|
|
+ char *b64EncodeBuf = nullptr;
|
|
+ if (util_base64_encode((unsigned char *)rawToken, strlen(rawToken), &b64EncodeBuf) < 0) {
|
|
ERROR("Encode raw token to base64 failed");
|
|
continue;
|
|
}
|
|
|
|
- std::string token(b64_encode_buf);
|
|
- free(b64_encode_buf);
|
|
- b64_encode_buf = nullptr;
|
|
+ std::string token(b64EncodeBuf);
|
|
+ free(b64EncodeBuf);
|
|
+ b64EncodeBuf = nullptr;
|
|
if (token.length() != TokenLen) {
|
|
continue;
|
|
}
|
|
@@ -133,37 +129,13 @@ bool RequestCache::IsValidToken(const std::string &token)
|
|
}
|
|
|
|
// Consume the token (remove it from the cache) and return the cached request, if found.
|
|
-runtime::v1alpha2::ExecRequest RequestCache::ConsumeExecRequest(const std::string &token)
|
|
-{
|
|
- std::lock_guard<std::mutex> lock(m_mutex);
|
|
-
|
|
- if (m_tokens.count(token) == 0 || m_tokens[token].execRequest.size() == 0) {
|
|
- ERROR("Invalid token");
|
|
- return runtime::v1alpha2::ExecRequest();
|
|
- }
|
|
-
|
|
- CacheEntry ele = m_tokens[token];
|
|
- for (auto it = m_ll.begin(); it != m_ll.end(); it++) {
|
|
- if (it->token == token) {
|
|
- m_ll.erase(it);
|
|
- break;
|
|
- }
|
|
- }
|
|
- m_tokens.erase(token);
|
|
- if (std::chrono::system_clock::now() > ele.expireTime) {
|
|
- return runtime::v1alpha2::ExecRequest();
|
|
- }
|
|
-
|
|
- return ele.execRequest.at(0);
|
|
-}
|
|
-
|
|
-runtime::v1alpha2::AttachRequest RequestCache::ConsumeAttachRequest(const std::string &token)
|
|
+::google::protobuf::Message *RequestCache::ConsumeRequest(const std::string &token)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
- if (m_tokens.count(token) == 0 || m_tokens[token].attachRequest.size() == 0) {
|
|
+ if (m_tokens.count(token) == 0) {
|
|
ERROR("Invalid token");
|
|
- return runtime::v1alpha2::AttachRequest();
|
|
+ return nullptr;
|
|
}
|
|
|
|
CacheEntry ele = m_tokens[token];
|
|
@@ -175,45 +147,20 @@ runtime::v1alpha2::AttachRequest RequestCache::ConsumeAttachRequest(const std::s
|
|
}
|
|
m_tokens.erase(token);
|
|
if (std::chrono::system_clock::now() > ele.expireTime) {
|
|
- return runtime::v1alpha2::AttachRequest();
|
|
- }
|
|
-
|
|
- return ele.attachRequest.at(0);
|
|
-}
|
|
-
|
|
-std::string RequestCache::GetExecContainerIDByToken(const std::string &token)
|
|
-{
|
|
- std::lock_guard<std::mutex> lock(m_mutex);
|
|
-
|
|
- if (m_tokens.count(token) == 0 || m_tokens[token].execRequest.size() == 0) {
|
|
- ERROR("Invalid token");
|
|
- return "";
|
|
+ return nullptr;
|
|
}
|
|
|
|
- return m_tokens[token].execRequest.at(0).container_id();
|
|
+ return ele.req;
|
|
}
|
|
|
|
-std::string RequestCache::GetAttachContainerIDByToken(const std::string &token)
|
|
+std::string RequestCache::GetContainerIDByToken(const std::string &token)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
- if (m_tokens.count(token) == 0 || m_tokens[token].attachRequest.size() == 0) {
|
|
+ if (m_tokens.count(token) == 0) {
|
|
ERROR("Invalid token");
|
|
return "";
|
|
}
|
|
|
|
- return m_tokens[token].attachRequest.at(0).container_id();
|
|
-}
|
|
-
|
|
-std::string RequestCache::GetContainerIDByToken(const std::string &method, const std::string &token)
|
|
-{
|
|
- if (method == "exec") {
|
|
- return GetExecContainerIDByToken(token);
|
|
- } else if (method == "attach") {
|
|
- return GetAttachContainerIDByToken(token);
|
|
- }
|
|
-
|
|
- ERROR("Invalid method: %s", method.c_str());
|
|
-
|
|
- return "";
|
|
+ return m_tokens[token].containerID;
|
|
}
|
|
diff --git a/src/daemon/entry/cri/request_cache.h b/src/daemon/entry/cri/request_cache.h
|
|
index d44b4d78..90ae20e8 100644
|
|
--- a/src/daemon/entry/cri/request_cache.h
|
|
+++ b/src/daemon/entry/cri/request_cache.h
|
|
@@ -1,5 +1,5 @@
|
|
/******************************************************************************
|
|
- * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved.
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved.
|
|
* iSulad licensed under the Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
@@ -23,44 +23,28 @@
|
|
#include <chrono>
|
|
#include <typeinfo>
|
|
#include <google/protobuf/message.h>
|
|
-#include "api.pb.h"
|
|
|
|
struct CacheEntry {
|
|
std::string token;
|
|
- std::vector<runtime::v1alpha2::ExecRequest> execRequest;
|
|
- std::vector<runtime::v1alpha2::AttachRequest> attachRequest;
|
|
+ std::string containerID;
|
|
+ ::google::protobuf::Message *req;
|
|
std::chrono::system_clock::time_point expireTime;
|
|
|
|
- void SetValue(const std::string &t,
|
|
- const runtime::v1alpha2::ExecRequest *execReq,
|
|
- const runtime::v1alpha2::AttachRequest *attachReq,
|
|
- std::chrono::system_clock::time_point et)
|
|
- {
|
|
- token = t;
|
|
- if (execReq != nullptr) {
|
|
- execRequest.push_back(*execReq);
|
|
- } else if (attachReq != nullptr) {
|
|
- attachRequest.push_back(*attachReq);
|
|
- }
|
|
- expireTime = et;
|
|
- }
|
|
+ void SetValue(const std::string &t, const std::string &id, ::google::protobuf::Message *request,
|
|
+ std::chrono::system_clock::time_point et);
|
|
};
|
|
|
|
class RequestCache {
|
|
public:
|
|
static RequestCache *GetInstance() noexcept;
|
|
- std::string InsertExecRequest(const runtime::v1alpha2::ExecRequest &req);
|
|
- std::string InsertAttachRequest(const runtime::v1alpha2::AttachRequest &req);
|
|
- runtime::v1alpha2::ExecRequest ConsumeExecRequest(const std::string &token);
|
|
- runtime::v1alpha2::AttachRequest ConsumeAttachRequest(const std::string &token);
|
|
- std::string GetContainerIDByToken(const std::string &method, const std::string &token);
|
|
+ std::string InsertRequest(const std::string &containerID, ::google::protobuf::Message *req);
|
|
+ ::google::protobuf::Message *ConsumeRequest(const std::string &token);
|
|
+ std::string GetContainerIDByToken(const std::string &token);
|
|
bool IsValidToken(const std::string &token);
|
|
|
|
private:
|
|
void GarbageCollection();
|
|
std::string UniqueToken();
|
|
- std::string GetExecContainerIDByToken(const std::string &token);
|
|
- std::string GetAttachContainerIDByToken(const std::string &token);
|
|
|
|
private:
|
|
RequestCache() = default;
|
|
diff --git a/src/daemon/entry/cri/websocket/service/attach_serve.cc b/src/daemon/entry/cri/websocket/service/attach_serve.cc
|
|
index cda63c45..abe23f51 100644
|
|
--- a/src/daemon/entry/cri/websocket/service/attach_serve.cc
|
|
+++ b/src/daemon/entry/cri/websocket/service/attach_serve.cc
|
|
@@ -1,5 +1,5 @@
|
|
/******************************************************************************
|
|
- * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2021. All rights reserved.
|
|
* iSulad licensed under the Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
@@ -8,86 +8,78 @@
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
* PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
- * Author: lifeng
|
|
+ * Author: wujing
|
|
* Create: 2018-11-08
|
|
* Description: provide container attach functions
|
|
******************************************************************************/
|
|
|
|
#include "attach_serve.h"
|
|
+#include "api.pb.h"
|
|
+#include "ws_server.h"
|
|
+#include "isula_libutils/log.h"
|
|
+#include "callback.h"
|
|
#include "utils.h"
|
|
|
|
-int AttachServe::Execute(session_data *lws_ctx, const std::string &token)
|
|
+AttachServe::~AttachServe()
|
|
{
|
|
- if (lws_ctx == nullptr) {
|
|
- return -1;
|
|
- }
|
|
+ free_container_attach_request(m_request);
|
|
+ free_container_attach_response(m_response);
|
|
+}
|
|
|
|
+void AttachServe::SetServeThreadName()
|
|
+{
|
|
prctl(PR_SET_NAME, "AttachServe");
|
|
+}
|
|
|
|
- service_executor_t *cb = get_service_executor();
|
|
- if (cb == nullptr || cb->container.attach == nullptr) {
|
|
- sem_post(lws_ctx->sync_close_sem);
|
|
+int AttachServe::SetContainerStreamRequest(::google::protobuf::Message *request, const std::string &suffix)
|
|
+{
|
|
+ auto *grequest = dynamic_cast<runtime::v1alpha2::AttachRequest *>(request);
|
|
+
|
|
+ m_request = static_cast<container_attach_request *>(util_common_calloc_s(sizeof(container_attach_request)));
|
|
+ if (m_request == nullptr) {
|
|
+ ERROR("Out of memory");
|
|
return -1;
|
|
}
|
|
|
|
- container_attach_request *container_req = nullptr;
|
|
- if (GetContainerRequest(token, &container_req) != 0) {
|
|
- ERROR("Failed to get contaner request");
|
|
- sem_post(lws_ctx->sync_close_sem);
|
|
+ if (!grequest->container_id().empty()) {
|
|
+ m_request->container_id = util_strdup_s(grequest->container_id().c_str());
|
|
+ }
|
|
+ m_request->attach_stdin = grequest->stdin();
|
|
+ m_request->attach_stdout = grequest->stdout();
|
|
+ m_request->attach_stderr = grequest->stderr();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int AttachServe::ExecuteStreamCommand(SessionData *lwsCtx)
|
|
+{
|
|
+ auto *cb = get_service_executor();
|
|
+ if (cb == nullptr || cb->container.attach == nullptr) {
|
|
+ ERROR("Failed to get attach service executor");
|
|
+ sem_post(lwsCtx->syncCloseSem);
|
|
return -1;
|
|
}
|
|
|
|
struct io_write_wrapper stringWriter = { 0 };
|
|
- stringWriter.context = (void *)(lws_ctx);
|
|
+ stringWriter.context = (void *)(lwsCtx);
|
|
stringWriter.write_func = WsWriteStdoutToClient;
|
|
stringWriter.close_func = closeWsConnect;
|
|
- container_req->attach_stderr = false;
|
|
-
|
|
- container_attach_response *container_res = nullptr;
|
|
- int ret = cb->container.attach(container_req, &container_res, container_req->attach_stdin ? lws_ctx->pipes.at(0) : -1,
|
|
- container_req->attach_stdout ? &stringWriter : nullptr, nullptr);
|
|
- if (ret != 0) {
|
|
- ERROR("Failed to attach container: %s", container_req->container_id);
|
|
- sem_post(lws_ctx->sync_close_sem);
|
|
- }
|
|
-
|
|
- free_container_attach_request(container_req);
|
|
- free_container_attach_response(container_res);
|
|
+ m_request->attach_stderr = false;
|
|
|
|
- return ret;
|
|
+ return cb->container.attach(m_request, &m_response, m_request->attach_stdin ? lwsCtx->pipes.at(0) : -1,
|
|
+ m_request->attach_stdout ? &stringWriter : nullptr, nullptr);
|
|
}
|
|
|
|
-int AttachServe::GetContainerRequest(const std::string &token, container_attach_request **container_req)
|
|
+void AttachServe::ErrorHandler(int ret, SessionData *lwsCtx)
|
|
{
|
|
- RequestCache *cache = RequestCache::GetInstance();
|
|
- auto request = cache->ConsumeAttachRequest(token);
|
|
-
|
|
- int ret = RequestFromCri(request, container_req);
|
|
- if (ret != 0) {
|
|
- ERROR("Failed to transform grpc request!");
|
|
+ if (ret == 0) {
|
|
+ return;
|
|
}
|
|
-
|
|
- return ret;
|
|
+ ERROR("Failed to attach container: %s", m_request->container_id);
|
|
+ sem_post(lwsCtx->syncCloseSem);
|
|
}
|
|
|
|
-int AttachServe::RequestFromCri(const runtime::v1alpha2::AttachRequest &grequest, container_attach_request **request)
|
|
+void AttachServe::CloseConnect(SessionData *lwsCtx)
|
|
{
|
|
- container_attach_request *tmpreq = nullptr;
|
|
-
|
|
- tmpreq = (container_attach_request *)util_common_calloc_s(sizeof(container_attach_request));
|
|
- if (tmpreq == nullptr) {
|
|
- ERROR("Out of memory");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- if (!grequest.container_id().empty()) {
|
|
- tmpreq->container_id = util_strdup_s(grequest.container_id().c_str());
|
|
- }
|
|
- tmpreq->attach_stdin = grequest.stdin();
|
|
- tmpreq->attach_stdout = grequest.stdout();
|
|
- tmpreq->attach_stderr = grequest.stderr();
|
|
-
|
|
- *request = tmpreq;
|
|
-
|
|
- return 0;
|
|
+ (void)lwsCtx;
|
|
}
|
|
diff --git a/src/daemon/entry/cri/websocket/service/attach_serve.h b/src/daemon/entry/cri/websocket/service/attach_serve.h
|
|
index f7b8a017..38e75e29 100644
|
|
--- a/src/daemon/entry/cri/websocket/service/attach_serve.h
|
|
+++ b/src/daemon/entry/cri/websocket/service/attach_serve.h
|
|
@@ -1,5 +1,5 @@
|
|
/******************************************************************************
|
|
- * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved.
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved.
|
|
* iSulad licensed under the Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
@@ -17,27 +17,27 @@
|
|
#define DAEMON_ENTRY_CRI_WEBSOCKET_SERVICE_ATTACH_SERVE_H
|
|
|
|
#include "route_callback_register.h"
|
|
-#include <chrono>
|
|
#include <string>
|
|
-#include <thread>
|
|
-#include "ws_server.h"
|
|
-
|
|
-#include "api.pb.h"
|
|
-#include "isula_libutils/log.h"
|
|
-#include "callback.h"
|
|
-#include "request_cache.h"
|
|
+#include "isula_libutils/container_attach_request.h"
|
|
+#include "isula_libutils/container_attach_response.h"
|
|
|
|
class AttachServe : public StreamingServeInterface {
|
|
public:
|
|
AttachServe() = default;
|
|
AttachServe(const AttachServe &) = delete;
|
|
AttachServe &operator=(const AttachServe &) = delete;
|
|
- virtual ~AttachServe() = default;
|
|
- int Execute(session_data *lws_ctx, const std::string &token) override;
|
|
+ virtual ~AttachServe();
|
|
+
|
|
+private:
|
|
+ virtual void SetServeThreadName() override;
|
|
+ virtual int SetContainerStreamRequest(::google::protobuf::Message *grequest, const std::string &suffix) override;
|
|
+ virtual int ExecuteStreamCommand(SessionData *lwsCtx) override;
|
|
+ virtual void ErrorHandler(int ret, SessionData *lwsCtx) override;
|
|
+ virtual void CloseConnect(SessionData *lwsCtx) override;
|
|
+
|
|
private:
|
|
- int RequestFromCri(const runtime::v1alpha2::AttachRequest &grequest,
|
|
- container_attach_request **request);
|
|
- int GetContainerRequest(const std::string &token, container_attach_request **container_req);
|
|
+ container_attach_request *m_request { nullptr };
|
|
+ container_attach_response *m_response { nullptr };
|
|
};
|
|
#endif // DAEMON_ENTRY_CRI_WEBSOCKET_SERVICE_ATTACH_SERVE_H
|
|
|
|
diff --git a/src/daemon/entry/cri/websocket/service/exec_serve.cc b/src/daemon/entry/cri/websocket/service/exec_serve.cc
|
|
index 26b552de..b7709c48 100644
|
|
--- a/src/daemon/entry/cri/websocket/service/exec_serve.cc
|
|
+++ b/src/daemon/entry/cri/websocket/service/exec_serve.cc
|
|
@@ -1,5 +1,5 @@
|
|
/******************************************************************************
|
|
- * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2021. All rights reserved.
|
|
* iSulad licensed under the Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
@@ -8,127 +8,111 @@
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
* PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
- * Author: lifeng
|
|
+ * Author: wujing
|
|
* Create: 2018-11-08
|
|
* Description: provide ExecServe functions
|
|
******************************************************************************/
|
|
|
|
#include "exec_serve.h"
|
|
+#include <isula_libutils/log.h>
|
|
#include "io_wrapper.h"
|
|
+#include "ws_server.h"
|
|
#include "utils.h"
|
|
#include "cri_helpers.h"
|
|
|
|
-int ExecServe::Execute(session_data *lws_ctx, const std::string &token)
|
|
+ExecServe::~ExecServe()
|
|
{
|
|
- if (lws_ctx == nullptr) {
|
|
- return -1;
|
|
- }
|
|
+ free_container_exec_request(m_request);
|
|
+ free_container_exec_response(m_response);
|
|
+}
|
|
|
|
+void ExecServe::SetServeThreadName()
|
|
+{
|
|
prctl(PR_SET_NAME, "ExecServe");
|
|
+}
|
|
|
|
- service_executor_t *cb = get_service_executor();
|
|
- if (cb == nullptr || cb->container.exec == nullptr) {
|
|
- sem_post(lws_ctx->sync_close_sem);
|
|
+int ExecServe::SetContainerStreamRequest(::google::protobuf::Message *request, const std::string &suffix)
|
|
+{
|
|
+ auto *grequest = dynamic_cast<runtime::v1alpha2::ExecRequest *>(request);
|
|
+
|
|
+ m_request = static_cast<container_exec_request *>(util_common_calloc_s(sizeof(container_exec_request)));
|
|
+ if (m_request == nullptr) {
|
|
+ ERROR("Out of memory");
|
|
return -1;
|
|
}
|
|
|
|
- container_exec_request *container_req = nullptr;
|
|
- if (GetContainerRequest(token, lws_ctx->suffix, &container_req) != 0) {
|
|
- ERROR("Failed to get contaner request");
|
|
- sem_post(lws_ctx->sync_close_sem);
|
|
+ m_request->tty = grequest->tty();
|
|
+ m_request->attach_stdin = grequest->stdin();
|
|
+ m_request->attach_stdout = grequest->stdout();
|
|
+ m_request->attach_stderr = grequest->stderr();
|
|
+
|
|
+ if (!grequest->container_id().empty()) {
|
|
+ m_request->container_id = util_strdup_s(grequest->container_id().c_str());
|
|
+ }
|
|
+
|
|
+ if (grequest->cmd_size() > 0) {
|
|
+ if (static_cast<size_t>(grequest->cmd_size()) > SIZE_MAX / sizeof(char *)) {
|
|
+ ERROR("Too many arguments!");
|
|
+ return -1;
|
|
+ }
|
|
+ m_request->argv = (char **)util_common_calloc_s(sizeof(char *) * grequest->cmd_size());
|
|
+ if (m_request->argv == nullptr) {
|
|
+ ERROR("Out of memory!");
|
|
+ return -1;
|
|
+ }
|
|
+ for (int i = 0; i < grequest->cmd_size(); i++) {
|
|
+ m_request->argv[i] = util_strdup_s(grequest->cmd(i).c_str());
|
|
+ }
|
|
+ m_request->argv_len = static_cast<size_t>(grequest->cmd_size());
|
|
+ }
|
|
+
|
|
+ m_request->suffix = util_strdup_s(suffix.c_str());
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int ExecServe::ExecuteStreamCommand(SessionData *lwsCtx)
|
|
+{
|
|
+ auto *cb = get_service_executor();
|
|
+ if (cb == nullptr || cb->container.exec == nullptr) {
|
|
+ ERROR("Failed to get exec service executor");
|
|
+ sem_post(lwsCtx->syncCloseSem);
|
|
return -1;
|
|
}
|
|
|
|
struct io_write_wrapper StdoutstringWriter = { 0 };
|
|
- StdoutstringWriter.context = (void *)lws_ctx;
|
|
+ StdoutstringWriter.context = (void *)lwsCtx;
|
|
StdoutstringWriter.write_func = WsWriteStdoutToClient;
|
|
// the close function of StderrstringWriter is preferred unless StderrstringWriter is nullptr
|
|
StdoutstringWriter.close_func = nullptr;
|
|
struct io_write_wrapper StderrstringWriter = { 0 };
|
|
- StderrstringWriter.context = (void *)lws_ctx;
|
|
+ StderrstringWriter.context = (void *)lwsCtx;
|
|
StderrstringWriter.write_func = WsWriteStderrToClient;
|
|
StderrstringWriter.close_func = nullptr;
|
|
|
|
- container_exec_response *container_res = nullptr;
|
|
- int ret = cb->container.exec(container_req, &container_res, container_req->attach_stdin ? lws_ctx->pipes.at(0) : -1,
|
|
- container_req->attach_stdout ? &StdoutstringWriter : nullptr,
|
|
- container_req->attach_stderr ? &StderrstringWriter : nullptr);
|
|
+ return cb->container.exec(m_request, &m_response, m_request->attach_stdin ? lwsCtx->pipes.at(0) : -1,
|
|
+ m_request->attach_stdout ? &StdoutstringWriter : nullptr,
|
|
+ m_request->attach_stderr ? &StderrstringWriter : nullptr);
|
|
+}
|
|
+
|
|
+void ExecServe::ErrorHandler(int ret, SessionData *lwsCtx)
|
|
+{
|
|
if (ret != 0) {
|
|
std::string message;
|
|
- if (container_res != nullptr && container_res->errmsg != nullptr) {
|
|
- message = container_res->errmsg;
|
|
+ if (m_response != nullptr && m_response->errmsg != nullptr) {
|
|
+ message = m_response->errmsg;
|
|
} else {
|
|
message = "Failed to call exec container callback. ";
|
|
}
|
|
- WsWriteStdoutToClient(lws_ctx, message.c_str(), message.length());
|
|
+ WsWriteStdoutToClient(lwsCtx, message.c_str(), message.length());
|
|
}
|
|
- if (container_res != nullptr && container_res->exit_code != 0) {
|
|
- std::string exit_info = "Exit code :" + std::to_string((int)container_res->exit_code) + "\n";
|
|
- WsWriteStdoutToClient(lws_ctx, exit_info.c_str(), exit_info.length());
|
|
+ if (m_response != nullptr && m_response->exit_code != 0) {
|
|
+ std::string exit_info = "Exit code :" + std::to_string((int)m_response->exit_code) + "\n";
|
|
+ WsWriteStdoutToClient(lwsCtx, exit_info.c_str(), exit_info.length());
|
|
}
|
|
-
|
|
- free_container_exec_request(container_req);
|
|
- free_container_exec_response(container_res);
|
|
-
|
|
- closeWsConnect((void*)lws_ctx, nullptr);
|
|
-
|
|
- return ret;
|
|
}
|
|
|
|
-int ExecServe::GetContainerRequest(const std::string &token, const std::string &suffix,
|
|
- container_exec_request **container_req)
|
|
+void ExecServe::CloseConnect(SessionData *lwsCtx)
|
|
{
|
|
- RequestCache *cache = RequestCache::GetInstance();
|
|
- auto request = cache->ConsumeExecRequest(token);
|
|
-
|
|
- int ret = RequestFromCri(request, suffix, container_req);
|
|
- if (ret != 0) {
|
|
- ERROR("Failed to transform grpc request!");
|
|
- }
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
-int ExecServe::RequestFromCri(const runtime::v1alpha2::ExecRequest &grequest, const std::string &suffix,
|
|
- container_exec_request **request)
|
|
-{
|
|
- container_exec_request *tmpreq = nullptr;
|
|
-
|
|
- tmpreq = (container_exec_request *)util_common_calloc_s(sizeof(container_exec_request));
|
|
- if (tmpreq == nullptr) {
|
|
- ERROR("Out of memory");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- tmpreq->tty = grequest.tty();
|
|
- tmpreq->attach_stdin = grequest.stdin();
|
|
- tmpreq->attach_stdout = grequest.stdout();
|
|
- tmpreq->attach_stderr = grequest.stderr();
|
|
-
|
|
- if (!grequest.container_id().empty()) {
|
|
- tmpreq->container_id = util_strdup_s(grequest.container_id().c_str());
|
|
- }
|
|
-
|
|
- if (grequest.cmd_size() > 0) {
|
|
- if ((size_t)grequest.cmd_size() > SIZE_MAX / sizeof(char *)) {
|
|
- ERROR("Too many arguments!");
|
|
- free_container_exec_request(tmpreq);
|
|
- return -1;
|
|
- }
|
|
- tmpreq->argv = (char **)util_common_calloc_s(sizeof(char *) * grequest.cmd_size());
|
|
- if (tmpreq->argv == nullptr) {
|
|
- ERROR("Out of memory!");
|
|
- free_container_exec_request(tmpreq);
|
|
- return -1;
|
|
- }
|
|
- for (int i = 0; i < grequest.cmd_size(); i++) {
|
|
- tmpreq->argv[i] = util_strdup_s(grequest.cmd(i).c_str());
|
|
- }
|
|
- tmpreq->argv_len = (size_t)grequest.cmd_size();
|
|
- }
|
|
-
|
|
- tmpreq->suffix = util_strdup_s(suffix.c_str());
|
|
-
|
|
- *request = tmpreq;
|
|
- return 0;
|
|
+ closeWsConnect((void*)lwsCtx, nullptr);
|
|
}
|
|
diff --git a/src/daemon/entry/cri/websocket/service/exec_serve.h b/src/daemon/entry/cri/websocket/service/exec_serve.h
|
|
index 5cccdee8..3afb2abb 100644
|
|
--- a/src/daemon/entry/cri/websocket/service/exec_serve.h
|
|
+++ b/src/daemon/entry/cri/websocket/service/exec_serve.h
|
|
@@ -1,5 +1,5 @@
|
|
/******************************************************************************
|
|
- * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved.
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved.
|
|
* iSulad licensed under the Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
@@ -20,28 +20,27 @@
|
|
#include <string>
|
|
#include <chrono>
|
|
#include <thread>
|
|
-#include <grpc++/grpc++.h>
|
|
-#include "api.grpc.pb.h"
|
|
-#include "container.grpc.pb.h"
|
|
|
|
#include "route_callback_register.h"
|
|
-#include "isula_libutils/log.h"
|
|
-#include "callback.h"
|
|
-#include "ws_server.h"
|
|
-#include "request_cache.h"
|
|
-#include "api.pb.h"
|
|
+#include "isula_libutils/container_exec_request.h"
|
|
+#include "isula_libutils/container_exec_response.h"
|
|
|
|
class ExecServe : public StreamingServeInterface {
|
|
public:
|
|
ExecServe() = default;
|
|
ExecServe(const ExecServe &) = delete;
|
|
ExecServe &operator=(const ExecServe &) = delete;
|
|
- virtual ~ExecServe() = default;
|
|
- int Execute(session_data *lws_ctx, const std::string &token) override;
|
|
+ virtual ~ExecServe();
|
|
|
|
private:
|
|
- int RequestFromCri(const runtime::v1alpha2::ExecRequest &grequest, const std::string &suffix,
|
|
- container_exec_request **request);
|
|
- int GetContainerRequest(const std::string &token, const std::string &suffix, container_exec_request **request);
|
|
+ virtual void SetServeThreadName() override;
|
|
+ virtual int SetContainerStreamRequest(::google::protobuf::Message *grequest, const std::string &suffix) override;
|
|
+ virtual int ExecuteStreamCommand(SessionData *lwsCtx) override;
|
|
+ virtual void ErrorHandler(int ret, SessionData *lwsCtx) override;
|
|
+ virtual void CloseConnect(SessionData *lwsCtx) override;
|
|
+
|
|
+private:
|
|
+ container_exec_request *m_request { nullptr };
|
|
+ container_exec_response *m_response { nullptr };
|
|
};
|
|
#endif // DAEMON_ENTRY_CRI_WEBSOCKET_SERVICE_EXEC_SERVE_H
|
|
diff --git a/src/daemon/entry/cri/websocket/service/route_callback_register.cc b/src/daemon/entry/cri/websocket/service/route_callback_register.cc
|
|
new file mode 100644
|
|
index 00000000..fb14381f
|
|
--- /dev/null
|
|
+++ b/src/daemon/entry/cri/websocket/service/route_callback_register.cc
|
|
@@ -0,0 +1,80 @@
|
|
+/******************************************************************************
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
|
|
+ * iSulad licensed under the Mulan PSL v2.
|
|
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
+ * You may obtain a copy of Mulan PSL v2 at:
|
|
+ * http://license.coscl.org.cn/MulanPSL2
|
|
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
+ * PURPOSE.
|
|
+ * See the Mulan PSL v2 for more details.
|
|
+ * Description: Streaming service function registration.
|
|
+ * Author: wujing
|
|
+ * Create: 2021-11-04
|
|
+ ******************************************************************************/
|
|
+#include "route_callback_register.h"
|
|
+#include <isula_libutils/log.h>
|
|
+#include "ws_server.h"
|
|
+
|
|
+int StreamingServeInterface::Execute(SessionData *lwsCtx, const std::string &token)
|
|
+{
|
|
+ if (lwsCtx == nullptr) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ SetServeThreadName();
|
|
+
|
|
+ auto *cache = RequestCache::GetInstance();
|
|
+ auto request = cache->ConsumeRequest(token);
|
|
+ if (request == nullptr) {
|
|
+ ERROR("Failed to get cache request!");
|
|
+ sem_post(lwsCtx->syncCloseSem);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (SetContainerStreamRequest(request, lwsCtx->suffix) != 0) {
|
|
+ ERROR("Failed to set container request");
|
|
+ sem_post(lwsCtx->syncCloseSem);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ // request is stored on the heap in the cache and needs to be released after use
|
|
+ delete request;
|
|
+ request = nullptr;
|
|
+
|
|
+ int ret = ExecuteStreamCommand(lwsCtx);
|
|
+
|
|
+ ErrorHandler(ret, lwsCtx);
|
|
+
|
|
+ CloseConnect(lwsCtx);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+bool RouteCallbackRegister::IsValidMethod(const std::string &method)
|
|
+{
|
|
+ return static_cast<bool>(m_registeredcallbacks.count(method));
|
|
+}
|
|
+
|
|
+int RouteCallbackRegister::HandleCallback(SessionData *lwsCtx, const std::string &method, const std::string &token)
|
|
+{
|
|
+ auto it = m_registeredcallbacks.find(method);
|
|
+ if (it != m_registeredcallbacks.end()) {
|
|
+ std::shared_ptr<StreamingServeInterface> callback = it->second;
|
|
+ if (callback) {
|
|
+ return callback->Execute(lwsCtx, token);
|
|
+ }
|
|
+ }
|
|
+ ERROR("invalid method!");
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+void RouteCallbackRegister::RegisterCallback(const std::string &path, std::shared_ptr<StreamingServeInterface> callback)
|
|
+{
|
|
+ m_registeredcallbacks.insert(std::pair<std::string, std::shared_ptr<StreamingServeInterface>>(path, callback));
|
|
+}
|
|
+
|
|
+int StreamTask::Run()
|
|
+{
|
|
+ return m_invoker->HandleCallback(m_lwsCtx, m_method, m_token);
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/daemon/entry/cri/websocket/service/route_callback_register.h b/src/daemon/entry/cri/websocket/service/route_callback_register.h
|
|
index 909c552b..da75fc5b 100644
|
|
--- a/src/daemon/entry/cri/websocket/service/route_callback_register.h
|
|
+++ b/src/daemon/entry/cri/websocket/service/route_callback_register.h
|
|
@@ -22,9 +22,9 @@
|
|
#include <map>
|
|
#include <unistd.h>
|
|
#include <semaphore.h>
|
|
-#include "isula_libutils/log.h"
|
|
+#include "request_cache.h"
|
|
|
|
-struct session_data;
|
|
+struct SessionData;
|
|
|
|
class StreamingServeInterface {
|
|
public:
|
|
@@ -32,7 +32,14 @@ public:
|
|
StreamingServeInterface(const StreamingServeInterface &) = delete;
|
|
StreamingServeInterface &operator=(const StreamingServeInterface &) = delete;
|
|
virtual ~StreamingServeInterface() = default;
|
|
- virtual int Execute(session_data *lws_ctx, const std::string &token) = 0;
|
|
+ int Execute(SessionData *lwsCtx, const std::string &token);
|
|
+
|
|
+protected:
|
|
+ virtual void SetServeThreadName() = 0;
|
|
+ virtual int SetContainerStreamRequest(::google::protobuf::Message *grequest, const std::string &suffix) = 0;
|
|
+ virtual int ExecuteStreamCommand(SessionData *lwsCtx) = 0;
|
|
+ virtual void ErrorHandler(int ret, SessionData *lwsCtx) = 0;
|
|
+ virtual void CloseConnect(SessionData *lwsCtx) = 0;
|
|
};
|
|
|
|
class RouteCallbackRegister {
|
|
@@ -41,30 +48,10 @@ public:
|
|
RouteCallbackRegister(const RouteCallbackRegister &) = delete;
|
|
RouteCallbackRegister &operator=(const RouteCallbackRegister &) = delete;
|
|
virtual ~RouteCallbackRegister() = default;
|
|
- bool IsValidMethod(const std::string &method)
|
|
- {
|
|
- return static_cast<bool>(m_registeredcallbacks.count(method));
|
|
- }
|
|
|
|
- int HandleCallback(session_data *lws_ctx, const std::string &method,
|
|
- const std::string &token)
|
|
- {
|
|
- auto it = m_registeredcallbacks.find(method);
|
|
- if (it != m_registeredcallbacks.end()) {
|
|
- std::shared_ptr<StreamingServeInterface> callback = it->second;
|
|
- if (callback) {
|
|
- return callback->Execute(lws_ctx, token);
|
|
- }
|
|
- }
|
|
- ERROR("invalid method!");
|
|
- return -1;
|
|
- }
|
|
- void RegisterCallback(const std::string &path,
|
|
- std::shared_ptr<StreamingServeInterface> callback)
|
|
- {
|
|
- m_registeredcallbacks.insert(std::pair<std::string,
|
|
- std::shared_ptr<StreamingServeInterface>>(path, callback));
|
|
- }
|
|
+ bool IsValidMethod(const std::string &method);
|
|
+ int HandleCallback(SessionData *lwsCtx, const std::string &method, const std::string &token);
|
|
+ void RegisterCallback(const std::string &path, std::shared_ptr<StreamingServeInterface> callback);
|
|
|
|
private:
|
|
std::map<std::string, std::shared_ptr<StreamingServeInterface>> m_registeredcallbacks;
|
|
@@ -72,24 +59,24 @@ private:
|
|
|
|
class StreamTask {
|
|
public:
|
|
- StreamTask(RouteCallbackRegister *invoker, session_data *lws_ctx,
|
|
- const std::string &method,
|
|
+ StreamTask(RouteCallbackRegister *invoker, SessionData *lwsCtx, const std::string &method,
|
|
const std::string &token)
|
|
- : m_invoker(invoker), m_lws_ctx(lws_ctx), m_method(method), m_token(token) {}
|
|
+ : m_invoker(invoker)
|
|
+ , m_lwsCtx(lwsCtx)
|
|
+ , m_method(method)
|
|
+ , m_token(token)
|
|
+ {
|
|
+ }
|
|
StreamTask(const StreamTask &) = delete;
|
|
StreamTask &operator=(const StreamTask &) = delete;
|
|
virtual ~StreamTask() = default;
|
|
- int Run()
|
|
- {
|
|
- return m_invoker->HandleCallback(m_lws_ctx, m_method, m_token);
|
|
- }
|
|
+ int Run();
|
|
+
|
|
private:
|
|
- RouteCallbackRegister *m_invoker{ nullptr };
|
|
- session_data *m_lws_ctx;
|
|
+ RouteCallbackRegister *m_invoker { nullptr };
|
|
+ SessionData *m_lwsCtx;
|
|
std::string m_method;
|
|
std::string m_token;
|
|
};
|
|
|
|
#endif // DAEMON_ENTRY_CRI_WEBSOCKET_SERVICE_ROUTE_CALLBACK_REGISTER_H
|
|
-
|
|
-
|
|
diff --git a/src/daemon/entry/cri/websocket/service/stream_server.cc b/src/daemon/entry/cri/websocket/service/stream_server.cc
|
|
index b4df642f..4342e006 100644
|
|
--- a/src/daemon/entry/cri/websocket/service/stream_server.cc
|
|
+++ b/src/daemon/entry/cri/websocket/service/stream_server.cc
|
|
@@ -22,7 +22,7 @@
|
|
|
|
void websocket_server_init(Errors &err)
|
|
{
|
|
- WebsocketServer *server = WebsocketServer::GetInstance();
|
|
+ auto *server = WebsocketServer::GetInstance();
|
|
server->RegisterCallback(std::string("exec"), std::make_shared<ExecServe>());
|
|
server->RegisterCallback(std::string("attach"), std::make_shared<AttachServe>());
|
|
server->Start(err);
|
|
@@ -30,13 +30,13 @@ void websocket_server_init(Errors &err)
|
|
|
|
void websocket_server_wait(void)
|
|
{
|
|
- WebsocketServer *server = WebsocketServer::GetInstance();
|
|
+ auto *server = WebsocketServer::GetInstance();
|
|
server->Wait();
|
|
}
|
|
|
|
void websocket_server_shutdown(void)
|
|
{
|
|
- WebsocketServer *server = WebsocketServer::GetInstance();
|
|
+ auto *server = WebsocketServer::GetInstance();
|
|
server->Shutdown();
|
|
}
|
|
|
|
diff --git a/src/daemon/entry/cri/websocket/service/stream_server.h b/src/daemon/entry/cri/websocket/service/stream_server.h
|
|
index 43e42b83..ba6b3672 100644
|
|
--- a/src/daemon/entry/cri/websocket/service/stream_server.h
|
|
+++ b/src/daemon/entry/cri/websocket/service/stream_server.h
|
|
@@ -1,5 +1,5 @@
|
|
/******************************************************************************
|
|
- * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2021. All rights reserved.
|
|
* iSulad licensed under the Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
@@ -8,7 +8,7 @@
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
* PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
- * Author: lifeng
|
|
+ * Author: wujing
|
|
* Create: 2018-11-08
|
|
* Description: provide websocket stream service definition
|
|
******************************************************************************/
|
|
diff --git a/src/daemon/entry/cri/websocket/service/ws_server.cc b/src/daemon/entry/cri/websocket/service/ws_server.cc
|
|
index e4b3a1b4..0e462737 100644
|
|
--- a/src/daemon/entry/cri/websocket/service/ws_server.cc
|
|
+++ b/src/daemon/entry/cri/websocket/service/ws_server.cc
|
|
@@ -1,5 +1,5 @@
|
|
/******************************************************************************
|
|
- * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved.
|
|
* iSulad licensed under the Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
@@ -8,8 +8,8 @@
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
* PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
- * Author: lifeng
|
|
- * Create: 2018-11-08
|
|
+ * Author: wujing
|
|
+ * Create: 2019-01-02
|
|
* Description: provide websocket server functions
|
|
******************************************************************************/
|
|
|
|
@@ -19,34 +19,132 @@
|
|
#include <future>
|
|
#include <utility>
|
|
#include <sys/resource.h>
|
|
+#include <isula_libutils/log.h>
|
|
#include "cxxutils.h"
|
|
-#include "isula_libutils/log.h"
|
|
#include "utils.h"
|
|
#include "request_cache.h"
|
|
#include "constants.h"
|
|
#include "isulad_config.h"
|
|
#include "callback.h"
|
|
#include "cri_helpers.h"
|
|
+#include "isula_libutils/cri_terminal_size.h"
|
|
|
|
struct lws_context *WebsocketServer::m_context = nullptr;
|
|
std::atomic<WebsocketServer *> WebsocketServer::m_instance;
|
|
RWMutex WebsocketServer::m_mutex;
|
|
-std::unordered_map<int, session_data *> WebsocketServer::m_wsis;
|
|
+std::unordered_map<int, SessionData *> WebsocketServer::m_wsis;
|
|
+
|
|
+namespace {
|
|
+const int MAX_BUF_LEN = 256;
|
|
+const int MAX_HTTP_HEADER_POOL = 8;
|
|
+// io copy maximum single transfer 4K, let max total buffer size: 1GB
|
|
+const int FIFO_LIST_BUFFER_MAX_LEN = 262144;
|
|
+const int SESSION_CAPABILITY = 300;
|
|
+const int MAX_SESSION_NUM = 128;
|
|
+}; // namespace
|
|
+
|
|
+enum WebsocketChannel { STDINCHANNEL = 0, STDOUTCHANNEL, STDERRCHANNEL, ERRORCHANNEL, RESIZECHANNEL };
|
|
+
|
|
+unsigned char *SessionData::FrontMessage()
|
|
+{
|
|
+ unsigned char *message = nullptr;
|
|
+
|
|
+ if (sessionMutex == nullptr) {
|
|
+ return nullptr;
|
|
+ }
|
|
+
|
|
+ sessionMutex->lock();
|
|
+ message = buffer.front();
|
|
+ sessionMutex->unlock();
|
|
+
|
|
+ return message;
|
|
+}
|
|
+
|
|
+void SessionData::PopMessage()
|
|
+{
|
|
+ if (sessionMutex == nullptr) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ sessionMutex->lock();
|
|
+ buffer.pop_front();
|
|
+ sessionMutex->unlock();
|
|
+}
|
|
+
|
|
+int SessionData::PushMessage(unsigned char *message)
|
|
+{
|
|
+ if (sessionMutex == nullptr) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ sessionMutex->lock();
|
|
+
|
|
+ // In extreme scenarios, websocket data cannot be processed,
|
|
+ // ignore the data coming in later to prevent iSulad from getting stuck
|
|
+ if (close || buffer.size() >= FIFO_LIST_BUFFER_MAX_LEN) {
|
|
+ free(message);
|
|
+ sessionMutex->unlock();
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ buffer.push_back(message);
|
|
+ sessionMutex->unlock();
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+bool SessionData::IsClosed()
|
|
+{
|
|
+ bool c = false;
|
|
+
|
|
+ if (sessionMutex == nullptr) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ sessionMutex->lock();
|
|
+ c = close;
|
|
+ sessionMutex->unlock();
|
|
+
|
|
+ return c;
|
|
+}
|
|
+
|
|
+void SessionData::CloseSession()
|
|
+{
|
|
+ if (sessionMutex == nullptr) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ sessionMutex->lock();
|
|
+ close = true;
|
|
+ sessionMutex->unlock();
|
|
+}
|
|
+
|
|
+void SessionData::EraseAllMessage()
|
|
+{
|
|
+ if (sessionMutex == nullptr) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ sessionMutex->lock();
|
|
+ for (auto iter = buffer.begin(); iter != buffer.end();) {
|
|
+ free(*iter);
|
|
+ *iter = NULL;
|
|
+ iter = buffer.erase(iter);
|
|
+ }
|
|
+ sessionMutex->unlock();
|
|
+}
|
|
|
|
WebsocketServer *WebsocketServer::GetInstance() noexcept
|
|
{
|
|
static std::once_flag flag;
|
|
|
|
- std::call_once(flag, [] {
|
|
- m_instance = new WebsocketServer;
|
|
- });
|
|
+ std::call_once(flag, [] { m_instance = new WebsocketServer; });
|
|
|
|
return m_instance;
|
|
}
|
|
|
|
WebsocketServer::WebsocketServer()
|
|
{
|
|
- m_force_exit = 0;
|
|
+ m_forceExit = 0;
|
|
m_wsis.reserve(SESSION_CAPABILITY);
|
|
}
|
|
|
|
@@ -60,19 +158,9 @@ url::URLDatum WebsocketServer::GetWebsocketUrl()
|
|
return m_url;
|
|
}
|
|
|
|
-void WebsocketServer::ReadLockAllWsSession()
|
|
-{
|
|
- m_mutex.rdlock();
|
|
-}
|
|
-
|
|
-void WebsocketServer::UnlockAllWsSession()
|
|
-{
|
|
- m_mutex.unlock();
|
|
-}
|
|
-
|
|
void WebsocketServer::Shutdown()
|
|
{
|
|
- m_force_exit = 1;
|
|
+ m_forceExit = 1;
|
|
lws_cancel_service(m_context);
|
|
}
|
|
|
|
@@ -99,15 +187,12 @@ void WebsocketServer::EmitLog(int level, const char *line)
|
|
|
|
int WebsocketServer::CreateContext()
|
|
{
|
|
- int limited;
|
|
- struct lws_context_creation_info info;
|
|
- struct rlimit oldLimit, newLimit;
|
|
- const size_t WS_ULIMIT_FDS = 1024;
|
|
+ const size_t WS_ULIMIT_FDS { 1024 };
|
|
|
|
m_url.SetScheme("ws");
|
|
m_url.SetHost("localhost:" + std::to_string(m_listenPort));
|
|
|
|
- (void)memset(&info, 0, sizeof(info));
|
|
+ lws_context_creation_info info { 0x00 };
|
|
lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | LLL_DEBUG, WebsocketServer::EmitLog);
|
|
|
|
info.port = m_listenPort;
|
|
@@ -125,9 +210,10 @@ int WebsocketServer::CreateContext()
|
|
* belowing lws_create_context limit the fds of websocket to RLIMIT_NOFILE,
|
|
* and malloced memory according to it. To reduce memory, we recover it to 1024 before create m_context.
|
|
*/
|
|
+ rlimit oldLimit, newLimit;
|
|
newLimit.rlim_cur = WS_ULIMIT_FDS;
|
|
newLimit.rlim_max = WS_ULIMIT_FDS;
|
|
- limited = prlimit(0, RLIMIT_NOFILE, &newLimit, &oldLimit);
|
|
+ int limited = prlimit(0, RLIMIT_NOFILE, &newLimit, &oldLimit);
|
|
if (limited != 0) {
|
|
WARN("Can not set ulimit of RLIMIT_NOFILE: %s", strerror(errno));
|
|
}
|
|
@@ -145,8 +231,7 @@ int WebsocketServer::CreateContext()
|
|
return 0;
|
|
}
|
|
|
|
-void WebsocketServer::RegisterCallback(const std::string &path,
|
|
- std::shared_ptr<StreamingServeInterface> callback)
|
|
+void WebsocketServer::RegisterCallback(const std::string &path, std::shared_ptr<StreamingServeInterface> callback)
|
|
{
|
|
m_handler.RegisterCallback(path, callback);
|
|
}
|
|
@@ -158,8 +243,8 @@ void WebsocketServer::CloseAllWsSession()
|
|
it->second->EraseAllMessage();
|
|
close(it->second->pipes.at(0));
|
|
close(it->second->pipes.at(1));
|
|
- (void)sem_destroy(it->second->sync_close_sem);
|
|
- delete it->second->session_mutex;
|
|
+ (void)sem_destroy(it->second->syncCloseSem);
|
|
+ delete it->second->sessionMutex;
|
|
delete it->second;
|
|
}
|
|
m_wsis.clear();
|
|
@@ -189,23 +274,23 @@ void WebsocketServer::CloseWsSession(int socketID)
|
|
close(session->pipes.at(1));
|
|
session->pipes.at(1) = -1;
|
|
}
|
|
- (void)sem_wait(session->sync_close_sem);
|
|
- (void)sem_destroy(session->sync_close_sem);
|
|
- delete session->sync_close_sem;
|
|
- session->sync_close_sem = nullptr;
|
|
+ (void)sem_wait(session->syncCloseSem);
|
|
+ (void)sem_destroy(session->syncCloseSem);
|
|
+ delete session->syncCloseSem;
|
|
+ session->syncCloseSem = nullptr;
|
|
close(session->pipes.at(0));
|
|
- delete session->session_mutex;
|
|
- session->session_mutex = nullptr;
|
|
+ delete session->sessionMutex;
|
|
+ session->sessionMutex = nullptr;
|
|
delete session;
|
|
}).detach();
|
|
}
|
|
|
|
-int WebsocketServer::GenerateSessionData(session_data *session, const std::string containerID) noexcept
|
|
+int WebsocketServer::GenerateSessionData(SessionData *session, const std::string containerID) noexcept
|
|
{
|
|
char *suffix = nullptr;
|
|
- int read_pipe_fd[PIPE_FD_NUM] = {-1, -1};
|
|
- std::mutex *buf_mutex = nullptr;
|
|
- sem_t *sync_close_sem = nullptr;
|
|
+ int readPipeFd[2] = { -1, -1 };
|
|
+ std::mutex *bufMutex = nullptr;
|
|
+ sem_t *syncCloseSem = nullptr;
|
|
|
|
suffix = CRIHelpers::GenerateExecSuffix();
|
|
if (suffix == nullptr) {
|
|
@@ -213,24 +298,24 @@ int WebsocketServer::GenerateSessionData(session_data *session, const std::strin
|
|
return -1;
|
|
}
|
|
|
|
- if (InitRWPipe(read_pipe_fd) < 0) {
|
|
+ if (InitRWPipe(readPipeFd) < 0) {
|
|
ERROR("failed to init read/write pipe!");
|
|
goto out;
|
|
}
|
|
|
|
- buf_mutex = new std::mutex;
|
|
- sync_close_sem = new sem_t;
|
|
+ bufMutex = new std::mutex;
|
|
+ syncCloseSem = new sem_t;
|
|
|
|
- if (sem_init(sync_close_sem, 0, 0) != 0) {
|
|
+ if (sem_init(syncCloseSem, 0, 0) != 0) {
|
|
ERROR("Semaphore initialization failed");
|
|
goto out;
|
|
}
|
|
|
|
- session->pipes = std::array<int, MAX_ARRAY_LEN> { read_pipe_fd[0], read_pipe_fd[1] };
|
|
- session->session_mutex = buf_mutex;
|
|
- session->sync_close_sem = sync_close_sem;
|
|
+ session->pipes = std::array<int, MAX_ARRAY_LEN> { readPipeFd[0], readPipeFd[1] };
|
|
+ session->sessionMutex = bufMutex;
|
|
+ session->syncCloseSem = syncCloseSem;
|
|
session->close = false;
|
|
- session->container_id = containerID;
|
|
+ session->containerID = containerID;
|
|
session->suffix = std::string(suffix);
|
|
|
|
free(suffix);
|
|
@@ -241,17 +326,17 @@ out:
|
|
if (suffix != nullptr) {
|
|
free(suffix);
|
|
}
|
|
- if (read_pipe_fd[1] >= 0) {
|
|
- close(read_pipe_fd[1]);
|
|
+ if (readPipeFd[1] >= 0) {
|
|
+ close(readPipeFd[1]);
|
|
}
|
|
- if (read_pipe_fd[0] >= 0) {
|
|
- close(read_pipe_fd[0]);
|
|
+ if (readPipeFd[0] >= 0) {
|
|
+ close(readPipeFd[0]);
|
|
}
|
|
- if (buf_mutex != nullptr) {
|
|
- delete buf_mutex;
|
|
+ if (bufMutex != nullptr) {
|
|
+ delete bufMutex;
|
|
}
|
|
- if (sync_close_sem) {
|
|
- delete sync_close_sem;
|
|
+ if (syncCloseSem) {
|
|
+ delete syncCloseSem;
|
|
}
|
|
|
|
return -1;
|
|
@@ -269,10 +354,9 @@ int WebsocketServer::RegisterStreamTask(struct lws *wsi) noexcept
|
|
buf[sizeof(buf) - 1] = '\0';
|
|
// format: "/cri/" + method + "/" + token + "/" + arg(container=cmd)
|
|
auto vec = CXXUtils::Split(buf + 1, '/');
|
|
- RequestCache *cache = RequestCache::GetInstance();
|
|
- if (vec.size() < MIN_VEC_SIZE ||
|
|
- !m_handler.IsValidMethod(vec.at(1)) ||
|
|
- !cache->IsValidToken(vec.at(2))) {
|
|
+ auto *cache = RequestCache::GetInstance();
|
|
+ // buffer contains at least 3 parts: cri, method, token
|
|
+ if (vec.size() < 3 || !m_handler.IsValidMethod(vec.at(1)) || !cache->IsValidToken(vec.at(2))) {
|
|
ERROR("invalid url(%s): incorrect format!", buf);
|
|
return -1;
|
|
}
|
|
@@ -288,13 +372,13 @@ int WebsocketServer::RegisterStreamTask(struct lws *wsi) noexcept
|
|
return -1;
|
|
}
|
|
|
|
- std::string containerID = cache->GetContainerIDByToken(vec.at(1), vec.at(2));
|
|
+ auto containerID = cache->GetContainerIDByToken(vec.at(2));
|
|
if (containerID.empty()) {
|
|
ERROR("Failed to get container id from %s request", vec.at(1).c_str());
|
|
return -1;
|
|
}
|
|
|
|
- session_data *session = new (std::nothrow) session_data;
|
|
+ auto *session = new (std::nothrow) SessionData;
|
|
if (session == nullptr) {
|
|
ERROR("Out of memory");
|
|
return -1;
|
|
@@ -304,7 +388,7 @@ int WebsocketServer::RegisterStreamTask(struct lws *wsi) noexcept
|
|
return -1;
|
|
}
|
|
|
|
- std::string suffixID = session->suffix;
|
|
+ auto suffixID = session->suffix;
|
|
auto insertRet = m_wsis.insert(std::make_pair(socketID, session));
|
|
if (!insertRet.second) {
|
|
ERROR("failed to insert session data to map");
|
|
@@ -351,8 +435,8 @@ int WebsocketServer::Wswrite(struct lws *wsi, const unsigned char *message)
|
|
if (strlen((const char *)(&message[LWS_PRE + 1])) == 0) {
|
|
return 0;
|
|
}
|
|
- int n = lws_write(wsi, (unsigned char *)(&message[LWS_PRE]),
|
|
- strlen((const char *)(&message[LWS_PRE + 1])) + 1, LWS_WRITE_TEXT);
|
|
+ auto n = lws_write(wsi, (unsigned char *)(&message[LWS_PRE]), strlen((const char *)(&message[LWS_PRE + 1])) + 1,
|
|
+ LWS_WRITE_TEXT);
|
|
if (n < 0) {
|
|
ERROR("ERROR %d writing to socket, hanging up", n);
|
|
return -1;
|
|
@@ -362,21 +446,18 @@ int WebsocketServer::Wswrite(struct lws *wsi, const unsigned char *message)
|
|
return 0;
|
|
}
|
|
|
|
-int WebsocketServer::parseTerminalSize(const char *jsonData, size_t len, uint16_t &width, uint16_t &height)
|
|
+int WebsocketServer::ParseTerminalSize(const char *jsonData, size_t len, uint16_t &width, uint16_t &height)
|
|
{
|
|
- int ret = 0;
|
|
- parser_error err = nullptr;
|
|
- cri_terminal_size *terminalSize = nullptr;
|
|
-
|
|
if (jsonData == nullptr || len == 0) {
|
|
return -1;
|
|
}
|
|
|
|
// No terminator is included in json data, and len contains a character occupied by channal
|
|
std::string jsonDataStr { jsonData, len - 1 };
|
|
-
|
|
+ parser_error err = nullptr;
|
|
+ int ret = 0;
|
|
// parse json data. eg: {"Width":xx,"Height":xx}
|
|
- terminalSize = cri_terminal_size_parse_data(jsonDataStr.c_str(), nullptr, &err);
|
|
+ cri_terminal_size *terminalSize = cri_terminal_size_parse_data(jsonDataStr.c_str(), nullptr, &err);
|
|
if (terminalSize == nullptr) {
|
|
ERROR("Failed to parse json: %s", err);
|
|
ret = -1;
|
|
@@ -391,29 +472,22 @@ int WebsocketServer::parseTerminalSize(const char *jsonData, size_t len, uint16_
|
|
return ret;
|
|
}
|
|
|
|
-int WebsocketServer::ResizeTerminal(
|
|
- int socketID, const char *jsonData, size_t len,
|
|
- const std::string &containerID,
|
|
- const std::string &suffix)
|
|
+int WebsocketServer::ResizeTerminal(int socketID, const char *jsonData, size_t len, const std::string &containerID,
|
|
+ const std::string &suffix)
|
|
{
|
|
- int ret;
|
|
- service_executor_t *cb = nullptr;
|
|
- struct isulad_container_resize_request *req = nullptr;
|
|
- struct isulad_container_resize_response *res = nullptr;
|
|
- uint16_t width = 0;
|
|
- uint16_t height = 0;
|
|
-
|
|
- cb = get_service_executor();
|
|
+ auto *cb = get_service_executor();
|
|
if (cb == nullptr || cb->container.resize == nullptr) {
|
|
return -1;
|
|
}
|
|
|
|
- if (parseTerminalSize(jsonData, len, width, height) != 0) {
|
|
+ uint16_t width = 0;
|
|
+ uint16_t height = 0;
|
|
+ if (ParseTerminalSize(jsonData, len, width, height) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
- req = (struct isulad_container_resize_request *)util_common_calloc_s(
|
|
- sizeof(struct isulad_container_resize_request));
|
|
+ auto *req = static_cast<isulad_container_resize_request *>(
|
|
+ util_common_calloc_s(sizeof(struct isulad_container_resize_request)));
|
|
if (req == nullptr) {
|
|
ERROR("Out of memory");
|
|
return -1;
|
|
@@ -424,12 +498,12 @@ int WebsocketServer::ResizeTerminal(
|
|
req->height = height;
|
|
req->width = width;
|
|
|
|
- ret = cb->container.resize(req, &res);
|
|
+ struct isulad_container_resize_response *res = nullptr;
|
|
+ int ret = cb->container.resize(req, &res);
|
|
|
|
isulad_container_resize_request_free(req);
|
|
isulad_container_resize_response_free(res);
|
|
|
|
-
|
|
return ret;
|
|
}
|
|
|
|
@@ -442,9 +516,7 @@ void WebsocketServer::Receive(int socketID, void *in, size_t len)
|
|
}
|
|
|
|
if (*static_cast<char *>(in) == WebsocketChannel::RESIZECHANNEL) {
|
|
- std::string containerID = it->second->container_id;
|
|
- std::string suffix = it->second->suffix;
|
|
- if (ResizeTerminal(socketID, (char *)in + 1, len, containerID, suffix) != 0) {
|
|
+ if (ResizeTerminal(socketID, (char *)in + 1, len, it->second->containerID, it->second->suffix) != 0) {
|
|
ERROR("Failed to resize terminal tty");
|
|
return;
|
|
}
|
|
@@ -459,8 +531,7 @@ void WebsocketServer::Receive(int socketID, void *in, size_t len)
|
|
}
|
|
}
|
|
|
|
-int WebsocketServer::Callback(struct lws *wsi, enum lws_callback_reasons reason,
|
|
- void *user, void *in, size_t len)
|
|
+int WebsocketServer::Callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
|
|
{
|
|
switch (reason) {
|
|
case LWS_CALLBACK_HTTP:
|
|
@@ -493,11 +564,11 @@ int WebsocketServer::Callback(struct lws *wsi, enum lws_callback_reasons reason,
|
|
return -1;
|
|
}
|
|
|
|
- auto isSessionClosed = it->second->IsClosed();
|
|
+ auto sessionClosed = it->second->IsClosed();
|
|
while (!it->second->buffer.empty()) {
|
|
- unsigned char *message = it->second->FrontMessage();
|
|
+ auto *message = it->second->FrontMessage();
|
|
// send success! free it and erase for list
|
|
- if (WebsocketServer::GetInstance()->Wswrite(wsi, (const unsigned char *)message) == 0) {
|
|
+ if (WebsocketServer::GetInstance()->Wswrite(wsi, const_cast<const unsigned char *>(message)) == 0) {
|
|
free(message);
|
|
it->second->PopMessage();
|
|
} else {
|
|
@@ -508,7 +579,7 @@ int WebsocketServer::Callback(struct lws *wsi, enum lws_callback_reasons reason,
|
|
}
|
|
|
|
// avoid: push message to buffer and set closed true
|
|
- if (isSessionClosed) {
|
|
+ if (sessionClosed) {
|
|
DEBUG("websocket session disconnected");
|
|
return -1;
|
|
}
|
|
@@ -517,7 +588,7 @@ int WebsocketServer::Callback(struct lws *wsi, enum lws_callback_reasons reason,
|
|
break;
|
|
case LWS_CALLBACK_RECEIVE: {
|
|
ReadGuard<RWMutex> lock(m_mutex);
|
|
- WebsocketServer::GetInstance()->Receive(lws_get_socket_fd(wsi), (char *)in, len);
|
|
+ WebsocketServer::GetInstance()->Receive(lws_get_socket_fd(wsi), static_cast<char *>(in), len);
|
|
}
|
|
break;
|
|
case LWS_CALLBACK_CLOSED: {
|
|
@@ -538,7 +609,7 @@ void WebsocketServer::ServiceWorkThread(int threadid)
|
|
|
|
prctl(PR_SET_NAME, "WebsocketServer");
|
|
|
|
- while (n >= 0 && !m_force_exit) {
|
|
+ while (n >= 0 && !m_forceExit) {
|
|
n = lws_service(m_context, 0);
|
|
}
|
|
}
|
|
@@ -553,16 +624,17 @@ void WebsocketServer::Start(Errors &err)
|
|
|
|
if (CreateContext() < 0) {
|
|
err.SetError("Websocket server start failed! please check your network status"
|
|
- "(eg: port " + std::to_string(m_listenPort) + " is occupied)");
|
|
+ "(eg: port " +
|
|
+ std::to_string(m_listenPort) + " is occupied)");
|
|
return;
|
|
}
|
|
- m_pthread_service = std::thread(&WebsocketServer::ServiceWorkThread, this, 0);
|
|
+ m_pthreadService = std::thread(&WebsocketServer::ServiceWorkThread, this, 0);
|
|
}
|
|
|
|
void WebsocketServer::Wait()
|
|
{
|
|
- if (m_pthread_service.joinable()) {
|
|
- m_pthread_service.join();
|
|
+ if (m_pthreadService.joinable()) {
|
|
+ m_pthreadService.join();
|
|
}
|
|
|
|
CloseAllWsSession();
|
|
@@ -571,19 +643,17 @@ void WebsocketServer::Wait()
|
|
}
|
|
|
|
namespace {
|
|
-
|
|
-void DoWriteToClient(session_data *session,
|
|
- const void *data, size_t len, WebsocketChannel channel)
|
|
+void DoWriteToClient(SessionData *session, const void *data, size_t len, WebsocketChannel channel)
|
|
{
|
|
- unsigned char *buf = (unsigned char *)util_common_calloc_s(LWS_PRE + MAX_BUFFER_SIZE + 1);
|
|
+ auto *buf = static_cast<unsigned char *>(util_common_calloc_s(LWS_PRE + MAX_BUFFER_SIZE + 1));
|
|
if (buf == nullptr) {
|
|
ERROR("Out of memory");
|
|
return;
|
|
}
|
|
// Determine if it is standard output channel or error channel
|
|
- buf[LWS_PRE] = channel;
|
|
+ buf[LWS_PRE] = static_cast<int>(channel);
|
|
|
|
- (void)memcpy(&buf[LWS_PRE + 1], (void *)data, len);
|
|
+ (void)memcpy(&buf[LWS_PRE + 1], const_cast<void *>(data), len);
|
|
|
|
// push back to message list
|
|
if (session->PushMessage(buf) != 0) {
|
|
@@ -594,7 +664,7 @@ void DoWriteToClient(session_data *session,
|
|
|
|
ssize_t WsWriteToClient(void *context, const void *data, size_t len, WebsocketChannel channel)
|
|
{
|
|
- auto *lwsCtx = static_cast<session_data *>(context);
|
|
+ auto *lwsCtx = static_cast<SessionData *>(context);
|
|
|
|
// CloseWsSession wait IOCopy finished, and then delete session in m_wsis
|
|
// So don't need rdlock m_wsis here
|
|
@@ -605,7 +675,7 @@ ssize_t WsWriteToClient(void *context, const void *data, size_t len, WebsocketCh
|
|
DoWriteToClient(lwsCtx, data, len, channel);
|
|
return static_cast<ssize_t>(len);
|
|
}
|
|
-};
|
|
+}; // namespace
|
|
|
|
ssize_t WsWriteStdoutToClient(void *context, const void *data, size_t len)
|
|
{
|
|
@@ -636,12 +706,12 @@ int closeWsConnect(void *context, char **err)
|
|
return -1;
|
|
}
|
|
|
|
- auto *lwsCtx = static_cast<session_data *>(context);
|
|
+ auto *lwsCtx = static_cast<SessionData *>(context);
|
|
|
|
lwsCtx->CloseSession();
|
|
|
|
- if (lwsCtx->sync_close_sem != nullptr) {
|
|
- (void)sem_post(lwsCtx->sync_close_sem);
|
|
+ if (lwsCtx->syncCloseSem != nullptr) {
|
|
+ (void)sem_post(lwsCtx->syncCloseSem);
|
|
}
|
|
|
|
return 0;
|
|
diff --git a/src/daemon/entry/cri/websocket/service/ws_server.h b/src/daemon/entry/cri/websocket/service/ws_server.h
|
|
index 3ab8e22f..2d3bb4a7 100644
|
|
--- a/src/daemon/entry/cri/websocket/service/ws_server.h
|
|
+++ b/src/daemon/entry/cri/websocket/service/ws_server.h
|
|
@@ -1,5 +1,5 @@
|
|
/******************************************************************************
|
|
- * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved.
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved.
|
|
* iSulad licensed under the Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
@@ -17,7 +17,6 @@
|
|
#define DAEMON_ENTRY_CRI_WEBSOCKET_SERVICE_WS_SERVER_H
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
-#include <unordered_set>
|
|
#include <string>
|
|
#include <mutex>
|
|
#include <atomic>
|
|
@@ -29,140 +28,40 @@
|
|
#include "url.h"
|
|
#include "errors.h"
|
|
#include "read_write_lock.h"
|
|
-#include "isula_libutils/cri_terminal_size.h"
|
|
|
|
-#define MAX_ECHO_PAYLOAD 4096
|
|
-#define MAX_ARRAY_LEN 2
|
|
-#define MAX_BUF_LEN 256
|
|
-#define MAX_PROTOCOL_NUM 2
|
|
-#define MAX_HTTP_HEADER_POOL 8
|
|
-#define MIN_VEC_SIZE 3
|
|
-#define PIPE_FD_NUM 2
|
|
-#define BUF_BASE_SIZE 1024
|
|
-#define LWS_TIMEOUT 50
|
|
-// io copy maximum single transfer 4K, let max total buffer size: 1GB
|
|
-#define FIFO_LIST_BUFFER_MAX_LEN 262144
|
|
-#define SESSION_CAPABILITY 300
|
|
-#define MAX_SESSION_NUM 128
|
|
+namespace
|
|
+{
|
|
+const int MAX_ECHO_PAYLOAD = 4096;
|
|
+const int MAX_ARRAY_LEN = 2;
|
|
+const int MAX_PROTOCOL_NUM = 2;
|
|
+}; // namespace
|
|
|
|
-enum WebsocketChannel {
|
|
- STDINCHANNEL = 0,
|
|
- STDOUTCHANNEL,
|
|
- STDERRCHANNEL,
|
|
- ERRORCHANNEL,
|
|
- RESIZECHANNEL
|
|
-};
|
|
-
|
|
-struct session_data {
|
|
+struct SessionData {
|
|
std::array<int, MAX_ARRAY_LEN> pipes;
|
|
volatile bool close;
|
|
- std::mutex *session_mutex;
|
|
- sem_t *sync_close_sem;
|
|
+ std::mutex *sessionMutex;
|
|
+ sem_t *syncCloseSem;
|
|
std::list<unsigned char *> buffer;
|
|
- std::string container_id;
|
|
+ std::string containerID;
|
|
std::string suffix;
|
|
|
|
- unsigned char *FrontMessage()
|
|
- {
|
|
- unsigned char *message = nullptr;
|
|
-
|
|
- if (session_mutex == nullptr) {
|
|
- return nullptr;
|
|
- }
|
|
-
|
|
- session_mutex->lock();
|
|
- message = buffer.front();
|
|
- session_mutex->unlock();
|
|
-
|
|
- return message;
|
|
- }
|
|
-
|
|
- void PopMessage()
|
|
- {
|
|
- if (session_mutex == nullptr) {
|
|
- return;
|
|
- }
|
|
-
|
|
- session_mutex->lock();
|
|
- buffer.pop_front();
|
|
- session_mutex->unlock();
|
|
- }
|
|
-
|
|
- int PushMessage(unsigned char *message)
|
|
- {
|
|
- if (session_mutex == nullptr) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
- session_mutex->lock();
|
|
-
|
|
- // In extreme scenarios, websocket data cannot be processed,
|
|
- // ignore the data coming in later to prevent iSulad from getting stuck
|
|
- if (close || buffer.size() >= FIFO_LIST_BUFFER_MAX_LEN) {
|
|
- free(message);
|
|
- session_mutex->unlock();
|
|
- return -1;
|
|
- }
|
|
-
|
|
- buffer.push_back(message);
|
|
- session_mutex->unlock();
|
|
- return 0;
|
|
- }
|
|
-
|
|
- bool IsClosed()
|
|
- {
|
|
- bool c = false;
|
|
-
|
|
- if (session_mutex == nullptr) {
|
|
- return true;
|
|
- }
|
|
-
|
|
- session_mutex->lock();
|
|
- c = close;
|
|
- session_mutex->unlock();
|
|
-
|
|
- return c;
|
|
- }
|
|
-
|
|
- void CloseSession()
|
|
- {
|
|
- if (session_mutex == nullptr) {
|
|
- return;
|
|
- }
|
|
-
|
|
- session_mutex->lock();
|
|
- close = true;
|
|
- session_mutex->unlock();
|
|
- }
|
|
-
|
|
- void EraseAllMessage()
|
|
- {
|
|
- if (session_mutex == nullptr) {
|
|
- return;
|
|
- }
|
|
-
|
|
- session_mutex->lock();
|
|
- for (auto iter = buffer.begin(); iter != buffer.end();) {
|
|
- free(*iter);
|
|
- *iter = NULL;
|
|
- iter = buffer.erase(iter);
|
|
- }
|
|
- session_mutex->unlock();
|
|
- }
|
|
+ unsigned char *FrontMessage();
|
|
+ void PopMessage();
|
|
+ int PushMessage(unsigned char *message);
|
|
+ bool IsClosed();
|
|
+ void CloseSession();
|
|
+ void EraseAllMessage();
|
|
};
|
|
|
|
class WebsocketServer {
|
|
public:
|
|
static WebsocketServer *GetInstance() noexcept;
|
|
- static std::atomic<WebsocketServer *> m_instance;
|
|
void Start(Errors &err);
|
|
void Wait();
|
|
void Shutdown();
|
|
void RegisterCallback(const std::string &path, std::shared_ptr<StreamingServeInterface> callback);
|
|
url::URLDatum GetWebsocketUrl();
|
|
void SetLwsSendedFlag(int socketID, bool sended);
|
|
- void ReadLockAllWsSession();
|
|
- void UnlockAllWsSession();
|
|
|
|
private:
|
|
WebsocketServer();
|
|
@@ -171,33 +70,41 @@ private:
|
|
virtual ~WebsocketServer();
|
|
int InitRWPipe(int read_fifo[]);
|
|
std::vector<std::string> split(std::string str, char r);
|
|
- static void EmitLog(int level, const char *line);
|
|
+
|
|
int CreateContext();
|
|
inline void Receive(int socketID, void *in, size_t len);
|
|
- int Wswrite(struct lws *wsi, const unsigned char *message);
|
|
+ int Wswrite(struct lws *wsi, const unsigned char *message);
|
|
inline void DumpHandshakeInfo(struct lws *wsi) noexcept;
|
|
int RegisterStreamTask(struct lws *wsi) noexcept;
|
|
- int GenerateSessionData(session_data *session, const std::string containerID) noexcept;
|
|
- static int Callback(struct lws *wsi, enum lws_callback_reasons reason,
|
|
- void *user, void *in, size_t len);
|
|
+ int GenerateSessionData(SessionData *session, const std::string containerID) noexcept;
|
|
void ServiceWorkThread(int threadid);
|
|
void CloseWsSession(int socketID);
|
|
void CloseAllWsSession();
|
|
- int ResizeTerminal(int socketID, const char *jsonData, size_t len,
|
|
- const std::string &containerID, const std::string &suffix);
|
|
- int parseTerminalSize(const char *jsonData, size_t len, uint16_t &width, uint16_t &height);
|
|
+ int ResizeTerminal(int socketID, const char *jsonData, size_t len, const std::string &containerID,
|
|
+ const std::string &suffix);
|
|
+ int ParseTerminalSize(const char *jsonData, size_t len, uint16_t &width, uint16_t &height);
|
|
+
|
|
+private:
|
|
+ // redirect libwebsockets logs to iSulad
|
|
+ static void EmitLog(int level, const char *line);
|
|
+ // libwebsockets Callback function
|
|
+ static int Callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
|
|
|
|
private:
|
|
+ static std::atomic<WebsocketServer *> m_instance;
|
|
static RWMutex m_mutex;
|
|
static struct lws_context *m_context;
|
|
- volatile int m_force_exit = 0;
|
|
- std::thread m_pthread_service;
|
|
- const struct lws_protocols m_protocols[MAX_PROTOCOL_NUM] = {
|
|
- { "channel.k8s.io", Callback, 0, MAX_ECHO_PAYLOAD, },
|
|
- { nullptr, nullptr, 0, 0 }
|
|
- };
|
|
+ volatile int m_forceExit = 0;
|
|
+ std::thread m_pthreadService;
|
|
+ const struct lws_protocols m_protocols[MAX_PROTOCOL_NUM] = { {
|
|
+ "channel.k8s.io",
|
|
+ Callback,
|
|
+ 0,
|
|
+ MAX_ECHO_PAYLOAD,
|
|
+ },
|
|
+ { nullptr, nullptr, 0, 0 } };
|
|
RouteCallbackRegister m_handler;
|
|
- static std::unordered_map<int, session_data *> m_wsis;
|
|
+ static std::unordered_map<int, SessionData *> m_wsis;
|
|
url::URLDatum m_url;
|
|
int m_listenPort;
|
|
};
|
|
@@ -207,4 +114,3 @@ ssize_t WsWriteStderrToClient(void *context, const void *data, size_t len);
|
|
int closeWsConnect(void *context, char **err);
|
|
|
|
#endif // DAEMON_ENTRY_CRI_WEBSOCKET_SERVICE_WS_SERVER_H
|
|
-
|
|
--
|
|
2.25.1
|
|
|