Dali 3D User Interface Engine
socket-impl.cpp
Go to the documentation of this file.
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>
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" );
65  }
66  }
67  else
68  {
69  // socket already open
70  mBound = true;
71  }
72 }
73 
75 {
76  if( SocketIsOpen() )
77  {
78  CloseSocket();
79  }
80 }
81 
83 {
84  return (mSocketFileDescriptor != -1);
85 }
86 
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 );
98  mListening = false;
99  mBound = false;
100 
101  if( ret == -1 )
102  {
103  DALI_LOG_ERROR("Socket close failed");
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");
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  (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");
144  return false;
145  }
146  int ret = listen( mSocketFileDescriptor, blacklog);
147 
148  if( ret == -1 )
149  {
150  DALI_LOG_ERROR("Listen failed");
151  return false;
152  }
153 
154  mListening = true;
155 
156  return true;
157 }
158 
160 {
161  if( !mListening )
162  {
163  DALI_LOG_ERROR("socket is not being listened to");
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");
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 
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");
194  return false;
195  }
196  mQuitPipeCreated = true;
197  }
198  return true;
199 }
201 {
202  if( mQuitPipeCreated )
203  {
204  close( mQuitPipe[0] );
205  close( mQuitPipe[1] );
206  }
207 }
208 
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");
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 
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 
Dali Docs Home
Read more about Dali