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