From 9031e2af7dd4e65ec70890ee78a7cf600d1b2cc5 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sat, 16 Oct 2010 03:02:11 +0000 Subject: Many, many changes. Documentation changes, renamed the socket class to TcpSocket, fixed many other things, and finally removed ParamProc. Anything that needs it will now have to switch to OptParser. --- src/tcpserversocket.cpp | 249 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 src/tcpserversocket.cpp (limited to 'src/tcpserversocket.cpp') diff --git a/src/tcpserversocket.cpp b/src/tcpserversocket.cpp new file mode 100644 index 0000000..7d7f6e4 --- /dev/null +++ b/src/tcpserversocket.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2007-2010 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. + */ + +#ifndef WIN32 + #include + #include + #include + #include +#endif + +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include "bu/tcpserversocket.h" + +#include "bu/config.h" + +namespace Bu { subExceptionDef( TcpServerSocketException ) } + +Bu::TcpServerSocket::TcpServerSocket( int nPort, int nPoolSize ) : + nPort( nPort ) +{ +#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( nPort ); + + // 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::TcpServerSocket::TcpServerSocket(const FString &sAddr,int nPort, int nPoolSize) : + nPort( nPort ) +{ +#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( nPort ); + +#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::TcpServerSocket::TcpServerSocket( int nServer, bool bInit, int nPoolSize ) : + nServer( nServer ), + nPort( 0 ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + if( bInit ) + { + struct sockaddr name; + socklen_t namelen = sizeof(name); + getpeername( nServer, &name, &namelen ); + + initServer( *((sockaddr_in *)&name), nPoolSize ); + } + else + { + FD_ZERO( &fdActive ); + FD_SET( nServer, &fdActive ); + } +} + +Bu::TcpServerSocket::TcpServerSocket( const TcpServerSocket &rSrc ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + nServer = dup( rSrc.nServer ); + nPort = rSrc.nPort; + FD_ZERO( &fdActive ); + FD_SET( nServer, &fdActive ); +} + +Bu::TcpServerSocket::~TcpServerSocket() +{ + if( nServer > -1 ) + ::close( nServer ); +} + +void Bu::TcpServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) +{ + /* Create the socket. */ + nServer = bu_socket( PF_INET, SOCK_STREAM, 0 ); + + if( nServer < 0 ) + { + throw Bu::TcpServerSocketException("Couldn't create a listen socket."); + } + + int opt = 1; + bu_setsockopt( + nServer, + SOL_SOCKET, + SO_REUSEADDR, + (char *)&opt, + sizeof( opt ) + ); + + initServer( name, nPoolSize ); +} + +void Bu::TcpServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) +{ + if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) + { + throw Bu::TcpServerSocketException("Couldn't bind to the listen socket."); + } + + if( bu_listen( nServer, nPoolSize ) < 0 ) + { + throw Bu::TcpServerSocketException( + "Couldn't begin listening to the server socket." + ); + } + + FD_ZERO( &fdActive ); + /* Initialize the set of active sockets. */ + FD_SET( nServer, &fdActive ); +} + +int Bu::TcpServerSocket::getSocket() +{ + return nServer; +} + +int Bu::TcpServerSocket::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( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) + { + throw Bu::TcpServerSocketException( + "Error scanning for new connections: %s", strerror( errno ) + ); + } + + if( FD_ISSET( nServer, &fdRead ) ) + { + struct sockaddr_in clientname; + socklen_t size; + int nClient; + + size = sizeof( clientname ); +#ifdef WIN32 + nClient = bu_accept( nServer, (struct sockaddr *)&clientname, &size); +#else /* not-WIN32 */ +#ifdef __CYGWIN__ + nClient = ::accept( nServer, (struct sockaddr *)&clientname, + (int *)&size + ); +#else /* not-cygwin */ +#ifdef __APPLE__ + nClient = ::accept( nServer, (struct sockaddr *)&clientname, (socklen_t*)&size ); +#else /* linux */ + nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size ); +#endif /* __APPLE__ */ +#endif /* __CYGWIN__ */ +#endif /* WIN32 */ + if( nClient < 0 ) + { + throw Bu::TcpServerSocketException( + "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::TcpServerSocketException( + "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 nClient; + } + + return -1; +} + +int Bu::TcpServerSocket::getPort() +{ + return nPort; +} + -- cgit v1.2.3