// 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 #if defined(__CYGWIN__) || !defined(WIN32) # include # include # include # define SOCKET int # define SOCKET_ERROR -1 #else # include # include //# include #ifdef _MSC_VER # pragma comment(lib, "Wininet") #endif #endif using namespace std; #if defined(__linux__) || defined(__CYGWIN__) # 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(); #if defined(__CYGWIN__) || !defined(WIN32) void async(bool set=true) const; #endif #if !defined(WIN32) 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): ios (sb) , istream(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): ios (sb) , ostream(sb) {} virtual ~osockstream () {} sockbuf* rdbuf () { return (sockbuf*)ios::rdbuf(); } sockbuf* operator -> () { return rdbuf(); } }; class iosockstream: public iostream { protected: iosockstream (); public: iosockstream(sockbuf* sb): ios(sb), iostream(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