A Discrete-Event Network Simulator
API
ipv4-end-point-demux.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005 INRIA
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18  */
19 
20 #include "ipv4-end-point-demux.h"
21 
22 #include "ipv4-end-point.h"
23 #include "ipv4-interface-address.h"
24 
25 #include "ns3/log.h"
26 
27 namespace ns3
28 {
29 
30 NS_LOG_COMPONENT_DEFINE("Ipv4EndPointDemux");
31 
33  : m_ephemeral(49152),
34  m_portLast(65535),
35  m_portFirst(49152)
36 {
37  NS_LOG_FUNCTION(this);
38 }
39 
41 {
42  NS_LOG_FUNCTION(this);
43  for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
44  {
45  Ipv4EndPoint* endPoint = *i;
46  delete endPoint;
47  }
48  m_endPoints.clear();
49 }
50 
51 bool
53 {
54  NS_LOG_FUNCTION(this << port);
55  for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
56  {
57  if ((*i)->GetLocalPort() == port)
58  {
59  return true;
60  }
61  }
62  return false;
63 }
64 
65 bool
67 {
68  NS_LOG_FUNCTION(this << addr << port);
69  for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
70  {
71  if ((*i)->GetLocalPort() == port && (*i)->GetLocalAddress() == addr &&
72  (*i)->GetBoundNetDevice() == boundNetDevice)
73  {
74  return true;
75  }
76  }
77  return false;
78 }
79 
82 {
83  NS_LOG_FUNCTION(this);
84  uint16_t port = AllocateEphemeralPort();
85  if (port == 0)
86  {
87  NS_LOG_WARN("Ephemeral port allocation failed.");
88  return nullptr;
89  }
90  auto endPoint = new Ipv4EndPoint(Ipv4Address::GetAny(), port);
91  m_endPoints.push_back(endPoint);
92  NS_LOG_DEBUG("Now have >>" << m_endPoints.size() << "<< endpoints.");
93  return endPoint;
94 }
95 
98 {
99  NS_LOG_FUNCTION(this << address);
100  uint16_t port = AllocateEphemeralPort();
101  if (port == 0)
102  {
103  NS_LOG_WARN("Ephemeral port allocation failed.");
104  return nullptr;
105  }
106  auto endPoint = new Ipv4EndPoint(address, port);
107  m_endPoints.push_back(endPoint);
108  NS_LOG_DEBUG("Now have >>" << m_endPoints.size() << "<< endpoints.");
109  return endPoint;
110 }
111 
114 {
115  NS_LOG_FUNCTION(this << port << boundNetDevice);
116 
117  return Allocate(boundNetDevice, Ipv4Address::GetAny(), port);
118 }
119 
122 {
123  NS_LOG_FUNCTION(this << address << port << boundNetDevice);
124  if (LookupLocal(boundNetDevice, address, port) || LookupLocal(nullptr, address, port))
125  {
126  NS_LOG_WARN("Duplicated endpoint.");
127  return nullptr;
128  }
129  auto endPoint = new Ipv4EndPoint(address, port);
130  m_endPoints.push_back(endPoint);
131  NS_LOG_DEBUG("Now have >>" << m_endPoints.size() << "<< endpoints.");
132  return endPoint;
133 }
134 
137  Ipv4Address localAddress,
138  uint16_t localPort,
139  Ipv4Address peerAddress,
140  uint16_t peerPort)
141 {
142  NS_LOG_FUNCTION(this << localAddress << localPort << peerAddress << peerPort << boundNetDevice);
143  for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
144  {
145  if ((*i)->GetLocalPort() == localPort && (*i)->GetLocalAddress() == localAddress &&
146  (*i)->GetPeerPort() == peerPort && (*i)->GetPeerAddress() == peerAddress &&
147  ((*i)->GetBoundNetDevice() == boundNetDevice || !(*i)->GetBoundNetDevice()))
148  {
149  NS_LOG_WARN("Duplicated endpoint.");
150  return nullptr;
151  }
152  }
153  auto endPoint = new Ipv4EndPoint(localAddress, localPort);
154  endPoint->SetPeer(peerAddress, peerPort);
155  m_endPoints.push_back(endPoint);
156 
157  NS_LOG_DEBUG("Now have >>" << m_endPoints.size() << "<< endpoints.");
158 
159  return endPoint;
160 }
161 
162 void
164 {
165  NS_LOG_FUNCTION(this << endPoint);
166  for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
167  {
168  if (*i == endPoint)
169  {
170  delete endPoint;
171  m_endPoints.erase(i);
172  break;
173  }
174  }
175 }
176 
177 /*
178  * return list of all available Endpoints
179  */
182 {
183  NS_LOG_FUNCTION(this);
184  EndPoints ret;
185 
186  for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
187  {
188  Ipv4EndPoint* endP = *i;
189  ret.push_back(endP);
190  }
191  return ret;
192 }
193 
194 /*
195  * If we have an exact match, we return it.
196  * Otherwise, if we find a generic match, we return it.
197  * Otherwise, we return 0.
198  */
201  uint16_t dport,
202  Ipv4Address saddr,
203  uint16_t sport,
204  Ptr<Ipv4Interface> incomingInterface)
205 {
206  NS_LOG_FUNCTION(this << daddr << dport << saddr << sport << incomingInterface);
207 
208  EndPoints retval1; // Matches exact on local port, wildcards on others
209  EndPoints retval2; // Matches exact on local port/adder, wildcards on others
210  EndPoints retval3; // Matches all but local address
211  EndPoints retval4; // Exact match on all 4
212 
213  NS_LOG_DEBUG("Looking up endpoint for destination address " << daddr << ":" << dport);
214  for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
215  {
216  Ipv4EndPoint* endP = *i;
217 
218  NS_LOG_DEBUG("Looking at endpoint dport="
219  << endP->GetLocalPort() << " daddr=" << endP->GetLocalAddress()
220  << " sport=" << endP->GetPeerPort() << " saddr=" << endP->GetPeerAddress());
221 
222  if (!endP->IsRxEnabled())
223  {
224  NS_LOG_LOGIC("Skipping endpoint " << &endP
225  << " because endpoint can not receive packets");
226  continue;
227  }
228 
229  if (endP->GetLocalPort() != dport)
230  {
231  NS_LOG_LOGIC("Skipping endpoint " << &endP << " because endpoint dport "
232  << endP->GetLocalPort()
233  << " does not match packet dport " << dport);
234  continue;
235  }
236  if (endP->GetBoundNetDevice())
237  {
238  if (endP->GetBoundNetDevice() != incomingInterface->GetDevice())
239  {
240  NS_LOG_LOGIC("Skipping endpoint "
241  << &endP << " because endpoint is bound to specific device and"
242  << endP->GetBoundNetDevice() << " does not match packet device "
243  << incomingInterface->GetDevice());
244  continue;
245  }
246  }
247 
248  bool localAddressMatchesExact = false;
249  bool localAddressIsAny = false;
250  bool localAddressIsSubnetAny = false;
251 
252  // We have 3 cases:
253  // 1) Exact local / destination address match
254  // 2) Local endpoint bound to Any -> matches anything
255  // 3) Local endpoint bound to x.y.z.0 -> matches Subnet-directed broadcast packet (e.g.,
256  // x.y.z.255 in a /24 net) and direct destination match.
257 
258  if (endP->GetLocalAddress() == daddr)
259  {
260  // Case 1:
261  localAddressMatchesExact = true;
262  }
263  else if (endP->GetLocalAddress() == Ipv4Address::GetAny())
264  {
265  // Case 2:
266  localAddressIsAny = true;
267  }
268  else
269  {
270  // Case 3:
271  for (uint32_t i = 0; i < incomingInterface->GetNAddresses(); i++)
272  {
273  Ipv4InterfaceAddress addr = incomingInterface->GetAddress(i);
274 
275  Ipv4Address addrNetpart = addr.GetLocal().CombineMask(addr.GetMask());
276  if (endP->GetLocalAddress() == addrNetpart)
277  {
278  NS_LOG_LOGIC("Endpoint is SubnetDirectedAny "
279  << endP->GetLocalAddress() << "/"
280  << addr.GetMask().GetPrefixLength());
281 
282  Ipv4Address daddrNetPart = daddr.CombineMask(addr.GetMask());
283  if (addrNetpart == daddrNetPart)
284  {
285  localAddressIsSubnetAny = true;
286  }
287  }
288  }
289 
290  // if no match here, keep looking
291  if (!localAddressIsSubnetAny)
292  {
293  continue;
294  }
295  }
296 
297  bool remotePortMatchesExact = endP->GetPeerPort() == sport;
298  bool remotePortMatchesWildCard = endP->GetPeerPort() == 0;
299  bool remoteAddressMatchesExact = endP->GetPeerAddress() == saddr;
300  bool remoteAddressMatchesWildCard = endP->GetPeerAddress() == Ipv4Address::GetAny();
301 
302  // If remote does not match either with exact or wildcard,
303  // skip this one
304  if (!(remotePortMatchesExact || remotePortMatchesWildCard))
305  {
306  continue;
307  }
308  if (!(remoteAddressMatchesExact || remoteAddressMatchesWildCard))
309  {
310  continue;
311  }
312 
313  bool localAddressMatchesWildCard = localAddressIsAny || localAddressIsSubnetAny;
314 
315  if (localAddressMatchesExact && remoteAddressMatchesExact && remotePortMatchesExact)
316  { // All 4 match - this is the case of an open TCP connection, for example.
317  NS_LOG_LOGIC("Found an endpoint for case 4, adding " << endP->GetLocalAddress() << ":"
318  << endP->GetLocalPort());
319  retval4.push_back(endP);
320  }
321  if (localAddressMatchesWildCard && remoteAddressMatchesExact && remotePortMatchesExact)
322  { // All but local address - no idea what this case could be.
323  NS_LOG_LOGIC("Found an endpoint for case 3, adding " << endP->GetLocalAddress() << ":"
324  << endP->GetLocalPort());
325  retval3.push_back(endP);
326  }
327  if (localAddressMatchesExact && remoteAddressMatchesWildCard && remotePortMatchesWildCard)
328  { // Only local port and local address matches exactly - Not yet opened connection
329  NS_LOG_LOGIC("Found an endpoint for case 2, adding " << endP->GetLocalAddress() << ":"
330  << endP->GetLocalPort());
331  retval2.push_back(endP);
332  }
333  if (localAddressMatchesWildCard && remoteAddressMatchesWildCard &&
334  remotePortMatchesWildCard)
335  { // Only local port matches exactly - Endpoint open to "any" connection
336  NS_LOG_LOGIC("Found an endpoint for case 1, adding " << endP->GetLocalAddress() << ":"
337  << endP->GetLocalPort());
338  retval1.push_back(endP);
339  }
340  }
341 
342  // Here we find the most exact match
343  EndPoints retval;
344  if (!retval4.empty())
345  {
346  retval = retval4;
347  }
348  else if (!retval3.empty())
349  {
350  retval = retval3;
351  }
352  else if (!retval2.empty())
353  {
354  retval = retval2;
355  }
356  else
357  {
358  retval = retval1;
359  }
360 
361  NS_ABORT_MSG_IF(retval.size() > 1,
362  "Too many endpoints - perhaps you created too many sockets without binding "
363  "them to different NetDevices.");
364  return retval; // might be empty if no matches
365 }
366 
369  uint16_t dport,
370  Ipv4Address saddr,
371  uint16_t sport)
372 {
373  NS_LOG_FUNCTION(this << daddr << dport << saddr << sport);
374 
375  // this code is a copy/paste version of an old BSD ip stack lookup
376  // function.
377  uint32_t genericity = 3;
378  Ipv4EndPoint* generic = nullptr;
379  for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
380  {
381  if ((*i)->GetLocalPort() != dport)
382  {
383  continue;
384  }
385  if ((*i)->GetLocalAddress() == daddr && (*i)->GetPeerPort() == sport &&
386  (*i)->GetPeerAddress() == saddr)
387  {
388  /* this is an exact match. */
389  return *i;
390  }
391  uint32_t tmp = 0;
392  if ((*i)->GetLocalAddress() == Ipv4Address::GetAny())
393  {
394  tmp++;
395  }
396  if ((*i)->GetPeerAddress() == Ipv4Address::GetAny())
397  {
398  tmp++;
399  }
400  if (tmp < genericity)
401  {
402  generic = (*i);
403  genericity = tmp;
404  }
405  }
406  return generic;
407 }
408 
409 uint16_t
411 {
412  // Similar to counting up logic in netinet/in_pcb.c
413  NS_LOG_FUNCTION(this);
414  uint16_t port = m_ephemeral;
415  int count = m_portLast - m_portFirst;
416  do
417  {
418  if (count-- < 0)
419  {
420  return 0;
421  }
422  ++port;
423  if (port < m_portFirst || port > m_portLast)
424  {
425  port = m_portFirst;
426  }
427  } while (LookupPortLocal(port));
428  m_ephemeral = port;
429  return port;
430 }
431 
432 } // namespace ns3
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
Ipv4Address CombineMask(const Ipv4Mask &mask) const
Combine this address with a network mask.
static Ipv4Address GetAny()
uint16_t m_portFirst
The first ephemeral port.
uint16_t AllocateEphemeralPort()
Allocate an ephemeral port.
EndPoints m_endPoints
A list of IPv4 end points.
uint16_t m_portLast
The last ephemeral port.
Ipv4EndPoint * SimpleLookup(Ipv4Address daddr, uint16_t dport, Ipv4Address saddr, uint16_t sport)
simple lookup for a match with all the parameters.
bool LookupLocal(Ptr< NetDevice > boundNetDevice, Ipv4Address addr, uint16_t port)
Lookup for address and port.
EndPoints GetAllEndPoints()
Get the entire list of end points registered.
uint16_t m_ephemeral
The ephemeral port.
EndPoints Lookup(Ipv4Address daddr, uint16_t dport, Ipv4Address saddr, uint16_t sport, Ptr< Ipv4Interface > incomingInterface)
lookup for a match with all the parameters.
bool LookupPortLocal(uint16_t port)
Lookup for port local.
void DeAllocate(Ipv4EndPoint *endPoint)
Remove a end point.
Ipv4EndPoint * Allocate()
Allocate a Ipv4EndPoint.
std::list< Ipv4EndPoint * > EndPoints
Container of the IPv4 endpoints.
A representation of an internet endpoint/connection.
Ipv4Address GetLocalAddress() const
Get the local address.
uint16_t GetPeerPort() const
Get the peer port.
Ptr< NetDevice > GetBoundNetDevice() const
Returns socket's bound netdevice, if any.
uint16_t GetLocalPort() const
Get the local port.
bool IsRxEnabled() const
Checks if the endpoint can receive packets.
Ipv4Address GetPeerAddress() const
Get the peer address.
a class to store IPv4 address information on an interface
Ipv4Mask GetMask() const
Get the network mask.
Ipv4Address GetLocal() const
Get the local address.
uint32_t GetNAddresses() const
Ipv4InterfaceAddress GetAddress(uint32_t index) const
Ptr< NetDevice > GetDevice() const
uint16_t GetPrefixLength() const
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
uint16_t port
Definition: dsdv-manet.cc:44
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:261
address
Definition: first.py:47
Every class exported by the ns3 library is enclosed in the ns3 namespace.