// $Header: /usr/u/moudgill/project/Socket/RCS/sstream.H,v 1.10 1992/10/02 18:35:09 moudgill Exp moudgill $
// 17th December, 1991. Mayan Moudgill.
// $Id: sstream.H,v 1.10 1992/10/02 18:35:09 moudgill Exp moudgill $

#ifndef mSSTREAM_H
#define mSSTREAM_H

/* #define USE_SIG_PF */

#include <sys/types.h>
#include <netinet/in.h>
#include <iostream.h>
#ifndef __GNUC__
#include <iomanip.h>
#else
#include "iomanip.h"
#endif

#include "selset.h"

extern class sockbuf;
extern class sstream;

typedef void iohandlerfn(sstream&, int);
typedef void urghandlerfn(sstream&, int);
typedef void pipehandlerfn(sstream&);
typedef void signalhandlerfn(int);


class sockbuf : public streambuf {
   friend class sstream;
private:
   sstream *                   _stream;
   char                        sunbuf[2];

   sockbuf *                   handlealloc();

protected:
   enum {
      bufsize                  = 1024,
   };

   static selset               _sockets;
   static sstream *            streams[FD_SETSIZE];
   static signalhandlerfn *    iouser;
   static void                 iomanager(int);
   static signalhandlerfn *    urguser;
   static void                 urgmanager(int);
   static signalhandlerfn *    pipeuser;
   static void                 pipemanager(int);

   int                         _sd;
   static int		       numfds;

   int                         _server;
   u_long                      _myaddr;
   u_short                     _myport;
   u_long                      _toaddr;
   u_short                     _toport;

   unsigned                    _serror;
   unsigned                    _serrno;
   unsigned                    _sstate;

   iohandlerfn *               _iohandler;
   urghandlerfn *              _urghandler;
   pipehandlerfn *             _pipehandler;

   virtual int                 doallocate();
   virtual int                 overflow(int = EOF);
   virtual int                 underflow();

                               sockbuf(sstream *);
                               sockbuf(sstream *, char *, int);
   sockbuf *                   open(int);
   sockbuf *                   open(char *, int);
   sockbuf *                   accept(sockbuf&);
   sockbuf *                   close();
			       ~sockbuf();

public:
   int                         sd();
   int                         server();

   void                        addr(u_long&, u_short&);
   void                        toaddr(u_long&, u_short&);
   char *                      host();
   char *                      tohost();
   int                         port();
   int                         toport();

   unsigned                    serror(void);
   unsigned                    serror(unsigned);
   unsigned                    serrno(void);
   unsigned                    sstate(void);
   unsigned                    sstate(unsigned);

   iohandlerfn *               iohandler(iohandlerfn *);
   iohandlerfn *               iohandler();

   urghandlerfn *              urghandler(urghandlerfn *);
   urghandlerfn *              urghandler();

   pipehandlerfn *             pipehandler(pipehandlerfn *);
   pipehandlerfn *             pipehandler();

   static selset               sockets();

   virtual streambuf *         setbuf(char *, int);
   virtual int                 sync();
};

class sstream : public sockbuf, public iostream, virtual public ios {

public:
   enum {
      socketbit                = 0x1,
      bindbit                  = 0x2,
      listenbit                = 0x4,
      acceptbit                = 0x8,
      connectbit               = 0x10,
      sendbit                  = 0x20,
      recvbit                  = 0x40,
      closebit                 = 0x80,

      pipebit                  = 0x100,
      openbit                  = 0x200,
      addrbit                  = 0x400,
      allocbit                 = 0x800,
      otherbit                 = 0x1000,
   };

   enum {
      openedbit                = 0x1,
      serverbit                = 0x2,
      serverdupbit             = 0x4,
      clientbit                = 0x8,

      trapiobit                = 0x10,
      trapurgbit               = 0x20,
      trappipebit              = 0x40,

      noblockbit               = 0x100,
      nolingerbit              = 0x200,
      noreuseaddrbit           = 0x400,
      nokeepalivebit           = 0x800,
      oobinlinebit             = 0x1000,
      unitbufferbit            = 0x2000,
   };

private:
   enum {
      tracecontrol             = 1,
      errorcontrol             = 1,
      monitorcontrol           = 1,
      syscallcontrol           = 1,
   };
   static int                  traceindent;
   void                        handlerror(sockbuf *);

public:
			       sstream();
			       sstream(char *, int);
   void                        open(int);
   void                        open(char *, int);
   void                        open(char *);
   void                        accept(sstream&);
   void                        close();

   static int                  showtrace;
   static int                  showerror;
   static int                  showmonitor;
   static int                  showsyscall;
   static void                 traceon(char *);
   static void                 traceoff(char *);
   static void                 error(int, unsigned int);
   static void                 fail(int, unsigned int);
   static void                 monitor(char *, int);
   static int                  syscall(int, char *);
};

inline                         sockbuf::sockbuf(sstream * s)
      : streambuf(), _stream(s),  _serror(0), _sd(EOF), _server(EOF),
#ifdef apollo
	_sstate(oobinlinebit)
#else
	_sstate(0)
#endif
{
}

inline                         sockbuf::sockbuf(sstream * s, char * p, int l)
      : streambuf(), _stream(s),  _serror(0), _sd(EOF), _server(EOF),
#ifdef apollo
	_sstate(oobinlinebit)
#else
	_sstate(0)
#endif
{
   setbuf(p, l);
}


inline int                     sockbuf::sd()
{
   return _sd;
}

inline int                     sockbuf::server()
{
   return _server;
}

inline void                    sockbuf::addr(u_long& mc, u_short& port)
{
   mc   = _myaddr;
   port = _myport;
}

inline void                    sockbuf::toaddr(u_long& mc, u_short& port)
{
   mc   = _toaddr;
   port = _toport;
}

inline int                     sockbuf::port()
{
   return _myport;
}

inline int                     sockbuf::toport()
{
   return _toport;
}

inline unsigned                sockbuf::serror(void)
{
   return _serror;
}

inline unsigned                sockbuf::serror(unsigned n)
{
int   o;

   o = _serror;
   _serror = n;
   return  o;
}

inline unsigned                sockbuf::serrno(void)
{
   return _serrno;
}

inline unsigned                sockbuf::sstate(void)
{
   return _sstate;
}

inline iohandlerfn *           sockbuf::iohandler(void)
{
   return _iohandler;
}

inline urghandlerfn *          sockbuf::urghandler(void)
{
   return _urghandler;
}

inline pipehandlerfn *         sockbuf::pipehandler(void)
{
   return _pipehandler;
}

inline selset                  sockbuf::sockets()
{
   return _sockets;
}

inline                         sstream::sstream()
     : sockbuf(this)
{
   init(this);
}

inline                         sstream::sstream(char * p, int l)
     : sockbuf(this, p, l)
{
   init(this);
}

inline void                    sstream::handlerror(sockbuf * s)
{
   if( s == 0) {
      if( errorcontrol && showerror ) {
	 cerr << "HANDLE " << _sd << "\n";
      }
      clear( rdstate() | ios::badbit);
   }
}

inline void                   sstream::open(int p)
{
   handlerror( sockbuf::open(p));
}

inline void                   sstream::open(char * h, int p)
{
   handlerror( sockbuf::open(h, p));
}

inline void                   sstream::accept(sstream& s)
{
   handlerror( sockbuf::accept(s));
}

inline void                   sstream::close()
{
   handlerror( sockbuf::close());
   clear();
}

#ifndef __GNUC__
typedef char *   charptr;
IOMANIPdeclare(char);
OMANIP(char)     osend(char);

IOMANIPdeclare(charptr);
IMANIP(charptr)  orecv(char&);
#else
extern oapp<char>  osend;
extern iapp<char&> orecv;
#endif

#endif
