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