1 /*
2 * Copyright (c) 2025 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 "softbus_mintp_socket.h"
17
18 #include "conn_log.h"
19 #include "softbus_adapter_errcode.h"
20 #include "softbus_conn_common.h"
21 #include "softbus_error_code.h"
22 #include "softbus_socket.h"
23 #include "softbus_tcp_socket.h"
24 #include "softbus_utils.h"
25
26 #define IPPROTO_MINTP 200
27 #define SOL_MTP 300
28 #define MTP_ADDR_TYPE_MAC 0
29 #define MTP_ADDR_TYPE_IPV4 1
30 #define MTP_ADDR_TYPE_IPV6 2
31 #define MTP_SOCKET_MSG_SIZE 8000
32 #define MTP_TOS 1
33 #define MTP_KEEPIDLE 2
34 #define MTP_MAX_MSG_SIZE 3
35 #define MTP_TRANS_TYPE 10
36 #define MTP_TIME_SYNC 11
37 #define USER_TIMEOUT_MS (15 * 1000) // 15s
38
39 struct MtpMacAddr {
40 unsigned char addr[6];
41 unsigned char pad[6]; // the inet framework need size of addr >= 16
42 };
43
44 struct MtpIpAddr {
45 unsigned char addr;
46 unsigned char pad[8]; // the inet framework need size of addr >= 16
47 };
48
49 struct MtpIp6Addr {
50 unsigned int flowinfo; // IPv6 flow information
51 unsigned char addr[16]; // IPv6 address
52 unsigned int scope; // IPv6 address scope
53 };
54
55 struct SockAddrMtp {
56 unsigned short saFamily;
57 unsigned char port;
58 unsigned char type;
59 union {
60 struct MtpMacAddr mac;
61 struct MtpIpAddr ip;
62 struct MtpIp6Addr ip6;
63 };
64 };
65
SetMintpSocketMsgSize(int32_t fd)66 int32_t SetMintpSocketMsgSize(int32_t fd)
67 {
68 int32_t msgSize = MTP_SOCKET_MSG_SIZE;
69 int32_t rc = SoftBusSocketSetOpt(fd, SOL_MTP, MTP_MAX_MSG_SIZE, &msgSize, sizeof(msgSize));
70 if (rc != SOFTBUS_ADAPTER_OK) {
71 CONN_LOGE(CONN_COMMON, "set MTP_MAX_MSG_SIZE fail. rc=%{public}d, errno=%{public}d", rc, errno);
72 return rc;
73 }
74 return SOFTBUS_OK;
75 }
76
SetMintpSocketTos(int32_t fd,uint32_t tos)77 int32_t SetMintpSocketTos(int32_t fd, uint32_t tos)
78 {
79 int32_t rc = SoftBusSocketSetOpt(fd, SOL_MTP, MTP_TOS, &tos, sizeof(tos));
80 if (rc != SOFTBUS_ADAPTER_OK) {
81 CONN_LOGE(CONN_COMMON, "set mintp tos fail. fd=%{public}d", fd);
82 return rc;
83 }
84 return SOFTBUS_OK;
85 }
86
SetMintpSocketTransType(int32_t fd,uint32_t transType)87 int32_t SetMintpSocketTransType(int32_t fd, uint32_t transType)
88 {
89 int32_t rc = SoftBusSocketSetOpt(fd, SOL_MTP, MTP_TRANS_TYPE, &transType, sizeof(transType));
90 if (rc != SOFTBUS_ADAPTER_OK) {
91 CONN_LOGE(CONN_COMMON, "set mintp trans type fail. fd=%{public}d", fd);
92 return rc;
93 }
94 return SOFTBUS_OK;
95 }
96
SetMintpSocketKeepAlive(int32_t fd,int32_t timeoutMs)97 int32_t SetMintpSocketKeepAlive(int32_t fd, int32_t timeoutMs)
98 {
99 if (timeoutMs <= 0) {
100 CONN_LOGE(CONN_COMMON, "invalid param.");
101 return SOFTBUS_INVALID_PARAM;
102 }
103 int32_t rc = SoftBusSocketSetOpt(fd, SOL_MTP, MTP_KEEPIDLE, &timeoutMs, sizeof(timeoutMs));
104 if (rc != SOFTBUS_ADAPTER_OK) {
105 CONN_LOGE(CONN_COMMON, "set mintp keep idle fail. fd=%{public}d", fd);
106 return rc;
107 }
108 return SOFTBUS_OK;
109 }
110
SetMintpSocketTimeSync(int32_t fd,MintpTimeSync * timeSync)111 int32_t SetMintpSocketTimeSync(int32_t fd, MintpTimeSync *timeSync)
112 {
113 if (timeSync == NULL) {
114 CONN_LOGE(CONN_COMMON, "invalid param.");
115 return SOFTBUS_INVALID_PARAM;
116 }
117 int32_t rc = SoftBusSocketSetOpt(fd, SOL_MTP, MTP_TIME_SYNC, timeSync, sizeof(MintpTimeSync));
118 if (rc != SOFTBUS_ADAPTER_OK) {
119 CONN_LOGE(CONN_COMMON, "set mintp time sync fail. fd=%{public}d", fd);
120 return rc;
121 }
122 return SOFTBUS_OK;
123 }
124
SetMintpOption(int32_t fd)125 static void SetMintpOption(int32_t fd)
126 {
127 SetMintpSocketKeepAlive(fd, USER_TIMEOUT_MS);
128 SetMintpSocketMsgSize(fd);
129 SetMintpSocketTransType(fd, 1);
130 }
131
BindMintp(int32_t domain,int32_t fd,const char * localIp)132 static int32_t BindMintp(int32_t domain, int32_t fd, const char *localIp)
133 {
134 bool isIpv4 = domain == SOFTBUS_AF_INET;
135 struct SockAddrMtp tmpAddr;
136 uint32_t addrLen;
137 (void)memset_s(&tmpAddr, sizeof(tmpAddr), 0, sizeof(tmpAddr));
138 tmpAddr.saFamily = domain;
139 tmpAddr.port = 0;
140 tmpAddr.type = isIpv4 ? MTP_ADDR_TYPE_IPV4 : MTP_ADDR_TYPE_IPV6;
141 if (isIpv4) {
142 int32_t rc = SoftBusInetPtoN(SOFTBUS_AF_INET, localIp, &tmpAddr.ip.addr);
143 if (rc != SOFTBUS_ADAPTER_OK) {
144 CONN_LOGE(CONN_COMMON, "ipv4 SoftBusInetPtoN fail. rc=%{public}d", rc);
145 return SOFTBUS_SOCKET_ADDR_ERR;
146 }
147 } else {
148 int32_t rc = SoftBusInetPtoN(SOFTBUS_AF_INET6, localIp, &tmpAddr.ip6.addr);
149 if (rc != SOFTBUS_ADAPTER_OK) {
150 CONN_LOGE(CONN_COMMON, "ipv6 SoftBusInetPtoN fail. rc=%{public}d", rc);
151 return SOFTBUS_SOCKET_ADDR_ERR;
152 }
153 }
154 addrLen = isIpv4 ? sizeof(SoftBusSockAddrIn) : sizeof(tmpAddr);
155 int32_t ret = bind(fd, (struct sockaddr *)&tmpAddr, addrLen);
156 if (ret != 0) {
157 CONN_LOGE(CONN_COMMON, "bind mintp fail. ret=%{public}d, errno=%{public}d(%{public}s)", ret, errno,
158 strerror(errno));
159 return SOFTBUS_SOCKET_BIND_ERR;
160 }
161 return SOFTBUS_OK;
162 }
163
OpenMintpServerSocket(const LocalListenerInfo * option)164 static int32_t OpenMintpServerSocket(const LocalListenerInfo *option)
165 {
166 CONN_CHECK_AND_RETURN_RET_LOGE(
167 option != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid param, option is null.");
168 CONN_CHECK_AND_RETURN_RET_LOGE(
169 option->type == CONNECT_HML, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid connect type.");
170 CONN_CHECK_AND_RETURN_RET_LOGE(option->socketOption.port >= 0, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid port.");
171
172 char animizedIp[IP_LEN] = { 0 };
173 ConvertAnonymizeIpAddress(animizedIp, IP_LEN, option->socketOption.addr, strlen(option->socketOption.addr));
174 CONN_LOGI(CONN_COMMON, "open mintp server socket, ip=%{public}s, port=%{public}d.", animizedIp,
175 option->socketOption.port);
176
177 int32_t fd = -1;
178 int32_t domain = GetDomainByAddr(option->socketOption.addr);
179 int32_t ret = SoftBusSocketCreate(domain, SOFTBUS_SOCK_DGRAM | SOFTBUS_SOCK_NONBLOCK, IPPROTO_MINTP, &fd);
180 if (ret != SOFTBUS_ADAPTER_OK) {
181 CONN_LOGE(CONN_COMMON, "create mintp socket fail. ret=%{public}d", ret);
182 return ret;
183 }
184 ret = BindMintp(domain, fd, option->socketOption.addr);
185 if (ret != SOFTBUS_OK) {
186 CONN_LOGE(CONN_COMMON, "bind mintp fail. ret=%{public}d", ret);
187 ConnShutdownSocket(fd);
188 return ret;
189 }
190 SetMintpOption(fd);
191 CONN_LOGI(CONN_COMMON, "open mintp server socket success, fd=%{public}d.", fd);
192 return fd;
193 }
194
MintpSocketConnect(int32_t fd,int32_t domain,const ConnectOption * option)195 static int32_t MintpSocketConnect(int32_t fd, int32_t domain, const ConnectOption *option)
196 {
197 struct SockAddrMtp tmpAddr;
198 tmpAddr.saFamily = domain;
199 tmpAddr.port = SoftBusHtoNs((uint16_t)(option->socketOption.port));
200 tmpAddr.type = domain == SOFTBUS_AF_INET ? MTP_ADDR_TYPE_IPV4 : MTP_ADDR_TYPE_IPV6;
201 if (domain == SOFTBUS_AF_INET) {
202 int32_t rc = SoftBusInetPtoN(SOFTBUS_AF_INET, option->socketOption.addr, &tmpAddr.ip.addr);
203 if (rc != SOFTBUS_ADAPTER_OK) {
204 CONN_LOGE(CONN_COMMON, "ipv4 SoftBusInetPtoN fail. rc=%{public}d", rc);
205 return rc;
206 }
207 } else {
208 int32_t rc = SoftBusInetPtoN(SOFTBUS_AF_INET6, option->socketOption.addr, &tmpAddr.ip6.addr);
209 if (rc != SOFTBUS_ADAPTER_OK) {
210 CONN_LOGE(CONN_COMMON, "ipv6 SoftBusInetPtoN fail. rc=%{public}d", rc);
211 return rc;
212 }
213 }
214 int32_t addrLen = domain == SOFTBUS_AF_INET ? sizeof(SoftBusSockAddrIn) : sizeof(tmpAddr);
215 return SOFTBUS_TEMP_FAILURE_RETRY(SoftBusSocketConnect(fd, (SoftBusSockAddr *)&tmpAddr, addrLen));
216 }
217
OpenMintpClientSocket(const ConnectOption * option,const char * myIp,bool isNonBlock)218 static int32_t OpenMintpClientSocket(const ConnectOption *option, const char *myIp, bool isNonBlock)
219 {
220 CONN_CHECK_AND_RETURN_RET_LOGE(
221 option != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid param, option is null.");
222 CONN_CHECK_AND_RETURN_RET_LOGE(myIp != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid param, myIp is null.");
223 CONN_CHECK_AND_RETURN_RET_LOGE(option->type == CONNECT_HML, SOFTBUS_INVALID_PARAM, CONN_COMMON,
224 "invalid param, unsupported connect type, type=%{public}d.", option->type);
225 CONN_CHECK_AND_RETURN_RET_LOGE(
226 option->socketOption.port > 0, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid param, port is invalid.");
227 CONN_CHECK_AND_RETURN_RET_LOGE(
228 option->socketOption.addr[0] != '\0', SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid param, addr is invalid.");
229
230 char animizedIp[IP_LEN] = { 0 };
231 ConvertAnonymizeIpAddress(animizedIp, IP_LEN, option->socketOption.addr, strlen(option->socketOption.addr));
232 CONN_LOGI(CONN_COMMON, "open mintp client socket, server ip=%{public}s, server port=%{public}d.", animizedIp,
233 option->socketOption.port);
234 int32_t fd = -1;
235 int32_t domain = GetDomainByAddr(option->socketOption.addr);
236 int32_t ret = SoftBusSocketCreate(domain, SOFTBUS_SOCK_DGRAM, IPPROTO_MINTP, &fd);
237 if (ret != SOFTBUS_OK) {
238 CONN_LOGE(CONN_COMMON, "create mintp socket fail. serverIp=%{public}s, serverPort=%{public}d, ret=%{public}d",
239 animizedIp, option->socketOption.port, ret);
240 return ret;
241 }
242 if (isNonBlock && ConnToggleNonBlockMode(fd, true) != SOFTBUS_OK) {
243 CONN_LOGE(CONN_COMMON, "set nonblock mode fail. serverIp=%{public}s, serverPort=%{public}d", animizedIp,
244 option->socketOption.port);
245 ConnShutdownSocket(fd);
246 return SOFTBUS_SOCKET_ERR;
247 }
248 ret = BindMintp(domain, fd, myIp);
249 if (ret != SOFTBUS_OK) {
250 CONN_LOGE(CONN_COMMON, "bind mintp fail. ret=%{public}d", ret);
251 ConnShutdownSocket(fd);
252 return ret;
253 }
254 SetMintpOption(fd);
255 ret = MintpSocketConnect(fd, domain, option);
256 if ((ret != SOFTBUS_ADAPTER_OK) && (ret != SOFTBUS_ADAPTER_SOCKET_EINPROGRESS) &&
257 (ret != SOFTBUS_ADAPTER_SOCKET_EAGAIN)) {
258 CONN_LOGE(CONN_COMMON, "connect mintp fail. serverIp=%{public}s, serverPort=%{public}d, ret=%{public}d",
259 animizedIp, option->socketOption.port, ret);
260 ConnShutdownSocket(fd);
261 return SOFTBUS_SOCKET_ERR;
262 }
263 CONN_LOGI(CONN_COMMON, "mintp connect success, fd=%{public}d, serverIp=%{public}s, serverPort=%{public}d.", fd,
264 animizedIp, option->socketOption.port);
265 return fd;
266 }
267
GetMintpSockPort(int32_t fd)268 int32_t GetMintpSockPort(int32_t fd)
269 {
270 SoftBusSockAddr addr;
271 int32_t rc = SoftBusSocketGetLocalName(fd, &addr);
272 if (rc != SOFTBUS_ADAPTER_OK) {
273 CONN_LOGE(CONN_COMMON, "get mintp sock port fail. rc=%{public}d, fd=%{public}d", rc, fd);
274 return rc;
275 }
276 if (addr.saFamily == SOFTBUS_AF_INET6) {
277 return SoftBusNtoHs(((SoftBusSockAddrIn6 *)&addr)->sin6Port);
278 }
279 return SoftBusNtoHs(((SoftBusSockAddrIn *)&addr)->sinPort);
280 }
281
AcceptMintpClient(int32_t fd,ConnectOption * clientAddr,int32_t * cfd)282 static int32_t AcceptMintpClient(int32_t fd, ConnectOption *clientAddr, int32_t *cfd)
283 {
284 CONN_CHECK_AND_RETURN_RET_LOGW(
285 clientAddr != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid param, clientAddr is null");
286 CONN_CHECK_AND_RETURN_RET_LOGW(cfd != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid param, cfd is null");
287 struct SockAddrMtp mtpClientAddr;
288 socklen_t addrLen = sizeof(mtpClientAddr);
289 (void)memset_s(&mtpClientAddr, addrLen, 0, addrLen);
290 int32_t ret = SOFTBUS_TEMP_FAILURE_RETRY(SoftBusSocketAccept(fd, (SoftBusSockAddr *)&mtpClientAddr, cfd));
291 if (ret != SOFTBUS_OK) {
292 CONN_LOGE(CONN_COMMON, "accept mintp client fail. ret=%{public}d", ret);
293 return ret;
294 }
295 clientAddr->type = CONNECT_HML;
296 clientAddr->socketOption.port = GetMintpSockPort(*cfd);
297 clientAddr->socketOption.protocol = LNN_PROTOCOL_MINTP;
298 char mtpMac[BT_MAC_LEN] = { 0 };
299 ret = ConvertBtMacToStr(mtpMac, sizeof(mtpMac), mtpClientAddr.mac.addr, sizeof(mtpClientAddr.mac.addr));
300 if (ret != SOFTBUS_OK) {
301 CONN_LOGE(CONN_COMMON, "convert mintp mac to string fail. ret=%{public}d", ret);
302 return ret;
303 }
304 ret = strcpy_s(clientAddr->socketOption.addr, sizeof(clientAddr->socketOption.addr), mtpMac);
305 if (ret != EOK) {
306 CONN_LOGE(CONN_COMMON, "copy mintp mac to clientAddr fail. ret=%{public}d", ret);
307 return SOFTBUS_ERR;
308 }
309 CONN_LOGI(CONN_COMMON, "accept mintp client success, cfd=%{public}d", *cfd);
310 return SOFTBUS_OK;
311 }
312
GetMintpProtocol(void)313 const SocketInterface *GetMintpProtocol(void)
314 {
315 static SocketInterface mintpSocketIntf = {
316 .name = "MINTP",
317 .type = LNN_PROTOCOL_MINTP,
318 .GetSockPort = GetMintpSockPort,
319 .OpenClientSocket = OpenMintpClientSocket,
320 .OpenServerSocket = OpenMintpServerSocket,
321 .AcceptClient = AcceptMintpClient,
322 };
323 return &mintpSocketIntf;
324 }
325