2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "socket-impl.h"
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
28 #include <dali/integration-api/debug.h>
40 const unsigned int MAX_SOCKET_DATA_WRITE_SIZE = 1024 * 1024 * 10 ; // limit maximum size to write to 10 MB
43 Socket::Socket( Protocol protocol , int fileDescriptor )
44 :mSocketFileDescriptor( fileDescriptor ),
47 mQuitPipeCreated(false),
50 int addressFamily( AF_INET );
51 int netProtocol( IPPROTO_TCP );
52 int type( SOCK_STREAM ); // for TCP
57 netProtocol = IPPROTO_UDP;
59 if( mSocketFileDescriptor == -1)
61 mSocketFileDescriptor = socket( addressFamily,type, netProtocol);
65 // socket already open
78 bool Socket::SocketIsOpen() const
80 return (mSocketFileDescriptor != -1);
83 bool Socket::CloseSocket()
86 if( ! SocketIsOpen() )
88 DALI_LOG_ERROR("Socket already closed or is invalid \n");
92 int ret = close( mSocketFileDescriptor );
93 mSocketFileDescriptor = -1;
99 DALI_LOG_ERROR("Socket close failed");
105 bool Socket::Bind( uint16_t port )
107 if( ! SocketIsOpen() || mBound )
109 DALI_LOG_ERROR("Socket is invalid, or already bound");
112 struct sockaddr_in serverAddress;
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
119 int ret = bind( mSocketFileDescriptor,
120 (struct sockaddr* ) &serverAddress,
121 sizeof(serverAddress));
125 DALI_LOG_ERROR("bind failed for port %d %s \n", port, strerror(errno) );
134 bool Socket::Listen( int blacklog)
136 if( ! mBound || mListening )
138 DALI_LOG_ERROR("socket is not bound, or already opened for listening");
141 int ret = listen( mSocketFileDescriptor, blacklog);
145 DALI_LOG_ERROR("Listen failed");
154 SocketInterface* Socket::Accept() const
158 DALI_LOG_ERROR("socket is not being listened to");
162 struct sockaddr clientAddress;
164 socklen_t addressLength(sizeof(sockaddr_in));
166 int clientFileDescriptor = accept( mSocketFileDescriptor, &clientAddress, &addressLength);
167 if( clientFileDescriptor == -1 )
169 DALI_LOG_ERROR("Accept failed");
173 // create a new socket, only TCP supports connections
174 Socket* client = new Socket( TCP, clientFileDescriptor );
179 bool Socket::CreateQuitPipe()
181 if( !mQuitPipeCreated )
183 // create a pipe file descriptor to be able to break from the Select statement
185 int ret = pipe( mQuitPipe );
188 DALI_LOG_ERROR("Pipe creation failed");
191 mQuitPipeCreated = true;
195 void Socket::DeleteQuitPipe()
197 if( mQuitPipeCreated )
199 close( mQuitPipe[0] );
200 close( mQuitPipe[1] );
204 SocketInterface::SelectReturn Socket::Select()
206 bool ok = CreateQuitPipe();
212 fd_set readFileDescriptors, exceptFileDescriptors;
213 FD_ZERO(&readFileDescriptors);
214 FD_ZERO(&exceptFileDescriptors);
216 FD_SET(mSocketFileDescriptor,&readFileDescriptors );
217 FD_SET(mQuitPipe[0],&readFileDescriptors );
219 FD_SET(mSocketFileDescriptor,&exceptFileDescriptors);
221 unsigned int maxFd = mQuitPipe[0] > mSocketFileDescriptor ? mQuitPipe[0]: mSocketFileDescriptor;
225 // this will block waiting for file descriptors
226 int ret = select( maxFd+1, &readFileDescriptors, NULL, &exceptFileDescriptors, NULL );
229 DALI_LOG_ERROR("select failed");
232 else if ( FD_ISSET( mQuitPipe[0] , &readFileDescriptors ))
234 // ExitSelect() called
237 else if ( FD_ISSET( mSocketFileDescriptor, &readFileDescriptors ))
239 // socket data received
240 return DATA_AVAILABLE;
246 void Socket::ExitSelect()
248 if( mQuitPipeCreated )
250 // write a single character to the pipe (can be anything)
252 int ret = write( mQuitPipe[1], &c, 1);
255 DALI_LOG_ERROR("ExitSelect failed!\n");
261 bool Socket::ReuseAddress( bool reUse )
263 if( ! SocketIsOpen() | mBound )
265 DALI_LOG_ERROR("Socket is invalid or already bound \n");
269 int reUseInteger = reUse; // convert it to an int
271 int ret = setsockopt( mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &reUseInteger, sizeof(reUseInteger));
274 DALI_LOG_ERROR("SO_REUSEADDR option failed %s \n",strerror(errno));
280 bool Socket::SetBufferSize( SocketInterface::BufferType type, unsigned int size )
282 if( ! SocketIsOpen() || mBound )
284 DALI_LOG_ERROR("Socket is invalid or already bound \n");
287 int option = SO_RCVBUF;
288 if( type == SocketInterface::SEND_BUFFER )
293 int ret = setsockopt( mSocketFileDescriptor, SOL_SOCKET,option,&size,sizeof(size));
296 DALI_LOG_ERROR("SO_RCVBUF / SO_SNDBUF option failed \n");
302 bool Socket::Read( void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead )
306 if( !SocketIsOpen() )
308 DALI_LOG_ERROR("Socket is invalid \n");
312 bytesRead = read( mSocketFileDescriptor, buffer, bufferSizeInBytes );
317 bool Socket::Write( const void* buffer, unsigned int bufferSizeInBytes )
319 if( !SocketIsOpen() )
321 DALI_LOG_ERROR("Socket is invalid \n");
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 )
328 DALI_LOG_ERROR("Writing %d bytes exceeds MAX_SOCKET_DATA_WRITE_SIZE of %d bytes \n", bufferSizeInBytes, MAX_SOCKET_DATA_WRITE_SIZE);
332 int bytesWritten = 0;
334 // write isn't guaranteed to write the entire buffer in one go
336 while( bytesWritten != static_cast< int>(bufferSizeInBytes))
338 const char* byteBuffer = static_cast<const char *>( buffer );
339 byteBuffer+=bytesWritten;
341 int ret = write( mSocketFileDescriptor, byteBuffer, bufferSizeInBytes - bytesWritten );
344 DALI_LOG_ERROR("Socket writer error \n");