A Discrete-Event Network Simulator
QKDNetSim v2.0 (NS-3 v3.41) @ (+)
API
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 
24 
25 #include <ns3/callback.h>
26 #include <ns3/config.h>
27 #include <ns3/inet-socket-address.h>
28 #include <ns3/inet6-socket-address.h>
29 #include <ns3/log.h>
30 #include <ns3/packet.h>
31 #include <ns3/pointer.h>
32 #include <ns3/simulator.h>
33 #include <ns3/socket.h>
34 #include <ns3/tcp-socket-factory.h>
35 #include <ns3/tcp-socket.h>
36 #include <ns3/uinteger.h>
37 
38 NS_LOG_COMPONENT_DEFINE("ThreeGppHttpServer");
39 
40 namespace ns3
41 {
42 
43 // HTTP SERVER ////////////////////////////////////////////////////////////////
44 
45 NS_OBJECT_ENSURE_REGISTERED(ThreeGppHttpServer);
46 
48  : m_state(NOT_STARTED),
49  m_initialSocket(nullptr),
50  m_txBuffer(Create<ThreeGppHttpServerTxBuffer>()),
51  m_httpVariables(CreateObject<ThreeGppHttpVariables>())
52 {
53  NS_LOG_FUNCTION(this);
54 
55  m_mtuSize = m_httpVariables->GetMtuSize();
56  NS_LOG_INFO(this << " MTU size for this server application is " << m_mtuSize << " bytes.");
57 }
58 
59 // static
60 TypeId
62 {
63  static TypeId tid =
64  TypeId("ns3::ThreeGppHttpServer")
66  .AddConstructor<ThreeGppHttpServer>()
67  .AddAttribute("Variables",
68  "Variable collection, which is used to control e.g. processing and "
69  "object generation delays.",
70  PointerValue(),
72  MakePointerChecker<ThreeGppHttpVariables>())
73  .AddAttribute("LocalAddress",
74  "The local address of the server, "
75  "i.e., the address on which to bind the Rx socket.",
76  AddressValue(),
77  MakeAddressAccessor(&ThreeGppHttpServer::m_localAddress),
78  MakeAddressChecker())
79  .AddAttribute("LocalPort",
80  "Port on which the application listen for incoming packets.",
81  UintegerValue(80), // the default HTTP port
83  MakeUintegerChecker<uint16_t>())
84  .AddAttribute("Mtu",
85  "Maximum transmission unit (in bytes) of the TCP sockets "
86  "used in this application, excluding the compulsory 40 "
87  "bytes TCP header. Typical values are 1460 and 536 bytes. "
88  "The attribute is read-only because the value is randomly "
89  "determined.",
91  UintegerValue(),
93  MakeUintegerChecker<uint32_t>())
94  .AddTraceSource(
95  "ConnectionEstablished",
96  "Connection to a remote web client has been established.",
98  "ns3::HttpServer::ConnectionEstablishedCallback")
99  .AddTraceSource("MainObject",
100  "A main object has been generated.",
102  "ns3::HttpServer::HttpObjectCallback")
103  .AddTraceSource("EmbeddedObject",
104  "An embedded object has been generated.",
106  "ns3::HttpServer::HttpObjectCallback")
107  .AddTraceSource("Tx",
108  "A packet has been sent.",
110  "ns3::Packet::TracedCallback")
111  .AddTraceSource("Rx",
112  "A packet has been received.",
114  "ns3::Packet::PacketAddressTracedCallback")
115  .AddTraceSource("RxDelay",
116  "A packet has been received with delay information.",
118  "ns3::Application::DelayAddressCallback")
119  .AddTraceSource("StateTransition",
120  "Trace fired upon every HTTP client state transition.",
122  "ns3::Application::StateTransitionCallback");
123  return tid;
124 }
125 
126 void
128 {
129  NS_LOG_FUNCTION(this << mtuSize);
130  m_mtuSize = mtuSize;
131 }
132 
135 {
136  return m_initialSocket;
137 }
138 
141 {
142  return m_state;
143 }
144 
145 std::string
147 {
148  return GetStateString(m_state);
149 }
150 
151 // static
152 std::string
154 {
155  switch (state)
156  {
157  case NOT_STARTED:
158  return "NOT_STARTED";
159  case STARTED:
160  return "STARTED";
161  case STOPPED:
162  return "STOPPED";
163  default:
164  NS_FATAL_ERROR("Unknown state");
165  return "FATAL_ERROR";
166  }
167 }
168 
169 void
171 {
172  NS_LOG_FUNCTION(this);
173 
174  if (!Simulator::IsFinished())
175  {
176  StopApplication();
177  }
178 
179  Application::DoDispose(); // Chain up.
180 }
181 
182 void
184 {
185  NS_LOG_FUNCTION(this);
186 
187  if (m_state == NOT_STARTED)
188  {
189  m_httpVariables->Initialize();
190  if (!m_initialSocket)
191  {
192  // Find the current default MTU value of TCP sockets.
193  Ptr<const ns3::AttributeValue> previousSocketMtu;
194  const TypeId tcpSocketTid = TcpSocket::GetTypeId();
195  for (uint32_t i = 0; i < tcpSocketTid.GetAttributeN(); i++)
196  {
197  TypeId::AttributeInformation attrInfo = tcpSocketTid.GetAttribute(i);
198  if (attrInfo.name == "SegmentSize")
199  {
200  previousSocketMtu = attrInfo.initialValue;
201  }
202  }
203 
204  // Creating a TCP socket to connect to the server.
207 
209  {
212  NS_LOG_INFO(this << " Binding on " << ipv4 << " port " << m_localPort << " / "
213  << inetSocket << ".");
214  int ret [[maybe_unused]] = m_initialSocket->Bind(inetSocket);
215  NS_LOG_DEBUG(this << " Bind() return value= " << ret
216  << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
217  }
219  {
221  const Inet6SocketAddress inet6Socket = Inet6SocketAddress(ipv6, m_localPort);
222  NS_LOG_INFO(this << " Binding on " << ipv6 << " port " << m_localPort << " / "
223  << inet6Socket << ".");
224  int ret [[maybe_unused]] = m_initialSocket->Bind(inet6Socket);
225  NS_LOG_DEBUG(this << " Bind() return value= " << ret
226  << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
227  }
228 
229  int ret [[maybe_unused]] = m_initialSocket->Listen();
230  NS_LOG_DEBUG(this << " Listen () return value= " << ret
231  << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
232 
233  } // end of `if (m_initialSocket == 0)`
234 
235  NS_ASSERT_MSG(m_initialSocket, "Failed creating socket.");
246 
247  } // end of `if (m_state == NOT_STARTED)`
248  else
249  {
250  NS_FATAL_ERROR("Invalid state " << GetStateString() << " for StartApplication().");
251  }
252 
253 } // end of `void StartApplication ()`
254 
255 void
257 {
258  NS_LOG_FUNCTION(this);
259 
261 
262  // Close all accepted sockets.
263  m_txBuffer->CloseAllSockets();
264 
265  // Stop listening.
266  if (m_initialSocket)
267  {
270  MakeNullCallback<void, Ptr<Socket>, const Address&>());
272  MakeNullCallback<void, Ptr<Socket>>());
275  }
276 }
277 
278 bool
280 {
281  NS_LOG_FUNCTION(this << socket << address);
282  return true; // Unconditionally accept the connection request.
283 }
284 
285 void
287 {
288  NS_LOG_FUNCTION(this << socket << address);
289 
294 
295  m_connectionEstablishedTrace(this, socket);
296  m_txBuffer->AddSocket(socket);
297 
298  /*
299  * A typical connection is established after receiving an empty (i.e., no
300  * data) TCP packet with ACK flag. The actual data will follow in a separate
301  * packet after that and will be received by ReceivedDataCallback().
302  *
303  * However, that empty ACK packet might get lost. In this case, we may
304  * receive the first data packet right here already, because it also counts
305  * as a new connection. The statement below attempts to fetch the data from
306  * that packet, if any.
307  */
308  ReceivedDataCallback(socket);
309 }
310 
311 void
313 {
314  NS_LOG_FUNCTION(this << socket);
315 
316  if (socket == m_initialSocket)
317  {
318  if (m_state == STARTED)
319  {
320  NS_FATAL_ERROR("Initial listener socket shall not be closed"
321  << " when the server instance is still running.");
322  }
323  }
324  else if (m_txBuffer->IsSocketAvailable(socket))
325  {
326  // The application should now prepare to close the socket.
327  if (m_txBuffer->IsBufferEmpty(socket))
328  {
329  /*
330  * Here we declare that we have nothing more to send and the socket
331  * may be closed immediately.
332  */
333  socket->ShutdownSend();
334  m_txBuffer->RemoveSocket(socket);
335  }
336  else
337  {
338  /*
339  * Remember to close the socket later, whenever the buffer becomes
340  * empty.
341  */
342  m_txBuffer->PrepareClose(socket);
343  }
344  }
345 }
346 
347 void
349 {
350  NS_LOG_FUNCTION(this << socket);
351 
352  if (socket == m_initialSocket)
353  {
354  if (m_state == STARTED)
355  {
356  NS_FATAL_ERROR("Initial listener socket shall not be closed"
357  << " when the server instance is still running.");
358  }
359  }
360  else if (m_txBuffer->IsSocketAvailable(socket))
361  {
362  m_txBuffer->CloseSocket(socket);
363  }
364 }
365 
366 void
368 {
369  NS_LOG_FUNCTION(this << socket);
370 
371  Ptr<Packet> packet;
372  Address from;
373 
374  while ((packet = socket->RecvFrom(from)))
375  {
376  if (packet->GetSize() == 0)
377  {
378  break; // EOF
379  }
380 
381 #ifdef NS3_LOG_ENABLE
382  // Some log messages.
384  {
385  NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
386  << " received from " << InetSocketAddress::ConvertFrom(from).GetIpv4()
387  << " port " << InetSocketAddress::ConvertFrom(from).GetPort() << " / "
389  }
390  else if (Inet6SocketAddress::IsMatchingType(from))
391  {
392  NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
393  << " received from " << Inet6SocketAddress::ConvertFrom(from).GetIpv6()
394  << " port " << Inet6SocketAddress::ConvertFrom(from).GetPort() << " / "
396  }
397 #endif /* NS3_LOG_ENABLE */
398 
399  // Check the header. No need to remove it, since it is not a "real" header.
400  ThreeGppHttpHeader httpHeader;
401  packet->PeekHeader(httpHeader);
402 
403  // Fire trace sources.
404  m_rxTrace(packet, from);
405  m_rxDelayTrace(Simulator::Now() - httpHeader.GetClientTs(), from);
406 
407  Time processingDelay;
408  switch (httpHeader.GetContentType())
409  {
411  processingDelay = m_httpVariables->GetMainObjectGenerationDelay();
412  NS_LOG_INFO(this << " Will finish generating a main object"
413  << " in " << processingDelay.As(Time::S) << ".");
414  m_txBuffer->RecordNextServe(socket,
415  Simulator::Schedule(processingDelay,
417  this,
418  socket),
419  httpHeader.GetClientTs());
420  break;
421 
423  processingDelay = m_httpVariables->GetEmbeddedObjectGenerationDelay();
424  NS_LOG_INFO(this << " Will finish generating an embedded object"
425  << " in " << processingDelay.As(Time::S) << ".");
426  m_txBuffer->RecordNextServe(
427  socket,
428  Simulator::Schedule(processingDelay,
430  this,
431  socket),
432  httpHeader.GetClientTs());
433  break;
434 
435  default:
436  NS_FATAL_ERROR("Invalid packet.");
437  break;
438  }
439 
440  } // end of `while ((packet = socket->RecvFrom (from)))`
441 
442 } // end of `void ReceivedDataCallback (Ptr<Socket> socket)`
443 
444 void
445 ThreeGppHttpServer::SendCallback(Ptr<Socket> socket, uint32_t availableBufferSize)
446 {
447  NS_LOG_FUNCTION(this << socket << availableBufferSize);
448 
449  if (!m_txBuffer->IsBufferEmpty(socket))
450  {
451  const uint32_t txBufferSize [[maybe_unused]] = m_txBuffer->GetBufferSize(socket);
452  const uint32_t actualSent [[maybe_unused]] = ServeFromTxBuffer(socket);
453 
454 #ifdef NS3_LOG_ENABLE
455  // Some log messages.
456  if (actualSent < txBufferSize)
457  {
458  switch (m_txBuffer->GetBufferContentType(socket))
459  {
461  NS_LOG_INFO(this << " Transmission of main object is suspended"
462  << " after " << actualSent << " bytes.");
463  break;
465  NS_LOG_INFO(this << " Transmission of embedded object is suspended"
466  << " after " << actualSent << " bytes.");
467  break;
468  default:
469  NS_FATAL_ERROR("Invalid Tx buffer content type.");
470  break;
471  }
472  }
473  else
474  {
475  switch (m_txBuffer->GetBufferContentType(socket))
476  {
478  NS_LOG_INFO(this << " Finished sending a whole main object.");
479  break;
481  NS_LOG_INFO(this << " Finished sending a whole embedded object.");
482  break;
483  default:
484  NS_FATAL_ERROR("Invalid Tx buffer content type.");
485  break;
486  }
487  }
488 #endif /* NS3_LOG_ENABLE */
489 
490  } // end of `if (m_txBuffer->IsBufferEmpty (socket))`
491 
492 } // end of `void SendCallback (Ptr<Socket> socket, uint32_t availableBufferSize)`
493 
494 void
496 {
497  NS_LOG_FUNCTION(this << socket);
498 
499  const uint32_t objectSize = m_httpVariables->GetMainObjectSize();
500  NS_LOG_INFO(this << " Main object to be served is " << objectSize << " bytes.");
501  m_mainObjectTrace(objectSize);
502  m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::MAIN_OBJECT, objectSize);
503  const uint32_t actualSent = ServeFromTxBuffer(socket);
504 
505  if (actualSent < objectSize)
506  {
507  NS_LOG_INFO(this << " Transmission of main object is suspended"
508  << " after " << actualSent << " bytes.");
509  }
510  else
511  {
512  NS_LOG_INFO(this << " Finished sending a whole main object.");
513  }
514 }
515 
516 void
518 {
519  NS_LOG_FUNCTION(this << socket);
520 
521  const uint32_t objectSize = m_httpVariables->GetEmbeddedObjectSize();
522  NS_LOG_INFO(this << " Embedded object to be served is " << objectSize << " bytes.");
523  m_embeddedObjectTrace(objectSize);
524  m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::EMBEDDED_OBJECT, objectSize);
525  const uint32_t actualSent = ServeFromTxBuffer(socket);
526 
527  if (actualSent < objectSize)
528  {
529  NS_LOG_INFO(this << " Transmission of embedded object is suspended"
530  << " after " << actualSent << " bytes.");
531  }
532  else
533  {
534  NS_LOG_INFO(this << " Finished sending a whole embedded object.");
535  }
536 }
537 
538 uint32_t
540 {
541  NS_LOG_FUNCTION(this << socket);
542 
543  if (m_txBuffer->IsBufferEmpty(socket))
544  {
545  NS_LOG_LOGIC(this << " Tx buffer is empty. Not sending anything.");
546  return 0;
547  }
548  bool firstPartOfObject = !m_txBuffer->HasTxedPartOfObject(socket);
549 
550  const uint32_t socketSize = socket->GetTxAvailable();
551  NS_LOG_DEBUG(this << " Socket has " << socketSize << " bytes available for Tx.");
552 
553  // Get the number of bytes remaining to be sent.
554  const uint32_t txBufferSize = m_txBuffer->GetBufferSize(socket);
555 
556  // Compute the size of actual content to be sent; has to fit into the socket.
557  // Note that header size is NOT counted as TxBuffer content. Header size is overhead.
558  uint32_t contentSize = std::min(txBufferSize, socketSize - 22);
559  Ptr<Packet> packet = Create<Packet>(contentSize);
560  uint32_t packetSize = contentSize;
561  if (packetSize == 0)
562  {
563  NS_LOG_LOGIC(this << " Socket size leads to packet size of zero; not sending anything.");
564  return 0;
565  }
566 
567  // If this is the first packet of an object, attach a header.
568  if (firstPartOfObject)
569  {
570  // Create header.
571  ThreeGppHttpHeader httpHeader;
572  httpHeader.SetContentLength(txBufferSize);
573  httpHeader.SetContentType(m_txBuffer->GetBufferContentType(socket));
574  // Using the client TS value as per the corresponding request packet.
575  httpHeader.SetClientTs(m_txBuffer->GetClientTs(socket));
576  httpHeader.SetServerTs(Simulator::Now());
577  packet->AddHeader(httpHeader);
578  packetSize += httpHeader.GetSerializedSize();
579 
580  NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize << " bytes."
581  << " The corresponding request came "
582  << (Simulator::Now() - httpHeader.GetClientTs()).As(Time::S) << " ago.");
583  }
584  else
585  {
586  NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize
587  << " bytes to be appended to a previous packet.");
588  }
589 
590  // Send.
591  const int actualBytes = socket->Send(packet);
592  NS_LOG_DEBUG(this << " Send() packet " << packet << " of " << packetSize << " bytes,"
593  << " return value= " << actualBytes << ".");
594  m_txTrace(packet);
595 
596  if (actualBytes == static_cast<int>(packetSize))
597  {
598  // The packet goes through successfully.
599  m_txBuffer->DepleteBufferSize(socket, contentSize);
600  NS_LOG_INFO(this << " Remaining object to be sent " << m_txBuffer->GetBufferSize(socket)
601  << " bytes.");
602  return packetSize;
603  }
604  else
605  {
606  NS_LOG_INFO(this << " Failed to send object,"
607  << " GetErrNo= " << socket->GetErrno() << ","
608  << " suspending transmission"
609  << " and waiting for another Tx opportunity.");
610  return 0;
611  }
612 
613 } // end of `uint32_t ServeFromTxBuffer (Ptr<Socket> socket)`
614 
615 void
617 {
618  const std::string oldState = GetStateString();
619  const std::string newState = GetStateString(state);
620  NS_LOG_FUNCTION(this << oldState << newState);
621  m_state = state;
622  NS_LOG_INFO(this << " ThreeGppHttpServer " << oldState << " --> " << newState << ".");
623  m_stateTransitionTrace(oldState, newState);
624 }
625 
626 // HTTP SERVER TX BUFFER //////////////////////////////////////////////////////
627 
629 {
630  NS_LOG_FUNCTION(this);
631 }
632 
633 bool
635 {
636  auto it = m_txBuffer.find(socket);
637  return (it != m_txBuffer.end());
638 }
639 
640 void
642 {
643  NS_LOG_FUNCTION(this << socket);
644 
646  this << " Cannot add socket " << socket
647  << " because it has already been added before.");
648 
649  TxBuffer_t txBuffer;
651  txBuffer.txBufferSize = 0;
652  txBuffer.isClosing = false;
653  txBuffer.hasTxedPartOfObject = false;
654  m_txBuffer.insert(std::pair<Ptr<Socket>, TxBuffer_t>(socket, txBuffer));
655 }
656 
657 void
659 {
660  NS_LOG_FUNCTION(this << socket);
661 
662  auto it = m_txBuffer.find(socket);
663  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
664 
665  if (!Simulator::IsExpired(it->second.nextServe))
666  {
667  NS_LOG_INFO(this << " Canceling a serving event which is due in "
668  << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
669  Simulator::Cancel(it->second.nextServe);
670  }
671 
672  it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
673  MakeNullCallback<void, Ptr<Socket>>());
674  it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
675  it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
676 
677  m_txBuffer.erase(it);
678 }
679 
680 void
682 {
683  NS_LOG_FUNCTION(this << socket);
684 
685  auto it = m_txBuffer.find(socket);
686  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
687 
688  if (!Simulator::IsExpired(it->second.nextServe))
689  {
690  NS_LOG_INFO(this << " Canceling a serving event which is due in "
691  << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
692  Simulator::Cancel(it->second.nextServe);
693  }
694 
695  if (it->second.txBufferSize > 0)
696  {
697  NS_LOG_WARN(this << " Closing a socket where " << it->second.txBufferSize
698  << " bytes of transmission"
699  << " is still pending in the corresponding Tx buffer.");
700  }
701 
702  it->first->Close();
703  it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
704  MakeNullCallback<void, Ptr<Socket>>());
705  it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
706  it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
707 
708  m_txBuffer.erase(it);
709 }
710 
711 void
713 {
714  NS_LOG_FUNCTION(this);
715 
716  for (auto it = m_txBuffer.begin(); it != m_txBuffer.end(); ++it)
717  {
718  if (!Simulator::IsExpired(it->second.nextServe))
719  {
720  NS_LOG_INFO(this << " Canceling a serving event which is due in "
721  << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
722  Simulator::Cancel(it->second.nextServe);
723  }
724 
725  it->first->Close();
726  it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
727  MakeNullCallback<void, Ptr<Socket>>());
728  it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
729  it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
730  }
731 
732  m_txBuffer.clear();
733 }
734 
735 bool
737 {
738  auto it = m_txBuffer.find(socket);
739  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
740  return (it->second.txBufferSize == 0);
741 }
742 
743 Time
745 {
746  auto it = m_txBuffer.find(socket);
747  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
748  return it->second.clientTs;
749 }
750 
753 {
754  auto it = m_txBuffer.find(socket);
755  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
756  return it->second.txBufferContentType;
757 }
758 
759 uint32_t
761 {
762  auto it = m_txBuffer.find(socket);
763  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
764  return it->second.txBufferSize;
765 }
766 
767 bool
769 {
770  auto it = m_txBuffer.find(socket);
771  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found");
772  return it->second.hasTxedPartOfObject;
773 }
774 
775 void
778  uint32_t objectSize)
779 {
780  NS_LOG_FUNCTION(this << socket << contentType << objectSize);
781 
783  "Unable to write an object without a proper Content-Type.");
784  NS_ASSERT_MSG(objectSize > 0, "Unable to write a zero-sized object.");
785 
786  auto it = m_txBuffer.find(socket);
787  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
788  NS_ASSERT_MSG(it->second.txBufferSize == 0,
789  "Cannot write to Tx buffer of socket "
790  << socket << " until the previous content has been completely sent.");
791  it->second.txBufferContentType = contentType;
792  it->second.txBufferSize = objectSize;
793  it->second.hasTxedPartOfObject = false;
794 }
795 
796 void
798  const EventId& eventId,
799  const Time& clientTs)
800 {
801  NS_LOG_FUNCTION(this << socket << clientTs.As(Time::S));
802 
803  auto it = m_txBuffer.find(socket);
804  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
805  it->second.nextServe = eventId;
806  it->second.clientTs = clientTs;
807 }
808 
809 void
811 {
812  NS_LOG_FUNCTION(this << socket << amount);
813 
814  NS_ASSERT_MSG(amount > 0, "Unable to consume zero bytes.");
815 
816  auto it = m_txBuffer.find(socket);
817  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
818  NS_ASSERT_MSG(it->second.txBufferSize >= amount,
819  "The requested amount is larger than the current buffer size.");
820  it->second.txBufferSize -= amount;
821  it->second.hasTxedPartOfObject = true;
822 
823  if (it->second.isClosing && (it->second.txBufferSize == 0))
824  {
825  /*
826  * The peer has earlier issued a close request and we have now waited
827  * until all the existing data are pushed into the socket. Now we close
828  * the socket explicitly.
829  */
830  CloseSocket(socket);
831  }
832 }
833 
834 void
836 {
837  NS_LOG_FUNCTION(this << socket);
838  auto it = m_txBuffer.find(socket);
839  NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
840  it->second.isClosing = true;
841 }
842 
843 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
a polymophic address class
Definition: address.h:101
The base class for all ns3 applications.
Definition: application.h:62
void DoDispose() override
Destructor implementation.
Definition: application.cc:86
Ptr< Node > GetNode() const
Definition: application.cc:108
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:42
static Ipv4Address ConvertFrom(const Address &address)
static bool IsMatchingType(const Address &address)
Describes an IPv6 address.
Definition: ipv6-address.h:49
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:204
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:861
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:571
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:285
static bool IsFinished()
Check if the simulation should finish.
Definition: simulator.cc:171
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static bool IsExpired(const EventId &id)
Check if an event has already run or been cancelled.
Definition: simulator.cc:295
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:217
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
virtual Socket::SocketErrno GetErrno() const =0
Get last error number.
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:96
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:105
void SetRecvCallback(Callback< void, Ptr< Socket >> receivedData)
Notify application when new data is available to be read.
Definition: socket.cc:128
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:121
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 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:415
@ S
second
Definition: nstime.h:116
a unique identifier for an interface.
Definition: type-id.h:59
@ ATTR_GET
The attribute can be read.
Definition: type-id.h:64
std::size_t GetAttributeN() const
Get the number of attributes.
Definition: type-id.cc:1100
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
TypeId::AttributeInformation GetAttribute(std::size_t i) const
Get Attribute information by index.
Definition: type-id.cc:1108
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
Callback< R, Args... > MakeNullCallback()
Definition: callback.h:747
#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:442
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
address
Definition: first.py:47
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:704
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Definition: pointer.h:227
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
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:81
std::string name
Attribute name.
Definition: type-id.h:83
Ptr< const AttributeValue > initialValue
Configured initial value.
Definition: type-id.h:91
static const uint32_t packetSize
Packet size generated at the AP.