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

panda/src/net/connectionManager.cxx

Go to the documentation of this file.
00001 // Filename: connectionManager.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 "connectionManager.h"
00020 #include "connection.h"
00021 #include "connectionReader.h"
00022 #include "connectionWriter.h"
00023 #include "netAddress.h"
00024 #include "pprerror.h"
00025 #include "config_net.h"
00026 
00027 #include <prerror.h>
00028 
00029 #ifdef WIN32_VC
00030 #include <winsock.h>  // For gethostname()
00031 #endif
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: ConnectionManager::Constructor
00035 //       Access: Public
00036 //  Description:
00037 ////////////////////////////////////////////////////////////////////
00038 ConnectionManager::
00039 ConnectionManager() {
00040   _set_mutex = PR_NewLock();
00041 }
00042 
00043 ////////////////////////////////////////////////////////////////////
00044 //     Function: ConnectionManager::Destructor
00045 //       Access: Public, Virtual
00046 //  Description:
00047 ////////////////////////////////////////////////////////////////////
00048 ConnectionManager::
00049 ~ConnectionManager() {
00050   // Notify all of our associated readers and writers that we're gone.
00051   Readers::iterator ri;
00052   for (ri = _readers.begin(); ri != _readers.end(); ++ri) {
00053     (*ri)->clear_manager();
00054   }
00055   Writers::iterator wi;
00056   for (wi = _writers.begin(); wi != _writers.end(); ++wi) {
00057     (*wi)->clear_manager();
00058   }
00059 
00060   PR_DestroyLock(_set_mutex);
00061 }
00062 
00063 
00064 ////////////////////////////////////////////////////////////////////
00065 //     Function: ConnectionManager::open_UDP_connection
00066 //       Access: Public
00067 //  Description: Opens a socket for sending and/or receiving UDP
00068 //               packets.  If the port number is negative, it will not
00069 //               be bound to a socket; this is generally a pointless
00070 //               thing to do.  If the port number is zero, a random
00071 //               socket will be chosen.  Otherwise, the specified
00072 //               port number is used.  Normally, you don't care what
00073 //               port a UDP connection is opened on, so you should use
00074 //               the default value of zero.
00075 //
00076 //               Use a ConnectionReader and ConnectionWriter to handle
00077 //               the actual communication.
00078 ////////////////////////////////////////////////////////////////////
00079 PT(Connection) ConnectionManager::
00080 open_UDP_connection(int port) {
00081   NetAddress address;
00082   address.set_any(port);
00083 
00084   PRFileDesc *socket = PR_NewUDPSocket();
00085   if (socket == (PRFileDesc *)NULL) {
00086     pprerror("PR_NewUDPSocket");
00087     return PT(Connection)();
00088   }
00089 
00090   if (port >= 0) {
00091     PRStatus result = PR_Bind(socket, address.get_addr());
00092     if (result != PR_SUCCESS) {
00093       pprerror("PR_Bind");
00094       PR_Close(socket);
00095       return PT(Connection)();
00096     }
00097 
00098     net_cat.info()
00099       << "Creating UDP connection for port " << port << "\n";
00100   } else {
00101     net_cat.info()
00102       << "Creating UDP connection\n";
00103   }
00104 
00105   PT(Connection) connection = new Connection(this, socket);
00106   new_connection(connection);
00107   return connection;
00108 }
00109 
00110 
00111 ////////////////////////////////////////////////////////////////////
00112 //     Function: ConnectionManager::open_TCP_server_rendezvous
00113 //       Access: Public
00114 //  Description: Creates a socket to be used as a rendezvous socket
00115 //               for a server to listen for TCP connections.  The
00116 //               socket returned by this call should only be added to
00117 //               a ConnectionListener (not to a generic
00118 //               ConnectionReader).
00119 //
00120 //               backlog is the maximum length of the queue of pending
00121 //               connections.
00122 ////////////////////////////////////////////////////////////////////
00123 PT(Connection) ConnectionManager::
00124 open_TCP_server_rendezvous(int port, int backlog) {
00125   NetAddress address;
00126   address.set_any(port);
00127 
00128   PRFileDesc *socket = PR_NewTCPSocket();
00129   if (socket == (PRFileDesc *)NULL) {
00130     pprerror("PR_NewTCPSocket");
00131     return PT(Connection)();
00132   }
00133 
00134   PRStatus result = PR_Bind(socket, address.get_addr());
00135   if (result != PR_SUCCESS) {
00136     pprerror("PR_Bind");
00137     net_cat.info()
00138       << "Unable to bind to port " << port << " for TCP.\n";
00139     PR_Close(socket);
00140     return PT(Connection)();
00141   }
00142 
00143   result = PR_Listen(socket, backlog);
00144   if (result != PR_SUCCESS) {
00145     pprerror("PR_Listen");
00146     net_cat.info()
00147       << "Unable to listen to port " << port << " for TCP.\n";
00148     PR_Close(socket);
00149     return PT(Connection)();
00150   }
00151 
00152   net_cat.info()
00153     << "Listening for TCP connections on port " << port << "\n";
00154 
00155   PT(Connection) connection = new Connection(this, socket);
00156   new_connection(connection);
00157   return connection;
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: ConnectionManager::open_TCP_client_connection
00162 //       Access: Public
00163 //  Description: Attempts to establish a TCP client connection to a
00164 //               server at the indicated address.  If the connection
00165 //               is not established within timeout_ms milliseconds, a
00166 //               null connection is returned.
00167 ////////////////////////////////////////////////////////////////////
00168 PT(Connection) ConnectionManager::
00169 open_TCP_client_connection(const NetAddress &address, int timeout_ms) {
00170   PRFileDesc *socket = PR_NewTCPSocket();
00171   if (socket == (PRFileDesc *)NULL) {
00172     pprerror("PR_NewTCPSocket");
00173     return PT(Connection)();
00174   }
00175 
00176   PRStatus result = PR_Connect(socket, address.get_addr(),
00177                                PR_MillisecondsToInterval(timeout_ms));
00178   if (result != PR_SUCCESS) {
00179     if (PR_GetError() != PR_CONNECT_RESET_ERROR) {
00180       pprerror("PR_Connect");
00181     }
00182     net_cat.info()
00183       << "Unable to open TCP connection to server "
00184       << address.get_ip_string() << " on port " << address.get_port() << "\n";
00185     PR_Close(socket);
00186     return PT(Connection)();
00187   }
00188 
00189   net_cat.info()
00190     << "Opened TCP connection to server " << address.get_ip_string() << " "
00191     << " on port " << address.get_port() << "\n";
00192 
00193   PT(Connection) connection = new Connection(this, socket);
00194   new_connection(connection);
00195   return connection;
00196 }
00197 
00198 ////////////////////////////////////////////////////////////////////
00199 //     Function: ConnectionManager::open_TCP_client_connection
00200 //       Access: Public
00201 //  Description: This is a shorthand version of the function to
00202 //               directly establish communcations to a named host and
00203 //               port.
00204 ////////////////////////////////////////////////////////////////////
00205 PT(Connection) ConnectionManager::
00206 open_TCP_client_connection(const string &hostname, int port,
00207                            int timeout_ms) {
00208   NetAddress address;
00209   if (!address.set_host(hostname, port)) {
00210     return PT(Connection)();
00211   }
00212 
00213   return open_TCP_client_connection(address, timeout_ms);
00214 }
00215 
00216 ////////////////////////////////////////////////////////////////////
00217 //     Function: ConnectionManager::close_connection
00218 //       Access: Public
00219 //  Description: Terminates a UDP or TCP socket previously opened.
00220 //               This also removes it from any associated
00221 //               ConnectionReader or ConnectionListeners.
00222 //
00223 //               The socket itself may not be immediately closed--it
00224 //               will not be closed until all outstanding pointers to
00225 //               it are cleared, including any pointers remaining in
00226 //               NetDatagrams recently received from the socket.
00227 //
00228 //               The return value is true if the connection was marked
00229 //               to be closed, or false if close_connection() had
00230 //               already been called (or the connection did not belong
00231 //               to this ConnectionManager).  In neither case can you
00232 //               infer anything about whether the connection has
00233 //               *actually* been closed yet based on the return value.
00234 ////////////////////////////////////////////////////////////////////
00235 bool ConnectionManager::
00236 close_connection(const PT(Connection) &connection) {
00237   PR_Lock(_set_mutex);
00238   Connections::iterator ci = _connections.find(connection);
00239   if (ci == _connections.end()) {
00240     // Already closed, or not part of this ConnectionManager.
00241     PR_Unlock(_set_mutex);
00242     return false;
00243   }
00244   _connections.erase(ci);
00245 
00246   Readers::iterator ri;
00247   for (ri = _readers.begin(); ri != _readers.end(); ++ri) {
00248     (*ri)->remove_connection(connection);
00249   }
00250   PR_Unlock(_set_mutex);
00251 
00252   PRFileDesc *socket = connection->get_socket();
00253 
00254   if (PR_GetDescType(socket) == PR_DESC_SOCKET_TCP) {
00255     // We can't *actually* close the connection right now, because
00256     // there might be outstanding pointers to it.  But we can at least
00257     // shut it down.  It will be eventually closed when all the
00258     // pointers let go.
00259 
00260     PRStatus result = PR_Shutdown(socket, PR_SHUTDOWN_BOTH);
00261     if (result != PR_SUCCESS) {
00262       PRErrorCode errcode = PR_GetError();
00263       if (errcode != PR_NOT_CONNECTED_ERROR) {
00264         pprerror("PR_Shutdown");
00265       }
00266     }
00267   }
00268 
00269   return true;
00270 }
00271 
00272 ////////////////////////////////////////////////////////////////////
00273 //     Function: ConnectionManager::get_host_name
00274 //       Access: Public, Static
00275 //  Description: Returns the name of this particular machine on the
00276 //               network, if available, or the empty string if the
00277 //               hostname cannot be determined.
00278 ////////////////////////////////////////////////////////////////////
00279 string ConnectionManager::
00280 get_host_name() {
00281   char temp_buff[1024];
00282   if (gethostname(temp_buff, 1024) == 0) {
00283     return string(temp_buff);
00284   }
00285 
00286   return string();
00287 }
00288 
00289 ////////////////////////////////////////////////////////////////////
00290 //     Function: ConnectionManager::new_connection
00291 //       Access: Protected
00292 //  Description: This internal function is called whenever a new
00293 //               connection is established.  It allows the
00294 //               ConnectionManager to save all of the pointers to open
00295 //               connections so they can't be inadvertently deleted
00296 //               until close_connection() is called.
00297 ////////////////////////////////////////////////////////////////////
00298 void ConnectionManager::
00299 new_connection(const PT(Connection) &connection) {
00300   PR_Lock(_set_mutex);
00301   _connections.insert(connection);
00302   PR_Unlock(_set_mutex);
00303 }
00304 
00305 ////////////////////////////////////////////////////////////////////
00306 //     Function: ConnectionManager::add_reader
00307 //       Access: Protected
00308 //  Description: This internal function is called by ConnectionReader
00309 //               when it is constructed.
00310 ////////////////////////////////////////////////////////////////////
00311 void ConnectionManager::
00312 add_reader(ConnectionReader *reader) {
00313   PR_Lock(_set_mutex);
00314   _readers.insert(reader);
00315   PR_Unlock(_set_mutex);
00316 }
00317 
00318 ////////////////////////////////////////////////////////////////////
00319 //     Function: ConnectionManager::remove_reader
00320 //       Access: Protected
00321 //  Description: This internal function is called by ConnectionReader
00322 //               when it is destructed.
00323 ////////////////////////////////////////////////////////////////////
00324 void ConnectionManager::
00325 remove_reader(ConnectionReader *reader) {
00326   PR_Lock(_set_mutex);
00327   _readers.erase(reader);
00328   PR_Unlock(_set_mutex);
00329 }
00330 
00331 ////////////////////////////////////////////////////////////////////
00332 //     Function: ConnectionManager::add_writer
00333 //       Access: Protected
00334 //  Description: This internal function is called by ConnectionWriter
00335 //               when it is constructed.
00336 ////////////////////////////////////////////////////////////////////
00337 void ConnectionManager::
00338 add_writer(ConnectionWriter *writer) {
00339   PR_Lock(_set_mutex);
00340   _writers.insert(writer);
00341   PR_Unlock(_set_mutex);
00342 }
00343 
00344 ////////////////////////////////////////////////////////////////////
00345 //     Function: ConnectionManager::remove_writer
00346 //       Access: Protected
00347 //  Description: This internal function is called by ConnectionWriter
00348 //               when it is destructed.
00349 ////////////////////////////////////////////////////////////////////
00350 void ConnectionManager::
00351 remove_writer(ConnectionWriter *writer) {
00352   PR_Lock(_set_mutex);
00353   _writers.erase(writer);
00354   PR_Unlock(_set_mutex);
00355 }

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