/* * Copyright (C) 2007-2019 Xagasoft, All rights reserved. * * This file is part of the libbu++ library and is released under the * terms of the license contained in the file LICENSE. */ #include "bu/config.h" #ifndef WIN32 #include #include #include #include #endif #include #include #include #include #include #include #include //#include #include #include "bu/serversockettcp.h" #include "bu/sockettcp.h" namespace Bu { subExceptionDef( ServerSocketTcpException ) } Bu::ServerSocketTcp::ServerSocketTcp( int iPort, int nPoolSize ) : iPort( iPort ) { #ifdef WIN32 Bu::Winsock2::getInstance(); #endif /* Create the socket and set it up to accept connections. */ struct sockaddr_in name; /* Give the socket a name. */ name.sin_family = AF_INET; name.sin_port = bu_htons( iPort ); // I think this specifies who we will accept connections from, // a good thing to make configurable later on name.sin_addr.s_addr = bu_htonl( INADDR_ANY ); startServer( name, nPoolSize ); } Bu::ServerSocketTcp::ServerSocketTcp(const String &sAddr,int iPort, int nPoolSize) : iPort( iPort ) { #ifdef WIN32 Bu::Winsock2::getInstance(); #endif /* Create the socket and set it up to accept connections. */ struct sockaddr_in name; /* Give the socket a name. */ name.sin_family = AF_INET; name.sin_port = bu_htons( iPort ); #ifdef WIN32 name.sin_addr.s_addr = bu_inet_addr( sAddr.getStr() ); #else inet_aton( sAddr.getStr(), &name.sin_addr ); #endif startServer( name, nPoolSize ); } Bu::ServerSocketTcp::ServerSocketTcp( socket_t iSocket, bool bInit, int nPoolSize ) : iSocket( iSocket ), iPort( 0 ) { #ifdef WIN32 Bu::Winsock2::getInstance(); #endif if( bInit ) { struct sockaddr name; socklen_t namelen = sizeof(name); getpeername( iSocket, &name, &namelen ); initServer( *((sockaddr_in *)&name), nPoolSize ); } else { FD_ZERO( &fdActive ); FD_SET( iSocket, &fdActive ); } } Bu::ServerSocketTcp::ServerSocketTcp( const ServerSocketTcp &rSrc ) { #ifdef WIN32 Bu::Winsock2::getInstance(); #endif iSocket = dup( rSrc.iSocket ); iPort = rSrc.iPort; FD_ZERO( &fdActive ); FD_SET( iSocket, &fdActive ); } Bu::ServerSocketTcp::~ServerSocketTcp() { #ifdef WIN32 if( iSocket != INVALID_SOCKET ) #else if( iSocket > -1 ) #endif ::close( iSocket ); } void Bu::ServerSocketTcp::startServer( struct sockaddr_in &name, int nPoolSize ) { /* Create the socket. */ iSocket = bu_socket( PF_INET, SOCK_STREAM, 0 ); #ifdef WIN32 if( iSocket == INVALID_SOCKET ) #else if( iSocket < 0 ) #endif { throw Bu::ServerSocketTcpException("Couldn't create a listen socket."); } int opt = 1; bu_setsockopt( iSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof( opt ) ); initServer( name, nPoolSize ); } void Bu::ServerSocketTcp::initServer( struct sockaddr_in &name, int nPoolSize ) { if( bu_bind( iSocket, (struct sockaddr *) &name, sizeof(name) ) < 0 ) { throw Bu::ServerSocketTcpException("Couldn't bind to the listen socket."); } if( bu_listen( iSocket, nPoolSize ) < 0 ) { throw Bu::ServerSocketTcpException( "Couldn't begin listening to the server socket." ); } FD_ZERO( &fdActive ); /* Initialize the set of active sockets. */ FD_SET( iSocket, &fdActive ); } Bu::Socket *Bu::ServerSocketTcp::accept( int nTimeoutSec, int nTimeoutUSec ) { fd_set fdRead = fdActive; struct timeval xT; xT.tv_sec = nTimeoutSec; xT.tv_usec = nTimeoutUSec; if( TEMP_FAILURE_RETRY( bu_select( iSocket+1, &fdRead, NULL, NULL, &xT )) < 0 ) { throw Bu::ServerSocketTcpException( "Error scanning for new connections: %s", strerror( errno ) ); } if( FD_ISSET( iSocket, &fdRead ) ) { struct sockaddr_in clientname; socklen_t size; int nClient; size = sizeof( clientname ); #ifdef WIN32 nClient = bu_accept( iSocket, (struct sockaddr *)&clientname, &size); #else /* not-WIN32 */ #ifdef __CYGWIN__ nClient = ::accept( iSocket, (struct sockaddr *)&clientname, (int *)&size ); #else /* not-cygwin */ #ifdef __APPLE__ nClient = ::accept( iSocket, (struct sockaddr *)&clientname, (socklen_t*)&size ); #else /* linux */ nClient = ::accept( iSocket, (struct sockaddr *)&clientname, &size ); #endif /* __APPLE__ */ #endif /* __CYGWIN__ */ #endif /* WIN32 */ if( nClient < 0 ) { throw Bu::ServerSocketTcpException( "Error accepting a new connection: %s", strerror( errno ) ); } #ifndef WIN32 char tmpa[20]; inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 ); //"New connection from host %s, port %hd.", // tmpa, ntohs (clientname.sin_port) ); #endif { #ifndef WIN32 int flags; flags = fcntl( nClient, F_GETFL, 0 ); flags |= O_NONBLOCK; if( fcntl( nClient, F_SETFL, flags ) < 0) { throw Bu::ServerSocketTcpException( "Error setting option on client socket: %s", strerror( errno ) ); } #else //------------------------- // Set the socket I/O mode: In this case FIONBIO // enables or disables the blocking mode for the // socket based on the numerical value of iMode. // If iMode = 0, blocking is enabled; // If iMode != 0, non-blocking mode is enabled. u_long iMode = 1; bu_ioctlsocket(nClient, FIONBIO, &iMode); #endif } return new SocketTcp( nClient ); } return NULL; } bool Bu::ServerSocketTcp::getFd( int &rFdOut ) const { rFdOut = iSocket; return true; }