1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "net_server.h" 17 18#include "utils/log.h" 19 20#include <cstdlib> 21 22using namespace std; 23 24NetServer::NetServer(napi_env env, napi_value thisVar) : EventTarget(env, thisVar) 25{ 26 loop_ = nullptr; 27 napi_get_uv_event_loop(env, &loop_); 28 tcpServer_ = { 0 }; 29 tcpServer_.data = this; 30 serverClosed_ = 0; 31 clients_ = nullptr; 32} 33 34NetServer::~NetServer() {} 35 36int NetServer::Start(int port) 37{ 38 struct sockaddr_in addr; 39 int result = 0; 40 41 uv_ip4_addr("0.0.0.0", port, &addr); 42 43 result = uv_tcp_init(loop_, &tcpServer_); 44 if (result) { 45 this->Emit("error", nullptr); 46 return -1; 47 } 48 49 result = uv_tcp_bind(&tcpServer_, (const struct sockaddr*)&addr, 0); 50 if (result) { 51 this->Emit("error", nullptr); 52 return -1; 53 } 54 55 result = uv_listen((uv_stream_t*)&tcpServer_, SOMAXCONN, OnConnection); 56 if (result) { 57 this->Emit("error", nullptr); 58 return -1; 59 } 60 61 Emit("started", nullptr); 62 63 return 0; 64} 65 66void NetServer::Stop() 67{ 68 Emit("closed", nullptr); 69 uint32_t thisRefCount = 0; 70 napi_reference_unref(env_, thisVarRef_, &thisRefCount); 71} 72 73void NetServer::OnClose(uv_handle_t* peer) 74{ 75 if (peer == nullptr) { 76 HILOG_ERROR("peer is null"); 77 return; 78 } 79 80 NetServer* that = static_cast<NetServer*>(peer->data); 81 that->Emit("disconnect", nullptr); 82 free(peer); 83} 84 85void NetServer::OnConnection(uv_stream_t* server, int status) 86{ 87 if (server == nullptr) { 88 HILOG_ERROR("server is null"); 89 return; 90 } 91 92 NetServer* that = static_cast<NetServer*>(server->data); 93 94 if (status != 0) { 95 that->Emit("error", nullptr); 96 } 97 98 if (that->clients_ == nullptr) { 99 that->clients_ = new NetClient(); 100 } else { 101 auto tmp = new NetClient(); 102 tmp->next = that->clients_; 103 that->clients_ = tmp; 104 } 105 106 uv_tcp_init(that->loop_, (uv_tcp_t*)&that->clients_->tcp); 107 that->clients_->tcp.data = server->data; 108 uv_accept(server, (uv_stream_t*)&that->clients_->tcp); 109 uv_read_start((uv_stream_t*)&that->clients_->tcp, EchoAlloc, AfterRead); 110 111 that->Emit("connect", nullptr); 112} 113 114void NetServer::OnServerClose(uv_handle_t* handle) 115{ 116 if (handle == nullptr) { 117 HILOG_ERROR("handle is null"); 118 return; 119 } 120 121 NetServer* that = static_cast<NetServer*>(handle->data); 122 123 for (NetClient* i = that->clients_; i != nullptr; i = i->next) { 124 uv_close((uv_handle_t*)&i->tcp, nullptr); 125 } 126 127 uint32_t thisRefCount = 0; 128 napi_reference_unref(that->env_, that->thisVarRef_, &thisRefCount); 129} 130 131void NetServer::AfterWrite(uv_write_t* req, int status) 132{ 133 if (req == nullptr) { 134 HILOG_ERROR("req is null"); 135 return; 136 } 137 138 NetServer* that = static_cast<NetServer*>(req->data); 139 140 WriteReq* wr = reinterpret_cast<WriteReq*>(req); 141 142 free(wr->buf.base); 143 free(wr); 144 145 if (status == 0) { 146 that->Emit("write", nullptr); 147 return; 148 } 149 150 that->Emit("error", nullptr); 151} 152 153void NetServer::TakeDiffactionsByStatus(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf, NetServer* that) 154{ 155 WriteReq* wr = nullptr; 156 uv_shutdown_t* sreq = nullptr; 157 if (nread < 0) { 158 free(buf->base); 159 sreq = (uv_shutdown_t*)malloc(sizeof(*sreq)); 160 if (sreq == nullptr) { 161 HILOG_ERROR("sreq is null"); 162 return; 163 } 164 sreq->data = that; 165 uv_shutdown(sreq, handle, AfterShutdown); 166 return; 167 } 168 169 if (!that->serverClosed_) { 170 for (int i = 0; i < nread; i++) { 171 if (buf->base[i] != 'Q') { 172 continue; 173 } 174 if (i + 1 < nread && buf->base[i + 1] == 'S') { 175 free(buf->base); 176 uv_close((uv_handle_t*)handle, OnClose); 177 return; 178 } else { 179 uv_close((uv_handle_t*)&that->tcpServer_, OnServerClose); 180 that->serverClosed_ = 1; 181 return; 182 } 183 } 184 } 185 186 that->Emit("read", nullptr); 187 wr = static_cast<WriteReq*>(malloc(sizeof(WriteReq))); 188 if (wr == nullptr) { 189 HILOG_ERROR("wr is null"); 190 free(buf->base); 191 return; 192 } 193 194 wr->buf = uv_buf_init(buf->base, nread); 195 wr->req.data = that; 196 if (uv_write(&wr->req, handle, &wr->buf, 1, AfterWrite) != 0) { 197 that->Emit("error", nullptr); 198 } 199} 200 201void NetServer::AfterRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) 202{ 203 if (handle == nullptr) { 204 HILOG_ERROR("handle is null"); 205 return; 206 } 207 208 if (buf == nullptr) { 209 HILOG_ERROR("buf is null"); 210 return; 211 } 212 213 NetServer* that = static_cast<NetServer*>(handle->data); 214 if (nread == 0) { 215 free(buf->base); 216 return; 217 } 218 219 TakeDiffactionsByStatus(handle, nread, buf, that); 220} 221 222void NetServer::AfterShutdown(uv_shutdown_t* req, int status) 223{ 224 if (req == nullptr) { 225 HILOG_ERROR("req is null"); 226 return; 227 } 228 229 uv_close((uv_handle_t*)req->handle, OnClose); 230 free(req); 231} 232 233void NetServer::EchoAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf) 234{ 235 if (handle == nullptr) { 236 HILOG_ERROR("handle is null"); 237 return; 238 } 239 240 if (buf == nullptr) { 241 HILOG_ERROR("buf is null"); 242 return; 243 } 244 245 if (suggestedSize == 0) { 246 HILOG_ERROR("suggestedSize = 0"); 247 return; 248 } 249 250 buf->base = (char*)malloc(suggestedSize); 251 if (buf->base != nullptr) { 252 HILOG_ERROR("buf->base is null"); 253 return; 254 } 255 256 buf->len = suggestedSize; 257} 258