• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "socket_module.h"
17 
18 #include <cstdint>
19 #include <unistd.h>
20 #include <initializer_list>
21 #include <new>
22 #include <utility>
23 
24 #include "bind_context.h"
25 #include "common_context.h"
26 #include "connect_context.h"
27 #include "context_key.h"
28 #include "event_list.h"
29 #include "napi/native_api.h"
30 #include "napi/native_common.h"
31 #include "net_address.h"
32 #include "event_manager.h"
33 #include "netstack_common_utils.h"
34 #include "netstack_log.h"
35 #include "module_template.h"
36 #include "napi_utils.h"
37 #include "node_api.h"
38 #include "socket_async_work.h"
39 #include "socket_exec.h"
40 #include "tcp_extra_context.h"
41 #include "tcp_send_context.h"
42 #include "tlssocket_module.h"
43 #include "udp_extra_context.h"
44 #include "udp_send_context.h"
45 
46 static constexpr const char *SOCKET_MODULE_NAME = "net.socket";
47 
48 static const char *UDP_BIND_NAME = "UdpBind";
49 static const char *UDP_SEND_NAME = "UdpSend";
50 static const char *UDP_CLOSE_NAME = "UdpClose";
51 static const char *UDP_GET_STATE = "UdpGetState";
52 static const char *UDP_SET_EXTRA_OPTIONS_NAME = "UdpSetExtraOptions";
53 
54 static const char *TCP_BIND_NAME = "TcpBind";
55 static const char *TCP_CONNECT_NAME = "TcpConnect";
56 static const char *TCP_SEND_NAME = "TcpSend";
57 static const char *TCP_CLOSE_NAME = "TcpClose";
58 static const char *TCP_GET_STATE = "TcpGetState";
59 static const char *TCP_GET_REMOTE_ADDRESS = "TcpGetRemoteAddress";
60 static const char *TCP_SET_EXTRA_OPTIONS_NAME = "TcpSetExtraOptions";
61 
62 static constexpr const char *KEY_SOCKET_FD = "socketFd";
63 
64 #define SOCKET_INTERFACE(Context, executor, callback, work, name) \
65     ModuleTemplate::Interface<Context>(env, info, name, work, SocketAsyncWork::executor, SocketAsyncWork::callback)
66 
67 namespace OHOS::NetStack {
Finalize(napi_env,void * data,void *)68 void Finalize(napi_env, void *data, void *)
69 {
70     NETSTACK_LOGI("socket handle is finalized");
71     auto manager = static_cast<EventManager *>(data);
72     if (manager != nullptr) {
73         manager->SetInvalid();
74         int sock = static_cast<int>(reinterpret_cast<uint64_t>(manager->GetData()));
75         if (sock != 0) {
76             close(sock);
77         }
78     }
79 }
80 
SetSocket(napi_env env,napi_value thisVal,BindContext * context,int sock)81 static bool SetSocket(napi_env env, napi_value thisVal, BindContext *context, int sock)
82 {
83     if (sock < 0) {
84         napi_value error = NapiUtils::CreateObject(env);
85         if (NapiUtils::GetValueType(env, error) != napi_object) {
86             return false;
87         }
88         NapiUtils::SetUint32Property(env, error, KEY_ERROR_CODE, errno);
89         context->Emit(EVENT_ERROR, std::make_pair(NapiUtils::GetUndefined(env), error));
90         return false;
91     }
92 
93     EventManager *manager = nullptr;
94     if (napi_unwrap(env, thisVal, reinterpret_cast<void **>(&manager)) != napi_ok || manager == nullptr) {
95         return false;
96     }
97 
98     manager->SetData(reinterpret_cast<void *>(sock));
99     NapiUtils::SetInt32Property(env, thisVal, KEY_SOCKET_FD, sock);
100     return true;
101 }
102 
MakeTcpSocket(napi_env env,napi_value thisVal,BindContext * context)103 static bool MakeTcpSocket(napi_env env, napi_value thisVal, BindContext *context)
104 {
105     if (!context->IsParseOK()) {
106         return false;
107     }
108     if (!CommonUtils::HasInternetPermission()) {
109         context->SetPermissionDenied(true);
110         return false;
111     }
112     int sock = SocketExec::MakeTcpSocket(context->address_.GetSaFamily());
113     if (!SetSocket(env, thisVal, context, sock)) {
114         return false;
115     }
116     context->SetExecOK(true);
117     return true;
118 }
119 
MakeUdpSocket(napi_env env,napi_value thisVal,BindContext * context)120 static bool MakeUdpSocket(napi_env env, napi_value thisVal, BindContext *context)
121 {
122     if (!context->IsParseOK()) {
123         return false;
124     }
125     if (!CommonUtils::HasInternetPermission()) {
126         context->SetPermissionDenied(true);
127         return false;
128     }
129     int sock = SocketExec::MakeUdpSocket(context->address_.GetSaFamily());
130     if (!SetSocket(env, thisVal, context, sock)) {
131         return false;
132     }
133     context->SetExecOK(true);
134     return true;
135 }
136 
InitSocketModule(napi_env env,napi_value exports)137 napi_value SocketModuleExports::InitSocketModule(napi_env env, napi_value exports)
138 {
139     TLSSocketModuleExports::InitTLSSocketModule(env, exports);
140     DefineUDPSocketClass(env, exports);
141     DefineTCPSocketClass(env, exports);
142     InitSocketProperties(env, exports);
143 
144     return exports;
145 }
146 
ConstructUDPSocketInstance(napi_env env,napi_callback_info info)147 napi_value SocketModuleExports::ConstructUDPSocketInstance(napi_env env, napi_callback_info info)
148 {
149     return ModuleTemplate::NewInstance(env, info, INTERFACE_UDP_SOCKET, Finalize);
150 }
151 
DefineUDPSocketClass(napi_env env,napi_value exports)152 void SocketModuleExports::DefineUDPSocketClass(napi_env env, napi_value exports)
153 {
154     std::initializer_list<napi_property_descriptor> properties = {
155         DECLARE_NAPI_FUNCTION(UDPSocket::FUNCTION_BIND, UDPSocket::Bind),
156         DECLARE_NAPI_FUNCTION(UDPSocket::FUNCTION_SEND, UDPSocket::Send),
157         DECLARE_NAPI_FUNCTION(UDPSocket::FUNCTION_CLOSE, UDPSocket::Close),
158         DECLARE_NAPI_FUNCTION(UDPSocket::FUNCTION_GET_STATE, UDPSocket::GetState),
159         DECLARE_NAPI_FUNCTION(UDPSocket::FUNCTION_SET_EXTRA_OPTIONS, UDPSocket::SetExtraOptions),
160         DECLARE_NAPI_FUNCTION(UDPSocket::FUNCTION_ON, UDPSocket::On),
161         DECLARE_NAPI_FUNCTION(UDPSocket::FUNCTION_OFF, UDPSocket::Off),
162     };
163     ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_UDP_SOCKET);
164 }
165 
ConstructTCPSocketInstance(napi_env env,napi_callback_info info)166 napi_value SocketModuleExports::ConstructTCPSocketInstance(napi_env env, napi_callback_info info)
167 {
168     return ModuleTemplate::NewInstance(env, info, INTERFACE_TCP_SOCKET, Finalize);
169 }
170 
DefineTCPSocketClass(napi_env env,napi_value exports)171 void SocketModuleExports::DefineTCPSocketClass(napi_env env, napi_value exports)
172 {
173     std::initializer_list<napi_property_descriptor> properties = {
174         DECLARE_NAPI_FUNCTION(TCPSocket::FUNCTION_BIND, TCPSocket::Bind),
175         DECLARE_NAPI_FUNCTION(TCPSocket::FUNCTION_CONNECT, TCPSocket::Connect),
176         DECLARE_NAPI_FUNCTION(TCPSocket::FUNCTION_SEND, TCPSocket::Send),
177         DECLARE_NAPI_FUNCTION(TCPSocket::FUNCTION_CLOSE, TCPSocket::Close),
178         DECLARE_NAPI_FUNCTION(TCPSocket::FUNCTION_GET_REMOTE_ADDRESS, TCPSocket::GetRemoteAddress),
179         DECLARE_NAPI_FUNCTION(TCPSocket::FUNCTION_GET_STATE, TCPSocket::GetState),
180         DECLARE_NAPI_FUNCTION(TCPSocket::FUNCTION_SET_EXTRA_OPTIONS, TCPSocket::SetExtraOptions),
181         DECLARE_NAPI_FUNCTION(TCPSocket::FUNCTION_ON, TCPSocket::On),
182         DECLARE_NAPI_FUNCTION(TCPSocket::FUNCTION_OFF, TCPSocket::Off),
183     };
184     ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_TCP_SOCKET);
185 }
186 
InitSocketProperties(napi_env env,napi_value exports)187 void SocketModuleExports::InitSocketProperties(napi_env env, napi_value exports)
188 {
189     std::initializer_list<napi_property_descriptor> properties = {
190         DECLARE_NAPI_FUNCTION(FUNCTION_CONSTRUCTOR_UDP_SOCKET_INSTANCE, ConstructUDPSocketInstance),
191         DECLARE_NAPI_FUNCTION(FUNCTION_CONSTRUCTOR_TCP_SOCKET_INSTANCE, ConstructTCPSocketInstance),
192     };
193     NapiUtils::DefineProperties(env, exports, properties);
194 }
195 
196 /* udp async works */
Bind(napi_env env,napi_callback_info info)197 napi_value SocketModuleExports::UDPSocket::Bind(napi_env env, napi_callback_info info)
198 {
199     return SOCKET_INTERFACE(BindContext, ExecUdpBind, BindCallback, MakeUdpSocket, UDP_BIND_NAME);
200 }
201 
Send(napi_env env,napi_callback_info info)202 napi_value SocketModuleExports::UDPSocket::Send(napi_env env, napi_callback_info info)
203 {
204     return SOCKET_INTERFACE(UdpSendContext, ExecUdpSend, UdpSendCallback, nullptr, UDP_SEND_NAME);
205 }
206 
Close(napi_env env,napi_callback_info info)207 napi_value SocketModuleExports::UDPSocket::Close(napi_env env, napi_callback_info info)
208 {
209     return SOCKET_INTERFACE(CloseContext, ExecClose, CloseCallback, nullptr, UDP_CLOSE_NAME);
210 }
211 
GetState(napi_env env,napi_callback_info info)212 napi_value SocketModuleExports::UDPSocket::GetState(napi_env env, napi_callback_info info)
213 {
214     return SOCKET_INTERFACE(GetStateContext, ExecGetState, GetStateCallback, nullptr, UDP_GET_STATE);
215 }
216 
SetExtraOptions(napi_env env,napi_callback_info info)217 napi_value SocketModuleExports::UDPSocket::SetExtraOptions(napi_env env, napi_callback_info info)
218 {
219     return SOCKET_INTERFACE(UdpSetExtraOptionsContext, ExecUdpSetExtraOptions, UdpSetExtraOptionsCallback, nullptr,
220                             UDP_SET_EXTRA_OPTIONS_NAME);
221 }
222 
On(napi_env env,napi_callback_info info)223 napi_value SocketModuleExports::UDPSocket::On(napi_env env, napi_callback_info info)
224 {
225     return ModuleTemplate::On(env, info, {EVENT_MESSAGE, EVENT_LISTENING, EVENT_ERROR, EVENT_CLOSE}, false);
226 }
227 
Off(napi_env env,napi_callback_info info)228 napi_value SocketModuleExports::UDPSocket::Off(napi_env env, napi_callback_info info)
229 {
230     return ModuleTemplate::Off(env, info, {EVENT_MESSAGE, EVENT_LISTENING, EVENT_ERROR, EVENT_CLOSE});
231 }
232 
233 /* tcp async works */
Bind(napi_env env,napi_callback_info info)234 napi_value SocketModuleExports::TCPSocket::Bind(napi_env env, napi_callback_info info)
235 {
236     return SOCKET_INTERFACE(BindContext, ExecTcpBind, BindCallback, MakeTcpSocket, TCP_BIND_NAME);
237 }
238 
Connect(napi_env env,napi_callback_info info)239 napi_value SocketModuleExports::TCPSocket::Connect(napi_env env, napi_callback_info info)
240 {
241     return SOCKET_INTERFACE(ConnectContext, ExecConnect, ConnectCallback, nullptr, TCP_CONNECT_NAME);
242 }
243 
Send(napi_env env,napi_callback_info info)244 napi_value SocketModuleExports::TCPSocket::Send(napi_env env, napi_callback_info info)
245 {
246     return SOCKET_INTERFACE(TcpSendContext, ExecTcpSend, TcpSendCallback, nullptr, TCP_SEND_NAME);
247 }
248 
Close(napi_env env,napi_callback_info info)249 napi_value SocketModuleExports::TCPSocket::Close(napi_env env, napi_callback_info info)
250 {
251     return SOCKET_INTERFACE(CloseContext, ExecClose, CloseCallback, nullptr, TCP_CLOSE_NAME);
252 }
253 
GetRemoteAddress(napi_env env,napi_callback_info info)254 napi_value SocketModuleExports::TCPSocket::GetRemoteAddress(napi_env env, napi_callback_info info)
255 {
256     return SOCKET_INTERFACE(GetRemoteAddressContext, ExecGetRemoteAddress, GetRemoteAddressCallback, nullptr,
257                             TCP_GET_REMOTE_ADDRESS);
258 }
259 
GetState(napi_env env,napi_callback_info info)260 napi_value SocketModuleExports::TCPSocket::GetState(napi_env env, napi_callback_info info)
261 {
262     return SOCKET_INTERFACE(GetStateContext, ExecGetState, GetStateCallback, nullptr, TCP_GET_STATE);
263 }
264 
SetExtraOptions(napi_env env,napi_callback_info info)265 napi_value SocketModuleExports::TCPSocket::SetExtraOptions(napi_env env, napi_callback_info info)
266 {
267     return SOCKET_INTERFACE(TcpSetExtraOptionsContext, ExecTcpSetExtraOptions, TcpSetExtraOptionsCallback, nullptr,
268                             TCP_SET_EXTRA_OPTIONS_NAME);
269 }
270 
On(napi_env env,napi_callback_info info)271 napi_value SocketModuleExports::TCPSocket::On(napi_env env, napi_callback_info info)
272 {
273     return ModuleTemplate::On(env, info, {EVENT_MESSAGE, EVENT_CONNECT, EVENT_ERROR, EVENT_CLOSE}, false);
274 }
275 
Off(napi_env env,napi_callback_info info)276 napi_value SocketModuleExports::TCPSocket::Off(napi_env env, napi_callback_info info)
277 {
278     return ModuleTemplate::Off(env, info, {EVENT_MESSAGE, EVENT_CONNECT, EVENT_ERROR, EVENT_CLOSE});
279 }
280 
281 static napi_module g_socketModule = {
282     .nm_version = 1,
283     .nm_flags = 0,
284     .nm_filename = nullptr,
285     .nm_register_func = SocketModuleExports::InitSocketModule,
286     .nm_modname = SOCKET_MODULE_NAME,
287     .nm_priv = nullptr,
288     .reserved = {nullptr},
289 };
290 /*
291  * Module register function
292  */
RegisterSocketModule(void)293 extern "C" __attribute__((constructor)) void RegisterSocketModule(void)
294 {
295     napi_module_register(&g_socketModule);
296 }
297 } // namespace OHOS::NetStack
298