A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
three-gpp-http-server.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013 Magister Solutions
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Budiarto Herman <budiarto.herman@magister.fi>
7 *
8 */
9
11
13
14#include <ns3/address-utils.h>
15#include <ns3/callback.h>
16#include <ns3/config.h>
17#include <ns3/log.h>
18#include <ns3/packet.h>
19#include <ns3/pointer.h>
20#include <ns3/simulator.h>
21#include <ns3/socket.h>
22#include <ns3/tcp-socket-factory.h>
23#include <ns3/tcp-socket.h>
24#include <ns3/uinteger.h>
25
26NS_LOG_COMPONENT_DEFINE("ThreeGppHttpServer");
27
28namespace ns3
29{
30
31// HTTP SERVER ////////////////////////////////////////////////////////////////
32
33NS_OBJECT_ENSURE_REGISTERED(ThreeGppHttpServer);
34
36 : SinkApplication(HTTP_DEFAULT_PORT),
37 m_state{NOT_STARTED},
38 m_initialSocket{nullptr},
40 m_httpVariables{CreateObject<ThreeGppHttpVariables>()},
41 m_optPort{},
42 m_mtuSize{m_httpVariables->GetMtuSize()}
43{
44 NS_LOG_FUNCTION(this);
45 NS_LOG_INFO(this << " MTU size for this server application is " << m_mtuSize << " bytes.");
46}
47
48// static
51{
52 static TypeId tid =
53 TypeId("ns3::ThreeGppHttpServer")
55 .AddConstructor<ThreeGppHttpServer>()
56 .AddAttribute("Variables",
57 "Variable collection, which is used to control e.g. processing and "
58 "object generation delays.",
62 .AddAttribute("LocalAddress",
63 "The local address of the server, "
64 "i.e., the address on which to bind the Rx socket.",
69 "Replaced by Local in ns-3.44.")
70 .AddAttribute("LocalPort",
71 "Port on which the application listen for incoming packets.",
72 UintegerValue(80), // the default HTTP port
76 "Replaced by Port in ns-3.44.")
77 .AddAttribute("Tos",
78 "The Type of Service used to send packets. "
79 "All 8 bits of the TOS byte are set (including ECN bits).",
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.",
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::AddressTracedCallback")
114 .AddTraceSource("RxWithAddresses",
115 "A packet has been received.",
117 "ns3::Packet::TwoAddressTracedCallback")
118 .AddTraceSource("RxDelay",
119 "A packet has been received with delay information.",
121 "ns3::Application::DelayAddressCallback")
122 .AddTraceSource("StateTransition",
123 "Trace fired upon every HTTP client state transition.",
125 "ns3::Application::StateTransitionCallback");
126 return tid;
127}
128
129void
131{
132 NS_LOG_FUNCTION(this << addr);
133 if (!addr.IsInvalid())
134 {
135 m_local = addr;
136 if (m_optPort)
137 {
139 }
140 }
141}
142
143void
145{
146 NS_LOG_FUNCTION(this << port);
147 if (port != INVALID_PORT)
148 {
149 m_port = port;
150 }
151 if (m_local.IsInvalid())
152 {
153 // save for later
155 return;
156 }
158 {
160 }
161}
162
163void
165{
166 NS_LOG_FUNCTION(this << mtuSize);
167 m_mtuSize = mtuSize;
168}
169
172{
173 return m_initialSocket;
174}
175
178{
179 return m_state;
180}
181
182std::string
187
188// static
189std::string
191{
192 switch (state)
193 {
194 case NOT_STARTED:
195 return "NOT_STARTED";
196 case STARTED:
197 return "STARTED";
198 case STOPPED:
199 return "STOPPED";
200 default:
201 NS_FATAL_ERROR("Unknown state");
202 return "FATAL_ERROR";
203 }
204}
205
206void
208{
209 NS_LOG_FUNCTION(this);
210
212 {
214 }
215
216 Application::DoDispose(); // Chain up.
217}
218
219void
221{
222 NS_LOG_FUNCTION(this);
223
224 if (m_state != NOT_STARTED)
225 {
226 NS_FATAL_ERROR("Invalid state " << GetStateString() << " for StartApplication().");
227 }
228
229 m_httpVariables->Initialize();
230 if (!m_initialSocket)
231 {
232 // Find the current default MTU value of TCP sockets.
233 Ptr<const ns3::AttributeValue> previousSocketMtu;
234 const TypeId tcpSocketTid = TcpSocket::GetTypeId();
235 for (uint32_t i = 0; i < tcpSocketTid.GetAttributeN(); i++)
236 {
237 TypeId::AttributeInformation attrInfo = tcpSocketTid.GetAttribute(i);
238 if (attrInfo.name == "SegmentSize")
239 {
240 previousSocketMtu = attrInfo.initialValue;
241 }
242 }
243
244 // Creating a TCP socket to connect to the server.
247
248 NS_ABORT_MSG_IF(m_local.IsInvalid(), "Local address not properly set");
250 {
251 const auto ipv4 [[maybe_unused]] = InetSocketAddress::ConvertFrom(m_local).GetIpv4();
252 m_initialSocket->SetIpTos(m_tos); // Affects only IPv4 sockets.
253 NS_LOG_INFO(this << " Binding on " << ipv4 << " port " << m_port << " / " << m_local
254 << ".");
255 }
257 {
258 const auto ipv6 [[maybe_unused]] = Inet6SocketAddress::ConvertFrom(m_local).GetIpv6();
259 NS_LOG_INFO(this << " Binding on " << ipv6 << " port " << m_port << " / " << m_local
260 << ".");
261 }
262 else
263 {
264 NS_ABORT_MSG("Incompatible local address");
265 }
266
267 auto ret [[maybe_unused]] = m_initialSocket->Bind(m_local);
268 NS_LOG_DEBUG(this << " Bind() return value= " << ret
269 << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
270
271 ret = m_initialSocket->Listen();
272 NS_LOG_DEBUG(this << " Listen () return value= " << ret
273 << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
274
275 NS_ASSERT_MSG(m_initialSocket, "Failed creating socket.");
285 } // end of `if (m_initialSocket == 0)`
286
288} // end of `void StartApplication ()`
289
290void
292{
293 NS_LOG_FUNCTION(this);
294
296
297 // Close all accepted sockets.
298 m_txBuffer->CloseAllSockets();
299
300 // Stop listening.
301 if (m_initialSocket)
302 {
305 MakeNullCallback<void, Ptr<Socket>, const Address&>());
310 }
311}
312
313bool
315{
316 NS_LOG_FUNCTION(this << socket << address);
317 return true; // Unconditionally accept the connection request.
318}
319
320void
322{
323 NS_LOG_FUNCTION(this << socket << address);
324
325 socket->SetCloseCallbacks(MakeCallback(&ThreeGppHttpServer::NormalCloseCallback, this),
327 socket->SetRecvCallback(MakeCallback(&ThreeGppHttpServer::ReceivedDataCallback, this));
328 socket->SetSendCallback(MakeCallback(&ThreeGppHttpServer::SendCallback, this));
329
330 m_connectionEstablishedTrace(this, socket);
331 m_txBuffer->AddSocket(socket);
332
333 /*
334 * A typical connection is established after receiving an empty (i.e., no
335 * data) TCP packet with ACK flag. The actual data will follow in a separate
336 * packet after that and will be received by ReceivedDataCallback().
337 *
338 * However, that empty ACK packet might get lost. In this case, we may
339 * receive the first data packet right here already, because it also counts
340 * as a new connection. The statement below attempts to fetch the data from
341 * that packet, if any.
342 */
343 ReceivedDataCallback(socket);
344}
345
346void
348{
349 NS_LOG_FUNCTION(this << socket);
350
351 if (socket == m_initialSocket)
352 {
353 if (m_state == STARTED)
354 {
355 NS_FATAL_ERROR("Initial listener socket shall not be closed"
356 << " when the server instance is still running.");
357 }
358 }
359 else if (m_txBuffer->IsSocketAvailable(socket))
360 {
361 // The application should now prepare to close the socket.
362 if (m_txBuffer->IsBufferEmpty(socket))
363 {
364 /*
365 * Here we declare that we have nothing more to send and the socket
366 * may be closed immediately.
367 */
368 socket->ShutdownSend();
369 m_txBuffer->RemoveSocket(socket);
370 }
371 else
372 {
373 /*
374 * Remember to close the socket later, whenever the buffer becomes
375 * empty.
376 */
377 m_txBuffer->PrepareClose(socket);
378 }
379 }
380}
381
382void
384{
385 NS_LOG_FUNCTION(this << socket);
386
387 if (socket == m_initialSocket)
388 {
389 if (m_state == STARTED)
390 {
391 NS_FATAL_ERROR("Initial listener socket shall not be closed"
392 << " when the server instance is still running.");
393 }
394 }
395 else if (m_txBuffer->IsSocketAvailable(socket))
396 {
397 m_txBuffer->CloseSocket(socket);
398 }
399}
400
401void
403{
404 NS_LOG_FUNCTION(this << socket);
405
406 Address from;
407 while (auto packet = socket->RecvFrom(from))
408 {
409 if (packet->GetSize() == 0)
410 {
411 break; // EOF
412 }
413
414#ifdef NS3_LOG_ENABLE
415 // Some log messages.
417 {
418 NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
419 << " received from " << InetSocketAddress::ConvertFrom(from).GetIpv4()
420 << " port " << InetSocketAddress::ConvertFrom(from).GetPort() << " / "
422 }
424 {
425 NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
426 << " received from " << Inet6SocketAddress::ConvertFrom(from).GetIpv6()
427 << " port " << Inet6SocketAddress::ConvertFrom(from).GetPort() << " / "
429 }
430#endif /* NS3_LOG_ENABLE */
431
432 // Check the header. No need to remove it, since it is not a "real" header.
433 ThreeGppHttpHeader httpHeader;
434 packet->PeekHeader(httpHeader);
435
436 // Fire trace sources.
437 m_rxTrace(packet, from);
438 m_rxTraceWithAddresses(packet, from, m_local);
439 m_rxDelayTrace(Simulator::Now() - httpHeader.GetClientTs(), from);
440
441 switch (httpHeader.GetContentType())
442 {
444 const auto processingDelay = m_httpVariables->GetMainObjectGenerationDelay();
445 NS_LOG_INFO(this << " Will finish generating a main object"
446 << " in " << processingDelay.As(Time::S) << ".");
447 m_txBuffer->RecordNextServe(socket,
448 Simulator::Schedule(processingDelay,
450 this,
451 socket),
452 httpHeader.GetClientTs());
453 break;
454 }
456 const auto processingDelay = m_httpVariables->GetEmbeddedObjectGenerationDelay();
457 NS_LOG_INFO(this << " Will finish generating an embedded object"
458 << " in " << processingDelay.As(Time::S) << ".");
459 m_txBuffer->RecordNextServe(
460 socket,
461 Simulator::Schedule(processingDelay,
463 this,
464 socket),
465 httpHeader.GetClientTs());
466 break;
467 }
468 default:
469 NS_FATAL_ERROR("Invalid packet.");
470 break;
471 }
472
473 } // end of `while ((packet = socket->RecvFrom (from)))`
474
475} // end of `void ReceivedDataCallback (Ptr<Socket> socket)`
476
477void
479{
480 NS_LOG_FUNCTION(this << socket << availableBufferSize);
481
482 if (m_txBuffer->IsBufferEmpty(socket))
483 {
484 return;
485 }
486
487 const auto txBufferSize [[maybe_unused]] = m_txBuffer->GetBufferSize(socket);
488 const auto actualSent [[maybe_unused]] = ServeFromTxBuffer(socket);
489
490#ifdef NS3_LOG_ENABLE
491 // Some log messages.
492 if (actualSent < txBufferSize)
493 {
494 switch (m_txBuffer->GetBufferContentType(socket))
495 {
497 NS_LOG_INFO(this << " Transmission of main object is suspended"
498 << " after " << actualSent << " bytes.");
499 break;
501 NS_LOG_INFO(this << " Transmission of embedded object is suspended"
502 << " after " << actualSent << " bytes.");
503 break;
504 default:
505 NS_FATAL_ERROR("Invalid Tx buffer content type.");
506 break;
507 }
508 }
509 else
510 {
511 switch (m_txBuffer->GetBufferContentType(socket))
512 {
514 NS_LOG_INFO(this << " Finished sending a whole main object.");
515 break;
517 NS_LOG_INFO(this << " Finished sending a whole embedded object.");
518 break;
519 default:
520 NS_FATAL_ERROR("Invalid Tx buffer content type.");
521 break;
522 }
523 }
524#endif /* NS3_LOG_ENABLE */
525
526} // end of `void SendCallback (Ptr<Socket> socket, uint32_t availableBufferSize)`
527
528void
530{
531 NS_LOG_FUNCTION(this << socket);
532
533 const auto objectSize = m_httpVariables->GetMainObjectSize();
534 NS_LOG_INFO(this << " Main object to be served is " << objectSize << " bytes.");
535 m_mainObjectTrace(objectSize);
536 m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::MAIN_OBJECT, objectSize);
537 const auto actualSent = ServeFromTxBuffer(socket);
538
539 if (actualSent < objectSize)
540 {
541 NS_LOG_INFO(this << " Transmission of main object is suspended"
542 << " after " << actualSent << " bytes.");
543 }
544 else
545 {
546 NS_LOG_INFO(this << " Finished sending a whole main object.");
547 }
548}
549
550void
552{
553 NS_LOG_FUNCTION(this << socket);
554
555 const auto objectSize = m_httpVariables->GetEmbeddedObjectSize();
556 NS_LOG_INFO(this << " Embedded object to be served is " << objectSize << " bytes.");
557 m_embeddedObjectTrace(objectSize);
558 m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::EMBEDDED_OBJECT, objectSize);
559 const auto actualSent = ServeFromTxBuffer(socket);
560
561 if (actualSent < objectSize)
562 {
563 NS_LOG_INFO(this << " Transmission of embedded object is suspended"
564 << " after " << actualSent << " bytes.");
565 }
566 else
567 {
568 NS_LOG_INFO(this << " Finished sending a whole embedded object.");
569 }
570}
571
574{
575 NS_LOG_FUNCTION(this << socket);
576
577 if (m_txBuffer->IsBufferEmpty(socket))
578 {
579 NS_LOG_LOGIC(this << " Tx buffer is empty. Not sending anything.");
580 return 0;
581 }
582
583 const auto socketSize = socket->GetTxAvailable();
584 NS_LOG_DEBUG(this << " Socket has " << socketSize << " bytes available for Tx.");
585
586 // Get the number of bytes remaining to be sent.
587 const auto txBufferSize = m_txBuffer->GetBufferSize(socket);
588
589 // Compute the size of actual content to be sent; has to fit into the socket.
590 // Note that header size is NOT counted as TxBuffer content. Header size is overhead.
591 const auto contentSize = std::min(txBufferSize, socketSize - 22);
592 auto packet = Create<Packet>(contentSize);
593 auto packetSize = contentSize;
594 if (packetSize == 0)
595 {
596 NS_LOG_LOGIC(this << " Socket size leads to packet size of zero; not sending anything.");
597 return 0;
598 }
599
600 // If this is the first packet of an object, attach a header.
601 if (!m_txBuffer->HasTxedPartOfObject(socket))
602 {
603 // Create header.
604 ThreeGppHttpHeader httpHeader;
605 httpHeader.SetContentLength(txBufferSize);
606 httpHeader.SetContentType(m_txBuffer->GetBufferContentType(socket));
607 // Using the client TS value as per the corresponding request packet.
608 httpHeader.SetClientTs(m_txBuffer->GetClientTs(socket));
609 httpHeader.SetServerTs(Simulator::Now());
610 packet->AddHeader(httpHeader);
611 packetSize += httpHeader.GetSerializedSize();
612
613 NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize << " bytes."
614 << " The corresponding request came "
615 << (Simulator::Now() - httpHeader.GetClientTs()).As(Time::S) << " ago.");
616 }
617 else
618 {
619 NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize
620 << " bytes to be appended to a previous packet.");
621 }
622
623 // Send.
624 const auto actualBytes = socket->Send(packet);
625 NS_LOG_DEBUG(this << " Send() packet " << packet << " of " << packetSize << " bytes,"
626 << " return value= " << actualBytes << ".");
627 m_txTrace(packet);
628
629 if (actualBytes == static_cast<int>(packetSize))
630 {
631 // The packet goes through successfully.
632 m_txBuffer->DepleteBufferSize(socket, contentSize);
633 NS_LOG_INFO(this << " Remaining object to be sent " << m_txBuffer->GetBufferSize(socket)
634 << " bytes.");
635 return packetSize;
636 }
637 else
638 {
639 NS_LOG_INFO(this << " Failed to send object,"
640 << " GetErrNo= " << socket->GetErrno() << ","
641 << " suspending transmission"
642 << " and waiting for another Tx opportunity.");
643 return 0;
644 }
645
646} // end of `uint32_t ServeFromTxBuffer (Ptr<Socket> socket)`
647
648void
650{
651 const auto oldState = GetStateString();
652 const auto newState = GetStateString(state);
653 NS_LOG_FUNCTION(this << oldState << newState);
654 m_state = state;
655 NS_LOG_INFO(this << " ThreeGppHttpServer " << oldState << " --> " << newState << ".");
656 m_stateTransitionTrace(oldState, newState);
657}
658
659// HTTP SERVER TX BUFFER //////////////////////////////////////////////////////
660
665
666bool
668{
669 auto it = m_txBuffer.find(socket);
670 return (it != m_txBuffer.end());
671}
672
673void
675{
676 NS_LOG_FUNCTION(this << socket);
677
679 this << " Cannot add socket " << socket
680 << " because it has already been added before.");
681
682 TxBuffer_t txBuffer;
684 txBuffer.txBufferSize = 0;
685 txBuffer.isClosing = false;
686 txBuffer.hasTxedPartOfObject = false;
687 m_txBuffer.insert(std::pair<Ptr<Socket>, TxBuffer_t>(socket, txBuffer));
688}
689
690void
692{
693 NS_LOG_FUNCTION(this << socket);
694
695 auto it = m_txBuffer.find(socket);
696 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
697
698 if (!Simulator::IsExpired(it->second.nextServe))
699 {
700 NS_LOG_INFO(this << " Canceling a serving event which is due in "
701 << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
702 Simulator::Cancel(it->second.nextServe);
703 }
704
705 it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
707 it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
708 it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
709
710 m_txBuffer.erase(it);
711}
712
713void
715{
716 NS_LOG_FUNCTION(this << socket);
717
718 auto it = m_txBuffer.find(socket);
719 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
720
721 if (!Simulator::IsExpired(it->second.nextServe))
722 {
723 NS_LOG_INFO(this << " Canceling a serving event which is due in "
724 << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
725 Simulator::Cancel(it->second.nextServe);
726 }
727
728 if (it->second.txBufferSize > 0)
729 {
730 NS_LOG_WARN(this << " Closing a socket where " << it->second.txBufferSize
731 << " bytes of transmission"
732 << " is still pending in the corresponding Tx buffer.");
733 }
734
735 it->first->Close();
736 it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
738 it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
739 it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
740
741 m_txBuffer.erase(it);
742}
743
744void
746{
747 NS_LOG_FUNCTION(this);
748
749 for (auto& [socket, buffer] : m_txBuffer)
750 {
751 if (!Simulator::IsExpired(buffer.nextServe))
752 {
753 NS_LOG_INFO(this << " Canceling a serving event which is due in "
754 << Simulator::GetDelayLeft(buffer.nextServe).As(Time::S) << ".");
755 Simulator::Cancel(buffer.nextServe);
756 }
757
758 socket->Close();
759 socket->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
761 socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
762 socket->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
763 }
764
765 m_txBuffer.clear();
766}
767
768bool
770{
771 const auto it = m_txBuffer.find(socket);
772 NS_ASSERT_MSG(it != m_txBuffer.cend(), "Socket " << socket << " cannot be found.");
773 return (it->second.txBufferSize == 0);
774}
775
776Time
778{
779 const auto it = m_txBuffer.find(socket);
780 NS_ASSERT_MSG(it != m_txBuffer.cend(), "Socket " << socket << " cannot be found.");
781 return it->second.clientTs;
782}
783
786{
787 const auto it = m_txBuffer.find(socket);
788 NS_ASSERT_MSG(it != m_txBuffer.cend(), "Socket " << socket << " cannot be found.");
789 return it->second.txBufferContentType;
790}
791
794{
795 const auto it = m_txBuffer.find(socket);
796 NS_ASSERT_MSG(it != m_txBuffer.cend(), "Socket " << socket << " cannot be found.");
797 return it->second.txBufferSize;
798}
799
800bool
802{
803 const auto it = m_txBuffer.find(socket);
804 NS_ASSERT_MSG(it != m_txBuffer.cend(), "Socket " << socket << " cannot be found");
805 return it->second.hasTxedPartOfObject;
806}
807
808void
811 uint32_t objectSize)
812{
813 NS_LOG_FUNCTION(this << socket << contentType << objectSize);
814
816 "Unable to write an object without a proper Content-Type.");
817 NS_ASSERT_MSG(objectSize > 0, "Unable to write a zero-sized object.");
818
819 auto it = m_txBuffer.find(socket);
820 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
821 NS_ASSERT_MSG(it->second.txBufferSize == 0,
822 "Cannot write to Tx buffer of socket "
823 << socket << " until the previous content has been completely sent.");
824 it->second.txBufferContentType = contentType;
825 it->second.txBufferSize = objectSize;
826 it->second.hasTxedPartOfObject = false;
827}
828
829void
831 const EventId& eventId,
832 const Time& clientTs)
833{
834 NS_LOG_FUNCTION(this << socket << clientTs.As(Time::S));
835
836 auto it = m_txBuffer.find(socket);
837 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
838 it->second.nextServe = eventId;
839 it->second.clientTs = clientTs;
840}
841
842void
844{
845 NS_LOG_FUNCTION(this << socket << amount);
846
847 NS_ASSERT_MSG(amount > 0, "Unable to consume zero bytes.");
848
849 auto it = m_txBuffer.find(socket);
850 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
851 NS_ASSERT_MSG(it->second.txBufferSize >= amount,
852 "The requested amount is larger than the current buffer size.");
853 it->second.txBufferSize -= amount;
854 it->second.hasTxedPartOfObject = true;
855
856 if (it->second.isClosing && (it->second.txBufferSize == 0))
857 {
858 /*
859 * The peer has earlier issued a close request and we have now waited
860 * until all the existing data are pushed into the socket. Now we close
861 * the socket explicitly.
862 */
863 CloseSocket(socket);
864 }
865}
866
867void
869{
870 NS_LOG_FUNCTION(this << socket);
871 auto it = m_txBuffer.find(socket);
872 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
873 it->second.isClosing = true;
874}
875
876} // namespace ns3
a polymophic address class
Definition address.h:90
bool IsInvalid() const
Definition address.cc:60
AttributeValue implementation for Address.
Definition address.h:275
void DoDispose() override
Destructor implementation.
Ptr< Node > GetNode() const
An identifier for simulation events.
Definition event-id.h:45
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.
static bool IsMatchingType(const Address &address)
Ipv4Address GetIpv4() const
static InetSocketAddress ConvertFrom(const Address &address)
Returns an InetSocketAddress which corresponds to the input Address.
static bool IsMatchingType(const Address &address)
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.
AttributeValue implementation for Pointer.
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
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:274
static bool IsFinished()
Check if the simulation should finish.
Definition simulator.cc:160
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static bool IsExpired(const EventId &id)
Check if an event has already run or been cancelled.
Definition simulator.cc:284
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
Base class for sink applications.
static constexpr uint32_t INVALID_PORT
invalid port
Address m_local
Local address to bind to (address and port)
uint32_t m_port
Local port to bind to.
virtual Socket::SocketErrno GetErrno() const =0
Get last error number.
void SetIpTos(uint8_t ipTos)
Manually set IP Type of Service field.
Definition socket.cc:423
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:94
void SetSendCallback(Callback< void, Ptr< Socket >, uint32_t > sendCb)
Notify application when space in transmit buffer is added.
Definition socket.cc:110
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:85
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition socket.cc:117
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:61
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.
static TypeId GetTypeId()
Get the type ID.
static TypeId GetTypeId()
Get the type ID.
Definition tcp-socket.cc:43
Header used by web browsing applications to transmit information about content type,...
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.
void SetLocal(const Address &addr) override
set the local address
TracedCallback< uint32_t > m_embeddedObjectTrace
The EmbeddedObject trace source.
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.
TracedCallback< Ptr< const Packet >, const Address &, const Address & > m_rxTraceWithAddresses
The Rx trace source with the local address.
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.
uint8_t m_tos
The Tos attribute.
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.
std::optional< uint16_t > m_optPort
The LocalPort attribute.
void SwitchToState(State_t state)
Change the state of the server.
void SetPort(uint32_t port) override
set the server port
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:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
@ S
second
Definition nstime.h:105
a unique identifier for an interface.
Definition type-id.h:48
@ ATTR_GET
The attribute can be read.
Definition type-id.h:53
std::size_t GetAttributeN() const
Get the number of attributes.
Definition type-id.cc:1170
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
TypeId::AttributeInformation GetAttribute(std::size_t i) const
Get Attribute information by index.
Definition type-id.cc:1178
@ DEPRECATED
Attribute or trace source is deprecated; user is warned.
Definition type-id.h:64
Hold an unsigned integer type.
Definition uinteger.h:34
uint16_t port
Definition dsdv-manet.cc:33
#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:75
Ptr< const AttributeChecker > MakeAddressChecker()
Definition address.cc:169
Ptr< const AttributeAccessor > MakeAddressAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition address.h:275
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:248
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:269
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
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:35
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#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:250
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
Address ConvertToSocketAddress(const Address &address, uint16_t port)
Convert IPv4/IPv6 address with port to a socket address.
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:684
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:70
std::string name
Attribute name.
Definition type-id.h:72
Ptr< const AttributeValue > initialValue
Configured initial value.
Definition type-id.h:80
static const uint32_t packetSize
Packet size generated at the AP.