Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/net/connection.cxx

Go to the documentation of this file.
00001 // Filename: connection.cxx
00002 // Created by:  jns (07Feb00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "connection.h"
00020 #include "connectionManager.h"
00021 #include "netDatagram.h"
00022 #include "datagramTCPHeader.h"
00023 #include "datagramUDPHeader.h"
00024 #include "pprerror.h"
00025 #include "config_net.h"
00026 #include "config_express.h" // for collect_tcp
00027 #include "clockObject.h"
00028 
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: Connection::Constructor
00032 //       Access: Published
00033 //  Description: Creates a connection.  Normally this constructor
00034 //               should not be used directly by user code; use one of
00035 //               the methods in ConnectionManager to make a new
00036 //               connection.
00037 ////////////////////////////////////////////////////////////////////
00038 Connection::
00039 Connection(ConnectionManager *manager, PRFileDesc *socket) :
00040   _manager(manager),
00041   _socket(socket)
00042 {
00043   _write_mutex = PR_NewLock();
00044   _collect_tcp = collect_tcp;
00045   _collect_tcp_interval = collect_tcp_interval;
00046   _queued_data_start = 0.0;
00047   _queued_count = 0;
00048 }
00049 
00050 ////////////////////////////////////////////////////////////////////
00051 //     Function: Connection::Destructor
00052 //       Access: Published
00053 //  Description: Closes a connection.
00054 ////////////////////////////////////////////////////////////////////
00055 Connection::
00056 ~Connection() {
00057   net_cat.info()
00058     << "Deleting connection " << (void *)this << "\n";
00059 
00060   if (_socket != (PRFileDesc *)NULL) {
00061     flush();
00062 
00063     PRStatus result = PR_Close(_socket);
00064     if (result != PR_SUCCESS) {
00065       pprerror("PR_Close");
00066     }
00067   }
00068 
00069   PR_DestroyLock(_write_mutex);
00070 }
00071 
00072 ////////////////////////////////////////////////////////////////////
00073 //     Function: Connection::get_address
00074 //       Access: Published
00075 //  Description: Returns the address bound to this connection, if it
00076 //               is a TCP connection.
00077 ////////////////////////////////////////////////////////////////////
00078 NetAddress Connection::
00079 get_address() const {
00080   PRNetAddr addr;
00081   if (PR_GetSockName(_socket, &addr) != PR_SUCCESS) {
00082     pprerror("PR_GetSockName");
00083   }
00084 
00085   return NetAddress(addr);
00086 }
00087 
00088 ////////////////////////////////////////////////////////////////////
00089 //     Function: Connection::get_manager
00090 //       Access: Published
00091 //  Description: Returns a pointer to the ConnectionManager object
00092 //               that serves this connection.
00093 ////////////////////////////////////////////////////////////////////
00094 ConnectionManager *Connection::
00095 get_manager() const {
00096   return _manager;
00097 }
00098 
00099 ////////////////////////////////////////////////////////////////////
00100 //     Function: Connection::get_socket
00101 //       Access: Published
00102 //  Description: Returns the internal NSPR pointer that defines the
00103 //               connection.
00104 ////////////////////////////////////////////////////////////////////
00105 PRFileDesc *Connection::
00106 get_socket() const {
00107   return _socket;
00108 }
00109 
00110 ////////////////////////////////////////////////////////////////////
00111 //     Function: Connection::set_collect_tcp
00112 //       Access: Published
00113 //  Description: Enables or disables "collect-tcp" mode.  In this
00114 //               mode, individual TCP packets are not sent
00115 //               immediately, but rather they are collected together
00116 //               and accumulated to be sent periodically as one larger
00117 //               TCP packet.  This cuts down on overhead from the
00118 //               TCP/IP protocol, especially if many small packets
00119 //               need to be sent on the same connection, but it
00120 //               introduces additional latency (since packets must be
00121 //               held before they can be sent).
00122 //
00123 //               See set_collect_tcp_interval() to specify the
00124 //               interval of time for which to hold packets before
00125 //               sending them.
00126 //
00127 //               If you enable this mode, you may also need to
00128 //               periodically call consider_flush() to flush the queue
00129 //               if no packets have been sent recently.
00130 ////////////////////////////////////////////////////////////////////
00131 void Connection::
00132 set_collect_tcp(bool collect_tcp) {
00133   _collect_tcp = collect_tcp;
00134 }
00135 
00136 ////////////////////////////////////////////////////////////////////
00137 //     Function: Connection::get_collect_tcp
00138 //       Access: Published
00139 //  Description: Returns the current setting of "collect-tcp" mode.
00140 //               See set_collect_tcp().
00141 ////////////////////////////////////////////////////////////////////
00142 bool Connection::
00143 get_collect_tcp() const {
00144   return _collect_tcp;
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: Connection::set_collect_tcp_interval
00149 //       Access: Published
00150 //  Description: Specifies the interval in time, in seconds, for which
00151 //               to hold TCP packets before sending all of the
00152 //               recently received packets at once.  This only has
00153 //               meaning if "collect-tcp" mode is enabled; see
00154 //               set_collect_tcp().
00155 ////////////////////////////////////////////////////////////////////
00156 void Connection::
00157 set_collect_tcp_interval(double interval) {
00158   _collect_tcp_interval = interval;
00159 }
00160 
00161 ////////////////////////////////////////////////////////////////////
00162 //     Function: Connection::get_collect_tcp_interval
00163 //       Access: Published
00164 //  Description: Returns the interval in time, in seconds, for which
00165 //               to hold TCP packets before sending all of the
00166 //               recently received packets at once.  This only has
00167 //               meaning if "collect-tcp" mode is enabled; see
00168 //               set_collect_tcp().
00169 ////////////////////////////////////////////////////////////////////
00170 double Connection::
00171 get_collect_tcp_interval() const {
00172   return _collect_tcp_interval;
00173 }
00174 
00175 ////////////////////////////////////////////////////////////////////
00176 //     Function: Connection::consider_flush
00177 //       Access: Published
00178 //  Description: Sends the most recently queued TCP datagram(s) if
00179 //               enough time has elapsed.  This only has meaning if
00180 //               set_collect_tcp() has been set to true.
00181 ////////////////////////////////////////////////////////////////////
00182 bool Connection::
00183 consider_flush() {
00184   PR_Lock(_write_mutex);
00185 
00186   if (!_collect_tcp || 
00187       ClockObject::get_global_clock()->get_real_time() - _queued_data_start >= _collect_tcp_interval) {
00188     return do_flush();
00189   }
00190 
00191   PR_Unlock(_write_mutex);
00192   return true;
00193 }
00194 
00195 ////////////////////////////////////////////////////////////////////
00196 //     Function: Connection::flush
00197 //       Access: Published
00198 //  Description: Sends the most recently queued TCP datagram(s) now.
00199 //               This only has meaning if set_collect_tcp() has been
00200 //               set to true.
00201 ////////////////////////////////////////////////////////////////////
00202 bool Connection::
00203 flush() {
00204   PR_Lock(_write_mutex);
00205   return do_flush();
00206 }
00207 
00208 ////////////////////////////////////////////////////////////////////
00209 //     Function: Connection::set_nonblock
00210 //       Access: Published
00211 //  Description: Sets whether nonblocking I/O should be in effect.
00212 ////////////////////////////////////////////////////////////////////
00213 void Connection::
00214 set_nonblock(bool flag) {
00215   PRSocketOptionData data;
00216   data.option = PR_SockOpt_Nonblocking;
00217   data.value.non_blocking = flag;
00218   PR_SetSocketOption(_socket, &data);
00219 }
00220 
00221 ////////////////////////////////////////////////////////////////////
00222 //     Function: Connection::set_linger
00223 //       Access: Published
00224 //  Description: Sets the time to linger on close if data is present.
00225 //               If flag is false, when you close a socket with data
00226 //               available the system attempts to deliver the data to
00227 //               the peer (the default behavior).  If flag is false
00228 //               but time is zero, the system discards any undelivered
00229 //               data when you close the socket.  If flag is false but
00230 //               time is nonzero, the system waits up to time seconds
00231 //               to deliver the data.
00232 ////////////////////////////////////////////////////////////////////
00233 void Connection::
00234 set_linger(bool flag, double time) {
00235   PRSocketOptionData data;
00236   data.option = PR_SockOpt_Linger;
00237   data.value.linger.polarity = flag;
00238   data.value.linger.linger = PRIntervalTime(time * PR_INTERVAL_MIN);
00239   PR_SetSocketOption(_socket, &data);
00240 }
00241 
00242 ////////////////////////////////////////////////////////////////////
00243 //     Function: Connection::set_reuse_addr
00244 //       Access: Published
00245 //  Description: Sets whether local address reuse is allowed.
00246 ////////////////////////////////////////////////////////////////////
00247 void Connection::
00248 set_reuse_addr(bool flag) {
00249   PRSocketOptionData data;
00250   data.option = PR_SockOpt_Reuseaddr;
00251   data.value.reuse_addr = flag;
00252   PR_SetSocketOption(_socket, &data);
00253 }
00254 
00255 ////////////////////////////////////////////////////////////////////
00256 //     Function: Connection::set_keep_alive
00257 //       Access: Published
00258 //  Description: Sets whether the connection is periodically tested to
00259 //               see if it is still alive.
00260 ////////////////////////////////////////////////////////////////////
00261 void Connection::
00262 set_keep_alive(bool flag) {
00263   PRSocketOptionData data;
00264   data.option = PR_SockOpt_Keepalive;
00265   data.value.keep_alive = flag;
00266   PR_SetSocketOption(_socket, &data);
00267 }
00268 
00269 ////////////////////////////////////////////////////////////////////
00270 //     Function: Connection::set_recv_buffer_size
00271 //       Access: Published
00272 //  Description: Sets the size of the receive buffer, in bytes.
00273 ////////////////////////////////////////////////////////////////////
00274 void Connection::
00275 set_recv_buffer_size(int size) {
00276   PRSocketOptionData data;
00277   data.option = PR_SockOpt_RecvBufferSize;
00278   data.value.recv_buffer_size = size;
00279   PR_SetSocketOption(_socket, &data);
00280 }
00281 
00282 ////////////////////////////////////////////////////////////////////
00283 //     Function: Connection::set_send_buffer_size
00284 //       Access: Published
00285 //  Description: Sets the size of the send buffer, in bytes.
00286 ////////////////////////////////////////////////////////////////////
00287 void Connection::
00288 set_send_buffer_size(int size) {
00289   PRSocketOptionData data;
00290   data.option = PR_SockOpt_SendBufferSize;
00291   data.value.send_buffer_size = size;
00292   PR_SetSocketOption(_socket, &data);
00293 }
00294 
00295 ////////////////////////////////////////////////////////////////////
00296 //     Function: Connection::set_ip_time_to_live
00297 //       Access: Published
00298 //  Description: Sets IP time-to-live.
00299 ////////////////////////////////////////////////////////////////////
00300 void Connection::
00301 set_ip_time_to_live(int ttl) {
00302   PRSocketOptionData data;
00303   data.option = PR_SockOpt_IpTimeToLive;
00304   data.value.ip_ttl = ttl;
00305   PR_SetSocketOption(_socket, &data);
00306 }
00307 
00308 ////////////////////////////////////////////////////////////////////
00309 //     Function: Connection::set_ip_type_of_service
00310 //       Access: Published
00311 //  Description: Sets IP type-of-service and precedence.
00312 ////////////////////////////////////////////////////////////////////
00313 void Connection::
00314 set_ip_type_of_service(int tos) {
00315   PRSocketOptionData data;
00316   data.option = PR_SockOpt_IpTypeOfService;
00317   data.value.tos = tos;
00318   PR_SetSocketOption(_socket, &data);
00319 }
00320 
00321 ////////////////////////////////////////////////////////////////////
00322 //     Function: Connection::set_no_delay
00323 //       Access: Published
00324 //  Description: If flag is true, this disables the Nagle algorithm,
00325 //               and prevents delaying of send to coalesce packets.
00326 ////////////////////////////////////////////////////////////////////
00327 void Connection::
00328 set_no_delay(bool flag) {
00329   PRSocketOptionData data;
00330   data.option = PR_SockOpt_NoDelay;
00331   data.value.no_delay = flag;
00332   PR_SetSocketOption(_socket, &data);
00333 }
00334 
00335 ////////////////////////////////////////////////////////////////////
00336 //     Function: Connection::set_max_segment
00337 //       Access: Published
00338 //  Description: Sets the maximum segment size.
00339 ////////////////////////////////////////////////////////////////////
00340 void Connection::
00341 set_max_segment(int size) {
00342   PRSocketOptionData data;
00343   data.option = PR_SockOpt_MaxSegment;
00344   data.value.max_segment = size;
00345   PR_SetSocketOption(_socket, &data);
00346 }
00347 
00348 ////////////////////////////////////////////////////////////////////
00349 //     Function: Connection::send_datagram
00350 //       Access: Private
00351 //  Description: This method is intended only to be called by
00352 //               ConnectionWriter.  It atomically writes the given
00353 //               datagram to the socket, returning true on success,
00354 //               false on failure.  If the socket seems to be closed,
00355 //               it notifies the ConnectionManager.
00356 ////////////////////////////////////////////////////////////////////
00357 bool Connection::
00358 send_datagram(const NetDatagram &datagram) {
00359   nassertr(_socket != (PRFileDesc *)NULL, false);
00360 
00361   if (PR_GetDescType(_socket) == PR_DESC_SOCKET_UDP) {
00362     // We have to send UDP right away.
00363     PR_Lock(_write_mutex);
00364     DatagramUDPHeader header(datagram);
00365     string data;
00366     data += header.get_header();
00367     data += datagram.get_message();
00368 
00369     PRInt32 bytes_to_send = data.length();
00370     PRInt32 result;
00371     result = PR_SendTo(_socket,
00372                        data.data(), bytes_to_send,
00373                        0,
00374                        datagram.get_address().get_addr(),
00375                        PR_INTERVAL_NO_TIMEOUT);
00376     PRErrorCode errcode = PR_GetError();
00377 
00378     if (net_cat.is_debug()) {
00379       header.verify_datagram(datagram);
00380     }
00381 
00382     PR_Unlock(_write_mutex);
00383     return check_send_error(result, errcode, bytes_to_send);
00384   }
00385 
00386   // We might queue up TCP packets for later sending.
00387   DatagramTCPHeader header(datagram);
00388 
00389   PR_Lock(_write_mutex);
00390   _queued_data += header.get_header();
00391   _queued_data += datagram.get_message();
00392   _queued_count++;
00393   
00394   if (net_cat.is_debug()) {
00395     header.verify_datagram(datagram);
00396   }
00397 
00398   if (!_collect_tcp || 
00399       ClockObject::get_global_clock()->get_real_time() - _queued_data_start >= _collect_tcp_interval) {
00400     return do_flush();
00401   }
00402 
00403   PR_Unlock(_write_mutex);
00404   return true;
00405 }
00406 
00407 ////////////////////////////////////////////////////////////////////
00408 //     Function: Connection::send_raw_datagram
00409 //       Access: Private
00410 //  Description: This method is intended only to be called by
00411 //               ConnectionWriter.  It atomically writes the given
00412 //               datagram to the socket, without the Datagram header.
00413 ////////////////////////////////////////////////////////////////////
00414 bool Connection::
00415 send_raw_datagram(const NetDatagram &datagram) {
00416   nassertr(_socket != (PRFileDesc *)NULL, false);
00417 
00418   if (PR_GetDescType(_socket) == PR_DESC_SOCKET_UDP) {
00419     // We have to send UDP right away.
00420 
00421     string data = datagram.get_message();
00422     PRInt32 bytes_to_send = data.length();
00423 
00424     if (net_cat.is_spam()) {
00425       net_cat.spam()
00426         << "Sending UDP datagram with " 
00427         << bytes_to_send << " bytes to " << (void *)this << "\n";
00428     }
00429 
00430     PR_Lock(_write_mutex);
00431     PRInt32 result;
00432     result = PR_SendTo(_socket,
00433                        data.data(), bytes_to_send,
00434                        0,
00435                        datagram.get_address().get_addr(),
00436                        PR_INTERVAL_NO_TIMEOUT);
00437     PRErrorCode errcode = PR_GetError();
00438 
00439     PR_Unlock(_write_mutex);
00440     return check_send_error(result, errcode, bytes_to_send);
00441   }
00442 
00443   // We might queue up TCP packets for later sending.
00444 
00445   PR_Lock(_write_mutex);
00446   _queued_data += datagram.get_message();
00447   _queued_count++;
00448 
00449   if (!_collect_tcp || 
00450       ClockObject::get_global_clock()->get_real_time() - _queued_data_start >= _collect_tcp_interval) {
00451     return do_flush();
00452   }
00453 
00454   PR_Unlock(_write_mutex);
00455   return true;
00456 }
00457 
00458 ////////////////////////////////////////////////////////////////////
00459 //     Function: Connection::do_flush
00460 //       Access: Private
00461 //  Description: The private implementation of flush(), this assumes
00462 //               the _write_mutex has already been locked on entry.
00463 //               It will be unlocked on return.
00464 ////////////////////////////////////////////////////////////////////
00465 bool Connection::
00466 do_flush() {
00467   PRInt32 bytes_to_send = _queued_data.length();
00468   if (bytes_to_send == 0) {
00469     _queued_count = 0;
00470     _queued_data_start = ClockObject::get_global_clock()->get_real_time();
00471     PR_Unlock(_write_mutex);
00472     return true;
00473   }
00474 
00475   if (net_cat.is_spam()) {
00476     net_cat.spam()
00477       << "Sending " << _queued_count << " TCP datagram(s) with " 
00478       << bytes_to_send << " total bytes to " << (void *)this << "\n";
00479   }
00480 
00481   PRInt32 result;
00482   result = PR_Send(_socket,
00483                    _queued_data.data(), bytes_to_send,
00484                    0,
00485                    PR_INTERVAL_NO_TIMEOUT);
00486   PRErrorCode errcode = PR_GetError();
00487 
00488   _queued_data = string();
00489   _queued_count = 0;
00490   _queued_data_start = ClockObject::get_global_clock()->get_real_time();
00491 
00492   PR_Unlock(_write_mutex);
00493 
00494   return check_send_error(result, errcode, bytes_to_send);
00495 }
00496 
00497 ////////////////////////////////////////////////////////////////////
00498 //     Function: Connection::check_send_error
00499 //       Access: Private
00500 //  Description: Checks the return value of a PR_Send() or PR_SendTo()
00501 //               call.
00502 ////////////////////////////////////////////////////////////////////
00503 bool Connection::
00504 check_send_error(PRInt32 result, PRErrorCode errcode, PRInt32 bytes_to_send) {
00505   if (result < 0) {
00506     if (errcode == PR_CONNECT_RESET_ERROR
00507 #ifdef PR_SOCKET_SHUTDOWN_ERROR
00508         || errcode == PR_SOCKET_SHUTDOWN_ERROR
00509         || errcode == PR_CONNECT_ABORTED_ERROR
00510 #endif
00511         ) {
00512       // The connection has been reset; tell our manager about it
00513       // and ignore it.
00514       if (_manager != (ConnectionManager *)NULL) {
00515         _manager->connection_reset(this);
00516       }
00517 
00518     } else if (errcode != PR_PENDING_INTERRUPT_ERROR) {
00519       pprerror("PR_SendTo");
00520     }
00521 
00522     return false;
00523 
00524   } else if (result != bytes_to_send) {
00525     net_cat.error() << "Not enough bytes sent to socket.\n";
00526     return false;
00527   }
00528 
00529   return true;
00530 }

Generated on Fri May 2 00:40:32 2003 for Panda by doxygen1.3