📄 sockstream.cpp
字号:
// 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 <gs4t@virginia.edu>//// 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 <sstream>#include <string>#if defined(__CYGWIN__) || !defined(WIN32)extern "C" {# include <sys/time.h># include <sys/socket.h># include <sys/ioctl.h># include <unistd.h># include <errno.h>}#else# if (_MSC_VER >= 1400)# include <errno.h># endif# 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#ifdef __sun#include <sys/sockio.h>#include <sys/filio.h>#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__<4)) || (defined(WIN32)&&!defined(__CYGWIN__)) || \ (!defined(__APPLE__) && !defined(WIN32) && !defined(_XOPEN_SOURCE_EXTENDED) && !defined(__FreeBSD__))#define socklen_t int#endifconst 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)// 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& 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){#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>(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):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 (c == SOCKET_ERROR) #if defined(__CYGWIN__) || !defined(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){ socklen_t len = sa.size (); int soc = -1; if ((soc = ::accept (rep->sock, sa.addr (), &len)) == -1) throw sockerr (errno, "sockbuf::sockdesc", sockname.c_str());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -