1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3 * Copyright (c) 2015 Magister Solutions
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: Budiarto Herman <budiarto.herman@magister.fi>
19 *
20 */
21
22 #include <ns3/test.h>
23 #include <ns3/log.h>
24 #include <ns3/config.h>
25 #include <ns3/ptr.h>
26 #include <ns3/nstime.h>
27 #include <ns3/integer.h>
28
29 #include <ns3/simple-channel.h>
30 #include <ns3/node.h>
31 #include <ns3/packet.h>
32 #include <ns3/mac48-address.h>
33 #include <ns3/simple-net-device.h>
34 #include <ns3/error-model.h>
35 #include <ns3/ipv4-address-helper.h>
36 #include <ns3/ipv6-address-helper.h>
37 #include <ns3/internet-stack-helper.h>
38 #include <ns3/tcp-l4-protocol.h>
39
40 #include <ns3/tcp-congestion-ops.h>
41
42 #include <ns3/three-gpp-http-client.h>
43 #include <ns3/three-gpp-http-server.h>
44 #include <ns3/three-gpp-http-helper.h>
45 #include <ns3/three-gpp-http-header.h>
46
47 #include <ns3/basic-data-calculators.h>
48 #include <list>
49 #include <sstream>
50
51
52 NS_LOG_COMPONENT_DEFINE ("ThreeGppHttpClientServerTest");
53
54 using namespace ns3;
55
56 // HTTP OBJECT TEST CASE //////////////////////////////////////////////////////
57
58 /**
59 * \ingroup http
60 * \ingroup applications-test
61 * \ingroup tests
62 * A test class which verifies that each HTTP object sent is also received the
63 * same size.
64 *
65 * The test uses a minimalist scenario of one HTTP server and one HTTP client,
66 * connected through a SimpleChannel. The simulation runs until 3 web pages
67 * have been successfully downloaded by the client.
68 *
69 * The test also collects some statistical information from the simulation for
70 * informational or debugging purpose. This can be seen by enabling LOG_INFO.
71 */
72 class ThreeGppHttpObjectTestCase : public TestCase
73 {
74 public:
75 /**
76 * \param name A textual label to briefly describe the test.
77 * \param rngRun Run index to be used, intended to affect the values produced
78 * by random number generators throughout the test.
79 * \param tcpType Type of TCP algorithm to be used by the connection between
80 * the client and the server. Must be a child type of
81 * ns3::TcpSocketFactory.
82 * \param channelDelay Transmission delay between the client and the server
83 * (and vice versa) which is due to the channel.
84 * \param bitErrorRate The probability of transmission error between the
85 * client and the server (and vice versa) in the unit of
86 * bits.
87 * \param mtuSize Maximum transmission unit (in bytes) to be used by the
88 * server model.
89 * \param useIpv6 If true, IPv6 will be used to address both client and
90 * server. Otherwise, IPv4 will be used.
91 */
92 ThreeGppHttpObjectTestCase (const std::string &name,
93 uint32_t rngRun,
94 const TypeId &tcpType,
95 const Time &channelDelay,
96 double bitErrorRate,
97 uint32_t mtuSize,
98 bool useIpv6);
99
100 private:
101 /**
102 * Creates a Node, complete with a TCP/IP stack and address assignment.
103 * #m_tcpType determines the TCP algorithm installed at the TCP stack.
104 * #m_useIpv6 determines whether to use IPv4 addressing or IPv6 addressing.
105 *
106 * \param[in] channel Pointer to a channel which the node's device will be
107 * attached to.
108 * \param[out] assignedAddress The resulting address of the node.
109 * \return Pointer to the newly created node.
110 */
111 Ptr<Node> CreateSimpleInternetNode (Ptr<SimpleChannel> channel,
112 Address &assignedAddress);
113
114 // Inherited from TestCase base class.
115 virtual void DoRun ();
116 virtual void DoTeardown ();
117
118 /**
119 * \internal
120 * Internal class used by ThreeGppHttpObjectTestCase. Keep track of the number
121 * of object and bytes that have been sent and received in the simulation by
122 * listening to the relevant trace sources.
123 */
124 class ThreeGppHttpObjectTracker
125 {
126 public:
127 /// Creates a new instance with all counters begin at zero.
128 ThreeGppHttpObjectTracker ();
129 /**
130 * Shall be invoked when a whole object has been transmitted.
131 * \param size Size of the whole object (in bytes).
132 */
133 void ObjectSent (uint32_t size);
134 /**
135 * Shall be invoked when an object part has been received.
136 * \param size Size of the object part (in bytes). This amount will be
137 * accumulated until ObjectReceived() is invoked.
138 */
139 void PartReceived (uint32_t size);
140 /**
141 * Shall be invoked after all parts of a complete object have been
142 * received.
143 * \param[out] txSize Size of the whole object (in bytes) when it was
144 * transmitted.
145 * \param[out] rxSize Size of the whole object (in bytes) received.
146 * \return True if this receive operation has a matching transmission
147 * operation (ObjectSent()), otherwise false. Both arguments are
148 * guaranteed to be replaced with initialized values if the return
149 * value is true.
150 */
151 bool ObjectReceived (uint32_t &txSize, uint32_t &rxSize);
152 /// \return True if zero object is currently tracked.
153 bool IsEmpty () const;
154 /// \return Number of whole objects that have been received so far.
155 uint16_t GetNumOfObjectsReceived () const;
156 private:
157 /**
158 * Each entry is the size (in bytes) of object transmitted. A new entry is
159 * pushed to the back when a new object is transmitted. The frontmost entry
160 * is then removed when a whole object is received, i.e., it's logically a
161 * first-in-first-out queue data structure.
162 */
163 std::list<uint32_t> m_objectsSize;
164 /// The accumulated size (in bytes) of parts of a whole object.
165 uint32_t m_rxBuffer;
166 /// Number of whole objects that have been received so far.
167 uint16_t m_numOfObjectsReceived;
168 };
169
170 // The following defines one tracker for each HTTP object type.
171 ThreeGppHttpObjectTracker m_requestObjectTracker; ///< Tracker of request objects.
172 ThreeGppHttpObjectTracker m_mainObjectTracker; ///< Tracker of main objects.
173 ThreeGppHttpObjectTracker m_embeddedObjectTracker; ///< Tracker of embedded objects.
174
175 // CALLBACK TO TRACE SOURCES.
176
177 /**
178 * Connected with `TxMainObjectRequest` trace source of the client.
179 * Updates #m_requestObjectTracker.
180 * \param packet The packet of main object sent.
181 */
182 void ClientTxMainObjectRequestCallback (Ptr<const Packet> packet);
183 /**
184 * Connected with `TxEmbeddedObjectRequest` trace source of the client.
185 * Updates #m_requestObjectTracker.
186 * \param packet The packet of embedded object sent.
187 */
188 void ClientTxEmbeddedObjectRequestCallback (Ptr<const Packet> packet);
189 /**
190 * Connected with `Rx` trace source of the server.
191 * Updates #m_requestObjectTracker and perform some tests on the packet and
192 * the size of the object.
193 * \param packet The packet received.
194 * \param from The address where the packet originates from.
195 */
196 void ServerRxCallback (Ptr<const Packet> packet, const Address &from);
197 /**
198 * Connected with `MainObject` trace source of the server.
199 * Updates #m_mainObjectTracker.
200 * \param size Size of the generated main object (in bytes).
201 */
202 void ServerMainObjectCallback (uint32_t size);
203 /**
204 * Connected with `RxMainObjectPacket` trace source of the client.
205 * Updates #m_mainObjectTracker and perform some tests on the packet.
206 * \param packet The packet received.
207 */
208 void ClientRxMainObjectPacketCallback (Ptr<const Packet> packet);
209 /**
210 * Connected with `RxMainObject` trace source of the client. Updates
211 * #m_mainObjectTracker and perform some tests on the size of the object.
212 * \param httpClient Pointer to the application.
213 * \param packet Full packet received by application.
214 */
215 void ClientRxMainObjectCallback (Ptr<const ThreeGppHttpClient> httpClient, Ptr<const Packet> packet);
216 /**
217 * Connected with `EmbeddedObject` trace source of the server.
218 * Updates #m_embeddedObjectTracker.
219 * \param size Size of the generated embedded object (in bytes).
220 */
221 void ServerEmbeddedObjectCallback (uint32_t size);
222 /**
223 * Connected with `RxEmbeddedObjectPacket` trace source of the client.
224 * Updates #m_embeddedObjectTracker and perform some tests on the packet.
225 * \param packet The packet received.
226 */
227 void ClientRxEmbeddedObjectPacketCallback (Ptr<const Packet> packet);
228 /**
229 * Connected with `RxEmbeddedObject` trace source of the client. Updates
230 * #m_embeddedObjectTracker and perform some tests on the size of the object.
231 * \param httpClient Pointer to the application.
232 * \param packet Full packet received by application.
233 */
234 void ClientRxEmbeddedObjectCallback (Ptr<const ThreeGppHttpClient> httpClient, Ptr<const Packet> packet);
235 /**
236 * Connected with `StateTransition` trace source of the client.
237 * Increments #m_numOfPagesReceived when the client enters READING state.
238 * \param oldState The name of the previous state.
239 * \param newState The name of the current state.
240 */
241 void ClientStateTransitionCallback (const std::string &oldState,
242 const std::string &newState);
243 /**
244 * Connected with `RxDelay` trace source of the client.
245 * Updates the statistics in #m_delayCalculator.
246 * \param delay The packet one-trip delay time.
247 * \param from The address of the device where the packet originates from.
248 */
249 void ClientRxDelayCallback (const Time &delay, const Address &from);
250 /**
251 * Connected with `RxRtt` trace source of the client.
252 * Updates the statistics in #m_rttCalculator.
253 * \param rtt The packet round trip delay time.
254 * \param from The address of the device where the packet originates from.
255 */
256 void ClientRxRttCallback (const Time &rtt, const Address &from);
257 /**
258 * Connected with `PhyRxDrop` trace source of both the client's and server's
259 * devices. Increments #m_numOfPacketDrops.
260 * \param packet Pointer to the packet being dropped.
261 */
262 void DeviceDropCallback (Ptr<const Packet> packet);
263 /**
264 * Dummy event
265 */
266 void ProgressCallback ();
267
268 // THE PARAMETERS OF THE TEST CASE.
269
270 uint32_t m_rngRun; ///< Determines the set of random values generated.
271 TypeId m_tcpType; ///< TCP algorithm used.
272 Time m_channelDelay; ///< %Time needed by a packet to propagate.
273 uint32_t m_mtuSize; ///< Maximum transmission unit (in bytes).
274 bool m_useIpv6; ///< Whether to use IPv6 or IPv4.
275
276 // OTHER MEMBER VARIABLES.
277
278 /// Receive error model to be attached to the devices of both directions.
279 Ptr<RateErrorModel> m_errorModel;
280 /// Begins with 0. Simulation stops if this reaches 3.
281 uint16_t m_numOfPagesReceived;
282 /// Number of packets dropped because of #m_errorModel.
283 uint16_t m_numOfPacketDrops;
284 /// Installs TCP/IP stack on the nodes.
285 InternetStackHelper m_internetStackHelper;
286 /// Assigns IPv4 addresses to the nodes.
287 Ipv4AddressHelper m_ipv4AddressHelper;
288 /// Assigns IPv6 addresses to the nodes.
289 Ipv6AddressHelper m_ipv6AddressHelper;
290 /// Keeps statistical information of one-trip delays (in seconds).
291 Ptr<MinMaxAvgTotalCalculator<double> > m_delayCalculator;
292 /// Keeps statistical information of round-trip delays (in seconds).
293 Ptr<MinMaxAvgTotalCalculator<double> > m_rttCalculator;
294
295 }; // end of `class HttpClientServerTestCase`
296
ThreeGppHttpObjectTestCase(const std::string & name,uint32_t rngRun,const TypeId & tcpType,const Time & channelDelay,double bitErrorRate,uint32_t mtuSize,bool useIpv6)297 ThreeGppHttpObjectTestCase::ThreeGppHttpObjectTestCase (const std::string &name,
298 uint32_t rngRun,
299 const TypeId &tcpType,
300 const Time &channelDelay,
301 double bitErrorRate,
302 uint32_t mtuSize,
303 bool useIpv6)
304 : TestCase (name),
305 m_rngRun (rngRun),
306 m_tcpType (tcpType),
307 m_channelDelay (channelDelay),
308 m_mtuSize (mtuSize),
309 m_useIpv6 (useIpv6),
310 m_numOfPagesReceived (0),
311 m_numOfPacketDrops (0)
312 {
313 NS_LOG_FUNCTION (this << GetName ());
314
315 //NS_ASSERT (tcpType.IsChildOf (TypeId::LookupByName ("ns3::TcpSocketBase")));
316 NS_ASSERT (channelDelay.IsPositive ());
317
318 m_errorModel = CreateObject<RateErrorModel> ();
319 m_errorModel->SetRate (bitErrorRate);
320 m_errorModel->SetUnit (RateErrorModel::ERROR_UNIT_BIT);
321
322 m_ipv4AddressHelper.SetBase (Ipv4Address ("10.0.0.0"),
323 Ipv4Mask ("255.0.0.0"),
324 Ipv4Address ("0.0.0.1"));
325 m_ipv6AddressHelper.SetBase (Ipv6Address ("2001:1::"),
326 Ipv6Prefix (64),
327 Ipv6Address ("::1"));
328
329 m_delayCalculator = CreateObject<MinMaxAvgTotalCalculator<double> > ();
330 m_rttCalculator = CreateObject<MinMaxAvgTotalCalculator<double> > ();
331 }
332
333 Ptr<Node>
CreateSimpleInternetNode(Ptr<SimpleChannel> channel,Address & assignedAddress)334 ThreeGppHttpObjectTestCase::CreateSimpleInternetNode (Ptr<SimpleChannel> channel,
335 Address &assignedAddress)
336 {
337 NS_LOG_FUNCTION (this << channel);
338
339 Ptr<SimpleNetDevice> dev = CreateObject<SimpleNetDevice> ();
340 dev->SetAddress (Mac48Address::Allocate ());
341 dev->SetChannel (channel);
342 dev->SetReceiveErrorModel (m_errorModel);
343
344 Ptr<Node> node = CreateObject<Node> ();
345 node->AddDevice (dev);
346 m_internetStackHelper.Install (node);
347
348 // Assign IP address according to the selected Ip version.
349 if (m_useIpv6)
350 {
351 Ipv6InterfaceContainer ipv6Ifs
352 = m_ipv6AddressHelper.Assign (NetDeviceContainer (dev));
353 NS_ASSERT (ipv6Ifs.GetN () == 1);
354 assignedAddress = ipv6Ifs.GetAddress (0, 0);
355 }
356 else
357 {
358 Ipv4InterfaceContainer ipv4Ifs
359 = m_ipv4AddressHelper.Assign (NetDeviceContainer (dev));
360 NS_ASSERT (ipv4Ifs.GetN () == 1);
361 assignedAddress = ipv4Ifs.GetAddress (0, 0);
362 }
363
364 NS_LOG_DEBUG (this << " node is assigned to " << assignedAddress << ".");
365
366 // Set the TCP algorithm.
367 Ptr<TcpL4Protocol> tcp = node->GetObject<TcpL4Protocol> ();
368 tcp->SetAttribute ("SocketType", TypeIdValue (m_tcpType));
369
370 // Connect with the trace source that informs about packet drop due to error.
371 dev->TraceConnectWithoutContext (
372 "PhyRxDrop",
373 MakeCallback (&ThreeGppHttpObjectTestCase::DeviceDropCallback, this));
374
375 return node;
376 }
377
378 void
DoRun()379 ThreeGppHttpObjectTestCase::DoRun ()
380 {
381 NS_LOG_FUNCTION (this << GetName ());
382 Config::SetGlobal ("RngRun", UintegerValue (m_rngRun));
383 NS_LOG_INFO (this << " Running test case " << GetName ());
384
385 /*
386 * Create topology:
387 *
388 * Server Node Client Node
389 * +-----------------+ +-----------------+
390 * | HTTP Server | | HTTP Client |
391 * | Application | | Application |
392 * +-----------------+ +-----------------+
393 * | TCP | | TCP |
394 * +-----------------+ +-----------------+
395 * | IPv4/v6 | | IPv4/v6 |
396 * +-----------------+ +-----------------+
397 * | Simple NetDev | | Simple NetDev |
398 * +-----------------+ +-----------------+
399 * | |
400 * | |
401 * +----------------------------+
402 * Simple Channel
403 */
404
405 // Channel.
406 Ptr<SimpleChannel> channel = CreateObject<SimpleChannel> ();
407 channel->SetAttribute ("Delay", TimeValue (m_channelDelay));
408
409 // Server node.
410 Address serverAddress;
411 Ptr<Node> serverNode = CreateSimpleInternetNode (channel, serverAddress);
412 ThreeGppHttpServerHelper serverHelper (serverAddress);
413 ApplicationContainer serverApplications = serverHelper.Install (serverNode);
414 NS_TEST_ASSERT_MSG_EQ (serverApplications.GetN (), 1,
415 "Invalid number of HTTP servers has been installed");
416 Ptr<ThreeGppHttpServer> httpServer = serverApplications.Get (0)->GetObject<ThreeGppHttpServer> ();
417 NS_TEST_ASSERT_MSG_NE (httpServer, 0,
418 "HTTP server installation fails to produce a proper type");
419 httpServer->SetMtuSize (m_mtuSize);
420
421 // Client node.
422 Address clientAddress;
423 Ptr<Node> clientNode = CreateSimpleInternetNode (channel, clientAddress);
424 ThreeGppHttpClientHelper clientHelper (serverAddress);
425 ApplicationContainer clientApplications = clientHelper.Install (clientNode);
426 NS_TEST_ASSERT_MSG_EQ (clientApplications.GetN (), 1,
427 "Invalid number of HTTP clients has been installed");
428 Ptr<ThreeGppHttpClient> httpClient = clientApplications.Get (0)->GetObject<ThreeGppHttpClient> ();
429 NS_TEST_ASSERT_MSG_NE (httpClient, 0,
430 "HTTP client installation fails to produce a proper type");
431
432 // Uplink (requests) trace sources.
433 bool traceSourceConnected = httpClient->TraceConnectWithoutContext (
434 "TxMainObjectRequest",
435 MakeCallback (&ThreeGppHttpObjectTestCase::ClientTxMainObjectRequestCallback,
436 this));
437 NS_ASSERT (traceSourceConnected);
438 traceSourceConnected = httpClient->TraceConnectWithoutContext (
439 "TxEmbeddedObjectRequest",
440 MakeCallback (&ThreeGppHttpObjectTestCase::ClientTxEmbeddedObjectRequestCallback,
441 this));
442 NS_ASSERT (traceSourceConnected);
443 traceSourceConnected = httpServer->TraceConnectWithoutContext (
444 "Rx",
445 MakeCallback (&ThreeGppHttpObjectTestCase::ServerRxCallback,
446 this));
447 NS_ASSERT (traceSourceConnected);
448
449 // Downlink (main objects) trace sources.
450 traceSourceConnected = httpServer->TraceConnectWithoutContext (
451 "MainObject",
452 MakeCallback (&ThreeGppHttpObjectTestCase::ServerMainObjectCallback,
453 this));
454 NS_ASSERT (traceSourceConnected);
455 traceSourceConnected = httpClient->TraceConnectWithoutContext (
456 "RxMainObjectPacket",
457 MakeCallback (&ThreeGppHttpObjectTestCase::ClientRxMainObjectPacketCallback,
458 this));
459 NS_ASSERT (traceSourceConnected);
460 traceSourceConnected = httpClient->TraceConnectWithoutContext (
461 "RxMainObject",
462 MakeCallback (&ThreeGppHttpObjectTestCase::ClientRxMainObjectCallback,
463 this));
464 NS_ASSERT (traceSourceConnected);
465
466 // Downlink (embedded objects) trace sources.
467 traceSourceConnected = httpServer->TraceConnectWithoutContext (
468 "EmbeddedObject",
469 MakeCallback (&ThreeGppHttpObjectTestCase::ServerEmbeddedObjectCallback,
470 this));
471 NS_ASSERT (traceSourceConnected);
472
473 traceSourceConnected = httpClient->TraceConnectWithoutContext (
474 "RxEmbeddedObjectPacket",
475 MakeCallback (&ThreeGppHttpObjectTestCase::ClientRxEmbeddedObjectPacketCallback,
476 this));
477 NS_ASSERT (traceSourceConnected);
478
479 traceSourceConnected = httpClient->TraceConnectWithoutContext (
480 "RxEmbeddedObject",
481 MakeCallback (&ThreeGppHttpObjectTestCase::ClientRxEmbeddedObjectCallback,
482 this));
483 NS_ASSERT (traceSourceConnected);
484
485 // Other trace sources.
486 traceSourceConnected = httpClient->TraceConnectWithoutContext (
487 "StateTransition",
488 MakeCallback (&ThreeGppHttpObjectTestCase::ClientStateTransitionCallback,
489 this));
490 NS_ASSERT (traceSourceConnected);
491 traceSourceConnected = httpClient->TraceConnectWithoutContext (
492 "RxDelay",
493 MakeCallback (&ThreeGppHttpObjectTestCase::ClientRxDelayCallback,
494 this));
495 NS_ASSERT (traceSourceConnected);
496 traceSourceConnected = httpClient->TraceConnectWithoutContext (
497 "RxRtt",
498 MakeCallback (&ThreeGppHttpObjectTestCase::ClientRxRttCallback,
499 this));
500 NS_ASSERT (traceSourceConnected);
501
502 Simulator::Schedule (Seconds (1.0), &ThreeGppHttpObjectTestCase::ProgressCallback, this);
503
504 /*
505 * Here we don't set the simulation stop time. During the run, the simulation
506 * will stop immediately after the client has completely received the third
507 * web page.
508 */
509 Simulator::Run ();
510
511 // Dump some statistical information about the simulation.
512 NS_LOG_INFO (this << " Total request objects received: "
513 << m_requestObjectTracker.GetNumOfObjectsReceived ()
514 << " object(s).");
515 NS_LOG_INFO (this << " Total main objects received: "
516 << m_mainObjectTracker.GetNumOfObjectsReceived ()
517 << " object(s).");
518 NS_LOG_INFO (this << " Total embedded objects received: "
519 << m_embeddedObjectTracker.GetNumOfObjectsReceived ()
520 << " object(s).");
521 NS_LOG_INFO (this << " One-trip delays:"
522 << " average=" << m_delayCalculator->getMean ()
523 << " min=" << m_delayCalculator->getMin ()
524 << " max=" << m_delayCalculator->getMax ());
525 NS_LOG_INFO (this << " Round-trip delays:"
526 << " average=" << m_rttCalculator->getMean ()
527 << " min=" << m_rttCalculator->getMin ()
528 << " max=" << m_rttCalculator->getMax ());
529 NS_LOG_INFO (this << " Number of packets dropped by the devices: "
530 << m_numOfPacketDrops << " packet(s).");
531
532 // Some post-simulation tests.
533 NS_TEST_EXPECT_MSG_EQ (m_numOfPagesReceived, 3,
534 "Unexpected number of web pages processed.");
535 NS_TEST_EXPECT_MSG_EQ (m_requestObjectTracker.IsEmpty (), true,
536 "Tracker of request objects detected irrelevant packet(s).");
537 NS_TEST_EXPECT_MSG_EQ (m_mainObjectTracker.IsEmpty (), true,
538 "Tracker of main objects detected irrelevant packet(s).");
539 NS_TEST_EXPECT_MSG_EQ (m_embeddedObjectTracker.IsEmpty (), true,
540 "Tracker of embedded objects detected irrelevant packet(s).");
541
542 Simulator::Destroy ();
543
544 } // end of `void HttpClientServerTestCase::DoRun ()`
545
546 void
DoTeardown()547 ThreeGppHttpObjectTestCase::DoTeardown ()
548 {
549 NS_LOG_FUNCTION (this << GetName ());
550 }
551
ThreeGppHttpObjectTracker()552 ThreeGppHttpObjectTestCase::ThreeGppHttpObjectTracker::ThreeGppHttpObjectTracker ()
553 : m_rxBuffer (0),
554 m_numOfObjectsReceived (0)
555 {
556 NS_LOG_FUNCTION (this);
557 }
558
559 void
ObjectSent(uint32_t size)560 ThreeGppHttpObjectTestCase::ThreeGppHttpObjectTracker::ObjectSent (uint32_t size)
561 {
562 NS_LOG_FUNCTION (this << size);
563 m_objectsSize.push_back (size);
564 }
565
566 void
PartReceived(uint32_t size)567 ThreeGppHttpObjectTestCase::ThreeGppHttpObjectTracker::PartReceived (uint32_t size)
568 {
569 NS_LOG_FUNCTION (this << size);
570 m_rxBuffer += size;
571 }
572
573 bool
ObjectReceived(uint32_t & txSize,uint32_t & rxSize)574 ThreeGppHttpObjectTestCase::ThreeGppHttpObjectTracker::ObjectReceived (uint32_t &txSize,
575 uint32_t &rxSize)
576 {
577 NS_LOG_FUNCTION (this);
578
579 if (m_objectsSize.empty ())
580 {
581 return false;
582 }
583
584 // Set output values.
585 txSize = m_objectsSize.front ();
586 rxSize = m_rxBuffer;
587
588 // Reset counters.
589 m_objectsSize.pop_front ();
590 m_rxBuffer = 0;
591 m_numOfObjectsReceived++;
592
593 return true;
594 }
595
596 bool
IsEmpty() const597 ThreeGppHttpObjectTestCase::ThreeGppHttpObjectTracker::IsEmpty () const
598 {
599 return (m_objectsSize.empty () && (m_rxBuffer == 0));
600 }
601
602 uint16_t
GetNumOfObjectsReceived() const603 ThreeGppHttpObjectTestCase::ThreeGppHttpObjectTracker::GetNumOfObjectsReceived () const
604 {
605 return m_numOfObjectsReceived;
606 }
607
608 void
ClientTxMainObjectRequestCallback(Ptr<const Packet> packet)609 ThreeGppHttpObjectTestCase::ClientTxMainObjectRequestCallback (Ptr<const Packet> packet)
610 {
611 NS_LOG_FUNCTION (this << packet << packet->GetSize ());
612 m_requestObjectTracker.ObjectSent (packet->GetSize ());
613 }
614
615 void
ClientTxEmbeddedObjectRequestCallback(Ptr<const Packet> packet)616 ThreeGppHttpObjectTestCase::ClientTxEmbeddedObjectRequestCallback (Ptr<const Packet> packet)
617 {
618 NS_LOG_FUNCTION (this << packet << packet->GetSize ());
619 m_requestObjectTracker.ObjectSent (packet->GetSize ());
620 }
621
622 void
ServerRxCallback(Ptr<const Packet> packet,const Address & from)623 ThreeGppHttpObjectTestCase::ServerRxCallback (Ptr<const Packet> packet,
624 const Address &from)
625 {
626 NS_LOG_FUNCTION (this << packet << packet->GetSize () << from);
627
628 // Check the header in packet
629 Ptr<Packet> copy = packet->Copy ();
630 ThreeGppHttpHeader httpHeader;
631 NS_TEST_ASSERT_MSG_EQ (copy->RemoveHeader (httpHeader), 22,
632 "Error finding ThreeGppHttpHeader in a packet received by the server");
633 NS_TEST_ASSERT_MSG_GT (httpHeader.GetClientTs (), Seconds (0.0),
634 "Request object's client TS is unexpectedly non-positive");
635
636 m_requestObjectTracker.PartReceived (packet->GetSize ());
637
638 /*
639 * Request objects are assumed to be small and to not typically split. So we
640 * immediately follow by concluding the receive of a whole request object.
641 */
642 uint32_t txSize;
643 uint32_t rxSize;
644 bool isSent = m_requestObjectTracker.ObjectReceived (txSize, rxSize);
645 NS_TEST_ASSERT_MSG_EQ (isSent, true,
646 "Server receives one too many request object");
647 NS_TEST_ASSERT_MSG_EQ (txSize, rxSize,
648 "Transmitted size and received size of request object differ");
649 }
650
651 void
ServerMainObjectCallback(uint32_t size)652 ThreeGppHttpObjectTestCase::ServerMainObjectCallback (uint32_t size)
653 {
654 NS_LOG_FUNCTION (this << size);
655 m_mainObjectTracker.ObjectSent (size);
656 }
657
658 void
ClientRxMainObjectPacketCallback(Ptr<const Packet> packet)659 ThreeGppHttpObjectTestCase::ClientRxMainObjectPacketCallback (Ptr<const Packet> packet)
660 {
661 NS_LOG_FUNCTION (this << packet << packet->GetSize ());
662 m_mainObjectTracker.PartReceived (packet->GetSize ());
663 }
664
665 void
ClientRxMainObjectCallback(Ptr<const ThreeGppHttpClient> httpClient,Ptr<const Packet> packet)666 ThreeGppHttpObjectTestCase::ClientRxMainObjectCallback (Ptr<const ThreeGppHttpClient> httpClient,
667 Ptr<const Packet> packet)
668 {
669 NS_LOG_FUNCTION (this << httpClient << httpClient->GetNode ()->GetId ());
670
671 // Verify the header in the packet.
672 Ptr<Packet> copy = packet->Copy ();
673 ThreeGppHttpHeader httpHeader;
674 NS_TEST_ASSERT_MSG_EQ (copy->RemoveHeader (httpHeader), 22,
675 "Error finding ThreeGppHttpHeader in a packet received by the server");
676 NS_TEST_ASSERT_MSG_EQ (httpHeader.GetContentType (), ThreeGppHttpHeader::MAIN_OBJECT,
677 "Invalid content type in the received packet");
678 NS_TEST_ASSERT_MSG_GT (httpHeader.GetClientTs (), Seconds (0.0),
679 "Main object's client TS is unexpectedly non-positive");
680 NS_TEST_ASSERT_MSG_GT (httpHeader.GetServerTs (), Seconds (0.0),
681 "Main object's server TS is unexpectedly non-positive");
682 uint32_t txSize;
683 uint32_t rxSize;
684 bool isSent = m_mainObjectTracker.ObjectReceived (txSize, rxSize);
685 NS_TEST_ASSERT_MSG_EQ (isSent, true,
686 "Client receives one too many main object");
687 NS_TEST_ASSERT_MSG_EQ (txSize, rxSize,
688 "Transmitted size and received size of main object differ");
689 NS_TEST_ASSERT_MSG_EQ (httpHeader.GetContentLength (), rxSize,
690 "Actual main object packet size and received size of main object differ");
691 }
692
693 void
ServerEmbeddedObjectCallback(uint32_t size)694 ThreeGppHttpObjectTestCase::ServerEmbeddedObjectCallback (uint32_t size)
695 {
696 NS_LOG_FUNCTION (this << size);
697 m_embeddedObjectTracker.ObjectSent (size);
698 }
699
700 void
ClientRxEmbeddedObjectPacketCallback(Ptr<const Packet> packet)701 ThreeGppHttpObjectTestCase::ClientRxEmbeddedObjectPacketCallback (Ptr<const Packet> packet)
702 {
703 NS_LOG_FUNCTION (this << packet << packet->GetSize ());
704 m_embeddedObjectTracker.PartReceived (packet->GetSize ());
705 }
706
707 void
ClientRxEmbeddedObjectCallback(Ptr<const ThreeGppHttpClient> httpClient,Ptr<const Packet> packet)708 ThreeGppHttpObjectTestCase::ClientRxEmbeddedObjectCallback (Ptr<const ThreeGppHttpClient> httpClient,
709 Ptr<const Packet> packet)
710 {
711 NS_LOG_FUNCTION (this << httpClient << httpClient->GetNode ()->GetId ());
712
713 // Verify the header in the packet.
714 Ptr<Packet> copy = packet->Copy ();
715 ThreeGppHttpHeader httpHeader;
716 NS_TEST_ASSERT_MSG_EQ (copy->RemoveHeader (httpHeader), 22,
717 "Error finding ThreeGppHttpHeader in a packet received by the server");
718 NS_TEST_ASSERT_MSG_EQ (httpHeader.GetContentType (), ThreeGppHttpHeader::EMBEDDED_OBJECT,
719 "Invalid content type in the received packet");
720 NS_TEST_ASSERT_MSG_GT (httpHeader.GetClientTs (), Seconds (0.0),
721 "Embedded object's client TS is unexpectedly non-positive");
722 NS_TEST_ASSERT_MSG_GT (httpHeader.GetServerTs (), Seconds (0.0),
723 "Embedded object's server TS is unexpectedly non-positive");
724
725 uint32_t txSize;
726 uint32_t rxSize;
727 bool isSent = m_embeddedObjectTracker.ObjectReceived (txSize, rxSize);
728 NS_TEST_ASSERT_MSG_EQ (isSent, true,
729 "Client receives one too many embedded object");
730 NS_TEST_ASSERT_MSG_EQ (txSize, rxSize,
731 "Transmitted size and received size of embedded object differ");
732 NS_TEST_ASSERT_MSG_EQ (httpHeader.GetContentLength (), rxSize,
733 "Actual embedded object packet size and received size of embedded object differ");
734 }
735
736 void
ClientStateTransitionCallback(const std::string & oldState,const std::string & newState)737 ThreeGppHttpObjectTestCase::ClientStateTransitionCallback (const std::string &oldState,
738 const std::string &newState)
739 {
740 NS_LOG_FUNCTION (this << oldState << newState);
741
742 if (newState == "READING")
743 {
744 m_numOfPagesReceived++;
745
746 if (m_numOfPagesReceived >= 3)
747 {
748 // We have processed 3 web pages and that should be enough for this test.
749 NS_LOG_LOGIC (this << " Test is stopping now.");
750 Simulator::Stop ();
751 }
752 }
753 }
754
755 void
ProgressCallback()756 ThreeGppHttpObjectTestCase::ProgressCallback ()
757 {
758 NS_LOG_INFO ("Simulator time now: " << Simulator::Now ().As (Time::S) << ".");
759 Simulator::Schedule (Seconds (1.0), &ThreeGppHttpObjectTestCase::ProgressCallback, this);
760 }
761
762 void
ClientRxDelayCallback(const Time & delay,const Address & from)763 ThreeGppHttpObjectTestCase::ClientRxDelayCallback (const Time &delay,
764 const Address &from)
765 {
766 NS_LOG_FUNCTION (this << delay.As (Time::S) << from);
767 m_delayCalculator->Update (delay.GetSeconds ());
768 }
769
770 void
ClientRxRttCallback(const Time & rtt,const Address & from)771 ThreeGppHttpObjectTestCase::ClientRxRttCallback (const Time &rtt,
772 const Address &from)
773 {
774 NS_LOG_FUNCTION (this << rtt.As (Time::S) << from);
775 m_rttCalculator->Update (rtt.GetSeconds ());
776 }
777
778 void
DeviceDropCallback(Ptr<const Packet> packet)779 ThreeGppHttpObjectTestCase::DeviceDropCallback (Ptr<const Packet> packet)
780 {
781 NS_LOG_FUNCTION (this << packet << packet->GetSize ());
782 m_numOfPacketDrops++;
783 }
784
785
786 // TEST SUITE /////////////////////////////////////////////////////////////////
787
788 /**
789 * \ingroup http
790 * \ingroup applications-test
791 * \ingroup tests
792 * A test class for running several system tests which validate the web
793 * browsing traffic model.
794 *
795 * The tests cover the combinations of the following parameters:
796 * - the use of NewReno (ns-3's default)
797 * - various lengths of channel delay: 3 ms, 30 ms, and 300 ms;
798 * - the existence of transmission error;
799 * - different MTU (maximum transmission unit) sizes;
800 * - IPv4 and IPv6; and
801 * - the use of different set of random numbers.
802 *
803 * The _fullness_ parameter specified when running the test framework will
804 * determine the number of test cases created by this test suite.
805 */
806 class ThreeGppHttpClientServerTestSuite : public TestSuite
807 {
808 public:
809 /// Instantiate the test suite.
ThreeGppHttpClientServerTestSuite()810 ThreeGppHttpClientServerTestSuite () : TestSuite ("three-gpp-http-client-server-test", SYSTEM)
811 {
812 // LogComponentEnable ("ThreeGppHttpClientServerTest", LOG_INFO);
813 // LogComponentEnable ("ThreeGppHttpClient", LOG_INFO);
814 // LogComponentEnable ("ThreeGppHttpServer", LOG_INFO);
815 // LogComponentEnableAll (LOG_PREFIX_ALL);
816
817 Time channelDelay[] = {
818 MilliSeconds (3),
819 MilliSeconds (30),
820 MilliSeconds (300)
821 };
822 double bitErrorRate[] = {0.0, 5.0e-6};
823 uint32_t mtuSize[] = {536, 1460};
824
825 uint32_t run = 1;
826 while (run <= 100)
827 {
828 for (uint32_t i1 = 0; i1 < 3; i1++)
829 {
830 for (uint32_t i2 = 0; i2 < 2; i2++)
831 {
832 for (uint32_t i3 = 0; i3 < 2; i3++)
833 {
834 AddHttpObjectTestCase (run++,
835 channelDelay[i1],
836 bitErrorRate[i2],
837 mtuSize[i3],
838 false);
839 AddHttpObjectTestCase (run++,
840 channelDelay[i1],
841 bitErrorRate[i2],
842 mtuSize[i3],
843 true);
844 }
845 }
846 }
847 }
848 }
849
850 private:
851 /**
852 * Creates a test case with the given parameters.
853 *
854 * \param rngRun Run index to be used, intended to affect the values produced
855 * by random number generators throughout the test.
856 * \param channelDelay Transmission delay between the client and the server
857 * (and vice versa) which is due to the channel.
858 * \param bitErrorRate The probability of transmission error between the
859 * client and the server (and vice versa) in the unit of
860 * bits.
861 * \param mtuSize Maximum transmission unit (in bytes) to be used by the
862 * server model.
863 * \param useIpv6 If true, IPv6 will be used to address both client and
864 * server. Otherwise, IPv4 will be used.
865 */
AddHttpObjectTestCase(uint32_t rngRun,const Time & channelDelay,double bitErrorRate,uint32_t mtuSize,bool useIpv6)866 void AddHttpObjectTestCase (uint32_t rngRun,
867 const Time &channelDelay,
868 double bitErrorRate,
869 uint32_t mtuSize,
870 bool useIpv6)
871 {
872 std::ostringstream name;
873 name << "Run #" << rngRun;
874 name << " delay=" << channelDelay.As (Time::MS);
875 name << " ber=" << bitErrorRate;
876 name << " mtu=" << mtuSize;
877
878 if (useIpv6)
879 {
880 name << " IPv6";
881 }
882 else
883 {
884 name << " IPv4";
885 }
886
887 // Assign higher fullness for tests with higher RngRun.
888 TestCase::TestDuration testDuration = TestCase::QUICK;
889 if (rngRun > 20)
890 {
891 testDuration = TestCase::EXTENSIVE;
892 }
893 if (rngRun > 50)
894 {
895 testDuration = TestCase::TAKES_FOREVER;
896 }
897
898 AddTestCase (new ThreeGppHttpObjectTestCase (name.str (),
899 rngRun,
900 TcpNewReno::GetTypeId (),
901 channelDelay,
902 bitErrorRate,
903 mtuSize,
904 useIpv6),
905 testDuration);
906 }
907
908 }; // end of class `ThreeGppHttpClientServerTestSuite`
909
910 /// The global instance of the `three-gpp-http-client-server` system test.
911 static ThreeGppHttpClientServerTestSuite g_httpClientServerTestSuiteInstance;
912
913