Panda3D
buffered_datagramconnection.h
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file buffered_datagramconnection.h
10  * @author drose
11  * @date 2007-03-05
12  */
13 
14 
15 #ifndef __BUFFERED_DATAGRAM_CONNECTION_H__
16 #define __BUFFERED_DATAGRAM_CONNECTION_H__
17 /*
18  * Ok here is the base behavior.. A message IO engin that is Smart enough to
19  * Do 1. Non Blocking Connect .. and Buffer the writes if needed 2. Handle 1
20  * to N targets for the connection.. 3. Handle Framing and Unframing properly
21  * ..
22  */
23 
24 #include "pandabase.h"
25 #include "socket_base.h"
26 #include "datagram.h"
27 #include "pvector.h"
28 #include "buffered_datagramreader.h"
29 #include "buffered_datagramwriter.h"
30 #include "config_nativenet.h"
31 
32 // there are 3 states 1. Socket not even assigned,,,, 2. Socket Assigned and
33 // trying to get a active connect open 3. Socket is open and writable.. (
34 // Fully powered up )...
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 explicit Buffered_DatagramConnection(int rbufsize, int wbufsize, int write_flush_point) ;
86  virtual ~Buffered_DatagramConnection(void) ;
87  // the reason thsi all exists
88  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 &
93  // timeout);
94 
95  inline void WaitForNetworkReadEvent(PN_stdfloat MaxTime)
96  {
97  Socket_fdset fdset;
98  fdset.setForSocket(*this);
99  Socket_Selector selector;
100  Time_Span waittime(MaxTime);
101  selector.WaitFor_Read_Error(fdset,waittime);
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  * used to do a full reset of buffers
137  */
138 inline void Buffered_DatagramConnection::ClearAll(void) {
139  if (nativenet_cat.is_debug()) {
140  nativenet_cat.debug()
141  << "Buffered_DatagramConnection::ClearAll Starting Auto Reset\n";
142  }
143  Close();
144  _Writer.ReSet();
145  _Reader.ReSet();
146 }
147 
148 inline bool Buffered_DatagramConnection::DoConnect(void) {
149  if(!_Addresslist.GetNext(_Adddress)) // lookup the proper value...
150  return false;
151 
152  if(ActiveOpen(_Adddress,true) == true) {
153  SetNoDelay();
154  SetNonBlocking(); // maybe should be blocking?
155  NewWriteBuffer();
156  return true;
157  }
158 
159  return false;
160 
161 }
162 
163 /**
164  * This is the function that does the connection for us
165  */
166 /*
167 inline bool Buffered_DatagramConnection::DoConnect(void) {
168  if(Active() != true) {
169  if(_LastConnectTry.Expired() != true)
170  return true;
171 
172  if(!_Addresslist.GetNext(_Adddress)) // lookup the proper value...
173  return false;
174 
175  if(ActiveOpen(_Adddress) == true) {
176  _LastConnectTry.ReStart();
177  _tryingToOpen = true; // set the flag indicating we are trying to open up
178  SetNonBlocking(); // maybe should be blocking?
179  SetSendBufferSize(1024*50); // we need to hand tune these for the os we are using
180  SetRecvBufferSize(1024*50);
181  NewWriteBuffer();
182  return true;
183  }
184 
185  return true;
186  }
187 
188  if(_tryingToOpen) { // okay handle the i am connecting state....
189  Socket_fdset fdset;
190  fdset.setForSocket(*this);
191  Socket_Selector selector;
192  if(selector.WaitFor_All(fdset,0) >0) {
193  _tryingToOpen = false;
194  if(selector._error.IsSetFor(*this) == true) { // means we are in errorconnected. else writable
195  ClearAll();
196  return false; // error on connect
197  }
198  PostConnect();
199  return true; // just got connected
200  }
201  return true; // still connecting
202  }
203  return true;
204 }
205 
206 */
207 
208 /**
209  *
210  */
212 {
213  Close();
214 }
215 /**
216  *
217  */
218 inline Buffered_DatagramConnection::Buffered_DatagramConnection(int rbufsize, int wbufsize, int write_flush_point)
219  : _Writer(wbufsize,write_flush_point) , _Reader(rbufsize)
220 {
221  if (nativenet_cat.is_debug()) {
222  nativenet_cat.debug()
223  << "Buffered_DatagramConnection Constructor rbufsize = " << rbufsize
224  << " wbufsize = " << wbufsize << " write_flush_point = " << write_flush_point << "\n";
225  }
226 }
227 
228 inline bool Buffered_DatagramConnection::SendMessageBufferOnly(Datagram &msg)
229 {
230  int val = _Writer.AddData(msg.get_data(),msg.get_length());
231  if(val >= 0)
232  return true;
233 
234  nativenet_cat.error() << "Buffered_DatagramConnection::SendMessageBufferOnly->Error On Write--Out Buffer = " << _Writer.AmountBuffered() << "\n";
235  ClearAll();
236  return false;
237 }
238 
239 /**
240  * must be called to set value to the server
241  */
243 {
244  _Addresslist.push_back(inadr);
245 }
246 
247 inline void Buffered_DatagramConnection::ClearAddresses(void)
248 {
249  _Addresslist.clear();
250 }
251 /**
252  * Reads a message. Returns false on failure.
253  */
255 {
256  if(IsConnected())
257  {
258  int ans1 = _Reader.PumpMessageReader(val,*this);
259  if(ans1 == 0)
260  return false;
261  if(ans1 <0) {
262  nativenet_cat.error() << "Buffered_DatagramConnection::GetMessage->Error On PumpMessageReader--Out Buffer = " << _Writer.AmountBuffered() << "\n";
263  ClearAll();
264  return false;
265  }
266  return true;
267  }
268  return false;
269 }
270 
271 
272 
273 /**
274  * Flush all writes.
275  */
277 {
278  if (IsConnected())
279  {
280  int flush_resp = _Writer.FlushNoBlock(*this);
281  if(flush_resp < 0)
282  {
283  nativenet_cat.error() << "Buffered_DatagramConnection::Flush->Error On Flush [" <<GetLastError() << "]\n"
284 
285  << "Buffered_DatagramConnection::Flush->Error ..Write--Out Buffer = " << _Writer.AmountBuffered() << "\n";
286  ClearAll();
287  return false;
288  }
289  return true;
290  }
291  return false;
292 }
293 
294 /**
295  * Reset
296  */
298  if (nativenet_cat.is_debug()) {
299  nativenet_cat.debug() << "Buffered_DatagramConnection::Reset()\n";
300  }
301  ClearAll();
302 }
303 
304 inline bool Buffered_DatagramConnection::IsConnected(void) {
305  return (Active() == true);
306 }
307 
308 #endif //__BUFFERED_DATAGRAM_CONNECTION_H__
void AddAddress(Socket_Address &inadr)
must be called to set value to the server
bool Flush(void)
Flush all writes.
virtual ~Buffered_DatagramConnection(void)
This is the function that does the connection for us.
bool GetMessage(Datagram &val)
Reads a message.
void ReSet(void)
Reset all read content, ie.
This is the buffered writer.
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:38
size_t get_length() const
Returns the number of bytes in the datagram.
Definition: datagram.I:335
const void * get_data() const
Returns a pointer to the beginning of the datagram's data.
Definition: datagram.I:327
size_t AmountBuffered(void)
Will report the number of unread chars in buffer.
Definition: ringbuffer.I:32
A simple place to store and manipulate tcp and port address for communication layer.
static int GetLastError()
Gets the last errcode from a socket operation.
Definition: socket_ip.h:140
void Close()
Closes a socket if it is open (allocated).
Definition: socket_ip.h:128
bool Active()
Ask if the socket is open (allocated)
Definition: socket_ip.h:96
int SetNonBlocking()
this function will throw a socket into non-blocking mode
Definition: socket_ip.h:169
Base functionality for a TCP connected socket This class is pretty useless by itself but it does hide...
Definition: socket_tcp.h:12
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:119
int SetNoDelay(bool flag=true)
Disable Nagle algorithm.
Definition: socket_tcp.h:62
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_type(TypeHandle &type_handle, const std::string &name)
This inline function is just a convenient way to call TypeRegistry::register_type(),...
Definition: register_type.I:22
int WaitFor_Read_Error(const Socket_fdset &fd, const Time_Span &timeout)
Helper function for WaitFor Only looks for readability and errors.