2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/network/common/socket-impl.h>
22 #include <dali/integration-api/debug.h>
24 #include <netinet/in.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
30 // Sockets enums like INADDR_ANY use C-Casts
31 #pragma GCC diagnostic push
32 #pragma GCC diagnostic ignored "-Wold-style-cast"
42 const unsigned int MAX_SOCKET_DATA_WRITE_SIZE = 1024 * 1024 * 10; // limit maximum size to write to 10 MB
45 Socket::Socket(Protocol protocol, int fileDescriptor)
46 : mSocketFileDescriptor(fileDescriptor),
49 mQuitPipeCreated(false),
52 int addressFamily(AF_INET);
53 int netProtocol(IPPROTO_TCP);
54 int type(SOCK_STREAM); // for TCP
59 netProtocol = IPPROTO_UDP;
61 if(mSocketFileDescriptor == -1)
63 mSocketFileDescriptor = socket(addressFamily, type, netProtocol);
64 if(mSocketFileDescriptor == -1)
66 DALI_LOG_ERROR("Unable to create socket\n");
71 // socket already open
84 bool Socket::SocketIsOpen() const
86 return (mSocketFileDescriptor != -1);
89 bool Socket::CloseSocket()
93 DALI_LOG_ERROR("Socket already closed or is invalid \n");
97 int ret = close(mSocketFileDescriptor);
98 mSocketFileDescriptor = -1;
104 DALI_LOG_ERROR("Socket close failed\n");
110 bool Socket::Bind(uint16_t port)
112 if(!SocketIsOpen() || mBound)
114 DALI_LOG_ERROR("Socket is invalid, or already bound\n");
117 struct sockaddr_in serverAddress;
119 memset(&serverAddress, 0, sizeof(serverAddress));
120 serverAddress.sin_family = AF_INET; // internet
121 serverAddress.sin_port = htons(port); // host-to-net short (16-bit) translation
122 serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); // binds the socket to all available interfaces
124 int ret = bind(mSocketFileDescriptor,
125 reinterpret_cast<struct sockaddr*>(&serverAddress),
126 sizeof(serverAddress));
131 DALI_LOG_ERROR("bind failed for port %d %s \n", port, strerror_r(errno, buf, 512));
140 bool Socket::Listen(int blacklog)
142 if(!mBound || mListening)
144 DALI_LOG_ERROR("socket is not bound, or already opened for listening\n");
147 int ret = listen(mSocketFileDescriptor, blacklog);
151 DALI_LOG_ERROR("Listen failed\n");
160 SocketInterface* Socket::Accept() const
164 DALI_LOG_ERROR("socket is not being listened to\n");
168 struct sockaddr clientAddress;
170 socklen_t addressLength(sizeof(sockaddr_in));
172 int clientFileDescriptor = accept(mSocketFileDescriptor, &clientAddress, &addressLength);
173 if(clientFileDescriptor == -1)
175 DALI_LOG_ERROR("Accept failed\n");
179 // create a new socket, only TCP supports connections
180 Socket* client = new Socket(TCP, clientFileDescriptor);
185 bool Socket::CreateQuitPipe()
187 if(!mQuitPipeCreated)
189 // create a pipe file descriptor to be able to break from the Select statement
191 int ret = pipe(mQuitPipe);
194 DALI_LOG_ERROR("Pipe creation failed\n");
197 mQuitPipeCreated = true;
201 void Socket::DeleteQuitPipe()
210 SocketInterface::SelectReturn Socket::Select()
212 bool ok = CreateQuitPipe();
218 fd_set readFileDescriptors, exceptFileDescriptors;
219 FD_ZERO(&readFileDescriptors);
220 FD_ZERO(&exceptFileDescriptors);
222 FD_SET(mSocketFileDescriptor, &readFileDescriptors);
223 FD_SET(mQuitPipe[0], &readFileDescriptors);
225 FD_SET(mSocketFileDescriptor, &exceptFileDescriptors);
227 unsigned int maxFd = mQuitPipe[0] > mSocketFileDescriptor ? mQuitPipe[0] : mSocketFileDescriptor;
231 // this will block waiting for file descriptors
232 int ret = select(maxFd + 1, &readFileDescriptors, NULL, &exceptFileDescriptors, NULL);
235 DALI_LOG_ERROR("select failed\n");
238 else if(FD_ISSET(mQuitPipe[0], &readFileDescriptors))
240 // ExitSelect() called
243 else if(FD_ISSET(mSocketFileDescriptor, &readFileDescriptors))
245 // socket data received
246 return DATA_AVAILABLE;
252 void Socket::ExitSelect()
256 // write a single character to the pipe (can be anything)
258 int ret = write(mQuitPipe[1], &c, 1);
261 DALI_LOG_ERROR("ExitSelect failed!\n");
267 bool Socket::ReuseAddress(bool reUse)
269 if(!SocketIsOpen() | mBound)
271 DALI_LOG_ERROR("Socket is invalid or already bound \n");
275 int reUseInteger = reUse; // convert it to an int
277 int ret = setsockopt(mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &reUseInteger, sizeof(reUseInteger));
281 DALI_LOG_ERROR("SO_REUSEADDR option failed %s \n", strerror_r(errno, buf, 512));
287 bool Socket::SetBufferSize(SocketInterface::BufferType type, unsigned int size)
289 if(!SocketIsOpen() || mBound)
291 DALI_LOG_ERROR("Socket is invalid or already bound \n");
294 int option = SO_RCVBUF;
295 if(type == SocketInterface::SEND_BUFFER)
300 int ret = setsockopt(mSocketFileDescriptor, SOL_SOCKET, option, &size, sizeof(size));
303 DALI_LOG_ERROR("SO_RCVBUF / SO_SNDBUF option failed \n");
309 bool Socket::Read(void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead)
315 DALI_LOG_ERROR("Socket is invalid \n");
319 bytesRead = read(mSocketFileDescriptor, buffer, bufferSizeInBytes);
324 bool Socket::Write(const void* buffer, unsigned int bufferSizeInBytes)
328 DALI_LOG_ERROR("Socket is invalid \n");
332 // check we don't try to write more than 10MB ( this can be increased if required)
333 if(bufferSizeInBytes > MAX_SOCKET_DATA_WRITE_SIZE)
335 DALI_LOG_ERROR("Writing %d bytes exceeds MAX_SOCKET_DATA_WRITE_SIZE of %d bytes \n", bufferSizeInBytes, MAX_SOCKET_DATA_WRITE_SIZE);
339 int bytesWritten = 0;
341 // write isn't guaranteed to write the entire buffer in one go
343 while(bytesWritten != static_cast<int>(bufferSizeInBytes))
345 const char* byteBuffer = static_cast<const char*>(buffer);
346 byteBuffer += bytesWritten;
348 int ret = write(mSocketFileDescriptor, byteBuffer, bufferSizeInBytes - bytesWritten);
351 DALI_LOG_ERROR("Socket writer error \n");
362 } // namespace Adaptor
364 } // namespace Internal
368 #pragma GCC diagnostic pop