Browse Source

work in progress: get_interfaces()

David Rose 12 years ago
parent
commit
d51a48acca
2 changed files with 170 additions and 0 deletions
  1. 116 0
      panda/src/net/connectionManager.cxx
  2. 54 0
      panda/src/net/connectionManager.h

+ 116 - 0
panda/src/net/connectionManager.cxx

@@ -23,6 +23,9 @@
 
 #if defined(WIN32_VC) || defined(WIN64_VC)
 #include <winsock2.h>  // For gethostname()
+#else
+#include <net/if.h>
+#include <ifaddrs.h>
 #endif
 
 ////////////////////////////////////////////////////////////////////
@@ -33,6 +36,7 @@
 ConnectionManager::
 ConnectionManager() : _set_mutex("ConnectionManager::_set_mutex") 
 {
+  _interfaces_scanned = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -504,6 +508,95 @@ get_host_name() {
   return string();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ConnectionManager::scan_interfaces
+//       Access: Published
+//  Description: Repopulates the list reported by
+//               get_num_interface()/get_interface().  It is not
+//               necessary to call this explicitly, unless you want to
+//               re-determine the connected interfaces (for instance,
+//               if you suspect the hardware has recently changed).
+////////////////////////////////////////////////////////////////////
+void ConnectionManager::
+scan_interfaces() {
+  LightMutexHolder holder(_set_mutex);
+  _interfaces.clear();
+  _interfaces_scanned = true;
+
+#ifdef WIN32_VC
+  // TODO.
+
+#else  // WIN32_VC
+  struct ifaddrs *ifa;
+  if (getifaddrs(&ifa) != 0) {
+    // Failure.
+    net_cat.error()
+      << "Failed to call getifaddrs\n";
+    return;
+  }
+
+  struct ifaddrs *p = ifa;
+  while (p != NULL) {
+    if (p->ifa_addr->sa_family == AF_INET) {
+      Interface interface;
+      interface.set_name(p->ifa_name);
+      if (p->ifa_addr != NULL) {
+        interface.set_ip(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_addr)));
+      }
+      if (p->ifa_netmask != NULL) {
+        interface.set_netmask(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_netmask)));
+      }
+      if ((p->ifa_flags & IFF_BROADCAST) && p->ifa_broadaddr != NULL) {
+        interface.set_broadcast(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_broadaddr)));
+      } else if ((p->ifa_flags & IFF_POINTOPOINT) && p->ifa_dstaddr != NULL) {
+        interface.set_p2p(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_dstaddr)));
+      }
+      _interfaces.push_back(interface);
+    }
+
+    p = p->ifa_next;
+  }
+
+  freeifaddrs(ifa);
+
+#endif // WIN32_VC
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConnectionManager::get_num_interfaces
+//       Access: Published
+//  Description: This returns the number of usable network interfaces
+//               detected on this machine.  (Currently, only IPv4
+//               interfaces are reported.)  See scan_interfaces() to
+//               repopulate this list.
+////////////////////////////////////////////////////////////////////
+int ConnectionManager::
+get_num_interfaces() {
+  if (!_interfaces_scanned) {
+    scan_interfaces();
+  }
+  LightMutexHolder holder(_set_mutex);
+  return _interfaces.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConnectionManager::get_interface
+//       Access: Published
+//  Description: Returns the nth usable network interface detected on
+//               this machine.  (Currently, only IPv4 interfaces are
+//               reported.)  See scan_interfaces() to repopulate this
+//               list.
+////////////////////////////////////////////////////////////////////
+const ConnectionManager::Interface &ConnectionManager::
+get_interface(int n) {
+  if (!_interfaces_scanned) {
+    scan_interfaces();
+  }
+  LightMutexHolder holder(_set_mutex);
+  nassertr(n >= 0 && n < (int)_interfaces.size(), _interfaces[0]);
+  return _interfaces[n];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ConnectionManager::new_connection
 //       Access: Protected
@@ -629,3 +722,26 @@ remove_writer(ConnectionWriter *writer) {
   LightMutexHolder holder(_set_mutex);
   _writers.erase(writer);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConnectionManager::Interface::Output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void ConnectionManager::Interface::
+output(ostream &out) const {
+  out << get_name() << " [";
+  if (has_ip()) {
+    out << " " << get_ip();
+  }
+  if (has_netmask()) {
+    out << " netmask " << get_netmask();
+  }
+  if (has_broadcast()) {
+    out << " broadcast " << get_broadcast();
+  }
+  if (has_p2p()) {
+    out << " p2p " << get_p2p();
+  }
+  out << " ]";
+}

+ 54 - 0
panda/src/net/connectionManager.h

@@ -21,6 +21,7 @@
 #include "connection.h"
 #include "pointerTo.h"
 #include "pset.h"
+#include "pvector.h"
 #include "lightMutex.h"
 
 class NetAddress;
@@ -66,6 +67,50 @@ PUBLISHED:
 
   static string get_host_name();
 
+  class Interface {
+  PUBLISHED:
+    const string &get_name() const { return _name; }
+    bool has_ip() const { return (_flags & F_has_ip) != 0; }
+    const NetAddress &get_ip() const { return _ip; }
+    bool has_netmask() const { return (_flags & F_has_netmask) != 0; }
+    const NetAddress &get_netmask() const { return _netmask; }
+    bool has_broadcast() const { return (_flags & F_has_broadcast) != 0; }
+    const NetAddress &get_broadcast() const { return _broadcast; }
+    bool has_p2p() const { return (_flags & F_has_p2p) != 0; }
+    const NetAddress &get_p2p() const { return _p2p; }
+
+    void output(ostream &out) const;
+
+  public:
+    Interface() { _flags = 0; }
+    void set_name(const string &name) { _name = name; }
+    void set_ip(const NetAddress &ip) { _ip = ip; _flags |= F_has_ip; }
+    void set_netmask(const NetAddress &ip) { _netmask = ip; _flags |= F_has_netmask; }
+    void set_broadcast(const NetAddress &ip) { _broadcast = ip; _flags |= F_has_broadcast; }
+    void set_p2p(const NetAddress &ip) { _p2p = ip; _flags |= F_has_p2p; }
+
+  private:
+    string _name;
+
+    NetAddress _ip;
+    NetAddress _netmask;
+    NetAddress _broadcast;
+    NetAddress _p2p;
+    int _flags;
+
+    enum Flags {
+      F_has_ip        = 0x001,
+      F_has_netmask   = 0x002,
+      F_has_broadcast = 0x004,
+      F_has_p2p       = 0x008,
+    };
+  };
+
+  void scan_interfaces();
+  int get_num_interfaces();
+  const Interface &get_interface(int n);
+  MAKE_SEQ(get_interfaces, get_num_interfaces, get_interface);
+
 protected:
   void new_connection(const PT(Connection) &connection);
   virtual void flush_read_connection(Connection *connection);
@@ -85,6 +130,10 @@ protected:
   Writers _writers;
   LightMutex _set_mutex;
 
+  typedef pvector<Interface> Interfaces;
+  Interfaces _interfaces;
+  bool _interfaces_scanned;
+
 private:
   friend class ConnectionReader;
   friend class ConnectionWriter;
@@ -92,4 +141,9 @@ private:
   friend class Connection;
 };
 
+INLINE ostream &operator << (ostream &out, const ConnectionManager::Interface &interface) {
+  interface.output(out);
+  return out;
+}
+
 #endif