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 // NS_DEPRECATED_3_44
63 .AddAttribute("LocalAddress",
64 "The local address of the server, "
65 "i.e., the address on which to bind the Rx socket.",
70 "Replaced by Local in ns-3.44.")
71 // NS_DEPRECATED_3_44
72 .AddAttribute("LocalPort",
73 "Port on which the application listen for incoming packets.",
74 UintegerValue(80), // the default HTTP port
78 "Replaced by Port in ns-3.44.")
79 .AddAttribute("Tos",
80 "The Type of Service used to send packets. "
81 "All 8 bits of the TOS byte are set (including ECN bits).",
85 .AddAttribute("Mtu",
86 "Maximum transmission unit (in bytes) of the TCP sockets "
87 "used in this application, excluding the compulsory 40 "
88 "bytes TCP header. Typical values are 1460 and 536 bytes. "
89 "The attribute is read-only because the value is randomly "
90 "determined.",
95 .AddTraceSource(
96 "ConnectionEstablished",
97 "Connection to a remote web client has been established.",
99 "ns3::HttpServer::ConnectionEstablishedCallback")
100 .AddTraceSource("MainObject",
101 "A main object has been generated.",
103 "ns3::HttpServer::HttpObjectCallback")
104 .AddTraceSource("EmbeddedObject",
105 "An embedded object has been generated.",
107 "ns3::HttpServer::HttpObjectCallback")
108 .AddTraceSource("Tx",
109 "A packet has been sent.",
111 "ns3::Packet::TracedCallback")
112 .AddTraceSource("Rx",
113 "A packet has been received.",
115 "ns3::Packet::AddressTracedCallback")
116 .AddTraceSource("RxWithAddresses",
117 "A packet has been received.",
119 "ns3::Packet::TwoAddressTracedCallback")
120 .AddTraceSource("RxDelay",
121 "A packet has been received with delay information.",
123 "ns3::Application::DelayAddressCallback")
124 .AddTraceSource("StateTransition",
125 "Trace fired upon every HTTP client state transition.",
127 "ns3::Application::StateTransitionCallback");
128 return tid;
129}
130
131void
133{
134 NS_LOG_FUNCTION(this << addr);
135 if (!addr.IsInvalid())
136 {
137 m_local = addr;
138 if (m_optPort)
139 {
141 }
142 }
143}
144
145void
147{
148 NS_LOG_FUNCTION(this << port);
149 if (port != INVALID_PORT)
150 {
151 m_port = port;
152 }
153 if (m_local.IsInvalid())
154 {
155 // save for later
157 return;
158 }
160 {
162 }
163}
164
165void
167{
168 NS_LOG_FUNCTION(this << mtuSize);
169 m_mtuSize = mtuSize;
170}
171
174{
175 return m_initialSocket;
176}
177
180{
181 return m_state;
182}
183
184std::string
189
190// static
191std::string
193{
194 switch (state)
195 {
196 case NOT_STARTED:
197 return "NOT_STARTED";
198 case STARTED:
199 return "STARTED";
200 case STOPPED:
201 return "STOPPED";
202 default:
203 NS_FATAL_ERROR("Unknown state");
204 return "FATAL_ERROR";
205 }
206}
207
208void
210{
211 NS_LOG_FUNCTION(this);
212
214 {
216 }
217
218 Application::DoDispose(); // Chain up.
219}
220
221void
223{
224 NS_LOG_FUNCTION(this);
225
226 if (m_state != NOT_STARTED)
227 {
228 NS_FATAL_ERROR("Invalid state " << GetStateString() << " for StartApplication().");
229 }
230
231 m_httpVariables->Initialize();
232 if (!m_initialSocket)
233 {
234 // Find the current default MTU value of TCP sockets.
235 Ptr<const ns3::AttributeValue> previousSocketMtu;
236 const TypeId tcpSocketTid = TcpSocket::GetTypeId();
237 for (uint32_t i = 0; i < tcpSocketTid.GetAttributeN(); i++)
238 {
239 TypeId::AttributeInformation attrInfo = tcpSocketTid.GetAttribute(i);
240 if (attrInfo.name == "SegmentSize")
241 {
242 previousSocketMtu = attrInfo.initialValue;
243 }
244 }
245
246 // Creating a TCP socket to connect to the server.
249
250 NS_ABORT_MSG_IF(m_local.IsInvalid(), "Local address not properly set");
252 {
253 const auto ipv4 [[maybe_unused]] = InetSocketAddress::ConvertFrom(m_local).GetIpv4();
254 m_initialSocket->SetIpTos(m_tos); // Affects only IPv4 sockets.
255 NS_LOG_INFO(this << " Binding on " << ipv4 << " port " << m_port << " / " << m_local
256 << ".");
257 }
259 {
260 const auto ipv6 [[maybe_unused]] = Inet6SocketAddress::ConvertFrom(m_local).GetIpv6();
261 NS_LOG_INFO(this << " Binding on " << ipv6 << " port " << m_port << " / " << m_local
262 << ".");
263 }
264 else
265 {
266 NS_ABORT_MSG("Incompatible local address");
267 }
268
269 auto ret [[maybe_unused]] = m_initialSocket->Bind(m_local);
270 NS_LOG_DEBUG(this << " Bind() return value= " << ret
271 << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
272
273 ret = m_initialSocket->Listen();
274 NS_LOG_DEBUG(this << " Listen () return value= " << ret
275 << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
276
277 NS_ASSERT_MSG(m_initialSocket, "Failed creating socket.");
287 }
288
290}
291
292void
294{
295 NS_LOG_FUNCTION(this);
296
298
299 // Close all accepted sockets.
300 m_txBuffer->CloseAllSockets();
301
302 // Stop listening.
303 if (m_initialSocket)
304 {
307 MakeNullCallback<void, Ptr<Socket>, const Address&>());
312 }
313}
314
315bool
317{
318 NS_LOG_FUNCTION(this << socket << address);
319 return true; // Unconditionally accept the connection request.
320}
321
322void
324{
325 NS_LOG_FUNCTION(this << socket << address);
326
327 socket->SetCloseCallbacks(MakeCallback(&ThreeGppHttpServer::NormalCloseCallback, this),
329 socket->SetRecvCallback(MakeCallback(&ThreeGppHttpServer::ReceivedDataCallback, this));
330 socket->SetSendCallback(MakeCallback(&ThreeGppHttpServer::SendCallback, this));
331
332 m_connectionEstablishedTrace(this, socket);
333 m_txBuffer->AddSocket(socket);
334
335 /*
336 * A typical connection is established after receiving an empty (i.e., no
337 * data) TCP packet with ACK flag. The actual data will follow in a separate
338 * packet after that and will be received by ReceivedDataCallback().
339 *
340 * However, that empty ACK packet might get lost. In this case, we may
341 * receive the first data packet right here already, because it also counts
342 * as a new connection. The statement below attempts to fetch the data from
343 * that packet, if any.
344 */
345 ReceivedDataCallback(socket);
346}
347
348void
350{
351 NS_LOG_FUNCTION(this << socket);
352
353 if (socket == m_initialSocket)
354 {
355 if (m_state == STARTED)
356 {
357 NS_FATAL_ERROR("Initial listener socket shall not be closed"
358 << " when the server instance is still running.");
359 }
360 }
361 else if (m_txBuffer->IsSocketAvailable(socket))
362 {
363 // The application should now prepare to close the socket.
364 if (m_txBuffer->IsBufferEmpty(socket))
365 {
366 /*
367 * Here we declare that we have nothing more to send and the socket
368 * may be closed immediately.
369 */
370 socket->ShutdownSend();
371 m_txBuffer->RemoveSocket(socket);
372 }
373 else
374 {
375 /*
376 * Remember to close the socket later, whenever the buffer becomes
377 * empty.
378 */
379 m_txBuffer->PrepareClose(socket);
380 }
381 }
382}
383
384void
386{
387 NS_LOG_FUNCTION(this << socket);
388
389 if (socket == m_initialSocket)
390 {
391 if (m_state == STARTED)
392 {
393 NS_FATAL_ERROR("Initial listener socket shall not be closed"
394 << " when the server instance is still running.");
395 }
396 }
397 else if (m_txBuffer->IsSocketAvailable(socket))
398 {
399 m_txBuffer->CloseSocket(socket);
400 }
401}
402
403void
405{
406 NS_LOG_FUNCTION(this << socket);
407
408 Address from;
409 while (auto packet = socket->RecvFrom(from))
410 {
411 if (packet->GetSize() == 0)
412 {
413 break; // EOF
414 }
415
416#ifdef NS3_LOG_ENABLE
417 // Some log messages.
419 {
420 NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
421 << " received from " << InetSocketAddress::ConvertFrom(from).GetIpv4()
422 << " port " << InetSocketAddress::ConvertFrom(from).GetPort() << " / "
424 }
426 {
427 NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
428 << " received from " << Inet6SocketAddress::ConvertFrom(from).GetIpv6()
429 << " port " << Inet6SocketAddress::ConvertFrom(from).GetPort() << " / "
431 }
432#endif /* NS3_LOG_ENABLE */
433
434 // Check the header. No need to remove it, since it is not a "real" header.
435 ThreeGppHttpHeader httpHeader;
436 packet->PeekHeader(httpHeader);
437
438 // Fire trace sources.
439 m_rxTrace(packet, from);
440 m_rxTraceWithAddresses(packet, from, m_local);
441 m_rxDelayTrace(Simulator::Now() - httpHeader.GetClientTs(), from);
442
443 switch (httpHeader.GetContentType())
444 {
446 const auto processingDelay = m_httpVariables->GetMainObjectGenerationDelay();
447 NS_LOG_INFO(this << " Will finish generating a main object in "
448 << processingDelay.As(Time::S) << ".");
449 m_txBuffer->RecordNextServe(socket,
450 Simulator::Schedule(processingDelay,
452 this,
453 socket),
454 httpHeader.GetClientTs());
455 break;
456 }
458 const auto processingDelay = m_httpVariables->GetEmbeddedObjectGenerationDelay();
459 NS_LOG_INFO(this << " Will finish generating an embedded object in "
460 << processingDelay.As(Time::S) << ".");
461 m_txBuffer->RecordNextServe(
462 socket,
463 Simulator::Schedule(processingDelay,
465 this,
466 socket),
467 httpHeader.GetClientTs());
468 break;
469 }
470 default:
471 NS_FATAL_ERROR("Invalid packet.");
472 break;
473 }
474 }
475}
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 after " << actualSent
498 << " bytes.");
499 break;
501 NS_LOG_INFO(this << " Transmission of embedded object is suspended after " << actualSent
502 << " 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
527void
529{
530 NS_LOG_FUNCTION(this << socket);
531
532 const auto objectSize = m_httpVariables->GetMainObjectSize();
533 NS_LOG_INFO(this << " Main object to be served is " << objectSize << " bytes.");
534 m_mainObjectTrace(objectSize);
535 m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::MAIN_OBJECT, objectSize);
536 const auto actualSent = ServeFromTxBuffer(socket);
537
538 if (actualSent < objectSize)
539 {
540 NS_LOG_INFO(this << " Transmission of main object is suspended after " << actualSent
541 << " bytes.");
542 }
543 else
544 {
545 NS_LOG_INFO(this << " Finished sending a whole main object.");
546 }
547}
548
549void
551{
552 NS_LOG_FUNCTION(this << socket);
553
554 const auto objectSize = m_httpVariables->GetEmbeddedObjectSize();
555 NS_LOG_INFO(this << " Embedded object to be served is " << objectSize << " bytes.");
556 m_embeddedObjectTrace(objectSize);
557 m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::EMBEDDED_OBJECT, objectSize);
558 const auto actualSent = ServeFromTxBuffer(socket);
559
560 if (actualSent < objectSize)
561 {
562 NS_LOG_INFO(this << " Transmission of embedded object is suspended after " << actualSent
563 << " bytes.");
564 }
565 else
566 {
567 NS_LOG_INFO(this << " Finished sending a whole embedded object.");
568 }
569}
570
573{
574 NS_LOG_FUNCTION(this << socket);
575
576 if (m_txBuffer->IsBufferEmpty(socket))
577 {
578 NS_LOG_LOGIC(this << " Tx buffer is empty. Not sending anything.");
579 return 0;
580 }
581
582 const auto socketSize = socket->GetTxAvailable();
583 NS_LOG_DEBUG(this << " Socket has " << socketSize << " bytes available for Tx.");
584
585 // Get the number of bytes remaining to be sent.
586 const auto txBufferSize = m_txBuffer->GetBufferSize(socket);
587
588 // Compute the size of actual content to be sent; has to fit into the socket.
589 // Note that header size is NOT counted as TxBuffer content. Header size is overhead.
590 const auto contentSize = std::min(txBufferSize, socketSize - 22);
591 auto packet = Create<Packet>(contentSize);
592 auto packetSize = contentSize;
593 if (packetSize == 0)
594 {
595 NS_LOG_LOGIC(this << " Socket size leads to packet size of zero; not sending anything.");
596 return 0;
597 }
598
599 // If this is the first packet of an object, attach a header.
600 if (!m_txBuffer->HasTxedPartOfObject(socket))
601 {
602 // Create header.
603 ThreeGppHttpHeader httpHeader;
604 httpHeader.SetContentLength(txBufferSize);
605 httpHeader.SetContentType(m_txBuffer->GetBufferContentType(socket));
606 // Using the client TS value as per the corresponding request packet.
607 httpHeader.SetClientTs(m_txBuffer->GetClientTs(socket));
608 httpHeader.SetServerTs(Simulator::Now());
609 packet->AddHeader(httpHeader);
610 packetSize += httpHeader.GetSerializedSize();
611
612 NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize << " bytes."
613 << " The corresponding request came "
614 << (Simulator::Now() - httpHeader.GetClientTs()).As(Time::S) << " ago.");
615 }
616 else
617 {
618 NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize
619 << " bytes to be appended to a previous packet.");
620 }
621
622 // Send.
623 const auto actualBytes = socket->Send(packet);
624 NS_LOG_DEBUG(this << " Send() packet " << packet << " of " << packetSize << " bytes,"
625 << " return value= " << actualBytes << ".");
626 m_txTrace(packet);
627
628 if (actualBytes == static_cast<int>(packetSize))
629 {
630 // The packet goes through successfully.
631 m_txBuffer->DepleteBufferSize(socket, contentSize);
632 NS_LOG_INFO(this << " Remaining object to be sent " << m_txBuffer->GetBufferSize(socket)
633 << " bytes.");
634 return packetSize;
635 }
636 else
637 {
638 NS_LOG_INFO(this << " Failed to send object, GetErrNo= " << socket->GetErrno()
639 << ", suspending transmission and waiting for another Tx opportunity.");
640 return 0;
641 }
642}
643
644void
646{
647 const auto oldState = GetStateString();
648 const auto newState = GetStateString(state);
649 NS_LOG_FUNCTION(this << oldState << newState);
650 m_state = state;
651 NS_LOG_INFO(this << " ThreeGppHttpServer " << oldState << " --> " << newState << ".");
652 m_stateTransitionTrace(oldState, newState);
653}
654
655// HTTP SERVER TX BUFFER //////////////////////////////////////////////////////
656
661
662bool
664{
665 auto it = m_txBuffer.find(socket);
666 return (it != m_txBuffer.end());
667}
668
669void
671{
672 NS_LOG_FUNCTION(this << socket);
673
675 this << " Cannot add socket " << socket
676 << " because it has already been added before.");
677
678 TxBuffer_t txBuffer;
680 txBuffer.txBufferSize = 0;
681 txBuffer.isClosing = false;
682 txBuffer.hasTxedPartOfObject = false;
683 m_txBuffer.insert(std::pair<Ptr<Socket>, TxBuffer_t>(socket, txBuffer));
684}
685
686void
688{
689 NS_LOG_FUNCTION(this << socket);
690
691 auto 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 it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
703 it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
704 it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
705
706 m_txBuffer.erase(it);
707}
708
709void
711{
712 NS_LOG_FUNCTION(this << socket);
713
714 auto it = m_txBuffer.find(socket);
715 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
716
717 if (!Simulator::IsExpired(it->second.nextServe))
718 {
719 NS_LOG_INFO(this << " Canceling a serving event which is due in "
720 << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
721 Simulator::Cancel(it->second.nextServe);
722 }
723
724 if (it->second.txBufferSize > 0)
725 {
726 NS_LOG_WARN(this << " Closing a socket where " << it->second.txBufferSize
727 << " bytes of transmission"
728 << " is still pending in the corresponding Tx buffer.");
729 }
730
731 it->first->Close();
732 it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
734 it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
735 it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
736
737 m_txBuffer.erase(it);
738}
739
740void
742{
743 NS_LOG_FUNCTION(this);
744
745 for (auto& [socket, buffer] : m_txBuffer)
746 {
747 if (!Simulator::IsExpired(buffer.nextServe))
748 {
749 NS_LOG_INFO(this << " Canceling a serving event which is due in "
750 << Simulator::GetDelayLeft(buffer.nextServe).As(Time::S) << ".");
751 Simulator::Cancel(buffer.nextServe);
752 }
753
754 socket->Close();
755 socket->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
757 socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
758 socket->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
759 }
760
761 m_txBuffer.clear();
762}
763
764bool
766{
767 const auto it = m_txBuffer.find(socket);
768 NS_ASSERT_MSG(it != m_txBuffer.cend(), "Socket " << socket << " cannot be found.");
769 return (it->second.txBufferSize == 0);
770}
771
772Time
774{
775 const auto it = m_txBuffer.find(socket);
776 NS_ASSERT_MSG(it != m_txBuffer.cend(), "Socket " << socket << " cannot be found.");
777 return it->second.clientTs;
778}
779
782{
783 const auto it = m_txBuffer.find(socket);
784 NS_ASSERT_MSG(it != m_txBuffer.cend(), "Socket " << socket << " cannot be found.");
785 return it->second.txBufferContentType;
786}
787
790{
791 const auto it = m_txBuffer.find(socket);
792 NS_ASSERT_MSG(it != m_txBuffer.cend(), "Socket " << socket << " cannot be found.");
793 return it->second.txBufferSize;
794}
795
796bool
798{
799 const auto it = m_txBuffer.find(socket);
800 NS_ASSERT_MSG(it != m_txBuffer.cend(), "Socket " << socket << " cannot be found");
801 return it->second.hasTxedPartOfObject;
802}
803
804void
807 uint32_t objectSize)
808{
809 NS_LOG_FUNCTION(this << socket << contentType << objectSize);
810
812 "Unable to write an object without a proper Content-Type.");
813 NS_ASSERT_MSG(objectSize > 0, "Unable to write a zero-sized object.");
814
815 auto it = m_txBuffer.find(socket);
816 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
817 NS_ASSERT_MSG(it->second.txBufferSize == 0,
818 "Cannot write to Tx buffer of socket "
819 << socket << " until the previous content has been completely sent.");
820 it->second.txBufferContentType = contentType;
821 it->second.txBufferSize = objectSize;
822 it->second.hasTxedPartOfObject = false;
823}
824
825void
827 const EventId& eventId,
828 const Time& clientTs)
829{
830 NS_LOG_FUNCTION(this << socket << clientTs.As(Time::S));
831
832 auto it = m_txBuffer.find(socket);
833 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
834 it->second.nextServe = eventId;
835 it->second.clientTs = clientTs;
836}
837
838void
840{
841 NS_LOG_FUNCTION(this << socket << amount);
842
843 NS_ASSERT_MSG(amount > 0, "Unable to consume zero bytes.");
844
845 auto it = m_txBuffer.find(socket);
846 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
847 NS_ASSERT_MSG(it->second.txBufferSize >= amount,
848 "The requested amount is larger than the current buffer size.");
849 it->second.txBufferSize -= amount;
850 it->second.hasTxedPartOfObject = true;
851
852 if (it->second.isClosing && (it->second.txBufferSize == 0))
853 {
854 /*
855 * The peer has earlier issued a close request and we have now waited
856 * until all the existing data are pushed into the socket. Now we close
857 * the socket explicitly.
858 */
859 CloseSocket(socket);
860 }
861}
862
863void
865{
866 NS_LOG_FUNCTION(this << socket);
867 auto it = m_txBuffer.find(socket);
868 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
869 it->second.isClosing = true;
870}
871
872} // 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:561
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:403
@ S
second
Definition nstime.h:105
a unique identifier for an interface.
Definition type-id.h:49
@ ATTR_GET
The attribute can be read.
Definition type-id.h:54
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.
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:86
std::string name
Attribute name.
Definition type-id.h:88
Ptr< const AttributeValue > initialValue
Configured initial value.
Definition type-id.h:96
static const uint32_t packetSize
Packet size generated at the AP.