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