From 34b70b0b46e34a73308a4034cc9b1c70209b9eb4 Mon Sep 17 00:00:00 2001 From: Fritz Elfert Date: Mon, 28 Jun 1999 08:56:01 +0000 Subject: First import. --- lib/ppsocket.cc | 863 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 863 insertions(+) create mode 100644 lib/ppsocket.cc (limited to 'lib/ppsocket.cc') diff --git a/lib/ppsocket.cc b/lib/ppsocket.cc new file mode 100644 index 0000000..c9ef495 --- /dev/null +++ b/lib/ppsocket.cc @@ -0,0 +1,863 @@ +// +// PLP - An implementation of the PSION link protocol +// +// Copyright (C) 1999 Philip Proudman +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// e-mail philip.proudman@btinternet.com + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../defaults.h" +#include "bool.h" +#include "bufferstore.h" +#include "ppsocket.h" + +//********************************************************************** +// For unix we need a few definitions +//********************************************************************** + +#ifndef MAKEWORD +#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8)) +#endif +#ifndef SHORT +#define SHORT int +#endif + +//This constructor is useful when converting a socket +//to a derived class of socket +ppsocket::ppsocket(const ppsocket& another) +{ + m_Socket = another.m_Socket; + m_HostAddr = another.m_HostAddr; + m_PeerAddr = another.m_PeerAddr; + m_Bound = another.m_Bound; + m_Timeout = another.m_Timeout; + m_LastError = another.m_LastError; + + m_Timeout = INFINITE; +} + + +ppsocket::ppsocket() +{ + m_Socket = INVALID_SOCKET; + + memset(&m_HostAddr, 0, sizeof(m_HostAddr)); + memset(&m_PeerAddr, 0, sizeof(m_PeerAddr)); + + + ((struct sockaddr_in*) &m_HostAddr)->sin_family = AF_INET; + ((struct sockaddr_in*) &m_PeerAddr)->sin_family = AF_INET; + + m_Bound = false; + + m_Timeout = INFINITE; +} + + +ppsocket::~ppsocket() +{ + if (m_Socket != INVALID_SOCKET) + { + close(m_Socket); + } +} + + +bool ppsocket::startup(void) +{ +#ifdef WIN32 + WSADATA wd; + m_LastError = WSAStartup(MAKEWORD(1, 1), &wd); +#else + m_LastError = 0; +#endif + + return(m_LastError == 0 ? true : false); +} + +//pre : must be bound and peer info set +bool ppsocket::reconnect() +{ + printPeer(); + if (::connect(m_Socket, &m_PeerAddr, sizeof(m_PeerAddr)) != 0) + { + m_LastError = lastErrorCode(); + cout << "Reconnect failed : status : " << m_LastError << endl << flush; + return(false); + } + return(true); +} + + +void ppsocket::printPeer() +{ + char* pPeer = 0; + int port; + + pPeer = inet_ntoa(((struct sockaddr_in*) &m_PeerAddr)->sin_addr); + if (pPeer) + { + port = ntohs(((struct sockaddr_in*) &m_PeerAddr)->sin_port); + cout << "Peer : " << pPeer << " Port : " << port << endl; + } + else + { + cout << "Error getting Peer details\n"; + } +} + +bool ppsocket::connect(char* Peer, int PeerPort, char* Host, int HostPort) +{ + + //**************************************************** + //* If we aren't already bound set the host and bind * + //**************************************************** + + if (!bindSocket(Host, HostPort)) + { + if (m_LastError != 0) + { + return(false); + } + } + + //**************** + //* Set the peer * + //**************** + if (!setPeer(Peer, PeerPort)) + { + return(false); + } + + //*********** + //* Connect * + //*********** + if (::connect(m_Socket, &m_PeerAddr, sizeof(m_PeerAddr)) != 0) + { + m_LastError = lastErrorCode(); + return(false); + } + + return(true); +} + + + +bool ppsocket::listen(char* Host, int Port) +{ + //**************************************************** + //* If we aren't already bound set the host and bind * + //**************************************************** + + if (!bindSocket(Host, Port)) + { + if (m_LastError != 0) + { + return(false); + } + } + + //********************** + //* Listen on the port * + //********************** + + if (::listen(m_Socket, 5) != 0) + { + m_LastError = lastErrorCode(); + return(false); + } + + return(true); +} + + +ppsocket* ppsocket::accept(char* Peer, int MaxLen) +{ + unsigned int len; + ppsocket* accepted; + char* peer; + + //***************************************************** + //* Allocate a new object to hold the accepted socket * + //***************************************************** + + accepted = new ppsocket; + + if (!accepted) + { + m_LastError = lastErrorCode(); + return(NULL); + } + + //*********************** + //* Accept a connection * + //*********************** + + len = sizeof(struct sockaddr); + fcntl(m_Socket, F_SETFL, O_NONBLOCK); + accepted->m_Socket = ::accept(m_Socket, &accepted->m_PeerAddr, &len); + + if (accepted->m_Socket == INVALID_SOCKET) + { + m_LastError = lastErrorCode(); + delete accepted; + return (NULL); + } + + //**************************************************** + //* Got a connection so fill in the other attributes * + //**************************************************** + + accepted->m_HostAddr = m_HostAddr; + accepted->m_Bound = true; + + //**************************************************** + //* If required get the name of the connected client * + //**************************************************** + + if (Peer) + { + peer = inet_ntoa(((struct sockaddr_in*) &accepted->m_PeerAddr)->sin_addr); + if (peer) + { + strncpy(Peer, peer, MaxLen); + Peer[MaxLen] = '\0'; + } + } + else + { + strcpy(Peer, ""); + } + + return(accepted); +} + + +int ppsocket::printf(const char* Format, ...) +{ int i; +va_list ap; +char s[512]; + +va_start(ap, Format); +vsprintf(s, Format, ap); +va_end(ap); + +i = writeTimeout(s, strlen(s), 0); + +return(i); +} + +bool ppsocket::dataToGet() const { + fd_set io; + FD_ZERO(&io); + FD_SET(m_Socket, &io); + struct timeval t; + t.tv_usec = 0; + t.tv_sec = 0; + return (select(m_Socket+1, &io, NULL, NULL, &t) != 0) ? true : false; +} + +int ppsocket::getBufferStore(bufferStore &a, bool wait) { + /* Returns a 0 for for no message, 1 for message OK, and -1 for socket problem */ + if (!wait && !dataToGet()) return 0; + a.init(); + bool hadEscape = false; + do { + char data; + int j = readTimeout(&data, 1, 0); + if (j == SOCKET_ERROR || j == 0) { + return -1; + } + if (hadEscape) { + a.addByte(data); + hadEscape = false; + } + else { + if (data == '\\') + hadEscape = true; + else if (data == '\0') + break; + else + a.addByte(data); + } + } while (true); +#ifdef SOCKET_DIAGNOSTICS + cout << "ppsocket got " << a << endl; +#endif + return (a.getLen() == 0) ? 0 : 1; +} + +bool ppsocket::sendBufferStore(const bufferStore &a) { +#ifdef SOCKET_DIAGNOSTICS + cout << "ppsocket sending " << a << endl; +#endif + bufferStore s; + long l = a.getLen(); + for (long i = 0; i 0) + { + i = writeTimeout(s.getString(sent), tosend, 0); + + if (i == SOCKET_ERROR || i == 0) + return( false); + + sent += i; + tosend -= i; + + if (++retries > 5) + { + m_LastError = 0; + return(false); + } + } + } + return true; +} + +int ppsocket::readEx(char* Data, int cTerm, int MaxLen) +{ + int i, j; + + for (i = 0; i < MaxLen; i++) + { + j = readTimeout(Data + i, 1, 0); + + if (j == SOCKET_ERROR || j == 0) + { + Data[i] = '\0'; + return(i > 0 ? i : 0); + } + + if (Data[i] == cTerm) + break; + } + + return(i+1); +} + +bool ppsocket::puts(const char* Data) +{ + int tosend, sent, retries, i; + + tosend = strlen(Data); + sent = retries = 0; + + while (tosend > 0) + { + i = writeTimeout(Data + sent, tosend, 0); + + if (i == SOCKET_ERROR || i == 0) + return(sent > 0 ? true : false); + + sent += i; + tosend -= i; + + if (++retries > 5) + { + m_LastError = 0; + return(false); + } + } + + return(true); +} + + + +char ppsocket::sgetc(void) +{ + int i; + char c; + + i = readTimeout(&c, 1, 0); + if (i == SOCKET_ERROR || i == 0) + { + return(0); + } + return(c); +} + + +bool ppsocket::sputc(char c) +{ + int i; + + cout << hex << (int)c << endl; + + i = writeTimeout(&c, 1, 0); + + if (i == SOCKET_ERROR || i == 0) + { + return(false); + } + + return(true); +} + + +int ppsocket::read(void* Data, size_t Size, size_t NumObj) +{ + int i = readTimeout((char*) Data, Size*NumObj, 0); + + return(i); +} + + +int ppsocket::write(const void* Data, size_t Size, size_t NumObj) +{ + int i = writeTimeout((char*) Data, Size*NumObj, 0); + + return(i); +} + + +int ppsocket::recv(char* buf, int len, int flags) +{ + int i = ::recv(m_Socket, buf, len, flags); + + if (i < 0) + m_LastError = lastErrorCode(); + + return(i); +} + + +int ppsocket::send(const char* buf, int len, int flags) +{ + int i = ::send(m_Socket, buf, len, flags); + + if (i < 0) + m_LastError = lastErrorCode(); + + return(i); +} + + +int ppsocket::readTimeout(char* buf, int len, int flags) +{ + int i; + + //********************************************************* + //* If there is no timeout use the Berkeley recv function * + //********************************************************* + + if (m_Timeout == INFINITE) + { + i = ::recv(m_Socket, buf, len, flags); + + if (i == SOCKET_ERROR) + { + m_LastError = lastErrorCode(); + } + } + + //******************************************** + //* If there is a timeout use overlapped i/o * + //******************************************** + + else + { + i = SOCKET_ERROR; + } + + + return(i); +} + + +int ppsocket::writeTimeout(const char* buf, int len, int flags) +{ + int i; + // If there is no timeout use the Berkeley send function + + if (m_Timeout == INFINITE) + { + i = ::send(m_Socket, buf, len, flags); + + if (i == SOCKET_ERROR) + { + m_LastError = lastErrorCode(); + } + } + else + { + // If there is a timeout use overlapped i/o + i = SOCKET_ERROR; + } + + return(i); +} + +bool ppsocket::closeSocket(void) +{ + if (close(m_Socket) != 0) + { + m_LastError = lastErrorCode(); + return(false); + } + + m_Socket = INVALID_SOCKET; + + return(true); +} + + +bool ppsocket::bindSocket(char* Host, int Port) +{ + + // If we are already bound return FALSE but with no last error + + m_LastError = 0; + + if (m_Bound) + { + return(false); + } + + // If the socket hasn't been created create it now + + if (m_Socket == INVALID_SOCKET) + { + if (!createSocket()) + { + return(false); + } + } + + // If a host name was supplied then use it + if (!setHost(Host, Port)) + { + return(false); + } + + // Now bind the socket + if (::bind(m_Socket, &m_HostAddr, sizeof(m_HostAddr)) != 0) + { + m_LastError = lastErrorCode(); + return(false); + } + + m_Bound = true; + + return(true); +} + + +bool ppsocket::bindInRange(char* Host, int Low, int High, int Retries) +{ + int port, i; + + // If we are already bound return FALSE but with no last error + + m_LastError = 0; + + if (m_Bound) + { + return(false); + } + + // If the socket hasn't been created create it now + + if (m_Socket == INVALID_SOCKET) + { + if (!createSocket()) + { + return(false); + } + } + // If the number of retries is greater than the range then work through the + // range sequentially. + + if (Retries > High - Low) + { + for (port = Low; port <= High; port++) + { + if (!setHost(Host, port)) + return(false); + + if (::bind(m_Socket, &m_HostAddr, sizeof(m_HostAddr)) == 0) + break; + } + + if (port > High) + { + m_LastError = lastErrorCode(); + return(false); + } + } + + // Else select numbers within the range at random + + else + { + for (i = 0; i < Retries; i++) + { + port = Low + (rand() % (High - Low)); + + if (!setHost(Host, port)) + return(false); + + if (::bind(m_Socket, &m_HostAddr, sizeof(m_HostAddr)) == 0) + break; + } + + if (i >= Retries) + { + m_LastError = lastErrorCode(); + return(false); + } + } + + m_Bound = true; + + return(true); +} + +bool ppsocket::linger(bool LingerOn, int LingerTime) +{ + int i; + struct linger l; + + // If the socket hasn't been created create it now + + if (m_Socket == INVALID_SOCKET) + { + if (!createSocket()) + { + return(false); + } + } + // Set the lingering + + if (LingerOn) + { + l.l_onoff = 1; + l.l_linger = LingerTime; + } + else + { + l.l_onoff = 0; + l.l_linger = 0; + } + i = setsockopt(m_Socket, SOL_SOCKET, SO_LINGER, (const char*) &l, sizeof(l)); + + // Check for errors + + if (i != 0) + { + m_LastError = lastErrorCode(); + return(false); + } + + // Return indicating success + + return(true); +} + + +bool ppsocket::createSocket(void) +{ + // If the socket has already been created just return true + if (m_Socket != INVALID_SOCKET) + { + return(true); + } + + // Create the socket + m_Socket = ::socket(PF_INET, SOCK_STREAM, 0); + + if (m_Socket == INVALID_SOCKET) + { + m_LastError = lastErrorCode(); + return(false); + } + + // By default set no lingering + + linger(FALSE, 0); + + // Return indicating success + + return(true); +} + +bool ppsocket::setPeer(char* Peer, int Port) +{ + struct hostent* he; + + // If a peer name was supplied then use it + if (Peer) + { + he = gethostbyname(Peer); + if (!he) + { + unsigned long ipaddress = inet_addr(Peer); + if (ipaddress == INADDR_NONE) + { + m_LastError = lastErrorCode(); + return(false); + } + + he = gethostbyaddr((const char*) &ipaddress, 4, PF_INET); + if (!he) + { + m_LastError = lastErrorCode(); + return(false); + } + } + memcpy((void*) &((struct sockaddr_in*) &m_PeerAddr)->sin_addr, (void*) he->h_addr_list[0], 4); + } + + // If a port name was supplied use it + + if (Port > 0) + { + ((struct sockaddr_in*) &m_PeerAddr)->sin_port = htons((SHORT) Port); + } + + return(true); +} + + +bool ppsocket::getPeer(char* Peer, int MaxLen, int* Port) +{ + char* peer; + + if (Peer) + { + peer = inet_ntoa(((struct sockaddr_in*) &m_PeerAddr)->sin_addr); + + if (!peer) + { + m_LastError = lastErrorCode(); + return(false); + } + + strncpy(Peer, peer, MaxLen); + Peer[MaxLen] = '\0'; + } + + if (Port) + { + *Port = ntohs(((struct sockaddr_in*) &m_PeerAddr)->sin_port); + } + + return(false); +} + + +bool ppsocket::setHost(char* Host, int Port) +{ + struct hostent* he; + + // If a host name was supplied then use it + if (Host) + { + he = gethostbyname(Host); + + if (!he) + { + unsigned long ipaddress = inet_addr(Host); + if (ipaddress == INADDR_NONE) + { + m_LastError = lastErrorCode(); + return(false); + } + + he = gethostbyaddr((const char*) &ipaddress, 4, PF_INET); + + if (!he) + { + m_LastError = lastErrorCode(); + return(false); + } + } + + memcpy((void*) &((struct sockaddr_in*) &m_HostAddr)->sin_addr, (void*) he->h_addr_list[0], 4); + } + + + // If a port name was supplied use it + + if (Port > 0) + { + ((struct sockaddr_in*) &m_HostAddr)->sin_port = htons((SHORT) Port); + } + + return(true); +} + + +bool ppsocket::getHost(char* Host, int MaxLen, int* Port) +{ + char* host; + + if (Host) + { + host = inet_ntoa(((struct sockaddr_in*) &m_HostAddr)->sin_addr); + + if (!host) + { + m_LastError = lastErrorCode(); + return(false); + } + + strncpy(Host, host, MaxLen); + Host[MaxLen] = '\0'; + } + + if (Port) + { + *Port = ntohs(((struct sockaddr_in*) &m_HostAddr)->sin_port); + } + return(false); +} + +DWORD ppsocket::lastErrorCode() +{ + return errno; +} + +void ppsocket::setSocketInvalid() +{ + m_Socket = INVALID_SOCKET; +} -- cgit v1.2.3