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 "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);
62 if( mSocketFileDescriptor == -1 )
64 DALI_LOG_ERROR( "Unable to create socket\n" );
69 // socket already open
82 bool Socket::SocketIsOpen() const
84 return (mSocketFileDescriptor != -1);
87 bool Socket::CloseSocket()
90 if( ! SocketIsOpen() )
92 DALI_LOG_ERROR("Socket already closed or is invalid \n");
96 int ret = close( mSocketFileDescriptor );
97 mSocketFileDescriptor = -1;
103 DALI_LOG_ERROR("Socket close failed\n");
109 bool Socket::Bind( uint16_t port )
111 if( ! SocketIsOpen() || mBound )
113 DALI_LOG_ERROR("Socket is invalid, or already bound\n");
116 struct sockaddr_in serverAddress;
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
123 int ret = bind( mSocketFileDescriptor,
124 reinterpret_cast< struct sockaddr* >( &serverAddress ),
125 sizeof(serverAddress));
130 DALI_LOG_ERROR( "bind failed for port %d %s \n", port, strerror_r( errno, buf, 512 ) );
139 bool Socket::Listen( int blacklog)
141 if( ! mBound || mListening )
143 DALI_LOG_ERROR("socket is not bound, or already opened for listening\n");
146 int ret = listen( mSocketFileDescriptor, blacklog);
150 DALI_LOG_ERROR("Listen failed\n");
159 SocketInterface* Socket::Accept() const
163 DALI_LOG_ERROR("socket is not being listened to\n");
167 struct sockaddr clientAddress;
169 socklen_t addressLength(sizeof(sockaddr_in));
171 int clientFileDescriptor = accept( mSocketFileDescriptor, &clientAddress, &addressLength);
172 if( clientFileDescriptor == -1 )
174 DALI_LOG_ERROR("Accept failed\n");
178 // create a new socket, only TCP supports connections
179 Socket* client = new Socket( TCP, clientFileDescriptor );
184 bool Socket::CreateQuitPipe()
186 if( !mQuitPipeCreated )
188 // create a pipe file descriptor to be able to break from the Select statement
190 int ret = pipe( mQuitPipe );
193 DALI_LOG_ERROR("Pipe creation failed\n");
196 mQuitPipeCreated = true;
200 void Socket::DeleteQuitPipe()
202 if( mQuitPipeCreated )
204 close( mQuitPipe[0] );
205 close( mQuitPipe[1] );
209 SocketInterface::SelectReturn Socket::Select()
211 bool ok = CreateQuitPipe();
217 fd_set readFileDescriptors, exceptFileDescriptors;
218 FD_ZERO(&readFileDescriptors);
219 FD_ZERO(&exceptFileDescriptors);
221 FD_SET(mSocketFileDescriptor,&readFileDescriptors );
222 FD_SET(mQuitPipe[0],&readFileDescriptors );
224 FD_SET(mSocketFileDescriptor,&exceptFileDescriptors);
226 unsigned int maxFd = mQuitPipe[0] > mSocketFileDescriptor ? mQuitPipe[0]: mSocketFileDescriptor;
230 // this will block waiting for file descriptors
231 int ret = select( maxFd+1, &readFileDescriptors, NULL, &exceptFileDescriptors, NULL );
234 DALI_LOG_ERROR("select failed\n");
237 else if ( FD_ISSET( mQuitPipe[0] , &readFileDescriptors ))
239 // ExitSelect() called
242 else if ( FD_ISSET( mSocketFileDescriptor, &readFileDescriptors ))
244 // socket data received
245 return DATA_AVAILABLE;
251 void Socket::ExitSelect()
253 if( mQuitPipeCreated )
255 // write a single character to the pipe (can be anything)
257 int ret = write( mQuitPipe[1], &c, 1);
260 DALI_LOG_ERROR("ExitSelect failed!\n");
266 bool Socket::ReuseAddress( bool reUse )
268 if( ! SocketIsOpen() | mBound )
270 DALI_LOG_ERROR("Socket is invalid or already bound \n");
274 int reUseInteger = reUse; // convert it to an int
276 int ret = setsockopt( mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &reUseInteger, sizeof(reUseInteger));
280 DALI_LOG_ERROR( "SO_REUSEADDR option failed %s \n", strerror_r( errno, buf, 512 ) );
286 bool Socket::SetBufferSize( SocketInterface::BufferType type, unsigned int size )
288 if( ! SocketIsOpen() || mBound )
290 DALI_LOG_ERROR("Socket is invalid or already bound \n");
293 int option = SO_RCVBUF;
294 if( type == SocketInterface::SEND_BUFFER )
299 int ret = setsockopt( mSocketFileDescriptor, SOL_SOCKET,option,&size,sizeof(size));
302 DALI_LOG_ERROR("SO_RCVBUF / SO_SNDBUF option failed \n");
308 bool Socket::Read( void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead )
312 if( !SocketIsOpen() )
314 DALI_LOG_ERROR("Socket is invalid \n");
318 bytesRead = read( mSocketFileDescriptor, buffer, bufferSizeInBytes );
323 bool Socket::Write( const void* buffer, unsigned int bufferSizeInBytes )
325 if( !SocketIsOpen() )
327 DALI_LOG_ERROR("Socket is invalid \n");
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 )
334 DALI_LOG_ERROR("Writing %d bytes exceeds MAX_SOCKET_DATA_WRITE_SIZE of %d bytes \n", bufferSizeInBytes, MAX_SOCKET_DATA_WRITE_SIZE);
338 int bytesWritten = 0;
340 // write isn't guaranteed to write the entire buffer in one go
342 while( bytesWritten != static_cast< int>(bufferSizeInBytes))
344 const char* byteBuffer = static_cast<const char *>( buffer );
345 byteBuffer+=bytesWritten;
347 int ret = write( mSocketFileDescriptor, byteBuffer, bufferSizeInBytes - bytesWritten );
350 DALI_LOG_ERROR("Socket writer error \n");