xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/multicast.h (revision 079c69cbfd7cd3c97baae91332251c8388a8bb02)
1 /*
2  * Copyright 2007, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *      Hugo Santos, hugosantos@gmail.com
7  */
8 #ifndef _PRIVATE_MULTICAST_H_
9 #define _PRIVATE_MULTICAST_H_
10 
11 
12 #include <util/DoublyLinkedList.h>
13 #include <util/OpenHashTable.h>
14 
15 #include <net_datalink.h>
16 
17 #include <netinet/in.h>
18 
19 #include <utility>
20 
21 
22 struct net_buffer;
23 struct net_protocol;
24 
25 // This code is template'ized as it is reusable for IPv6
26 
27 template<typename Addressing> class MulticastFilter;
28 template<typename Addressing> class MulticastGroupInterface;
29 
30 // TODO move this elsewhere...
31 struct IPv4Multicast {
32 	typedef struct in_addr AddressType;
33 	typedef struct ipv4_protocol ProtocolType;
34 	typedef MulticastGroupInterface<IPv4Multicast> GroupInterface;
35 
36 	static status_t JoinGroup(GroupInterface *);
37 	static status_t LeaveGroup(GroupInterface *);
38 
39 	static const in_addr &AddressFromSockAddr(const sockaddr *sockaddr)
40 		{ return ((const sockaddr_in *)sockaddr)->sin_addr; }
41 	static size_t HashAddress(const in_addr &address)
42 		{ return address.s_addr; }
43 };
44 
45 template<typename AddressType>
46 class AddressSet {
47 	struct ContainedAddress : DoublyLinkedListLinkImpl<ContainedAddress> {
48 		AddressType address;
49 	};
50 
51 	typedef DoublyLinkedList<ContainedAddress> AddressList;
52 
53 public:
54 	AddressSet()
55 		: fCount(0) {}
56 
57 	~AddressSet() { Clear(); }
58 
59 	status_t Add(const AddressType &address)
60 	{
61 		if (Has(address))
62 			return B_OK;
63 
64 		ContainedAddress *container = new ContainedAddress();
65 		if (container == NULL)
66 			return B_NO_MEMORY;
67 
68 		container->address = address;
69 		fAddresses.Add(container);
70 
71 		return B_OK;
72 	}
73 
74 	void Remove(const AddressType &address)
75 	{
76 		ContainedAddress *container = _Get(address);
77 		if (container == NULL)
78 			return;
79 
80 		fAddresses.Remove(container);
81 		delete container;
82 	}
83 
84 	bool Has(const AddressType &address) const
85 	{
86 		return _Get(address) != NULL;
87 	}
88 
89 	bool IsEmpty() const { return fAddresses.IsEmpty(); }
90 
91 	void Clear()
92 	{
93 		while (!fAddresses.IsEmpty())
94 			Remove(fAddresses.Head()->address);
95 	}
96 
97 	class Iterator {
98 	public:
99 		Iterator(const AddressList &addresses)
100 			: fBaseIterator(addresses.GetIterator()) {}
101 
102 		bool HasNext() const { return fBaseIterator.HasNext(); }
103 		AddressType &Next() { return fBaseIterator.Next()->address; }
104 
105 	private:
106 		typename AddressList::ConstIterator fBaseIterator;
107 	};
108 
109 	Iterator GetIterator() const { return Iterator(fAddresses); }
110 
111 private:
112 	ContainedAddress *_Get(const AddressType &address) const
113 	{
114 		typename AddressList::ConstIterator it = fAddresses.GetIterator();
115 		while (it.HasNext()) {
116 			ContainedAddress *container = it.Next();
117 			if (container->address == address)
118 				return container;
119 		}
120 		return NULL;
121 	}
122 
123 	AddressList fAddresses;
124 	int fCount;
125 };
126 
127 
128 template<typename Addressing>
129 class MulticastGroupInterface
130 	: public HashTableLink< MulticastGroupInterface<Addressing> > {
131 public:
132 	typedef MulticastGroupInterface<Addressing> ThisType;
133 	typedef HashTableLink<ThisType> HashLink;
134 	typedef typename Addressing::AddressType AddressType;
135 	typedef MulticastFilter<Addressing> Filter;
136 	typedef AddressSet<AddressType> AddressSet;
137 
138 	enum FilterMode {
139 		kInclude,
140 		kExclude
141 	};
142 
143 	MulticastGroupInterface(Filter *parent, const AddressType &address,
144 		net_interface *interface);
145 	~MulticastGroupInterface();
146 
147 	Filter *Parent() const { return fParent; }
148 
149 	const AddressType &Address() const { return fMulticastAddress; }
150 	net_interface *Interface() const { return fInterface; }
151 
152 	status_t Add();
153 	status_t Drop();
154 	status_t BlockSource(const AddressType &sourceAddress);
155 	status_t UnblockSource(const AddressType &sourceAddress);
156 	status_t AddSSM(const AddressType &sourceAddress);
157 	status_t DropSSM(const AddressType &sourceAddress);
158 
159 	bool IsEmpty() const;
160 	void Clear();
161 
162 	FilterMode Mode() const { return fFilterMode; }
163 	const AddressSet &Sources() const { return fAddresses; }
164 
165 	bool FilterAccepts(net_buffer *buffer) const;
166 
167 	struct HashDefinition {
168 		typedef std::pair<const AddressType *, uint32> KeyType;
169 		typedef ThisType ValueType;
170 
171 		size_t HashKey(const KeyType &key) const
172 			{ return Addressing::HashAddress(*key.first) ^ key.second; }
173 		size_t Hash(ValueType *value) const
174 			{ return HashKey(std::make_pair(&value->Address(),
175 				value->Interface()->index)); }
176 		bool Compare(const KeyType &key, ValueType *value) const
177 			{ return value->Interface()->index == key.second
178 				&& value->Address().s_addr == key.first->s_addr; }
179 		HashLink  *GetLink(ValueType *value) const { return &value->fLink; }
180 	};
181 
182 private:
183 	// for g++ 2.95
184 	friend class HashDefinition;
185 
186 	Filter *fParent;
187 	AddressType fMulticastAddress;
188 	net_interface *fInterface;
189 	FilterMode fFilterMode;
190 	AddressSet fAddresses;
191 	HashLink fLink;
192 };
193 
194 template<typename Addressing>
195 class MulticastFilter {
196 public:
197 	typedef typename Addressing::AddressType AddressType;
198 	typedef typename Addressing::ProtocolType ProtocolType;
199 	typedef MulticastGroupInterface<Addressing> GroupInterface;
200 
201 	MulticastFilter(ProtocolType *parent);
202 	~MulticastFilter();
203 
204 	ProtocolType *Socket() const { return fParent; }
205 
206 	status_t GetState(const AddressType &groupAddress,
207 		net_interface *interface, GroupInterface* &state, bool create);
208 	void ReturnState(GroupInterface *state);
209 
210 private:
211 	typedef typename GroupInterface::HashDefinition HashDefinition;
212 	typedef OpenHashTable<HashDefinition> States;
213 
214 	void _ReturnState(GroupInterface *state);
215 
216 	ProtocolType *fParent;
217 	States fStates;
218 };
219 
220 #endif
221