146527f68SHugo Santos /* 246527f68SHugo Santos * Copyright 2007, Haiku, Inc. All Rights Reserved. 346527f68SHugo Santos * Distributed under the terms of the MIT License. 446527f68SHugo Santos * 546527f68SHugo Santos * Authors: 646527f68SHugo Santos * Hugo Santos, hugosantos@gmail.com 746527f68SHugo Santos */ 846527f68SHugo Santos #ifndef _PRIVATE_MULTICAST_H_ 946527f68SHugo Santos #define _PRIVATE_MULTICAST_H_ 1046527f68SHugo Santos 1184052230SAxel Dörfler 1246527f68SHugo Santos #include <util/DoublyLinkedList.h> 130e30c21cSHugo Santos #include <util/OpenHashTable.h> 1446527f68SHugo Santos 158aa4c7e3SHugo Santos #include <net_datalink.h> 168aa4c7e3SHugo Santos 176a606180SHugo Santos #include <netinet/in.h> 186c501a40SHugo Santos 198aa4c7e3SHugo Santos #include <utility> 208aa4c7e3SHugo Santos 2184052230SAxel Dörfler 226a606180SHugo Santos struct net_buffer; 236a606180SHugo Santos struct net_protocol; 246a606180SHugo Santos 256a606180SHugo Santos // This code is template'ized as it is reusable for IPv6 266a606180SHugo Santos 276a606180SHugo Santos template<typename Addressing> class MulticastFilter; 288aa4c7e3SHugo Santos template<typename Addressing> class MulticastGroupInterface; 296a606180SHugo Santos 306a606180SHugo Santos // TODO move this elsewhere... 316a606180SHugo Santos struct IPv4Multicast { 326a606180SHugo Santos typedef struct in_addr AddressType; 330e30c21cSHugo Santos typedef struct ipv4_protocol ProtocolType; 348aa4c7e3SHugo Santos typedef MulticastGroupInterface<IPv4Multicast> GroupInterface; 356a606180SHugo Santos 368aa4c7e3SHugo Santos static status_t JoinGroup(GroupInterface *); 378aa4c7e3SHugo Santos static status_t LeaveGroup(GroupInterface *); 386a606180SHugo Santos AddressFromSockAddrIPv4Multicast390e30c21cSHugo Santos static const in_addr &AddressFromSockAddr(const sockaddr *sockaddr) 400e30c21cSHugo Santos { return ((const sockaddr_in *)sockaddr)->sin_addr; } HashAddressIPv4Multicast410e30c21cSHugo Santos static size_t HashAddress(const in_addr &address) 420e30c21cSHugo Santos { return address.s_addr; } 436a606180SHugo Santos }; 4446527f68SHugo Santos 4546527f68SHugo Santos template<typename AddressType> 468aa4c7e3SHugo Santos class AddressSet { 478aa4c7e3SHugo Santos struct ContainedAddress : DoublyLinkedListLinkImpl<ContainedAddress> { 4846527f68SHugo Santos AddressType address; 4946527f68SHugo Santos }; 5046527f68SHugo Santos 51ab7e05a3SHugo Santos typedef DoublyLinkedList<ContainedAddress> AddressList; 52ab7e05a3SHugo Santos 53ab7e05a3SHugo Santos public: AddressSet()54ab7e05a3SHugo Santos AddressSet() 55ab7e05a3SHugo Santos : fCount(0) {} 56ab7e05a3SHugo Santos ~AddressSet()578aa4c7e3SHugo Santos ~AddressSet() { Clear(); } 5846527f68SHugo Santos Add(const AddressType & address)598aa4c7e3SHugo Santos status_t Add(const AddressType &address) 608aa4c7e3SHugo Santos { 618aa4c7e3SHugo Santos if (Has(address)) 628aa4c7e3SHugo Santos return B_OK; 6346527f68SHugo Santos 648aa4c7e3SHugo Santos ContainedAddress *container = new ContainedAddress(); 658aa4c7e3SHugo Santos if (container == NULL) 668aa4c7e3SHugo Santos return B_NO_MEMORY; 6746527f68SHugo Santos 688aa4c7e3SHugo Santos container->address = address; 698aa4c7e3SHugo Santos fAddresses.Add(container); 708aa4c7e3SHugo Santos 718aa4c7e3SHugo Santos return B_OK; 728aa4c7e3SHugo Santos } 738aa4c7e3SHugo Santos Remove(const AddressType & address)748aa4c7e3SHugo Santos void Remove(const AddressType &address) 758aa4c7e3SHugo Santos { 768aa4c7e3SHugo Santos ContainedAddress *container = _Get(address); 778aa4c7e3SHugo Santos if (container == NULL) 788aa4c7e3SHugo Santos return; 798aa4c7e3SHugo Santos 808aa4c7e3SHugo Santos fAddresses.Remove(container); 818aa4c7e3SHugo Santos delete container; 828aa4c7e3SHugo Santos } 838aa4c7e3SHugo Santos Has(const AddressType & address)848aa4c7e3SHugo Santos bool Has(const AddressType &address) const 858aa4c7e3SHugo Santos { 868aa4c7e3SHugo Santos return _Get(address) != NULL; 878aa4c7e3SHugo Santos } 888aa4c7e3SHugo Santos IsEmpty()898aa4c7e3SHugo Santos bool IsEmpty() const { return fAddresses.IsEmpty(); } 908aa4c7e3SHugo Santos Clear()918aa4c7e3SHugo Santos void Clear() 928aa4c7e3SHugo Santos { 938aa4c7e3SHugo Santos while (!fAddresses.IsEmpty()) 948aa4c7e3SHugo Santos Remove(fAddresses.Head()->address); 958aa4c7e3SHugo Santos } 966a606180SHugo Santos 97ab7e05a3SHugo Santos class Iterator { 98ab7e05a3SHugo Santos public: Iterator(const AddressList & addresses)99ab7e05a3SHugo Santos Iterator(const AddressList &addresses) 100ab7e05a3SHugo Santos : fBaseIterator(addresses.GetIterator()) {} 10146527f68SHugo Santos HasNext()102ab7e05a3SHugo Santos bool HasNext() const { return fBaseIterator.HasNext(); } Next()103ab7e05a3SHugo Santos AddressType &Next() { return fBaseIterator.Next()->address; } 104ab7e05a3SHugo Santos 105ab7e05a3SHugo Santos private: 106ab7e05a3SHugo Santos typename AddressList::ConstIterator fBaseIterator; 107ab7e05a3SHugo Santos }; 108ab7e05a3SHugo Santos GetIterator()109ab7e05a3SHugo Santos Iterator GetIterator() const { return Iterator(fAddresses); } 110ab7e05a3SHugo Santos 111ab7e05a3SHugo Santos private: _Get(const AddressType & address)1128aa4c7e3SHugo Santos ContainedAddress *_Get(const AddressType &address) const 1138aa4c7e3SHugo Santos { 1148465a069SHugo Santos typename AddressList::ConstIterator it = fAddresses.GetIterator(); 1158aa4c7e3SHugo Santos while (it.HasNext()) { 1168aa4c7e3SHugo Santos ContainedAddress *container = it.Next(); 1178aa4c7e3SHugo Santos if (container->address == address) 1188aa4c7e3SHugo Santos return container; 1198aa4c7e3SHugo Santos } 1208aa4c7e3SHugo Santos return NULL; 1218aa4c7e3SHugo Santos } 12246527f68SHugo Santos 1238aa4c7e3SHugo Santos AddressList fAddresses; 124ab7e05a3SHugo Santos int fCount; 12546527f68SHugo Santos }; 12646527f68SHugo Santos 1278aa4c7e3SHugo Santos 1286a606180SHugo Santos template<typename Addressing> 1295147963dSStephan Aßmus class MulticastGroupInterface { 13046527f68SHugo Santos public: 1318aa4c7e3SHugo Santos typedef MulticastGroupInterface<Addressing> ThisType; 1326a606180SHugo Santos typedef typename Addressing::AddressType AddressType; 1338aa4c7e3SHugo Santos typedef MulticastFilter<Addressing> Filter; 134fb3e35fcSMichael Lotz typedef ::AddressSet<AddressType> AddressSet; 13546527f68SHugo Santos 13646527f68SHugo Santos enum FilterMode { 13746527f68SHugo Santos kInclude, 13846527f68SHugo Santos kExclude 13946527f68SHugo Santos }; 14046527f68SHugo Santos 1418aa4c7e3SHugo Santos MulticastGroupInterface(Filter *parent, const AddressType &address, 1428aa4c7e3SHugo Santos net_interface *interface); 1438aa4c7e3SHugo Santos ~MulticastGroupInterface(); 1448aa4c7e3SHugo Santos Parent()1458aa4c7e3SHugo Santos Filter *Parent() const { return fParent; } 1468aa4c7e3SHugo Santos Address()1478aa4c7e3SHugo Santos const AddressType &Address() const { return fMulticastAddress; } Interface()1488aa4c7e3SHugo Santos net_interface *Interface() const { return fInterface; } 1498aa4c7e3SHugo Santos 1508aa4c7e3SHugo Santos status_t Add(); 1518aa4c7e3SHugo Santos status_t Drop(); 1528aa4c7e3SHugo Santos status_t BlockSource(const AddressType &sourceAddress); 1538aa4c7e3SHugo Santos status_t UnblockSource(const AddressType &sourceAddress); 1548aa4c7e3SHugo Santos status_t AddSSM(const AddressType &sourceAddress); 1558aa4c7e3SHugo Santos status_t DropSSM(const AddressType &sourceAddress); 1568aa4c7e3SHugo Santos 1578aa4c7e3SHugo Santos bool IsEmpty() const; 1588aa4c7e3SHugo Santos void Clear(); 1598aa4c7e3SHugo Santos Mode()160ab7e05a3SHugo Santos FilterMode Mode() const { return fFilterMode; } Sources()161ab7e05a3SHugo Santos const AddressSet &Sources() const { return fAddresses; } 162ab7e05a3SHugo Santos 1638aa4c7e3SHugo Santos bool FilterAccepts(net_buffer *buffer) const; 1648aa4c7e3SHugo Santos 1658aa4c7e3SHugo Santos struct HashDefinition { 1668aa4c7e3SHugo Santos typedef std::pair<const AddressType *, uint32> KeyType; 1678aa4c7e3SHugo Santos typedef ThisType ValueType; 1688aa4c7e3SHugo Santos HashKeyHashDefinition1698aa4c7e3SHugo Santos size_t HashKey(const KeyType &key) const 1708aa4c7e3SHugo Santos { return Addressing::HashAddress(*key.first) ^ key.second; } HashHashDefinition1718aa4c7e3SHugo Santos size_t Hash(ValueType *value) const 1728aa4c7e3SHugo Santos { return HashKey(std::make_pair(&value->Address(), 1738aa4c7e3SHugo Santos value->Interface()->index)); } CompareHashDefinition1748aa4c7e3SHugo Santos bool Compare(const KeyType &key, ValueType *value) const 1758aa4c7e3SHugo Santos { return value->Interface()->index == key.second 1768aa4c7e3SHugo Santos && value->Address().s_addr == key.first->s_addr; } GetLinkHashDefinition1775147963dSStephan Aßmus MulticastGroupInterface*& GetLink(ValueType *value) const 1785147963dSStephan Aßmus { return value->HashLink(); } 1798aa4c7e3SHugo Santos }; 1808aa4c7e3SHugo Santos HashLink()1815147963dSStephan Aßmus MulticastGroupInterface*& HashLink() { return fLink; } MulticastGroupsHashLink()18219d8e4f7SAlexander Andreev MulticastGroupInterface*& MulticastGroupsHashLink() { return fMulticastGroupsLink; } 1835147963dSStephan Aßmus 1848aa4c7e3SHugo Santos private: 1858aa4c7e3SHugo Santos // for g++ 2.95 186*81521280SX512 friend struct HashDefinition; 1878aa4c7e3SHugo Santos 1888aa4c7e3SHugo Santos Filter *fParent; 18946527f68SHugo Santos AddressType fMulticastAddress; 1908aa4c7e3SHugo Santos net_interface *fInterface; 19146527f68SHugo Santos FilterMode fFilterMode; 192ab7e05a3SHugo Santos AddressSet fAddresses; 1935147963dSStephan Aßmus MulticastGroupInterface* fLink; 19419d8e4f7SAlexander Andreev MulticastGroupInterface* fMulticastGroupsLink; 19546527f68SHugo Santos }; 19646527f68SHugo Santos 1976a606180SHugo Santos template<typename Addressing> 19846527f68SHugo Santos class MulticastFilter { 19946527f68SHugo Santos public: 2006a606180SHugo Santos typedef typename Addressing::AddressType AddressType; 2010e30c21cSHugo Santos typedef typename Addressing::ProtocolType ProtocolType; 2028aa4c7e3SHugo Santos typedef MulticastGroupInterface<Addressing> GroupInterface; 20346527f68SHugo Santos 2040e30c21cSHugo Santos MulticastFilter(ProtocolType *parent); 20546527f68SHugo Santos ~MulticastFilter(); 20646527f68SHugo Santos Socket()2078aa4c7e3SHugo Santos ProtocolType *Socket() const { return fParent; } 2086c501a40SHugo Santos 2098aa4c7e3SHugo Santos status_t GetState(const AddressType &groupAddress, 2108aa4c7e3SHugo Santos net_interface *interface, GroupInterface* &state, bool create); 2118aa4c7e3SHugo Santos void ReturnState(GroupInterface *state); 21246527f68SHugo Santos 21346527f68SHugo Santos private: 2148aa4c7e3SHugo Santos typedef typename GroupInterface::HashDefinition HashDefinition; 2155147963dSStephan Aßmus typedef BOpenHashTable<HashDefinition> States; 21646527f68SHugo Santos 2178aa4c7e3SHugo Santos void _ReturnState(GroupInterface *state); 21857967505SHugo Santos 2190e30c21cSHugo Santos ProtocolType *fParent; 22046527f68SHugo Santos States fStates; 22146527f68SHugo Santos }; 22246527f68SHugo Santos 22346527f68SHugo Santos #endif 224