1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013 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 "three-gpp-http-client.h"
23 
24 #include <ns3/log.h>
25 #include <ns3/simulator.h>
26 #include <ns3/callback.h>
27 #include <ns3/pointer.h>
28 #include <ns3/uinteger.h>
29 #include <ns3/double.h>
30 #include <ns3/three-gpp-http-variables.h>
31 #include <ns3/packet.h>
32 #include <ns3/socket.h>
33 #include <ns3/tcp-socket-factory.h>
34 #include <ns3/inet-socket-address.h>
35 #include <ns3/inet6-socket-address.h>
36 #include <ns3/unused.h>
37 
38 
39 NS_LOG_COMPONENT_DEFINE ("ThreeGppHttpClient");
40 
41 
42 namespace ns3 {
43 
44 NS_OBJECT_ENSURE_REGISTERED (ThreeGppHttpClient);
45 
46 
ThreeGppHttpClient()47 ThreeGppHttpClient::ThreeGppHttpClient ()
48   : m_state (NOT_STARTED),
49   m_socket (0),
50   m_objectBytesToBeReceived (0),
51   m_objectClientTs (MilliSeconds (0)),
52   m_objectServerTs (MilliSeconds (0)),
53   m_embeddedObjectsToBeRequested (0),
54   m_httpVariables (CreateObject<ThreeGppHttpVariables> ())
55 {
56   NS_LOG_FUNCTION (this);
57 }
58 
59 
60 // static
61 TypeId
GetTypeId()62 ThreeGppHttpClient::GetTypeId ()
63 {
64   static TypeId tid = TypeId ("ns3::ThreeGppHttpClient")
65     .SetParent<Application> ()
66     .AddConstructor<ThreeGppHttpClient> ()
67     .AddAttribute ("Variables",
68                    "Variable collection, which is used to control e.g. timing and HTTP request size.",
69                    PointerValue (),
70                    MakePointerAccessor (&ThreeGppHttpClient::m_httpVariables),
71                    MakePointerChecker<ThreeGppHttpVariables> ())
72     .AddAttribute ("RemoteServerAddress",
73                    "The address of the destination server.",
74                    AddressValue (),
75                    MakeAddressAccessor (&ThreeGppHttpClient::m_remoteServerAddress),
76                    MakeAddressChecker ())
77     .AddAttribute ("RemoteServerPort",
78                    "The destination port of the outbound packets.",
79                    UintegerValue (80), // the default HTTP port
80                    MakeUintegerAccessor (&ThreeGppHttpClient::m_remoteServerPort),
81                    MakeUintegerChecker<uint16_t> ())
82     .AddTraceSource ("ConnectionEstablished",
83                      "Connection to the destination web server has been established.",
84                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_connectionEstablishedTrace),
85                      "ns3::ThreeGppHttpClient::TracedCallback")
86     .AddTraceSource ("ConnectionClosed",
87                      "Connection to the destination web server is closed.",
88                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_connectionClosedTrace),
89                      "ns3::ThreeGppHttpClient::TracedCallback")
90     .AddTraceSource ("Tx",
91                      "General trace for sending a packet of any kind.",
92                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_txTrace),
93                      "ns3::Packet::TracedCallback")
94     .AddTraceSource ("TxMainObjectRequest",
95                      "Sent a request for a main object.",
96                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_txMainObjectRequestTrace),
97                      "ns3::Packet::TracedCallback")
98     .AddTraceSource ("TxEmbeddedObjectRequest",
99                      "Sent a request for an embedded object.",
100                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_txEmbeddedObjectRequestTrace),
101                      "ns3::Packet::TracedCallback")
102     .AddTraceSource ("RxMainObjectPacket",
103                      "A packet of main object has been received.",
104                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_rxMainObjectPacketTrace),
105                      "ns3::Packet::TracedCallback")
106     .AddTraceSource ("RxMainObject",
107                      "Received a whole main object. Header is included.",
108                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_rxMainObjectTrace),
109                      "ns3::ThreeGppHttpClient::TracedCallback")
110     .AddTraceSource ("RxEmbeddedObjectPacket",
111                      "A packet of embedded object has been received.",
112                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_rxEmbeddedObjectPacketTrace),
113                      "ns3::Packet::TracedCallback")
114     .AddTraceSource ("RxEmbeddedObject",
115                      "Received a whole embedded object. Header is included.",
116                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_rxEmbeddedObjectTrace),
117                      "ns3::ThreeGppHttpClient::TracedCallback")
118     .AddTraceSource ("Rx",
119                      "General trace for receiving a packet of any kind.",
120                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_rxTrace),
121                      "ns3::Packet::PacketAddressTracedCallback")
122     .AddTraceSource ("RxDelay",
123                      "General trace of delay for receiving a complete object.",
124                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_rxDelayTrace),
125                      "ns3::Application::DelayAddressCallback")
126     .AddTraceSource ("RxRtt",
127                      "General trace of round trip delay time for receiving a complete object.",
128                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_rxRttTrace),
129                      "ns3::Application::DelayAddressCallback")
130     .AddTraceSource ("StateTransition",
131                      "Trace fired upon every HTTP client state transition.",
132                      MakeTraceSourceAccessor (&ThreeGppHttpClient::m_stateTransitionTrace),
133                      "ns3::Application::StateTransitionCallback")
134   ;
135   return tid;
136 }
137 
138 
139 Ptr<Socket>
GetSocket() const140 ThreeGppHttpClient::GetSocket () const
141 {
142   return m_socket;
143 }
144 
145 
146 ThreeGppHttpClient::State_t
GetState() const147 ThreeGppHttpClient::GetState () const
148 {
149   return m_state;
150 }
151 
152 
153 std::string
GetStateString() const154 ThreeGppHttpClient::GetStateString () const
155 {
156   return GetStateString (m_state);
157 }
158 
159 // static
160 std::string
GetStateString(ThreeGppHttpClient::State_t state)161 ThreeGppHttpClient::GetStateString (ThreeGppHttpClient::State_t state)
162 {
163   switch (state)
164     {
165     case NOT_STARTED:
166       return "NOT_STARTED";
167       break;
168     case CONNECTING:
169       return "CONNECTING";
170       break;
171     case EXPECTING_MAIN_OBJECT:
172       return "EXPECTING_MAIN_OBJECT";
173       break;
174     case PARSING_MAIN_OBJECT:
175       return "PARSING_MAIN_OBJECT";
176       break;
177     case EXPECTING_EMBEDDED_OBJECT:
178       return "EXPECTING_EMBEDDED_OBJECT";
179       break;
180     case READING:
181       return "READING";
182       break;
183     case STOPPED:
184       return "STOPPED";
185       break;
186     default:
187       NS_FATAL_ERROR ("Unknown state");
188       return "FATAL_ERROR";
189       break;
190     }
191 }
192 
193 
194 void
DoDispose()195 ThreeGppHttpClient::DoDispose ()
196 {
197   NS_LOG_FUNCTION (this);
198 
199   if (!Simulator::IsFinished ())
200     {
201       StopApplication ();
202     }
203 
204   Application::DoDispose (); // Chain up.
205 }
206 
207 
208 void
StartApplication()209 ThreeGppHttpClient::StartApplication ()
210 {
211   NS_LOG_FUNCTION (this);
212 
213   if (m_state == NOT_STARTED)
214     {
215       m_httpVariables->Initialize ();
216       OpenConnection ();
217     }
218   else
219     {
220       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
221                                        << " for StartApplication().");
222     }
223 }
224 
225 
226 void
StopApplication()227 ThreeGppHttpClient::StopApplication ()
228 {
229   NS_LOG_FUNCTION (this);
230 
231   SwitchToState (STOPPED);
232   CancelAllPendingEvents ();
233   m_socket->Close ();
234   m_socket->SetConnectCallback (MakeNullCallback<void, Ptr<Socket> > (),
235                                 MakeNullCallback<void, Ptr<Socket> > ());
236   m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
237 }
238 
239 
240 void
ConnectionSucceededCallback(Ptr<Socket> socket)241 ThreeGppHttpClient::ConnectionSucceededCallback (Ptr<Socket> socket)
242 {
243   NS_LOG_FUNCTION (this << socket);
244 
245   if (m_state == CONNECTING)
246     {
247       NS_ASSERT_MSG (m_socket == socket, "Invalid socket.");
248       m_connectionEstablishedTrace (this);
249       socket->SetRecvCallback (MakeCallback (&ThreeGppHttpClient::ReceivedDataCallback,
250                                              this));
251       NS_ASSERT (m_embeddedObjectsToBeRequested == 0);
252       m_eventRequestMainObject = Simulator::ScheduleNow (
253           &ThreeGppHttpClient::RequestMainObject, this);
254     }
255   else
256     {
257       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
258                                        << " for ConnectionSucceeded().");
259     }
260 }
261 
262 
263 void
ConnectionFailedCallback(Ptr<Socket> socket)264 ThreeGppHttpClient::ConnectionFailedCallback (Ptr<Socket> socket)
265 {
266   NS_LOG_FUNCTION (this << socket);
267 
268   if (m_state == CONNECTING)
269     {
270       NS_LOG_ERROR ("Client failed to connect"
271                     << " to remote address " << m_remoteServerAddress
272                     << " port " << m_remoteServerPort << ".");
273     }
274   else
275     {
276       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
277                                        << " for ConnectionFailed().");
278     }
279 }
280 
281 
282 void
NormalCloseCallback(Ptr<Socket> socket)283 ThreeGppHttpClient::NormalCloseCallback (Ptr<Socket> socket)
284 {
285   NS_LOG_FUNCTION (this << socket);
286 
287   CancelAllPendingEvents ();
288 
289   if (socket->GetErrno () != Socket::ERROR_NOTERROR)
290     {
291       NS_LOG_ERROR (this << " Connection has been terminated,"
292                          << " error code: " << socket->GetErrno () << ".");
293     }
294 
295   m_socket->SetCloseCallbacks (MakeNullCallback<void, Ptr<Socket> > (),
296                                MakeNullCallback<void, Ptr<Socket> > ());
297 
298   m_connectionClosedTrace (this);
299 }
300 
301 
302 void
ErrorCloseCallback(Ptr<Socket> socket)303 ThreeGppHttpClient::ErrorCloseCallback (Ptr<Socket> socket)
304 {
305   NS_LOG_FUNCTION (this << socket);
306 
307   CancelAllPendingEvents ();
308   if (socket->GetErrno () != Socket::ERROR_NOTERROR)
309     {
310       NS_LOG_ERROR (this << " Connection has been terminated,"
311                          << " error code: " << socket->GetErrno () << ".");
312     }
313 
314   m_connectionClosedTrace (this);
315 }
316 
317 
318 void
ReceivedDataCallback(Ptr<Socket> socket)319 ThreeGppHttpClient::ReceivedDataCallback (Ptr<Socket> socket)
320 {
321   NS_LOG_FUNCTION (this << socket);
322 
323   Ptr<Packet> packet;
324   Address from;
325 
326   while ((packet = socket->RecvFrom (from)))
327     {
328       if (packet->GetSize () == 0)
329         {
330           break; // EOF
331         }
332 
333 #ifdef NS3_LOG_ENABLE
334       // Some log messages.
335       if (InetSocketAddress::IsMatchingType (from))
336         {
337           NS_LOG_INFO (this << " A packet of " << packet->GetSize () << " bytes"
338                             << " received from " << InetSocketAddress::ConvertFrom (from).GetIpv4 ()
339                             << " port " << InetSocketAddress::ConvertFrom (from).GetPort ()
340                             << " / " << InetSocketAddress::ConvertFrom (from) << ".");
341         }
342       else if (Inet6SocketAddress::IsMatchingType (from))
343         {
344           NS_LOG_INFO (this << " A packet of " << packet->GetSize () << " bytes"
345                             << " received from " << Inet6SocketAddress::ConvertFrom (from).GetIpv6 ()
346                             << " port " << Inet6SocketAddress::ConvertFrom (from).GetPort ()
347                             << " / " << Inet6SocketAddress::ConvertFrom (from) << ".");
348         }
349 #endif /* NS3_LOG_ENABLE */
350 
351       m_rxTrace (packet, from);
352 
353       switch (m_state)
354         {
355         case EXPECTING_MAIN_OBJECT:
356           ReceiveMainObject (packet, from);
357           break;
358         case EXPECTING_EMBEDDED_OBJECT:
359           ReceiveEmbeddedObject (packet, from);
360           break;
361         default:
362           NS_FATAL_ERROR ("Invalid state " << GetStateString ()
363                                            << " for ReceivedData().");
364           break;
365         }
366 
367     } // end of `while ((packet = socket->RecvFrom (from)))`
368 
369 } // end of `void ReceivedDataCallback (Ptr<Socket> socket)`
370 
371 
372 void
OpenConnection()373 ThreeGppHttpClient::OpenConnection ()
374 {
375   NS_LOG_FUNCTION (this);
376 
377   if (m_state == NOT_STARTED || m_state == EXPECTING_EMBEDDED_OBJECT
378       || m_state == PARSING_MAIN_OBJECT || m_state == READING)
379     {
380       m_socket = Socket::CreateSocket (GetNode (),
381                                        TcpSocketFactory::GetTypeId ());
382 
383       int ret;
384 
385       if (Ipv4Address::IsMatchingType (m_remoteServerAddress))
386         {
387           ret = m_socket->Bind ();
388           NS_LOG_DEBUG (this << " Bind() return value= " << ret
389                              << " GetErrNo= " << m_socket->GetErrno () << ".");
390 
391           Ipv4Address ipv4 = Ipv4Address::ConvertFrom (m_remoteServerAddress);
392           InetSocketAddress inetSocket = InetSocketAddress (ipv4,
393                                                             m_remoteServerPort);
394           NS_LOG_INFO (this << " Connecting to " << ipv4
395                             << " port " << m_remoteServerPort
396                             << " / " << inetSocket << ".");
397           ret = m_socket->Connect (inetSocket);
398           NS_LOG_DEBUG (this << " Connect() return value= " << ret
399                              << " GetErrNo= " << m_socket->GetErrno () << ".");
400         }
401       else if (Ipv6Address::IsMatchingType (m_remoteServerAddress))
402         {
403           ret = m_socket->Bind6 ();
404           NS_LOG_DEBUG (this << " Bind6() return value= " << ret
405                              << " GetErrNo= " << m_socket->GetErrno () << ".");
406 
407           Ipv6Address ipv6 = Ipv6Address::ConvertFrom (m_remoteServerAddress);
408           Inet6SocketAddress inet6Socket = Inet6SocketAddress (ipv6,
409                                                                m_remoteServerPort);
410           NS_LOG_INFO (this << " connecting to " << ipv6
411                             << " port " << m_remoteServerPort
412                             << " / " << inet6Socket << ".");
413           ret = m_socket->Connect (inet6Socket);
414           NS_LOG_DEBUG (this << " Connect() return value= " << ret
415                              << " GetErrNo= " << m_socket->GetErrno () << ".");
416         }
417 
418       NS_UNUSED (ret); // Mute compiler warning.
419       NS_ASSERT_MSG (m_socket != 0, "Failed creating socket.");
420 
421       SwitchToState (CONNECTING);
422 
423       m_socket->SetConnectCallback (MakeCallback (&ThreeGppHttpClient::ConnectionSucceededCallback,
424                                                   this),
425                                     MakeCallback (&ThreeGppHttpClient::ConnectionFailedCallback,
426                                                   this));
427       m_socket->SetCloseCallbacks (MakeCallback (&ThreeGppHttpClient::NormalCloseCallback,
428                                                  this),
429                                    MakeCallback (&ThreeGppHttpClient::ErrorCloseCallback,
430                                                  this));
431       m_socket->SetRecvCallback (MakeCallback (&ThreeGppHttpClient::ReceivedDataCallback,
432                                                this));
433       m_socket->SetAttribute ("MaxSegLifetime", DoubleValue (0.02)); // 20 ms.
434 
435     } // end of `if (m_state == {NOT_STARTED, EXPECTING_EMBEDDED_OBJECT, PARSING_MAIN_OBJECT, READING})`
436   else
437     {
438       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
439                                        << " for OpenConnection().");
440     }
441 
442 } // end of `void OpenConnection ()`
443 
444 
445 void
RequestMainObject()446 ThreeGppHttpClient::RequestMainObject ()
447 {
448   NS_LOG_FUNCTION (this);
449 
450   if (m_state == CONNECTING || m_state == READING)
451     {
452       ThreeGppHttpHeader header;
453       header.SetContentLength (0); // Request does not need any content length.
454       header.SetContentType (ThreeGppHttpHeader::MAIN_OBJECT);
455       header.SetClientTs (Simulator::Now ());
456 
457       const uint32_t requestSize = m_httpVariables->GetRequestSize ();
458       Ptr<Packet> packet = Create<Packet> (requestSize);
459       packet->AddHeader (header);
460       const uint32_t packetSize = packet->GetSize ();
461       m_txMainObjectRequestTrace (packet);
462       m_txTrace (packet);
463       const int actualBytes = m_socket->Send (packet);
464       NS_LOG_DEBUG (this << " Send() packet " << packet
465                          << " of " << packet->GetSize () << " bytes,"
466                          << " return value= " << actualBytes << ".");
467       if (actualBytes != static_cast<int> (packetSize))
468         {
469           NS_LOG_ERROR (this << " Failed to send request for embedded object,"
470                              << " GetErrNo= " << m_socket->GetErrno () << ","
471                              << " waiting for another Tx opportunity.");
472         }
473       else
474         {
475           SwitchToState (EXPECTING_MAIN_OBJECT);
476         }
477     }
478   else
479     {
480       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
481                                        << " for RequestMainObject().");
482     }
483 
484 } // end of `void RequestMainObject ()`
485 
486 
487 void
RequestEmbeddedObject()488 ThreeGppHttpClient::RequestEmbeddedObject ()
489 {
490   NS_LOG_FUNCTION (this);
491 
492   if (m_state == CONNECTING || m_state == PARSING_MAIN_OBJECT
493       || m_state == EXPECTING_EMBEDDED_OBJECT)
494     {
495       if (m_embeddedObjectsToBeRequested > 0)
496         {
497           ThreeGppHttpHeader header;
498           header.SetContentLength (0); // Request does not need any content length.
499           header.SetContentType (ThreeGppHttpHeader::EMBEDDED_OBJECT);
500           header.SetClientTs (Simulator::Now ());
501 
502           const uint32_t requestSize = m_httpVariables->GetRequestSize ();
503           Ptr<Packet> packet = Create<Packet> (requestSize);
504           packet->AddHeader (header);
505           const uint32_t packetSize = packet->GetSize ();
506           m_txEmbeddedObjectRequestTrace (packet);
507           m_txTrace (packet);
508           const int actualBytes = m_socket->Send (packet);
509           NS_LOG_DEBUG (this << " Send() packet " << packet
510                              << " of " << packet->GetSize () << " bytes,"
511                              << " return value= " << actualBytes << ".");
512 
513           if (actualBytes != static_cast<int> (packetSize))
514             {
515               NS_LOG_ERROR (this << " Failed to send request for embedded object,"
516                                  << " GetErrNo= " << m_socket->GetErrno () << ","
517                                  << " waiting for another Tx opportunity.");
518             }
519           else
520             {
521               m_embeddedObjectsToBeRequested--;
522               SwitchToState (EXPECTING_EMBEDDED_OBJECT);
523             }
524         }
525       else
526         {
527           NS_LOG_WARN (this << " No embedded object to be requested.");
528         }
529     }
530   else
531     {
532       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
533                                        << " for RequestEmbeddedObject().");
534     }
535 
536 } // end of `void RequestEmbeddedObject ()`
537 
538 
539 void
ReceiveMainObject(Ptr<Packet> packet,const Address & from)540 ThreeGppHttpClient::ReceiveMainObject (Ptr<Packet> packet, const Address &from)
541 {
542   NS_LOG_FUNCTION (this << packet << from);
543 
544   if (m_state == EXPECTING_MAIN_OBJECT)
545     {
546       /*
547        * In the following call to Receive(), #m_objectBytesToBeReceived *will*
548        * be updated. #m_objectClientTs and #m_objectServerTs *may* be updated.
549        * ThreeGppHttpHeader will be removed from the packet, if it is the first
550        * packet of the object to be received; the header will be available in
551        * #m_constructedPacketHeader.
552        * #m_constructedPacket will also be updated.
553        */
554       Receive (packet);
555       m_rxMainObjectPacketTrace (packet);
556 
557       if (m_objectBytesToBeReceived > 0)
558         {
559           /*
560            * There are more packets of this main object, so just stay still
561            * and wait until they arrive.
562            */
563           NS_LOG_INFO (this << " " << m_objectBytesToBeReceived << " byte(s)"
564                             << " remains from this chunk of main object.");
565         }
566       else
567         {
568           /*
569            * This is the last packet of this main object. Acknowledge the
570            * reception of a whole main object
571            */
572           NS_LOG_INFO (this << " Finished receiving a main object.");
573           m_rxMainObjectTrace (this, m_constructedPacket);
574 
575           if (!m_objectServerTs.IsZero ())
576             {
577               m_rxDelayTrace (Simulator::Now () - m_objectServerTs, from);
578               m_objectServerTs = MilliSeconds (0); // Reset back to zero.
579             }
580 
581           if (!m_objectClientTs.IsZero ())
582             {
583               m_rxRttTrace (Simulator::Now () - m_objectClientTs, from);
584               m_objectClientTs = MilliSeconds (0); // Reset back to zero.
585             }
586 
587           EnterParsingTime ();
588 
589         } // end of else of `if (m_objectBytesToBeReceived > 0)`
590 
591     } // end of `if (m_state == EXPECTING_MAIN_OBJECT)`
592   else
593     {
594       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
595                                        << " for ReceiveMainObject().");
596     }
597 
598 } // end of `void ReceiveMainObject (Ptr<Packet> packet)`
599 
600 
601 void
ReceiveEmbeddedObject(Ptr<Packet> packet,const Address & from)602 ThreeGppHttpClient::ReceiveEmbeddedObject (Ptr<Packet> packet, const Address &from)
603 {
604   NS_LOG_FUNCTION (this << packet << from);
605 
606   if (m_state == EXPECTING_EMBEDDED_OBJECT)
607     {
608       /*
609        * In the following call to Receive(), #m_objectBytesToBeReceived *will*
610        * be updated. #m_objectClientTs and #m_objectServerTs *may* be updated.
611        * ThreeGppHttpHeader will be removed from the packet, if it is the first
612        * packet of the object to be received; the header will be available in
613        * #m_constructedPacket, which will also be updated.
614        */
615       Receive (packet);
616       m_rxEmbeddedObjectPacketTrace (packet);
617 
618       if (m_objectBytesToBeReceived > 0)
619         {
620           /*
621            * There are more packets of this embedded object, so just stay
622            * still and wait until they arrive.
623            */
624           NS_LOG_INFO (this << " " << m_objectBytesToBeReceived << " byte(s)"
625                             << " remains from this chunk of embedded object");
626         }
627       else
628         {
629           /*
630            * This is the last packet of this embedded object. Acknowledge
631            * the reception of a whole embedded object
632            */
633           NS_LOG_INFO (this << " Finished receiving an embedded object.");
634           m_rxEmbeddedObjectTrace (this, m_constructedPacket);
635 
636           if (!m_objectServerTs.IsZero ())
637             {
638               m_rxDelayTrace (Simulator::Now () - m_objectServerTs, from);
639               m_objectServerTs = MilliSeconds (0); // Reset back to zero.
640             }
641 
642           if (!m_objectClientTs.IsZero ())
643             {
644               m_rxRttTrace (Simulator::Now () - m_objectClientTs, from);
645               m_objectClientTs = MilliSeconds (0); // Reset back to zero.
646             }
647 
648           if (m_embeddedObjectsToBeRequested > 0)
649             {
650               NS_LOG_INFO (this << " " << m_embeddedObjectsToBeRequested
651                                 << " more embedded object(s) to be requested.");
652               // Immediately request another using the existing connection.
653               m_eventRequestEmbeddedObject = Simulator::ScheduleNow (
654                   &ThreeGppHttpClient::RequestEmbeddedObject, this);
655             }
656           else
657             {
658               /*
659                * There is no more embedded object, the web page has been
660                * downloaded completely. Now is the time to read it.
661                */
662               NS_LOG_INFO (this << " Finished receiving a web page.");
663               EnterReadingTime ();
664             }
665 
666         } // end of else of `if (m_objectBytesToBeReceived > 0)`
667 
668     } // end of `if (m_state == EXPECTING_EMBEDDED_OBJECT)`
669   else
670     {
671       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
672                                        << " for ReceiveEmbeddedObject().");
673     }
674 
675 } // end of `void ReceiveEmbeddedObject (Ptr<Packet> packet)`
676 
677 
678 void
Receive(Ptr<Packet> packet)679 ThreeGppHttpClient::Receive (Ptr<Packet> packet)
680 {
681   NS_LOG_FUNCTION (this << packet);
682 
683   /* In a "real" HTTP message the message size is coded differently. The use of a header
684    * is to avoid the burden of doing a real message parser.
685    */
686   bool firstPacket = false;
687 
688   if (m_objectBytesToBeReceived == 0)
689     {
690       // This is the first packet of the object.
691       firstPacket = true;
692 
693       // Remove the header in order to calculate remaining data to be received.
694       ThreeGppHttpHeader httpHeader;
695       packet->RemoveHeader (httpHeader);
696 
697       m_objectBytesToBeReceived = httpHeader.GetContentLength ();
698       m_objectClientTs = httpHeader.GetClientTs ();
699       m_objectServerTs = httpHeader.GetServerTs ();
700 
701       // Take a copy for constructed packet trace. Note that header is included.
702       m_constructedPacket = packet->Copy ();
703       m_constructedPacket->AddHeader (httpHeader);
704     }
705   uint32_t contentSize = packet->GetSize ();
706 
707   /* Note that the packet does not contain header at this point.
708    * The content is purely raw data, which was the only intended data to be received.
709    */
710   if (m_objectBytesToBeReceived < contentSize)
711     {
712       NS_LOG_WARN (this << " The received packet"
713                         << " (" << contentSize << " bytes of content)"
714                         << " is larger than"
715                         << " the content that we expected to receive"
716                         << " (" << m_objectBytesToBeReceived << " bytes).");
717       // Stop expecting any more packet of this object.
718       m_objectBytesToBeReceived = 0;
719       m_constructedPacket = NULL;
720     }
721   else
722     {
723       m_objectBytesToBeReceived -= contentSize;
724       if (!firstPacket)
725         {
726           Ptr<Packet> packetCopy = packet->Copy ();
727           m_constructedPacket->AddAtEnd (packetCopy);
728         }
729     }
730 
731 } // end of `void Receive (packet)`
732 
733 
734 void
EnterParsingTime()735 ThreeGppHttpClient::EnterParsingTime ()
736 {
737   NS_LOG_FUNCTION (this);
738 
739   if (m_state == EXPECTING_MAIN_OBJECT)
740     {
741       const Time parsingTime = m_httpVariables->GetParsingTime ();
742       NS_LOG_INFO (this << " The parsing of this main object"
743                         << " will complete in "
744                         << parsingTime.As (Time::S) << ".");
745       m_eventParseMainObject = Simulator::Schedule (
746           parsingTime, &ThreeGppHttpClient::ParseMainObject, this);
747       SwitchToState (PARSING_MAIN_OBJECT);
748     }
749   else
750     {
751       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
752                                        << " for EnterParsingTime().");
753     }
754 }
755 
756 
757 void
ParseMainObject()758 ThreeGppHttpClient::ParseMainObject ()
759 {
760   NS_LOG_FUNCTION (this);
761 
762   if (m_state == PARSING_MAIN_OBJECT)
763     {
764       m_embeddedObjectsToBeRequested = m_httpVariables->GetNumOfEmbeddedObjects ();
765       NS_LOG_INFO (this << " Parsing has determined "
766                         << m_embeddedObjectsToBeRequested
767                         << " embedded object(s) in the main object.");
768 
769       if (m_embeddedObjectsToBeRequested > 0)
770         {
771           /*
772            * Immediately request the first embedded object using the
773            * existing connection.
774            */
775           m_eventRequestEmbeddedObject = Simulator::ScheduleNow (
776               &ThreeGppHttpClient::RequestEmbeddedObject, this);
777         }
778       else
779         {
780           /*
781            * There is no embedded object in the main object. So sit back and
782            * enjoy the plain web page.
783            */
784           NS_LOG_INFO (this << " Finished receiving a web page.");
785           EnterReadingTime ();
786         }
787 
788     }
789   else
790     {
791       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
792                                        << " for ParseMainObject().");
793     }
794 
795 } // end of `void ParseMainObject ()`
796 
797 
798 void
EnterReadingTime()799 ThreeGppHttpClient::EnterReadingTime ()
800 {
801   NS_LOG_FUNCTION (this);
802 
803   if (m_state == EXPECTING_EMBEDDED_OBJECT || m_state == PARSING_MAIN_OBJECT)
804     {
805       const Time readingTime = m_httpVariables->GetReadingTime ();
806       NS_LOG_INFO (this << " Client will finish reading this web page in "
807                         << readingTime.As (Time::S) << ".");
808 
809       // Schedule a request of another main object once the reading time expires.
810       m_eventRequestMainObject = Simulator::Schedule (
811           readingTime, &ThreeGppHttpClient::RequestMainObject, this);
812       SwitchToState (READING);
813     }
814   else
815     {
816       NS_FATAL_ERROR ("Invalid state " << GetStateString ()
817                                        << " for EnterReadingTime().");
818     }
819 }
820 
821 
822 void
CancelAllPendingEvents()823 ThreeGppHttpClient::CancelAllPendingEvents ()
824 {
825   NS_LOG_FUNCTION (this);
826 
827   if (!Simulator::IsExpired (m_eventRequestMainObject))
828     {
829       NS_LOG_INFO (this << " Canceling RequestMainObject() which is due in "
830                         << Simulator::GetDelayLeft (m_eventRequestMainObject).As (Time::S)
831                         << ".");
832       Simulator::Cancel (m_eventRequestMainObject);
833     }
834 
835   if (!Simulator::IsExpired (m_eventRequestEmbeddedObject))
836     {
837       NS_LOG_INFO (this << " Canceling RequestEmbeddedObject() which is due in "
838                         << Simulator::GetDelayLeft (m_eventRequestEmbeddedObject).As (Time::S)
839                         << ".");
840       Simulator::Cancel (m_eventRequestEmbeddedObject);
841     }
842 
843   if (!Simulator::IsExpired (m_eventParseMainObject))
844     {
845       NS_LOG_INFO (this << " Canceling ParseMainObject() which is due in "
846                         << Simulator::GetDelayLeft (m_eventParseMainObject).As (Time::S)
847                         << ".");
848       Simulator::Cancel (m_eventParseMainObject);
849     }
850 }
851 
852 
853 void
SwitchToState(ThreeGppHttpClient::State_t state)854 ThreeGppHttpClient::SwitchToState (ThreeGppHttpClient::State_t state)
855 {
856   const std::string oldState = GetStateString ();
857   const std::string newState = GetStateString (state);
858   NS_LOG_FUNCTION (this << oldState << newState);
859 
860   if ((state == EXPECTING_MAIN_OBJECT) || (state == EXPECTING_EMBEDDED_OBJECT))
861     {
862       if (m_objectBytesToBeReceived > 0)
863         {
864           NS_FATAL_ERROR ("Cannot start a new receiving session"
865                           << " if the previous object"
866                           << " (" << m_objectBytesToBeReceived << " bytes)"
867                           << " is not completely received yet.");
868         }
869     }
870 
871   m_state = state;
872   NS_LOG_INFO (this << " HttpClient " << oldState
873                     << " --> " << newState << ".");
874   m_stateTransitionTrace (oldState, newState);
875 }
876 
877 
878 } // end of `namespace ns3`
879 
880