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 946527f68SHugo Santos #ifndef _PRIVATE_MULTICAST_H_ 1046527f68SHugo Santos #define _PRIVATE_MULTICAST_H_ 1146527f68SHugo Santos 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 216a606180SHugo Santos struct net_buffer; 226a606180SHugo Santos struct net_protocol; 236a606180SHugo Santos 246a606180SHugo Santos // This code is template'ized as it is reusable for IPv6 256a606180SHugo Santos 266a606180SHugo Santos template<typename Addressing> class MulticastFilter; 278aa4c7e3SHugo Santos template<typename Addressing> class MulticastGroupInterface; 286a606180SHugo Santos 296a606180SHugo Santos // TODO move this elsewhere... 306a606180SHugo Santos struct IPv4Multicast { 316a606180SHugo Santos typedef struct in_addr AddressType; 320e30c21cSHugo Santos typedef struct ipv4_protocol ProtocolType; 338aa4c7e3SHugo Santos typedef MulticastGroupInterface<IPv4Multicast> GroupInterface; 346a606180SHugo Santos 358aa4c7e3SHugo Santos static status_t JoinGroup(GroupInterface *); 368aa4c7e3SHugo Santos static status_t LeaveGroup(GroupInterface *); 376a606180SHugo Santos 380e30c21cSHugo Santos static const in_addr &AddressFromSockAddr(const sockaddr *sockaddr) 390e30c21cSHugo Santos { return ((const sockaddr_in *)sockaddr)->sin_addr; } 400e30c21cSHugo Santos static size_t HashAddress(const in_addr &address) 410e30c21cSHugo Santos { return address.s_addr; } 426a606180SHugo Santos }; 4346527f68SHugo Santos 4446527f68SHugo Santos template<typename AddressType> 458aa4c7e3SHugo Santos class AddressSet { 468aa4c7e3SHugo Santos public: 478aa4c7e3SHugo Santos struct ContainedAddress : DoublyLinkedListLinkImpl<ContainedAddress> { 4846527f68SHugo Santos AddressType address; 4946527f68SHugo Santos }; 5046527f68SHugo Santos 518aa4c7e3SHugo Santos ~AddressSet() { Clear(); } 5246527f68SHugo Santos 538aa4c7e3SHugo Santos status_t Add(const AddressType &address) 548aa4c7e3SHugo Santos { 558aa4c7e3SHugo Santos if (Has(address)) 568aa4c7e3SHugo Santos return B_OK; 5746527f68SHugo Santos 588aa4c7e3SHugo Santos ContainedAddress *container = new ContainedAddress(); 598aa4c7e3SHugo Santos if (container == NULL) 608aa4c7e3SHugo Santos return B_NO_MEMORY; 6146527f68SHugo Santos 628aa4c7e3SHugo Santos container->address = address; 638aa4c7e3SHugo Santos fAddresses.Add(container); 648aa4c7e3SHugo Santos 658aa4c7e3SHugo Santos return B_OK; 668aa4c7e3SHugo Santos } 678aa4c7e3SHugo Santos 688aa4c7e3SHugo Santos void Remove(const AddressType &address) 698aa4c7e3SHugo Santos { 708aa4c7e3SHugo Santos ContainedAddress *container = _Get(address); 718aa4c7e3SHugo Santos if (container == NULL) 728aa4c7e3SHugo Santos return; 738aa4c7e3SHugo Santos 748aa4c7e3SHugo Santos fAddresses.Remove(container); 758aa4c7e3SHugo Santos delete container; 768aa4c7e3SHugo Santos } 778aa4c7e3SHugo Santos 788aa4c7e3SHugo Santos bool Has(const AddressType &address) const 798aa4c7e3SHugo Santos { 808aa4c7e3SHugo Santos return _Get(address) != NULL; 818aa4c7e3SHugo Santos } 828aa4c7e3SHugo Santos 838aa4c7e3SHugo Santos bool IsEmpty() const { return fAddresses.IsEmpty(); } 848aa4c7e3SHugo Santos 858aa4c7e3SHugo Santos void Clear() 868aa4c7e3SHugo Santos { 878aa4c7e3SHugo Santos while (!fAddresses.IsEmpty()) 888aa4c7e3SHugo Santos Remove(fAddresses.Head()->address); 898aa4c7e3SHugo Santos } 906a606180SHugo Santos 9146527f68SHugo Santos private: 928aa4c7e3SHugo Santos typedef DoublyLinkedList<ContainedAddress> AddressList; 9346527f68SHugo Santos 948aa4c7e3SHugo Santos ContainedAddress *_Get(const AddressType &address) const 958aa4c7e3SHugo Santos { 96*8465a069SHugo Santos typename AddressList::ConstIterator it = fAddresses.GetIterator(); 978aa4c7e3SHugo Santos while (it.HasNext()) { 988aa4c7e3SHugo Santos ContainedAddress *container = it.Next(); 998aa4c7e3SHugo Santos if (container->address == address) 1008aa4c7e3SHugo Santos return container; 1018aa4c7e3SHugo Santos } 1028aa4c7e3SHugo Santos return NULL; 1038aa4c7e3SHugo Santos } 10446527f68SHugo Santos 1058aa4c7e3SHugo Santos AddressList fAddresses; 10646527f68SHugo Santos }; 10746527f68SHugo Santos 1088aa4c7e3SHugo Santos 1096a606180SHugo Santos template<typename Addressing> 1108aa4c7e3SHugo Santos class MulticastGroupInterface 1118aa4c7e3SHugo Santos : public HashTableLink< MulticastGroupInterface<Addressing> > { 11246527f68SHugo Santos public: 1138aa4c7e3SHugo Santos typedef MulticastGroupInterface<Addressing> ThisType; 1140e30c21cSHugo Santos typedef HashTableLink<ThisType> HashLink; 1156a606180SHugo Santos typedef typename Addressing::AddressType AddressType; 1168aa4c7e3SHugo Santos typedef MulticastFilter<Addressing> Filter; 11746527f68SHugo Santos 11846527f68SHugo Santos enum FilterMode { 11946527f68SHugo Santos kInclude, 12046527f68SHugo Santos kExclude 12146527f68SHugo Santos }; 12246527f68SHugo Santos 1238aa4c7e3SHugo Santos MulticastGroupInterface(Filter *parent, const AddressType &address, 1248aa4c7e3SHugo Santos net_interface *interface); 1258aa4c7e3SHugo Santos ~MulticastGroupInterface(); 1268aa4c7e3SHugo Santos 1278aa4c7e3SHugo Santos Filter *Parent() const { return fParent; } 1288aa4c7e3SHugo Santos 1298aa4c7e3SHugo Santos const AddressType &Address() const { return fMulticastAddress; } 1308aa4c7e3SHugo Santos net_interface *Interface() const { return fInterface; } 1318aa4c7e3SHugo Santos 1328aa4c7e3SHugo Santos status_t Add(); 1338aa4c7e3SHugo Santos status_t Drop(); 1348aa4c7e3SHugo Santos status_t BlockSource(const AddressType &sourceAddress); 1358aa4c7e3SHugo Santos status_t UnblockSource(const AddressType &sourceAddress); 1368aa4c7e3SHugo Santos status_t AddSSM(const AddressType &sourceAddress); 1378aa4c7e3SHugo Santos status_t DropSSM(const AddressType &sourceAddress); 1388aa4c7e3SHugo Santos 1398aa4c7e3SHugo Santos bool IsEmpty() const; 1408aa4c7e3SHugo Santos void Clear(); 1418aa4c7e3SHugo Santos 1428aa4c7e3SHugo Santos bool FilterAccepts(net_buffer *buffer) const; 1438aa4c7e3SHugo Santos 1448aa4c7e3SHugo Santos struct HashDefinition { 1458aa4c7e3SHugo Santos typedef void ParentType; 1468aa4c7e3SHugo Santos typedef std::pair<const AddressType *, uint32> KeyType; 1478aa4c7e3SHugo Santos typedef ThisType ValueType; 1488aa4c7e3SHugo Santos 1498aa4c7e3SHugo Santos size_t HashKey(const KeyType &key) const 1508aa4c7e3SHugo Santos { return Addressing::HashAddress(*key.first) ^ key.second; } 1518aa4c7e3SHugo Santos size_t Hash(ValueType *value) const 1528aa4c7e3SHugo Santos { return HashKey(std::make_pair(&value->Address(), 1538aa4c7e3SHugo Santos value->Interface()->index)); } 1548aa4c7e3SHugo Santos bool Compare(const KeyType &key, ValueType *value) const 1558aa4c7e3SHugo Santos { return value->Interface()->index == key.second 1568aa4c7e3SHugo Santos && value->Address().s_addr == key.first->s_addr; } 1578aa4c7e3SHugo Santos HashLink *GetLink(ValueType *value) const { return &value->fLink; } 1588aa4c7e3SHugo Santos }; 1598aa4c7e3SHugo Santos 1608aa4c7e3SHugo Santos private: 1618aa4c7e3SHugo Santos // for g++ 2.95 1628aa4c7e3SHugo Santos friend class HashDefinition; 1638aa4c7e3SHugo Santos 1648aa4c7e3SHugo Santos Filter *fParent; 16546527f68SHugo Santos AddressType fMulticastAddress; 1668aa4c7e3SHugo Santos net_interface *fInterface; 16746527f68SHugo Santos FilterMode fFilterMode; 1688aa4c7e3SHugo Santos AddressSet<AddressType> fAddresses; 1698aa4c7e3SHugo Santos HashLink fLink; 17046527f68SHugo Santos }; 17146527f68SHugo Santos 1726a606180SHugo Santos template<typename Addressing> 17346527f68SHugo Santos class MulticastFilter { 17446527f68SHugo Santos public: 1756a606180SHugo Santos typedef typename Addressing::AddressType AddressType; 1760e30c21cSHugo Santos typedef typename Addressing::ProtocolType ProtocolType; 1778aa4c7e3SHugo Santos typedef MulticastGroupInterface<Addressing> GroupInterface; 17846527f68SHugo Santos 1790e30c21cSHugo Santos MulticastFilter(ProtocolType *parent); 18046527f68SHugo Santos ~MulticastFilter(); 18146527f68SHugo Santos 1828aa4c7e3SHugo Santos ProtocolType *Socket() const { return fParent; } 1836c501a40SHugo Santos 1848aa4c7e3SHugo Santos status_t GetState(const AddressType &groupAddress, 1858aa4c7e3SHugo Santos net_interface *interface, GroupInterface* &state, bool create); 1868aa4c7e3SHugo Santos void ReturnState(GroupInterface *state); 18746527f68SHugo Santos 18846527f68SHugo Santos private: 1898aa4c7e3SHugo Santos typedef typename GroupInterface::HashDefinition HashDefinition; 1908aa4c7e3SHugo Santos typedef OpenHashTable<HashDefinition> States; 19146527f68SHugo Santos 1928aa4c7e3SHugo Santos void _ReturnState(GroupInterface *state); 19357967505SHugo Santos 1940e30c21cSHugo Santos ProtocolType *fParent; 19546527f68SHugo Santos States fStates; 19646527f68SHugo Santos }; 19746527f68SHugo Santos 19846527f68SHugo Santos #endif 199