A Discrete-Event Network Simulator
API
ipv4-fragmentation-test.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011 Universita' di Firenze, Italy
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
19  */
24 #include "ns3/test.h"
25 #include "ns3/config.h"
26 #include "ns3/uinteger.h"
27 #include "ns3/socket-factory.h"
28 #include "ns3/ipv4-raw-socket-factory.h"
29 #include "ns3/udp-socket-factory.h"
30 #include "ns3/simulator.h"
31 #include "ns3/simple-net-device.h"
32 #include "ns3/simple-net-device-helper.h"
33 #include "ns3/socket.h"
34 #include "ns3/udp-socket.h"
35 
36 #include "ns3/log.h"
37 #include "ns3/node.h"
38 #include "ns3/inet-socket-address.h"
39 #include "ns3/boolean.h"
40 
41 #include "ns3/arp-l3-protocol.h"
42 #include "ns3/ipv4-l3-protocol.h"
43 #include "ns3/icmpv4-l4-protocol.h"
44 #include "ns3/ipv4-list-routing.h"
45 #include "ns3/ipv4-static-routing.h"
46 #include "ns3/udp-l4-protocol.h"
47 #include "ns3/internet-stack-helper.h"
48 #include "ns3/error-channel.h"
49 
50 #include <string>
51 #include <limits>
52 #include <netinet/in.h>
53 
54 using namespace ns3;
55 
56 class UdpSocketImpl;
57 
64 class IPv4TestTag : public Tag {
65 private:
66  uint64_t token;
67 public:
72  static TypeId GetTypeId () {
73  static TypeId tid = TypeId ("ns3::IPv4TestTag").SetParent<Tag> ().AddConstructor<IPv4TestTag> ();
74  return tid;
75  }
76  virtual TypeId GetInstanceTypeId () const { return GetTypeId (); }
77  virtual uint32_t GetSerializedSize () const { return sizeof (token); }
78  virtual void Serialize (TagBuffer buffer) const { buffer.WriteU64 (token); }
79  virtual void Deserialize (TagBuffer buffer) { token = buffer.ReadU64 (); }
80  virtual void Print (std::ostream &os) const { os << "token=" << token; }
85  void SetToken (uint64_t token) { this->token = token; }
90  uint64_t GetToken () { return token; }
91 };
92 
100 {
104 
105 
108  uint32_t m_dataSize;
109  uint8_t *m_data;
110  uint32_t m_size;
111  uint8_t m_icmpType;
112  bool m_broadcast;
113 
114 public:
115  virtual void DoRun (void);
116  Ipv4FragmentationTest (bool broadcast);
118 
119  // server part
120 
125  void StartServer (Ptr<Node> ServerNode);
130  void HandleReadServer (Ptr<Socket> socket);
131 
132  // client part
133 
138  void StartClient (Ptr<Node> ClientNode);
143  void HandleReadClient (Ptr<Socket> socket);
152  void HandleReadIcmpClient (Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
153  uint8_t icmpCode, uint32_t icmpInfo);
154 
161  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
162 
167  Ptr<Packet> SendClient (void);
168 
169 };
170 
172  : TestCase (std::string ("Verify the IPv4 layer 3 protocol fragmentation and reassembly: ") +
173  (broadcast? "broadcast": "unicast"))
174 {
175  m_socketServer = 0;
176  m_data = 0;
177  m_dataSize = 0;
178  m_size = 0;
179  m_icmpType = 0;
180  m_broadcast = broadcast;
181 }
182 
184 {
185  if ( m_data )
186  {
187  delete[] m_data;
188  }
189  m_data = 0;
190  m_dataSize = 0;
191 }
192 
193 
194 void
196 {
197 
198  if (m_socketServer == 0)
199  {
200  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
201  m_socketServer = Socket::CreateSocket (ServerNode, tid);
202  InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 9);
203  m_socketServer->Bind (local);
204  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
205  if (udpSocket)
206  {
207  // equivalent to setsockopt (MCAST_JOIN_GROUP)
208  udpSocket->MulticastJoinGroup (0, Ipv4Address ("10.0.0.1"));
209  }
210  }
211 
213 }
214 
215 void
217 {
218  Ptr<Packet> packet;
219  Address from;
220  while ((packet = socket->RecvFrom (from)))
221  {
222  if (InetSocketAddress::IsMatchingType (from))
223  {
224  m_receivedPacketServer = packet->Copy();
225  }
226  }
227 }
228 
229 void
231 {
232 
233  if (m_socketClient == 0)
234  {
235  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
236  m_socketClient = Socket::CreateSocket (ClientNode, tid);
237  m_socketClient->Bind ();
240  m_socketClient->SetAttribute ("IcmpCallback", cbValue);
242  }
243 
245 }
246 
247 void
249 {
250  Ptr<Packet> packet;
251  Address from;
252  while ((packet = socket->RecvFrom (from)))
253  {
254  if (InetSocketAddress::IsMatchingType (from))
255  {
256  m_receivedPacketClient = packet->Copy();
257  }
258  }
259 }
260 
261 void
263  uint8_t icmpTtl, uint8_t icmpType,
264  uint8_t icmpCode, uint32_t icmpInfo)
265 {
266  m_icmpType = icmpType;
267 }
268 
269 void
270 Ipv4FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
271 {
272  if (dataSize != m_dataSize)
273  {
274  delete [] m_data;
275  m_data = new uint8_t [dataSize];
276  m_dataSize = dataSize;
277  }
278 
279  if (fillSize >= dataSize)
280  {
281  memcpy (m_data, fill, dataSize);
282  return;
283  }
284 
285  uint32_t filled = 0;
286  while (filled + fillSize < dataSize)
287  {
288  memcpy (&m_data[filled], fill, fillSize);
289  filled += fillSize;
290  }
291 
292  memcpy(&m_data[filled], fill, dataSize - filled);
293 
294  m_size = dataSize;
295 }
296 
298 {
299  Ptr<Packet> p;
300  if (m_dataSize)
301  {
302  p = Create<Packet> (m_data, m_dataSize);
303  }
304  else
305  {
306  p = Create<Packet> (m_size);
307  }
308  IPv4TestTag tag;
309  tag.SetToken (42);
310  p->AddPacketTag (tag);
311  p->AddByteTag (tag);
312 
313  if (m_broadcast)
314  {
317  InetSocketAddress saddress = InetSocketAddress::ConvertFrom (address);
318  saddress.SetIpv4 (Ipv4Address::GetBroadcast ());
319  m_socketClient->SendTo (p, 0, saddress);
320  }
321  else
322  {
323  m_socketClient->Send (p);
324  }
325 
326  return p;
327 }
328 
329 void
331 {
332  // set the arp cache to something quite high
333  // we shouldn't need because the NetDevice used doesn't need arp, but still
334  Config::SetDefault ("ns3::ArpCache::PendingQueueSize", UintegerValue (100));
335 
336  // Create topology
337 
338  // Receiver Node
339  Ptr<Node> serverNode = CreateObject<Node> ();
340  // Sender Node
341  Ptr<Node> clientNode = CreateObject<Node> ();
342 
343  NodeContainer nodes (serverNode, clientNode);
344 
345  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
346  channel->SetJumpingTime (Seconds (0.5));
347 
348  SimpleNetDeviceHelper helperChannel;
349  helperChannel.SetNetDevicePointToPointMode (true);
350  NetDeviceContainer net = helperChannel.Install (nodes, channel);
351 
352  InternetStackHelper internet;
353  internet.Install (nodes);
354 
355  Ptr<Ipv4> ipv4;
356  uint32_t netdev_idx;
357  Ipv4InterfaceAddress ipv4Addr;
358 
359  // Receiver Node
360  ipv4 = serverNode->GetObject<Ipv4> ();
361  netdev_idx = ipv4->AddInterface (net.Get (0));
362  ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.1"), Ipv4Mask (0xffff0000U));
363  ipv4->AddAddress (netdev_idx, ipv4Addr);
364  ipv4->SetUp (netdev_idx);
365  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
366  Ptr<SimpleNetDevice> serverDev = DynamicCast<SimpleNetDevice> (net.Get (0));
367  serverDevErrorModel->Disable ();
368  serverDev->SetMtu(1500);
369  serverDev->SetReceiveErrorModel (serverDevErrorModel);
370  StartServer (serverNode);
371 
372  // Sender Node
373  ipv4 = clientNode->GetObject<Ipv4> ();
374  netdev_idx = ipv4->AddInterface (net.Get (1));
375  ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.2"), Ipv4Mask (0xffff0000U));
376  ipv4->AddAddress (netdev_idx, ipv4Addr);
377  ipv4->SetUp (netdev_idx);
378  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
379  Ptr<SimpleNetDevice> clientDev = DynamicCast<SimpleNetDevice> (net.Get (1));
380  clientDevErrorModel->Disable ();
381  clientDev->SetMtu(1500);
382  clientDev->SetReceiveErrorModel (clientDevErrorModel);
383  StartClient (clientNode);
384 
385  // some small packets, some rather big ones
386  uint32_t packetSizes[5] = {1000, 2000, 5000, 10000, 65000};
387 
388  // using the alphabet
389  uint8_t fillData[78];
390  for ( uint32_t k=48; k<=125; k++ )
391  {
392  fillData[k-48] = k;
393  }
394 
395  // First test: normal channel, no errors, no delays
396  for( int i= 0; i<5; i++)
397  {
398  uint32_t packetSize = packetSizes[i];
399 
400  SetFill (fillData, 78, packetSize);
401 
402  m_receivedPacketServer = Create<Packet> ();
403  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
405  Simulator::Run ();
406 
407  uint8_t recvBuffer[65000];
408 
409  uint16_t recvSize = m_receivedPacketServer->GetSize ();
410 
411  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
412 
413  m_receivedPacketServer->CopyData(recvBuffer, 65000);
415  0, "Packet content differs");
416  }
417 
418  // Second test: normal channel, no errors, delays each 2 packets.
419  // Each other fragment will arrive out-of-order.
420  // The packets should be received correctly since reassembly will reorder the fragments.
421  channel->SetJumpingMode(true);
422  for( int i= 0; i<5; i++)
423  {
424  uint32_t packetSize = packetSizes[i];
425 
426  SetFill (fillData, 78, packetSize);
427 
428  m_receivedPacketServer = Create<Packet> ();
429  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
431  Simulator::Run ();
432 
433  uint8_t recvBuffer[65000];
434 
435  uint16_t recvSize = m_receivedPacketServer->GetSize ();
436 
437  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
438 
439  m_receivedPacketServer->CopyData(recvBuffer, 65000);
441  0, "Packet content differs");
442  }
443  channel->SetJumpingMode(false);
444 
445  // Third test: normal channel, some errors, no delays.
446  // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
447  // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
448  // to the sender (if the first fragment has been received).
449  // In this test case the first fragment is received, so we do expect an ICMP.
450  // Client -> Server : errors enabled
451  // Server -> Client : errors disabled (we want to have back the ICMP)
452  clientDevErrorModel->Disable();
453  serverDevErrorModel->Enable();
454  for( int i= 1; i<5; i++)
455  {
456  uint32_t packetSize = packetSizes[i];
457 
458  SetFill (fillData, 78, packetSize);
459 
460  // reset the model, we want to receive the very first fragment.
461  serverDevErrorModel->Reset();
462 
463  m_receivedPacketServer = Create<Packet> ();
464  m_icmpType = 0;
465  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
467  Simulator::Run ();
468 
469  uint16_t recvSize = m_receivedPacketServer->GetSize ();
470 
471  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
472  NS_TEST_EXPECT_MSG_EQ ((m_icmpType == 11), true, "Client did not receive ICMP::TIME_EXCEEDED");
473  }
474 
475  // Fourth test: normal channel, no errors, no delays.
476  // We check tags
477  clientDevErrorModel->Disable ();
478  serverDevErrorModel->Disable ();
479  for (int i= 0; i<5; i++)
480  {
481  uint32_t packetSize = packetSizes[i];
482 
483  SetFill (fillData, 78, packetSize);
484 
485  m_receivedPacketServer = Create<Packet> ();
486  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
488  Simulator::Run ();
489 
490  IPv4TestTag packetTag;
491  bool found = m_receivedPacketServer->PeekPacketTag (packetTag);
492 
493  NS_TEST_EXPECT_MSG_EQ (found, true, "PacketTag not found");
494  NS_TEST_EXPECT_MSG_EQ (packetTag.GetToken (), 42, "PacketTag value not correct");
495 
497 
498  uint32_t end = 0;
499  uint32_t tagStart = 0;
500  uint32_t tagEnd = 0;
501  while (iter.HasNext ())
502  {
503  ByteTagIterator::Item item = iter.Next ();
504  NS_TEST_EXPECT_MSG_EQ (item.GetTypeId ().GetName (), "ns3::IPv4TestTag", "ByteTag name not correct");
505  tagStart = item.GetStart ();
506  tagEnd = item.GetEnd ();
507  if (end == 0)
508  {
509  NS_TEST_EXPECT_MSG_EQ (tagStart, 0, "First ByteTag Start not correct");
510  }
511  if (end != 0)
512  {
513  NS_TEST_EXPECT_MSG_EQ (tagStart, end, "ByteTag End not correct");
514  }
515  end = tagEnd;
516  IPv4TestTag *byteTag = dynamic_cast<IPv4TestTag *> (item.GetTypeId ().GetConstructor () ());
517  NS_TEST_EXPECT_MSG_NE (byteTag, 0, "ByteTag not found");
518  item.GetTag (*byteTag);
519  NS_TEST_EXPECT_MSG_EQ (byteTag->GetToken (), 42, "ByteTag value not correct");
520  delete byteTag;
521  }
523  }
524 
525 
526  Simulator::Destroy ();
527 }
528 
529 
537 {
538 public:
540 };
541 
543  : TestSuite ("ipv4-fragmentation", UNIT)
544 {
545  AddTestCase (new Ipv4FragmentationTest(false), TestCase::QUICK);
546  AddTestCase (new Ipv4FragmentationTest(true), TestCase::QUICK);
547 }
548 
Callback< ObjectBase * > GetConstructor(void) const
Get the constructor callback.
Definition: type-id.cc:1061
TypeId GetTypeId(void) const
Definition: packet.cc:34
std::string GetName(void) const
Get the name.
Definition: type-id.cc:977
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
an Inet address class
uint64_t GetToken()
Get the token.
void StartClient(Ptr< Node > ClientNode)
Start the client.
uint32_t GetId(void) const
Definition: node.cc:109
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:852
void WriteU64(uint64_t v)
Definition: tag-buffer.cc:102
virtual bool SetAllowBroadcast(bool allowBroadcast)=0
Configure whether broadcast datagram transmissions are allowed.
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:269
static const uint32_t packetSize
A suite of tests to run.
Definition: test.h:1343
Ptr< Packet > m_sentPacketClient
Packet sent by client.
aggregate IP/TCP/UDP functionality to existing Nodes.
uint32_t GetStart(void) const
The index is an offset from the start of the packet.
Definition: packet.cc:39
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:283
static TypeId GetTypeId()
Get the type ID.
encapsulates test code
Definition: test.h:1153
STL namespace.
Ptr< Socket > m_socketServer
Server socket.
IPv4 Fragmentation TestSuite.
A sockets interface to UDP.
a polymophic address class
Definition: address.h:90
AttributeValue implementation for Callback.
Definition: callback.h:1937
channel
Definition: third.py:92
Ptr< Socket > m_socketClient
Client socket.
Ptr< Packet > SendClient(void)
Send a packet.
Tag used in IPv4 Fragmentation Test.
Identifies a byte tag and a set of bytes within a packet to which the tag applies.
Definition: packet.h:61
virtual int MulticastJoinGroup(uint32_t interface, const Address &groupAddress)=0
Corresponds to socket option MCAST_JOIN_GROUP.
nodes
Definition: first.py:32
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
virtual void Deserialize(TagBuffer buffer)
virtual void SetUp(uint32_t interface)=0
Hold an unsigned integer type.
Definition: uinteger.h:44
holds a vector of ns3::NetDevice pointers
void SetRecvCallback(Callback< void, Ptr< Socket > >)
Notify application when new data is available to be read.
Definition: socket.cc:128
static Ipv4FragmentationTestSuite g_ipv4fragmentationTestSuite
Static variable for test initialization.
void Disable(void)
Disable the error model.
Definition: error-model.cc:132
bool m_broadcast
broadcast packets
virtual int Connect(const Address &address)=0
Initiate a connection to a remote host.
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:76
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
tag a set of bytes in a packet
Definition: tag.h:36
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
keep track of a set of node pointers.
uint64_t ReadU64(void)
Definition: tag-buffer.cc:134
address
Definition: first.py:44
IPv4 Fragmentation Test.
virtual void Print(std::ostream &os) const
void SetNetDevicePointToPointMode(bool pointToPointMode)
SimpleNetDevice is Broadcast capable and ARP needing.
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:121
Iterator over the set of byte tags in a packet.
Definition: packet.h:54
void Reset(void)
Reset any state associated with the error model.
Definition: error-model.cc:118
#define NS_TEST_EXPECT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report if not.
Definition: test.h:737
void SetIpv4(Ipv4Address address)
virtual TypeId GetInstanceTypeId() const
Get the most derived TypeId for this Object.
void HandleReadIcmpClient(Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
Handle incoming ICMP packets.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
uint32_t GetEnd(void) const
The index is an offset from the start of the packet.
Definition: packet.cc:44
uint32_t m_dataSize
Data size.
void StartServer(Ptr< Node > ServerNode)
Start the server.
virtual void Serialize(TagBuffer buffer) const
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:41
read and write tag data
Definition: tag-buffer.h:51
a class to store IPv4 address information on an interface
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:956
virtual Ptr< Node > GetNode(void) const =0
Return the node this socket is associated with.
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:378
uint32_t m_size
packet size.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1278
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:849
void SetToken(uint64_t token)
Set the token.
Ptr< Packet > m_receivedPacketServer
Packet received by server.
uint64_t token
Token carried by the tag.
virtual bool AddAddress(uint32_t interface, Ipv4InterfaceAddress address)=0
virtual int SendTo(Ptr< Packet > p, uint32_t flags, const Address &toAddress)=0
Send data to a specified peer.
Ptr< Packet > m_receivedPacketClient
Packet received by client.
virtual void DoRun(void)
Implementation to actually run this TestCase.
virtual int GetPeerName(Address &address) const =0
Get the peer address of a connected socket.
virtual Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress)=0
Read a single packet from the socket and retrieve the sender address.
build a set of SimpleNetDevice objects
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:978
void GetTag(Tag &tag) const
Read the requested tag and store it in the user-provided tag instance.
Definition: packet.cc:49
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
NetDeviceContainer Install(Ptr< Node > node) const
This method creates an ns3::SimpleChannel with the attributes configured by SimpleNetDeviceHelper::Se...
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:185
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:912
void Enable(void)
Enable the error model.
Definition: error-model.cc:125
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1642
void SetFill(uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
Set the packet fill.
ByteTagIterator GetByteTagIterator(void) const
Returns an iterator over the set of byte tags included in this packet.
Definition: packet.cc:933
void HandleReadClient(Ptr< Socket > socket)
Handle incoming packets.
void HandleReadServer(Ptr< Socket > socket)
Handle incoming packets.
virtual uint32_t GetSerializedSize() const