prepared the ipv4 multicast code for full multicast support.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20945 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -85,6 +85,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
Iterator GetIterator() const { return HashTable::GetIterator(); }
|
||||
|
||||
private:
|
||||
void _Insert(ValueType **table, size_t tableSize, ValueType *value)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "multicast.h"
|
||||
|
||||
#include <net_datalink.h>
|
||||
#include <net_datalink_protocol.h>
|
||||
#include <net_protocol.h>
|
||||
#include <net_stack.h>
|
||||
#include <NetBufferUtilities.h>
|
||||
@@ -22,7 +23,7 @@
|
||||
#include <util/list.h>
|
||||
#include <util/khash.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
#include <util/MultiHashTable.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
@@ -30,6 +31,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <utility>
|
||||
|
||||
|
||||
//#define TRACE_IPV4
|
||||
@@ -118,48 +120,6 @@ class FragmentPacket {
|
||||
};
|
||||
|
||||
|
||||
class MulticastGroup {
|
||||
public:
|
||||
MulticastGroup(const in_addr &address);
|
||||
|
||||
status_t Deliver(net_protocol_module_info *module, net_buffer *buffer,
|
||||
bool raw);
|
||||
|
||||
void Add(IPv4Multicast::GroupState *groupState);
|
||||
void Remove(IPv4Multicast::GroupState *groupState);
|
||||
bool IsEmpty() const { return fLinks.IsEmpty(); }
|
||||
|
||||
struct HashDefinition {
|
||||
typedef void ParentType;
|
||||
typedef const in_addr KeyType;
|
||||
typedef MulticastGroup ValueType;
|
||||
|
||||
size_t HashKey(const in_addr &address) const
|
||||
{ return address.s_addr; }
|
||||
size_t Hash(MulticastGroup *group) const
|
||||
{ return HashKey(group->fMulticastAddress); }
|
||||
bool Compare(const in_addr &address, MulticastGroup *group) const
|
||||
{ return group->fMulticastAddress.s_addr == address.s_addr; }
|
||||
HashTableLink<MulticastGroup> *GetLink(MulticastGroup *group) const
|
||||
{ return &group->fLink; }
|
||||
};
|
||||
|
||||
void DumpInternalState() const;
|
||||
|
||||
private:
|
||||
// for g++ 2.95
|
||||
friend class HashDefinition;
|
||||
|
||||
typedef DoublyLinkedList<IPv4Multicast::GroupState> Links;
|
||||
|
||||
in_addr fMulticastAddress;
|
||||
Links fLinks;
|
||||
|
||||
HashTableLink<MulticastGroup> fLink;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class RawSocket : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> {
|
||||
public:
|
||||
RawSocket(net_socket *socket);
|
||||
@@ -167,8 +127,29 @@ class RawSocket : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSoc
|
||||
|
||||
typedef DoublyLinkedList<RawSocket> RawSocketList;
|
||||
|
||||
typedef MulticastGroupInterface<IPv4Multicast> IPv4GroupInterface;
|
||||
typedef MulticastFilter<IPv4Multicast> IPv4MulticastFilter;
|
||||
|
||||
struct MulticastStateHash {
|
||||
typedef void ParentType;
|
||||
typedef std::pair<const in_addr *, uint32> KeyType;
|
||||
typedef IPv4GroupInterface ValueType;
|
||||
|
||||
size_t HashKey(const KeyType &key) const
|
||||
{ return key.first->s_addr ^ key.second; }
|
||||
size_t Hash(ValueType *value) const
|
||||
{ return HashKey(std::make_pair(&value->Address(),
|
||||
value->Interface()->index)); }
|
||||
bool Compare(const KeyType &key, ValueType *value) const
|
||||
{ return value->Interface()->index == key.second
|
||||
&& value->Address().s_addr == key.first->s_addr; }
|
||||
bool CompareValues(ValueType *value1, ValueType *value2) const
|
||||
{ return value1->Interface()->index == value2->Interface()->index
|
||||
&& value1->Address().s_addr == value2->Address().s_addr; }
|
||||
HashTableLink<ValueType> *GetLink(ValueType *value) const { return value; }
|
||||
};
|
||||
|
||||
|
||||
struct ipv4_protocol : net_protocol {
|
||||
ipv4_protocol()
|
||||
: multicast_filter(this) {}
|
||||
@@ -205,8 +186,10 @@ static benaphore sRawSocketsLock;
|
||||
static benaphore sFragmentLock;
|
||||
static hash_table *sFragmentHash;
|
||||
static benaphore sMulticastGroupsLock;
|
||||
typedef OpenHashTable<MulticastGroup::HashDefinition> MulticastGroups;
|
||||
static MulticastGroups *sMulticastGroups;
|
||||
|
||||
typedef MultiHashTable<MulticastStateHash> MulticastState;
|
||||
static MulticastState *sMulticastState;
|
||||
|
||||
static net_protocol_module_info *sReceivingProtocol[256];
|
||||
static benaphore sReceivingProtocolLock;
|
||||
|
||||
@@ -461,73 +444,6 @@ FragmentPacket::StaleTimer(struct net_timer *timer, void *data)
|
||||
}
|
||||
|
||||
|
||||
MulticastGroup::MulticastGroup(const in_addr &address)
|
||||
: fMulticastAddress(address)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MulticastGroup::Deliver(net_protocol_module_info *module, net_buffer *buffer,
|
||||
bool deliverToRaw)
|
||||
{
|
||||
Links::Iterator iterator = fLinks.GetIterator();
|
||||
|
||||
while (iterator.HasNext()) {
|
||||
IPv4Multicast::GroupState *groupState = iterator.Next();
|
||||
|
||||
if (deliverToRaw && groupState->Socket()->raw == NULL)
|
||||
continue;
|
||||
|
||||
if (groupState->FilterAccepts(buffer)) {
|
||||
// as Multicast filters are installed with an IPv4 protocol
|
||||
// reference, we need to go and find the appropriate instance
|
||||
// related to the 'receiving protocol' with module 'module'.
|
||||
net_protocol *proto = groupState->Socket()->socket->first_protocol;
|
||||
|
||||
while (proto && proto->module != module)
|
||||
proto = proto->next;
|
||||
|
||||
if (proto)
|
||||
module->deliver_data(proto, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MulticastGroup::Add(IPv4Multicast::GroupState *groupState)
|
||||
{
|
||||
fLinks.Add(groupState);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MulticastGroup::Remove(IPv4Multicast::GroupState *groupState)
|
||||
{
|
||||
fLinks.Remove(groupState);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MulticastGroup::DumpInternalState() const
|
||||
{
|
||||
char addrBuf[64];
|
||||
|
||||
kprintf("group %s (%p)\n", print_address(&fMulticastAddress, addrBuf,
|
||||
sizeof(addrBuf)), this);
|
||||
|
||||
Links::ConstIterator it = fLinks.GetIterator();
|
||||
while (it.HasNext()) {
|
||||
IPv4Multicast::GroupState *group = it.Next();
|
||||
|
||||
kprintf(" socket %p\n", group->Socket());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
@@ -730,12 +646,37 @@ deliver_multicast(net_protocol_module_info *module, net_buffer *buffer,
|
||||
|
||||
BenaphoreLocker _(sMulticastGroupsLock);
|
||||
|
||||
MulticastGroup *group = sMulticastGroups->Lookup(
|
||||
((sockaddr_in *)&buffer->destination)->sin_addr);
|
||||
if (group == NULL)
|
||||
return B_OK;
|
||||
sockaddr_in *multicastAddr = (sockaddr_in *)&buffer->destination;
|
||||
|
||||
return group->Deliver(module, buffer, deliverToRaw);
|
||||
MulticastState::Iterator it = sMulticastState->Lookup(std::make_pair(
|
||||
&multicastAddr->sin_addr, buffer->interface->index));
|
||||
|
||||
while (it.HasNext()) {
|
||||
IPv4GroupInterface *state = it.Next();
|
||||
|
||||
if (state->Interface()->index != buffer->interface->index
|
||||
|| state->Address().s_addr != multicastAddr->sin_addr.s_addr)
|
||||
break;
|
||||
|
||||
if (deliverToRaw && state->Parent()->Socket()->raw == NULL)
|
||||
continue;
|
||||
|
||||
if (state->FilterAccepts(buffer)) {
|
||||
// as Multicast filters are installed with an IPv4 protocol
|
||||
// reference, we need to go and find the appropriate instance
|
||||
// related to the 'receiving protocol' with module 'module'.
|
||||
net_protocol *proto =
|
||||
state->Parent()->Socket()->socket->first_protocol;
|
||||
|
||||
while (proto && proto->module != module)
|
||||
proto = proto->next;
|
||||
|
||||
if (proto)
|
||||
module->deliver_data(proto, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -770,40 +711,42 @@ raw_receive_data(net_buffer *buffer)
|
||||
|
||||
|
||||
status_t
|
||||
IPv4Multicast::JoinGroup(GroupState *groupState)
|
||||
IPv4Multicast::JoinGroup(IPv4GroupInterface *state)
|
||||
{
|
||||
BenaphoreLocker _(sMulticastGroupsLock);
|
||||
|
||||
MulticastGroup *group = sMulticastGroups->Lookup(groupState->Address());
|
||||
if (group == NULL) {
|
||||
group = new (std::nothrow) MulticastGroup(groupState->Address());
|
||||
if (group == NULL)
|
||||
return B_NO_MEMORY;
|
||||
sockaddr_in groupAddr;
|
||||
memset(&groupAddr, 0, sizeof(groupAddr));
|
||||
groupAddr.sin_addr = state->Address();
|
||||
|
||||
sMulticastGroups->Insert(group);
|
||||
}
|
||||
net_interface *intf = state->Interface();
|
||||
|
||||
group->Add(groupState);
|
||||
status_t status =
|
||||
intf->first_protocol->module->join_multicast(intf->first_protocol,
|
||||
(sockaddr *)&groupAddr);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
sMulticastState->Insert(state);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IPv4Multicast::LeaveGroup(GroupState *groupState)
|
||||
IPv4Multicast::LeaveGroup(IPv4GroupInterface *state)
|
||||
{
|
||||
BenaphoreLocker _(sMulticastGroupsLock);
|
||||
|
||||
MulticastGroup *group = sMulticastGroups->Lookup(groupState->Address());
|
||||
if (group == NULL)
|
||||
return ENOENT;
|
||||
sMulticastState->Remove(state);
|
||||
|
||||
group->Remove(groupState);
|
||||
if (group->IsEmpty()) {
|
||||
sMulticastGroups->Remove(group);
|
||||
delete group;
|
||||
}
|
||||
sockaddr_in groupAddr;
|
||||
memset(&groupAddr, 0, sizeof(groupAddr));
|
||||
groupAddr.sin_addr = state->Address();
|
||||
|
||||
return B_OK;
|
||||
net_interface *intf = state->Interface();
|
||||
|
||||
return intf->first_protocol->module->join_multicast(intf->first_protocol,
|
||||
(sockaddr *)&groupAddr);
|
||||
}
|
||||
|
||||
|
||||
@@ -838,22 +781,22 @@ fill_sockaddr_in(sockaddr_in *target, in_addr_t address)
|
||||
|
||||
|
||||
static status_t
|
||||
ipv4_delta_group(IPv4MulticastFilter::GroupState *group, int option,
|
||||
ipv4_delta_group(IPv4GroupInterface *group, int option,
|
||||
net_interface *interface, const in_addr *sourceAddr)
|
||||
{
|
||||
switch (option) {
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
return group->Add(interface);
|
||||
return group->Add();
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
return group->Drop(interface);
|
||||
return group->Drop();
|
||||
case IP_BLOCK_SOURCE:
|
||||
return group->BlockSource(interface, *sourceAddr);
|
||||
return group->BlockSource(*sourceAddr);
|
||||
case IP_UNBLOCK_SOURCE:
|
||||
return group->UnblockSource(interface, *sourceAddr);
|
||||
return group->UnblockSource(*sourceAddr);
|
||||
case IP_ADD_SOURCE_MEMBERSHIP:
|
||||
return group->AddSSM(interface, *sourceAddr);
|
||||
return group->AddSSM(*sourceAddr);
|
||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
||||
return group->DropSSM(interface, *sourceAddr);
|
||||
return group->DropSSM(*sourceAddr);
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
@@ -866,22 +809,21 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
||||
const in_addr *sourceAddr)
|
||||
{
|
||||
IPv4MulticastFilter &filter = protocol->multicast_filter;
|
||||
IPv4MulticastFilter::GroupState *group = NULL;
|
||||
IPv4GroupInterface *state = NULL;
|
||||
status_t status = B_OK;
|
||||
|
||||
switch (option) {
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
case IP_ADD_SOURCE_MEMBERSHIP:
|
||||
group = filter.GetGroup(*groupAddr, true);
|
||||
if (group == NULL)
|
||||
return ENOBUFS;
|
||||
status = filter.GetState(*groupAddr, interface, state, true);
|
||||
break;
|
||||
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
case IP_BLOCK_SOURCE:
|
||||
case IP_UNBLOCK_SOURCE:
|
||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
||||
group = filter.GetGroup(*groupAddr, false);
|
||||
if (group == NULL) {
|
||||
filter.GetState(*groupAddr, interface, state, false);
|
||||
if (state == NULL) {
|
||||
if (option == IP_DROP_MEMBERSHIP
|
||||
|| option == IP_DROP_SOURCE_MEMBERSHIP)
|
||||
return EADDRNOTAVAIL;
|
||||
@@ -891,10 +833,11 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
||||
break;
|
||||
}
|
||||
|
||||
status_t status = ipv4_delta_group(group, option, interface, sourceAddr);
|
||||
|
||||
filter.ReturnGroup(group);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
status = ipv4_delta_group(state, option, interface, sourceAddr);
|
||||
filter.ReturnState(state);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1590,10 +1533,17 @@ ipv4_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
|
||||
static int
|
||||
dump_ipv4_multicast(int argc, char *argv[])
|
||||
{
|
||||
MulticastGroups::Iterator it = sMulticastGroups->GetIterator();
|
||||
MulticastState::Iterator it = sMulticastState->GetIterator();
|
||||
|
||||
while (it.HasNext())
|
||||
it.Next()->DumpInternalState();
|
||||
while (it.HasNext()) {
|
||||
IPv4GroupInterface *state = it.Next();
|
||||
|
||||
char addrBuf[64];
|
||||
|
||||
kprintf("%p: group <%s, %s> sock %p\n", state,
|
||||
state->Interface()->name, print_address(&state->Address(),
|
||||
addrBuf, sizeof(addrBuf)), state->Parent()->Socket());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1623,11 +1573,11 @@ init_ipv4()
|
||||
if (status < B_OK)
|
||||
goto err3;
|
||||
|
||||
sMulticastGroups = new MulticastGroups();
|
||||
if (sMulticastGroups == NULL)
|
||||
sMulticastState = new MulticastState();
|
||||
if (sMulticastState == NULL)
|
||||
goto err4;
|
||||
|
||||
status = sMulticastGroups->InitCheck();
|
||||
status = sMulticastState->InitCheck();
|
||||
if (status < B_OK)
|
||||
goto err5;
|
||||
|
||||
@@ -1659,7 +1609,7 @@ init_ipv4()
|
||||
err6:
|
||||
hash_uninit(sFragmentHash);
|
||||
err5:
|
||||
delete sMulticastGroups;
|
||||
delete sMulticastState;
|
||||
err4:
|
||||
benaphore_destroy(&sReceivingProtocolLock);
|
||||
err3:
|
||||
@@ -1688,7 +1638,7 @@ uninit_ipv4()
|
||||
gStackModule->unregister_domain(sDomain);
|
||||
benaphore_unlock(&sReceivingProtocolLock);
|
||||
|
||||
delete sMulticastGroups;
|
||||
delete sMulticastState;
|
||||
hash_uninit(sFragmentHash);
|
||||
|
||||
benaphore_destroy(&sMulticastGroupsLock);
|
||||
|
||||
@@ -23,227 +23,120 @@ operator==(const in_addr &a1, const in_addr &a2)
|
||||
using std::nothrow;
|
||||
|
||||
|
||||
template<typename AddressType>
|
||||
MulticastGroupInterfaceState<AddressType>::MulticastGroupInterfaceState(
|
||||
net_interface *interface)
|
||||
: fInterface(interface)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<typename AddressType>
|
||||
MulticastGroupInterfaceState<AddressType>::~MulticastGroupInterfaceState()
|
||||
{
|
||||
typename SourceList::Iterator iterator = fSources.GetIterator();
|
||||
while (iterator.HasNext()) {
|
||||
_Remove(iterator.Next());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename AddressType> status_t
|
||||
MulticastGroupInterfaceState<AddressType>::Add(const AddressType &address)
|
||||
{
|
||||
return _Get(address, true) ? B_OK : ENOBUFS;
|
||||
}
|
||||
|
||||
|
||||
template<typename AddressType> status_t
|
||||
MulticastGroupInterfaceState<AddressType>::Remove(const AddressType &address)
|
||||
{
|
||||
Source *state = _Get(address, false);
|
||||
if (state == NULL)
|
||||
return EADDRNOTAVAIL;
|
||||
|
||||
_Remove(state);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename AddressType> typename MulticastGroupInterfaceState<AddressType>::Source *
|
||||
MulticastGroupInterfaceState<AddressType>::_Get(const AddressType &address,
|
||||
bool create)
|
||||
{
|
||||
typename SourceList::Iterator iterator = fSources.GetIterator();
|
||||
while (iterator.HasNext()) {
|
||||
Source *state = iterator.Next();
|
||||
if (state->address == address)
|
||||
return state;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return false;
|
||||
|
||||
Source *state = new (nothrow) Source;
|
||||
if (state) {
|
||||
state->address = address;
|
||||
fSources.Add(state);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
template<typename AddressType> void
|
||||
MulticastGroupInterfaceState<AddressType>::_Remove(Source *state)
|
||||
{
|
||||
fSources.Remove(state);
|
||||
delete state;
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing>
|
||||
MulticastGroupState<Addressing>::MulticastGroupState(ProtocolType *socket,
|
||||
const AddressType &address)
|
||||
: fSocket(socket), fMulticastAddress(address), fFilterMode(kInclude)
|
||||
MulticastGroupInterface<Addressing>::MulticastGroupInterface(Filter *parent,
|
||||
const AddressType &address, net_interface *interface)
|
||||
: fParent(parent), fMulticastAddress(address), fInterface(interface)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing>
|
||||
MulticastGroupState<Addressing>::~MulticastGroupState()
|
||||
MulticastGroupInterface<Addressing>::~MulticastGroupInterface()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> status_t
|
||||
MulticastGroupState<Addressing>::Add(net_interface *interface)
|
||||
MulticastGroupInterface<Addressing>::Add()
|
||||
{
|
||||
if (fFilterMode == kInclude && !fInterfaces.IsEmpty())
|
||||
if (fFilterMode == kInclude && !fAddresses.IsEmpty())
|
||||
return EINVAL;
|
||||
|
||||
fFilterMode = kExclude;
|
||||
|
||||
return _GetInterface(interface, true) != NULL ? B_OK : ENOBUFS;
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> status_t
|
||||
MulticastGroupState<Addressing>::Drop(net_interface *interface)
|
||||
{
|
||||
InterfaceState *state = _GetInterface(interface, false);
|
||||
if (state == NULL)
|
||||
return EADDRNOTAVAIL;
|
||||
|
||||
_RemoveInterface(state);
|
||||
|
||||
if (fInterfaces.IsEmpty())
|
||||
fFilterMode = kInclude;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> status_t
|
||||
MulticastGroupState<Addressing>::BlockSource(net_interface *interface,
|
||||
MulticastGroupInterface<Addressing>::Drop()
|
||||
{
|
||||
fAddresses.Clear();
|
||||
fFilterMode = kInclude;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> status_t
|
||||
MulticastGroupInterface<Addressing>::BlockSource(
|
||||
const AddressType &sourceAddress)
|
||||
{
|
||||
if (fFilterMode != kExclude)
|
||||
return EINVAL;
|
||||
|
||||
InterfaceState *state = _GetInterface(interface, false);
|
||||
if (state == NULL)
|
||||
return EINVAL;
|
||||
|
||||
return state->Add(sourceAddress);
|
||||
fAddresses.Add(sourceAddress);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> status_t
|
||||
MulticastGroupState<Addressing>::UnblockSource(net_interface *interface,
|
||||
MulticastGroupInterface<Addressing>::UnblockSource(
|
||||
const AddressType &sourceAddress)
|
||||
{
|
||||
if (fFilterMode != kExclude)
|
||||
return EINVAL;
|
||||
|
||||
InterfaceState *state = _GetInterface(interface, false);
|
||||
if (state == NULL)
|
||||
return EINVAL;
|
||||
|
||||
return state->Remove(sourceAddress);
|
||||
}
|
||||
|
||||
template<typename Addressing> status_t
|
||||
MulticastGroupState<Addressing>::AddSSM(net_interface *interface,
|
||||
const AddressType &sourceAddress)
|
||||
{
|
||||
if (fFilterMode == kExclude)
|
||||
return EINVAL;
|
||||
|
||||
InterfaceState *state = _GetInterface(interface, true);
|
||||
if (state == NULL)
|
||||
return ENOBUFS;
|
||||
|
||||
return state->Add(sourceAddress);
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> status_t
|
||||
MulticastGroupState<Addressing>::DropSSM(net_interface *interface,
|
||||
const AddressType &sourceAddress)
|
||||
{
|
||||
if (fFilterMode == kExclude)
|
||||
return EINVAL;
|
||||
|
||||
InterfaceState *state = _GetInterface(interface, false);
|
||||
if (state == NULL)
|
||||
if (!fAddresses.Has(sourceAddress))
|
||||
return EADDRNOTAVAIL;
|
||||
|
||||
return state->Remove(sourceAddress);
|
||||
fAddresses.Add(sourceAddress);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> void
|
||||
MulticastGroupState<Addressing>::Clear()
|
||||
template<typename Addressing> status_t
|
||||
MulticastGroupInterface<Addressing>::AddSSM(const AddressType &sourceAddress)
|
||||
{
|
||||
typename InterfaceList::Iterator iterator = fInterfaces.GetIterator();
|
||||
while (iterator.HasNext())
|
||||
_RemoveInterface(iterator.Next());
|
||||
if (fFilterMode == kExclude)
|
||||
return EINVAL;
|
||||
|
||||
fAddresses.Add(sourceAddress);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> status_t
|
||||
MulticastGroupInterface<Addressing>::DropSSM(const AddressType &sourceAddress)
|
||||
{
|
||||
if (fFilterMode == kExclude)
|
||||
return EINVAL;
|
||||
|
||||
if (!fAddresses.Has(sourceAddress))
|
||||
return EADDRNOTAVAIL;
|
||||
|
||||
fAddresses.Add(sourceAddress);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> bool
|
||||
MulticastGroupState<Addressing>::FilterAccepts(net_buffer *buffer)
|
||||
MulticastGroupInterface<Addressing>::IsEmpty() const
|
||||
{
|
||||
InterfaceState *state = _GetInterface(buffer->interface, false);
|
||||
if (state == NULL)
|
||||
return false;
|
||||
|
||||
bool has = state->Contains(Addressing::AddressFromSockAddr(
|
||||
(sockaddr *)&buffer->source));
|
||||
|
||||
return (has && fFilterMode == kInclude) || (!has && fFilterMode == kExclude);
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> typename MulticastGroupState<Addressing>::InterfaceState *
|
||||
MulticastGroupState<Addressing>::_GetInterface(net_interface *interface,
|
||||
bool create)
|
||||
{
|
||||
typename InterfaceList::Iterator iterator = fInterfaces.GetIterator();
|
||||
while (iterator.HasNext()) {
|
||||
InterfaceState *state = iterator.Next();
|
||||
if (state->Interface() == interface)
|
||||
return state;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return false;
|
||||
|
||||
InterfaceState *state = new (nothrow) InterfaceState(interface);
|
||||
if (state)
|
||||
fInterfaces.Add(state);
|
||||
|
||||
return state;
|
||||
return fFilterMode == kInclude && fAddresses.IsEmpty();
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> void
|
||||
MulticastGroupState<Addressing>::_RemoveInterface(InterfaceState *state)
|
||||
MulticastGroupInterface<Addressing>::Clear()
|
||||
{
|
||||
fInterfaces.Remove(state);
|
||||
delete state;
|
||||
if (IsEmpty())
|
||||
return;
|
||||
|
||||
fFilterMode = kInclude;
|
||||
fAddresses.Clear();
|
||||
Addressing::LeaveGroup(this);
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> bool
|
||||
MulticastGroupInterface<Addressing>::FilterAccepts(net_buffer *buffer) const
|
||||
{
|
||||
bool has = fAddresses.Has(Addressing::AddressFromSockAddr(
|
||||
(sockaddr *)&buffer->source));
|
||||
|
||||
return (has && fFilterMode == kInclude)
|
||||
|| (!has && fFilterMode == kExclude);
|
||||
}
|
||||
|
||||
|
||||
@@ -262,56 +155,58 @@ MulticastFilter<Addressing>::~MulticastFilter()
|
||||
if (!iterator.HasNext())
|
||||
return;
|
||||
|
||||
GroupState *state = iterator.Next();
|
||||
GroupInterface *state = iterator.Next();
|
||||
state->Clear();
|
||||
_ReturnGroup(state);
|
||||
_ReturnState(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> typename MulticastFilter<Addressing>::GroupState *
|
||||
MulticastFilter<Addressing>::GetGroup(const AddressType &groupAddress,
|
||||
bool create)
|
||||
template<typename Addressing> status_t
|
||||
MulticastFilter<Addressing>::GetState(const AddressType &groupAddress,
|
||||
net_interface *interface, GroupInterface* &state, bool create)
|
||||
{
|
||||
GroupState *state = fStates.Lookup(groupAddress);
|
||||
if (state)
|
||||
return state;
|
||||
state = fStates.Lookup(std::make_pair(&groupAddress, interface->index));
|
||||
|
||||
if (create) {
|
||||
state = new (nothrow) GroupState(fParent, groupAddress);
|
||||
if (state) {
|
||||
if (fStates.Insert(state) >= B_OK) {
|
||||
if (Addressing::JoinGroup(state) >= B_OK)
|
||||
return state;
|
||||
|
||||
fStates.Remove(state);
|
||||
}
|
||||
if (state == NULL && create) {
|
||||
state = new (nothrow) GroupInterface(this, groupAddress, interface);
|
||||
if (state == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t status = fStates.Insert(state);
|
||||
if (status < B_OK) {
|
||||
delete state;
|
||||
return status;
|
||||
}
|
||||
|
||||
status = Addressing::JoinGroup(state);
|
||||
if (status < B_OK) {
|
||||
fStates.Remove(state);
|
||||
delete state;
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> void
|
||||
MulticastFilter<Addressing>::ReturnGroup(GroupState *group)
|
||||
MulticastFilter<Addressing>::ReturnState(GroupInterface *state)
|
||||
{
|
||||
if (group->IsEmpty())
|
||||
_ReturnGroup(group);
|
||||
if (state->IsEmpty())
|
||||
_ReturnState(state);
|
||||
}
|
||||
|
||||
|
||||
template<typename Addressing> void
|
||||
MulticastFilter<Addressing>::_ReturnGroup(GroupState *group)
|
||||
MulticastFilter<Addressing>::_ReturnState(GroupInterface *state)
|
||||
{
|
||||
Addressing::LeaveGroup(group);
|
||||
fStates.Remove(group);
|
||||
delete group;
|
||||
fStates.Remove(state);
|
||||
delete state;
|
||||
}
|
||||
|
||||
// IPv4 explicit template instantiation
|
||||
template class MulticastFilter<IPv4Multicast>;
|
||||
template class MulticastGroupState<IPv4Multicast>;
|
||||
template class MulticastGroupInterfaceState<in_addr>;
|
||||
template class MulticastGroupInterface<IPv4Multicast>;
|
||||
|
||||
@@ -12,25 +12,28 @@
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
#include <net_datalink.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
struct net_buffer;
|
||||
struct net_interface;
|
||||
struct net_protocol;
|
||||
|
||||
// This code is template'ized as it is reusable for IPv6
|
||||
|
||||
template<typename Addressing> class MulticastFilter;
|
||||
template<typename Addressing> class MulticastGroupState;
|
||||
template<typename Addressing> class MulticastGroupInterface;
|
||||
|
||||
// TODO move this elsewhere...
|
||||
struct IPv4Multicast {
|
||||
typedef struct in_addr AddressType;
|
||||
typedef struct ipv4_protocol ProtocolType;
|
||||
typedef MulticastGroupState<IPv4Multicast> GroupState;
|
||||
typedef MulticastGroupInterface<IPv4Multicast> GroupInterface;
|
||||
|
||||
static status_t JoinGroup(GroupState *);
|
||||
static status_t LeaveGroup(GroupState *);
|
||||
static status_t JoinGroup(GroupInterface *);
|
||||
static status_t LeaveGroup(GroupInterface *);
|
||||
|
||||
static const in_addr &AddressFromSockAddr(const sockaddr *sockaddr)
|
||||
{ return ((const sockaddr_in *)sockaddr)->sin_addr; }
|
||||
@@ -39,106 +42,131 @@ struct IPv4Multicast {
|
||||
};
|
||||
|
||||
template<typename AddressType>
|
||||
struct MulticastSource
|
||||
: DoublyLinkedListLinkImpl< MulticastSource<AddressType> > {
|
||||
AddressType address;
|
||||
};
|
||||
|
||||
template<typename AddressType>
|
||||
class MulticastGroupInterfaceState
|
||||
: public DoublyLinkedListLinkImpl< MulticastGroupInterfaceState<AddressType> > {
|
||||
class AddressSet {
|
||||
public:
|
||||
MulticastGroupInterfaceState(net_interface *interface);
|
||||
~MulticastGroupInterfaceState();
|
||||
|
||||
net_interface *Interface() const { return fInterface; }
|
||||
|
||||
status_t Add(const AddressType &address);
|
||||
status_t Remove(const AddressType &address);
|
||||
|
||||
bool Contains(const AddressType &address)
|
||||
{ return _Get(address, false) != NULL; }
|
||||
|
||||
private:
|
||||
typedef MulticastSource<AddressType> Source;
|
||||
typedef DoublyLinkedList<Source> SourceList;
|
||||
|
||||
Source *_Get(const AddressType &address, bool create);
|
||||
void _Remove(Source *state);
|
||||
|
||||
net_interface *fInterface;
|
||||
// TODO make this an hash table as well
|
||||
SourceList fSources;
|
||||
};
|
||||
|
||||
template<typename Addressing>
|
||||
class MulticastGroupState
|
||||
: public DoublyLinkedListLinkImpl< MulticastGroupState<Addressing> > {
|
||||
public:
|
||||
typedef MulticastGroupState<Addressing> ThisType;
|
||||
typedef HashTableLink<ThisType> HashLink;
|
||||
typedef typename Addressing::AddressType AddressType;
|
||||
typedef typename Addressing::ProtocolType ProtocolType;
|
||||
|
||||
MulticastGroupState(ProtocolType *parent, const AddressType &address);
|
||||
~MulticastGroupState();
|
||||
|
||||
ProtocolType *Socket() const { return fSocket; }
|
||||
|
||||
const AddressType &Address() const { return fMulticastAddress; }
|
||||
bool IsEmpty() const
|
||||
{ return fFilterMode == kInclude && fInterfaces.IsEmpty(); }
|
||||
|
||||
status_t Add(net_interface *interface);
|
||||
status_t Drop(net_interface *interface);
|
||||
status_t BlockSource(net_interface *interface,
|
||||
const AddressType &sourceAddress);
|
||||
status_t UnblockSource(net_interface *interface,
|
||||
const AddressType &sourceAddress);
|
||||
status_t AddSSM(net_interface *interface,
|
||||
const AddressType &sourceAddress);
|
||||
status_t DropSSM(net_interface *interface,
|
||||
const AddressType &sourceAddress);
|
||||
|
||||
void Clear();
|
||||
|
||||
bool FilterAccepts(net_buffer *buffer);
|
||||
|
||||
struct HashDefinition {
|
||||
typedef void ParentType;
|
||||
typedef typename MulticastGroupState::AddressType KeyType;
|
||||
typedef typename MulticastGroupState::ThisType ValueType;
|
||||
typedef typename MulticastGroupState::HashLink HashLink;
|
||||
|
||||
size_t HashKey(const KeyType &key) const
|
||||
{ return Addressing::HashAddress(key); }
|
||||
size_t Hash(ValueType *value) const
|
||||
{ return HashKey(value->Address()); }
|
||||
bool Compare(const KeyType &key, ValueType *value) const
|
||||
{ return key == value->Address(); }
|
||||
HashLink *GetLink(ValueType *value) const { return &value->fHashLink; }
|
||||
struct ContainedAddress : DoublyLinkedListLinkImpl<ContainedAddress> {
|
||||
AddressType address;
|
||||
};
|
||||
|
||||
~AddressSet() { Clear(); }
|
||||
|
||||
status_t Add(const AddressType &address)
|
||||
{
|
||||
if (Has(address))
|
||||
return B_OK;
|
||||
|
||||
ContainedAddress *container = new ContainedAddress();
|
||||
if (container == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
container->address = address;
|
||||
fAddresses.Add(container);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void Remove(const AddressType &address)
|
||||
{
|
||||
ContainedAddress *container = _Get(address);
|
||||
if (container == NULL)
|
||||
return;
|
||||
|
||||
fAddresses.Remove(container);
|
||||
delete container;
|
||||
}
|
||||
|
||||
bool Has(const AddressType &address) const
|
||||
{
|
||||
return _Get(address) != NULL;
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return fAddresses.IsEmpty(); }
|
||||
|
||||
void Clear()
|
||||
{
|
||||
while (!fAddresses.IsEmpty())
|
||||
Remove(fAddresses.Head()->address);
|
||||
}
|
||||
|
||||
private:
|
||||
// for g++ 2.95
|
||||
friend class HashDefinition;
|
||||
typedef DoublyLinkedList<ContainedAddress> AddressList;
|
||||
|
||||
typedef MulticastGroupInterfaceState<AddressType> InterfaceState;
|
||||
typedef DoublyLinkedList<InterfaceState> InterfaceList;
|
||||
ContainedAddress *_Get(const AddressType &address) const
|
||||
{
|
||||
AddressList::ConstIterator it = fAddresses.GetIterator();
|
||||
while (it.HasNext()) {
|
||||
ContainedAddress *container = it.Next();
|
||||
if (container->address == address)
|
||||
return container;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InterfaceState *_GetInterface(net_interface *interface, bool create);
|
||||
void _RemoveInterface(InterfaceState *state);
|
||||
AddressList fAddresses;
|
||||
};
|
||||
|
||||
|
||||
template<typename Addressing>
|
||||
class MulticastGroupInterface
|
||||
: public HashTableLink< MulticastGroupInterface<Addressing> > {
|
||||
public:
|
||||
typedef MulticastGroupInterface<Addressing> ThisType;
|
||||
typedef HashTableLink<ThisType> HashLink;
|
||||
typedef typename Addressing::AddressType AddressType;
|
||||
typedef MulticastFilter<Addressing> Filter;
|
||||
|
||||
enum FilterMode {
|
||||
kInclude,
|
||||
kExclude
|
||||
};
|
||||
|
||||
ProtocolType *fSocket;
|
||||
MulticastGroupInterface(Filter *parent, const AddressType &address,
|
||||
net_interface *interface);
|
||||
~MulticastGroupInterface();
|
||||
|
||||
Filter *Parent() const { return fParent; }
|
||||
|
||||
const AddressType &Address() const { return fMulticastAddress; }
|
||||
net_interface *Interface() const { return fInterface; }
|
||||
|
||||
status_t Add();
|
||||
status_t Drop();
|
||||
status_t BlockSource(const AddressType &sourceAddress);
|
||||
status_t UnblockSource(const AddressType &sourceAddress);
|
||||
status_t AddSSM(const AddressType &sourceAddress);
|
||||
status_t DropSSM(const AddressType &sourceAddress);
|
||||
|
||||
bool IsEmpty() const;
|
||||
void Clear();
|
||||
|
||||
bool FilterAccepts(net_buffer *buffer) const;
|
||||
|
||||
struct HashDefinition {
|
||||
typedef void ParentType;
|
||||
typedef std::pair<const AddressType *, uint32> KeyType;
|
||||
typedef ThisType ValueType;
|
||||
|
||||
size_t HashKey(const KeyType &key) const
|
||||
{ return Addressing::HashAddress(*key.first) ^ key.second; }
|
||||
size_t Hash(ValueType *value) const
|
||||
{ return HashKey(std::make_pair(&value->Address(),
|
||||
value->Interface()->index)); }
|
||||
bool Compare(const KeyType &key, ValueType *value) const
|
||||
{ return value->Interface()->index == key.second
|
||||
&& value->Address().s_addr == key.first->s_addr; }
|
||||
HashLink *GetLink(ValueType *value) const { return &value->fLink; }
|
||||
};
|
||||
|
||||
private:
|
||||
// for g++ 2.95
|
||||
friend class HashDefinition;
|
||||
|
||||
Filter *fParent;
|
||||
AddressType fMulticastAddress;
|
||||
net_interface *fInterface;
|
||||
FilterMode fFilterMode;
|
||||
InterfaceList fInterfaces;
|
||||
HashLink fHashLink;
|
||||
AddressSet<AddressType> fAddresses;
|
||||
HashLink fLink;
|
||||
};
|
||||
|
||||
template<typename Addressing>
|
||||
@@ -146,21 +174,22 @@ class MulticastFilter {
|
||||
public:
|
||||
typedef typename Addressing::AddressType AddressType;
|
||||
typedef typename Addressing::ProtocolType ProtocolType;
|
||||
typedef MulticastGroupState<Addressing> GroupState;
|
||||
typedef MulticastGroupInterface<Addressing> GroupInterface;
|
||||
|
||||
MulticastFilter(ProtocolType *parent);
|
||||
~MulticastFilter();
|
||||
|
||||
ProtocolType *Parent() const { return fParent; }
|
||||
ProtocolType *Socket() const { return fParent; }
|
||||
|
||||
GroupState *GetGroup(const AddressType &groupAddress, bool create);
|
||||
void ReturnGroup(GroupState *group);
|
||||
status_t GetState(const AddressType &groupAddress,
|
||||
net_interface *interface, GroupInterface* &state, bool create);
|
||||
void ReturnState(GroupInterface *state);
|
||||
|
||||
private:
|
||||
typedef typename GroupState::HashDefinition GroupHashDefinition;
|
||||
typedef OpenHashTable<GroupHashDefinition> States;
|
||||
typedef typename GroupInterface::HashDefinition HashDefinition;
|
||||
typedef OpenHashTable<HashDefinition> States;
|
||||
|
||||
void _ReturnGroup(GroupState *group);
|
||||
void _ReturnState(GroupInterface *state);
|
||||
|
||||
ProtocolType *fParent;
|
||||
States fStates;
|
||||
|
||||
@@ -804,7 +804,7 @@ interface_protocol_join_multicast(net_datalink_protocol *_protocol,
|
||||
const sockaddr *address)
|
||||
{
|
||||
// TODO
|
||||
return EINVAL;
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
@@ -813,7 +813,7 @@ interface_protocol_leave_multicast(net_datalink_protocol *_protocol,
|
||||
const sockaddr *address)
|
||||
{
|
||||
// TODO
|
||||
return EINVAL;
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user