From 2a3f7b2799be4bdfb182a56313263823a4bfdbf6 Mon Sep 17 00:00:00 2001 From: Don BURNS Date: Sat, 28 Aug 2004 07:25:21 +0000 Subject: [PATCH] Added the .net plug-in. This allows the reading of files by specifying :file..net for example: osgviewer osgcvs.no-ip.com:OSGModels/cow.osg.net --- src/osgPlugins/net/GNUmakefile | 15 + src/osgPlugins/net/ReaderWriterNET.cpp | 76 ++ src/osgPlugins/net/sockinet.cpp | 439 +++++++++++ src/osgPlugins/net/sockinet.h | 140 ++++ src/osgPlugins/net/sockstream.cpp | 1005 ++++++++++++++++++++++++ src/osgPlugins/net/sockstream.h | 364 +++++++++ 6 files changed, 2039 insertions(+) create mode 100644 src/osgPlugins/net/GNUmakefile create mode 100644 src/osgPlugins/net/ReaderWriterNET.cpp create mode 100644 src/osgPlugins/net/sockinet.cpp create mode 100644 src/osgPlugins/net/sockinet.h create mode 100644 src/osgPlugins/net/sockstream.cpp create mode 100644 src/osgPlugins/net/sockstream.h diff --git a/src/osgPlugins/net/GNUmakefile b/src/osgPlugins/net/GNUmakefile new file mode 100644 index 000000000..7ae7d60f8 --- /dev/null +++ b/src/osgPlugins/net/GNUmakefile @@ -0,0 +1,15 @@ +TOPDIR = ../../.. +include $(TOPDIR)/Make/makedefs + +CXXFILES =\ + ReaderWriterNET.cpp\ + sockinet.cpp\ + sockstream.cpp\ + +LIBS += $(OSG_LIBS) $(OTHER_LIBS) + +TARGET_BASENAME = net +include $(TOPDIR)/Make/cygwin_plugin_def +PLUGIN = $(PLUGIN_PREFIX)$(TARGET_BASENAME).$(PLUGIN_EXT) + +include $(TOPDIR)/Make/makerules diff --git a/src/osgPlugins/net/ReaderWriterNET.cpp b/src/osgPlugins/net/ReaderWriterNET.cpp new file mode 100644 index 000000000..066cefc3b --- /dev/null +++ b/src/osgPlugins/net/ReaderWriterNET.cpp @@ -0,0 +1,76 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "sockinet.h" + +extern bool goGetTheFile(const std::string &host, const std::string & file, const std::string &saveDir ); + +class NetReader : public osgDB::ReaderWriter +{ + public: + NetReader() {} + + virtual const char* className() { return "Network Reader"; } + + virtual bool acceptsExtension(const std::string& extension) + { + return osgDB::equalCaseInsensitive(extension,"net"); + } + + virtual ReadResult readObject(const std::string& fileName, const Options* opt) + { return readNode(fileName,opt); } + + virtual ReadResult readNode(const std::string& fileName, const Options* ) + { + std::string ext = osgDB::getFileExtension(fileName); + if (!acceptsExtension(ext)) + return ReadResult::FILE_NOT_HANDLED; + + int index = fileName.find(":"); + if( index == -1 ) + return ReadResult::FILE_NOT_HANDLED; + + std::string host = fileName.substr( 0, index); + int rindex = fileName.rfind( "." ); + std::string file = fileName.substr( index+1, rindex-index-1 ); + + iosockinet sio (sockbuf::sock_stream); + sio->connect( host.c_str(), 80 ); + + sio << "GET /" << file << " HTTP/1.1\n" << "Host:\n\n"; + sio.flush(); + + char linebuff[256]; + do + { + sio.getline( linebuff, sizeof( linebuff )); + } while( linebuff[0] != '\r' ); + + osgDB::ReaderWriter *reader = + osgDB::Registry::instance()->getReaderWriterForExtension( osgDB::getFileExtension(file)); + + ReadResult readResult = ReadResult::FILE_NOT_HANDLED; + if( reader == 0L ) + return ReadResult::FILE_NOT_HANDLED; + else + readResult = reader->readNode( sio ); + + return readResult; + } +}; + +osgDB::RegisterReaderWriterProxy g_netReader_Proxy; + + + + diff --git a/src/osgPlugins/net/sockinet.cpp b/src/osgPlugins/net/sockinet.cpp new file mode 100644 index 000000000..a2d1daf7d --- /dev/null +++ b/src/osgPlugins/net/sockinet.cpp @@ -0,0 +1,439 @@ +// sockinet.C -*- C++ -*- socket library +// Copyright (C) 2002 Herbert Straub +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 +// 2002-07-25 Version 1.2 (C) Herbert Straub +// Adding improved Error Handling in sockerr class +// sockinetaddr::setport if the first character of the port parameter is a +// digit, then the parameter is interpreted as a number +// 2002-07-28 Version 1.2 (C) Herbert Straub +// Eliminating sorry_about_global_temp inititialisation. This don't work +// in combination with NewsCache. My idea is: initializing the classes with (0) +// and in the second step call ios::init (sockinetbuf *) and iosockstream::init ... +// The constructors of isockinet, osockinet and iosockinet are changed. + +#include "sockinet.h" +#if defined(__APPLE) +typedef int socklen_t; +#endif + +#ifndef WIN32 +extern "C" { +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +} +#else +# define socklen_t int +# define EADDRNOTAVAIL WSAEADDRNOTAVAIL +# define EADDRINUSE WSAEADDRINUSE +# define ENOPROTOOPT WSAENOPROTOOPT +#endif // !WIN32 + +void herror(const char*); + +sockinetaddr::sockinetaddr () +{ + sin_family = sockinetbuf::af_inet; + sin_addr.s_addr = htonl(INADDR_ANY); + sin_port = 0; +} + +sockinetaddr::sockinetaddr(unsigned long addr, int port_no) +// addr and port_no are in host byte order +{ + sin_family = sockinetbuf::af_inet; + sin_addr.s_addr = htonl(addr); + sin_port = htons(port_no); +} + +sockinetaddr::sockinetaddr(unsigned long addr, const char* sn, const char* pn) +// addr is in host byte order +{ + sin_family = sockinetbuf::af_inet; + sin_addr.s_addr = htonl (addr); // Added by cgay@cs.uoregon.edu May 29, 1993 + setport(sn, pn); +} + +sockinetaddr::sockinetaddr (const char* host_name, int port_no) +// port_no is in host byte order +{ + setaddr(host_name); + sin_port = htons(port_no); +} + +sockinetaddr::sockinetaddr(const char* hn, const char* sn, const char* pn) +{ + setaddr(hn); + setport(sn, pn); +} + +sockinetaddr::sockinetaddr (const sockinetaddr& sina) +{ + sin_family = sockinetbuf::af_inet; + sin_addr.s_addr = sina.sin_addr.s_addr; + sin_port = sina.sin_port; +} + +void sockinetaddr::setport(const char* sn, const char* pn) +{ + if (isdigit (*sn)) { + sin_port = htons(atoi(sn)); + } else { + servent* sp = getservbyname(sn, pn); + if (sp == 0) throw sockerr (EADDRNOTAVAIL, "sockinetaddr::setport"); + sin_port = sp->s_port; + } +} + +int sockinetaddr::getport () const +{ + return ntohs (sin_port); +} + +void sockinetaddr::setaddr(const char* host_name) +{ + if ( (sin_addr.s_addr = inet_addr(host_name)) == INADDR_NONE) { + hostent* hp = gethostbyname(host_name); + if (hp == 0) throw sockerr (EADDRNOTAVAIL, "sockinetaddr::setaddr"); + memcpy(&sin_addr, hp->h_addr, hp->h_length); + sin_family = hp->h_addrtype; + } else + sin_family = sockinetbuf::af_inet; +} + +const char* sockinetaddr::gethostname () const +{ + if (sin_addr.s_addr == htonl(INADDR_ANY)) { + static char hostname[64]; + if (::gethostname(hostname, 63) == -1) return ""; + return hostname; + } + + hostent* hp = gethostbyaddr((const char*) &sin_addr, + sizeof(sin_addr), + family()); + if (hp == 0) return ""; + if (hp->h_name) return hp->h_name; + return ""; +} + +sockinetbuf::sockinetbuf (const sockbuf::sockdesc& sd) + : sockbuf (sd.sock) +{} + +sockinetbuf::sockinetbuf(sockbuf::type ty, int proto) + : sockbuf (af_inet, ty, proto) +{} + +sockinetaddr sockinetbuf::localaddr() const +{ + sockinetaddr sin; + int len = sin.size(); + if (::getsockname(rep->sock, sin.addr (), (socklen_t*) // LN + &len) == -1) + throw sockerr (errno, "sockinetbuf::localaddr"); + return sin; +} + +int sockinetbuf::localport() const +{ + sockinetaddr sin = localaddr(); + if (sin.family() != af_inet) return -1; + return sin.getport(); +} + +const char* sockinetbuf::localhost() const +{ + sockinetaddr sin = localaddr(); + if (sin.family() != af_inet) return ""; + return sin.gethostname(); +} + +sockinetaddr sockinetbuf::peeraddr() const +{ + sockinetaddr sin; + int len = sin.size(); + if (::getpeername(rep->sock, sin.addr (), (socklen_t*) // LN + &len) == -1) + throw sockerr (errno, "sockinetbuf::peeraddr"); + return sin; +} + +int sockinetbuf::peerport() const +{ + sockinetaddr sin = peeraddr(); + if (sin.family() != af_inet) return -1; + return sin.getport(); +} + +const char* sockinetbuf::peerhost() const +{ + sockinetaddr sin = peeraddr(); + if (sin.family() != af_inet) return ""; + return sin.gethostname(); +} + +void sockinetbuf::bind_until_success (int portno) +// a. bind to (INADDR_ANY, portno) +// b. if success return +// c. if failure and errno is EADDRINUSE, portno++ and go to step a. +{ + for (;;) { + try { + bind (portno++); + } + catch (sockerr e) { +// if (e.errno () != EADDRINUSE) throw; + if (e.serrno () != EADDRINUSE) throw; // LN + continue; + } + break; + } +} + +void sockinetbuf::bind (sockAddr& sa) +{ + sockbuf::bind (sa); +} + +void sockinetbuf::bind (int port_no) +{ + sockinetaddr sa ((long unsigned int) // LN + INADDR_ANY, port_no); + bind (sa); +} + +void sockinetbuf::bind (unsigned long addr, int port_no) +// address and portno are in host byte order +{ + sockinetaddr sa (addr, port_no); + bind (sa); +} + +void sockinetbuf::bind (const char* host_name, int port_no) +{ + sockinetaddr sa (host_name, port_no); + bind (sa); +} + +void sockinetbuf::bind (unsigned long addr, + const char* service_name, + const char* protocol_name) +{ + sockinetaddr sa (addr, service_name, protocol_name); + bind (sa); +} + +void sockinetbuf::bind (const char* host_name, + const char* service_name, + const char* protocol_name) +{ + sockinetaddr sa (host_name, service_name, protocol_name); + bind (sa); +} + +void sockinetbuf::connect (sockAddr& sa) +{ + sockbuf::connect (sa); +} + +void sockinetbuf::connect (unsigned long addr, int port_no) +// address and portno are in host byte order +{ + sockinetaddr sa (addr, port_no); + connect (sa); +} + +void sockinetbuf::connect (const char* host_name, int port_no) +{ + sockinetaddr sa (host_name, port_no); + connect (sa); +} + +void sockinetbuf::connect (unsigned long addr, + const char* service_name, + const char* protocol_name) +{ + sockinetaddr sa (addr, service_name, protocol_name); + connect (sa); +} + +void sockinetbuf::connect (const char* host_name, + const char* service_name, + const char* protocol_name) +{ + sockinetaddr sa (host_name, service_name, protocol_name); + connect (sa); +} + +sockbuf::sockdesc sockinetbuf::accept () +{ + return sockbuf::accept (); +} + +sockbuf::sockdesc sockinetbuf::accept (sockAddr& sa) +{ + return sockbuf::accept (sa); +} + +sockbuf::sockdesc sockinetbuf::accept (unsigned long addr, + int port_no) +{ + sockinetaddr sa (addr, port_no); + return accept (sa); +} + +sockbuf::sockdesc sockinetbuf::accept (const char* host_name, + int port_no) +{ + sockinetaddr sa (host_name, port_no); + return accept (sa); +} + +bool sockinetbuf::tcpnodelay () const +{ + struct protoent* proto = getprotobyname ("tcp"); + if (proto == 0) throw sockerr (ENOPROTOOPT, "sockinetbuf::tcpnodelay"); + + int old = 0; + getopt (TCP_NODELAY, &old, sizeof (old), proto->p_proto); + return old!=0; +} + +bool sockinetbuf::tcpnodelay (bool set) const +{ + struct protoent* proto = getprotobyname ("tcp"); + if (proto == 0) throw sockerr (ENOPROTOOPT, "sockinetbuf::tcpnodelay"); + + int old = 0; + int opt = set; + getopt (TCP_NODELAY, &old, sizeof (old), proto->p_proto); + setopt (TCP_NODELAY, &opt, sizeof (opt), proto->p_proto); + return old!=0; +} + +isockinet::isockinet (const sockbuf::sockdesc& sd) + : ios(0), isockstream(0) +{ + sockinetbuf *t = new sockinetbuf (sd); + + ios::init (t); + isockstream::init (t); +} + +isockinet::isockinet (sockbuf::type ty, int proto) + : ios (0), isockstream(0) +{ + sockinetbuf *t = new sockinetbuf (ty, proto); + + ios::init (t); + isockstream::init (t); +} + +isockinet::isockinet (const sockinetbuf& sb) + : ios (0), isockstream(0) +{ + sockinetbuf *t = new sockinetbuf (sb); + + ios::init (t); + isockstream::init (t); +} + +isockinet::~isockinet () +{ + delete ios::rdbuf (); +} + +osockinet::osockinet (const sockbuf::sockdesc& sd) + : ios (0), osockstream(0) +{ + sockinetbuf *t = new sockinetbuf (sd); + + ios::init (t); + osockstream::init (t); +} + +osockinet::osockinet (sockbuf::type ty, int proto) + : ios (0), osockstream(0) +{ + sockinetbuf *t = new sockinetbuf (ty, proto); + + ios::init (t); + osockstream::init (t); +} + +osockinet::osockinet (const sockinetbuf& sb) + : ios (0), osockstream(0) +{ + sockinetbuf *t = new sockinetbuf (sb); + + ios::init (t); + osockstream::init (t); +} + +osockinet::~osockinet () +{ + delete ios::rdbuf (); +} + +iosockinet::iosockinet (const sockbuf::sockdesc& sd) + : ios (0), iosockstream(0) +{ + sockinetbuf *t = new sockinetbuf(sd); + + ios::init (t); + iosockstream::init (t); +} + +iosockinet::iosockinet (sockbuf::type ty, int proto) + : ios (0), iosockstream (0) +{ + sockinetbuf *t = new sockinetbuf (ty, proto); + + ios::init (t); + iosockstream::init (t); +} + +iosockinet::iosockinet (const sockinetbuf& sb) + : ios (0), iosockstream(0) +{ + sockinetbuf *t = new sockinetbuf (sb); + + ios::init (t); + iosockstream::init (t); +} + +iosockinet::~iosockinet () +{ + delete ios::rdbuf (); +} diff --git a/src/osgPlugins/net/sockinet.h b/src/osgPlugins/net/sockinet.h new file mode 100644 index 000000000..dd97640c5 --- /dev/null +++ b/src/osgPlugins/net/sockinet.h @@ -0,0 +1,140 @@ +// sockinet.h -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#ifndef _SOCKINET_H +#define _SOCKINET_H + +#include "sockstream.h" +#ifndef WIN32 +# include +#endif // !WIN32 + +class sockinetaddr: public sockAddr, public sockaddr_in +{ + protected: + void setport (const char* sn, const char* pn="tcp"); + void setaddr (const char* hn); + + public: + ~sockinetaddr () {} + sockinetaddr (); + sockinetaddr (unsigned long addr, int port_no=0); + sockinetaddr (const char* host_name, int port_no=0); + sockinetaddr (unsigned long addr, + const char* service_name, + const char* protocol_name="tcp"); + sockinetaddr (const char* host_name, + const char* service_name, + const char* protocol_name="tcp"); + sockinetaddr (const sockinetaddr& sina); + + operator void* () const { return addr_in (); } + + sockaddr_in* addr_in () const { return (sockaddr_in*) this; } + int size () const { return sizeof (sockaddr_in); } + int family() const { return sin_family; } + sockaddr* addr () const { return (sockaddr*) addr_in (); } + + int getport () const; + const char* gethostname() const; +}; + +class sockinetbuf: public sockbuf { +public: + enum domain { af_inet = AF_INET }; + + sockinetbuf (const sockbuf::sockdesc& sd); + sockinetbuf (const sockinetbuf& si): sockbuf (si) {} + sockinetbuf (sockbuf::type ty, int proto=0); + sockinetbuf& operator=(const sockinetbuf& si); + ~sockinetbuf () {} + + sockinetaddr localaddr() const; + int localport() const; + const char* localhost() const; + + sockinetaddr peeraddr() const; + int peerport() const; + const char* peerhost() const; + + void bind_until_success (int portno); + + virtual void bind (sockAddr& sa); + void bind (int port_no=0); // addr is assumed to be INADDR_ANY + // and thus defaults to local host + + void bind (unsigned long addr, int port_no); + void bind (const char* host_name, int port_no=0); + void bind (unsigned long addr, + const char* service_name, + const char* protocol_name="tcp"); + void bind (const char* host_name, + const char* service_name, + const char* protocol_name="tcp"); + + virtual void connect (sockAddr& sa); + void connect (unsigned long addr, int port_no); + void connect (const char* host_name, int port_no); + void connect (unsigned long addr, + const char* service_name, + const char* protocol_name="tcp"); + void connect (const char* host_name, + const char* service_name, + const char* protocol_name="tcp"); + + virtual sockdesc accept (); + virtual sockdesc accept (sockAddr& sa); + sockdesc accept (unsigned long addr, int port_no); + sockdesc accept (const char* host_name, int port_no); + + bool tcpnodelay () const; + bool tcpnodelay (bool set) const; +}; + +class isockinet: public isockstream +{ +public: + isockinet (const sockbuf::sockdesc& sd); + isockinet (const sockinetbuf& sb); + isockinet (sockbuf::type ty=sockbuf::sock_stream, + int proto=0); + ~isockinet (); + + sockinetbuf* rdbuf () { return (sockinetbuf*)ios::rdbuf (); } + sockinetbuf* operator -> () { return rdbuf (); } +}; + +class osockinet: public osockstream +{ +public: + osockinet (const sockbuf::sockdesc& sd); + osockinet (const sockinetbuf& sb); + osockinet (sockbuf::type ty=sockbuf::sock_stream, + int proto=0); + ~osockinet (); + + sockinetbuf* rdbuf () { return (sockinetbuf*)ios::rdbuf (); } + sockinetbuf* operator -> () { return rdbuf (); } +}; + +class iosockinet: public iosockstream +{ +public: + iosockinet (const sockbuf::sockdesc& sd); + iosockinet (const sockinetbuf& sb); + iosockinet (sockbuf::type ty=sockbuf::sock_stream, + int proto=0); + ~iosockinet (); + + sockinetbuf* rdbuf () { return (sockinetbuf*)ios::rdbuf (); } + sockinetbuf* operator -> () { return rdbuf (); } +}; + +#endif // _SOCKINET_H diff --git a/src/osgPlugins/net/sockstream.cpp b/src/osgPlugins/net/sockstream.cpp new file mode 100644 index 000000000..d72d02072 --- /dev/null +++ b/src/osgPlugins/net/sockstream.cpp @@ -0,0 +1,1005 @@ +// sockstream.C -*- C++ -*- socket library +// Copyright (C) 2002 Herbert Straub for my changes, see ChangeLog. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 +// +// You can simultaneously read and write into +// a sockbuf just like you can listen and talk +// through a telephone. Hence, the read and the +// write buffers are different. That is, they do not +// share the same memory. +// +// Read: +// gptr() points to the start of the get area. +// The unread chars are gptr() - egptr(). +// base() points to the read buffer +// +// eback() is set to base() so that pbackfail() +// is called only when there is no place to +// putback a char. And pbackfail() always returns EOF. +// +// Write: +// pptr() points to the start of the put area +// The unflushed chars are pbase() - pptr() +// pbase() points to the write buffer. +// epptr() points to the end of the write buffer. +// +// Output is flushed whenever one of the following conditions +// holds: +// (1) pptr() == epptr() +// (2) EOF is written +// (3) linebuffered and '\n' is written +// +// Unbuffered: +// Input buffer size is assumed to be of size 1 and output +// buffer is of size 0. That is, egptr() <= base()+1 and +// epptr() == pbase(). +// +// Version: 1.2 2002-07-25 Herbert Straub +// Improved Error Handling - extending the sockerr class by cOperation + + +#include "sockstream.h" +#include +#include +#if defined(__APPLE__) +#typedef int socklen_t; +#endif + +#ifndef WIN32 +extern "C" { +# include +# include +# include +# include +# include +} +#else +# define socklen_t int + +# define EWOULDBLOCK WSAEWOULDBLOCK +# define EINPROGRESS WSAEINPROGRESS +# define EALREADY WSAEALREADY +# define ENOTSOCK WSAENOTSOCK +# define EDESTADDRREQ WSAEDESTADDRREQ +# define EMSGSIZE WSAEMSGSIZE +# define EPROTOTYPE WSAEPROTOTYPE +# define ENOPROTOOPT WSAENOPROTOOPT +# define EPROTONOSUPPORT WSAEPROTONOSUPPORT +# define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +# define EOPNOTSUPP WSAEOPNOTSUPP +# define EPFNOSUPPORT WSAEPFNOSUPPORT +# define EAFNOSUPPORT WSAEAFNOSUPPORT +# define EADDRINUSE WSAEADDRINUSE +# define EADDRNOTAVAIL WSAEADDRNOTAVAIL +# define ENETDOWN WSAENETDOWN +# define ENETUNREACH WSAENETUNREACH +# define ENETRESET WSAENETRESET +# define ECONNABORTED WSAECONNABORTED +# define ECONNRESET WSAECONNRESET +# define ENOBUFS WSAENOBUFS +# define EISCONN WSAEISCONN +# define ENOTCONN WSAENOTCONN +# define ESHUTDOWN WSAESHUTDOWN +# define ETOOMANYREFS WSAETOOMANYREFS +# define ETIMEDOUT WSAETIMEDOUT +# define ECONNREFUSED WSAECONNREFUSED +# define ELOOP WSAELOOP +# define EHOSTDOWN WSAEHOSTDOWN +# define EHOSTUNREACH WSAEHOSTUNREACH +# define EPROCLIM WSAEPROCLIM +# define EUSERS WSAEUSERS +# define EDQUOT WSAEDQUOT +# define EISCONN WSAEISCONN +# define ENOTCONN WSAENOTCONN +# define ECONNRESET WSAECONNRESET +# define ECONNREFUSED WSAECONNREFUSED +# define ETIMEDOUT WSAETIMEDOUT +# define EADDRINUSE WSAEADDRINUSE +# define EADDRNOTAVAIL WSAEADDRNOTAVAIL +# define EWOULDBLOCK WSAEWOULDBLOCK + + +#endif // !WIN32 + +#ifndef BUFSIZ +# define BUFSIZ 1024 +#endif + +#ifdef FD_ZERO +# undef FD_ZERO // bzero causes so much trouble to us +#endif +#define FD_ZERO(p) (memset ((p), 0, sizeof *(p))) + +const char* sockerr::errstr () const +{ +#ifndef WIN32 + //extern char *sys_errlist; + return sys_errlist[err]; + //return SYS_ERRLIST [err]; +#else + return 0; // TODO +#endif +} + +bool sockerr::io () const +// recoverable io error. +{ + switch (err) { + case EWOULDBLOCK: + case EINPROGRESS: + case EALREADY: + return true; + } + return false; +} + +bool sockerr::arg () const +// recoverable argument error. +{ + switch (err) { + case ENOTSOCK: + case EDESTADDRREQ: + case EMSGSIZE: + case EPROTOTYPE: + case ENOPROTOOPT: + case EPROTONOSUPPORT: + case ESOCKTNOSUPPORT: + case EOPNOTSUPP: + case EPFNOSUPPORT: + case EAFNOSUPPORT: + case EADDRINUSE: + case EADDRNOTAVAIL: + return true; + } + return false; +} + +bool sockerr::op () const +// operational error encountered +{ + switch (err) { + case ENETDOWN: + case ENETUNREACH: + case ENETRESET: + case ECONNABORTED: + case ECONNRESET: + case ENOBUFS: + case EISCONN: + case ENOTCONN: + case ESHUTDOWN: + case ETOOMANYREFS: + case ETIMEDOUT: + case ECONNREFUSED: + case ELOOP: + case ENAMETOOLONG: + case EHOSTDOWN: + case EHOSTUNREACH: + case ENOTEMPTY: +# if !defined(__linux__) // LN + case EPROCLIM: +# endif + case EUSERS: + case EDQUOT: + return true; + } + return false; +} + +bool sockerr::conn () const +// return true if err is EISCONN, ENOTCONN, ECONNRESET, ECONNREFUSED, +// ETIMEDOUT, or EPIPE +{ + switch (err) { + case EISCONN: + case ENOTCONN: + case ECONNRESET: + case ECONNREFUSED: + case ETIMEDOUT: + case EPIPE: + return true; + } + return false; +} + +bool sockerr::addr () const +// return true if err is EADDRINUSE or EADDRNOTAVAIL +{ + switch (err) { + case EADDRINUSE: + case EADDRNOTAVAIL: + return true; + } + return false; +} + +bool sockerr::benign () const +// return true if err is EINTR, EWOULDBLOCK, or EAGAIN +{ + switch (err) { + case EINTR: + case EWOULDBLOCK: +// On FreeBSD (and probably on Linux too) +// EAGAIN has the same value as EWOULDBLOCK +#if !defined(__linux__) && !(defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__)) // LN + case EAGAIN: +#endif + return true; + } + return false; +} + +sockbuf::sockbuf (const sockbuf::sockdesc& sd) +// : rep (new sockbuf::sockcnt (sd.sock)) +{ + rep = new sockbuf::sockcnt (sd.sock); + char_type* gbuf = new char_type [BUFSIZ]; + char_type* pbuf = new char_type [BUFSIZ]; + setg (gbuf, gbuf + BUFSIZ, gbuf + BUFSIZ); + setp (pbuf, pbuf + BUFSIZ); + rep->gend = gbuf + BUFSIZ; + rep->pend = pbuf + BUFSIZ; +} + +sockbuf::sockbuf (int domain, sockbuf::type st, int proto) + : rep (0) +{ + SOCKET soc = ::socket (domain, st, proto); + + if (soc == SOCKET_ERROR) +#ifndef WIN32 + throw sockerr (errno, "sockbuf::sockbuf"); +#else + throw sockerr(WSAGetLastError(), "sockbuf::sockbuf"); +#endif + + rep = new sockbuf::sockcnt (soc); + + char_type* gbuf = new char_type [BUFSIZ]; + char_type* pbuf = new char_type [BUFSIZ]; + setg (gbuf, gbuf + BUFSIZ, gbuf + BUFSIZ); + setp (pbuf, pbuf + BUFSIZ); + rep->gend = gbuf + BUFSIZ; + rep->pend = pbuf + BUFSIZ; +} + +sockbuf::sockbuf (const sockbuf& sb) +: +//streambuf (sb), +rep (sb.rep) +{ + // the streambuf::streambuf (const streambuf&) is assumed + // to haved handled pbase () and gbase () correctly. + + rep->cnt++; +} + +/*sockbuf& sockbuf::operator = (const sockbuf& sb) +{ + if (this != &sb && rep != sb.rep && rep->sock != sb.rep->sock) { + streambuf::operator = (sb); + this->sockbuf::~sockbuf(); + + // the streambuf::operator = (const streambuf&) is assumed + // to have handled pbase () and gbase () correctly. + rep = sb.rep; + rep->cnt++; + } + return *this; +}*/ + +sockbuf::~sockbuf () +{ + overflow (eof); // flush write buffer + if (--rep->cnt == 0) { + delete [] pbase (); + delete [] eback (); +#ifndef WIN32 + int c = close (rep->sock); +#else + int c = closesocket(rep->sock); +#endif + delete rep; + if (c == SOCKET_ERROR) +#ifndef WIN32 + throw sockerr (errno, "sockbuf::~sockbuf", sockname.c_str()); +#else + throw sockerr(WSAGetLastError(), "sockbuf::~sockbuf", sockname.c_str()); +#endif + } +} + +bool sockbuf::is_open () const +// if socket is still connected to the peer, return true +// else return false +{ + return false; +} + +int sockbuf::sync () +// we never return -1 because we throw sockerr +// exception in the event of an error. +{ + if (pptr () && pbase () < pptr () && pptr () <= epptr ()) { + // we have some data to flush + try { + write (pbase (), pptr () - pbase ()); + } + catch (int wlen) { + // write was not completely successful + stringstream sb; + string err ("sockbuf::sync"); + err += "(" + sockname + ")"; + if (wlen) { + // reposition unwritten chars + char* pto = pbase (); + char* pfrom = pbase () + wlen; + int len = pptr () - pbase () - wlen; + while (pfrom < pptr ()) *pto++ = *pfrom++; + setp (pbase (), (char_type*) rep->pend); + pbump (len); + sb << " wlen=(" << wlen << ")"; + err += sb.rdbuf()->str(); + } + throw sockerr (errno, err.c_str ()); + } + + setp (pbase (), (char_type*) rep->pend); + } + + // we cannot restore input data back to the socket stream + // thus we do not do anything on the input stream + + return 0; +} + +int sockbuf::showmanyc () const +// return the number of chars in the input sequence +{ + if (gptr () && gptr () < egptr ()) + return egptr () - gptr (); + return 0; +} + +sockbuf::int_type sockbuf::underflow () +{ + if (gptr () == 0) + return eof; // input stream has been disabled + + if (gptr () < egptr ()) + return (unsigned char) *gptr (); // eof is a -ve number; make it + // unsigned to be diff from eof + + int rlen = read (eback (), (char*) rep->gend - (char*) eback ()); + + if (rlen == 0) + return eof; + + setg (eback (), eback (), eback () + rlen); + return (unsigned char) *gptr (); +} + +sockbuf::int_type sockbuf::uflow () +{ + int_type ret = underflow (); + if (ret == eof) + return eof; + + gbump (1); + return ret; +} + +streamsize sockbuf::xsgetn (char_type* s, streamsize n) +{ + int rval = showmanyc (); + if (rval >= n) { + memcpy (s, gptr (), n * sizeof (char_type)); + gbump (n); + return n; + } + + memcpy (s, gptr (), rval * sizeof (char_type)); + gbump (rval); + + if (underflow () != eof) + return rval + xsgetn (s + rval, n - rval); + + return rval; +} + +sockbuf::int_type sockbuf::pbackfail (int) +{ + return eof; +} + +sockbuf::int_type sockbuf::overflow (sockbuf::int_type c) +// if pbase () == 0, no write is allowed and thus return eof. +// if c == eof, we sync the output and return 0. +// if pptr () == epptr (), buffer is full and thus sync the output, +// insert c into buffer, and return c. +// In all cases, if error happens, throw exception. +{ + if (pbase () == 0) + return eof; + + if (c == eof) + return sync (); + + if (pptr () == epptr ()) + sync (); + *pptr () = (char_type)c; + pbump (1); + return c; +} + +streamsize sockbuf::xsputn (const char_type* s, streamsize n) +{ + int wval = epptr () - pptr (); + if (n <= wval) { + memcpy (pptr (), s, n * sizeof (char_type)); + pbump (n); + return n; + } + + memcpy (pptr (), s, wval * sizeof (char_type)); + pbump (wval); + + if (overflow () != eof) + return wval + xsputn (s + wval, n - wval); + + return wval; +} + +void sockbuf::bind (sockAddr& sa) +{ + if (::bind (rep->sock, sa.addr (), sa.size ()) == -1) + throw sockerr (errno, "sockbuf::bind", sockname.c_str()); +} + +void sockbuf::connect (sockAddr& sa) +{ + if (::connect(rep->sock, sa.addr (), sa.size()) == -1) + throw sockerr (errno, "sockbuf::connect", sockname.c_str()); +} + +void sockbuf::listen (int num) +{ + if (::listen (rep->sock, num) == -1) + throw sockerr (errno, "sockbuf::listen", sockname.c_str()); +} + +sockbuf::sockdesc sockbuf::accept (sockAddr& sa) +{ + int len = sa.size (); + int soc = -1; + if ((soc = ::accept (rep->sock, sa.addr (), (socklen_t*) // LN + &len)) == -1) + throw sockerr (errno, "sockbuf::sockdesc", sockname.c_str()); + return sockdesc (soc); +} + +sockbuf::sockdesc sockbuf::accept () +{ + int soc = -1; + if ((soc = ::accept (rep->sock, 0, 0)) == -1) + throw sockerr (errno, "sockbuf::sockdesc", sockname.c_str()); + return sockdesc (soc); +} + +int sockbuf::read (void* buf, int len) +{ + if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) { + throw sockerr (ETIMEDOUT, "sockbuf::read", sockname.c_str()); + } + + if (rep->oob && atmark ()) + throw sockoob (); + + int rval = 0; + if ((rval = ::read (rep->sock, (char*) buf, len)) == -1) + throw sockerr (errno, "sockbuf::read", sockname.c_str()); + return rval; +} + +int sockbuf::recv (void* buf, int len, int msgf) +{ + if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::recv", sockname.c_str()); + + if (rep->oob && atmark ()) + throw sockoob (); + + int rval = 0; + if ((rval = ::recv (rep->sock, (char*) buf, len, msgf)) == -1) + throw sockerr (errno, "sockbuf::recv", sockname.c_str()); + return rval; +} + +int sockbuf::recvfrom (sockAddr& sa, void* buf, int len, int msgf) +{ + if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::recvfrom", sockname.c_str()); + + if (rep->oob && atmark ()) + throw sockoob (); + + int rval = 0; + int sa_len = sa.size (); + + if ((rval = ::recvfrom (rep->sock, (char*) buf, len, + msgf, sa.addr (), (socklen_t*) // LN + &sa_len)) == -1) + throw sockerr (errno, "sockbuf::recvfrom", sockname.c_str()); + return rval; +} + +int sockbuf::write(const void* buf, int len) +// upon error, write throws the number of bytes writen so far instead +// of sockerr. +{ + if (rep->stmo != -1 && is_writeready (rep->stmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::write", sockname.c_str()); + + int wlen=0; + while(len>0) { + int wval = ::write (rep->sock, (char*) buf, len); + if (wval == -1) throw wlen; + len -= wval; + wlen += wval; + } + return wlen; // == len if every thing is all right +} + +int sockbuf::send (const void* buf, int len, int msgf) +// upon error, write throws the number of bytes writen so far instead +// of sockerr. +{ + if (rep->stmo != -1 && is_writeready (rep->stmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::send", sockname.c_str()); + + int wlen=0; + while(len>0) { + int wval = ::send (rep->sock, (char*) buf, len, msgf); + if (wval == -1) throw wlen; + len -= wval; + wlen += wval; + } + return wlen; +} + +int sockbuf::sendto (sockAddr& sa, const void* buf, int len, int msgf) +// upon error, write throws the number of bytes writen so far instead +// of sockerr. +{ + if (rep->stmo != -1 && is_writeready (rep->stmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::sendto", sockname.c_str()); + + int wlen=0; + while(len>0) { + int wval = ::sendto (rep->sock, (char*) buf, len, msgf, + sa.addr (), sa.size()); + if (wval == -1) throw wlen; + len -= wval; + wlen += wval; + } + return wlen; +} + +#if !defined(__linux__) && !defined(WIN32) +// does not have sendmsg or recvmsg + +int sockbuf::recvmsg (msghdr* msg, int msgf) +{ + if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::recvmsg", sockname.c_str()); + + if (rep->oob && atmark ()) + throw sockoob (); + + int rval = ::recvmsg(rep->sock, msg, msgf); + if (rval == -1) throw sockerr (errno, "sockbuf::recvmsg", sockname.c_str()); + return rval; +} + +int sockbuf::sendmsg (msghdr* msg, int msgf) +// upon error, write throws the number of bytes writen so far instead +// of sockerr. +{ + if (rep->stmo != -1 && is_writeready (rep->stmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::sendmsg", sockname.c_str()); + + int wlen = ::sendmsg (rep->sock, msg, msgf); + if (wlen == -1) throw 0; + return wlen; +} +#endif // !__linux__ && !WIN32 + +int sockbuf::sendtimeout (int wp) +{ + int oldstmo = rep->stmo; + rep->stmo = (wp < 0) ? -1: wp; + return oldstmo; +} + +int sockbuf::recvtimeout (int wp) +{ + int oldrtmo = rep->rtmo; + rep->rtmo = (wp < 0) ? -1: wp; + return oldrtmo; +} + +int sockbuf::is_readready (int wp_sec, int wp_usec) const +{ + fd_set fds; + FD_ZERO (&fds); + FD_SET (rep->sock, &fds); + + timeval tv; + tv.tv_sec = wp_sec; + tv.tv_usec = wp_usec; + + int ret = select (rep->sock+1, &fds, 0, 0, (wp_sec == -1) ? 0: &tv); + if (ret == -1) throw sockerr (errno, "sockbuf::is_readready", sockname.c_str()); + return ret; +} + +int sockbuf::is_writeready (int wp_sec, int wp_usec) const +{ + fd_set fds; + FD_ZERO (&fds); + FD_SET (rep->sock, &fds); + + timeval tv; + tv.tv_sec = wp_sec; + tv.tv_usec = wp_usec; + + int ret = select (rep->sock+1, 0, &fds, 0, (wp_sec == -1) ? 0: &tv); + if (ret == -1) throw sockerr (errno, "sockbuf::is_writeready", sockname.c_str()); + return ret; +} + +int sockbuf::is_exceptionpending (int wp_sec, int wp_usec) const +{ + fd_set fds; + FD_ZERO (&fds); + FD_SET (rep->sock, &fds); + + timeval tv; + tv.tv_sec = wp_sec; + tv.tv_usec = wp_usec; + + int ret = select (rep->sock+1, 0, 0, &fds, (wp_sec == -1) ? 0: &tv); + if (ret == -1) throw sockerr (errno, "sockbuf::is_exceptionpending", sockname.c_str()); + return ret; +} + +void sockbuf::shutdown (shuthow sh) +{ + switch (sh) { + case shut_read: + delete [] eback (); + setg (0, 0, 0); + break; + case shut_write: + delete [] pbase (); + setp (0, 0); + break; + case shut_readwrite: + shutdown (shut_read); + shutdown (shut_write); + break; + } + if (::shutdown(rep->sock, sh) == -1) throw sockerr (errno, "sockbuf::shutdown", sockname.c_str()); +} + +int sockbuf::getopt (int op, void* buf, int len, int level) const +{ + if (::getsockopt (rep->sock, level, op, (char*) buf, (socklen_t*) // LN + &len) == -1) + throw sockerr (errno, "sockbuf::getopt", sockname.c_str()); + return len; +} + +void sockbuf::setopt (int op, void* buf, int len, int level) const +{ + if (::setsockopt (rep->sock, level, op, (char*) buf, len) == -1) + throw sockerr (errno, "sockbuf::setopt", sockname.c_str()); +} + +sockbuf::type sockbuf::gettype () const +{ + int ty=0; + getopt (so_type, &ty, sizeof (ty)); + return sockbuf::type(ty); +} + +int sockbuf::clearerror () const +{ + int err=0; + getopt (so_error, &err, sizeof (err)); + return err; +} + +bool sockbuf::debug () const +{ + int old = 0; + getopt (so_debug, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::debug (bool set) const +{ + int old=0; + int opt = set; + getopt (so_debug, &old, sizeof (old)); + setopt (so_debug, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::reuseaddr () const +{ + int old = 0; + getopt (so_reuseaddr, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::reuseaddr (bool set) const +{ + int old=0; + int opt = set; + getopt (so_reuseaddr, &old, sizeof (old)); + setopt (so_reuseaddr, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::keepalive () const +{ + int old = 0; + getopt (so_keepalive, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::keepalive (bool set) const +{ + int old=0; + int opt = set; + getopt (so_keepalive, &old, sizeof (old)); + setopt (so_keepalive, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::dontroute () const +{ + int old = 0; + getopt (so_dontroute, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::dontroute (bool set) const +{ + int old = 0; + int opt = set; + getopt (so_dontroute, &old, sizeof (old)); + setopt (so_dontroute, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::broadcast () const +{ + int old=0; + getopt (so_broadcast, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::broadcast (bool set) const +{ + int old = 0; + int opt = set; + getopt (so_broadcast, &old, sizeof (old)); + setopt (so_broadcast, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::oobinline () const +{ + int old=0; + getopt (so_oobinline, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::oobinline (bool set) const +{ + int old = 0; + int opt = set; + getopt (so_oobinline, &old, sizeof (old)); + setopt (so_oobinline, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::oob (bool b) +{ + bool old = rep->oob; + rep->oob = b; + return old; +} + +sockbuf::socklinger sockbuf::linger () const +{ + socklinger old (0, 0); + getopt (so_linger, &old, sizeof (old)); + return old; +} + +sockbuf::socklinger sockbuf::linger (sockbuf::socklinger opt) const +{ + socklinger old (0, 0); + getopt (so_linger, &old, sizeof (old)); + setopt (so_linger, &opt, sizeof (opt)); + return old; +} + +int sockbuf::sendbufsz () const +{ + int old=0; + getopt (so_sndbuf, &old, sizeof (old)); + return old; +} + +int sockbuf::sendbufsz (int sz) const +{ + int old=0; + getopt (so_sndbuf, &old, sizeof (old)); + setopt (so_sndbuf, &sz, sizeof (sz)); + return old; +} + +int sockbuf::recvbufsz () const +{ + int old=0; + getopt (so_rcvbuf, &old, sizeof (old)); + return old; +} + +int sockbuf::recvbufsz (int sz) const +{ + int old=0; + getopt (so_rcvbuf, &old, sizeof (old)); + setopt (so_rcvbuf, &sz, sizeof (sz)); + return old; +} + +bool sockbuf::atmark () const +// return true, if the read pointer for socket points to an +// out of band data +{ +#ifndef WIN32 + int arg; + if (::ioctl (rep->sock, SIOCATMARK, &arg) == -1) + throw sockerr (errno, "sockbuf::atmark", sockname.c_str()); +#else + unsigned long arg = 0; + if (::ioctlsocket(rep->sock, SIOCATMARK, &arg) == SOCKET_ERROR) + throw sockerr (WSAGetLastError(), "sockbuf::atmark", sockname.c_str()); +#endif // !WIN32 + return arg!=0; +} + +#ifndef WIN32 +int sockbuf::pgrp () const +// return the process group id that would receive SIGIO and SIGURG +// signals +{ + int arg; + if (::ioctl (rep->sock, SIOCGPGRP, &arg) == -1) + throw sockerr (errno, "sockbuf::pgrp", sockname.c_str()); + return arg; +} + +int sockbuf::pgrp (int new_pgrp) const +// set the process group id that would receive SIGIO and SIGURG signals. +// return the old pgrp +{ + int old = pgrp (); + if (::ioctl (rep->sock, SIOCSPGRP, &new_pgrp) == -1) + throw sockerr (errno, "sockbuf::pgrp", sockname.c_str()); + return old; +} + +void sockbuf::closeonexec (bool set) const +// if set is true, set close on exec flag +// else clear close on exec flag +{ + if (set) { + if (::ioctl (rep->sock, FIOCLEX, 0) == -1) + throw sockerr (errno, "sockbuf::closeonexec", sockname.c_str()); + } else { + if (::ioctl (rep->sock, FIONCLEX, 0) == -1) + throw sockerr (errno, "sockbuf::closeonexec", sockname.c_str()); + } +} +#endif // !WIN32 + +long sockbuf::nread () const +// return how many chars are available for reading in the recvbuf of +// the socket. +{ + long arg; +#ifndef WIN32 + if (::ioctl (rep->sock, FIONREAD, &arg) == -1) + throw sockerr (errno, "sockbuf::nread", sockname.c_str()); +#else + if (::ioctlsocket (rep->sock, FIONREAD, (unsigned long *) &arg) == SOCKET_ERROR) + throw sockerr (WSAGetLastError(), "sockbuf::nread", sockname.c_str()); +#endif // !WIN32 + return arg; +} + +long sockbuf::howmanyc () const +// return how many chars are available for reading in the input buffer +// and the recvbuf of the socket. +{ + return showmanyc () + nread (); +} + +void sockbuf::nbio (bool set) const +// if set is true, set socket to non-blocking io. Henceforth, any +// write or read operation will not wait if write or read would block. +// The read or write operation will result throwing a sockerr +// exception with errno set to EWOULDBLOCK. +{ +#ifndef WIN32 + int arg = set; + if (::ioctl (rep->sock, FIONBIO, &arg) == -1) + throw sockerr (errno, "sockbuf::nbio", sockname.c_str()); +#else + unsigned long arg = (set)?1:0; + if (::ioctlsocket (rep->sock, FIONBIO, &arg) == -1) + throw sockerr (WSAGetLastError(), "sockbuf::nbio", sockname.c_str()); +#endif // !WIN32 +} + +#ifndef WIN32 +void sockbuf::async (bool set) const +// if set is true, set socket for asynchronous io. If any io is +// possible on the socket, the process will get SIGIO +{ + int arg = set; + if (::ioctl (rep->sock, FIOASYNC, &arg) == -1) + throw sockerr (errno, "sockbuf::async", sockname.c_str()); +} +#endif // !WIN32 + +osockstream& crlf (osockstream& o) +{ + o << "\r\n"; + o.rdbuf ()->pubsync (); + return o; +} + +osockstream& lfcr (osockstream& o) +{ + o << "\n\r"; + o.rdbuf ()->pubsync (); + return o; +} diff --git a/src/osgPlugins/net/sockstream.h b/src/osgPlugins/net/sockstream.h new file mode 100644 index 000000000..bd28b71ee --- /dev/null +++ b/src/osgPlugins/net/sockstream.h @@ -0,0 +1,364 @@ +// sockstream.h -*- C++ -*- socket library +// Copyright (C) 2002 Herbert Straub +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 +// +// Version: 1.2 2002-07-25 Herbert Straub +// Improved Error Handling - extending the sockerr class by cOperation +// 2003-03-06 Herbert Straub +// adding sockbuf::getname und setname (sockname) +// sockbuf methods throw method name + sockname + +#ifndef _SOCKSTREAM_H +#define _SOCKSTREAM_H + +#include // must be ANSI compatible +#include +#include +#include +#include +#include +#include +#ifndef WIN32 +# include +# include +# include +# define SOCKET int +# define SOCKET_ERROR -1 +#else +# include +# pragma comment(lib, "Wininet") +#endif + +using namespace std; + +#ifdef __linux__ +# define MSG_MAXIOVLEN 16 +#endif // __linux__ + +// socket exception classes +class sockerr { + int err; + string text; +public: + sockerr (int e, const char *operation = NULL): err (e) { + if (operation != NULL) { + text = operation; + } + } + sockerr (int e, const char *operation, const char *specification) : err (e) { + if (operation != NULL) + text = operation; + if (specification != NULL) { + text += "("; + text += specification; + text += ")"; + } + } + sockerr (int e, const string &operation): err (e) { + text = operation; + } + sockerr (const sockerr &O) { + err = O.err; + text = O.text; + } + + const char* what () const { return "sockerr"; } + const char* operation () const { return text.c_str(); } + +// int errno () const { return err; } + int serrno () const { return err; } // LN + const char* errstr () const; + bool error (int eno) const { return eno == err; } + + bool io () const; // non-blocking and interrupt io recoverable error. + bool arg () const; // incorrect argument supplied. recoverable error. + bool op () const; // operational error. recovery difficult. + + bool conn () const; // connection error + bool addr () const; // address error + bool benign () const; // recoverable read/write error like EINTR etc. +}; + +class sockoob { +public: + const char* what () const { return "sockoob"; } +}; + +// socket address classes +struct sockaddr; + +class sockAddr { +public: + virtual ~sockAddr() {} + + virtual operator void* () const =0; + operator sockaddr* () const { return addr (); } + virtual int size () const =0; + virtual int family () const =0; + virtual sockaddr* addr () const =0; +}; + +struct msghdr; + +// socket buffer class +class sockbuf: public streambuf { +public: + enum type { + sock_stream = SOCK_STREAM, + sock_dgram = SOCK_DGRAM, + sock_raw = SOCK_RAW, + sock_rdm = SOCK_RDM, + sock_seqpacket = SOCK_SEQPACKET + }; + enum option { + so_debug = SO_DEBUG, + so_reuseaddr = SO_REUSEADDR, + so_keepalive = SO_KEEPALIVE, + so_dontroute = SO_DONTROUTE, + so_broadcast = SO_BROADCAST, + so_linger = SO_LINGER, + so_oobinline = SO_OOBINLINE, + so_sndbuf = SO_SNDBUF, + so_rcvbuf = SO_RCVBUF, + so_error = SO_ERROR, + so_type = SO_TYPE + }; + enum level { + sol_socket = SOL_SOCKET + }; + enum msgflag { + msg_oob = MSG_OOB, + msg_peek = MSG_PEEK, + msg_dontroute = MSG_DONTROUTE, + +#if !(defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__)) + msg_maxiovlen = MSG_MAXIOVLEN +#endif + }; + enum shuthow { + shut_read, + shut_write, + shut_readwrite + }; + enum { somaxconn = SOMAXCONN }; + struct socklinger { + int l_onoff; // option on/off + int l_linger; // linger time + + socklinger (int a, int b): l_onoff (a), l_linger (b) {} + }; + + typedef char char_type; + typedef streampos pos_type; + typedef streamoff off_type; + typedef int int_type; + typedef int seekdir; + // const int_type eof = EOF; + enum { eof = EOF }; // LN + + struct sockdesc { + int sock; + sockdesc (int d): sock (d) {} + }; + +protected: + struct sockcnt { + SOCKET sock; + int cnt; + int stmo; // -1==block, 0==poll, >0 == waiting time in secs + int rtmo; // -1==block, 0==poll, >0 == waiting time in secs + bool oob; // check for out-of-band byte while reading + void* gend; // end of input buffer + void* pend; // end of output buffer + + sockcnt(SOCKET s) + : sock(s), cnt(1), stmo (-1), rtmo (-1), oob (false), + gend (0), pend (0) {} + }; + + sockcnt* rep; // counts the # refs to sock + string sockname; // name of sockbuf - Herbert Straub + +#if 0 + virtual sockbuf* setbuf (char_type* s, int_type* n); + virtual pos_type seekoff (off_type off, + seekdir way, + ios::openmode which = ios::in|ios::out); + virtual pos_type seekpos (pos_type sp, + ios::openmode which = ios::in|ios::out); +#endif + + virtual int sync (); + + virtual int showmanyc () const; + virtual streamsize xsgetn (char_type* s, streamsize n); + virtual int_type underflow (); + virtual int_type uflow (); + + virtual int_type pbackfail (int_type c = eof); + + virtual streamsize xsputn (const char_type* s, streamsize n); + virtual int_type overflow (int_type c = eof); + +public: + sockbuf (const sockdesc& sd); + sockbuf (int domain, type, int proto); + sockbuf (const sockbuf&); +// sockbuf& operator = (const sockbuf&); + virtual ~sockbuf (); + + int sd () const { return rep->sock; } + int pubsync () { return sync (); } + virtual bool is_open () const; + + virtual void bind (sockAddr&); + virtual void connect (sockAddr&); + + void listen (int num=somaxconn); + virtual sockdesc accept (); + virtual sockdesc accept (sockAddr& sa); + + int read (void* buf, int len); + int recv (void* buf, int len, int msgf=0); + int recvfrom(sockAddr& sa, + void* buf, int len, int msgf=0); + +#if !defined(__linux__) && !defined(WIN32) + int recvmsg (msghdr* msg, int msgf=0); + int sendmsg (msghdr* msg, int msgf=0); +#endif + + int write (const void* buf, int len); + int send (const void* buf, int len, int msgf=0); + int sendto (sockAddr& sa, + const void* buf, int len, int msgf=0); + + int sendtimeout (int wp=-1); + int recvtimeout (int wp=-1); + int is_readready (int wp_sec, int wp_usec=0) const; + int is_writeready (int wp_sec, int wp_usec=0) const; + int is_exceptionpending (int wp_sec, int wp_usec=0) const; + + void shutdown (shuthow sh); + + int getopt(int op, void* buf, int len, + int level=sol_socket) const; + void setopt(int op, void* buf, int len, + int level=sol_socket) const; + + type gettype () const; + int clearerror () const; + bool debug () const; + bool debug (bool set) const; + bool reuseaddr () const; + bool reuseaddr (bool set) const; + bool keepalive () const; + bool keepalive (bool set) const; + bool dontroute () const; + bool dontroute (bool set) const; + bool broadcast () const; + bool broadcast (bool set) const; + bool oobinline () const; + bool oobinline (bool set) const; + bool oob () const { return rep->oob; } + bool oob (bool b); + int sendbufsz () const; + int sendbufsz (int sz) const; + int recvbufsz () const; + int recvbufsz (int sz) const; + socklinger linger () const; + socklinger linger (socklinger opt) const; + socklinger linger (int onoff, int tm) const + { return linger (socklinger (onoff, tm)); } + + bool atmark () const; + long nread () const; + long howmanyc () const; + void nbio (bool set=true) const; + inline void setname (const char *name); + inline void setname (const string &name); + inline const string& getname (); + +#ifndef WIN32 + void async (bool set=true) const; + int pgrp () const; + int pgrp (int new_pgrp) const; + void closeonexec (bool set=true) const; +#endif +}; + +class isockstream: public istream { +protected: +// isockstream (): istream(rdbuf()), ios (0) {} +public: + isockstream(sockbuf* sb): istream(sb), ios (sb) {} + virtual ~isockstream () {} + + sockbuf* rdbuf () { return (sockbuf*)ios::rdbuf(); } + sockbuf* operator -> () { return rdbuf(); } +}; + +class osockstream: public ostream { +protected: + // osockstream (): ostream(static_cast<>rdbuf()), ios (0) {} +public: + osockstream(sockbuf* sb): ostream(sb), ios (sb) {} + virtual ~osockstream () {} + + sockbuf* rdbuf () { return (sockbuf*)ios::rdbuf(); } + sockbuf* operator -> () { return rdbuf(); } +}; + +class iosockstream: public iostream { +protected: + iosockstream (); +public: + iosockstream(sockbuf* sb): iostream(sb), ios (sb) {} + virtual ~iosockstream () {} + + sockbuf* rdbuf () { return (sockbuf*)ios::rdbuf(); } + sockbuf* operator -> () { return rdbuf(); } +}; + +// manipulators +extern osockstream& crlf (osockstream&); +extern osockstream& lfcr (osockstream&); + +// inline + +void sockbuf::setname (const char *name) +{ + sockname = name; +} +void sockbuf::setname (const string &name) +{ + sockname = name; +} +const string& sockbuf::getname () +{ + return sockname; +} + +#endif // _SOCKSTREAM_H