Merge "[AT-SPI] Rework intercepting key events" into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / network / common / socket-impl.cpp
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/network/common/socket-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <errno.h>
24 #include <netinet/in.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29
30 // Sockets enums like INADDR_ANY use C-Casts
31 #pragma GCC diagnostic push
32 #pragma GCC diagnostic ignored "-Wold-style-cast"
33
34 namespace Dali
35 {
36 namespace Internal
37 {
38 namespace Adaptor
39 {
40 namespace
41 {
42 const unsigned int MAX_SOCKET_DATA_WRITE_SIZE = 1024 * 1024 * 10; // limit maximum size to write to 10 MB
43 }
44
45 Socket::Socket(Protocol protocol, int fileDescriptor)
46 : mSocketFileDescriptor(fileDescriptor),
47   mBound(false),
48   mListening(false),
49   mQuitPipeCreated(false),
50   mBlocked(false)
51 {
52   int addressFamily(AF_INET);
53   int netProtocol(IPPROTO_TCP);
54   int type(SOCK_STREAM); // for TCP
55
56   if(protocol == UDP)
57   {
58     type        = SOCK_DGRAM;
59     netProtocol = IPPROTO_UDP;
60   }
61   if(mSocketFileDescriptor == -1)
62   {
63     mSocketFileDescriptor = socket(addressFamily, type, netProtocol);
64     if(mSocketFileDescriptor == -1)
65     {
66       DALI_LOG_ERROR("Unable to create socket\n");
67     }
68   }
69   else
70   {
71     // socket already open
72     mBound = true;
73   }
74 }
75
76 Socket::~Socket()
77 {
78   if(SocketIsOpen())
79   {
80     CloseSocket();
81   }
82 }
83
84 bool Socket::SocketIsOpen() const
85 {
86   return (mSocketFileDescriptor != -1);
87 }
88
89 bool Socket::CloseSocket()
90 {
91   if(!SocketIsOpen())
92   {
93     DALI_LOG_ERROR("Socket already closed or is invalid \n");
94     return false;
95   }
96
97   int ret               = close(mSocketFileDescriptor);
98   mSocketFileDescriptor = -1;
99   mListening            = false;
100   mBound                = false;
101
102   if(ret == -1)
103   {
104     DALI_LOG_ERROR("Socket close failed\n");
105     return false;
106   }
107   return true;
108 }
109
110 bool Socket::Bind(uint16_t port)
111 {
112   if(!SocketIsOpen() || mBound)
113   {
114     DALI_LOG_ERROR("Socket is invalid, or already bound\n");
115     return false;
116   }
117   struct sockaddr_in serverAddress;
118
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
123
124   int ret = bind(mSocketFileDescriptor,
125                  reinterpret_cast<struct sockaddr*>(&serverAddress),
126                  sizeof(serverAddress));
127
128   if(ret == -1)
129   {
130     char buf[512];
131     DALI_LOG_ERROR("bind failed for port %d %s \n", port, strerror_r(errno, buf, 512));
132     return false;
133   }
134
135   mBound = true;
136
137   return true;
138 }
139
140 bool Socket::Listen(int blacklog)
141 {
142   if(!mBound || mListening)
143   {
144     DALI_LOG_ERROR("socket is not bound, or already opened for listening\n");
145     return false;
146   }
147   int ret = listen(mSocketFileDescriptor, blacklog);
148
149   if(ret == -1)
150   {
151     DALI_LOG_ERROR("Listen failed\n");
152     return false;
153   }
154
155   mListening = true;
156
157   return true;
158 }
159
160 SocketInterface* Socket::Accept() const
161 {
162   if(!mListening)
163   {
164     DALI_LOG_ERROR("socket is not being listened to\n");
165     return NULL;
166   }
167
168   struct sockaddr clientAddress;
169
170   socklen_t addressLength(static_cast<socklen_t>(sizeof(sockaddr_in)));
171
172   int clientFileDescriptor = accept(mSocketFileDescriptor, &clientAddress, &addressLength);
173   if(clientFileDescriptor == -1)
174   {
175     DALI_LOG_ERROR("Accept failed\n");
176     return NULL;
177   }
178
179   // create a new socket, only TCP supports connections
180   Socket* client = new Socket(TCP, clientFileDescriptor);
181
182   return client;
183 }
184
185 bool Socket::CreateQuitPipe()
186 {
187   if(!mQuitPipeCreated)
188   {
189     // create a pipe file descriptor to be able to break from the Select statement
190     //
191     int ret = pipe(mQuitPipe);
192     if(ret != 0)
193     {
194       DALI_LOG_ERROR("Pipe creation failed\n");
195       return false;
196     }
197     mQuitPipeCreated = true;
198   }
199   return true;
200 }
201 void Socket::DeleteQuitPipe()
202 {
203   if(mQuitPipeCreated)
204   {
205     close(mQuitPipe[0]);
206     close(mQuitPipe[1]);
207   }
208 }
209
210 SocketInterface::SelectReturn Socket::Select()
211 {
212   bool ok = CreateQuitPipe();
213   if(!ok)
214   {
215     return ERROR;
216   }
217
218   fd_set readFileDescriptors, exceptFileDescriptors;
219   FD_ZERO(&readFileDescriptors);
220   FD_ZERO(&exceptFileDescriptors);
221
222   FD_SET(mSocketFileDescriptor, &readFileDescriptors);
223   FD_SET(mQuitPipe[0], &readFileDescriptors);
224
225   FD_SET(mSocketFileDescriptor, &exceptFileDescriptors);
226
227   unsigned int maxFd = mQuitPipe[0] > mSocketFileDescriptor ? mQuitPipe[0] : mSocketFileDescriptor;
228
229   for(;;)
230   {
231     // this will block waiting for file descriptors
232     int ret = select(maxFd + 1, &readFileDescriptors, NULL, &exceptFileDescriptors, NULL);
233     if(ret == -1)
234     {
235       DALI_LOG_ERROR("select failed\n");
236       return ERROR;
237     }
238     else if(FD_ISSET(mQuitPipe[0], &readFileDescriptors))
239     {
240       // ExitSelect() called
241       return QUIT;
242     }
243     else if(FD_ISSET(mSocketFileDescriptor, &readFileDescriptors))
244     {
245       // socket data received
246       return DATA_AVAILABLE;
247     }
248   }
249   return QUIT;
250 }
251
252 void Socket::ExitSelect()
253 {
254   if(mQuitPipeCreated)
255   {
256     // write a single character to the pipe (can be anything)
257     char c   = ' ';
258     int  ret = write(mQuitPipe[1], &c, 1);
259     if(ret < 1)
260     {
261       DALI_LOG_ERROR("ExitSelect failed!\n");
262     }
263     return;
264   }
265 }
266
267 bool Socket::ReuseAddress(bool reUse)
268 {
269   if(!SocketIsOpen() | mBound)
270   {
271     DALI_LOG_ERROR("Socket is invalid or already bound \n");
272     return false;
273   }
274
275   int reUseInteger = reUse; // convert it to an int
276
277   int ret = setsockopt(mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &reUseInteger, sizeof(reUseInteger));
278   if(ret == -1)
279   {
280     char buf[512];
281     DALI_LOG_ERROR("SO_REUSEADDR option failed %s \n", strerror_r(errno, buf, 512));
282     return false;
283   }
284   return true;
285 }
286
287 bool Socket::SetBufferSize(SocketInterface::BufferType type, unsigned int size)
288 {
289   if(!SocketIsOpen() || mBound)
290   {
291     DALI_LOG_ERROR("Socket is invalid or already bound \n");
292     return false;
293   }
294   int option = SO_RCVBUF;
295   if(type == SocketInterface::SEND_BUFFER)
296   {
297     option = SO_SNDBUF;
298   }
299
300   int ret = setsockopt(mSocketFileDescriptor, SOL_SOCKET, option, &size, sizeof(size));
301   if(ret == -1)
302   {
303     DALI_LOG_ERROR("SO_RCVBUF / SO_SNDBUF  option failed \n");
304     return false;
305   }
306   return true;
307 }
308
309 bool Socket::Read(void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead)
310 {
311   bytesRead = 0;
312
313   if(!SocketIsOpen())
314   {
315     DALI_LOG_ERROR("Socket is invalid \n");
316     return false;
317   }
318
319   bytesRead = static_cast<unsigned int>(read(mSocketFileDescriptor, buffer, bufferSizeInBytes));
320
321   return true;
322 }
323
324 bool Socket::Write(const void* buffer, unsigned int bufferSizeInBytes)
325 {
326   if(!SocketIsOpen())
327   {
328     DALI_LOG_ERROR("Socket is invalid \n");
329     return false;
330   }
331
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)
334   {
335     DALI_LOG_ERROR("Writing %d bytes exceeds MAX_SOCKET_DATA_WRITE_SIZE of %d bytes \n", bufferSizeInBytes, MAX_SOCKET_DATA_WRITE_SIZE);
336     return false;
337   }
338
339   unsigned int bytesWritten = 0;
340
341   // write isn't guaranteed to write the entire buffer in one go
342
343   while(bytesWritten != bufferSizeInBytes)
344   {
345     if(bufferSizeInBytes < bytesWritten)
346     {
347       DALI_LOG_ERROR("Socket writer error! required size : %u byte, real written : %u byte \n", bufferSizeInBytes, bytesWritten);
348       return false;
349     }
350
351     const char* byteBuffer = static_cast<const char*>(buffer);
352     byteBuffer += bytesWritten;
353
354     int ret = write(mSocketFileDescriptor, byteBuffer, bufferSizeInBytes - bytesWritten);
355     if(ret < 1)
356     {
357       DALI_LOG_ERROR("Socket writer error \n");
358       return false;
359     }
360     else
361     {
362       bytesWritten += ret;
363     }
364   }
365   return true;
366 }
367
368 } // namespace Adaptor
369
370 } // namespace Internal
371
372 } // namespace Dali
373
374 #pragma GCC diagnostic pop