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