Panda3D
 All Classes Functions Variables Enumerations
buffered_datagramconnection.h
1 #ifndef __NONECLOCKING_CONNECTTION_H_
2 #define __NONECLOCKING_CONNECTTION_H_
3 ////////////////////////////////////////////////////////////////////
4 //
5 // Ok here is the base behavior..
6 // A message IO engin that is Smart enough to Do
7 //
8 // 1. Non Blocking Connect .. and Buffer the writes if needed
9 // 2. Handle 1 to N targets for the connection..
10 //
11 // 3. Handle Framing and Unframing properly ..
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pandabase.h"
16 #include "socket_base.h"
17 #include "datagram.h"
18 #include "pvector.h"
19 #include "buffered_datagramreader.h"
20 #include "buffered_datagramwriter.h"
21 #include "config_nativenet.h"
22 
23 #ifdef HAVE_PYTHON
24 #include "py_panda.h"
25 #endif
26 
27 ////////////////////////////////////////////////////////////////
28 // there are 3 states
29 //
30 // 1. Socket not even assigned,,,,
31 // 2. Socket Assigned and trying to get a active connect open
32 // 3. Socket is open and writable.. ( Fully powered up )...
33 //
34 ///////////////////////////////////////////////////////////////
35 class EXPCL_PANDA_NATIVENET Buffered_DatagramConnection : public Socket_TCP
36 {
37 private:
38  struct AddressQueue : private pvector<Socket_Address> // this is used to do a round robin for addres to connect to ..
39  {
40  size_t _active_index;
41 
42  INLINE AddressQueue() : _active_index(0) {}
43 
44  bool GetNext(Socket_Address &out) {
45  size_t the_size = size();
46  if (the_size == 0) {
47  return false;
48  }
49 
50  if (_active_index >= the_size) {
51  _active_index = 0;
52  }
53 
54  out = (*this)[_active_index++];
55  return true;
56  }
57 
58  INLINE void clear() {
60  }
61 
62  void push_back(Socket_Address &address) {
63  iterator ii;
64  for(ii = begin(); ii != end(); ii++)
65  if(*ii == address)
66  return;
68  }
69 
70  size_t size() { return pvector<Socket_Address>::size(); };
71  };
72 
73 protected:
74  // c++ upcalls for
75  virtual void PostConnect(void) { };
76  virtual void NewWriteBuffer(void) { };
77  ///////////////////////////////////////////
78  inline void ClearAll(void);
79 
80  inline bool SendMessageBufferOnly(Datagram &msg); // do not use this .. this is a way for the the COnnecting UPcall to drop messages in queue first..
81 PUBLISHED:
82  inline bool GetMessage(Datagram &val);
83  inline bool DoConnect(void); // all the real state magic is in here
84  inline bool IsConnected(void);
85  inline Buffered_DatagramConnection(int rbufsize, int wbufsize, int write_flush_point) ;
86  virtual ~Buffered_DatagramConnection(void) ;
87  // the reason thsi all exists
88  inline bool SendMessage(const Datagram &msg);
89  inline bool Flush(void);
90  inline void Reset(void);
91 
92 // int WaitFor_Read_Error(const Socket_fdset & fd, const Time_Span & timeout);
93 
94  inline void WaitForNetworkReadEvent(PN_stdfloat MaxTime)
95  {
96  Socket_fdset fdset;
97  fdset.setForSocket(*this);
98  Socket_Selector selector;
99  Time_Span waittime(MaxTime);
100  selector.WaitFor_Read_Error(fdset,waittime);
101  }
102 
103 
104  // address queue stuff
105  inline size_t AddressQueueSize() { return _Addresslist.size(); };
106  inline void AddAddress(Socket_Address &inadr);
107  inline void ClearAddresses(void);
108 private:
109  Buffered_DatagramWriter _Writer; // buffered writing
110  Buffered_DatagramReader _Reader; // buffered reader
111  AddressQueue _Addresslist; // the location of the round robin address list
112  Socket_Address _Adddress; // the conection address ( active one from list being used)
113 
114  friend class Buffered_DatagramReader;
115  friend class Buffered_DatagramWriter;
116 
117 public:
118  static TypeHandle get_class_type() {
119  return _type_handle;
120  }
121  static void init_type() {
122  Socket_IP::init_type();
123  register_type(_type_handle, "Buffered_DatagramConnection",
124  Socket_IP::get_class_type());
125  }
126  virtual TypeHandle get_type() const {
127  return get_class_type();
128  }
129  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
130 
131 private:
132  static TypeHandle _type_handle;
133 };
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function name : Buffered_DatagramConnection::ClearAll
137 // Description : used to do a full reset of buffers
138 //
139 // Return type : inline void
140 // Argument : void
141 ////////////////////////////////////////////////////////////////////
142 inline void Buffered_DatagramConnection::ClearAll(void) {
143  nativenet_cat.error() << "Buffered_DatagramConnection::ClearAll Starting Auto Reset\n";
144  Close();
145  _Writer.ReSet();
146  _Reader.ReSet();
147 }
148 
149 inline bool Buffered_DatagramConnection::DoConnect(void) {
150  if(!_Addresslist.GetNext(_Adddress)) // lookup the proper value...
151  return false;
152 
153  if(ActiveOpen(_Adddress,true) == true) {
154  SetNoDelay();
155  SetNonBlocking(); // maybe should be blocking?
156  NewWriteBuffer();
157  return true;
158  }
159 
160  return false;
161 
162 }
163 
164 /*
165 ////////////////////////////////////////////////////////////////////
166 // Function name : Buffered_DatagramConnection::DoConnect
167 // Description : This is the function thah does the conection for us
168 //
169 // Return type : inline bool
170 // Argument : void
171 ////////////////////////////////////////////////////////////////////
172 inline bool Buffered_DatagramConnection::DoConnect(void) {
173  if(Active() != true) {
174  if(_LastConnectTry.Expired() != true)
175  return true;
176 
177  if(!_Addresslist.GetNext(_Adddress)) // lookup the proper value...
178  return false;
179 
180  if(ActiveOpen(_Adddress) == true) {
181  _LastConnectTry.ReStart();
182  _tryingToOpen = true; // set the flag indicating we are trying to open up
183  SetNonBlocking(); // maybe should be blocking?
184  SetSendBufferSize(1024*50); // we need to hand tune these for the os we are using
185  SetRecvBufferSize(1024*50);
186  NewWriteBuffer();
187  return true;
188  }
189 
190  return true;
191  }
192 
193  if(_tryingToOpen) { // okay handle the i am connecting state....
194  Socket_fdset fdset;
195  fdset.setForSocket(*this);
196  Socket_Selector selector;
197  if(selector.WaitFor_All(fdset,0) >0) {
198  _tryingToOpen = false;
199  if(selector._error.IsSetFor(*this) == true) { // means we are in errorconnected. else writable
200  ClearAll();
201  return false; // error on connect
202  }
203  PostConnect();
204  return true; // just got connected
205  }
206  return true; // still connecting
207  }
208  return true;
209 }
210 
211 */
212 
213 ////////////////////////////////////////////////////////////////////
214 // Function name : Buffered_DatagramConnection::~Buffered_DatagramConnection
215 // Description :
216 //
217 // Return type : inline
218 // Argument : void
219 ////////////////////////////////////////////////////////////////////
221 {
222  Close();
223 }
224 ////////////////////////////////////////////////////////////////////
225 // Function name : Buffered_DatagramConnection::Buffered_DatagramConnection
226 // Description :
227 //
228 // Return type : inline
229 // Argument : bool do_blocking_writes
230 // Argument : int rbufsize
231 // Argument : int wbufsize
232 ////////////////////////////////////////////////////////////////////
233 inline Buffered_DatagramConnection::Buffered_DatagramConnection(int rbufsize, int wbufsize, int write_flush_point)
234  : _Writer(wbufsize,write_flush_point) , _Reader(rbufsize)
235 {
236  nativenet_cat.error() << "Buffered_DatagramConnection Constructor rbufsize = " << rbufsize
237  << " wbufsize = " << wbufsize << " write_flush_point = " << write_flush_point << "\n";
238 }
239 ////////////////////////////////////////////////////////////////////
240 // Function name : Buffered_DatagramConnection::SendMessage
241 // Description : send the message
242 //
243 // Return type : inline bool
244 // Argument : DataGram &msg
245 ////////////////////////////////////////////////////////////////////
247 {
248  if(IsConnected()) {
249 // printf(" DO SendMessage %d\n",msg.get_length());
250  int val = 0;
251  val = _Writer.AddData(msg.get_data(),msg.get_length(),*this);
252  if(val >= 0)
253  return true;
254  // Raise an exception to give us more information at the python level
255  nativenet_cat.warning() << "Buffered_DatagramConnection::SendMessage->Error On Write--Out Buffer = " << _Writer.AmountBuffered() << "\n";
256  #ifdef HAVE_PYTHON
257  ostringstream s;
258 
259 #if PY_MAJOR_VERSION >= 3
260  PyObject *exc_type = PyExc_ConnectionError;
261 #else
262  PyObject *exc_type = PyExc_StandardError;
263 #endif
264 
265  s << endl << "Error sending message: " << endl;
266  msg.dump_hex(s);
267 
268  s << "Message data: " << msg.get_data() << endl;
269 
270  string message = s.str();
271  PyErr_SetString(exc_type, message.c_str());
272  #endif
273 
274  ClearAll();
275  }
276  return false;
277 }
278 
279 inline bool Buffered_DatagramConnection::SendMessageBufferOnly(Datagram &msg)
280 {
281  int val = _Writer.AddData(msg.get_data(),msg.get_length());
282  if(val >= 0)
283  return true;
284 
285  nativenet_cat.error() << "Buffered_DatagramConnection::SendMessageBufferOnly->Error On Write--Out Buffer = " << _Writer.AmountBuffered() << "\n";
286  ClearAll();
287  return false;
288 }
289 
290 ////////////////////////////////////////////////////////////////////
291 // Function name : Buffered_DatagramConnection::Init
292 // Description : must be called to set value to the server
293 //
294 // Return type : inline void
295 // Argument : Socket_Address &inadr
296 ////////////////////////////////////////////////////////////////////
298 {
299  _Addresslist.push_back(inadr);
300 }
301 
302 inline void Buffered_DatagramConnection::ClearAddresses(void)
303 {
304  _Addresslist.clear();
305 }
306 ////////////////////////////////////////////////////////////////////
307 // Function name : Buffered_DatagramConnection::GetMessage
308 // Description : read a message
309 //
310 // false means something bad happened..
311 //
312 //
313 // Return type : inline bool
314 // Argument : Datagram &val
315 ////////////////////////////////////////////////////////////////////
317 {
318  if(IsConnected())
319  {
320  int ans1 = _Reader.PumpMessageReader(val,*this);
321  if(ans1 == 0)
322  return false;
323  if(ans1 <0) {
324  nativenet_cat.error() << "Buffered_DatagramConnection::GetMessage->Error On PumpMessageReader--Out Buffer = " << _Writer.AmountBuffered() << "\n";
325  ClearAll();
326  return false;
327  }
328  return true;
329  }
330  return false;
331 }
332 
333 
334 
335 ////////////////////////////////////////////////////////////////////
336 // Function name : Buffered_DatagramConnection::Flush
337 // Description : flush all wrightes
338 //
339 // Return type : bool
340 // Argument : void
341 ////////////////////////////////////////////////////////////////////
343 {
344  if (IsConnected())
345  {
346  int flush_resp = _Writer.FlushNoBlock(*this);
347  if(flush_resp < 0)
348  {
349  nativenet_cat.error() << "Buffered_DatagramConnection::Flush->Error On Flush [" <<GetLastError() << "]\n"
350 
351  << "Buffered_DatagramConnection::Flush->Error ..Write--Out Buffer = " << _Writer.AmountBuffered() << "\n";
352  ClearAll();
353  return false;
354  }
355  return true;
356  }
357  return false;
358 }
359 ////////////////////////////////////////////////////////////////////
360 // Function name : Buffered_DatagramConnection::Reset
361 // Description : Reset
362 //
363 // Return type : void
364 // Argument : void
365 ////////////////////////////////////////////////////////////////////
367 {
368  nativenet_cat.error() << "Buffered_DatagramConnection::Reset()\n";
369  ClearAll();
370 };
371 
372 
373 inline bool Buffered_DatagramConnection::IsConnected(void) {
374  return ( Active() == true );
375 }
376 
377 
378 #endif //__NONECLOCKING_CONNECTTION_H_
379 
void AddAddress(Socket_Address &inadr)
must be called to set value to the server
Base functionality for a TCP connected socket This class is pretty useless by itself but it does hide...
Definition: socket_tcp.h:15
int SetNonBlocking()
this function will throw a socket into non-blocking mode
Definition: socket_ip.h:183
size_t get_length() const
Returns the number of bytes in the datagram.
Definition: datagram.I:457
bool Active()
Ask if the socket is open (allocated)
Definition: socket_ip.h:105
bool SendMessage(const Datagram &msg)
send the message
bool Flush(void)
flush all wrightes
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
bool GetMessage(Datagram &val)
read a message
Buffered_DatagramConnection(int rbufsize, int wbufsize, int write_flush_point)
Return type : inline Argument : bool do_blocking_writes Argument : int rbufsize Argument : int wbufsi...
void dump_hex(ostream &out, unsigned int indent=0) const
Writes a representation of the entire datagram contents, as a sequence of hex (and ASCII) values...
Definition: datagram.cxx:52
int AddData(const void *data, size_t len, Socket_TCP &sck)
Return type : inline int Argument : const void * data Argument : int len Argument : Socket_TCP &amp;sck...
virtual ~Buffered_DatagramConnection(void)
Return type : inline Argument : void.
A simple place to store and munipulate tcp and port address for communication layer.
static int GetLastError()
gets the last errcode from a socket operation
Definition: socket_ip.h:152
void Close()
closes a socket if it is open (allocated)
Definition: socket_ip.h:141
This is the buffered writer.
const void * get_data() const
Returns a pointer to the beginning of the datagram&#39;s data.
Definition: datagram.I:447
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
int WaitFor_Read_Error(const Socket_fdset &fd, const Time_Span &timeout)
Helper function for WaitFor Only looks for readability and errors.
bool ActiveOpen(const Socket_Address &theaddress, bool setdelay)
This function will try and set the socket up for active open to a specified address and port provided...
Definition: socket_tcp.h:131
void ReSet(void)
used to clear the buffrers ...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
int SetNoDelay(bool flag=true)
Disable Nagle algorithm.
Definition: socket_tcp.h:68