/* * SocketCore.h * * Created on: 13 May 2016 * Author: wentzelc */ // redA Libraries #include "TimingCore.h" #include "SocketCore.h" #include "LogCore.h" // Standard C/C++ Libraries #include #include #include #include #include #include #include #include #include #include #include #include //--------------------------------------------------------------------------- CSocketCore::CSocketCore( const char * ServerName ) : CFunctionCore( ServerName ) { ServerAddress[0] = 0; PortNo = 0; ClientAddress[0] = 0; ServerHandle = -1; ServerState = ssNone; ClientHandle = -1; ClientState = ssNone; } //--------------------------------------------------------------------------- CSocketCore::~CSocketCore() { } //--------------------------------------------------------------------------- int CSocketCore::OpenTCPserverSocket( const char *pAddress, int pPortNo, bool KeepAlive ) { socklen_t addr_len; struct sockaddr_in address; strcpy( ServerAddress, pAddress ); PortNo = pPortNo; // Socket options struct linger ServerLinger_opt; ServerLinger_opt.l_onoff = 1; ServerLinger_opt.l_linger = 5; int Reuse_opt = 1; int KeepAlive_opt = 1; int TCPidle_opt = 60; int TCPint_opt = 15; int TCPcnt_opt = 3; // Create address address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr(ServerAddress); address.sin_port = htons(PortNo); addr_len = sizeof(address); // Set default socket state ServerState = ssNone; // Create socket if ((ServerHandle = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf( "Server Socket: %s [%d] -> Failed to create server socket (%s)\n", Name, PortNo, strerror(errno) ); ServerState = ssFailed; return -1; }; // Configure connection if ((setsockopt( ServerHandle, SOL_SOCKET, SO_LINGER, &ServerLinger_opt, sizeof(ServerLinger_opt)) == -1) || (setsockopt( ServerHandle, SOL_SOCKET, SO_REUSEADDR, &Reuse_opt, sizeof(Reuse_opt)) == -1)) { printf( "Server Socket: %s [%d] -> Could not set socket options (%s)\n", Name, PortNo, strerror(errno) ); ServerState = ssFailed; return -1; } // Configure TCP keep alive settings if (KeepAlive && ((setsockopt( ServerHandle, SOL_SOCKET, SO_KEEPALIVE, &KeepAlive_opt, sizeof(KeepAlive_opt)) == -1) || (setsockopt( ServerHandle, SOL_TCP, TCP_KEEPIDLE, &TCPidle_opt, sizeof(TCPidle_opt)) == -1) || (setsockopt( ServerHandle, SOL_TCP, TCP_KEEPCNT, &TCPcnt_opt, sizeof(TCPcnt_opt)) == -1) || (setsockopt( ServerHandle, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) )) { printf( "Server Socket: %s [%d] -> Could not set socket keepalive options (%s)\n", Name, PortNo, strerror(errno) ); ServerState = ssFailed; return -1; } // Bind socket if (bind( ServerHandle, (struct sockaddr *)&address, addr_len ) < 0) { printf( "Server Socket: %s [%d] -> Failed to bind server to socket (%s)\n", Name, PortNo, strerror(errno) ); close( ServerHandle ); ServerState = ssFailed; return -1; }; // Create que for 5 connections if (listen( ServerHandle, 5 ) < 0) { printf( "Server Socket: %s [%d] -> Failed to create server socket listen que (%s)\n", Name, PortNo, strerror(errno) ); close( ServerHandle ); ServerState = ssFailed; return -1; }; // Server open ServerState = ssOpen; printf( "Server Socket: %s [%d] -> Socket binded and listening\n", Name, PortNo ); return ServerHandle; } //--------------------------------------------------------------------------- int CSocketCore::OpenTCPinClientSocket() { socklen_t addr_len; struct sockaddr_in address; // Set default socket state if (ClientHandle == -1) { // Accept connection on current socket addr_len = sizeof( address ); if ((ClientHandle = accept( ServerHandle, (struct sockaddr *)&address, &addr_len)) == -1) { if (errno == EWOULDBLOCK) printf( "Remote Socket: %s [*] -> Failed to accept blocking connection (%s)\n", Name, strerror(errno) ); else printf( "Remote Socket: %s [*] -> Failed to accept connection (%s)\n", Name, strerror(errno) ); close( ClientHandle ); return -1; } // Return client address strcpy( ClientAddress, inet_ntoa(address.sin_addr) ); ClientState = ssOpen; printf( "Remote Socket: %s -> Server accepted connection from client (%s)\n", Name, ClientAddress ); } else if (ClientState == ssWaitingtoOpen) { // Clear non blocking flag int flags = fcntl( ClientHandle, F_GETFL, 0 ); fcntl( ClientHandle, F_SETFL, (!O_NONBLOCK)&flags ); // Log event printf( "Socket: %s -> Client now connected to server (%s)\n", Name, ServerAddress ); // Trigger handler & set new state ClientState = ssOpen; } return ClientHandle; } //--------------------------------------------------------------------------- int CSocketCore::OpenTCPoutClientSocket( const char *pAddress, int pPortNo, bool KeepAlive ) { socklen_t addr_len; struct sockaddr_in address; strcpy( ServerAddress, pAddress ); PortNo = pPortNo; // Socket options int KeepAlive_opt = 1; int TCPidle_opt = 5; int TCPcnt_opt = 3; int TCPint_opt = 2; // Set default socket state ClientState = ssNone; // Create File descriptor if ((ClientHandle = socket( AF_INET, SOCK_STREAM, 0 )) < 0) { printf( "Client Socket: %s [*] -> Failed to create Client Socket (%s)\n", Name, strerror(errno) ); return -1; }; // Set Non blocking open int flags = fcntl( ClientHandle, F_GETFL, 0 ); fcntl( ClientHandle, F_SETFL, O_NONBLOCK|flags ); // Configure TCP keep alive settings if (KeepAlive && ((setsockopt( ClientHandle, SOL_SOCKET, SO_KEEPALIVE, &KeepAlive_opt, sizeof(KeepAlive_opt)) == -1) || (setsockopt( ClientHandle, SOL_TCP, TCP_KEEPIDLE, &TCPidle_opt, sizeof(TCPidle_opt)) == -1) || (setsockopt( ClientHandle, SOL_TCP, TCP_KEEPCNT, &TCPcnt_opt, sizeof(TCPcnt_opt)) == -1) || (setsockopt( ClientHandle, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) )) { printf( "Client Socket: %s -> Could not set socket keepalive options (%s)\n", Name, strerror(errno) ); return -1; } // Declare address address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr( ServerAddress ); address.sin_port = htons(PortNo); addr_len = sizeof(address); if (!connect( ClientHandle, (struct sockaddr *)&address, addr_len )) { // Set status ClientState = ssOpen; return ClientHandle; } else if (errno == EINPROGRESS) { // Set status ClientState = ssWaitingtoOpen; return ClientHandle; } else { printf( "Client Socket: %s -> Client failed to connect (%s)\n", Name, strerror(errno) ); // Set status ClientState = ssFailed; // Close socket close( ClientHandle ); return -1; } } //--------------------------------------------------------------------------- // Delete socket bool CSocketCore::CloseTCPSocket( ESockConnectType SocketType ) { bool Fail; if (SocketType == ctServer) { Fail = (close( ServerHandle ))? true : false; ServerState = ((Fail)? ssFailed : ssClosed); } else { Fail = (close( ClientHandle ))? true : false; ClientState = ((Fail)? ssFailed : ssClosed); } // Show action switch (SocketType) { case ctServer: printf( "Server Socket: %s -> Server %s\n", Name, ((Fail)? "failed" : "closed") ); break; case ctRemoteClient: printf( "Remote Client: %s -> Connection to client %s\n", Name, ((Fail)? "failed" : "closed") ); break; case ctClient: printf( "Client Socket: %s -> Connection to server %s\n", Name, ((Fail)? "failed" : "closed") ); break; case ctNone: default: printf( "Socket : %s -> Cannot %s socket (invalid socket type)\n", Name, ((Fail)? "fail" : "close") ); break; }; return true; } //--------------------------------------------------------------------------- int CSocketCore::Input( int InputID, char * Data, int Len ) { return WriteToFD( ClientHandle, Data, Len ); } //--------------------------------------------------------------------------- bool CSocketCore::Read( int FD ) { int SockBytesRead = 0; int SockBytesWaiting = 0; // Check if anything to read ioctl( FD, FIONREAD, &SockBytesWaiting ); // Test for close event if (!SockBytesWaiting) { // EOF from server (close connection) CloseTCPSocket( ctRemoteClient ); ClientHandle = -1; return false; } // Check if socket ready (non-block open not in progress) else if (ClientState == ssWaitingtoOpen) { printf( "Socket: %s -> Cannot read from socket in waiting\n", Name ); SockBytesWaiting = 0; } // Handle incoming data else { // Read data from socket if (!(SockBytesRead = Buffer->ReadFromFD( FD, SockBytesWaiting ))) { return false; } // Process Buffer ProcessBuffer( false ); // Start timer SetStartTime( &InStart ); } return true; } //--------------------------------------------------------------------------- bool CSocketCore::ProcessBuffer( bool Force ) { int Pos = 0; int Len = 0; char * Data = NULL; // Check if buffered data if (!Buffer->Len()) { return false; } // Check if forced processed if (Force) { // Show Packet Len = Buffer->Peek( &Data ); ShowOutput( "Port In", OUT_NORMAL, Data, Len ); // Write buffer to Port if (OutFunction) OutFunction->Input( 0, Data, Len ); // Clear processed bytes from buffer Buffer->Clear( Len ); } else { // Search for end of packet marker while (Buffer->FindChar( '\n', Pos )) { // Show Packet Len = Buffer->Peek( &Data, 0, Pos+1 ); ShowOutput( "Port In", OUT_NORMAL, Data, Len ); // Write buffer to Port if (OutFunction) OutFunction->Input( 0, Data, Len ); // Clear processed bytes from buffer Buffer->Clear( Len ); } } return true; } //---------------------------------------------------------------------------