aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ppsocket.cc
diff options
context:
space:
mode:
authorFritz Elfert <felfert@to.com>1999-06-28 08:56:01 +0000
committerFritz Elfert <felfert@to.com>1999-06-28 08:56:01 +0000
commit34b70b0b46e34a73308a4034cc9b1c70209b9eb4 (patch)
tree7abe8be40fde08828d3606e13c41435b2fc9a26c /lib/ppsocket.cc
parent3d3be141551bb4622da1cb610e4f6f798dd1715e (diff)
downloadplptools-34b70b0b46e34a73308a4034cc9b1c70209b9eb4.tar.gz
plptools-34b70b0b46e34a73308a4034cc9b1c70209b9eb4.tar.bz2
plptools-34b70b0b46e34a73308a4034cc9b1c70209b9eb4.zip
First import.
Diffstat (limited to 'lib/ppsocket.cc')
-rw-r--r--lib/ppsocket.cc863
1 files changed, 863 insertions, 0 deletions
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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <iostream.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#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<l; i++) {
+ unsigned char cc = a.getByte(i);
+ if (cc == '\0' || cc == '\\') {
+ s.addByte('\\');
+ }
+ s.addByte(cc);
+ }
+ s.addByte('\0');
+
+ {
+ int tosend, sent, retries, i;
+
+ tosend = s.getLen();
+ sent = retries = 0;
+
+ while (tosend > 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;
+}