/* * SocketCore.h * * Created on: 13 May 2016 * Author: wentzelc */ // redA Libraries #include "TimingCore.h" #include "SocketCore.h" // Standard C/C++ Libraries #include #include #include #include #include #include #include #include #include #include #include #include //--------------------------------------------------------------------------- // Variables char * ServerName = NULL; char ServerAddress[25] = ""; int PortNo = 0; char ClientAddress[25] = ""; int ServerHandle = -1; ESocketState ServerState = ssNone; int ClientHandle = -1; ESocketState ClientState = ssNone; char SockInBuffer[500] = ""; int SockInBufLen = 500; int SockInLen = 0; // SockIn Timer timeval SockInStart = { 0, 0 }; long SockInTimeout = 100; // millisecs int SockBytesRead = 0; int SockBytesWaiting = 0; //--------------------------------------------------------------------------- int OpenTCPserverSocket( const char *pName, const char *pAddress, int pPortNo, bool KeepAlive ) { socklen_t addr_len; struct sockaddr_in address; ServerName = (char*)malloc( strlen(pName)+1 ); strcpy( ServerName, pName ); 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", ServerName, 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", ServerName, 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", ServerName, 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", ServerName, 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", ServerName, PortNo, strerror(errno) ); close( ServerHandle ); ServerState = ssFailed; return -1; }; // Server open ServerState = ssOpen; printf( "Server Socket: %s [%d] -> Socket binded and listening\n", ServerName, PortNo ); return ServerHandle; } //--------------------------------------------------------------------------- int 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", ServerName, strerror(errno) ); else printf( "Remote Socket: %s [*] -> Failed to accept connection (%s)\n", ServerName, 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", ServerName, 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", ServerName, ServerAddress ); // Trigger handler & set new state ClientState = ssOpen; } return ClientHandle; } //--------------------------------------------------------------------------- int OpenTCPoutClientSocket( const char *pName, const char *pAddress, int pPortNo, bool KeepAlive ) { socklen_t addr_len; struct sockaddr_in address; ServerName = (char*)malloc( strlen(pName)+1 ); strcpy( ServerName, pName ); 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", ServerName, 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", ServerName, 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", ServerName, strerror(errno) ); // Set status ClientState = ssFailed; // Close socket close( ClientHandle ); return -1; } } //--------------------------------------------------------------------------- // Delete socket bool 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", ServerName, ((Fail)? "failed" : "closed") ); break; case ctRemoteClient: printf( "Remote Client: %s -> Connection to client %s\n", ServerName, ((Fail)? "failed" : "closed") ); break; case ctClient: printf( "Client Socket: %s -> Connection to server %s\n", ServerName, ((Fail)? "failed" : "closed") ); break; case ctNone: default: printf( "Socket : %s -> Cannot %s socket (invalid socket type)\n", ServerName, ((Fail)? "fail" : "close") ); break; }; return true; } //--------------------------------------------------------------------------- bool ReadClientSocket() { // Check if anything to read ioctl( ClientHandle, 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", ServerName ); SockBytesWaiting = 0; } // Handel incoming data else { // Read data into buffer SockBytesRead = read( ClientHandle, &SockInBuffer[SockInLen], SockBytesWaiting ); // SockInBufLen-SockInLen // Check of errors if (SockBytesRead == -1) { printf( "Socket: %s -> Cannot read from socket (%s)\n", ServerName, strerror(errno) ); SockBytesRead = 0; // Check of non-blocking write // bool Blocked = ((errno == EAGAIN)? true : false ); } else if (SockBytesRead > 0) { // Process Reply SockInLen += SockBytesRead; // Reset timer SetStartTime( &SockInStart ); } } return true; } //--------------------------------------------------------------------------- bool MaintainSocket( int PortHandle ) { // Init vars long Duration = 0; int BytesWritten = 0; int StartWrite = 0; if (SockInLen > 0) { // Check duration since last PortIn Duration = TimePassed( SockInStart ); if (Duration > SockInTimeout) { // Handle buffer as packet SockInBuffer[ SockInLen ] = 0; //ShowOutput( "Sock", SockInBuffer, SockInLen, Duration ); // Write output to Port BytesWritten = 0; StartWrite = 0; if (PortHandle != -1) { while (StartWrite < SockInLen) { BytesWritten = write( PortHandle, &SockInBuffer[StartWrite], SockInLen ); StartWrite += BytesWritten; } } // Reset buffer and timer SockInLen = 0; SetInterval( &SockInStart, 0 ); } } return true; } //---------------------------------------------------------------------------