Bug 943 - Add a SO_BROADCAST socket option
Add a SO_BROADCAST socket option
Status: RESOLVED FIXED
Product: ns-3
Classification: Unclassified
Component: network
ns-3-dev
All All
: P5 normal
Assigned To: ns-bugs
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2010-06-15 06:40 EDT by Gustavo J. A. M. Carneiro
Modified: 2010-07-19 10:21 EDT (History)
1 user (show)

See Also:


Attachments
patch (6.43 KB, patch)
2010-06-15 06:40 EDT, Gustavo J. A. M. Carneiro
Details | Diff
patch to enforce the AllowBroadcast socket option for UDP (2.14 KB, patch)
2010-06-18 12:18 EDT, Gustavo J. A. M. Carneiro
Details | Diff
patch to SetAllowBroadcast return bool (minus python bindings rescan) (6.93 KB, patch)
2010-07-16 11:46 EDT, Gustavo J. A. M. Carneiro
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Gustavo J. A. M. Carneiro 2010-06-15 06:40:44 EDT
Created attachment 919 [details]
patch

Real world sockets do not allow applications to send datagrams to a broadcast destination address unless the socket has been configured to allow broadcast via setsockopt with SO_BROADCAST.

This patch adds such an option to the socket via SetAllowBroadcast and GetAllowBroadcast methods.  The option is not properly enforced yet in any of the NS-3 sockets, but we should probably try to implement it in UDP sockets at least (I would have, but it does not sound trivial).  I have implemented in a new socket type I am working on called RealUdpSocket, which translates NS-3 socket API calls into real unix sockets.
Comment 1 Tom Henderson 2010-06-16 01:04:08 EDT
In principle I have no problems with the concept; I like to align with sockets when people have use cases for it.

I think it is applicable to Ipv4 datagram sockets only.  For stream sockets or for IPv6 we could either return -1 and set EINVAL, or else (keeping the return void as you have done) just unconditionally FATAL_ERROR ("Invalid for this type of socket"), and always return "false" for the Get() method.

Plus, as you mention, enforce it.
Comment 2 Gustavo J. A. M. Carneiro 2010-06-16 09:26:31 EDT
(In reply to comment #1)
> In principle I have no problems with the concept; I like to align with sockets
> when people have use cases for it.
> 
> I think it is applicable to Ipv4 datagram sockets only.  For stream sockets or
> for IPv6 we could either return -1 and set EINVAL, or else (keeping the return
> void as you have done) just unconditionally FATAL_ERROR ("Invalid for this type
> of socket"), and always return "false" for the Get() method.

Agreed regarding IPv6.  I checked olsrd, it does not seem to use the SO_BROADCAST option for the IPv6 sockets, only for the IPv4 ones.

About returning void or an error code, the choice of returning void I made based on the only other socket option method that I saw available: BindToNetDevice().  However, setsockopt does return an int (0=ok, -1=error), so I think it makes more sense to return some kind of error indicator.  In the case of the Socket class, we seem to be using the same kind of 0 or -1 int return for signalling errors...

> 
> Plus, as you mention, enforce it.

This might require changes deep in the bowels of IPv4, as it is not easy to determine immediately whether a destination address is broadcast or not, you have to look at the available interfaces in the host.  SendTo is the most problematic one: doing the above iteration of host interfaces on a per-packet basis is going to be slow without some sort of cache based optimization, and adding a cache also wastes memory... really not the kind of decision I like to make (lose-lose) :-/
Comment 3 Gustavo J. A. M. Carneiro 2010-06-18 12:18:34 EDT
Created attachment 923 [details]
patch to enforce the AllowBroadcast socket option for UDP

This additional patch enforces the AllowBroadcast option for UDP sockets (sorry, not possible to distinguish between IPv4 and IPv6 atm).  TCP sockets do not allow broadcast.  All the other sockets report that they allow broadcast.
Comment 4 Gustavo J. A. M. Carneiro 2010-07-12 06:46:24 EDT
comparing with ssh://code@code.nsnam.org/repos/ns-3-dev
searching for changes
changeset:   6437:c11291f51d57
user:        Gustavo J. A. M. Carneiro  <gjc@inescporto.pt>
date:        Tue Jun 15 18:29:45 2010 +0100
summary:     Bug 943 - Add a SO_BROADCAST socket option

changeset:   6438:96f612b05035
user:        Gustavo J. A. M. Carneiro  <gjc@inescporto.pt>
date:        Tue Jun 15 18:32:04 2010 +0100
summary:     Fix OLSR socket usage: use the new SetAllowBroadcast socket option; Bind to interface bcast address instead of local address, use SendTo instead of Send.  This is how things have to work with real world sockets.

changeset:   6439:958a299f1100
user:        Gustavo J. A. M. Carneiro  <gjc@inescporto.pt>
date:        Fri Jun 18 17:18:59 2010 +0100
summary:     Enforce the AllowBroadcast socket option for UDP sockets

changeset:   6440:38a995eb219e
user:        Gustavo J. A. M. Carneiro  <gjc@inescporto.pt>
date:        Mon Jul 12 11:44:47 2010 +0100
summary:     Update python bindings

changeset:   6441:f555caf874dc
tag:         tip
user:        Gustavo J. A. M. Carneiro  <gjc@inescporto.pt>
date:        Mon Jul 12 11:45:15 2010 +0100
summary:     Fix regression tests after bug 943 changes
Comment 5 Tom Henderson 2010-07-16 01:19:04 EDT
Reopening...

In repairing the failing regression test tonight, it seemed to me that this is not quite correct:

  /**
   * \brief Query whether broadcast datagram transmissions are allowed
   *
   * This method corresponds to using getsockopt() SO_BROADCAST of
   * real network or BSD sockets.
   *
   * \returns true if broadcast is allowed, false otherwise
   */
  virtual bool GetAllowBroadcast () const = 0;

The way this is implemented is that it returns true if the socket is Udp, regardless of whether SetAllowBroadcast(true) was called or not.  However, getsockopt(SO_BROADCAST) will return the state of the broadcast flag.

If we want to make the implementation match the doxygen and match getsockopt(), we should return the state of the underlying broadcast flag.  

If we do that, we will be lacking a way to tell whether the underlying socket is broadcast capable.  I see three possible solutions here.

1) add to class Socket

  virtual void GetSockType (enum Socket::SocketType& stype) = 0;

and check stype against SOCK_DGRAM before trying to SetAllowBroadcast().

2) make this change to SetAllowBroadcast:

   * \param allowBroadcast Whether broadcast is allowed
+   * \return true if operation succeeds
   */
-  virtual void SetAllowBroadcast (bool allowBroadcast) = 0;
+  virtual bool SetAllowBroadcast (bool allowBroadcast) = 0;

3) keep SetAllowBroadcast returning void, but set SocketErrno

I would vote for 2) above to solve this particular problem.
Comment 6 Gustavo J. A. M. Carneiro 2010-07-16 07:06:45 EDT
(In reply to comment #5)
> Reopening...
> 
> In repairing the failing regression test tonight, it seemed to me that this is
> not quite correct:
> 
>   /**
>    * \brief Query whether broadcast datagram transmissions are allowed
>    *
>    * This method corresponds to using getsockopt() SO_BROADCAST of
>    * real network or BSD sockets.
>    *
>    * \returns true if broadcast is allowed, false otherwise
>    */
>   virtual bool GetAllowBroadcast () const = 0;
> 
> The way this is implemented is that it returns true if the socket is Udp,
> regardless of whether SetAllowBroadcast(true) was called or not.  However,
> getsockopt(SO_BROADCAST) will return the state of the broadcast flag.
> 
> If we want to make the implementation match the doxygen and match getsockopt(),
> we should return the state of the underlying broadcast flag.  

Sorry about that, an obvious oversight.

> 
> If we do that, we will be lacking a way to tell whether the underlying socket
> is broadcast capable.  I see three possible solutions here.
> 
> 1) add to class Socket
> 
>   virtual void GetSockType (enum Socket::SocketType& stype) = 0;
> 
> and check stype against SOCK_DGRAM before trying to SetAllowBroadcast().
> 
> 2) make this change to SetAllowBroadcast:
> 
>    * \param allowBroadcast Whether broadcast is allowed
> +   * \return true if operation succeeds
>    */
> -  virtual void SetAllowBroadcast (bool allowBroadcast) = 0;
> +  virtual bool SetAllowBroadcast (bool allowBroadcast) = 0;
> 
> 3) keep SetAllowBroadcast returning void, but set SocketErrno
> 
> I would vote for 2) above to solve this particular problem.

Yes. 2) sounds good. But then, in addition we should never have fatal errors if trying to enable broadcast for a socket that doesn't support broadcast.
Comment 7 Tom Henderson 2010-07-16 09:18:39 EDT
> 
> Yes. 2) sounds good. But then, in addition we should never have fatal errors if
> trying to enable broadcast for a socket that doesn't support broadcast.

Agree.
Comment 8 Gustavo J. A. M. Carneiro 2010-07-16 11:46:04 EDT
Created attachment 935 [details]
patch to SetAllowBroadcast return bool (minus python bindings rescan)
Comment 9 Gustavo J. A. M. Carneiro 2010-07-19 10:21:07 EDT
comparing with ssh://code@code.nsnam.org/repos/ns-3-dev
searching for changes
changeset:   6448:184a509cc71d
user:        Gustavo J. A. M. Carneiro  <gjc@inescporto.pt>
date:        Mon Jul 19 12:17:51 2010 +0100
summary:     Still Bug 943: fix UdpSocketImpl::GetAllowBroadcast, let Socket::SetAllowBroadcast return a bool indicating success/failure, instead of a fatal error.