// sockstream.C -*- C++ -*- socket library // Copyright (C) 2002 Herbert Straub for my changes, see ChangeLog. // // 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 #include #include #if defined(__CYGWIN__) || !defined(WIN32) extern "C" { # include # include # include # include # include } #else # if (_MSC_VER >= 1400) # include # endif #ifndef EWOULDBLOCK # define EWOULDBLOCK WSAEWOULDBLOCK #endif #ifndef EINPROGRESS # define EINPROGRESS WSAEINPROGRESS #endif #ifndef EALREADY # define EALREADY WSAEALREADY #endif #ifndef ENOTSOCK # define ENOTSOCK WSAENOTSOCK #endif #ifndef EDESTADDRREQ # define EDESTADDRREQ WSAEDESTADDRREQ #endif #ifndef EMSGSIZE # define EMSGSIZE WSAEMSGSIZE #endif #ifndef EPROTOTYPE # define EPROTOTYPE WSAEPROTOTYPE #endif #ifndef ENOPROTOOPT # define ENOPROTOOPT WSAENOPROTOOPT #endif #ifndef EPROTONOSUPPORT # define EPROTONOSUPPORT WSAEPROTONOSUPPORT #endif #ifndef ESOCKTNOSUPPORT # define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT #endif #ifndef EOPNOTSUPP # define EOPNOTSUPP WSAEOPNOTSUPP #endif #ifndef EPFNOSUPPORT # define EPFNOSUPPORT WSAEPFNOSUPPORT #endif #ifndef EAFNOSUPPORT # define EAFNOSUPPORT WSAEAFNOSUPPORT #endif #ifndef EADDRINUSE # define EADDRINUSE WSAEADDRINUSE #endif #ifndef EADDRNOTAVAIL # define EADDRNOTAVAIL WSAEADDRNOTAVAIL #endif #ifndef ENETDOWN # define ENETDOWN WSAENETDOWN #endif #ifndef ENETUNREACH # define ENETUNREACH WSAENETUNREACH #endif #ifndef ENETRESET # define ENETRESET WSAENETRESET #endif #ifndef ECONNABORTED # define ECONNABORTED WSAECONNABORTED #endif #ifndef ECONNRESET # define ECONNRESET WSAECONNRESET #endif #ifndef ENOBUFS # define ENOBUFS WSAENOBUFS #endif #ifndef EISCONN # define EISCONN WSAEISCONN #endif #ifndef ENOTCONN # define ENOTCONN WSAENOTCONN #endif #ifndef ESHUTDOWN # define ESHUTDOWN WSAESHUTDOWN #endif #ifndef ETOOMANYREFS # define ETOOMANYREFS WSAETOOMANYREFS #endif #ifndef ETIMEDOUT # define ETIMEDOUT WSAETIMEDOUT #endif #ifndef ECONNREFUSED # define ECONNREFUSED WSAECONNREFUSED #endif #ifndef ELOOP # define ELOOP WSAELOOP #endif #ifndef EHOSTDOWN # define EHOSTDOWN WSAEHOSTDOWN #endif #ifndef EHOSTUNREACH # define EHOSTUNREACH WSAEHOSTUNREACH #endif #ifndef EPROCLIM # define EPROCLIM WSAEPROCLIM #endif #ifndef EUSERS # define EUSERS WSAEUSERS #endif #ifndef EDQUOT # define EDQUOT WSAEDQUOT #endif #ifndef EISCONN # define EISCONN WSAEISCONN #endif #ifndef ENOTCONN # define ENOTCONN WSAENOTCONN #endif #ifndef ECONNRESET # define ECONNRESET WSAECONNRESET #endif #ifndef ECONNREFUSED # define ECONNREFUSED WSAECONNREFUSED #endif #ifndef ETIMEDOUT # define ETIMEDOUT WSAETIMEDOUT #endif #ifndef EADDRINUSE # define EADDRINUSE WSAEADDRINUSE #endif #ifndef EADDRNOTAVAIL # define EADDRNOTAVAIL WSAEADDRNOTAVAIL #endif #endif // !WIN32 #ifdef __sun #include #include #endif #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))) // Do not include anything below that define. That should in no case change any forward decls in // system headers ... #if (defined(__APPLE__)&&(__GNUC__<3)) || (defined(WIN32)&&!defined(__CYGWIN__)) || \ (!defined(__APPLE__) && !defined(WIN32) && !defined(__GNUC__) && !defined(_XOPEN_SOURCE_EXTENDED) && !defined(__FreeBSD__)) #define socklen_t int #endif const char* sockerr::errstr () const { #if defined(__CYGWIN__) || !defined(WIN32) return strerror(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__) && !defined(__sun) && !defined(__hpux) && !defined(__EMSCRIPTEN__) // 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: #if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK) case EAGAIN: #endif return true; } return false; } sockbuf::sockbuf (const sockbuf::sockdesc& thesd) // : rep (new sockbuf::sockcnt (sd.sock)) { rep = new sockbuf::sockcnt (thesd.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 (nullptr) { #if defined(WIN32) && !defined(__CYGWIN__) WORD version = MAKEWORD(1,1); WSADATA wsaData; WSAStartup(version, &wsaData); #endif SOCKET soc = ::socket (domain, st, proto); if (soc == static_cast(SOCKET_ERROR)) #if defined(__CYGWIN__) || !defined(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) : std::streambuf(), //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 (); #if defined(__CYGWIN__) || !defined(WIN32) int c = close (rep->sock); #else int c = closesocket(rep->sock); #endif delete rep; #if 0 if (c == SOCKET_ERROR) #if defined(__CYGWIN__) || !defined(WIN32) throw sockerr (errno, "sockbuf::~sockbuf", sockname.text.c_str()); #else throw sockerr(WSAGetLastError(), "sockbuf::~sockbuf", sockname.text.c_str()); #endif #else assert(c != SOCKET_ERROR); (void)c; #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 std::stringstream sb; std::string err ("sockbuf::sync"); err += "(" + sockname.text + ")"; 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; } std::streamsize sockbuf::showmanyc () // 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 () == nullptr) 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; } std::streamsize sockbuf::xsgetn (char_type* s, std::streamsize n) { std::streamsize rval = showmanyc (); if (rval >= n) { memcpy (s, gptr (), (size_t)(n * sizeof (char_type))); gbump ((int)n); return n; } memcpy (s, gptr (), (size_t)(rval * sizeof (char_type))); gbump ((int)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 () == nullptr) return eof; if (c == eof) return sync (); if (pptr () == epptr ()) sync (); *pptr () = (char_type)c; pbump (1); return c; } std::streamsize sockbuf::xsputn (const char_type* s, std::streamsize n) { std::streamsize wval = epptr () - pptr (); if (n <= wval) { memcpy (pptr (), s, (size_t)(n * sizeof (char_type))); pbump ((int)n); return n; } memcpy (pptr (), s, (size_t)(wval * sizeof (char_type))); pbump ((int)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.text.c_str()); } void sockbuf::connect (sockAddr& sa) { if (::connect(rep->sock, sa.addr (), sa.size()) == -1) throw sockerr (errno, "sockbuf::connect", sockname.text.c_str()); } void sockbuf::listen (int num) { if (::listen (rep->sock, num) == -1) throw sockerr (errno, "sockbuf::listen", sockname.text.c_str()); } sockbuf::sockdesc sockbuf::accept (sockAddr& sa) { socklen_t len = sa.size (); int soc = -1; if ((int)(soc = ::accept (rep->sock, sa.addr (), &len)) == -1) throw sockerr (errno, "sockbuf::sockdesc", sockname.text.c_str()); return {soc}; } sockbuf::sockdesc sockbuf::accept () { int soc = -1; if ((int)(soc = ::accept (rep->sock, nullptr, nullptr)) == -1) throw sockerr (errno, "sockbuf::sockdesc", sockname.text.c_str()); return {soc}; } int sockbuf::read (void* buf, int len) { if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) { throw sockerr (ETIMEDOUT, "sockbuf::read", sockname.text.c_str()); } if (rep->oob && atmark ()) throw sockoob (); int rval = 0; //if ((rval = ::read (rep->sock, (char*) buf, len)) == -1) if ((rval = ::recv (rep->sock, (char*) buf, len, 0)) == -1) throw sockerr (errno, "sockbuf::read", sockname.text.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.text.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.text.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.text.c_str()); if (rep->oob && atmark ()) throw sockoob (); int rval = 0; socklen_t __sa_len = sa.size (); if ((rval = ::recvfrom (rep->sock, (char*) buf, len, msgf, sa.addr (), &__sa_len)) == -1) throw sockerr (errno, "sockbuf::recvfrom", sockname.text.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.text.c_str()); int wlen=0; while(len>0) { //int wval = ::write (rep->sock, (char*) buf, len); int wval = ::send (rep->sock, (const char*) buf, len, 0); //assert( wval > 0 ); 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.text.c_str()); int wlen=0; while(len>0) { int wval = ::send (rep->sock, (const 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.text.c_str()); int wlen=0; while(len>0) { int wval = ::sendto (rep->sock, (const 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.text.c_str()); if (rep->oob && atmark ()) throw sockoob (); int rval = ::recvmsg(rep->sock, msg, msgf); if (rval == -1) throw sockerr (errno, "sockbuf::recvmsg", sockname.text.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.text.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 ((int)(rep->sock)+1, &fds, nullptr, nullptr, (wp_sec == -1) ? nullptr: &tv); if (ret == -1) throw sockerr (errno, "sockbuf::is_readready", sockname.text.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 ((int)(rep->sock)+1, nullptr, &fds, nullptr, (wp_sec == -1) ? nullptr: &tv); if (ret == -1) throw sockerr (errno, "sockbuf::is_writeready", sockname.text.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 ((int)(rep->sock)+1, nullptr, nullptr, &fds, (wp_sec == -1) ? nullptr: &tv); if (ret == -1) throw sockerr (errno, "sockbuf::is_exceptionpending", sockname.text.c_str()); return ret; } void sockbuf::shutdown (shuthow sh) { switch (sh) { case shut_read: delete [] eback (); setg (nullptr, nullptr, nullptr); break; case shut_write: delete [] pbase (); setp (nullptr, nullptr); break; case shut_readwrite: shutdown (shut_read); shutdown (shut_write); break; } if (::shutdown(rep->sock, sh) == -1) throw sockerr (errno, "sockbuf::shutdown", sockname.text.c_str()); } int sockbuf::getopt (int op, void* buf, int len, int thelevel) const { socklen_t salen = len; if (::getsockopt (rep->sock, thelevel, op, (char*) buf, &salen) == -1) throw sockerr (errno, "sockbuf::getopt", sockname.text.c_str()); return len; } void sockbuf::setopt (int op, void* buf, int len, int thelevel) const { if (::setsockopt (rep->sock, thelevel, op, (char*) buf, len) == -1) throw sockerr (errno, "sockbuf::setopt", sockname.text.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 { #if !defined(WIN32) || defined(__CYGWIN__) int arg; if (::ioctl (rep->sock, SIOCATMARK, &arg) == -1) throw sockerr (errno, "sockbuf::atmark", sockname.text.c_str()); #else unsigned long arg = 0; if (::ioctlsocket(rep->sock, SIOCATMARK, &arg) == SOCKET_ERROR) throw sockerr (WSAGetLastError(), "sockbuf::atmark", sockname.text.c_str()); #endif // !WIN32 return arg!=0; } //#if !defined(WIN32) #if !(defined(__CYGWIN__) || defined(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.text.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.text.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 !defined( __sgi) && !defined(__hpux) if (set) { if (::ioctl (rep->sock, FIOCLEX, 0) == -1) throw sockerr (errno, "sockbuf::closeonexec", sockname.text.c_str()); } else { if (::ioctl (rep->sock, FIONCLEX, 0) == -1) throw sockerr (errno, "sockbuf::closeonexec", sockname.text.c_str()); } #endif } #endif // !WIN32 long sockbuf::nread () const // return how many chars are available for reading in the recvbuf of // the socket. { long arg; #if defined(__CYGWIN__) || !defined(WIN32) if (::ioctl (rep->sock, FIONREAD, &arg) == -1) throw sockerr (errno, "sockbuf::nread", sockname.text.c_str()); #else if (::ioctlsocket (rep->sock, FIONREAD, (unsigned long *) &arg) == SOCKET_ERROR) throw sockerr (WSAGetLastError(), "sockbuf::nread", sockname.text.c_str()); #endif // !WIN32 return arg; } long sockbuf::howmanyc () // return how many chars are available for reading in the input buffer // and the recvbuf of the socket. { std::streamsize theShowMany = showmanyc(); assert (theShowMany < INT_MAX); return (long)theShowMany + 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. { #if defined(__CYGWIN__) || !defined(WIN32) int arg = set; if (::ioctl (rep->sock, FIONBIO, &arg) == -1) throw sockerr (errno, "sockbuf::nbio", sockname.text.c_str()); #else unsigned long arg = (set)?1:0; if (::ioctlsocket (rep->sock, FIONBIO, &arg) == -1) throw sockerr (WSAGetLastError(), "sockbuf::nbio", sockname.text.c_str()); #endif // !WIN32 } #if defined(__CYGWIN__) || !defined(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.text.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; }