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