Panda3D

buffered_datagramconnection.h

00001 #ifndef __NONECLOCKING_CONNECTTION_H_
00002 #define __NONECLOCKING_CONNECTTION_H_
00003 ////////////////////////////////////////////////////////////////////
00004 // 
00005 // Ok here is the base behavior..
00006 //     A message IO engin that is Smart enough to Do 
00007 //
00008 //  1. Non Blocking Connect .. and Buffer the writes if needed
00009 //  2. Handle 1 to N targets for the connection.. 
00010 //
00011 //  3. Handle Framing and Unframing properly ..
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 #include "pandabase.h"
00015 #include "socket_base.h"
00016 #include "datagram.h"
00017 #include "pvector.h"
00018 #include "buffered_datagramreader.h"
00019 #include "buffered_datagramwriter.h"
00020 #include "config_nativenet.h"
00021 
00022 
00023 ////////////////////////////////////////////////////////////////
00024 // there are 3 states   
00025 //
00026 //      1. Socket not even assigned,,,,
00027 //      2. Socket Assigned and trying to get a active connect open
00028 //      3. Socket is open and  writable.. ( Fully powered up )...
00029 //
00030 ///////////////////////////////////////////////////////////////
00031 class EXPCL_PANDA_NATIVENET Buffered_DatagramConnection : public Socket_TCP
00032 {
00033 private:
00034   struct AddressQueue : private pvector<Socket_Address> // this is used to do a round robin for addres to connect to ..
00035   {   
00036     size_t _active_index;   
00037     bool GetNext(Socket_Address &out) 
00038     {
00039       size_t the_size = size();
00040       if(the_size == 0)
00041         return false;
00042       
00043       if(_active_index >= the_size || _active_index < 0)
00044         _active_index = 0;
00045       out = (*this)[_active_index++];   
00046       return true;
00047     }            
00048 
00049     void clear() { pvector<Socket_Address>::clear(); };
00050     void push_back(Socket_Address &address)
00051     {
00052       iterator ii;
00053       for(ii = begin(); ii != end(); ii++)
00054         if(*ii == address)
00055           return;
00056       pvector<Socket_Address>::push_back(address);
00057     }
00058 
00059     size_t size() { return pvector<Socket_Address>::size(); };
00060   };
00061 protected:
00062   // c++ upcals for 
00063   virtual void PostConnect(void) { };
00064   virtual void NewWriteBuffer(void) { };
00065   ///////////////////////////////////////////
00066   inline void ClearAll(void);
00067 
00068   inline bool SendMessageBufferOnly(Datagram &msg); // do not use this .. this is a way for the the COnnecting UPcall to drop messages in queue first..
00069 PUBLISHED:
00070   inline bool GetMessage(Datagram &val);
00071   inline bool DoConnect(void);           // all the real state magic is in here
00072   inline bool IsConnected(void); 
00073   inline Buffered_DatagramConnection(int rbufsize, int wbufsize, int write_flush_point) ;
00074   virtual ~Buffered_DatagramConnection(void) ;
00075   // the reason thsi all exists
00076   inline bool SendMessage(const Datagram &msg);
00077   inline bool Flush(void);
00078   inline void Reset(void);
00079 
00080 //  int WaitFor_Read_Error(const Socket_fdset & fd, const Time_Span & timeout);
00081 
00082   inline void WaitForNetworkReadEvent(PN_stdfloat MaxTime)
00083   {
00084     Socket_fdset  fdset;
00085     fdset.setForSocket(*this);
00086     Socket_Selector  selector;
00087     Time_Span   waittime(MaxTime);
00088     selector.WaitFor_Read_Error(fdset,waittime);
00089   }
00090 
00091   
00092   // address queue stuff
00093   inline size_t AddressQueueSize() { return _Addresslist.size(); };
00094   inline void AddAddress(Socket_Address &inadr);
00095   inline void ClearAddresses(void);
00096 private:
00097   Buffered_DatagramWriter _Writer;      // buffered writing
00098   Buffered_DatagramReader _Reader;      // buffered reader
00099   AddressQueue            _Addresslist;   // the location of the round robin address list
00100   Socket_Address          _Adddress;    // the conection address ( active one from list being used)
00101 
00102   friend class Buffered_DatagramReader;
00103   friend class Buffered_DatagramWriter;
00104 
00105 public:
00106   static TypeHandle get_class_type() {
00107     return _type_handle;
00108   }
00109   static void init_type() {
00110     Socket_IP::init_type();
00111     register_type(_type_handle, "Buffered_DatagramConnection",
00112                   Socket_IP::get_class_type());
00113   }
00114   virtual TypeHandle get_type() const {
00115     return get_class_type();
00116   }
00117   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
00118 
00119 private:
00120   static TypeHandle _type_handle;
00121 };
00122 
00123 ////////////////////////////////////////////////////////////////////
00124 // Function name    : Buffered_DatagramConnection::ClearAll
00125 // Description      :  used to do a full reset of buffers
00126 //  
00127 // Return type      : inline void 
00128 // Argument         : void
00129 ////////////////////////////////////////////////////////////////////
00130 inline void Buffered_DatagramConnection::ClearAll(void) {
00131   nativenet_cat.error() << "Buffered_DatagramConnection::ClearAll Starting Auto Reset\n";
00132   Close();
00133   _Writer.ReSet();
00134   _Reader.ReSet();
00135 }
00136 
00137 inline bool Buffered_DatagramConnection::DoConnect(void) {
00138   if(!_Addresslist.GetNext(_Adddress)) // lookup the proper value...
00139      return false;
00140     
00141   if(ActiveOpen(_Adddress,true) == true) {
00142     SetNoDelay();
00143     SetNonBlocking(); // maybe should be blocking?
00144     NewWriteBuffer();
00145     return true;
00146   }
00147       
00148   return false;
00149   
00150 }
00151 
00152 /*
00153 ////////////////////////////////////////////////////////////////////
00154 // Function name    : Buffered_DatagramConnection::DoConnect
00155 // Description      : This is the function thah does the conection for us
00156 //  
00157 // Return type      : inline bool 
00158 // Argument         : void
00159 ////////////////////////////////////////////////////////////////////
00160 inline bool Buffered_DatagramConnection::DoConnect(void) {
00161   if(Active() != true) { 
00162     if(_LastConnectTry.Expired() != true)
00163       return true;
00164     
00165     if(!_Addresslist.GetNext(_Adddress)) // lookup the proper value...
00166       return false;
00167     
00168     if(ActiveOpen(_Adddress) == true) {
00169       _LastConnectTry.ReStart();
00170       _tryingToOpen = true; // set the flag indicating we are trying to open up 
00171       SetNonBlocking(); // maybe should be blocking?
00172       SetSendBufferSize(1024*50);  // we need to hand tune these for the os we are using
00173       SetRecvBufferSize(1024*50);
00174       NewWriteBuffer();
00175       return true;
00176     }
00177       
00178     return true;
00179   }
00180   
00181   if(_tryingToOpen) {  // okay handle the  i am connecting state....
00182     Socket_fdset  fdset;
00183     fdset.setForSocket(*this);
00184     Socket_Selector  selector;
00185     if(selector.WaitFor_All(fdset,0) >0) {
00186       _tryingToOpen = false;
00187       if(selector._error.IsSetFor(*this) == true) { // means we are in errorconnected. else writable
00188         ClearAll();
00189         return false;  // error on connect 
00190       }
00191       PostConnect();
00192       return true;  // just got connected
00193     }
00194     return true; // still connecting
00195   }    
00196   return true;
00197 }
00198 
00199 */
00200 
00201 ////////////////////////////////////////////////////////////////////
00202 // Function name    : Buffered_DatagramConnection::~Buffered_DatagramConnection
00203 // Description      : 
00204 //  
00205 // Return type      : inline 
00206 // Argument         : void
00207 ////////////////////////////////////////////////////////////////////
00208 inline Buffered_DatagramConnection::~Buffered_DatagramConnection(void) 
00209 {
00210     Close();
00211 }
00212 ////////////////////////////////////////////////////////////////////
00213 // Function name    : Buffered_DatagramConnection::Buffered_DatagramConnection
00214 // Description      : 
00215 //  
00216 // Return type      : inline 
00217 // Argument         : bool do_blocking_writes
00218 // Argument         : int rbufsize
00219 // Argument         : int wbufsize
00220 ////////////////////////////////////////////////////////////////////
00221 inline Buffered_DatagramConnection::Buffered_DatagramConnection(int rbufsize, int wbufsize, int write_flush_point) 
00222     :  _Writer(wbufsize,write_flush_point) , _Reader(rbufsize) 
00223 {
00224   nativenet_cat.error() << "Buffered_DatagramConnection Constructor rbufsize = " << rbufsize 
00225                         << " wbufsize = " << wbufsize << " write_flush_point = " << write_flush_point << "\n";
00226 }
00227 ////////////////////////////////////////////////////////////////////
00228 // Function name    :  Buffered_DatagramConnection::SendMessage
00229 // Description      : send the message 
00230 //  
00231 // Return type      : inline bool 
00232 // Argument         : DataGram &msg
00233 ////////////////////////////////////////////////////////////////////
00234 inline bool  Buffered_DatagramConnection::SendMessage(const Datagram &msg)
00235 {
00236       if(IsConnected()) {
00237 //        printf(" DO SendMessage %d\n",msg.get_length()); 
00238         int val = 0;        
00239         val = _Writer.AddData(msg.get_data(),msg.get_length(),*this);
00240         if(val >= 0)
00241           return true;
00242         // Raise an exception to give us more information at the python level
00243         nativenet_cat.warning() << "Buffered_DatagramConnection::SendMessage->Error On Write--Out Buffer = " << _Writer.AmountBuffered() << "\n";
00244         #ifdef HAVE_PYTHON
00245         ostringstream s;
00246         PyObject *exc_type = PyExc_StandardError;
00247         
00248         s << endl << "Error sending message: " << endl;
00249         msg.dump_hex(s);
00250         
00251         s << "Message data: " << msg.get_data() << endl;
00252         
00253         string message = s.str();
00254         PyErr_SetString(exc_type, message.c_str());
00255         #endif
00256     
00257         ClearAll();
00258       }
00259       return false;
00260 }
00261 
00262 inline bool  Buffered_DatagramConnection::SendMessageBufferOnly(Datagram &msg)
00263 {
00264     int val = _Writer.AddData(msg.get_data(),msg.get_length());
00265     if(val >= 0)
00266         return true;
00267 
00268     nativenet_cat.error() << "Buffered_DatagramConnection::SendMessageBufferOnly->Error On Write--Out Buffer = " << _Writer.AmountBuffered() << "\n";
00269     ClearAll();
00270     return false;
00271 }
00272 
00273 ////////////////////////////////////////////////////////////////////
00274 // Function name    : Buffered_DatagramConnection::Init
00275 // Description      :  must be called to set value to the server
00276 //  
00277 // Return type      : inline void 
00278 // Argument         : Socket_Address &inadr
00279 ////////////////////////////////////////////////////////////////////
00280 inline void Buffered_DatagramConnection::AddAddress(Socket_Address &inadr)
00281 {
00282     _Addresslist.push_back(inadr);
00283 }
00284 
00285 inline void Buffered_DatagramConnection::ClearAddresses(void)
00286 {
00287     _Addresslist.clear();
00288 }
00289 ////////////////////////////////////////////////////////////////////
00290 // Function name    : Buffered_DatagramConnection::GetMessage
00291 // Description      :  read a message
00292 //  
00293 //  false means something bad happened..
00294 //
00295 //
00296 // Return type      : inline bool 
00297 // Argument         : Datagram &val
00298 ////////////////////////////////////////////////////////////////////
00299 inline bool Buffered_DatagramConnection::GetMessage(Datagram  &val)
00300 {
00301   if(IsConnected()) 
00302   {
00303     int ans1 = _Reader.PumpMessageReader(val,*this);
00304     if(ans1 == 0)
00305       return false;
00306     if(ans1 <0) {
00307       nativenet_cat.error() << "Buffered_DatagramConnection::GetMessage->Error On PumpMessageReader--Out Buffer = " << _Writer.AmountBuffered() << "\n";
00308       ClearAll();
00309       return false;
00310     }
00311     return true;
00312   }
00313   return false;
00314 }
00315 
00316 
00317 
00318 ////////////////////////////////////////////////////////////////////
00319 // Function name    : Buffered_DatagramConnection::Flush
00320 // Description      : flush all wrightes
00321 //  
00322 // Return type      : bool 
00323 // Argument         : void
00324 ////////////////////////////////////////////////////////////////////
00325 bool Buffered_DatagramConnection::Flush(void)
00326 {
00327     if (IsConnected())
00328     {
00329         int flush_resp = _Writer.FlushNoBlock(*this);
00330         if(flush_resp < 0)
00331         {
00332                   nativenet_cat.error() << "Buffered_DatagramConnection::Flush->Error On Flush [" <<GetLastError() << "]\n" 
00333 
00334                                        << "Buffered_DatagramConnection::Flush->Error ..Write--Out Buffer = " << _Writer.AmountBuffered() << "\n";
00335             ClearAll();  
00336             return false;
00337         }
00338         return true;
00339     }
00340     return false;
00341 }
00342 ////////////////////////////////////////////////////////////////////
00343 // Function name    : Buffered_DatagramConnection::Reset
00344 // Description      : Reset 
00345 //  
00346 // Return type      : void 
00347 // Argument         : void
00348 ////////////////////////////////////////////////////////////////////
00349 inline void Buffered_DatagramConnection::Reset()
00350 {
00351   nativenet_cat.error() << "Buffered_DatagramConnection::Reset()\n";
00352   ClearAll();
00353 };
00354 
00355 
00356 inline bool Buffered_DatagramConnection::IsConnected(void) {
00357   return ( Active() == true );
00358 }
00359 
00360 
00361 #endif //__NONECLOCKING_CONNECTTION_H_
00362 
 All Classes Functions Variables Enumerations