123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
|
/*******************************************************************************
copyright: Copyright (c) 2004 Kris Bell. All rights reserved
license: BSD style: $(LICENSE)
version: Jun 2004 : Initial release
version: Dec 2006 : South pacific version
author: Kris
*******************************************************************************/
module tango.net.device.Multicast;
public import tango.net.InternetAddress;
public import tango.net.device.Datagram;
private import tango.net.device.Berkeley;
/******************************************************************************
MulticastConduit sends and receives data on a multicast group, as
described by a class-D address. To send data, the recipient group
should be handed to the write() method. To receive, the socket is
bound to an available local adapter/port as a listener and must
join() the group before it becomes eligible for input from there.
While MulticastConduit is a flavour of datagram, it doesn't support
being connected to a specific endpoint.
Sending and receiving via a multicast group:
---
auto group = new InternetAddress ("225.0.0.10", 8080);
// listen for datagrams on the group address (via port 8080)
auto multi = new MulticastConduit (group);
// join and broadcast to the group
multi.join.write ("hello", group);
// we are listening also ...
char[8] tmp;
auto bytes = multi.read (tmp);
---
Note that this example is expecting to receive its own broadcast;
thus it may be necessary to enable loopback operation (see below)
for successful receipt of the broadcast.
Note that class D addresses range from 225.0.0.0 to 239.255.255.255
see: http://www.kohala.com/start/mcast.api.txt
*******************************************************************************/
class Multicast : Datagram
{
private InternetAddress group;
enum {Host=0, Subnet=1, Site=32, Region=64, Continent=128, Unrestricted=255}
/***********************************************************************
Create a writable multicast socket
***********************************************************************/
this ()
{
super ();
}
/***********************************************************************
Create a read/write multicast socket
This flavour is necessary only for a multicast receiver
(e.g. use this ctor in conjunction with SocketListener).
You should specify both a group address and a port to
listen upon. The resultant socket will be bound to the
specified port (locally), and listening on the class-D
address. Expect this to fail without a network adapter
present, as bind() will not find anything to work with.
The reuse parameter dictates how to behave when the port
is already in use. Default behaviour is to throw an IO
exception, and the alternate is to force usage.
To become eligible for incoming group datagrams, you must
also invoke the join() method
***********************************************************************/
this (InternetAddress group, bool reuse = false)
{
super ();
this.group = group;
/* Posix also seems to require to bind to the specific group, while
* Windows does not allow binding to multicast groups. The most
* portable way seems to always bind for posix, but not for other
* systems.
* Reference; http://markmail.org/thread/co53qzbsvqivqxgc
*/
version (Posix) {
native.addressReuse(reuse).bind(group);
} else {
native.addressReuse(reuse).bind(new InternetAddress(group.port));
}
}
/***********************************************************************
Enable/disable the receipt of multicast packets sent
from the same adapter. The default state is OS specific
***********************************************************************/
Multicast loopback (bool yes = true)
{
uint[1] onoff = yes;
native.setOption (SocketOptionLevel.IP, SocketOption.MULTICAST_LOOP, onoff);
return this;
}
/***********************************************************************
Set the number of hops (time to live) of this socket.
Convenient values are
---
Host: packets are restricted to the same host
Subnet: packets are restricted to the same subnet
Site: packets are restricted to the same site
Region: packets are restricted to the same region
Continent: packets are restricted to the same continent
Unrestricted: packets are unrestricted in scope
---
***********************************************************************/
Multicast ttl (uint value=Subnet)
{
uint[1] options = value;
native.setOption (SocketOptionLevel.IP, SocketOption.MULTICAST_TTL, options);
return this;
}
/***********************************************************************
Add this socket to the listening group
***********************************************************************/
Multicast join ()
{
native.joinGroup (group, true);
return this;
}
/***********************************************************************
Remove this socket from the listening group
***********************************************************************/
Multicast leave ()
{
native.joinGroup (group, false);
return this;
}
}
/******************************************************************************
*******************************************************************************/
debug (Multicast)
{
import tango.io.Console;
void main()
{
auto group = new InternetAddress ("225.0.0.10", 8080);
// listen for datagrams on the group address
auto multi = new Multicast (group);
// join and broadcast to the group
multi.join.write ("hello", group);
// we are listening also ...
char[8] tmp;
auto bytes = multi.read (tmp);
Cout (tmp[0..bytes]).newline;
}
}
|