xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/multicast.h (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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:
131 	typedef MulticastGroupInterface<Addressing> ThisType;
132 	typedef typename Addressing::AddressType AddressType;
133 	typedef MulticastFilter<Addressing> Filter;
134 	typedef ::AddressSet<AddressType> AddressSet;
135 
136 	enum FilterMode {
137 		kInclude,
138 		kExclude
139 	};
140 
141 	MulticastGroupInterface(Filter *parent, const AddressType &address,
142 		net_interface *interface);
143 	~MulticastGroupInterface();
144 
145 	Filter *Parent() const { return fParent; }
146 
147 	const AddressType &Address() const { return fMulticastAddress; }
148 	net_interface *Interface() const { return fInterface; }
149 
150 	status_t Add();
151 	status_t Drop();
152 	status_t BlockSource(const AddressType &sourceAddress);
153 	status_t UnblockSource(const AddressType &sourceAddress);
154 	status_t AddSSM(const AddressType &sourceAddress);
155 	status_t DropSSM(const AddressType &sourceAddress);
156 
157 	bool IsEmpty() const;
158 	void Clear();
159 
160 	FilterMode Mode() const { return fFilterMode; }
161 	const AddressSet &Sources() const { return fAddresses; }
162 
163 	bool FilterAccepts(net_buffer *buffer) const;
164 
165 	struct HashDefinition {
166 		typedef std::pair<const AddressType *, uint32> KeyType;
167 		typedef ThisType ValueType;
168 
169 		size_t HashKey(const KeyType &key) const
170 			{ return Addressing::HashAddress(*key.first) ^ key.second; }
171 		size_t Hash(ValueType *value) const
172 			{ return HashKey(std::make_pair(&value->Address(),
173 				value->Interface()->index)); }
174 		bool Compare(const KeyType &key, ValueType *value) const
175 			{ return value->Interface()->index == key.second
176 				&& value->Address().s_addr == key.first->s_addr; }
177 		MulticastGroupInterface*& GetLink(ValueType *value) const
178 			{ return value->HashLink(); }
179 	};
180 
181 	MulticastGroupInterface*& HashLink() { return fLink; }
182 	MulticastGroupInterface*& MulticastGroupsHashLink() { return fMulticastGroupsLink; }
183 
184 private:
185 	// for g++ 2.95
186 	friend class HashDefinition;
187 
188 	Filter *fParent;
189 	AddressType fMulticastAddress;
190 	net_interface *fInterface;
191 	FilterMode fFilterMode;
192 	AddressSet fAddresses;
193 	MulticastGroupInterface* fLink;
194 	MulticastGroupInterface* fMulticastGroupsLink;
195 };
196 
197 template<typename Addressing>
198 class MulticastFilter {
199 public:
200 	typedef typename Addressing::AddressType AddressType;
201 	typedef typename Addressing::ProtocolType ProtocolType;
202 	typedef MulticastGroupInterface<Addressing> GroupInterface;
203 
204 	MulticastFilter(ProtocolType *parent);
205 	~MulticastFilter();
206 
207 	ProtocolType *Socket() const { return fParent; }
208 
209 	status_t GetState(const AddressType &groupAddress,
210 		net_interface *interface, GroupInterface* &state, bool create);
211 	void ReturnState(GroupInterface *state);
212 
213 private:
214 	typedef typename GroupInterface::HashDefinition HashDefinition;
215 	typedef BOpenHashTable<HashDefinition> States;
216 
217 	void _ReturnState(GroupInterface *state);
218 
219 	ProtocolType *fParent;
220 	States fStates;
221 };
222 
223 #endif
224