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