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
AfterRead(uv_stream_t * handle,ssize_t nread,const uv_buf_t * buf)153 void NetServer::AfterRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
154 {
155 if (handle == nullptr) {
156 HILOG_ERROR("handle is null");
157 return;
158 }
159
160 if (buf == nullptr) {
161 HILOG_ERROR("buf is null");
162 return;
163 }
164
165 NetServer* that = static_cast<NetServer*>(handle->data);
166 WriteReq* wr = nullptr;
167 uv_shutdown_t* sreq = nullptr;
168
169 if (nread < 0) {
170 free(buf->base);
171 sreq = (uv_shutdown_t*)malloc(sizeof(*sreq));
172 if (sreq == nullptr) {
173 HILOG_ERROR("sreq is null");
174 return;
175 }
176 sreq->data = that;
177 uv_shutdown(sreq, handle, AfterShutdown);
178 return;
179 }
180
181 if (nread == 0) {
182 free(buf->base);
183 return;
184 }
185
186 if (!that->serverClosed_) {
187 for (int i = 0; i < nread; i++) {
188 if (buf->base[i] == 'Q') {
189 if (i + 1 < nread && buf->base[i + 1] == 'S') {
190 free(buf->base);
191 uv_close((uv_handle_t*)handle, OnClose);
192 return;
193 } else {
194 uv_close((uv_handle_t*)&that->tcpServer_, OnServerClose);
195 that->serverClosed_ = 1;
196 return;
197 }
198 }
199 }
200 }
201
202 that->Emit("read", nullptr);
203
204 wr = static_cast<WriteReq*>(malloc(sizeof(WriteReq)));
205 if (wr == nullptr) {
206 HILOG_ERROR("wr is null");
207 free(buf->base);
208 return;
209 }
210
211 wr->buf = uv_buf_init(buf->base, nread);
212
213 wr->req.data = that;
214
215 if (uv_write(&wr->req, handle, &wr->buf, 1, AfterWrite) != 0) {
216 that->Emit("error", nullptr);
217 }
218 }
219
AfterShutdown(uv_shutdown_t * req,int status)220 void NetServer::AfterShutdown(uv_shutdown_t* req, int status)
221 {
222 if (req == nullptr) {
223 HILOG_ERROR("req is null");
224 return;
225 }
226
227 uv_close((uv_handle_t*)req->handle, OnClose);
228 free(req);
229 }
230
EchoAlloc(uv_handle_t * handle,size_t suggestedSize,uv_buf_t * buf)231 void NetServer::EchoAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf)
232 {
233 if (handle == nullptr) {
234 HILOG_ERROR("handle is null");
235 return;
236 }
237
238 if (buf == nullptr) {
239 HILOG_ERROR("buf is null");
240 return;
241 }
242
243 if (suggestedSize == 0) {
244 HILOG_ERROR("suggestedSize = 0");
245 return;
246 }
247
248 buf->base = (char*)malloc(suggestedSize);
249 if (buf->base != nullptr) {
250 HILOG_ERROR("buf->base is null");
251 return;
252 }
253
254 buf->len = suggestedSize;
255 }
256