xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/multicast.h (revision 815212800210a100d07c2c3d8dfea18360426319)
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