Panda3D
|
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