diff options
Diffstat (limited to 'debian/htdig/htdig-3.2.0b6/htnet/Connection.cc')
-rw-r--r-- | debian/htdig/htdig-3.2.0b6/htnet/Connection.cc | 861 |
1 files changed, 861 insertions, 0 deletions
diff --git a/debian/htdig/htdig-3.2.0b6/htnet/Connection.cc b/debian/htdig/htdig-3.2.0b6/htnet/Connection.cc new file mode 100644 index 00000000..e6781db9 --- /dev/null +++ b/debian/htdig/htdig-3.2.0b6/htnet/Connection.cc @@ -0,0 +1,861 @@ +// +// Connection.cc +// +// Connection: This class forms a easy to use interface to the berkeley +// tcp socket library. All the calls are basically the same, +// but the parameters do not have any stray _addr or _in +// mixed in... +// +// Part of the ht://Dig package <http://www.htdig.org/> +// Copyright (c) 1999-2004 The ht://Dig Group +// For copyright details, see the file COPYING in your distribution +// or the GNU Library General Public License (LGPL) version 2 or later +// <http://www.gnu.org/copyleft/lgpl.html> +// +// $Id: Connection.cc,v 1.10 2004/05/28 13:15:22 lha Exp $ +// +#ifdef HAVE_CONFIG_H +#include "htconfig.h" +#endif /* HAVE_CONFIG_H */ + +#include "Connection.h" +#include "Object.h" +#include "List.h" + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> + +#ifdef _MSC_VER /* _WIN32 */ +#include <windows.h> +#include <winsock.h> +#define EALREADY WSAEALREADY +#define EISCONN WSAEISCONN +#else +#include <sys/socket.h> +#include <arpa/inet.h> // For inet_ntoa +#include <netinet/in.h> +#include <netdb.h> +#include <sys/ioctl.h> +#include <sys/uio.h> +#endif + +#ifndef _MSC_VER /* _WIN32 */ +#include <sys/file.h> +#include <sys/time.h> +#else +#include <io.h> +#endif + +#include <signal.h> +#include <fcntl.h> +#include <stdlib.h> + +#ifndef _MSC_VER /* _WIN32 */ +#include <unistd.h> +#endif + +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +typedef void (*SIGNAL_HANDLER) (...); + +#ifndef _MSC_VER /* _WIN32 */ +extern "C" { + int rresvport(int *); +} +#endif + +#undef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) + +List all_connections; + +//************************************************************************* +// Connection::Connection(int socket) +// - Default constructor +// PURPOSE: +// Create a connection from just a socket. +// PARAMETERS: +// int socket: obvious!!!! +// +//************************************************************************* +Connection::Connection(int socket) +: pos(0), pos_max(0), + sock(socket), connected(0), peer(""), server_name(""), server_ip_address(""), + need_io_stop(0), timeout_value(0), retry_value(1), + wait_time(5) // wait 5 seconds after a failed connection attempt +{ + Win32Socket_Init(); + + if (socket > 0) + { + GETPEERNAME_LENGTH_T length = sizeof(server); + if (getpeername(socket, (struct sockaddr *)&server, &length) < 0) + perror("getpeername"); + } + + all_connections.Add(this); +} + +// Copy constructor +Connection::Connection(const Connection& rhs) +: pos(rhs.pos), pos_max(rhs.pos_max), + sock(rhs.sock), connected(rhs.connected), + peer(rhs.peer), server_name(rhs.server_name), server_ip_address(rhs.server_ip_address), + need_io_stop(rhs.need_io_stop), timeout_value(rhs.timeout_value), + retry_value(rhs.retry_value), + wait_time(rhs.wait_time) // wait 5 seconds after a failed connection attempt +{ + all_connections.Add(this); +} + + +//***************************************************************************** +// Connection::~Connection() +// +Connection::~Connection() +{ + all_connections.Remove(this); + this->Close(); +} + + +//***************************************************************************** +// int Connection::Win32Socket_init(void) +// +// This function is only used when Code is compiled as a Native Windows +// application +// +// The native Windows socket system needs to be initialized. +// +int Connection::Win32Socket_Init(void) +{ +#ifdef _MSC_VER /* _WIN32 */ + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD(2, 2); + + if (WSAStartup(wVersionRequested, &wsaData)) + return(-1); + + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 ) { + WSACleanup(); + return(-1); + } +#endif + + return(0); +} +//***************************************************************************** +// int Connection::Open(int priv) +// +int Connection::Open(int priv) +{ + if (priv) + { + int aport = IPPORT_RESERVED - 1; + +// Native Windows (MSVC) has no rresvport +#ifndef _MSC_VER /* _WIN32 */ + sock = rresvport(&aport); +#else + return NOTOK; +#endif + } + else + { + sock = socket(AF_INET, SOCK_STREAM, 0); + //cout << "socket() sock=" << sock << endl; + } + + if (sock == NOTOK) + return NOTOK; + + int on = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); + server.sin_family = AF_INET; + + return OK; +} + + +//***************************************************************************** +// int Connection::Ndelay() +// +int Connection::Ndelay() +{ +#ifndef _MSC_VER /* _WIN32 */ + return fcntl(sock, F_SETFL, FNDELAY); +#else + // Note: This function is never called + // TODO: Look into ioctsocket(..) of Win32 Socket API + return(0); +#endif +} + + +//***************************************************************************** +// int Connection::Nondelay() +// +int Connection::Nondelay() +{ +#ifndef _MSC_VER /* _WIN32 */ + return fcntl(sock, F_SETFL, 0); +#else + // Note: This function is never called + // TODO: Look into ioctsocket(..) of Win32 Socket API + return(0); +#endif +} + +//***************************************************************************** +// int Connection::Timeout(int value) +// +int Connection::Timeout(int value) +{ + int oval = timeout_value; + timeout_value = value; + return oval; +} + +//***************************************************************************** +// int Connection::retries(int value) +// +int Connection::Retries(int value) +{ + int oval = retry_value; + retry_value = value; + return oval; +} + +//***************************************************************************** +// int Connection::Close() +// +int Connection::Close() +{ + connected = 0; + if (sock >= 0) + { + int ret = close(sock); + sock = -1; + return ret; + } + return NOTOK; +} + + +//***************************************************************************** +// int Connection::Assign_Port(int port) +// +int Connection::Assign_Port(int port) +{ + server.sin_port = htons(port); + return OK; +} + + +//***************************************************************************** +// int Connection::Assign_Port(char *service) +// +int Connection::Assign_Port(const String &service) +{ + struct servent *sp; + + sp = getservbyname(service, "tcp"); + if (sp == 0) + { + return NOTOK; + } + server.sin_port = sp->s_port; + return OK; +} + +//***************************************************************************** +// int Connection::Assign_Server(unsigned int addr) +// +int Connection::Assign_Server(unsigned int addr) +{ + server.sin_addr.s_addr = addr; + return OK; +} + +#ifndef _MSC_VER /* _WIN32 */ +//extern "C" unsigned int inet_addr(char *); +#endif + +//***************************************************************************** +// +int Connection::Assign_Server(const String& name) +{ + struct hostent *hp; + char **alias_list; + unsigned int addr; + + // + // inet_addr arg IS const char even though prototype says otherwise + // + addr = inet_addr((char*)name.get()); + if (addr == (unsigned int)~0) + { + // Gets the host given a string + hp = gethostbyname(name); + + if (hp == 0) + return NOTOK; + + alias_list = hp->h_aliases; + memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); + } + else + { + memcpy((char *)&server.sin_addr, (char *)&addr, sizeof(addr)); + } + + server_name = name.get(); + server_ip_address = inet_ntoa(server.sin_addr); + + return OK; +} + +// +// Do nothing, we are only interested in the EINTR return of the +// running system call. +// +static void handler_timeout(int) { +} + +//***************************************************************************** +// int Connection::Connect() +// +int Connection::Connect() +{ + int status; + int retries = retry_value; + + while (retries--) + { +#ifndef _MSC_VER /* _WIN32 */ + // + // Set an alarm to make sure the connect() call times out + // appropriately This ensures the call won't hang on a + // dead server or bad DNS call. + // Save the previous alarm signal handling policy, if any. + // + struct sigaction action; + struct sigaction old_action; + memset((char*)&action, '\0', sizeof(struct sigaction)); + memset((char*)&old_action, '\0', sizeof(struct sigaction)); + action.sa_handler = handler_timeout; + sigaction(SIGALRM, &action, &old_action); + alarm(timeout_value); +#endif + + status = connect(sock, (struct sockaddr *)&server, sizeof(server)); + + // + // Disable alarm and restore previous policy if any + // +#ifndef _MSC_VER /* _WIN32 */ + alarm(0); + sigaction(SIGALRM, &old_action, 0); +#endif + + if (status == 0 || errno == EALREADY || errno == EISCONN) + { + connected = 1; + return OK; + } + + // + // Only loop if timed out. Other errors are fatal. + // + if (status < 0 && errno != EINTR) + break; + + // cout << " <" << ::strerror(errno) << "> "; + close(sock); + Open(); + + sleep(wait_time); + + } + +#if 0 + if (status == ECONNREFUSED) + { + // + // For the case where the connection attempt is refused, we need + // to close the socket and create a new one in order to do any + // more with it. + // + Close(sock); + Open(); + } +#else + close(sock); + Open(0); +#endif + + connected = 0; + return NOTOK; +} + + +//***************************************************************************** +// int Connection::Bind() +// +int Connection::Bind() +{ + if (bind(sock, (struct sockaddr *)&server, sizeof(server)) == NOTOK) + { + return NOTOK; + } + return OK; +} + + +//***************************************************************************** +// int Connection::Get_Port() +// +int Connection::Get_Port() +{ + GETPEERNAME_LENGTH_T length = sizeof(server); + + if (getsockname(sock, (struct sockaddr *)&server, &length) == NOTOK) + { + return NOTOK; + } + return ntohs(server.sin_port); +} + + +//***************************************************************************** +// int Connection::Listen(int n) +// +int Connection::Listen(int n) +{ + return listen(sock, n); +} + + +//***************************************************************************** +// Connection *Connection::Accept(int priv) +// +Connection *Connection::Accept(int priv) +{ + int newsock; + + while (1) + { + newsock = accept(sock, (struct sockaddr *)0, (GETPEERNAME_LENGTH_T *)0); + if (newsock == NOTOK && errno == EINTR) + continue; + break; + } + if (newsock == NOTOK) + return (Connection *)0; + + Connection *newconnect = new Connection; + newconnect->sock = newsock; + + GETPEERNAME_LENGTH_T length = sizeof(newconnect->server); + getpeername(newsock, (struct sockaddr *)&newconnect->server, &length); + + if (priv && newconnect->server.sin_port >= IPPORT_RESERVED) + { + delete newconnect; + return (Connection *)0; + } + + return newconnect; +} + + +//************************************************************************* +// Connection *Connection::Accept_Privileged() +// PURPOSE: +// Accept in incoming connection but only if it is from a +// privileged port +// +Connection * Connection::Accept_Privileged() +{ + return Accept(1); +} + +//***************************************************************************** +// int Connection::read_char() +// +int Connection::Read_Char() +{ + if (pos >= pos_max) + { + pos_max = Read_Partial(buffer, sizeof(buffer)); + pos = 0; + if (pos_max <= 0) + { + return -1; + } + } + return buffer[pos++] & 0xff; +} + + +//***************************************************************************** +// String *Connection::Read_Line(String &s, char *terminator) +// +String *Connection::Read_Line(String &s, char *terminator) +{ + int termseq = 0; + s = 0; + + for (;;) + { + int ch = Read_Char(); + if (ch < 0) + { + // + // End of file reached. If we still have stuff in the input buffer + // we need to return it first. When we get called again we will + // return 0 to let the caller know about the EOF condition. + // + if (s.length()) + break; + else + return (String *) 0; + } + else if (terminator[termseq] && ch == terminator[termseq]) + { + // + // Got one of the terminator characters. We will not put + // it in the string but keep track of the fact that we + // have seen it. + // + termseq++; + if (!terminator[termseq]) + break; + } + else + { + s << (char) ch; + } + } + + return &s; +} + + +//***************************************************************************** +// String *Connection::read_line(char *terminator) +// +String *Connection::Read_Line(char *terminator) +{ + String *s; + + s = new String; + return Read_Line(*s, terminator); +} + + +//***************************************************************************** +// char *Connection::read_line(char *buffer, int maxlength, char *terminator) +// +char *Connection::Read_Line(char *buffer, int maxlength, char *terminator) +{ + char *start = buffer; + int termseq = 0; + + while (maxlength > 0) + { + int ch = Read_Char(); + if (ch < 0) + { + // + // End of file reached. If we still have stuff in the input buffer + // we need to return it first. When we get called again, we will + // return 0 to let the caller know about the EOF condition. + // + if (buffer > start) + break; + else + return (char *) 0; + } + else if (terminator[termseq] && ch == terminator[termseq]) + { + // + // Got one of the terminator characters. We will not put + // it in the string but keep track of the fact that we + // have seen it. + // + termseq++; + if (!terminator[termseq]) + break; + } + else + { + *buffer++ = ch; + maxlength--; + } + } + *buffer = '\0'; + + return start; +} + + +//***************************************************************************** +// int Connection::write_line(char *str, char *eol) +// +int Connection::Write_Line(char *str, char *eol) +{ + int n, nn; + + if ((n = Write(str)) < 0) + return -1; + + if ((nn = Write(eol)) < 0) + return -1; + + return n + nn; +} + + +//***************************************************************************** +// int Connection::Write(char *buffer, int length) +// +int Connection::Write(char *buffer, int length) +{ + int nleft, nwritten; + + if (length == -1) + length = strlen(buffer); + + nleft = length; + while (nleft > 0) + { + nwritten = Write_Partial(buffer, nleft); + if (nwritten < 0 && errno == EINTR) + continue; + if (nwritten <= 0) + return nwritten; + nleft -= nwritten; + buffer += nwritten; + } + return length - nleft; +} + + +//***************************************************************************** +// int Connection::Read(char *buffer, int length) +// +int Connection::Read(char *buffer, int length) +{ + int nleft, nread; + + nleft = length; + + // + // If there is data in our internal input buffer, use that first. + // + if (pos < pos_max) + { + int n = MIN(length, pos_max - pos); + + memcpy(buffer, &this->buffer[pos], n); + pos += n; + buffer += n; + nleft -= n; + } + + while (nleft > 0) + { + nread = Read_Partial(buffer, nleft); + if (nread < 0 && errno == EINTR) + continue; + if (nread < 0) + return -1; + else if (nread == 0) + break; + + nleft -= nread; + buffer += nread; + } + return length - nleft; +} + + +void Connection::Flush() +{ + pos = pos_max = 0; +} + +//************************************************************************* +// int Connection::Read_Partial(char *buffer, int maxlength) +// PURPOSE: +// Read at most <maxlength> from the current TCP connection. +// This is equivalent to the workings of the standard read() +// system call +// PARAMETERS: +// char *buffer: Buffer to read the data into +// int maxlength: Maximum number of bytes to read into the buffer +// RETURN VALUE: +// The actual number of bytes read in. +// ASSUMPTIONS: +// The connection has been previously established. +// FUNCTIONS USED: +// read() +// +int Connection::Read_Partial(char *buffer, int maxlength) +{ + int count; + + need_io_stop = 0; + do + { + errno = 0; + + if (timeout_value > 0) { + FD_SET_T fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + + timeval tv; + tv.tv_sec = timeout_value; + tv.tv_usec = 0; + + int selected = select(sock+1, &fds, 0, 0, &tv); + if (selected <= 0) + need_io_stop++; + } + + if (!need_io_stop) + count = recv(sock, buffer, maxlength, 0); + else + count = -1; // Input timed out + } + while (count <= 0 && errno == EINTR && !need_io_stop); + need_io_stop = 0; + + return count; +} + + +//************************************************************************* +// int Connection::Write_Partial(char *buffer, int maxlength) +// +int Connection::Write_Partial(char *buffer, int maxlength) +{ + int count; + + do + { + + count = send(sock, buffer, maxlength, 0); + + } + while (count < 0 && errno == EINTR && !need_io_stop); + need_io_stop = 0; + + return count; +} + + +//************************************************************************* +// char * Connection::Socket_as_String() +// PURPOSE: +// Return the numeric ASCII equivalent of the socket number. +// This is needed to pass the socket to another program +// +char * Connection::Socket_as_String() +{ + char *buffer = new char[20]; + + sprintf(buffer, "%d", sock); + return buffer; +} + +#ifndef _MSC_VER /* _WIN32 */ +extern "C" char *inet_ntoa(struct in_addr); +#endif + +//************************************************************************* +// char *Connection::Get_Peername() +// +const char* Connection::Get_Peername() +{ + if (peer.empty()) + { + struct sockaddr_in p; + GETPEERNAME_LENGTH_T length = sizeof(p); + struct hostent *hp; + + if (getpeername(sock, (struct sockaddr *) &p, &length) < 0) + { + return 0; + } + + length = sizeof(p.sin_addr); + hp = gethostbyaddr((const char *) &p.sin_addr, length, AF_INET); + if (hp) + peer = (char *) hp->h_name; + else + peer = (char *) inet_ntoa(p.sin_addr); + } + return (const char*) peer.get(); +} + + +//************************************************************************* +// char *Connection::Get_PeerIP() +// +const char* Connection::Get_PeerIP() const +{ + struct sockaddr_in p; + GETPEERNAME_LENGTH_T length = sizeof(p); + + if (getpeername(sock, (struct sockaddr *) &p, &length) < 0) + { + return 0; + } + return (const char*) inet_ntoa(p.sin_addr); +} + +#ifdef NEED_PROTO_GETHOSTNAME +extern "C" int gethostname(char *name, int namelen); +#endif + +//************************************************************************* +// unsigned int GetHostIP(char *ip, int length) +// +unsigned int GetHostIP(char *ip, int length) +{ + char hostname[100]; + if (gethostname(hostname, sizeof(hostname)) == NOTOK) + return 0; + + struct hostent *ent = gethostbyname(hostname); + if (!ent) + return 0; + + struct in_addr addr; + memcpy((char *) &addr.s_addr, ent->h_addr, sizeof(addr)); + if (ip) + strncpy(ip, inet_ntoa(addr), length); + return addr.s_addr; +} + + + +//************************************************************************* +// int Connection::WaitTime(unsigned int _wt) +// +int Connection::WaitTime(unsigned int _wt) +{ + wait_time = _wt; + return OK; +} |