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