• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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