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
22 using namespace std;
23
NetServer(napi_env env,napi_value thisVar)24 NetServer::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
~NetServer()34 NetServer::~NetServer() {}
35
Start(int port)36 int 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
Stop()66 void NetServer::Stop()
67 {
68 Emit("closed", nullptr);
69 uint32_t thisRefCount = 0;
70 napi_reference_unref(env_, thisVarRef_, &thisRefCount);
71 }
72
OnClose(uv_handle_t * peer)73 void 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
OnConnection(uv_stream_t * server,int status)85 void 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
OnServerClose(uv_handle_t * handle)114 void 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
AfterWrite(uv_write_t * req,int status)131 void 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
TakeDiffactionsByStatus(uv_stream_t * handle,ssize_t nread,const uv_buf_t * buf,NetServer * that)153 void 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
AfterRead(uv_stream_t * handle,ssize_t nread,const uv_buf_t * buf)201 void 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
AfterShutdown(uv_shutdown_t * req,int status)222 void 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
EchoAlloc(uv_handle_t * handle,size_t suggestedSize,uv_buf_t * buf)233 void 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