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
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 napi_get_uv_event_loop(env, &loop_);
27 tcpServer_ = { 0 };
28 tcpServer_.data = this;
29 serverClosed_ = false;
30 clients_ = nullptr;
31 }
32
~NetServer()33 NetServer::~NetServer() {}
34
Start(int port)35 int 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
Stop()65 void NetServer::Stop()
66 {
67 Emit("closed", nullptr);
68 uint32_t thisRefCount = 0;
69 napi_reference_unref(env_, thisVarRef_, &thisRefCount);
70 }
71
OnClose(uv_handle_t * peer)72 void 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
OnConnection(uv_stream_t * server,int status)84 void 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
OnServerClose(uv_handle_t * handle)113 void 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
AfterWrite(uv_write_t * req,int status)130 void 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
TakeDiffactionsByStatus(uv_stream_t * handle,ssize_t nread,const uv_buf_t * buf,NetServer * that)152 void 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
AfterRead(uv_stream_t * handle,ssize_t nread,const uv_buf_t * buf)200 void 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
AfterShutdown(uv_shutdown_t * req,int status)221 void 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
EchoAlloc(uv_handle_t * handle,size_t suggestedSize,uv_buf_t * buf)232 void 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