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:
Hugo Santos
2007-05-01 11:38:59 +00:00
parent 1a41adbcd2
commit 8aa4c7e370
5 changed files with 333 additions and 457 deletions
@@ -85,6 +85,8 @@ public:
return true;
}
Iterator GetIterator() const { return HashTable::GetIterator(); }
private:
void _Insert(ValueType **table, size_t tableSize, ValueType *value)
{
+110 -160
View File
@@ -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;
}