A Discrete-Event Network Simulator
API
three-gpp-http-server.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Magister Solutions
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Budiarto Herman <budiarto.herman@magister.fi>
18  *
19  */
20 
21 #include "three-gpp-http-server.h"
22 
23 #include <ns3/callback.h>
24 #include <ns3/config.h>
25 #include <ns3/inet-socket-address.h>
26 #include <ns3/inet6-socket-address.h>
27 #include <ns3/log.h>
28 #include <ns3/packet.h>
29 #include <ns3/pointer.h>
30 #include <ns3/simulator.h>
31 #include <ns3/socket.h>
32 #include <ns3/tcp-socket-factory.h>
33 #include <ns3/tcp-socket.h>
34 #include <ns3/three-gpp-http-variables.h>
35 #include <ns3/uinteger.h>
36 
37 NS_LOG_COMPONENT_DEFINE("ThreeGppHttpServer");
38 
39 namespace ns3
40 {
41 
42 // HTTP SERVER ////////////////////////////////////////////////////////////////
43 
44 NS_OBJECT_ENSURE_REGISTERED(ThreeGppHttpServer);
45 
47  : m_state(NOT_STARTED),
48  m_initialSocket(nullptr),
49  m_txBuffer(Create<ThreeGppHttpServerTxBuffer>()),
50  m_httpVariables(CreateObject<ThreeGppHttpVariables>())
51 {
52  NS_LOG_FUNCTION(this);
53 
54  m_mtuSize = m_httpVariables->GetMtuSize();
55  NS_LOG_INFO(this << " MTU size for this server application is " << m_mtuSize << " bytes.");
56 }
57 
58 // static
59 TypeId
61 {
62  static TypeId tid =
63  TypeId("ns3::ThreeGppHttpServer")
65  .AddConstructor<ThreeGppHttpServer>()
66  .AddAttribute("Variables",
67  "Variable collection, which is used to control e.g. processing and "
68  "object generation delays.",
69  PointerValue(),
71  MakePointerChecker<ThreeGppHttpVariables>())
72  .AddAttribute("LocalAddress",
73  "The local address of the server, "
74  "i.e., the address on which to bind the Rx socket.",
75  AddressValue(),
76  MakeAddressAccessor(&ThreeGppHttpServer::m_localAddress),
77  MakeAddressChecker())
78  .AddAttribute("LocalPort",
79  "Port on which the application listen for incoming packets.",
80  UintegerValue(80), // the default HTTP port
82  MakeUintegerChecker<uint16_t>())
83  .AddAttribute("Mtu",
84  "Maximum transmission unit (in bytes) of the TCP sockets "
85  "used in this application, excluding the compulsory 40 "
86  "bytes TCP header. Typical values are 1460 and 536 bytes. "
87  "The attribute is read-only because the value is randomly "
88  "determined.",
90  UintegerValue(),
92  MakeUintegerChecker<uint32_t>())
93  .AddTraceSource(
94  "ConnectionEstablished",
95  "Connection to a remote web client has been established.",
97  "ns3::HttpServer::ConnectionEstablishedCallback")
98  .AddTraceSource("MainObject",
99  "A main object has been generated.",
101  "ns3::HttpServer::HttpObjectCallback")
102  .AddTraceSource("EmbeddedObject",
103  "An embedded object has been generated.",
105  "ns3::HttpServer::HttpObjectCallback")
106  .AddTraceSource("Tx",
107  "A packet has been sent.",
109  "ns3::Packet::TracedCallback")
110  .AddTraceSource("Rx",
111  "A packet has been received.",
113  "ns3::Packet::PacketAddressTracedCallback")
114  .AddTraceSource("RxDelay",
115  "A packet has been received with delay information.",
117  "ns3::Application::DelayAddressCallback")
118  .AddTraceSource("StateTransition",
119  "Trace fired upon every HTTP client state transition.",
121  "ns3::Application::StateTransitionCallback");
122  return tid;
123 }
124 
125 void
127 {
128  NS_LOG_FUNCTION(this << mtuSize);
129  m_mtuSize = mtuSize;
130 }
131 
134 {
135  return m_initialSocket;
136 }
137 
140 {
141  return m_state;
142 }
143 
144 std::string
146 {
147  return GetStateString(m_state);
148 }
149 
150 // static
151 std::string
153 {
154  switch (state)
155  {
156  case NOT_STARTED:
157  return "NOT_STARTED";
158  break;
159  case STARTED:
160  return "STARTED";
161  break;
162  case STOPPED:
163  return "STOPPED";
164  break;
165  default:
166  NS_FATAL_ERROR("Unknown state");
167  return "FATAL_ERROR";
168  break;
169  }
170 }
171 
172 void
174 {
175  NS_LOG_FUNCTION(this);
176 
177  if (!Simulator::IsFinished())
178  {
179  StopApplication();
180  }
181 
182  Application::DoDispose(); // Chain up.
183 }
184 
185 void
187 {
188  NS_LOG_FUNCTION(this);
189 
190  if (m_state == NOT_STARTED)
191  {
192  m_httpVariables->Initialize();
193  if (!m_initialSocket)
194  {
195  // Find the current default MTU value of TCP sockets.
196  Ptr<const ns3::AttributeValue> previousSocketMtu;
197  const TypeId tcpSocketTid = TcpSocket::GetTypeId();
198  for (uint32_t i = 0; i < tcpSocketTid.GetAttributeN(); i++)
199  {
200  struct TypeId::AttributeInformation attrInfo = tcpSocketTid.GetAttribute(i);
201  if (attrInfo.name == "SegmentSize")
202  {
203  previousSocketMtu = attrInfo.initialValue;
204  }
205  }
206 
207  // Creating a TCP socket to connect to the server.
210 
212  {
214  const InetSocketAddress inetSocket = InetSocketAddress(ipv4, m_localPort);
215  NS_LOG_INFO(this << " Binding on " << ipv4 << " port " << m_localPort << " / "
216  << inetSocket << ".");
217  int ret [[maybe_unused]] = m_initialSocket->Bind(inetSocket);
218  NS_LOG_DEBUG(this << " Bind() return value= " << ret
219  << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
220  }
222  {
224  const Inet6SocketAddress inet6Socket = Inet6SocketAddress(ipv6, m_localPort);
225  NS_LOG_INFO(this << " Binding on " << ipv6 << " port " << m_localPort << " / "
226  << inet6Socket << ".");
227  int ret [[maybe_unused]] = m_initialSocket->Bind(inet6Socket);
228  NS_LOG_DEBUG(this << " Bind() return value= " << ret
229  << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
230  }
231 
232  int ret [[maybe_unused]] = m_initialSocket->Listen();
233  NS_LOG_DEBUG(this << " Listen () return value= " << ret
234  << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
235 
236  } // end of `if (m_initialSocket == 0)`
237 
238  NS_ASSERT_MSG(m_initialSocket, "Failed creating socket.");
249 
250  } // end of `if (m_state == NOT_STARTED)`
251  else
252  {
253  NS_FATAL_ERROR("Invalid state " << GetStateString() << " for StartApplication().");
254  }
255 
256 } // end of `void StartApplication ()`
257 
258 void
260 {
261  NS_LOG_FUNCTION(this);
262 
264 
265  // Close all accepted sockets.
266  m_txBuffer->CloseAllSockets();
267 
268  // Stop listening.
269  if (m_initialSocket)
270  {
273  MakeNullCallback<void, Ptr<Socket>, const Address&>());
275  MakeNullCallback<void, Ptr<Socket>>());
278  }
279 }
280 
281 bool
283 {
284  NS_LOG_FUNCTION(this << socket << address);
285  return true; // Unconditionally accept the connection request.
286 }
287 
288 void
290 {
291  NS_LOG_FUNCTION(this << socket << address);
292 
297 
298  m_connectionEstablishedTrace(this, socket);
299  m_txBuffer->AddSocket(socket);
300 
301  /*
302  * A typical connection is established after receiving an empty (i.e., no
303  * data) TCP packet with ACK flag. The actual data will follow in a separate
304  * packet after that and will be received by ReceivedDataCallback().
305  *
306  * However, that empty ACK packet might get lost. In this case, we may
307  * receive the first data packet right here already, because it also counts
308  * as a new connection. The statement below attempts to fetch the data from
309  * that packet, if any.
310  */
311  ReceivedDataCallback(socket);
312 }
313 
314 void
316 {
317  NS_LOG_FUNCTION(this << socket);
318 
319  if (socket == m_initialSocket)
320  {
321  if (m_state == STARTED)
322  {
323  NS_FATAL_ERROR("Initial listener socket shall not be closed"
324  << " when the server instance is still running.");
325  }
326  }
327  else if (m_txBuffer->IsSocketAvailable(socket))
328  {
329  // The application should now prepare to close the socket.
330  if (m_txBuffer->IsBufferEmpty(socket))
331  {
332  /*
333  * Here we declare that we have nothing more to send and the socket
334  * may be closed immediately.
335  */
336  socket->ShutdownSend();
337  m_txBuffer->RemoveSocket(socket);
338  }
339  else
340  {
341  /*
342  * Remember to close the socket later, whenever the buffer becomes
343  * empty.
344  */
345  m_txBuffer->PrepareClose(socket);
346  }
347  }
348 }
349 
350 void
352 {
353  NS_LOG_FUNCTION(this << socket);
354 
355  if (socket == m_initialSocket)
356  {
357  if (m_state == STARTED)
358  {
359  NS_FATAL_ERROR("Initial listener socket shall not be closed"
360  << " when the server instance is still running.");
361  }
362  }
363  else if (m_txBuffer->IsSocketAvailable(socket))
364  {
365  m_txBuffer->CloseSocket(socket);
366  }
367 }
368 
369 void
371 {
372  NS_LOG_FUNCTION(this << socket);
373 
374  Ptr<Packet> packet;
375  Address from;
376 
377  while ((packet = socket->RecvFrom(from)))
378  {
379  if (packet->GetSize() == 0)
380  {
381  break; // EOF
382  }
383 
384 #ifdef NS3_LOG_ENABLE
385  // Some log messages.
387  {
388  NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
389  << " received from " << InetSocketAddress::ConvertFrom(from).GetIpv4()
390  << " port " << InetSocketAddress::ConvertFrom(from).GetPort() << " / "
392  }
393  else if (Inet6SocketAddress::IsMatchingType(from))
394  {
395  NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
396  << " received from " << Inet6SocketAddress::ConvertFrom(from).GetIpv6()
397  << " port " << Inet6SocketAddress::ConvertFrom(from).GetPort() << " / "
399  }
400 #endif /* NS3_LOG_ENABLE */
401 
402  // Check the header. No need to remove it, since it is not a "real" header.
403  ThreeGppHttpHeader httpHeader;
404  packet->PeekHeader(httpHeader);
405 
406  // Fire trace sources.
407  m_rxTrace(packet, from);
408  m_rxDelayTrace(Simulator::Now() - httpHeader.GetClientTs(), from);
409 
410  Time processingDelay;
411  switch (httpHeader.GetContentType())
412  {
414  processingDelay = m_httpVariables->GetMainObjectGenerationDelay();
415  NS_LOG_INFO(this << " Will finish generating a main object"
416  << " in " << processingDelay.As(Time::S) << ".");
417  m_txBuffer->RecordNextServe(socket,
418  Simulator::Schedule(processingDelay,
420  this,
421  socket),
422  httpHeader.GetClientTs());
423  break;
424 
426  processingDelay = m_httpVariables->GetEmbeddedObjectGenerationDelay();
427  NS_LOG_INFO(this << " Will finish generating an embedded object"
428  << " in " << processingDelay.As(Time::S) << ".");
429  m_txBuffer->RecordNextServe(
430  socket,
431  Simulator::Schedule(processingDelay,
433  this,
434  socket),
435  httpHeader.GetClientTs());
436  break;
437 
438  default:
439  NS_FATAL_ERROR("Invalid packet.");
440  break;
441  }
442 
443  } // end of `while ((packet = socket->RecvFrom (from)))`
444 
445 } // end of `void ReceivedDataCallback (Ptr<Socket> socket)`
446 
447 void
448 ThreeGppHttpServer::SendCallback(Ptr<Socket> socket, uint32_t availableBufferSize)
449 {
450  NS_LOG_FUNCTION(this << socket << availableBufferSize);
451 
452  if (!m_txBuffer->IsBufferEmpty(socket))
453  {
454  const uint32_t txBufferSize [[maybe_unused]] = m_txBuffer->GetBufferSize(socket);
455  const uint32_t actualSent [[maybe_unused]] = ServeFromTxBuffer(socket);
456 
457 #ifdef NS3_LOG_ENABLE
458  // Some log messages.
459  if (actualSent < txBufferSize)
460  {
461  switch (m_txBuffer->GetBufferContentType(socket))
462  {
464  NS_LOG_INFO(this << " Transmission of main object is suspended"
465  << " after " << actualSent << " bytes.");
466  break;
468  NS_LOG_INFO(this << " Transmission of embedded object is suspended"
469  << " after " << actualSent << " bytes.");
470  break;
471  default:
472  NS_FATAL_ERROR("Invalid Tx buffer content type.");
473  break;
474  }
475  }
476  else
477  {
478  switch (m_txBuffer->GetBufferContentType(socket))
479  {
481  NS_LOG_INFO(this << " Finished sending a whole main object.");
482  break;
484  NS_LOG_INFO(this << " Finished sending a whole embedded object.");
485  break;
486  default:
487  NS_FATAL_ERROR("Invalid Tx buffer content type.");
488  break;
489  }
490  }
491 #endif /* NS3_LOG_ENABLE */
492 
493  } // end of `if (m_txBuffer->IsBufferEmpty (socket))`
494 
495 } // end of `void SendCallback (Ptr<Socket> socket, uint32_t availableBufferSize)`
496 
497 void
499 {
500  NS_LOG_FUNCTION(this << socket);
501 
502  const uint32_t objectSize = m_httpVariables->GetMainObjectSize();
503  NS_LOG_INFO(this << " Main object to be served is " << objectSize << " bytes.");
504  m_mainObjectTrace(objectSize);
505  m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::MAIN_OBJECT, objectSize);
506  const uint32_t actualSent = ServeFromTxBuffer(socket);
507 
508  if (actualSent < objectSize)
509  {
510  NS_LOG_INFO(this << " Transmission of main object is suspended"
511  << " after " << actualSent << " bytes.");
512  }
513  else
514  {
515  NS_LOG_INFO(this << " Finished sending a whole main object.");
516  }
517 }
518 
519 void
521 {
522  NS_LOG_FUNCTION(this << socket);
523 
524  const uint32_t objectSize = m_httpVariables->GetEmbeddedObjectSize();
525  NS_LOG_INFO(this << " Embedded object to be served is " << objectSize << " bytes.");
526  m_embeddedObjectTrace(objectSize);
527  m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::EMBEDDED_OBJECT, objectSize);
528  const uint32_t actualSent = ServeFromTxBuffer(socket);
529 
530  if (actualSent < objectSize)
531  {
532  NS_LOG_INFO(this << " Transmission of embedded object is suspended"
533  << " after " << actualSent << " bytes.");
534  }
535  else
536  {
537  NS_LOG_INFO(this << " Finished sending a whole embedded object.");
538  }
539 }
540 
541 uint32_t
543 {
544  NS_LOG_FUNCTION(this << socket);
545 
546  if (m_txBuffer->IsBufferEmpty(socket))
547  {
548  NS_LOG_LOGIC(this << " Tx buffer is empty. Not sending anything.");
549  return 0;
550  }
551  bool firstPartOfObject = !m_txBuffer->HasTxedPartOfObject(socket);
552 
553  const uint32_t socketSize = socket->GetTxAvailable();
554  NS_LOG_DEBUG(this << " Socket has " << socketSize << " bytes available for Tx.");
555 
556  // Get the number of bytes remaining to be sent.
557  const uint32_t txBufferSize = m_txBuffer->GetBufferSize(socket);
558 
559  // Compute the size of actual content to be sent; has to fit into the socket.
560  // Note that header size is NOT counted as TxBuffer content. Header size is overhead.
561  uint32_t contentSize = std::min(txBufferSize, socketSize - 22);
562  Ptr<Packet> packet = Create<Packet>(contentSize);
563  uint32_t packetSize = contentSize;
564  if (packetSize == 0)
565  {
566  NS_LOG_LOGIC(this << " Socket size leads to packet size of zero; not sending anything.");
567  return 0;
568  }
569 
570  // If this is the first packet of an object, attach a header.
571  if (firstPartOfObject)
572  {
573  // Create header.
574  ThreeGppHttpHeader httpHeader;
575  httpHeader.SetContentLength(txBufferSize);
576  httpHeader.SetContentType(m_txBuffer->GetBufferContentType(socket));
577  // Using the client TS value as per the corresponding request packet.
578  httpHeader.SetClientTs(m_txBuffer->GetClientTs(socket));
579  httpHeader.SetServerTs(Simulator::Now());
580  packet->AddHeader(httpHeader);
581  packetSize += httpHeader.GetSerializedSize();
582 
583  NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize << " bytes."
584  << " The corresponding request came "
585  << (Simulator::Now() - httpHeader.GetClientTs()).As(Time::S) << " ago.");
586  }
587  else
588  {
589  NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize
590  << " bytes to be appended to a previous packet.");
591  }
592 
593  // Send.
594  const int actualBytes = socket->Send(packet);
595  NS_LOG_DEBUG(this << " Send() packet " << packet << " of " << packetSize << " bytes,"
596  << " return value= " << actualBytes << ".");
597  m_txTrace(packet);
598 
599  if (actualBytes == static_cast<int>(packetSize))
600  {
601  // The packet goes through successfully.
602  m_txBuffer->DepleteBufferSize(socket, contentSize);
603  NS_LOG_INFO(this << " Remaining object to be sent " << m_txBuffer->GetBufferSize(socket)
604  << " bytes.");
605  return packetSize;
606  }
607  else
608  {
609  NS_LOG_INFO(this << " Failed to send object,"
610  << " GetErrNo= " << socket->GetErrno() << ","
611  << " suspending transmission"
612  << " and waiting for another Tx opportunity.");
613  return 0;
614  }
615 
616 } // end of `uint32_t ServeFromTxBuffer (Ptr<Socket> socket)`
617 
618 void
620 {
621  const std::string oldState = GetStateString();
622  const std::string newState = GetStateString(state);
623  NS_LOG_FUNCTION(this << oldState << newState);
624  m_state = state;
625  NS_LOG_INFO(this << " ThreeGppHttpServer " << oldState << " --> " << newState << ".");
626  m_stateTransitionTrace(oldState, newState);
627 }
628 
629 // HTTP SERVER TX BUFFER //////////////////////////////////////////////////////
630 
632 {
633  NS_LOG_FUNCTION(this);
634 }
635 
636 bool
638 {
639  std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
640  it = m_txBuffer.find(socket);
641  return (it != m_txBuffer.end());
642 }
643 
644 void
646 {
647  NS_LOG_FUNCTION(this << socket);
648 
650  this << " Cannot add socket " << socket
651  << " because it has already been added before.");
652 
653  TxBuffer_t txBuffer;
655  txBuffer.txBufferSize = 0;
656  txBuffer.isClosing = false;
657  txBuffer.hasTxedPartOfObject = false;
658  m_txBuffer.insert(std::pair<Ptr<Socket>, TxBuffer_t>(socket, txBuffer));
659 }
660 
661 void
663 {
664  NS_LOG_FUNCTION(this << socket);
665 
666  std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
667  it = m_txBuffer.find(socket);
668  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
669 
670  if (!Simulator::IsExpired(it->second.nextServe))
671  {
672  NS_LOG_INFO(this << " Canceling a serving event which is due in "
673  << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
674  Simulator::Cancel(it->second.nextServe);
675  }
676 
677  it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
678  MakeNullCallback<void, Ptr<Socket>>());
679  it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
680  it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
681 
682  m_txBuffer.erase(it);
683 }
684 
685 void
687 {
688  NS_LOG_FUNCTION(this << socket);
689 
690  std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
691  it = m_txBuffer.find(socket);
692  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
693 
694  if (!Simulator::IsExpired(it->second.nextServe))
695  {
696  NS_LOG_INFO(this << " Canceling a serving event which is due in "
697  << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
698  Simulator::Cancel(it->second.nextServe);
699  }
700 
701  if (it->second.txBufferSize > 0)
702  {
703  NS_LOG_WARN(this << " Closing a socket where " << it->second.txBufferSize
704  << " bytes of transmission"
705  << " is still pending in the corresponding Tx buffer.");
706  }
707 
708  it->first->Close();
709  it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
710  MakeNullCallback<void, Ptr<Socket>>());
711  it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
712  it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
713 
714  m_txBuffer.erase(it);
715 }
716 
717 void
719 {
720  NS_LOG_FUNCTION(this);
721 
722  std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
723  for (it = m_txBuffer.begin(); it != m_txBuffer.end(); ++it)
724  {
725  if (!Simulator::IsExpired(it->second.nextServe))
726  {
727  NS_LOG_INFO(this << " Canceling a serving event which is due in "
728  << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
729  Simulator::Cancel(it->second.nextServe);
730  }
731 
732  it->first->Close();
733  it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
734  MakeNullCallback<void, Ptr<Socket>>());
735  it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
736  it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
737  }
738 
739  m_txBuffer.clear();
740 }
741 
742 bool
744 {
745  std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
746  it = m_txBuffer.find(socket);
747  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
748  return (it->second.txBufferSize == 0);
749 }
750 
751 Time
753 {
754  std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
755  it = m_txBuffer.find(socket);
756  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
757  return it->second.clientTs;
758 }
759 
762 {
763  std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
764  it = m_txBuffer.find(socket);
765  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
766  return it->second.txBufferContentType;
767 }
768 
769 uint32_t
771 {
772  std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
773  it = m_txBuffer.find(socket);
774  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
775  return it->second.txBufferSize;
776 }
777 
778 bool
780 {
781  std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
782  it = m_txBuffer.find(socket);
783  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found");
784  return it->second.hasTxedPartOfObject;
785 }
786 
787 void
790  uint32_t objectSize)
791 {
792  NS_LOG_FUNCTION(this << socket << contentType << objectSize);
793 
795  "Unable to write an object without a proper Content-Type.");
796  NS_ASSERT_MSG(objectSize > 0, "Unable to write a zero-sized object.");
797 
798  std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
799  it = m_txBuffer.find(socket);
800  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
801  NS_ASSERT_MSG(it->second.txBufferSize == 0,
802  "Cannot write to Tx buffer of socket "
803  << socket << " until the previous content has been completely sent.");
804  it->second.txBufferContentType = contentType;
805  it->second.txBufferSize = objectSize;
806  it->second.hasTxedPartOfObject = false;
807 }
808 
809 void
811  const EventId& eventId,
812  const Time& clientTs)
813 {
814  NS_LOG_FUNCTION(this << socket << clientTs.As(Time::S));
815 
816  std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
817  it = m_txBuffer.find(socket);
818  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
819  it->second.nextServe = eventId;
820  it->second.clientTs = clientTs;
821 }
822 
823 void
825 {
826  NS_LOG_FUNCTION(this << socket << amount);
827 
828  NS_ASSERT_MSG(amount > 0, "Unable to consume zero bytes.");
829 
830  std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
831  it = m_txBuffer.find(socket);
832  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
833  NS_ASSERT_MSG(it->second.txBufferSize >= amount,
834  "The requested amount is larger than the current buffer size.");
835  it->second.txBufferSize -= amount;
836  it->second.hasTxedPartOfObject = true;
837 
838  if (it->second.isClosing && (it->second.txBufferSize == 0))
839  {
840  /*
841  * The peer has earlier issued a close request and we have now waited
842  * until all the existing data are pushed into the socket. Now we close
843  * the socket explicitly.
844  */
845  CloseSocket(socket);
846  }
847 }
848 
849 void
851 {
852  NS_LOG_FUNCTION(this << socket);
853  std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
854  it = m_txBuffer.find(socket);
855  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
856  it->second.isClosing = true;
857 }
858 
859 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:42
a polymophic address class
Definition: address.h:100
AttributeValue implementation for Address.
The base class for all ns3 applications.
Definition: application.h:61
void DoDispose() override
Destructor implementation.
Definition: application.cc:85
Ptr< Node > GetNode() const
Definition: application.cc:107
An identifier for simulation events.
Definition: event-id.h:55
An Inet6 address class.
static Inet6SocketAddress ConvertFrom(const Address &addr)
Convert the address to a InetSocketAddress.
uint16_t GetPort() const
Get the port.
static bool IsMatchingType(const Address &addr)
If the address match.
Ipv6Address GetIpv6() const
Get the IPv6 address.
an Inet address class
static bool IsMatchingType(const Address &address)
Ipv4Address GetIpv4() const
static InetSocketAddress ConvertFrom(const Address &address)
Returns an InetSocketAddress which corresponds to the input Address.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:43
static Ipv4Address ConvertFrom(const Address &address)
static bool IsMatchingType(const Address &address)
Describes an IPv6 address.
Definition: ipv6-address.h:50
static Ipv6Address ConvertFrom(const Address &address)
Convert the Address object into an Ipv6Address ones.
static bool IsMatchingType(const Address &address)
If the Address matches the type.
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:200
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:268
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:863
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:305
Hold objects of type Ptr<T>.
Definition: pointer.h:37
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static void Cancel(const EventId &id)
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
Definition: simulator.cc:276
static bool IsFinished()
Check if the simulation should finish.
Definition: simulator.cc:169
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static bool IsExpired(const EventId &id)
Check if an event has already run or been cancelled.
Definition: simulator.cc:286
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:208
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
void SetCloseCallbacks(Callback< void, Ptr< Socket >> normalClose, Callback< void, Ptr< Socket >> errorClose)
Detect socket recv() events such as graceful shutdown or error.
Definition: socket.cc:94
void SetAcceptCallback(Callback< bool, Ptr< Socket >, const Address & > connectionRequest, Callback< void, Ptr< Socket >, const Address & > newConnectionCreated)
Accept connection requests from remote hosts.
Definition: socket.cc:103
void SetRecvCallback(Callback< void, Ptr< Socket >> receivedData)
Notify application when new data is available to be read.
Definition: socket.cc:126
virtual int ShutdownSend()=0
void SetSendCallback(Callback< void, Ptr< Socket >, uint32_t > sendCb)
Notify application when space in transmit buffer is added.
Definition: socket.cc:119
static Ptr< Socket > CreateSocket(Ptr< Node > node, TypeId tid)
This method wraps the creation of sockets that is performed on a given node by a SocketFactory specif...
Definition: socket.cc:72
virtual enum Socket::SocketErrno GetErrno() const =0
Get last error number.
virtual int Close()=0
Close a socket.
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
virtual int Listen()=0
Listen for incoming connections.
virtual uint32_t GetTxAvailable() const =0
Returns the number of bytes which can be sent in a single call to Send.
virtual Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress)=0
Read a single packet from the socket and retrieve the sender address.
static TypeId GetTypeId()
Get the type ID.
static TypeId GetTypeId()
Get the type ID.
Definition: tcp-socket.cc:54
Header used by web browsing applications to transmit information about content type,...
void SetClientTs(Time clientTs)
void SetServerTs(Time serverTs)
uint32_t GetSerializedSize() const override
void SetContentLength(uint32_t contentLength)
void SetContentType(ContentType_t contentType)
ContentType_t
The possible types of content (default = NOT_SET).
@ NOT_SET
Integer equivalent = 0.
@ EMBEDDED_OBJECT
Integer equivalent = 2.
@ MAIN_OBJECT
Integer equivalent = 1.
ContentType_t GetContentType() const
State_t
The possible states of the application.
@ NOT_STARTED
Before StartApplication() is invoked.
@ STOPPED
After StopApplication() is invoked.
@ STARTED
Passively listening and responding to requests.
void StartApplication() override
Application specific startup code.
uint32_t ServeFromTxBuffer(Ptr< Socket > socket)
Creates a packet out of a pending object in the Tx buffer send it over the given socket.
State_t m_state
The current state of the client application. Begins with NOT_STARTED.
Ptr< ThreeGppHttpVariables > m_httpVariables
The Variables attribute.
uint16_t m_localPort
The LocalPort attribute.
TracedCallback< uint32_t > m_embeddedObjectTrace
The EmbeddedObject trace source.
Address m_localAddress
The LocalAddress attribute.
void ReceivedDataCallback(Ptr< Socket > socket)
Invoked when m_initialSocket receives some packet data.
void ServeNewMainObject(Ptr< Socket > socket)
Generates a new main object and push it into the Tx buffer.
TracedCallback< uint32_t > m_mainObjectTrace
The MainObject trace source.
uint32_t m_mtuSize
The Mtu attribute.
TracedCallback< const Time &, const Address & > m_rxDelayTrace
The RxDelay trace source.
State_t GetState() const
Returns the current state of the application.
Ptr< ThreeGppHttpServerTxBuffer > m_txBuffer
Pointer to the transmission buffer.
bool ConnectionRequestCallback(Ptr< Socket > socket, const Address &address)
Invoked when m_initialSocket receives a connection request.
void ServeNewEmbeddedObject(Ptr< Socket > socket)
Generates a new embedded object and push it into the Tx buffer.
TracedCallback< const std::string &, const std::string & > m_stateTransitionTrace
The StateTransition trace source.
void ErrorCloseCallback(Ptr< Socket > socket)
Invoked when a connection with a web client is terminated.
void SendCallback(Ptr< Socket > socket, uint32_t availableBufferSize)
Invoked when more buffer space for transmission is added to a socket.
TracedCallback< Ptr< const Packet >, const Address & > m_rxTrace
The Rx trace source.
Ptr< Socket > GetSocket() const
Returns a pointer to the listening socket.
TracedCallback< Ptr< const ThreeGppHttpServer >, Ptr< Socket > > m_connectionEstablishedTrace
The ConnectionEstablished trace source.
Ptr< Socket > m_initialSocket
The listening socket, for receiving connection requests from clients.
static TypeId GetTypeId()
Returns the object TypeId.
std::string GetStateString() const
Returns the current state of the application in string format.
ThreeGppHttpServer()
Creates a new instance of HTTP server application.
TracedCallback< Ptr< const Packet > > m_txTrace
The Tx trace source.
void NormalCloseCallback(Ptr< Socket > socket)
Invoked when a connection with a web client is terminated.
void DoDispose() override
Destructor implementation.
void StopApplication() override
Application specific shutdown code.
void NewConnectionCreatedCallback(Ptr< Socket > socket, const Address &address)
Invoked when a new connection has been established.
void SetMtuSize(uint32_t mtuSize)
Sets the maximum transmission unit (MTU) size used by the application.
void SwitchToState(State_t state)
Change the state of the server.
void DepleteBufferSize(Ptr< Socket > socket, uint32_t amount)
Decrements a buffer size by a given amount.
ThreeGppHttpHeader::ContentType_t GetBufferContentType(Ptr< Socket > socket) const
Returns ThreeGppHttpHeader::NOT_SET when the buffer is new and never been filled with any data before...
uint32_t GetBufferSize(Ptr< Socket > socket) const
void CloseAllSockets()
Close and remove all stored sockets, hence clearing the buffer.
bool HasTxedPartOfObject(Ptr< Socket > socket) const
void PrepareClose(Ptr< Socket > socket)
Tell the buffer to close the associated socket once the buffer becomes empty.
Time GetClientTs(Ptr< Socket > socket) const
void CloseSocket(Ptr< Socket > socket)
Close and remove a socket and its associated transmission buffer, and then unset the socket's callbac...
ThreeGppHttpServerTxBuffer()
Create an empty instance of transmission buffer.
void RecordNextServe(Ptr< Socket > socket, const EventId &eventId, const Time &clientTs)
Informs about a pending transmission event associated with the socket, so that it would be automatica...
std::map< Ptr< Socket >, TxBuffer_t > m_txBuffer
Collection of accepted sockets and its individual transmission buffer.
void WriteNewObject(Ptr< Socket > socket, ThreeGppHttpHeader::ContentType_t contentType, uint32_t objectSize)
Writes a data representing a new main object or embedded object to the transmission buffer.
bool IsBufferEmpty(Ptr< Socket > socket) const
bool IsSocketAvailable(Ptr< Socket > socket) const
This method is typically used before calling other methods.
void AddSocket(Ptr< Socket > socket)
Add a new socket and create an empty transmission buffer for it.
void RemoveSocket(Ptr< Socket > socket)
Remove a socket and its associated transmission buffer, and then unset the socket's callbacks to prev...
Container of various random variables to assist in generating web browsing traffic pattern.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:417
@ S
second
Definition: nstime.h:116
a unique identifier for an interface.
Definition: type-id.h:60
@ ATTR_GET
The attribute can be read.
Definition: type-id.h:65
struct TypeId::AttributeInformation GetAttribute(std::size_t i) const
Get Attribute information by index.
Definition: type-id.cc:1112
std::size_t GetAttributeN() const
Get the number of attributes.
Definition: type-id.cc:1104
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
Hold an unsigned integer type.
Definition: uinteger.h:45
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: pointer.h:231
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: uinteger.h:46
Callback< R, Args... > MakeNullCallback()
Definition: callback.h:750
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:261
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition: object.h:579
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition: ptr.h:481
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
address
Definition: first.py:40
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:707
Set of fields representing a single transmission buffer, which will be associated with a socket.
ThreeGppHttpHeader::ContentType_t txBufferContentType
The content type of the current data inside the transmission buffer.
uint32_t txBufferSize
The length (in bytes) of the current data inside the transmission buffer.
bool isClosing
True if the remote end has issued a request to close, which means that this socket will immediately c...
bool hasTxedPartOfObject
True if the buffer content has been read since it is written.
Attribute implementation.
Definition: type-id.h:82
std::string name
Attribute name.
Definition: type-id.h:84
Ptr< const AttributeValue > initialValue
Configured initial value.
Definition: type-id.h:92
static const uint32_t packetSize
Packet size generated at the AP.