1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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_utils.h"
17 #include <arpa/inet.h>
18 #include <fcntl.h>
19 #include <iostream>
20 #include <netinet/tcp.h>
21 #include <unistd.h>
22 #include "common/const_def.h"
23 #include "common/media_log.h"
24
25 namespace OHOS {
26 namespace Sharing {
27 uint16_t SocketUtils::minPort_ = MIN_PORT;
28 uint16_t SocketUtils::maxPort_ = MAX_PORT;
29
CreateTcpServer(const char * ip,unsigned port,int32_t & fd)30 bool SocketUtils::CreateTcpServer(const char *ip, unsigned port, int32_t &fd)
31 {
32 SHARING_LOGD("trace.");
33 return CreateSocket(SOCK_STREAM, fd) && SetReuseAddr(fd, true) && SetNoDelay(fd, true) &&
34 BindSocket(fd, ip, port) && ListenSocket(fd);
35 }
36
GetAvailableUdpPortPair()37 uint16_t SocketUtils::GetAvailableUdpPortPair()
38 {
39 SHARING_LOGD("trace.");
40 static uint16_t gAvailablePort = minPort_;
41
42 SHARING_LOGD("current udp port: %{public}d.", gAvailablePort);
43 if (gAvailablePort >= maxPort_) {
44 gAvailablePort = minPort_;
45 }
46
47 uint16_t port = GetAvailableUdpPortPair(gAvailablePort, maxPort_);
48 if (port != 0) {
49 gAvailablePort = port + 2; // 2: pair port
50 return port;
51 }
52
53 port = GetAvailableUdpPortPair(minPort_, gAvailablePort);
54 if (port != 0) {
55 gAvailablePort = port + 2; // 2: pair port
56 }
57
58 return port;
59 }
60
GetAvailableUdpPortPair(uint16_t minPort,uint16_t maxPort)61 uint16_t SocketUtils::GetAvailableUdpPortPair(uint16_t minPort, uint16_t maxPort)
62 {
63 SHARING_LOGD("trace.");
64 if (minPort == maxPort) {
65 return 0;
66 }
67
68 uint16_t port = minPort;
69 bool portAvalaible = false;
70 while (!portAvalaible) {
71 if (port >= maxPort) {
72 port = 0;
73 portAvalaible = true;
74 } else if (IsUdpPortAvailable(port) && IsUdpPortAvailable(port + 1)) {
75 portAvalaible = true;
76 } else {
77 port += 2; // 2: pair port
78 }
79 }
80
81 return port;
82 }
83
IsUdpPortAvailable(uint16_t port)84 bool SocketUtils::IsUdpPortAvailable(uint16_t port)
85 {
86 SHARING_LOGD("trace.");
87 int32_t fd = -1;
88 auto ret = CreateSocket(SOCK_DGRAM, fd) && BindSocket(fd, "", port);
89 if (fd != -1) {
90 CloseSocket(fd);
91 }
92
93 return ret;
94 }
95
CreateTcpClient(const char * ip,unsigned port,int32_t & fd,int32_t & ret)96 bool SocketUtils::CreateTcpClient(const char *ip, unsigned port, int32_t &fd, int32_t &ret)
97 {
98 SHARING_LOGD("trace.");
99 return CreateSocket(SOCK_STREAM, fd) && ConnectSocket(fd, true, ip, port, ret);
100 }
101
CreateUdpSession(unsigned port,int32_t & fd)102 bool SocketUtils::CreateUdpSession(unsigned port, int32_t &fd)
103 {
104 SHARING_LOGD("trace.");
105 return CreateSocket(SOCK_DGRAM, fd) && SetRecvBuf(fd) && SetSendBuf(fd) && BindSocket(fd, "", port);
106 }
107
CreateSocket(int32_t socketType,int32_t & fd)108 bool SocketUtils::CreateSocket(int32_t socketType, int32_t &fd)
109 {
110 SHARING_LOGD("trace.");
111 fd = -1;
112 if (socketType != SOCK_STREAM && socketType != SOCK_DGRAM) {
113 SHARING_LOGE("type error: %{public}d!", socketType);
114 }
115
116 fd = socket(AF_INET, socketType, (socketType == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP));
117 if (fd < 0) {
118 SHARING_LOGE("error: %{public}s!", strerror(errno));
119 return false;
120 }
121 SHARING_LOGD("success fd: %{public}d.", fd);
122 return true;
123 }
124
BindSocket(int32_t fd,const std::string & host,uint16_t port)125 bool SocketUtils::BindSocket(int32_t fd, const std::string &host, uint16_t port)
126 {
127 SHARING_LOGD("trace.");
128 struct sockaddr_in addr = {};
129 addr.sin_family = AF_INET;
130 addr.sin_port = htons(port);
131 if (host == "" || host == "::") {
132 addr.sin_addr.s_addr = INADDR_ANY;
133 } else {
134 if (inet_pton(AF_INET, host.c_str(), &addr.sin_addr) <= 0) {
135 SHARING_LOGE("error: %{public}s!", strerror(errno));
136 return false;
137 }
138 }
139 if (::bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
140 SHARING_LOGE("error: %{public}s!", strerror(errno));
141 return false;
142 }
143
144 return true;
145 }
146
ListenSocket(int32_t fd,uint32_t backlog)147 bool SocketUtils::ListenSocket(int32_t fd, uint32_t backlog)
148 {
149 SHARING_LOGD("trace.");
150 if (::listen(fd, backlog) == -1) {
151 SHARING_LOGE("error: %{public}s!", strerror(errno));
152 return false;
153 }
154
155 return true;
156 }
157
ConnectSocket(int32_t fd,bool isAsync,const std::string & ip,uint16_t port,int32_t & ret)158 bool SocketUtils::ConnectSocket(int32_t fd, bool isAsync, const std::string &ip, uint16_t port, int32_t &ret)
159 {
160 SHARING_LOGD("trace.");
161 if (ip == "") {
162 SHARING_LOGE("ip null!");
163 return false;
164 }
165
166 struct sockaddr_in serverAddr = {};
167 serverAddr.sin_family = AF_INET;
168 serverAddr.sin_port = htons(port);
169 if (inet_pton(AF_INET, ip.c_str(), &serverAddr.sin_addr) <= 0) {
170 SHARING_LOGE("inet_pton ip error: %{public}s!", strerror(errno));
171 return false;
172 }
173
174 int32_t res = ::connect(fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
175 ret = res;
176 if (isAsync) {
177 if (res == 0) {
178 SHARING_LOGI("connect immediately.");
179 return true;
180 } else {
181 if (errno == EINPROGRESS) {
182 SHARING_LOGI("connecting.");
183 return SocketUtils::CheckAsyncConnect(fd);
184 } else {
185 return false;
186 }
187 }
188 } else {
189 if (res == 0) {
190 return true;
191 } else {
192 return false;
193 }
194 }
195 }
196
CheckAsyncConnect(int32_t fd)197 bool SocketUtils::CheckAsyncConnect(int32_t fd)
198 {
199 SHARING_LOGD("trace.");
200 struct timeval timeout;
201 timeout.tv_sec = 2; // 2: wait +2 second
202 timeout.tv_usec = 500 * 1000; // 500 * 1000: wait +0.5 second
203
204 fd_set fdr;
205 fd_set fdw;
206 FD_ZERO(&fdr);
207 FD_ZERO(&fdw);
208 FD_SET(fd, &fdr);
209 FD_SET(fd, &fdw);
210
211 int32_t rc = select(fd + 1, &fdr, &fdw, nullptr, &timeout);
212 if (rc == 1 && FD_ISSET(fd, &fdw)) {
213 SHARING_LOGI("async connect success\n");
214 return true;
215 }
216
217 if (rc == 0) {
218 SHARING_LOGE("async connect timeout.");
219 }
220
221 if ((rc < 0) || (rc == 2)) { // 2: select error
222 SHARING_LOGE("async connect error: %{public}s!", strerror(errno));
223 }
224
225 return false;
226 }
227
ShutDownSocket(int32_t fd)228 void SocketUtils::ShutDownSocket(int32_t fd)
229 {
230 SHARING_LOGD("trace.");
231 if (fd >= 0) {
232 SHARING_LOGD("shutdown fd: %{public}d.", fd);
233 shutdown(fd, SHUT_RDWR);
234 }
235 }
236
SetReuseAddr(int32_t fd,bool isReuse)237 bool SocketUtils::SetReuseAddr(int32_t fd, bool isReuse)
238 {
239 SHARING_LOGD("trace.");
240 int32_t on = isReuse ? 1 : 0;
241 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) {
242 SHARING_LOGE("error: %{public}s!", strerror(errno));
243 return false;
244 }
245
246 return true;
247 }
248
SetReusePort(int32_t fd,bool isReuse)249 bool SocketUtils::SetReusePort(int32_t fd, bool isReuse)
250 {
251 SHARING_LOGD("trace.");
252 int32_t on = isReuse ? 1 : 0;
253 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) != 0) {
254 SHARING_LOGE("error: %{public}s!", strerror(errno));
255 return false;
256 }
257
258 return true;
259 }
260
SetCloseWait(int32_t fd,int32_t second)261 bool SocketUtils::SetCloseWait(int32_t fd, int32_t second)
262 {
263 SHARING_LOGD("trace.");
264 linger sLinger;
265 sLinger.l_onoff = (second > 0);
266 sLinger.l_linger = second;
267 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &sLinger, sizeof(linger)) == -1) {
268 SHARING_LOGE("error: %{public}s!", strerror(errno));
269 return false;
270 }
271
272 return true;
273 }
274
SetCloExec(int32_t fd,bool isOn)275 bool SocketUtils::SetCloExec(int32_t fd, bool isOn)
276 {
277 SHARING_LOGD("trace.");
278
279 int32_t flags = fcntl(fd, F_GETFD);
280 if (flags == -1) {
281 SHARING_LOGE("fcntl error: %{public}s!", strerror(errno));
282 return false;
283 }
284
285 if (isOn) {
286 flags |= FD_CLOEXEC;
287 } else {
288 int32_t cloexec = FD_CLOEXEC;
289 flags &= ~cloexec;
290 }
291
292 if (fcntl(fd, F_SETFD, flags) == -1) {
293 SHARING_LOGE("error: %{public}s!", strerror(errno));
294 return false;
295 }
296
297 return true;
298 }
299
SetNoDelay(int32_t fd,bool isOn)300 bool SocketUtils::SetNoDelay(int32_t fd, bool isOn)
301 {
302 SHARING_LOGD("trace.");
303 int32_t on = isOn;
304 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) {
305 SHARING_LOGE("error: %{public}s!", strerror(errno));
306 return false;
307 }
308
309 return true;
310 }
311
SetKeepAlive(int32_t sockfd)312 void SocketUtils::SetKeepAlive(int32_t sockfd)
313 {
314 SHARING_LOGD("trace.");
315 int32_t on = 1;
316 setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, reinterpret_cast<char*>(&on), sizeof(on));
317 }
318
SetNonBlocking(int32_t fd,bool isNonBlock,uint32_t writeTimeout)319 bool SocketUtils::SetNonBlocking(int32_t fd, bool isNonBlock, uint32_t writeTimeout)
320 {
321 SHARING_LOGD("trace.");
322 int32_t flags = -1;
323 if (isNonBlock) {
324 flags = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
325 } else {
326 flags = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
327 if (writeTimeout > 0) {
328 struct timeval tv = {writeTimeout / 1000, (writeTimeout % 1000) * 1000};
329 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char*>(&tv), sizeof tv);
330 }
331 }
332
333 return (flags != -1) ? true : false;
334 }
335
SetSendBuf(int32_t fd,int32_t size)336 bool SocketUtils::SetSendBuf(int32_t fd, int32_t size)
337 {
338 SHARING_LOGD("trace.");
339 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) != 0) {
340 SHARING_LOGE("error: %{public}s!", strerror(errno));
341 return false;
342 }
343
344 return true;
345 }
346
SetRecvBuf(int32_t fd,int32_t size)347 bool SocketUtils::SetRecvBuf(int32_t fd, int32_t size)
348 {
349 SHARING_LOGD("trace.");
350 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != 0) {
351 SHARING_LOGE("error: %{public}s!", strerror(errno));
352 return false;
353 }
354
355 return true;
356 }
357
CloseSocket(int32_t fd)358 void SocketUtils::CloseSocket(int32_t fd)
359 {
360 SHARING_LOGD("trace.");
361 if (fd >= 0) {
362 SHARING_LOGD("close fd: %{public}d.", fd);
363 close(fd);
364 }
365 }
366
SendSocket(int32_t fd,const char * buf,int32_t len)367 int32_t SocketUtils::SendSocket(int32_t fd, const char *buf, int32_t len)
368 {
369 SHARING_LOGD("trace.");
370 if (fd < 0 || buf == nullptr || len == 0) {
371 return -1;
372 }
373 SHARING_LOGD("sendSocket: \r\n%{public}s.", buf);
374 int32_t bytes = 0;
375 bool sending = true;
376 while (sending) {
377 if (bytes >= len || bytes < 0) {
378 sending = false;
379 break;
380 }
381
382 int32_t retCode = send(fd, &buf[bytes], len - bytes, 0);
383 if ((retCode < 0) && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)) {
384 SHARING_LOGD("sendSocket: continue.");
385 continue;
386 } else if (retCode > 0) {
387 bytes += retCode;
388 if (bytes == len) {
389 sending = false;
390 break;
391 }
392 } else {
393 SHARING_LOGE("error: %{public}s!", strerror(errno));
394 bytes = 0;
395 sending = false;
396 break;
397 }
398 }
399
400 SHARING_LOGD("finish! fd: %{public}d size: %{public}d.", fd, bytes);
401 return bytes;
402 }
403
Sendto(int32_t fd,const char * buf,size_t len,const char * ip,int32_t nPort)404 int32_t SocketUtils::Sendto(int32_t fd, const char *buf, size_t len, const char *ip, int32_t nPort)
405 {
406 SHARING_LOGD("trace: \r\n%{public}s.", buf);
407 struct sockaddr_in addr = {};
408 addr.sin_family = AF_INET;
409 addr.sin_port = htons(nPort);
410 if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) {
411 SHARING_LOGE("inet_pton error: %{public}s!", strerror(errno));
412 return -1;
413 }
414 int32_t retCode = sendto(fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(addr));
415 if (retCode < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)) {
416 } else if (retCode > 0) {
417 } else {
418 SHARING_LOGE("sendto error: %{public}s!", strerror(errno));
419 retCode = 0;
420 }
421
422 return retCode;
423 }
424
ReadSocket(int32_t fd,char * buf,uint32_t len,int32_t & error)425 int32_t SocketUtils::ReadSocket(int32_t fd, char *buf, uint32_t len, int32_t &error)
426 {
427 SHARING_LOGD("trace.");
428 if (fd < 0 || buf == nullptr || len == 0) {
429 SHARING_LOGE("invalid param!");
430 return -1;
431 }
432
433 int32_t retCode = read(fd, buf, len);
434 error = errno;
435 if (retCode < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)) {
436 } else if (retCode > 0) {
437 } else {
438 SHARING_LOGE("error: %{public}s!", strerror(errno));
439 retCode = 0;
440 }
441
442 return retCode;
443 }
444
ReadSocket(int32_t fd,DataBuffer::Ptr buf,int32_t & error)445 int32_t SocketUtils::ReadSocket(int32_t fd, DataBuffer::Ptr buf, int32_t &error)
446 {
447 SHARING_LOGD("trace.");
448 if (fd < 0 || !buf) {
449 SHARING_LOGE("readSocket:invalid param!");
450 return -1;
451 }
452
453 auto size = buf->Capacity() - buf->Size();
454 if (size < READ_BUF_SIZE) {
455 uint32_t bufferReaderSize = buf->Size();
456 if (bufferReaderSize > MAX_READ_BUF_SIZE) {
457 SHARING_LOGE("error data size!");
458 return -1;
459 }
460 buf->Resize(bufferReaderSize + READ_BUF_SIZE);
461 }
462
463 int32_t bytesRead = read(fd, buf->Data() + buf->Size(), READ_BUF_SIZE);
464 error = errno;
465 if (bytesRead > 0) {
466 buf->UpdateSize(buf->Size() + bytesRead);
467 } else if (bytesRead < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)) {
468 } else {
469 bytesRead = 0;
470 SHARING_LOGE("error: %{public}s!", strerror(errno));
471 }
472
473 return bytesRead;
474 }
475
RecvSocket(int32_t fd,char * buf,uint32_t len,int32_t flags,int32_t & error)476 int32_t SocketUtils::RecvSocket(int32_t fd, char *buf, uint32_t len, int32_t flags, int32_t &error)
477 {
478 SHARING_LOGD("trace.");
479 if (fd < 0 || buf == nullptr || len == 0) {
480 SHARING_LOGE("invalid param.");
481 return -1;
482 }
483
484 int32_t retCode = recv(fd, buf, len, flags);
485 error = errno;
486 if (retCode < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)) {
487 } else if (retCode > 0) {
488 } else {
489 SHARING_LOGE("error: %{public}s!", strerror(errno));
490 retCode = 0;
491 }
492
493 return retCode;
494 }
495
AcceptSocket(int32_t fd,struct sockaddr_in * clientAddr,socklen_t * addrLen)496 int32_t SocketUtils::AcceptSocket(int32_t fd, struct sockaddr_in *clientAddr, socklen_t *addrLen)
497 {
498 SHARING_LOGD("trace.");
499 int32_t clientFd = accept(fd, reinterpret_cast<struct sockaddr *>(clientAddr), addrLen);
500 if (clientFd < 0) {
501 SHARING_LOGE("accept error: %{public}s!", strerror(errno));
502 }
503
504 return clientFd;
505 }
506
GetIpPortInfo(int32_t fd,std::string & strLocalAddr,std::string & strRemoteAddr,uint16_t & localPort,uint16_t & remotePort)507 bool SocketUtils::GetIpPortInfo(int32_t fd, std::string &strLocalAddr, std::string &strRemoteAddr, uint16_t &localPort,
508 uint16_t &remotePort)
509 {
510 SHARING_LOGD("trace.");
511 struct sockaddr_in localAddr;
512 socklen_t localAddrLen = sizeof(localAddr);
513 if (-1 == getsockname(fd, (struct sockaddr *)&localAddr, &localAddrLen)) {
514 SHARING_LOGE("getsockname error: %{public}s!", strerror(errno));
515 return false;
516 }
517
518 struct sockaddr_in remoteAddr;
519 socklen_t remoteAddrLen = sizeof(remoteAddr);
520 if (-1 == getpeername(fd, (struct sockaddr *)&remoteAddr, &remoteAddrLen)) {
521 SHARING_LOGE("getpeername error: %{public}s!", strerror(errno));
522 return false;
523 }
524
525 strLocalAddr = inet_ntoa(localAddr.sin_addr);
526 strRemoteAddr = inet_ntoa(remoteAddr.sin_addr);
527
528 localPort = ntohs(localAddr.sin_port);
529 remotePort = ntohs(remoteAddr.sin_port);
530 SHARING_LOGD("localAddr: %{public}s localPort: %{public}d remoteAddr: %{public}s remotePort: %{public}d",
531 strLocalAddr.c_str(), localPort, strRemoteAddr.c_str(), remotePort);
532 return true;
533 }
534 } // namespace Sharing
535 } // namespace OHOS