Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

netstream.h

Go to the documentation of this file.
00001 #ifndef INCLUDED_netstream_h_
00002 #define INCLUDED_netstream_h_
00003 
00004 #ifdef PLATFORM_APERIOS
00005 #error netstream not yet supported on AIBO/Aperios
00006 #endif
00007 
00008 #include <cstdio>
00009 #include <cstring>
00010 #include <iostream>
00011 #include <iosfwd>
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <ctype.h>
00015 #include <unistd.h>
00016 #include <stdexcept>
00017 
00018 #include <errno.h>
00019 #include <signal.h>
00020 //#include <sys/time.h>
00021 #include <sys/types.h>
00022 #include <sys/socket.h>
00023 #include <netinet/in.h>
00024 #include <arpa/inet.h>
00025 #include <netdb.h>
00026 #include <cstring>
00027 #include <string>
00028 #include <poll.h>
00029 
00030 #define OTAssert(str, b) if(!b) std::cerr << "ERR " << __FILE__ << '(' << __LINE__ << "): " << str << std::endl;
00031 
00032 class IPaddr {
00033 public:
00034   typedef std::string ipname_t;
00035   typedef unsigned int ipnum_t;
00036   typedef unsigned short ipport_t;
00037   const static unsigned int maxHostNameLen;
00038   
00039   IPaddr();
00040   explicit IPaddr(const ipnum_t& num);
00041   explicit IPaddr(const ipname_t& name);
00042   IPaddr(const ipnum_t& num, const ipport_t& port);
00043   IPaddr(const ipname_t& name, const ipport_t& port);
00044   virtual ~IPaddr() {}
00045 
00046   virtual bool set_num(const ipnum_t& num);
00047   virtual bool set_name(const ipname_t& name);
00048   virtual bool set_addr(const ipnum_t& num, const ipport_t& port) { return set_num(num) && set_port(port); }
00049   virtual bool set_addr(const ipname_t& name, const ipport_t& port) { return set_name(name) && set_port(port); }
00050   virtual bool set_port(const ipport_t& port) { ipport=port; server.sin_port=htons(port); return true; }
00051   virtual ipnum_t get_num() const { return ntohl(server.sin_addr.s_addr); }
00052   virtual const ipname_t& get_name() const { return ipname; }
00053   virtual ipname_t get_display_num() const;
00054   virtual ipname_t get_rname() const;
00055   virtual ipport_t get_port() const { return ipport; }
00056 
00057   virtual const sockaddr_in& get_addr() const { return server; }
00058 protected:
00059   void Init();
00060   
00061   struct sockaddr_in server;
00062   ipname_t ipname;
00063   ipport_t ipport;
00064 };
00065 
00066 
00067 template <class charT, class traits=std::char_traits<charT> >
00068 class basic_netbuf : public std::basic_streambuf<charT,traits> {
00069 public:
00070   //  Types:
00071   typedef charT                     char_type;
00072   typedef typename traits::int_type int_type;
00073   typedef typename traits::pos_type pos_type;
00074   typedef typename traits::off_type off_type;
00075   typedef traits                    traits_type;
00076   
00077   //Constructors/Destructors:
00078   basic_netbuf();
00079   basic_netbuf(const IPaddr& addr, bool datagram=false);
00080   basic_netbuf(const IPaddr::ipname_t& host, const IPaddr::ipport_t port, bool datagram=false);
00081   basic_netbuf(size_t buf_in_size, size_t buf_out_size);
00082   virtual ~basic_netbuf();
00083   
00084   
00085   
00086   //basic_netbuf Functions:
00087 public:
00088   virtual bool      open(const IPaddr& addr, bool datagram=false);
00089   virtual bool      open(const IPaddr::ipname_t& str, bool datagram=false);
00090   virtual bool      open(const IPaddr::ipname_t& ahost, unsigned int aPort, bool datagram=false) { return open(IPaddr(ahost,aPort),datagram); }
00091   virtual bool      listen(unsigned int aPort, bool datagram=false) { return listen(IPaddr(ntohl(INADDR_ANY),aPort),datagram); }
00092   virtual bool      listen(const IPaddr& addr, bool datagram=false);
00093   virtual bool      is_open() const { return (sock!=INVALID_SOCKET); }
00094   virtual void      update_status();
00095   virtual void      close();
00096   virtual void      reset() { close(); reconnect(); }
00097   
00098   virtual int     adoptFD(int fd) { int old=sock; sock=fd; update_status(); return old; }
00099 
00100   virtual void      setReconnect(bool doReconnect) { autoReconnect = doReconnect; }
00101   virtual bool      getReconnect() const { return autoReconnect; }
00102   
00103   virtual void      setEcho(bool val = true) { is_echoing = val; }
00104   virtual bool      getEcho() { return is_echoing; }
00105   
00106   virtual const IPaddr&   getPeerAddress() const { return peerAddress; }
00107   virtual const IPaddr&   getLocalAddress() const { return localAddress; }
00108   
00109 protected:
00110   virtual void      reconnect();
00111   static void     printBuffer(const char* buf, int buflen, const char* header, const char* prefix);
00112   void          Init() { Init(def_buf_in_size, def_buf_out_size); }
00113   void          Init(size_t insize, size_t outsize);
00114 
00115 
00116   
00117 //Inherited Functions:
00118 public:
00119   virtual void      in_sync(); //users shouldn't need to call this directly... but can if want to
00120   virtual void      out_flush();
00121 
00122 protected:
00123   using std::basic_streambuf<charT,traits>::eback;
00124   using std::basic_streambuf<charT,traits>::gptr;
00125   using std::basic_streambuf<charT,traits>::egptr;
00126   using std::basic_streambuf<charT,traits>::gbump;
00127   using std::basic_streambuf<charT,traits>::pbase;
00128   using std::basic_streambuf<charT,traits>::pptr;
00129   using std::basic_streambuf<charT,traits>::epptr;
00130   using std::basic_streambuf<charT,traits>::pbump;
00131   
00132   //  lib.streambuf.virt.get Get area:
00133   virtual std::streamsize showmanyc();
00134   //  virtual streamsize xsgetn(char_type* s, streamsize n);
00135   virtual int_type    underflow();
00136   virtual int_type    uflow();
00137   
00138   //  lib.streambuf.virt.pback Putback:
00139   //  virtual int_type pbackfail(int_type c = traits::eof() );
00140   //  lib.streambuf.virt.put Put area:
00141   //  virtual streamsize xsputn(const char_type* s, streamsize n);
00142   virtual int_type    overflow(int_type c  = traits::eof());
00143   
00144   //  lib.streambuf.virt.buffer Buffer management and positioning:
00145   //  virtual _Myt basic_netbuf<char_type, traits_type>* setbuf(char_type* s, streamsize n);
00146   virtual pos_type seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
00147   virtual pos_type seekpos(pos_type sp, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) {  return seekoff(sp,std::ios_base::beg,which); }
00148   virtual int     sync();
00149   //  lib.streambuf.virt.locales Locales:
00150   //  virtual void imbue(const locale &loc);
00151   
00152 //Data:
00153 protected:
00154   static const int INVALID_SOCKET=-1;
00155   charT *buf_in, *buf_out;
00156   bool using_buf_in, using_buf_out;
00157   static const size_t def_buf_in_size;
00158   static const size_t def_buf_out_size;
00159   int sock;
00160   bool canRead;
00161   bool canWrite;
00162   bool is_echoing;
00163   bool autoReconnect;
00164   bool sockFromServer;
00165   
00166   IPaddr peerAddress;
00167   IPaddr localAddress;
00168   IPaddr tgtAddress;
00169   bool isDatagram;
00170 
00171 private:
00172   basic_netbuf(const basic_netbuf&); // copy constructor, don't call
00173   basic_netbuf& operator=(const basic_netbuf&); //!< assignment, don't call
00174 };
00175 template <class charT, class traits>
00176 const size_t basic_netbuf<charT,traits>::def_buf_in_size=(1<<14)-28;
00177 template <class charT, class traits>
00178 const size_t basic_netbuf<charT,traits>::def_buf_out_size=(1<<14)-28;
00179 
00180 
00181 template <class charT, class traits=std::char_traits<charT> >
00182 class basic_netbuf_interface {
00183 public:
00184   basic_netbuf_interface() : nb() {}
00185   basic_netbuf_interface(const IPaddr::ipname_t& host, const IPaddr::ipport_t port, bool datagram) : nb(host,port,datagram) {}
00186   basic_netbuf_interface(const IPaddr& addr, bool datagram) : nb(addr,datagram) {}
00187   basic_netbuf_interface(size_t buf_in_size, size_t buf_out_size) : nb(buf_in_size,buf_out_size) {}
00188   
00189   inline bool     open(const IPaddr& addr, bool datagram=false) { return nb.open(addr,datagram); }
00190   inline bool     open(const IPaddr::ipname_t& str, bool datagram=false) { return nb.open(str,datagram); }
00191   inline bool     open(const IPaddr::ipname_t& ahost, unsigned int aPort, bool datagram=false) { return nb.open(ahost,aPort,datagram); }
00192   inline bool     listen(unsigned int aPort, bool datagram=false) { return nb.listen(aPort,datagram); }
00193   inline bool     listen(const IPaddr& addr, bool datagram=false) { return nb.listen(addr,datagram); }
00194   
00195   inline bool     is_open() const { return nb.is_open(); }
00196   inline void     update_status() { nb.update_status(); }
00197   
00198   inline void     close() { nb.close(); }
00199   inline void     reset() { nb.close(); nb.reconnect(); }
00200   
00201   inline void     setReconnect(bool reconnect) { nb.setReconnect(reconnect); }
00202   inline bool     getReconnect() const { return nb.getReconnect(); }
00203   
00204   inline void     setEcho(bool val=true) { nb.setEcho(val); }
00205   inline bool     getEcho() { return nb.getEcho(); }
00206   
00207   inline const IPaddr&    getPeerAddress() const { return nb.getPeerAddress(); }
00208   inline const IPaddr&    getLocalAddress() const { return nb.getLocalAddress(); }
00209   
00210   inline basic_netbuf<charT, traits>* rdbuf() const { return const_cast<basic_netbuf<charT, traits>*>(&nb); }
00211 
00212 protected:
00213   ~basic_netbuf_interface() {}
00214   basic_netbuf<charT, traits> nb;
00215 };
00216 
00217 template <class charT, class traits=std::char_traits<charT> >
00218 class basic_inetstream : public virtual basic_netbuf_interface<charT,traits>, public std::basic_istream<charT,traits>
00219 {
00220 public:
00221   typedef charT                     char_type;
00222   typedef typename traits::int_type int_type;
00223   typedef typename traits::pos_type pos_type;
00224   typedef typename traits::off_type off_type;
00225   typedef traits                    traits_type;
00226   //  lib.ifstream.cons Constructors:
00227   basic_inetstream() : basic_netbuf_interface<charT,traits>(), std::basic_istream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()) {}
00228   basic_inetstream(const IPaddr& addr, bool datagram=false) : basic_netbuf_interface<charT,traits>(addr,datagram), std::basic_istream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()) {}
00229   basic_inetstream(const IPaddr::ipname_t& host, const IPaddr::ipport_t port, bool datagram=false) : basic_netbuf_interface<charT,traits>(host,port,datagram), std::basic_istream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()) {}
00230   basic_inetstream(size_t buf_in_size, size_t buf_out_size) : basic_netbuf_interface<charT,traits>(buf_in_size,buf_out_size), std::basic_istream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()) {}
00231   using basic_netbuf_interface<charT,traits>::rdbuf;
00232 };
00233 
00234 
00235 template <class charT, class traits=std::char_traits<charT> >
00236 class basic_onetstream : public virtual basic_netbuf_interface<charT,traits>, public std::basic_ostream<charT,traits>
00237 {
00238 public:
00239   typedef charT                     char_type;
00240   typedef typename traits::int_type int_type;
00241   typedef typename traits::pos_type pos_type;
00242   typedef typename traits::off_type off_type;
00243   typedef traits                    traits_type;
00244   //  lib.ifstream.cons Constructors:
00245   basic_onetstream() : basic_netbuf_interface<charT,traits>(), std::basic_ostream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()) {}
00246   basic_onetstream(const IPaddr& addr, bool datagram=false) : basic_netbuf_interface<charT,traits>(addr,datagram), std::basic_ostream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()) {}
00247   basic_onetstream(const IPaddr::ipname_t& host, const IPaddr::ipport_t port, bool datagram=false) : basic_netbuf_interface<charT,traits>(host,port,datagram), std::basic_ostream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()) {}
00248   basic_onetstream(size_t buf_in_size, size_t buf_out_size) : basic_netbuf_interface<charT,traits>(buf_in_size,buf_out_size) , std::basic_ostream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()){}
00249   using basic_netbuf_interface<charT,traits>::rdbuf;
00250 };
00251 
00252 
00253 template <class charT, class traits=std::char_traits<charT> >
00254 class basic_ionetstream : public virtual basic_netbuf_interface<charT,traits>, public std::basic_iostream<charT,traits>
00255 {
00256 public:
00257   typedef charT                     char_type;
00258   typedef typename traits::int_type int_type;
00259   typedef typename traits::pos_type pos_type;
00260   typedef typename traits::off_type off_type;
00261   typedef traits                    traits_type;
00262   //  lib.ifstream.cons Constructors:
00263   basic_ionetstream() : basic_netbuf_interface<charT,traits>(), std::basic_iostream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()) {}
00264   basic_ionetstream(const IPaddr& addr, bool datagram=false) : basic_netbuf_interface<charT,traits>(addr,datagram), std::basic_iostream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()) {}
00265   basic_ionetstream(const IPaddr::ipname_t& host, const IPaddr::ipport_t port, bool datagram=false) : basic_netbuf_interface<charT,traits>(host,port,datagram), std::basic_iostream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()) {}
00266   basic_ionetstream(size_t buf_in_size, size_t buf_out_size) : basic_netbuf_interface<charT,traits>(buf_in_size,buf_out_size) , std::basic_iostream<charT,traits>(basic_netbuf_interface<charT,traits>::rdbuf()){}
00267   using basic_netbuf_interface<charT,traits>::rdbuf;
00268 };
00269 
00270 /*
00271 template<class T>
00272 class char_traits {
00273 public:
00274   typedef T char_type;
00275   typedef int int_type;
00276   typedef T* pos_type;
00277   typedef unsigned int off_type;
00278   static void copy(pos_type dst, pos_type src, off_type size) {
00279     memcpy(dst,src,size);
00280   }
00281   static void move(pos_type dst, pos_type src, off_type size) {
00282     memmove(dst,src,size);
00283   }
00284   static int to_int_type(T c) { return c; }
00285   static int eof() { return EOF; }
00286 };*/
00287 
00288 typedef basic_netbuf<char, std::char_traits<char> > netbuf;
00289 typedef basic_inetstream<char, std::char_traits<char> > inetstream;
00290 typedef basic_onetstream<char, std::char_traits<char> > onetstream;
00291 typedef basic_ionetstream<char, std::char_traits<char> > ionetstream;
00292 
00293 
00294 
00295 
00296 template <class charT, class traits>
00297 basic_netbuf<charT,traits>::basic_netbuf() 
00298   : std::basic_streambuf<charT,traits>(), buf_in(NULL), buf_out(NULL), using_buf_in(false), using_buf_out(false),
00299   sock(INVALID_SOCKET), canRead(false), canWrite(false), is_echoing(false), autoReconnect(false), sockFromServer(),
00300   peerAddress(), localAddress(), tgtAddress(), isDatagram() {
00301   Init();
00302 }
00303 template <class charT, class traits>
00304 basic_netbuf<charT,traits>::basic_netbuf(const IPaddr& addr, bool datagram)
00305   : std::basic_streambuf<charT,traits>(), buf_in(NULL), buf_out(NULL), using_buf_in(false), using_buf_out(false),
00306   sock(INVALID_SOCKET), canRead(false), canWrite(false), is_echoing(false), autoReconnect(false), sockFromServer(),
00307   peerAddress(), localAddress(), tgtAddress(), isDatagram()  {
00308   Init();
00309   open(addr,datagram);
00310 }
00311 
00312 template <class charT, class traits>
00313 basic_netbuf<charT,traits>::basic_netbuf(const IPaddr::ipname_t& host, const IPaddr::ipport_t port, bool datagram)
00314   : std::basic_streambuf<charT,traits>(), buf_in(NULL), buf_out(NULL), using_buf_in(false), using_buf_out(false),
00315   sock(INVALID_SOCKET), canRead(false), canWrite(false), is_echoing(false), autoReconnect(false), sockFromServer(),
00316   peerAddress(), localAddress(), tgtAddress(), isDatagram()  {
00317   Init();
00318   open(host,port,datagram);
00319 }
00320 
00321 template <class charT, class traits>
00322 basic_netbuf<charT,traits>::basic_netbuf(size_t buf_in_size, size_t buf_out_size) 
00323   : std::basic_streambuf<charT,traits>(), buf_in(NULL), buf_out(NULL), using_buf_in(false), using_buf_out(false),
00324   sock(INVALID_SOCKET), canRead(false), canWrite(false), is_echoing(false), autoReconnect(false), sockFromServer(),
00325   peerAddress(), localAddress(), tgtAddress(), isDatagram()  {
00326   Init();
00327 }
00328 
00329 template <class charT, class traits>
00330 basic_netbuf<charT,traits>::~basic_netbuf() {
00331   autoReconnect=false;
00332   if(is_open()) {
00333     out_flush();
00334     close();
00335   }
00336   if(using_buf_in)
00337     delete [] buf_in;
00338   if(using_buf_out)
00339     delete [] buf_out;
00340 }
00341 
00342 template<class charT, class traits>
00343 void
00344 basic_netbuf<charT,traits>::Init(size_t insize, size_t outsize) {
00345   buf_in = new charT[insize];
00346   buf_out = new charT[outsize];
00347   using_buf_in = using_buf_out = true;
00348   setg(buf_in,buf_in+insize,buf_in+insize);
00349   setp(buf_out,buf_out+outsize);
00350   //  cout << "Buffer is:" << endl;
00351   //  cout << "Input buffer: " << egptr() << " to " << egptr() << " at " << gptr() << endl;
00352   //  cout << "Output buffer: " << pbase() << " to " << epptr() << " at " << pptr() << endl;
00353 }
00354 
00355 template<class charT, class traits>
00356 void
00357 basic_netbuf<charT,traits>::update_status() {
00358   pollfd pfd;
00359   pfd.fd=sock;
00360   pfd.events = POLLIN | POLLOUT;
00361   if(poll(&pfd,1,0)==-1)
00362     perror("basic_netbuf poll");
00363   if(pfd.revents&(POLLERR|POLLHUP|POLLNVAL)) {
00364     close();
00365     if(autoReconnect)
00366       reconnect();
00367     if(is_open())
00368       update_status();
00369   } else {
00370     canRead = (pfd.revents&POLLIN);
00371     canWrite = (pfd.revents&POLLOUT);
00372   }
00373 }
00374 
00375 template <class charT, class traits>
00376 bool
00377 basic_netbuf<charT,traits>::open(const IPaddr& addr, bool datagram) {
00378   if(is_open())
00379     close();
00380   tgtAddress=addr;
00381   
00382   while(!is_open()) {
00383     //cout << "netstream opening " << addr.get_display_num() << ":" << addr.get_port() << endl;
00384     // create socket
00385     int opsock = ::socket(AF_INET, datagram ? (int)SOCK_DGRAM : (int)SOCK_STREAM, 0);
00386     if(opsock < 1) {
00387       perror("netstream socket()");
00388       //std::cerr << "netstream error: socket failed to create stream socket" << std::endl;
00389       return false;
00390     }
00391     int on=1;
00392     if ( ::setsockopt ( opsock, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 ) {
00393       perror("netstream SO_REUSEADDR setsockopt");
00394     }
00395     if(datagram) {
00396       if ( ::setsockopt ( opsock, SOL_SOCKET, SO_BROADCAST, ( const char* ) &on, sizeof ( on ) ) == -1 ) {
00397         perror("netstream SO_BROADCAST setsockopt");
00398       }
00399       const int sndbuf=(epptr()-pbase());
00400       if ( ::setsockopt ( opsock, SOL_SOCKET, SO_SNDBUF, ( const char* ) &sndbuf, sizeof ( sndbuf ) ) == -1 ) {
00401         perror("netstream SO_SNDBUF setsockopt");
00402       }
00403     }
00404     
00405     // connect to server.
00406     sockaddr_in server = addr.get_addr();
00407     int err = ::connect(opsock, (const sockaddr *) &server, sizeof(server));
00408     if(err < 0) {
00409       //perror("netstream connect()");
00410       //cout << "netstream error: connect failed to connect to requested address" << endl;
00411 			::close(opsock);
00412       if(!autoReconnect)
00413         return false;
00414       usleep(750000); // don't try to reconnect too fast
00415     } else {
00416       sock=opsock;
00417       sockFromServer=false;
00418       isDatagram=datagram;
00419       socklen_t server_size=sizeof(server);
00420       err = ::getpeername(sock, reinterpret_cast<sockaddr *>(&server), &server_size);
00421       if(err<0)
00422         perror("netstream getpeername");
00423       else {
00424         peerAddress.set_addr(ntohl(server.sin_addr.s_addr), ntohs(server.sin_port));
00425       }
00426       err = ::getsockname(sock, reinterpret_cast<sockaddr *>(&server), &server_size);
00427       if(err<0)
00428         perror("netstream getsockname");
00429       else {
00430         localAddress.set_addr(ntohl(server.sin_addr.s_addr), ntohs(server.sin_port));
00431       }
00432       //cout << " netstream connected to " << getPeerAddress().get_display_num() << ":" << getPeerAddress().get_port()
00433       //  << " from " << getLocalAddress().get_display_num() << ":" << getLocalAddress().get_port() << endl;
00434     }
00435   }
00436   
00437   return true;
00438 }
00439 
00440 template <class charT, class traits>
00441 bool
00442 basic_netbuf<charT,traits>::listen(const IPaddr& addr, bool datagram) {
00443   if(is_open())
00444     close();
00445   tgtAddress=addr;
00446   
00447   // create socket
00448   int opsock = ::socket(AF_INET, datagram ? (int)SOCK_DGRAM : (int)SOCK_STREAM, 0);
00449   if(opsock < 1) {
00450     perror("netstream socket");
00451     //cout << "netstream error: socket failed to create stream socket" << endl;
00452     return false;
00453   }
00454   int on=1;
00455   if ( ::setsockopt ( opsock, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 ) {
00456     perror("netstream SO_REUSEADDR setsockopt");
00457   }
00458   if(datagram) {
00459     if ( ::setsockopt ( opsock, SOL_SOCKET, SO_BROADCAST, ( const char* ) &on, sizeof ( on ) ) == -1 ) {
00460       perror("netstream SO_BROADCAST setsockopt");
00461     }
00462     const int sndbuf=(epptr()-pbase());
00463     if ( ::setsockopt ( opsock, SOL_SOCKET, SO_SNDBUF, ( const char* ) &sndbuf, sizeof ( sndbuf ) ) == -1 ) {
00464       perror("netstream SO_SNDBUF setsockopt");
00465     }
00466   }
00467   
00468   sockaddr_in server = addr.get_addr();
00469   
00470   // bind socket to specified address
00471   if(::bind(opsock, (const sockaddr *) &server, sizeof(server)) != 0) {
00472     //perror("netstream bind");
00473 		::close(opsock);
00474     return false;
00475   }
00476   
00477   // tell OS to start listening
00478   if(::listen(opsock, 1) != 0) {
00479     perror("netstream listen");
00480 		::close(opsock);
00481     return false;
00482   }
00483   
00484   while(!is_open()) {
00485     // block until connection
00486     sockaddr tmp;
00487     socklen_t tmplen;
00488     int sock2 = ::accept(opsock, &tmp, &tmplen);
00489     if(sock2 < 0) {
00490       perror("netstream accept");
00491       if(!autoReconnect) {
00492 				::close(opsock);
00493         return false;
00494       }
00495     } else {
00496       // close server socket
00497 			::close(opsock);
00498       //replace with accepted socket
00499       sock=sock2;
00500       sockFromServer=true;
00501       isDatagram=datagram;
00502       socklen_t server_size=sizeof(server);
00503       int err = ::getpeername(sock, reinterpret_cast<sockaddr *>(&server), &server_size);
00504       if(err<0)
00505         perror("netstream getpeername");
00506       else {
00507         peerAddress.set_addr(ntohl(server.sin_addr.s_addr), ntohs(server.sin_port));
00508       }
00509       err = ::getsockname(sock, reinterpret_cast<sockaddr *>(&server), &server_size);
00510       if(err<0)
00511         perror("netstream getsockname");
00512       else {
00513         localAddress.set_addr(ntohl(server.sin_addr.s_addr), ntohs(server.sin_port));
00514       }
00515       //cout << " netstream connected to " << getPeerAddress().get_display_num() << ":" << getPeerAddress().get_port()
00516       //  << " from " << getLocalAddress().get_display_num() << ":" << getLocalAddress().get_port() << endl;
00517     }
00518   }
00519   
00520   return true;
00521 }
00522 
00523 template <class charT, class traits>
00524 bool
00525 basic_netbuf<charT,traits>::open(const IPaddr::ipname_t& str, bool datagram) {
00526   std::string::size_type colon = str.rfind(':');
00527   if(colon==std::string::npos)
00528     return false;
00529   IPaddr::ipport_t port = atoi(str.substr(colon+1).c_str());
00530   bool res = open(str.substr(0,colon),port,datagram);
00531   return res;
00532 }
00533 
00534 template <class charT, class traits>
00535 void
00536 basic_netbuf<charT,traits>::close() {
00537   //cout << "close called" << endl;
00538   if(!is_open())
00539     return;
00540   //cout << "closing" << endl;
00541 	::close(sock);
00542   //cout << "closed" << endl;
00543   sock = INVALID_SOCKET;
00544 }
00545 
00546 template <class charT, class traits>
00547 void
00548 basic_netbuf<charT,traits>::reconnect() {
00549   if(sockFromServer) {
00550     listen(tgtAddress,isDatagram);
00551   } else {
00552     open(tgtAddress,isDatagram);
00553   }
00554 }
00555 
00556 template <class charT, class traits>
00557 void
00558 basic_netbuf<charT,traits>::printBuffer(const char *buf, int buflen, const char *header, const char *prefix) {
00559   fputs(header, stderr);
00560   int line_begin = 0;
00561   for(int i = 0; i < buflen; i++) {
00562     if(buf[i] == '\n') {
00563       line_begin = 1;
00564       fputc('\n', stderr);
00565     } else {
00566       if(line_begin) fputs(prefix, stderr);
00567       line_begin = 0;
00568       fputc(buf[i], stderr);
00569     }
00570   }
00571 }
00572 
00573 template <class charT, class traits>
00574 void
00575 basic_netbuf<charT,traits>::in_sync() {
00576   if(!is_open()) {
00577     //cout << "netstream error: must open connection before reading from it" << endl;
00578     return;
00579   }
00580   update_status();
00581   if(!is_open())
00582     return; // just discovered close, don't complain
00583   if(gptr()>egptr())
00584     gbump( egptr()-gptr() );
00585   if(gptr()==eback()) {
00586     //cout << "netstream error: in_sync without room in input buffer" << endl;
00587     return;
00588   }
00589   unsigned long n = gptr()-eback()-1;
00590   charT * temp_buf = new char[n*sizeof(charT)];
00591   ssize_t used = read(sock, temp_buf, n*sizeof(charT));
00592   while(used==0 || used==(ssize_t)-1) {
00593     //cout << "netstream error: connection dropped" << endl;
00594     close();
00595     if(autoReconnect)
00596       reconnect();
00597     if(!is_open()) {
00598       delete [] temp_buf;
00599       return;
00600     }
00601     used = read(sock, temp_buf, n*sizeof(charT));
00602   }
00603   if(is_echoing)
00604     printBuffer(temp_buf, used, "netstream receiving: ", "< ");
00605   //TODO - what if sizeof(charT)>1?  We might need to worry about getting/storing partial char
00606   OTAssert("Partial char was dropped!",(ssize_t)((used/sizeof(charT))*sizeof(charT))==used);
00607   used/=sizeof(charT);
00608   size_t remain = egptr()-eback()-used;
00609   traits::move(eback(),egptr()-remain,remain);
00610   traits::copy(egptr()-used,temp_buf,used);
00611   delete [] temp_buf;
00612   gbump( -used );
00613 }
00614 
00615 template <class charT, class traits>
00616 void
00617 basic_netbuf<charT,traits>::out_flush() {
00618   if(!is_open()) {
00619     //cout << "netstream error: must open connection before writing to it" << endl;
00620     return;
00621   }
00622   update_status();
00623   if(!is_open())
00624     return; // just discovered close, don't complain
00625   size_t n = (pptr()-pbase())*sizeof(charT);
00626   if(n==0)
00627     return;
00628   size_t total = 0;
00629   while(total<n) {
00630     int sent = write(sock, pbase()+total, n-total);
00631     while(sent < 0) {
00632       //cout << "netstream error: send error" << endl;
00633       //perror("netstream send");
00634       close();
00635       if(autoReconnect)
00636         reconnect();
00637       if(!is_open())
00638         return;
00639       sent = write(sock, pbase()+total, n-total);
00640     }
00641     //if(sent==0)
00642     //  cout << "got send 0" << endl;
00643     if(is_echoing)
00644       printBuffer(pbase()+total, sent, "netstream sending: ", "> ");
00645     total += sent;
00646   }
00647   total/=sizeof(charT);
00648   n/=sizeof(charT);
00649   if(total!=n)
00650     traits::move(pbase(),pbase()+total,n-total);
00651   pbump( -total );
00652 }
00653 
00654 
00655 template <class charT, class traits>
00656 inline std::streamsize
00657 basic_netbuf<charT, traits>::showmanyc() {
00658   update_status();
00659   return (is_open() && canRead) ? 1 : 0;
00660   //return (gptr()<egptr())?(egptr()-gptr()):0;
00661 }
00662 
00663 template <class charT, class traits>
00664 inline typename basic_netbuf<charT, traits>::int_type
00665 basic_netbuf<charT, traits>::underflow() {
00666   in_sync();
00667   if(gptr()<egptr())
00668     return traits::to_int_type(*gptr());
00669 //  cout << "UNDERFLOW" << endl;
00670   return traits::eof();
00671 }
00672 
00673 template <class charT, class traits>
00674 inline typename basic_netbuf<charT, traits>::int_type
00675 basic_netbuf<charT, traits>::uflow() {
00676   in_sync();
00677   if(gptr()<egptr()) {
00678     int_type ans = traits::to_int_type(*gptr());
00679     gbump(1);
00680     return ans;
00681   }
00682 //  cout << "UNDERFLOW" << endl;
00683   return traits::eof();
00684 }
00685 
00686 template <class charT, class traits>
00687 inline typename basic_netbuf<charT, traits>::int_type
00688 basic_netbuf<charT, traits>::overflow(int_type c) { 
00689   out_flush();
00690   if(!is_open())
00691     return traits::eof();
00692   if(!traits::eq_int_type(c, traits::eof())) {
00693     *pptr() = c;
00694     pbump(1);
00695   }
00696   return traits::not_eof(c);
00697 }
00698 
00699 //template <class charT, class traits>
00700 //inline basic_netbuf<charT, traits>::_Myt //not supported - don't know details of expected implementation
00701 //basic_netbuf<charT, traits>::setbuf(char_type* /*s*/, streamsize /*n*/) {
00702 //  return this;
00703 //}
00704 
00705 template <class charT, class traits>
00706 typename basic_netbuf<charT, traits>::pos_type
00707 basic_netbuf<charT, traits>::seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode which /*= ios_base::in | ios_base::out*/) {
00708   bool dog = (which & std::ios_base::in);
00709   bool dop = (which & std::ios_base::out);
00710   charT* newg, *newp;
00711   int gb,pb;
00712   switch(way) {
00713     case std::ios_base::beg: {
00714       newg = eback()+off;
00715       gb = newg-gptr();
00716       newp = pbase()+off;
00717       pb = newp-pptr();
00718     } break;
00719     case std::ios_base::cur: {
00720       newg = gptr()+off;
00721       newp = pptr()+off;
00722       gb=pb=off;
00723     } break;
00724     case std::ios_base::end: {
00725       newg = egptr()+off;
00726       gb = newg-gptr();
00727       newp = epptr()+off;
00728       pb = newp-pptr();
00729     } break;
00730     default:
00731       return pos_type(off_type(-1));
00732   }
00733   if(dog && (newg<eback() || egptr()<newg) || dop && (newp<pbase() || epptr()<newp))
00734     return pos_type(off_type(-1));
00735   if(dog)
00736     gbump(gb);
00737   if(dop) {
00738     pbump(pb);
00739     return pptr()-pbase();
00740   } else {
00741     return gptr()-eback();
00742   }
00743 }
00744 
00745 template <class charT, class traits>
00746 inline int
00747 basic_netbuf<charT, traits>::sync() {
00748   out_flush();
00749   //in_sync();
00750   return is_open()?0:-1;
00751 }
00752 
00753 #undef OTAssert
00754 
00755 #endif

Tekkotsu v4.0
Generated Thu Nov 22 00:54:54 2007 by Doxygen 1.5.4