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 * 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
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
38NS_LOG_COMPONENT_DEFINE("ThreeGppHttpServer");
39
40namespace ns3
41{
42
43// HTTP SERVER ////////////////////////////////////////////////////////////////
44
45NS_OBJECT_ENSURE_REGISTERED(ThreeGppHttpServer);
46
48 : m_state(NOT_STARTED),
49 m_initialSocket(nullptr),
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
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.",
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.",
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("Tos",
85 "The Type of Service used to send packets. "
86 "All 8 bits of the TOS byte are set (including ECN bits).",
89 MakeUintegerChecker<uint8_t>())
90 .AddAttribute("Mtu",
91 "Maximum transmission unit (in bytes) of the TCP sockets "
92 "used in this application, excluding the compulsory 40 "
93 "bytes TCP header. Typical values are 1460 and 536 bytes. "
94 "The attribute is read-only because the value is randomly "
95 "determined.",
99 MakeUintegerChecker<uint32_t>())
100 .AddTraceSource(
101 "ConnectionEstablished",
102 "Connection to a remote web client has been established.",
104 "ns3::HttpServer::ConnectionEstablishedCallback")
105 .AddTraceSource("MainObject",
106 "A main object has been generated.",
108 "ns3::HttpServer::HttpObjectCallback")
109 .AddTraceSource("EmbeddedObject",
110 "An embedded object has been generated.",
112 "ns3::HttpServer::HttpObjectCallback")
113 .AddTraceSource("Tx",
114 "A packet has been sent.",
116 "ns3::Packet::TracedCallback")
117 .AddTraceSource("Rx",
118 "A packet has been received.",
120 "ns3::Packet::PacketAddressTracedCallback")
121 .AddTraceSource("RxDelay",
122 "A packet has been received with delay information.",
124 "ns3::Application::DelayAddressCallback")
125 .AddTraceSource("StateTransition",
126 "Trace fired upon every HTTP client state transition.",
128 "ns3::Application::StateTransitionCallback");
129 return tid;
130}
131
132void
134{
135 NS_LOG_FUNCTION(this << mtuSize);
136 m_mtuSize = mtuSize;
137}
138
141{
142 return m_initialSocket;
143}
144
147{
148 return m_state;
149}
150
151std::string
153{
154 return GetStateString(m_state);
155}
156
157// static
158std::string
160{
161 switch (state)
162 {
163 case NOT_STARTED:
164 return "NOT_STARTED";
165 case STARTED:
166 return "STARTED";
167 case STOPPED:
168 return "STOPPED";
169 default:
170 NS_FATAL_ERROR("Unknown state");
171 return "FATAL_ERROR";
172 }
173}
174
175void
177{
178 NS_LOG_FUNCTION(this);
179
181 {
183 }
184
185 Application::DoDispose(); // Chain up.
186}
187
188void
190{
191 NS_LOG_FUNCTION(this);
192
193 if (m_state == NOT_STARTED)
194 {
195 m_httpVariables->Initialize();
196 if (!m_initialSocket)
197 {
198 // Find the current default MTU value of TCP sockets.
199 Ptr<const ns3::AttributeValue> previousSocketMtu;
200 const TypeId tcpSocketTid = TcpSocket::GetTypeId();
201 for (uint32_t i = 0; i < tcpSocketTid.GetAttributeN(); i++)
202 {
203 TypeId::AttributeInformation attrInfo = tcpSocketTid.GetAttribute(i);
204 if (attrInfo.name == "SegmentSize")
205 {
206 previousSocketMtu = attrInfo.initialValue;
207 }
208 }
209
210 // Creating a TCP socket to connect to the server.
213
215 "'LocalAddress' attribute not properly set");
216
218 {
220 const InetSocketAddress inetSocket = InetSocketAddress(ipv4, m_localPort);
221 NS_LOG_INFO(this << " Binding on " << ipv4 << " port " << m_localPort << " / "
222 << inetSocket << ".");
223 int ret [[maybe_unused]] = m_initialSocket->Bind(inetSocket);
224 NS_LOG_DEBUG(this << " Bind() return value= " << ret
225 << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
226
227 m_initialSocket->SetIpTos(m_tos); // Affects only IPv4 sockets.
228 }
230 {
232 const Inet6SocketAddress inet6Socket = Inet6SocketAddress(ipv6, m_localPort);
233 NS_LOG_INFO(this << " Binding on " << ipv6 << " port " << m_localPort << " / "
234 << inet6Socket << ".");
235 int ret [[maybe_unused]] = m_initialSocket->Bind(inet6Socket);
236 NS_LOG_DEBUG(this << " Bind() return value= " << ret
237 << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
238 }
239 else
240 {
241 NS_ABORT_MSG("Incompatible local address");
242 }
243
244 int ret [[maybe_unused]] = m_initialSocket->Listen();
245 NS_LOG_DEBUG(this << " Listen () return value= " << ret
246 << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
247
248 } // end of `if (m_initialSocket == 0)`
249
250 NS_ASSERT_MSG(m_initialSocket, "Failed creating socket.");
261
262 } // end of `if (m_state == NOT_STARTED)`
263 else
264 {
265 NS_FATAL_ERROR("Invalid state " << GetStateString() << " for StartApplication().");
266 }
267
268} // end of `void StartApplication ()`
269
270void
272{
273 NS_LOG_FUNCTION(this);
274
276
277 // Close all accepted sockets.
278 m_txBuffer->CloseAllSockets();
279
280 // Stop listening.
281 if (m_initialSocket)
282 {
285 MakeNullCallback<void, Ptr<Socket>, const Address&>());
290 }
291}
292
293bool
295{
296 NS_LOG_FUNCTION(this << socket << address);
297 return true; // Unconditionally accept the connection request.
298}
299
300void
302{
303 NS_LOG_FUNCTION(this << socket << address);
304
305 socket->SetCloseCallbacks(MakeCallback(&ThreeGppHttpServer::NormalCloseCallback, this),
307 socket->SetRecvCallback(MakeCallback(&ThreeGppHttpServer::ReceivedDataCallback, this));
308 socket->SetSendCallback(MakeCallback(&ThreeGppHttpServer::SendCallback, this));
309
310 m_connectionEstablishedTrace(this, socket);
311 m_txBuffer->AddSocket(socket);
312
313 /*
314 * A typical connection is established after receiving an empty (i.e., no
315 * data) TCP packet with ACK flag. The actual data will follow in a separate
316 * packet after that and will be received by ReceivedDataCallback().
317 *
318 * However, that empty ACK packet might get lost. In this case, we may
319 * receive the first data packet right here already, because it also counts
320 * as a new connection. The statement below attempts to fetch the data from
321 * that packet, if any.
322 */
323 ReceivedDataCallback(socket);
324}
325
326void
328{
329 NS_LOG_FUNCTION(this << socket);
330
331 if (socket == m_initialSocket)
332 {
333 if (m_state == STARTED)
334 {
335 NS_FATAL_ERROR("Initial listener socket shall not be closed"
336 << " when the server instance is still running.");
337 }
338 }
339 else if (m_txBuffer->IsSocketAvailable(socket))
340 {
341 // The application should now prepare to close the socket.
342 if (m_txBuffer->IsBufferEmpty(socket))
343 {
344 /*
345 * Here we declare that we have nothing more to send and the socket
346 * may be closed immediately.
347 */
348 socket->ShutdownSend();
349 m_txBuffer->RemoveSocket(socket);
350 }
351 else
352 {
353 /*
354 * Remember to close the socket later, whenever the buffer becomes
355 * empty.
356 */
357 m_txBuffer->PrepareClose(socket);
358 }
359 }
360}
361
362void
364{
365 NS_LOG_FUNCTION(this << socket);
366
367 if (socket == m_initialSocket)
368 {
369 if (m_state == STARTED)
370 {
371 NS_FATAL_ERROR("Initial listener socket shall not be closed"
372 << " when the server instance is still running.");
373 }
374 }
375 else if (m_txBuffer->IsSocketAvailable(socket))
376 {
377 m_txBuffer->CloseSocket(socket);
378 }
379}
380
381void
383{
384 NS_LOG_FUNCTION(this << socket);
385
386 Ptr<Packet> packet;
387 Address from;
388
389 while ((packet = socket->RecvFrom(from)))
390 {
391 if (packet->GetSize() == 0)
392 {
393 break; // EOF
394 }
395
396#ifdef NS3_LOG_ENABLE
397 // Some log messages.
399 {
400 NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
401 << " received from " << InetSocketAddress::ConvertFrom(from).GetIpv4()
402 << " port " << InetSocketAddress::ConvertFrom(from).GetPort() << " / "
404 }
406 {
407 NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
408 << " received from " << Inet6SocketAddress::ConvertFrom(from).GetIpv6()
409 << " port " << Inet6SocketAddress::ConvertFrom(from).GetPort() << " / "
411 }
412#endif /* NS3_LOG_ENABLE */
413
414 // Check the header. No need to remove it, since it is not a "real" header.
415 ThreeGppHttpHeader httpHeader;
416 packet->PeekHeader(httpHeader);
417
418 // Fire trace sources.
419 m_rxTrace(packet, from);
420 m_rxDelayTrace(Simulator::Now() - httpHeader.GetClientTs(), from);
421
422 Time processingDelay;
423 switch (httpHeader.GetContentType())
424 {
426 processingDelay = m_httpVariables->GetMainObjectGenerationDelay();
427 NS_LOG_INFO(this << " Will finish generating a main object"
428 << " in " << processingDelay.As(Time::S) << ".");
429 m_txBuffer->RecordNextServe(socket,
430 Simulator::Schedule(processingDelay,
432 this,
433 socket),
434 httpHeader.GetClientTs());
435 break;
436
438 processingDelay = m_httpVariables->GetEmbeddedObjectGenerationDelay();
439 NS_LOG_INFO(this << " Will finish generating an embedded object"
440 << " in " << processingDelay.As(Time::S) << ".");
441 m_txBuffer->RecordNextServe(
442 socket,
443 Simulator::Schedule(processingDelay,
445 this,
446 socket),
447 httpHeader.GetClientTs());
448 break;
449
450 default:
451 NS_FATAL_ERROR("Invalid packet.");
452 break;
453 }
454
455 } // end of `while ((packet = socket->RecvFrom (from)))`
456
457} // end of `void ReceivedDataCallback (Ptr<Socket> socket)`
458
459void
461{
462 NS_LOG_FUNCTION(this << socket << availableBufferSize);
463
464 if (!m_txBuffer->IsBufferEmpty(socket))
465 {
466 const uint32_t txBufferSize [[maybe_unused]] = m_txBuffer->GetBufferSize(socket);
467 const uint32_t actualSent [[maybe_unused]] = ServeFromTxBuffer(socket);
468
469#ifdef NS3_LOG_ENABLE
470 // Some log messages.
471 if (actualSent < txBufferSize)
472 {
473 switch (m_txBuffer->GetBufferContentType(socket))
474 {
476 NS_LOG_INFO(this << " Transmission of main object is suspended"
477 << " after " << actualSent << " bytes.");
478 break;
480 NS_LOG_INFO(this << " Transmission of embedded object is suspended"
481 << " after " << actualSent << " bytes.");
482 break;
483 default:
484 NS_FATAL_ERROR("Invalid Tx buffer content type.");
485 break;
486 }
487 }
488 else
489 {
490 switch (m_txBuffer->GetBufferContentType(socket))
491 {
493 NS_LOG_INFO(this << " Finished sending a whole main object.");
494 break;
496 NS_LOG_INFO(this << " Finished sending a whole embedded object.");
497 break;
498 default:
499 NS_FATAL_ERROR("Invalid Tx buffer content type.");
500 break;
501 }
502 }
503#endif /* NS3_LOG_ENABLE */
504
505 } // end of `if (m_txBuffer->IsBufferEmpty (socket))`
506
507} // end of `void SendCallback (Ptr<Socket> socket, uint32_t availableBufferSize)`
508
509void
511{
512 NS_LOG_FUNCTION(this << socket);
513
514 const uint32_t objectSize = m_httpVariables->GetMainObjectSize();
515 NS_LOG_INFO(this << " Main object to be served is " << objectSize << " bytes.");
516 m_mainObjectTrace(objectSize);
517 m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::MAIN_OBJECT, objectSize);
518 const uint32_t actualSent = ServeFromTxBuffer(socket);
519
520 if (actualSent < objectSize)
521 {
522 NS_LOG_INFO(this << " Transmission of main object is suspended"
523 << " after " << actualSent << " bytes.");
524 }
525 else
526 {
527 NS_LOG_INFO(this << " Finished sending a whole main object.");
528 }
529}
530
531void
533{
534 NS_LOG_FUNCTION(this << socket);
535
536 const uint32_t objectSize = m_httpVariables->GetEmbeddedObjectSize();
537 NS_LOG_INFO(this << " Embedded object to be served is " << objectSize << " bytes.");
538 m_embeddedObjectTrace(objectSize);
539 m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::EMBEDDED_OBJECT, objectSize);
540 const uint32_t actualSent = ServeFromTxBuffer(socket);
541
542 if (actualSent < objectSize)
543 {
544 NS_LOG_INFO(this << " Transmission of embedded object is suspended"
545 << " after " << actualSent << " bytes.");
546 }
547 else
548 {
549 NS_LOG_INFO(this << " Finished sending a whole embedded object.");
550 }
551}
552
555{
556 NS_LOG_FUNCTION(this << socket);
557
558 if (m_txBuffer->IsBufferEmpty(socket))
559 {
560 NS_LOG_LOGIC(this << " Tx buffer is empty. Not sending anything.");
561 return 0;
562 }
563 bool firstPartOfObject = !m_txBuffer->HasTxedPartOfObject(socket);
564
565 const uint32_t socketSize = socket->GetTxAvailable();
566 NS_LOG_DEBUG(this << " Socket has " << socketSize << " bytes available for Tx.");
567
568 // Get the number of bytes remaining to be sent.
569 const uint32_t txBufferSize = m_txBuffer->GetBufferSize(socket);
570
571 // Compute the size of actual content to be sent; has to fit into the socket.
572 // Note that header size is NOT counted as TxBuffer content. Header size is overhead.
573 uint32_t contentSize = std::min(txBufferSize, socketSize - 22);
574 Ptr<Packet> packet = Create<Packet>(contentSize);
575 uint32_t packetSize = contentSize;
576 if (packetSize == 0)
577 {
578 NS_LOG_LOGIC(this << " Socket size leads to packet size of zero; not sending anything.");
579 return 0;
580 }
581
582 // If this is the first packet of an object, attach a header.
583 if (firstPartOfObject)
584 {
585 // Create header.
586 ThreeGppHttpHeader httpHeader;
587 httpHeader.SetContentLength(txBufferSize);
588 httpHeader.SetContentType(m_txBuffer->GetBufferContentType(socket));
589 // Using the client TS value as per the corresponding request packet.
590 httpHeader.SetClientTs(m_txBuffer->GetClientTs(socket));
591 httpHeader.SetServerTs(Simulator::Now());
592 packet->AddHeader(httpHeader);
593 packetSize += httpHeader.GetSerializedSize();
594
595 NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize << " bytes."
596 << " The corresponding request came "
597 << (Simulator::Now() - httpHeader.GetClientTs()).As(Time::S) << " ago.");
598 }
599 else
600 {
601 NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize
602 << " bytes to be appended to a previous packet.");
603 }
604
605 // Send.
606 const int actualBytes = socket->Send(packet);
607 NS_LOG_DEBUG(this << " Send() packet " << packet << " of " << packetSize << " bytes,"
608 << " return value= " << actualBytes << ".");
609 m_txTrace(packet);
610
611 if (actualBytes == static_cast<int>(packetSize))
612 {
613 // The packet goes through successfully.
614 m_txBuffer->DepleteBufferSize(socket, contentSize);
615 NS_LOG_INFO(this << " Remaining object to be sent " << m_txBuffer->GetBufferSize(socket)
616 << " bytes.");
617 return packetSize;
618 }
619 else
620 {
621 NS_LOG_INFO(this << " Failed to send object,"
622 << " GetErrNo= " << socket->GetErrno() << ","
623 << " suspending transmission"
624 << " and waiting for another Tx opportunity.");
625 return 0;
626 }
627
628} // end of `uint32_t ServeFromTxBuffer (Ptr<Socket> socket)`
629
630void
632{
633 const std::string oldState = GetStateString();
634 const std::string newState = GetStateString(state);
635 NS_LOG_FUNCTION(this << oldState << newState);
636 m_state = state;
637 NS_LOG_INFO(this << " ThreeGppHttpServer " << oldState << " --> " << newState << ".");
638 m_stateTransitionTrace(oldState, newState);
639}
640
641// HTTP SERVER TX BUFFER //////////////////////////////////////////////////////
642
644{
645 NS_LOG_FUNCTION(this);
646}
647
648bool
650{
651 auto it = m_txBuffer.find(socket);
652 return (it != m_txBuffer.end());
653}
654
655void
657{
658 NS_LOG_FUNCTION(this << socket);
659
661 this << " Cannot add socket " << socket
662 << " because it has already been added before.");
663
664 TxBuffer_t txBuffer;
666 txBuffer.txBufferSize = 0;
667 txBuffer.isClosing = false;
668 txBuffer.hasTxedPartOfObject = false;
669 m_txBuffer.insert(std::pair<Ptr<Socket>, TxBuffer_t>(socket, txBuffer));
670}
671
672void
674{
675 NS_LOG_FUNCTION(this << socket);
676
677 auto it = m_txBuffer.find(socket);
678 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
679
680 if (!Simulator::IsExpired(it->second.nextServe))
681 {
682 NS_LOG_INFO(this << " Canceling a serving event which is due in "
683 << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
684 Simulator::Cancel(it->second.nextServe);
685 }
686
687 it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
689 it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
690 it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
691
692 m_txBuffer.erase(it);
693}
694
695void
697{
698 NS_LOG_FUNCTION(this << socket);
699
700 auto it = m_txBuffer.find(socket);
701 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
702
703 if (!Simulator::IsExpired(it->second.nextServe))
704 {
705 NS_LOG_INFO(this << " Canceling a serving event which is due in "
706 << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
707 Simulator::Cancel(it->second.nextServe);
708 }
709
710 if (it->second.txBufferSize > 0)
711 {
712 NS_LOG_WARN(this << " Closing a socket where " << it->second.txBufferSize
713 << " bytes of transmission"
714 << " is still pending in the corresponding Tx buffer.");
715 }
716
717 it->first->Close();
718 it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
720 it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
721 it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
722
723 m_txBuffer.erase(it);
724}
725
726void
728{
729 NS_LOG_FUNCTION(this);
730
731 for (auto it = m_txBuffer.begin(); it != m_txBuffer.end(); ++it)
732 {
733 if (!Simulator::IsExpired(it->second.nextServe))
734 {
735 NS_LOG_INFO(this << " Canceling a serving event which is due in "
736 << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
737 Simulator::Cancel(it->second.nextServe);
738 }
739
740 it->first->Close();
741 it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
743 it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
744 it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
745 }
746
747 m_txBuffer.clear();
748}
749
750bool
752{
753 auto it = m_txBuffer.find(socket);
754 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
755 return (it->second.txBufferSize == 0);
756}
757
758Time
760{
761 auto it = m_txBuffer.find(socket);
762 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
763 return it->second.clientTs;
764}
765
768{
769 auto it = m_txBuffer.find(socket);
770 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
771 return it->second.txBufferContentType;
772}
773
776{
777 auto it = m_txBuffer.find(socket);
778 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
779 return it->second.txBufferSize;
780}
781
782bool
784{
785 auto it = m_txBuffer.find(socket);
786 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found");
787 return it->second.hasTxedPartOfObject;
788}
789
790void
793 uint32_t objectSize)
794{
795 NS_LOG_FUNCTION(this << socket << contentType << objectSize);
796
798 "Unable to write an object without a proper Content-Type.");
799 NS_ASSERT_MSG(objectSize > 0, "Unable to write a zero-sized object.");
800
801 auto it = m_txBuffer.find(socket);
802 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
803 NS_ASSERT_MSG(it->second.txBufferSize == 0,
804 "Cannot write to Tx buffer of socket "
805 << socket << " until the previous content has been completely sent.");
806 it->second.txBufferContentType = contentType;
807 it->second.txBufferSize = objectSize;
808 it->second.hasTxedPartOfObject = false;
809}
810
811void
813 const EventId& eventId,
814 const Time& clientTs)
815{
816 NS_LOG_FUNCTION(this << socket << clientTs.As(Time::S));
817
818 auto it = m_txBuffer.find(socket);
819 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
820 it->second.nextServe = eventId;
821 it->second.clientTs = clientTs;
822}
823
824void
826{
827 NS_LOG_FUNCTION(this << socket << amount);
828
829 NS_ASSERT_MSG(amount > 0, "Unable to consume zero bytes.");
830
831 auto it = m_txBuffer.find(socket);
832 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
833 NS_ASSERT_MSG(it->second.txBufferSize >= amount,
834 "The requested amount is larger than the current buffer size.");
835 it->second.txBufferSize -= amount;
836 it->second.hasTxedPartOfObject = true;
837
838 if (it->second.isClosing && (it->second.txBufferSize == 0))
839 {
840 /*
841 * The peer has earlier issued a close request and we have now waited
842 * until all the existing data are pushed into the socket. Now we close
843 * the socket explicitly.
844 */
845 CloseSocket(socket);
846 }
847}
848
849void
851{
852 NS_LOG_FUNCTION(this << socket);
853 auto it = m_txBuffer.find(socket);
854 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
855 it->second.isClosing = true;
856}
857
858} // namespace ns3
a polymophic address class
Definition: address.h:101
bool IsInvalid() const
Definition: address.cc:71
AttributeValue implementation for Address.
Definition: address.h:286
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:211
AttributeValue implementation for Pointer.
Definition: pointer.h:48
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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 Socket::SocketErrno GetErrno() const =0
Get last error number.
void SetIpTos(uint8_t ipTos)
Manually set IP Type of Service field.
Definition: socket.cc:434
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 SetSendCallback(Callback< void, Ptr< Socket >, uint32_t > sendCb)
Notify application when space in transmit buffer is added.
Definition: socket.cc:121
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 SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition: socket.cc:128
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.
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.
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.
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:1101
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
TypeId::AttributeInformation GetAttribute(std::size_t i) const
Get Attribute information by index.
Definition: type-id.cc:1109
Hold an unsigned integer type.
Definition: uinteger.h:45
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
Ptr< const AttributeChecker > MakeAddressChecker()
Definition: address.cc:180
Ptr< const AttributeAccessor > MakeAddressAccessor(T1 a1)
Definition: address.h:286
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Definition: pointer.h:259
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
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_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#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:630
#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.
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
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.