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 "netserver.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 napi_get_uv_event_loop(env, &loop_); 27 tcpServer_ = { 0 }; 28 tcpServer_.data = this; 29 serverClosed_ = false; 30 clients_ = nullptr; 31} 32 33NetServer::~NetServer() {} 34 35int NetServer::Start(int port) 36{ 37 struct sockaddr_in addr; 38 int result = 0; 39 40 uv_ip4_addr("0.0.0.0", port, &addr); 41 42 result = uv_tcp_init(loop_, &tcpServer_); 43 if (result) { 44 this->Emit("error", nullptr); 45 return -1; 46 } 47 48 result = uv_tcp_bind(&tcpServer_, (const struct sockaddr*)&addr, 0); 49 if (result) { 50 this->Emit("error", nullptr); 51 return -1; 52 } 53 54 result = uv_listen((uv_stream_t*)&tcpServer_, SOMAXCONN, OnConnection); 55 if (result) { 56 this->Emit("error", nullptr); 57 return -1; 58 } 59 60 Emit("started", nullptr); 61 62 return 0; 63} 64 65void NetServer::Stop() 66{ 67 Emit("closed", nullptr); 68 uint32_t thisRefCount = 0; 69 napi_reference_unref(env_, thisVarRef_, &thisRefCount); 70} 71 72void NetServer::OnClose(uv_handle_t* peer) 73{ 74 if (peer == nullptr) { 75 HILOG_ERROR("peer is null"); 76 return; 77 } 78 79 NetServer* that = (NetServer*)peer->data; 80 that->Emit("disconnect", nullptr); 81 free(peer); 82} 83 84void NetServer::OnConnection(uv_stream_t* server, int status) 85{ 86 if (server == nullptr) { 87 HILOG_ERROR("server is null"); 88 return; 89 } 90 91 NetServer* that = (NetServer*)server->data; 92 93 if (status != 0) { 94 that->Emit("error", nullptr); 95 } 96 97 if (that->clients_ == nullptr) { 98 that->clients_ = new NetClient(); 99 } else { 100 auto tmp = new NetClient(); 101 tmp->next = that->clients_; 102 that->clients_ = tmp; 103 } 104 105 uv_tcp_init(that->loop_, (uv_tcp_t*)&that->clients_->tcp); 106 that->clients_->tcp.data = server->data; 107 uv_accept(server, (uv_stream_t*)&that->clients_->tcp); 108 uv_read_start((uv_stream_t*)&that->clients_->tcp, EchoAlloc, AfterRead); 109 110 that->Emit("connect", nullptr); 111} 112 113void NetServer::OnServerClose(uv_handle_t* handle) 114{ 115 if (handle == nullptr) { 116 HILOG_ERROR("handle is null"); 117 return; 118 } 119 120 NetServer* that = (NetServer*)handle->data; 121 122 for (NetClient* i = that->clients_; i != nullptr; i = i->next) { 123 uv_close((uv_handle_t*)&i->tcp, nullptr); 124 } 125 126 uint32_t thisRefCount = 0; 127 napi_reference_unref(that->env_, that->thisVarRef_, &thisRefCount); 128} 129 130void NetServer::AfterWrite(uv_write_t* req, int status) 131{ 132 if (req == nullptr) { 133 HILOG_ERROR("req is null"); 134 return; 135 } 136 137 NetServer* that = (NetServer*)req->data; 138 139 WriteReq* wr = (WriteReq*)req; 140 141 free(wr->buf.base); 142 free(wr); 143 144 if (status == 0) { 145 that->Emit("write", nullptr); 146 return; 147 } 148 149 that->Emit("error", nullptr); 150} 151 152void NetServer::TakeDiffactionsByStatus(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf, NetServer* that) 153{ 154 WriteReq* wr = nullptr; 155 uv_shutdown_t* sreq = nullptr; 156 if (nread < 0) { 157 free(buf->base); 158 sreq = (uv_shutdown_t*)malloc(sizeof(*sreq)); 159 if (sreq == nullptr) { 160 HILOG_ERROR("sreq is null"); 161 return; 162 } 163 sreq->data = that; 164 uv_shutdown(sreq, handle, AfterShutdown); 165 return; 166 } 167 168 if (!that->serverClosed_) { 169 for (int i = 0; i < nread; i++) { 170 if (buf->base[i] != 'Q') { 171 continue; 172 } 173 if (i + 1 < nread && buf->base[i + 1] == 'S') { 174 free(buf->base); 175 uv_close((uv_handle_t*)handle, OnClose); 176 return; 177 } else { 178 uv_close((uv_handle_t*)&that->tcpServer_, OnServerClose); 179 that->serverClosed_ = 1; 180 return; 181 } 182 } 183 } 184 185 that->Emit("read", nullptr); 186 wr = (WriteReq*)malloc(sizeof(WriteReq)); 187 if (wr == nullptr) { 188 HILOG_ERROR("wr is null"); 189 free(buf->base); 190 return; 191 } 192 193 wr->buf = uv_buf_init(buf->base, nread); 194 wr->req.data = that; 195 if (uv_write(&wr->req, handle, &wr->buf, 1, AfterWrite) != 0) { 196 that->Emit("error", nullptr); 197 } 198} 199 200void NetServer::AfterRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) 201{ 202 if (handle == nullptr) { 203 HILOG_ERROR("handle is null"); 204 return; 205 } 206 207 if (buf == nullptr) { 208 HILOG_ERROR("buf is null"); 209 return; 210 } 211 212 NetServer* that = (NetServer*)handle->data; 213 if (nread == 0) { 214 free(buf->base); 215 return; 216 } 217 218 TakeDiffactionsByStatus(handle, nread, buf, that); 219} 220 221void NetServer::AfterShutdown(uv_shutdown_t* req, int status) 222{ 223 if (req == nullptr) { 224 HILOG_ERROR("req is null"); 225 return; 226 } 227 228 uv_close((uv_handle_t*)req->handle, OnClose); 229 free(req); 230} 231 232void NetServer::EchoAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf) 233{ 234 if (handle == nullptr) { 235 HILOG_ERROR("handle is null"); 236 return; 237 } 238 239 if (buf == nullptr) { 240 HILOG_ERROR("buf is null"); 241 return; 242 } 243 244 buf->base = (char*)malloc(suggestedSize); 245 if (buf->base != nullptr) { 246 HILOG_ERROR("buf->base is null"); 247 return; 248 } 249 250 buf->len = suggestedSize; 251} 252