1 /*
2 * Copyright (c) 2024 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 * Description: tcp socket.
15 * Author: renshuang
16 * Create: 2023-09-25
17 */
18
19 #include "tcp_socket.h"
20
21 #include "cast_engine_log.h"
22 #include "securec.h"
23
24 namespace OHOS {
25 namespace CastEngine {
26 namespace CastEngineService {
27 DEFINE_CAST_ENGINE_LABEL("CastEngine-TcpSocket");
28
TcpSocket()29 TcpSocket::TcpSocket()
30 {
31 socket_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
32 if (socket_ < RET_OK) {
33 CLOGE("Create socket error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
34 } else {
35 CLOGD("Create socket success.");
36 }
37 }
38
~TcpSocket()39 TcpSocket::~TcpSocket()
40 {
41 Close();
42 }
43
Bind(const std::string & ip,int port)44 int TcpSocket::Bind(const std::string &ip, int port)
45 {
46 struct sockaddr_in sockaddr{};
47 sockaddr.sin_family = AF_INET;
48 if (ip.empty()) {
49 sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
50 } else {
51 sockaddr.sin_addr.s_addr = inet_addr(ip.c_str());
52 }
53 if (port == INVALID_PORT) {
54 sockaddr.sin_port = htons(RANDOM_PORT);
55 } else {
56 sockaddr.sin_port = htons(port);
57 }
58 if (::bind(socket_, reinterpret_cast<struct sockaddr *>(&sockaddr), sizeof(sockaddr)) < RET_OK) {
59 CLOGE("Socket bind error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
60 return INVALID_PORT;
61 }
62 CLOGD("Socket bind success.");
63 if (port == INVALID_PORT) {
64 return GetBindPort();
65 }
66 return port;
67 }
68
GetBindPort()69 int TcpSocket::GetBindPort()
70 {
71 if (socket_ == INVALID_SOCKET) {
72 CLOGE("Socket getBindPort error: socket_ is invalid");
73 return INVALID_PORT;
74 }
75 struct sockaddr_in sockaddr{};
76 socklen_t addrLen = sizeof(sockaddr);
77 if (getsockname(socket_, reinterpret_cast<struct sockaddr *>(&sockaddr), &addrLen) < RET_OK) {
78 CLOGE("Socket getBindPort error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
79 return INVALID_PORT;
80 }
81 return ntohs(sockaddr.sin_port);
82 }
83
GetPeerPort(int fd)84 int TcpSocket::GetPeerPort(int fd)
85 {
86 if (fd == INVALID_SOCKET) {
87 CLOGE("Socket getPeerPort error: socket is invalid");
88 return INVALID_PORT;
89 }
90 struct sockaddr_in sockaddr{};
91 socklen_t addrLen = sizeof(sockaddr);
92 if (getpeername(fd, reinterpret_cast<struct sockaddr *>(&sockaddr), &addrLen) < RET_OK) {
93 CLOGE("Socket getPeerPort error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
94 return INVALID_PORT;
95 }
96 return ntohs(sockaddr.sin_port);
97 }
98
GetSocketFd()99 int TcpSocket::GetSocketFd()
100 {
101 return socket_;
102 }
103
Listen(int backlog)104 bool TcpSocket::Listen(int backlog)
105 {
106 if (::listen(socket_, backlog) < RET_OK) {
107 CLOGE("Socket listen error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
108 return false;
109 }
110 CLOGD("Socket listening...");
111 return true;
112 }
113
Connect(const std::string & ip,int port)114 bool TcpSocket::Connect(const std::string & ip, int port)
115 {
116 struct sockaddr_in sockaddr{};
117 sockaddr.sin_family = AF_INET;
118 sockaddr.sin_addr.s_addr = inet_addr(ip.c_str());
119 sockaddr.sin_port = htons(port);
120 if (::connect(socket_, reinterpret_cast<struct sockaddr *>(&sockaddr), sizeof(sockaddr)) < RET_OK) {
121 CLOGE("Socket connect error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
122 return false;
123 }
124 CLOGD("Socket connect success.");
125 return true;
126 }
127
Accept()128 int TcpSocket::Accept()
129 {
130 int connfd = ::accept(socket_, nullptr, nullptr);
131 if (connfd < RET_OK) {
132 CLOGE("Socket accept error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
133 return INVALID_SOCKET;
134 }
135 CLOGD("Socket accept success.");
136 return connfd;
137 }
138
Send(int fd,const uint8_t * buff,size_t length)139 int TcpSocket::Send(int fd, const uint8_t *buff, size_t length)
140 {
141 auto ret = ::send(fd, buff, length, SOCKET_FLAG);
142 if (ret < RET_OK) {
143 CLOGE("Socket send error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
144 }
145 return ret;
146 }
147
Recv(int fd,uint8_t * buff,size_t length)148 ssize_t TcpSocket::Recv(int fd, uint8_t *buff, size_t length)
149 {
150 size_t recvLen = 0;
151 while (recvLen < length) {
152 ssize_t len;
153 int error;
154 do {
155 len = ::recv(fd, buff + recvLen, length - recvLen, SOCKET_FLAG);
156 error = errno;
157 if (stopReceive_) {
158 return STOP_RECEIVE;
159 }
160 } while (len <= 0 && (error == EINTR || error == EAGAIN));
161
162 if (len < RET_OK) {
163 CLOGE("Socket recv error: errno = %{public}d, errmsg = %{public}s.", error, strerror(error));
164 return RET_ERR;
165 }
166
167 recvLen += static_cast<size_t>(len);
168 }
169
170 CLOGD("Socket recv DONE!, size:%zu", recvLen);
171 return recvLen;
172 }
173
Close()174 void TcpSocket::Close()
175 {
176 if (socket_ > INVALID_SOCKET) {
177 ::close(socket_);
178 socket_ = INVALID_SOCKET;
179 }
180 }
181
Shutdown(int fd)182 void TcpSocket::Shutdown(int fd)
183 {
184 if (fd > INVALID_SOCKET) {
185 stopReceive_ = true;
186 ::shutdown((fd), SHUT_RDWR);
187 }
188 }
189
SetSendBufferSize(int size)190 bool TcpSocket::SetSendBufferSize(int size)
191 {
192 int buffSize = size;
193 if (setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, &buffSize, sizeof(buffSize)) < RET_OK) {
194 CLOGE("Socket SetSendBufferSize error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
195 return false;
196 }
197 CLOGD("Socket SetSendBufferSize success.");
198 return true;
199 }
200
SetRecvBufferSize(int size)201 bool TcpSocket::SetRecvBufferSize(int size)
202 {
203 int buffSize = size;
204 if (setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, &buffSize, sizeof(buffSize)) < RET_OK) {
205 CLOGE("Socket SetRecvBufferSize error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
206 return false;
207 }
208 CLOGD("Socket SetRecvBufferSize success.");
209 return true;
210 }
211
SetLinger(bool active,int seconds)212 bool TcpSocket::SetLinger(bool active, int seconds)
213 {
214 struct linger lgr{};
215 lgr.l_onoff = active ? SOCKET_ON : SOCKET_OFF;
216 lgr.l_linger = seconds;
217 if (setsockopt(socket_, SOL_SOCKET, SO_LINGER, &lgr, sizeof(lgr)) < RET_OK) {
218 CLOGE("Socket SetLinger error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
219 return false;
220 }
221 CLOGD("Socket SetLinger success.");
222 return true;
223 }
224
SetKeepAlive()225 bool TcpSocket::SetKeepAlive()
226 {
227 return SetKeepAlive(DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE);
228 }
229
SetKeepAlive(unsigned idleTime,unsigned numProbes,unsigned probeInterval)230 bool TcpSocket::SetKeepAlive(unsigned idleTime, unsigned numProbes, unsigned probeInterval)
231 {
232 int flag = SOCKET_ON;
233 if (setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag)) < RET_OK) {
234 CLOGE("Socket SetKeepAlive error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
235 return false;
236 }
237 if (idleTime != DEFAULT_VALUE) {
238 if (setsockopt(socket_, SOL_TCP, TCP_KEEPIDLE, &idleTime, sizeof(idleTime)) < RET_OK) {
239 CLOGE("Socket SetKeepIDLE error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
240 return false;
241 }
242 }
243 if (numProbes != DEFAULT_VALUE) {
244 if (setsockopt(socket_, SOL_TCP, TCP_KEEPCNT, &numProbes, sizeof(numProbes)) < RET_OK) {
245 CLOGE("Socket SetKeepCNT error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
246 return false;
247 }
248 }
249 if (probeInterval != DEFAULT_VALUE) {
250 if (setsockopt(socket_, SOL_TCP, TCP_KEEPINTVL, &probeInterval, sizeof(probeInterval)) < RET_OK) {
251 CLOGE("Socket SetKeepINTVL error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
252 return false;
253 }
254 }
255 CLOGD("Socket SetKeepAlive success.");
256 return true;
257 }
258
SetReuseAddr()259 bool TcpSocket::SetReuseAddr()
260 {
261 int flag = SOCKET_ON;
262 if (setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) < RET_OK) {
263 CLOGE("Socket SetReuseAddr error: errno = %{public}d, errmsg = %{public}s.", errno, strerror(errno));
264 return false;
265 }
266 CLOGD("Socket SetReuseAddr success.");
267 return true;
268 }
269
270 } // namespace CastEngineService
271 } // namespace CastEngine
272 } // namespace OHOS