2 * Copyright (c) 2017 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 <dali/internal/network/common/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>
30 // Sockets enums like INADDR_ANY use C-Casts
31 #pragma GCC diagnostic push
32 #pragma GCC diagnostic ignored "-Wold-style-cast"
43 const unsigned int MAX_SOCKET_DATA_WRITE_SIZE = 1024 * 1024 * 10 ; // limit maximum size to write to 10 MB
46 Socket::Socket( Protocol protocol , int fileDescriptor )
47 :mSocketFileDescriptor( fileDescriptor ),
50 mQuitPipeCreated(false),
53 int addressFamily( AF_INET );
54 int netProtocol( IPPROTO_TCP );
55 int type( SOCK_STREAM ); // for TCP
60 netProtocol = IPPROTO_UDP;
62 if( mSocketFileDescriptor == -1)
64 mSocketFileDescriptor = socket( addressFamily,type, netProtocol);
65 if( mSocketFileDescriptor == -1 )
67 DALI_LOG_ERROR( "Unable to create socket\n" );
72 // socket already open
85 bool Socket::SocketIsOpen() const
87 return (mSocketFileDescriptor != -1);
90 bool Socket::CloseSocket()
93 if( ! SocketIsOpen() )
95 DALI_LOG_ERROR("Socket already closed or is invalid \n");
99 int ret = close( mSocketFileDescriptor );
100 mSocketFileDescriptor = -1;
106 DALI_LOG_ERROR("Socket close failed\n");
112 bool Socket::Bind( uint16_t port )
114 if( ! SocketIsOpen() || mBound )
116 DALI_LOG_ERROR("Socket is invalid, or already bound\n");
119 struct sockaddr_in serverAddress;
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
126 int ret = bind( mSocketFileDescriptor,
127 reinterpret_cast< struct sockaddr* >( &serverAddress ),
128 sizeof(serverAddress));
133 DALI_LOG_ERROR( "bind failed for port %d %s \n", port, strerror_r( errno, buf, 512 ) );
142 bool Socket::Listen( int blacklog)
144 if( ! mBound || mListening )
146 DALI_LOG_ERROR("socket is not bound, or already opened for listening\n");
149 int ret = listen( mSocketFileDescriptor, blacklog);
153 DALI_LOG_ERROR("Listen failed\n");
162 SocketInterface* Socket::Accept() const
166 DALI_LOG_ERROR("socket is not being listened to\n");
170 struct sockaddr clientAddress;
172 socklen_t addressLength(sizeof(sockaddr_in));
174 int clientFileDescriptor = accept( mSocketFileDescriptor, &clientAddress, &addressLength);
175 if( clientFileDescriptor == -1 )
177 DALI_LOG_ERROR("Accept failed\n");
181 // create a new socket, only TCP supports connections
182 Socket* client = new Socket( TCP, clientFileDescriptor );
187 bool Socket::CreateQuitPipe()
189 if( !mQuitPipeCreated )
191 // create a pipe file descriptor to be able to break from the Select statement
193 int ret = pipe( mQuitPipe );
196 DALI_LOG_ERROR("Pipe creation failed\n");
199 mQuitPipeCreated = true;
203 void Socket::DeleteQuitPipe()
205 if( mQuitPipeCreated )
207 close( mQuitPipe[0] );
208 close( mQuitPipe[1] );
212 SocketInterface::SelectReturn Socket::Select()
214 bool ok = CreateQuitPipe();
220 fd_set readFileDescriptors, exceptFileDescriptors;
221 FD_ZERO(&readFileDescriptors);
222 FD_ZERO(&exceptFileDescriptors);
224 FD_SET(mSocketFileDescriptor,&readFileDescriptors );
225 FD_SET(mQuitPipe[0],&readFileDescriptors );
227 FD_SET(mSocketFileDescriptor,&exceptFileDescriptors);
229 unsigned int maxFd = mQuitPipe[0] > mSocketFileDescriptor ? mQuitPipe[0]: mSocketFileDescriptor;
233 // this will block waiting for file descriptors
234 int ret = select( maxFd+1, &readFileDescriptors, NULL, &exceptFileDescriptors, NULL );
237 DALI_LOG_ERROR("select failed\n");
240 else if ( FD_ISSET( mQuitPipe[0] , &readFileDescriptors ))
242 // ExitSelect() called
245 else if ( FD_ISSET( mSocketFileDescriptor, &readFileDescriptors ))
247 // socket data received
248 return DATA_AVAILABLE;
254 void Socket::ExitSelect()
256 if( mQuitPipeCreated )
258 // write a single character to the pipe (can be anything)
260 int ret = write( mQuitPipe[1], &c, 1);
263 DALI_LOG_ERROR("ExitSelect failed!\n");
269 bool Socket::ReuseAddress( bool reUse )
271 if( ! SocketIsOpen() | mBound )
273 DALI_LOG_ERROR("Socket is invalid or already bound \n");
277 int reUseInteger = reUse; // convert it to an int
279 int ret = setsockopt( mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &reUseInteger, sizeof(reUseInteger));
283 DALI_LOG_ERROR( "SO_REUSEADDR option failed %s \n", strerror_r( errno, buf, 512 ) );
289 bool Socket::SetBufferSize( SocketInterface::BufferType type, unsigned int size )
291 if( ! SocketIsOpen() || mBound )
293 DALI_LOG_ERROR("Socket is invalid or already bound \n");
296 int option = SO_RCVBUF;
297 if( type == SocketInterface::SEND_BUFFER )
302 int ret = setsockopt( mSocketFileDescriptor, SOL_SOCKET,option,&size,sizeof(size));
305 DALI_LOG_ERROR("SO_RCVBUF / SO_SNDBUF option failed \n");
311 bool Socket::Read( void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead )
315 if( !SocketIsOpen() )
317 DALI_LOG_ERROR("Socket is invalid \n");
321 bytesRead = read( mSocketFileDescriptor, buffer, bufferSizeInBytes );
326 bool Socket::Write( const void* buffer, unsigned int bufferSizeInBytes )
328 if( !SocketIsOpen() )
330 DALI_LOG_ERROR("Socket is invalid \n");
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 )
337 DALI_LOG_ERROR("Writing %d bytes exceeds MAX_SOCKET_DATA_WRITE_SIZE of %d bytes \n", bufferSizeInBytes, MAX_SOCKET_DATA_WRITE_SIZE);
341 int bytesWritten = 0;
343 // write isn't guaranteed to write the entire buffer in one go
345 while( bytesWritten != static_cast< int>(bufferSizeInBytes))
347 const char* byteBuffer = static_cast<const char *>( buffer );
348 byteBuffer+=bytesWritten;
350 int ret = write( mSocketFileDescriptor, byteBuffer, bufferSizeInBytes - bytesWritten );
353 DALI_LOG_ERROR("Socket writer error \n");
370 #pragma GCC diagnostic pop