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