]> git.saurik.com Git - wxWidgets.git/commitdiff
added support for broadcasting to UDP sockets (patch 1740266)
authorVadim Zeitlin <vadim@wxwidgets.org>
Wed, 4 Jul 2007 21:33:11 +0000 (21:33 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Wed, 4 Jul 2007 21:33:11 +0000 (21:33 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@47126 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

14 files changed:
docs/changes.txt
docs/latex/wx/ipaddr.tex
docs/latex/wx/socket.tex
include/wx/gsocket.h
include/wx/msw/gsockmsw.h
include/wx/sckaddr.h
include/wx/socket.h
include/wx/unix/gsockunx.h
src/common/sckaddr.cpp
src/common/socket.cpp
src/mac/carbon/cfsocket.cpp
src/mac/carbon/gsocket.cpp
src/msw/gsocket.cpp
src/unix/gsocket.cpp

index 020280fbec77799adf79bfd294dc3d766dfb46bd..60494b7ba33101e5fcc4dfe3dab0f9735653f75d 100644 (file)
@@ -109,6 +109,7 @@ All:
 - Added functions for atomically inc/decrementing integers (Armel Asselin)
 - wxLogInterposer has been added to replace wxLogPassThrough and new
   wxLogInterposerTemp was added
+- Added support for broadcasting to UDP sockets (Andrew Vincent)
 
 All (GUI):
 
index 390e72c36e7dbc0b7ffe489cf84b440eeecb782f..be39274d3096aea19a5da3127c7cafbd6068c9f9 100644 (file)
@@ -98,6 +98,23 @@ On IPV6 implementations, ::
 
 Returns true on success, false if something went wrong.
 
+%
+% BroadcastAddress
+%
+
+\membersection{wxIPaddress::BroadcastAddress}\label{wxIPaddressbroadcastaddress}
+
+\func{virtual bool}{BroadcastAddress}{\void}
+
+Internally, this is the same as setting the IP address
+to {\bf INADDR\_BROADCAST}.
+
+On IPV4 implementations, 255.255.255.255
+
+\wxheading{Return value}
+
+Returns true on success, false if something went wrong.
+
 %
 % LocalHost
 %
index de3c5c5a88d708c04dbe246862400fdead31745f..ac48755b04f1d8c622bdb659540d05c2a0a91040 100644 (file)
@@ -524,6 +524,8 @@ The following flags can be used:
 \twocolitem{{\bf wxSOCKET\_WAITALL}}{Wait for all required data to be read/written unless an error occurs.}
 \twocolitem{{\bf wxSOCKET\_BLOCK}}{Block the GUI (do not yield) while reading/writing data.}
 \twocolitem{{\bf wxSOCKET\_REUSEADDR}}{Allows the use of an in-use port (wxServerSocket only)}
+\twocolitem{{\bf wxSOCKET\_BROADCAST}}{Switches the socket to broadcast mode}
+\twocolitem{{\bf wxSOCKET\_NOBIND}}{Stops the socket from being bound to a specific adapter (normally used in conjunction with {\bf wxSOCKET\_BROADCAST})}
 \end{twocollist}
 
 A brief overview on how to use these flags follows.
@@ -568,6 +570,10 @@ your platform's implementation of setsockopt(). Note that on BSD-based systems (
 use of wxSOCKET\_REUSEADDR implies SO\_REUSEPORT in addition to SO\_REUSEADDR to be consistent
 with Windows.
 
+The {\bf wxSOCKET\_BROADCAST} flag controls the use of the SO\_BROADCAST standard
+setsockopt() flag. This flag allows the socket to use the broadcast address, and is generally
+used in conjunction with {\bf wxSOCKET\_NOBIND} and \helpref{wxIPaddress::BroadcastAddress}{wxipaddressbroadcastaddress}.
+
 So:
 
 {\bf wxSOCKET\_NONE} will try to read at least SOME data, no matter how much.
index ffd70673d67ef5a08815b662a4ec832e6fc9121b..ade7734433add37781f6bdc82d7c63711dca8383 100644 (file)
@@ -150,6 +150,7 @@ GAddressType GAddress_GetFamily(GAddress *address);
  */
 
 GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname);
+GSocketError GAddress_INET_SetBroadcastAddress(GAddress *address);
 GSocketError GAddress_INET_SetAnyAddress(GAddress *address);
 GSocketError GAddress_INET_SetHostAddress(GAddress *address,
                                           unsigned long hostaddr);
index 859ed60513acd8ced9c68286fe871d922c2d6da9..a32589d602dae7c943de2f46149f048b91df9326 100644 (file)
@@ -63,6 +63,8 @@ public:
   GSocketError SetServer();
   GSocket *WaitConnection();
   bool SetReusable();
+  bool SetBroadcast();
+  bool DontDoBind();
   GSocketError Connect(GSocketStream stream);
   GSocketError SetNonOriented();
   int Read(char *buffer, int size);
@@ -101,6 +103,8 @@ public:
   bool m_stream;
   bool m_establishing;
   bool m_reusable;
+  bool m_broadcast;
+  bool m_dobind;
   struct timeval m_timeout;
 
   /* Callbacks */
index 98e1c0d4e7b592c28b91a963e91a8b2353737fee..f24627bd5f17c638365b5589789054e7ec6c296c 100644 (file)
@@ -64,6 +64,7 @@ public:
   virtual bool IsLocalHost() const = 0;
 
   virtual bool AnyAddress() = 0;
+  virtual bool BroadcastAddress() = 0;
 
   virtual wxString IPAddress() const = 0;
 
@@ -93,6 +94,8 @@ public:
 
   // any (0.0.0.0)
   virtual bool AnyAddress();
+  // all (255.255.255.255)
+  virtual bool BroadcastAddress();
 
   virtual wxString Hostname() const;
   wxString OrigHostname() { return m_origHostname; }
@@ -149,6 +152,8 @@ public:
 
   // any (0000:0000:0000:0000:0000:0000:0000:0000 (::))
   virtual bool AnyAddress();
+  // all (?)
+  virtual bool BroadcastAddress();
 
   // 3ffe:ffff:0100:f101:0210:a4ff:fee3:9566
   virtual wxString IPAddress() const;
index 3c61361a56d651539675aa0f07d9bf56801041a9..ea55c060db17bd5eca22d995fe724a03cf5c64c0 100644 (file)
@@ -71,7 +71,9 @@ enum
   wxSOCKET_NOWAIT = 1,
   wxSOCKET_WAITALL = 2,
   wxSOCKET_BLOCK = 4,
-  wxSOCKET_REUSEADDR = 8
+  wxSOCKET_REUSEADDR = 8,
+  wxSOCKET_BROADCAST = 16,
+  wxSOCKET_NOBIND = 32
 };
 
 enum wxSocketType
index c4a5ba3773bf6267310bb02fc9c864fb71277044..438b7255203dd650e17f0c07b144546bb900f8f7 100644 (file)
@@ -52,6 +52,8 @@ public:
     GSocketError SetServer();
     GSocket *WaitConnection();
     bool SetReusable();
+    bool SetBroadcast();
+    bool DontDoBind();
     GSocketError Connect(GSocketStream stream);
     GSocketError SetNonOriented();
     int Read(char *buffer, int size);
@@ -91,6 +93,8 @@ public:
   bool m_stream;
   bool m_establishing;
   bool m_reusable;
+  bool m_broadcast;
+  bool m_dobind;
   unsigned long m_timeout;
 
   /* Callbacks */
index 81bafbdf717e8216e03dcf125743f53aa3e27380..8e79847d83e4d9ab0d9dbb778294ea45bcc15f6f 100644 (file)
@@ -178,6 +178,11 @@ bool wxIPV4address::IsLocalHost() const
   return (Hostname() == wxT("localhost") || IPAddress() == wxT("127.0.0.1"));
 }
 
+bool wxIPV4address::BroadcastAddress()
+{
+  return (GAddress_INET_SetBroadcastAddress(m_address) == GSOCK_NOERROR);
+}
+
 bool wxIPV4address::AnyAddress()
 {
   return (GAddress_INET_SetAnyAddress(m_address) == GSOCK_NOERROR);
@@ -275,6 +280,11 @@ bool wxIPV6address::IsLocalHost() const
   return (Hostname() == wxT("localhost") || IPAddress() == wxT("127.0.0.1"));
 }
 
+bool wxIPV6address::BroadcastAddress()
+{
+  return (GAddress_INET_SetBroadcastAddress(m_address) == GSOCK_NOERROR);
+}
+
 bool wxIPV6address::AnyAddress()
 {
   return (GAddress_INET_SetAnyAddress(m_address) == GSOCK_NOERROR);
index e36bfe9768f3ec07e2fbd04b125eb6afff30cf62..7e82eb01c69ac32d0fcdc3016db9c3e1b1971258 100644 (file)
@@ -1105,6 +1105,12 @@ wxSocketServer::wxSocketServer(const wxSockAddress& addr_man,
     if (GetFlags() & wxSOCKET_REUSEADDR) {
         m_socket->SetReusable();
     }
+    if (GetFlags() & wxSOCKET_BROADCAST) {
+        m_socket->SetBroadcast();
+    }
+    if (GetFlags() & wxSOCKET_NOBIND) {
+        m_socket->DontDoBind();
+    }
 
     if (m_socket->SetServer() != GSOCK_NOERROR)
     {
@@ -1275,6 +1281,14 @@ bool wxSocketClient::DoConnect(wxSockAddress& addr_man, wxSockAddress* local, bo
   {
     m_socket->SetReusable();
   }
+  if (GetFlags() & wxSOCKET_BROADCAST)
+  {
+    m_socket->SetBroadcast();
+  }
+  if (GetFlags() & wxSOCKET_NOBIND)
+  {
+    m_socket->DontDoBind();
+  }
 
   // If no local address was passed and one has been set, use the one that was Set
   if (!local && m_localAddress.GetAddress())
@@ -1355,6 +1369,14 @@ wxDatagramSocket::wxDatagramSocket( const wxSockAddress& addr,
     {
         m_socket->SetReusable();
     }
+    if (GetFlags() & wxSOCKET_BROADCAST)
+    {
+        m_socket->SetBroadcast();
+    }
+    if (GetFlags() & wxSOCKET_NOBIND)
+    {
+        m_socket->DontDoBind();
+    }
     if ( m_socket->SetNonOriented() != GSOCK_NOERROR )
     {
         delete m_socket;
index a8a331f03d5b0ed032ba0c8ed56af515540a7d07..8a2383c7f5772a075bbf356a0cc7310a42f04f10 100644 (file)
@@ -1562,6 +1562,11 @@ GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname)
   return GSOCK_NOERROR;
 }
 
+GSocketError GAddress_INET_SetBroadcastAddress(GAddress *address)
+{
+  return GAddress_INET_SetHostAddress(address, INADDR_BROADCAST);
+}
+
 GSocketError GAddress_INET_SetAnyAddress(GAddress *address)
 {
   return GAddress_INET_SetHostAddress(address, INADDR_ANY);
index 04441b27dfcc8bde2a0729e679b302dd4b194dcd..1b14f7d3a0d74a2ef033e234d23994f124c56416 100644 (file)
@@ -1314,6 +1314,11 @@ GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname)
   return GSOCK_NOERROR;
 }
 
+GSocketError GAddress_INET_SetBroadcastAddress(GAddress *address)
+{
+  return GAddress_INET_SetHostAddress(address, INADDR_BROADCAST);
+}
+
 GSocketError GAddress_INET_SetAnyAddress(GAddress *address)
 {
   return GAddress_INET_SetHostAddress(address, INADDR_ANY);
index 2edc3ab24796396c89d07cbb61a85c201a92798c..63da4996692828eb30a996b0f1cdbdfdba2f9936 100644 (file)
@@ -177,6 +177,8 @@ GSocket::GSocket()
   m_timeout.tv_usec = 0;
   m_establishing    = false;
   m_reusable        = false;
+  m_broadcast          = false;
+  m_dobind          = true;
 
   assert(gs_gui_functions);
   /* Per-socket GUI-specific initialization */
@@ -529,6 +531,34 @@ bool GSocket::SetReusable()
     return false;
 }
 
+/* GSocket_SetBroadcast:
+*  Simply sets the m_broadcast flag on the socket. GSocket_SetServer will
+*  make the appropriate setsockopt() call.
+*  Implemented as a GSocket function because clients (ie, wxSocketServer)
+*  don't have access to the GSocket struct information.
+*  Returns true if the flag was set correctly, false if an error occurred
+*  (ie, if the parameter was NULL)
+*/
+bool GSocket::SetBroadcast()
+{
+    /* socket must not be in use/already bound */
+    if (m_fd == INVALID_SOCKET) {
+        m_broadcast = true;
+        return true;
+    }
+    return false;
+}
+
+bool GSocket::DontDoBind()
+{
+    /* socket must not be in use/already bound */
+    if (m_fd == INVALID_SOCKET) {
+        m_dobind = false;
+        return true;
+    }
+    return false;
+}
+
 /* Client specific parts */
 
 /* GSocket_Connect:
@@ -706,18 +736,24 @@ GSocketError GSocket::SetNonOriented()
   {
     setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&arg, sizeof(arg));
   }
-
-  /* Bind to the local address,
-   * and retrieve the actual address bound.
-   */
-  if ((bind(m_fd, m_local->m_addr, m_local->m_len) != 0) ||
-      (getsockname(m_fd,
-                   m_local->m_addr,
-                   (WX_SOCKLEN_T *)&m_local->m_len) != 0))
+  if (m_broadcast)
   {
-    Close();
-    m_error = GSOCK_IOERR;
-    return GSOCK_IOERR;
+    setsockopt(m_fd, SOL_SOCKET, SO_BROADCAST, (const char*)&arg, sizeof(arg));
+  }
+  if (m_dobind)
+  {
+    /* Bind to the local address,
+     * and retrieve the actual address bound.
+     */
+    if ((bind(m_fd, m_local->m_addr, m_local->m_len) != 0) ||
+        (getsockname(m_fd,
+                     m_local->m_addr,
+                     (WX_SOCKLEN_T *)&m_local->m_len) != 0))
+    {
+      Close();
+      m_error = GSOCK_IOERR;
+      return GSOCK_IOERR;
+    }
   }
 
   return GSOCK_NOERROR;
@@ -1413,6 +1449,11 @@ GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname)
   return GSOCK_NOERROR;
 }
 
+GSocketError GAddress_INET_SetBroadcastAddress(GAddress *address)
+{
+  return GAddress_INET_SetHostAddress(address, INADDR_BROADCAST);
+}
+
 GSocketError GAddress_INET_SetAnyAddress(GAddress *address)
 {
   return GAddress_INET_SetHostAddress(address, INADDR_ANY);
index e2423cdd2c96d062e9ede15a966d11b604e05016..13a3b5b12cf02b3c6ce9367615ddc1209882b630 100644 (file)
@@ -533,6 +533,8 @@ GSocket::GSocket()
   m_gui_dependent       = NULL;
   m_non_blocking        = false;
   m_reusable            = false;
+  m_broadcast           = false;
+  m_dobind              = true;
   m_timeout             = 10*60*1000;
                                 /* 10 minutes * 60 sec * 1000 millisec */
   m_establishing        = false;
@@ -903,6 +905,26 @@ bool GSocket::SetReusable()
     return false;
 }
 
+bool GSocket::SetBroadcast()
+{
+    /* socket must not be in use/already bound */
+    if (m_fd == INVALID_SOCKET) {
+        m_broadcast = true;
+        return true;
+    }
+    return false;
+}
+
+bool GSocket::DontDoBind()
+{
+    /* socket must not be in use/already bound */
+    if (m_fd == INVALID_SOCKET) {
+        m_dobind = false;
+        return true;
+    }
+    return false;
+}
+
 /* Client specific parts */
 
 /* GSocket_Connect:
@@ -1119,19 +1141,25 @@ GSocketError GSocket::SetNonOriented()
 #endif
   }
 
-  /* Bind to the local address,
-   * and retrieve the actual address bound.
-   */
-  if ((bind(m_fd, m_local->m_addr, m_local->m_len) != 0) ||
-      (getsockname(m_fd,
-                   m_local->m_addr,
-                   (WX_SOCKLEN_T *) &m_local->m_len) != 0))
+  if (m_broadcast)
   {
-    Close();
-    m_error = GSOCK_IOERR;
-    return GSOCK_IOERR;
+    setsockopt(m_fd, SOL_SOCKET, SO_BROADCAST, (const char*)&arg, sizeof(arg));
+  }
+  if (m_dobind)
+  {
+      /* Bind to the local address,
+       * and retrieve the actual address bound.
+       */
+      if ((bind(m_fd, m_local->m_addr, m_local->m_len) != 0) ||
+          (getsockname(m_fd,
+                       m_local->m_addr,
+                       (WX_SOCKLEN_T *) &m_local->m_len) != 0))
+      {
+        Close();
+        m_error = GSOCK_IOERR;
+        return GSOCK_IOERR;
+      }
   }
-
   return GSOCK_NOERROR;
 }
 
@@ -2068,6 +2096,12 @@ GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname)
   return GSOCK_NOERROR;
 }
 
+
+GSocketError GAddress_INET_SetBroadcastAddress(GAddress *address)
+{
+  return GAddress_INET_SetHostAddress(address, INADDR_BROADCAST);
+}
+
 GSocketError GAddress_INET_SetAnyAddress(GAddress *address)
 {
   return GAddress_INET_SetHostAddress(address, INADDR_ANY);