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
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 case STARTED:
159 return "STARTED";
160 case STOPPED:
161 return "STOPPED";
162 default:
163 NS_FATAL_ERROR("Unknown state");
164 return "FATAL_ERROR";
165 }
166}
167
168void
170{
171 NS_LOG_FUNCTION(this);
172
174 {
176 }
177
178 Application::DoDispose(); // Chain up.
179}
180
181void
183{
184 NS_LOG_FUNCTION(this);
185
186 if (m_state == NOT_STARTED)
187 {
188 m_httpVariables->Initialize();
189 if (!m_initialSocket)
190 {
191 // Find the current default MTU value of TCP sockets.
192 Ptr<const ns3::AttributeValue> previousSocketMtu;
193 const TypeId tcpSocketTid = TcpSocket::GetTypeId();
194 for (uint32_t i = 0; i < tcpSocketTid.GetAttributeN(); i++)
195 {
196 TypeId::AttributeInformation attrInfo = tcpSocketTid.GetAttribute(i);
197 if (attrInfo.name == "SegmentSize")
198 {
199 previousSocketMtu = attrInfo.initialValue;
200 }
201 }
202
203 // Creating a TCP socket to connect to the server.
206
208 {
210 const InetSocketAddress inetSocket = InetSocketAddress(ipv4, m_localPort);
211 NS_LOG_INFO(this << " Binding on " << ipv4 << " port " << m_localPort << " / "
212 << inetSocket << ".");
213 int ret [[maybe_unused]] = m_initialSocket->Bind(inetSocket);
214 NS_LOG_DEBUG(this << " Bind() return value= " << ret
215 << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
216 }
218 {
220 const Inet6SocketAddress inet6Socket = Inet6SocketAddress(ipv6, m_localPort);
221 NS_LOG_INFO(this << " Binding on " << ipv6 << " port " << m_localPort << " / "
222 << inet6Socket << ".");
223 int ret [[maybe_unused]] = m_initialSocket->Bind(inet6Socket);
224 NS_LOG_DEBUG(this << " Bind() return value= " << ret
225 << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
226 }
227
228 int ret [[maybe_unused]] = m_initialSocket->Listen();
229 NS_LOG_DEBUG(this << " Listen () return value= " << ret
230 << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
231
232 } // end of `if (m_initialSocket == 0)`
233
234 NS_ASSERT_MSG(m_initialSocket, "Failed creating socket.");
245
246 } // end of `if (m_state == NOT_STARTED)`
247 else
248 {
249 NS_FATAL_ERROR("Invalid state " << GetStateString() << " for StartApplication().");
250 }
251
252} // end of `void StartApplication ()`
253
254void
256{
257 NS_LOG_FUNCTION(this);
258
260
261 // Close all accepted sockets.
262 m_txBuffer->CloseAllSockets();
263
264 // Stop listening.
265 if (m_initialSocket)
266 {
269 MakeNullCallback<void, Ptr<Socket>, const Address&>());
274 }
275}
276
277bool
279{
280 NS_LOG_FUNCTION(this << socket << address);
281 return true; // Unconditionally accept the connection request.
282}
283
284void
286{
287 NS_LOG_FUNCTION(this << socket << address);
288
289 socket->SetCloseCallbacks(MakeCallback(&ThreeGppHttpServer::NormalCloseCallback, this),
291 socket->SetRecvCallback(MakeCallback(&ThreeGppHttpServer::ReceivedDataCallback, this));
292 socket->SetSendCallback(MakeCallback(&ThreeGppHttpServer::SendCallback, this));
293
294 m_connectionEstablishedTrace(this, socket);
295 m_txBuffer->AddSocket(socket);
296
297 /*
298 * A typical connection is established after receiving an empty (i.e., no
299 * data) TCP packet with ACK flag. The actual data will follow in a separate
300 * packet after that and will be received by ReceivedDataCallback().
301 *
302 * However, that empty ACK packet might get lost. In this case, we may
303 * receive the first data packet right here already, because it also counts
304 * as a new connection. The statement below attempts to fetch the data from
305 * that packet, if any.
306 */
307 ReceivedDataCallback(socket);
308}
309
310void
312{
313 NS_LOG_FUNCTION(this << socket);
314
315 if (socket == m_initialSocket)
316 {
317 if (m_state == STARTED)
318 {
319 NS_FATAL_ERROR("Initial listener socket shall not be closed"
320 << " when the server instance is still running.");
321 }
322 }
323 else if (m_txBuffer->IsSocketAvailable(socket))
324 {
325 // The application should now prepare to close the socket.
326 if (m_txBuffer->IsBufferEmpty(socket))
327 {
328 /*
329 * Here we declare that we have nothing more to send and the socket
330 * may be closed immediately.
331 */
332 socket->ShutdownSend();
333 m_txBuffer->RemoveSocket(socket);
334 }
335 else
336 {
337 /*
338 * Remember to close the socket later, whenever the buffer becomes
339 * empty.
340 */
341 m_txBuffer->PrepareClose(socket);
342 }
343 }
344}
345
346void
348{
349 NS_LOG_FUNCTION(this << socket);
350
351 if (socket == m_initialSocket)
352 {
353 if (m_state == STARTED)
354 {
355 NS_FATAL_ERROR("Initial listener socket shall not be closed"
356 << " when the server instance is still running.");
357 }
358 }
359 else if (m_txBuffer->IsSocketAvailable(socket))
360 {
361 m_txBuffer->CloseSocket(socket);
362 }
363}
364
365void
367{
368 NS_LOG_FUNCTION(this << socket);
369
370 Ptr<Packet> packet;
371 Address from;
372
373 while ((packet = socket->RecvFrom(from)))
374 {
375 if (packet->GetSize() == 0)
376 {
377 break; // EOF
378 }
379
380#ifdef NS3_LOG_ENABLE
381 // Some log messages.
383 {
384 NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
385 << " received from " << InetSocketAddress::ConvertFrom(from).GetIpv4()
386 << " port " << InetSocketAddress::ConvertFrom(from).GetPort() << " / "
388 }
390 {
391 NS_LOG_INFO(this << " A packet of " << packet->GetSize() << " bytes"
392 << " received from " << Inet6SocketAddress::ConvertFrom(from).GetIpv6()
393 << " port " << Inet6SocketAddress::ConvertFrom(from).GetPort() << " / "
395 }
396#endif /* NS3_LOG_ENABLE */
397
398 // Check the header. No need to remove it, since it is not a "real" header.
399 ThreeGppHttpHeader httpHeader;
400 packet->PeekHeader(httpHeader);
401
402 // Fire trace sources.
403 m_rxTrace(packet, from);
404 m_rxDelayTrace(Simulator::Now() - httpHeader.GetClientTs(), from);
405
406 Time processingDelay;
407 switch (httpHeader.GetContentType())
408 {
410 processingDelay = m_httpVariables->GetMainObjectGenerationDelay();
411 NS_LOG_INFO(this << " Will finish generating a main object"
412 << " in " << processingDelay.As(Time::S) << ".");
413 m_txBuffer->RecordNextServe(socket,
414 Simulator::Schedule(processingDelay,
416 this,
417 socket),
418 httpHeader.GetClientTs());
419 break;
420
422 processingDelay = m_httpVariables->GetEmbeddedObjectGenerationDelay();
423 NS_LOG_INFO(this << " Will finish generating an embedded object"
424 << " in " << processingDelay.As(Time::S) << ".");
425 m_txBuffer->RecordNextServe(
426 socket,
427 Simulator::Schedule(processingDelay,
429 this,
430 socket),
431 httpHeader.GetClientTs());
432 break;
433
434 default:
435 NS_FATAL_ERROR("Invalid packet.");
436 break;
437 }
438
439 } // end of `while ((packet = socket->RecvFrom (from)))`
440
441} // end of `void ReceivedDataCallback (Ptr<Socket> socket)`
442
443void
445{
446 NS_LOG_FUNCTION(this << socket << availableBufferSize);
447
448 if (!m_txBuffer->IsBufferEmpty(socket))
449 {
450 const uint32_t txBufferSize [[maybe_unused]] = m_txBuffer->GetBufferSize(socket);
451 const uint32_t actualSent [[maybe_unused]] = ServeFromTxBuffer(socket);
452
453#ifdef NS3_LOG_ENABLE
454 // Some log messages.
455 if (actualSent < txBufferSize)
456 {
457 switch (m_txBuffer->GetBufferContentType(socket))
458 {
460 NS_LOG_INFO(this << " Transmission of main object is suspended"
461 << " after " << actualSent << " bytes.");
462 break;
464 NS_LOG_INFO(this << " Transmission of embedded object is suspended"
465 << " after " << actualSent << " bytes.");
466 break;
467 default:
468 NS_FATAL_ERROR("Invalid Tx buffer content type.");
469 break;
470 }
471 }
472 else
473 {
474 switch (m_txBuffer->GetBufferContentType(socket))
475 {
477 NS_LOG_INFO(this << " Finished sending a whole main object.");
478 break;
480 NS_LOG_INFO(this << " Finished sending a whole embedded object.");
481 break;
482 default:
483 NS_FATAL_ERROR("Invalid Tx buffer content type.");
484 break;
485 }
486 }
487#endif /* NS3_LOG_ENABLE */
488
489 } // end of `if (m_txBuffer->IsBufferEmpty (socket))`
490
491} // end of `void SendCallback (Ptr<Socket> socket, uint32_t availableBufferSize)`
492
493void
495{
496 NS_LOG_FUNCTION(this << socket);
497
498 const uint32_t objectSize = m_httpVariables->GetMainObjectSize();
499 NS_LOG_INFO(this << " Main object to be served is " << objectSize << " bytes.");
500 m_mainObjectTrace(objectSize);
501 m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::MAIN_OBJECT, objectSize);
502 const uint32_t actualSent = ServeFromTxBuffer(socket);
503
504 if (actualSent < objectSize)
505 {
506 NS_LOG_INFO(this << " Transmission of main object is suspended"
507 << " after " << actualSent << " bytes.");
508 }
509 else
510 {
511 NS_LOG_INFO(this << " Finished sending a whole main object.");
512 }
513}
514
515void
517{
518 NS_LOG_FUNCTION(this << socket);
519
520 const uint32_t objectSize = m_httpVariables->GetEmbeddedObjectSize();
521 NS_LOG_INFO(this << " Embedded object to be served is " << objectSize << " bytes.");
522 m_embeddedObjectTrace(objectSize);
523 m_txBuffer->WriteNewObject(socket, ThreeGppHttpHeader::EMBEDDED_OBJECT, objectSize);
524 const uint32_t actualSent = ServeFromTxBuffer(socket);
525
526 if (actualSent < objectSize)
527 {
528 NS_LOG_INFO(this << " Transmission of embedded object is suspended"
529 << " after " << actualSent << " bytes.");
530 }
531 else
532 {
533 NS_LOG_INFO(this << " Finished sending a whole embedded object.");
534 }
535}
536
539{
540 NS_LOG_FUNCTION(this << socket);
541
542 if (m_txBuffer->IsBufferEmpty(socket))
543 {
544 NS_LOG_LOGIC(this << " Tx buffer is empty. Not sending anything.");
545 return 0;
546 }
547 bool firstPartOfObject = !m_txBuffer->HasTxedPartOfObject(socket);
548
549 const uint32_t socketSize = socket->GetTxAvailable();
550 NS_LOG_DEBUG(this << " Socket has " << socketSize << " bytes available for Tx.");
551
552 // Get the number of bytes remaining to be sent.
553 const uint32_t txBufferSize = m_txBuffer->GetBufferSize(socket);
554
555 // Compute the size of actual content to be sent; has to fit into the socket.
556 // Note that header size is NOT counted as TxBuffer content. Header size is overhead.
557 uint32_t contentSize = std::min(txBufferSize, socketSize - 22);
558 Ptr<Packet> packet = Create<Packet>(contentSize);
559 uint32_t packetSize = contentSize;
560 if (packetSize == 0)
561 {
562 NS_LOG_LOGIC(this << " Socket size leads to packet size of zero; not sending anything.");
563 return 0;
564 }
565
566 // If this is the first packet of an object, attach a header.
567 if (firstPartOfObject)
568 {
569 // Create header.
570 ThreeGppHttpHeader httpHeader;
571 httpHeader.SetContentLength(txBufferSize);
572 httpHeader.SetContentType(m_txBuffer->GetBufferContentType(socket));
573 // Using the client TS value as per the corresponding request packet.
574 httpHeader.SetClientTs(m_txBuffer->GetClientTs(socket));
575 httpHeader.SetServerTs(Simulator::Now());
576 packet->AddHeader(httpHeader);
577 packetSize += httpHeader.GetSerializedSize();
578
579 NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize << " bytes."
580 << " The corresponding request came "
581 << (Simulator::Now() - httpHeader.GetClientTs()).As(Time::S) << " ago.");
582 }
583 else
584 {
585 NS_LOG_INFO(this << " Created packet " << packet << " of " << packetSize
586 << " bytes to be appended to a previous packet.");
587 }
588
589 // Send.
590 const int actualBytes = socket->Send(packet);
591 NS_LOG_DEBUG(this << " Send() packet " << packet << " of " << packetSize << " bytes,"
592 << " return value= " << actualBytes << ".");
593 m_txTrace(packet);
594
595 if (actualBytes == static_cast<int>(packetSize))
596 {
597 // The packet goes through successfully.
598 m_txBuffer->DepleteBufferSize(socket, contentSize);
599 NS_LOG_INFO(this << " Remaining object to be sent " << m_txBuffer->GetBufferSize(socket)
600 << " bytes.");
601 return packetSize;
602 }
603 else
604 {
605 NS_LOG_INFO(this << " Failed to send object,"
606 << " GetErrNo= " << socket->GetErrno() << ","
607 << " suspending transmission"
608 << " and waiting for another Tx opportunity.");
609 return 0;
610 }
611
612} // end of `uint32_t ServeFromTxBuffer (Ptr<Socket> socket)`
613
614void
616{
617 const std::string oldState = GetStateString();
618 const std::string newState = GetStateString(state);
619 NS_LOG_FUNCTION(this << oldState << newState);
620 m_state = state;
621 NS_LOG_INFO(this << " ThreeGppHttpServer " << oldState << " --> " << newState << ".");
622 m_stateTransitionTrace(oldState, newState);
623}
624
625// HTTP SERVER TX BUFFER //////////////////////////////////////////////////////
626
628{
629 NS_LOG_FUNCTION(this);
630}
631
632bool
634{
635 std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
636 it = m_txBuffer.find(socket);
637 return (it != m_txBuffer.end());
638}
639
640void
642{
643 NS_LOG_FUNCTION(this << socket);
644
646 this << " Cannot add socket " << socket
647 << " because it has already been added before.");
648
649 TxBuffer_t txBuffer;
651 txBuffer.txBufferSize = 0;
652 txBuffer.isClosing = false;
653 txBuffer.hasTxedPartOfObject = false;
654 m_txBuffer.insert(std::pair<Ptr<Socket>, TxBuffer_t>(socket, txBuffer));
655}
656
657void
659{
660 NS_LOG_FUNCTION(this << socket);
661
662 std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
663 it = m_txBuffer.find(socket);
664 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
665
666 if (!Simulator::IsExpired(it->second.nextServe))
667 {
668 NS_LOG_INFO(this << " Canceling a serving event which is due in "
669 << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
670 Simulator::Cancel(it->second.nextServe);
671 }
672
673 it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
675 it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
676 it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
677
678 m_txBuffer.erase(it);
679}
680
681void
683{
684 NS_LOG_FUNCTION(this << socket);
685
686 std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
687 it = m_txBuffer.find(socket);
688 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
689
690 if (!Simulator::IsExpired(it->second.nextServe))
691 {
692 NS_LOG_INFO(this << " Canceling a serving event which is due in "
693 << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
694 Simulator::Cancel(it->second.nextServe);
695 }
696
697 if (it->second.txBufferSize > 0)
698 {
699 NS_LOG_WARN(this << " Closing a socket where " << it->second.txBufferSize
700 << " bytes of transmission"
701 << " is still pending in the corresponding Tx buffer.");
702 }
703
704 it->first->Close();
705 it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
707 it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
708 it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
709
710 m_txBuffer.erase(it);
711}
712
713void
715{
716 NS_LOG_FUNCTION(this);
717
718 std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
719 for (it = m_txBuffer.begin(); it != m_txBuffer.end(); ++it)
720 {
721 if (!Simulator::IsExpired(it->second.nextServe))
722 {
723 NS_LOG_INFO(this << " Canceling a serving event which is due in "
724 << Simulator::GetDelayLeft(it->second.nextServe).As(Time::S) << ".");
725 Simulator::Cancel(it->second.nextServe);
726 }
727
728 it->first->Close();
729 it->first->SetCloseCallbacks(MakeNullCallback<void, Ptr<Socket>>(),
731 it->first->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
732 it->first->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t>());
733 }
734
735 m_txBuffer.clear();
736}
737
738bool
740{
741 std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
742 it = m_txBuffer.find(socket);
743 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
744 return (it->second.txBufferSize == 0);
745}
746
747Time
749{
750 std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
751 it = m_txBuffer.find(socket);
752 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
753 return it->second.clientTs;
754}
755
758{
759 std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
760 it = m_txBuffer.find(socket);
761 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
762 return it->second.txBufferContentType;
763}
764
767{
768 std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
769 it = m_txBuffer.find(socket);
770 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
771 return it->second.txBufferSize;
772}
773
774bool
776{
777 std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
778 it = m_txBuffer.find(socket);
779 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found");
780 return it->second.hasTxedPartOfObject;
781}
782
783void
786 uint32_t objectSize)
787{
788 NS_LOG_FUNCTION(this << socket << contentType << objectSize);
789
791 "Unable to write an object without a proper Content-Type.");
792 NS_ASSERT_MSG(objectSize > 0, "Unable to write a zero-sized object.");
793
794 std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
795 it = m_txBuffer.find(socket);
796 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
797 NS_ASSERT_MSG(it->second.txBufferSize == 0,
798 "Cannot write to Tx buffer of socket "
799 << socket << " until the previous content has been completely sent.");
800 it->second.txBufferContentType = contentType;
801 it->second.txBufferSize = objectSize;
802 it->second.hasTxedPartOfObject = false;
803}
804
805void
807 const EventId& eventId,
808 const Time& clientTs)
809{
810 NS_LOG_FUNCTION(this << socket << clientTs.As(Time::S));
811
812 std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
813 it = m_txBuffer.find(socket);
814 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
815 it->second.nextServe = eventId;
816 it->second.clientTs = clientTs;
817}
818
819void
821{
822 NS_LOG_FUNCTION(this << socket << amount);
823
824 NS_ASSERT_MSG(amount > 0, "Unable to consume zero bytes.");
825
826 std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
827 it = m_txBuffer.find(socket);
828 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
829 NS_ASSERT_MSG(it->second.txBufferSize >= amount,
830 "The requested amount is larger than the current buffer size.");
831 it->second.txBufferSize -= amount;
832 it->second.hasTxedPartOfObject = true;
833
834 if (it->second.isClosing && (it->second.txBufferSize == 0))
835 {
836 /*
837 * The peer has earlier issued a close request and we have now waited
838 * until all the existing data are pushed into the socket. Now we close
839 * the socket explicitly.
840 */
841 CloseSocket(socket);
842 }
843}
844
845void
847{
848 NS_LOG_FUNCTION(this << socket);
849 std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
850 it = m_txBuffer.find(socket);
851 NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
852 it->second.isClosing = true;
853}
854
855} // namespace ns3
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: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:200
Hold objects of type Ptr<T>.
Definition: pointer.h:37
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
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 Socket::SocketErrno GetErrno() const =0
Get last error number.
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
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 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.
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: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:1105
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:936
TypeId::AttributeInformation GetAttribute(std::size_t i) const
Get Attribute information by index.
Definition: type-id.cc:1113
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:227
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
Callback< R, Args... > MakeNullCallback()
Definition: callback.h:745
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:261
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition: object.h:579
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition: ptr.h:481
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:702
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.