From 915005e218b5d00939b548de65ce6354f7acb487 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 28 Jul 2023 21:18:56 -0700 Subject: Completely redesigned Server and Client. Like, seriously, they're almost completely different. --- src/stable/serversockettcp.cpp | 254 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 src/stable/serversockettcp.cpp (limited to 'src/stable/serversockettcp.cpp') diff --git a/src/stable/serversockettcp.cpp b/src/stable/serversockettcp.cpp new file mode 100644 index 0000000..c3750b2 --- /dev/null +++ b/src/stable/serversockettcp.cpp @@ -0,0 +1,254 @@ +/* + * 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; +} + -- cgit v1.2.3