diff --git a/doc/tutorial/Makefile b/doc/tutorial/Makefile index b229ba74c..f0b2f4f8f 100644 --- a/doc/tutorial/Makefile +++ b/doc/tutorial/Makefile @@ -7,7 +7,7 @@ CONVERT = convert CSS = --css-include=tutorial.css SPLIT = --split section -DIA_SOURCES = buffer.dia pp.dia dumbbell.dia star.dia +DIA_SOURCES = buffer.dia pp.dia dumbbell.dia star.dia sockets-overview.dia TGIF_SOURCES = packet.obj helpers.obj DIA_EPS = ${DIA_SOURCES:.dia=.eps} diff --git a/doc/tutorial/figures/sockets-overview.dia b/doc/tutorial/figures/sockets-overview.dia new file mode 100644 index 000000000..af9e58310 Binary files /dev/null and b/doc/tutorial/figures/sockets-overview.dia differ diff --git a/doc/tutorial/sockets.texi b/doc/tutorial/sockets.texi new file mode 100644 index 000000000..0c17cde02 --- /dev/null +++ b/doc/tutorial/sockets.texi @@ -0,0 +1,243 @@ +@node Sockets APIs +@chapter Sockets APIs + +The @uref{http://en.wikipedia.org/wiki/Berkeley_sockets,,sockets API} +is a long-standing API used by user-space applications to access +network services in the kernel. A ``socket'' is an abstraction, like +a Unix file handle, that allows applications to connect to other +Internet hosts and exchange reliable byte streams and unreliable +datagrams, among other services. + +ns-3 provides two types of sockets APIs, and it is important to +understand the differences between them. The first is a @emph{native} +ns-3 API, while the second uses the services of the native API to +provide a @uref{http://en.wikipedia.org/wiki/POSIX,,POSIX-like} +API as part of an overall application process. Both APIs strive +to be close to the typical sockets API that application writers +on Unix systems are accustomed to, but the POSIX variant is much +closer to a real system's sockets API. + +@section ns-3 sockets API + +The native sockets API for ns-3 provides an interface to various +types of transport protocols (TCP, UDP) as well as to packet sockets +and, in the future, Netlink-like sockets. However, users are cautioned +to understand that the semantics are @strong{not} the exact same as +one finds in a real system (for an API which is very much aligned +to real systems, see the next section). + +@code{class ns3::Socket} is defined in @code{src/node/socket.cc,h}. +Readers will note that many public member functions are aligned +with real sockets function calls, and all other things being equal, +we have tried to align with a Posix sockets API. However, note that: + +@itemize @bullet +@item ns-3 applications handle a smart pointer to a Socket object, not +a file descriptor; +@item there is no notion of synchronous API or a ``blocking'' API; +in fact, the model for interaction between application and socket is +one of asynchronous I/O, which is not typically found in real systems +(more on this below); +@item the C-style socket address structures are not used; +@item the API is not a complete sockets API, such as supporting +all socket options or all function variants; +@item many calls use @code{ns3::Packet} class to transfer data +between application and socket. This may seem a little funny to +people to pass ``Packets'' across a stream socket API, but think +of these packets as just fancy byte buffers at this level (more +on this also below). +@end itemize + +@subsection Basic operation and calls + +@float Figure,fig:sockets-overview +@caption{Implementation overview of native sockets API} +@image{figures/sockets-overview, 10cm} +@end float + +@subsubsection Creating sockets + +An application that wants to use sockets must first create one. +On real systems, this is accomplished by calling socket(): +@verbatim + int + socket(int domain, int type, int protocol); +@end verbatim +which creates a socket in the system and returns an integer descriptor. + +In ns-3, we have no equivalent of a system call at the lower layers, +so we adopt the following model. There are certain @emph{factory} +objects that can create sockets. Each factory is capable of creating +one type of socket, and if sockets of a particular type are able to +be created on a given node, then a factory that can create such sockets +must be aggregated to the Node. +@verbatim + static Ptr CreateSocket (Ptr node, TypeId tid); +@end verbatim +Examples of TypeIds to pass to this method are @code{TcpSocketFactory}, +@code{PacketSocketFactory}, and @code{UdpSocketFactory}. + +This method returns a smart pointer to a Socket object. Here is an +example: +@verbatim + Ptr n0; + // Do some stuff to build up the Node's internet stack + Ptr localSocket = Socket::CreateSocket (n0, TcpSocketFactory::GetTypeId ()); +@end verbatim + +In some ns-3 code, sockets will not be explicitly created by user's +main programs, if an ns-3 application does it. For instance, for +@code{class ns3::OnOffApplication}, the function @code{StartApplication()} +performs the socket creation, and the application holds the socket +pointer. + +@subsubsection Using sockets + +Below is a typical sequence of socket calls for a TCP client in a +real implementation: +@itemize @bullet +@item @code{sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);} +@item @code{bind(sock, ...);} +@item @code{connect(sock, ...);} +@item @code{send(sock, ...);} +@item @code{recv(sock, ...);} +@item @code{close(sock);} +@end itemize + +There are analogs to all of these calls in ns-3, but we will focus on +two aspects here. First, most usage of sockets in real systems +requires a way to manage I/O between the application and kernel. +These models include @emph{blocking sockets}, @emph{signal-based I/O}, +and @emph{non-blocking sockets} with polling. In ns-3, we make use +of the callback mechanisms to support a fourth mode, which is +analogous to POSIX @emph{asynchronous I/O}. + +In this model, on the sending side, if the @code{send()} call were to +fail because of insufficient buffers, the application suspends the +sending of more data until a function registered at the +@code{SetSendCallback()} callback is invoked. An application can +also ask the socket how much space is available by calling +@code{GetTxAvailable ()}. A typical sequence of events for +sending data (ignoring connection setup) might be: + +@itemize @bullet +@item @code{SetSendCallback (MakeCallback(&HandleSendCallback));} +@item @code{Send ();} +@item @code{Send ();} +@item ... +@item @code{// Send fails because buffer is full} +@item (wait until HandleSendCallback() is called) +@item (HandleSendCallback() is called by socket, since space now available) +@item @code{Send (); // Start sending again} +@end itemize + +Similarly, on the receive side, the socket user does not block on +a call to @code{recv()}. Instead, the application sets a callback +with @code{SetRecvCallback ()} in which the socket will notify the +application when (and how much) there is data to be read, and +the application then calls @code{Recv()} to read the data until +no more can be read. + +@subsection Packet vs. buffer variants + +There are two basic variants of @code{Send()} and @code{Recv()} supported: +@verbatim + virtual int Send (Ptr p) = 0; + int Send (const uint8_t* buf, uint32_t size); + + Ptr Recv (void); + int Recv (uint8_t* buf, uint32_t size); +@end verbatim + +The non-Packet variants are left for legacy API reasons. When calling +the raw buffer variant of @code{Send()}, the buffer is immediately +written into a Packet and the @code{Send (Ptr p)} is invoked. + +Users may find it semantically odd to pass a Packet to a stream socket +such as TCP. However, do not let the name bother you; think of +@code{ns3::Packet} to be a fancy byte buffer. There are a few reasons why +the Packet variants are more likely to be preferred in ns-3: + +@itemize @bullet +@item Users can use the Tags facility of packets to, for example, encode +a flow ID or other helper data. +@item Users can exploit the copy-on-write implementation to avoid +memory copies (on the receive side, the conversion back to a +@code{uint8_t* buf} may sometimes incur an additional copy). +@item Use of Packet is more aligned with the rest of the ns-3 API +@end itemize + +@subsection Sending dummy data + +Sometimes, users want the simulator to just pretend that there is an +actual data payload in the packet (e.g. to calculate transmission delay) +but do not want to actually produce or consume the data. This is +straightforward to support in ns-3; have applications call +@code{Create (size);} instead of @code{Create (buffer, size);}. +Similarly, passing in a zero to the pointer argument in the raw buffer +variants has the same effect. Note that, if some subsequent code tries +to read the Packet data buffer, the fake buffer will be converted to +a real (zero'ed) buffer on the spot, and the efficiency will be lost there. + +@subsection Socket options + +@emph{to be completed} + +@subsection Socket errno + +@emph{to be completed} + +@subsection Example programs + +@emph{to be completed} + +@section POSIX-like sockets API + +@emph{this capability is under development and is scheduled for +inclusion in August 2008 timeframe; see the repository +http://code.nsnam.org/mathieu/ns-3-simu for details} + +The below is excerpted from Mathieu's post to ns-developers list +on April 4, 2008. + +"To summarize, the goal is that the full posix/socket API is defined in +src/process/simu.h: each posix type and function is re-defined there +with a simu_ or SIMU_ prefix to avoid ugly name clashes and collisions +(feel free to come up with a better prefix). + +Each process is created with a call to ProcessManager::Create and is +attached to that ProcessManager instance. So, if the ProcessManager +(which is aggregated to a Node in src/helper/process-helper.cc) is +killed when the simulation ends, the system will automatically reclaim +all the resources of each process associated to each manager. The same +happens when an application "exits" from its main function. + +The example application defines two posix "processes": the function +ClientProgram creates a udp socket on the localhost port 2000 and the +function ServerProgram creates a udp socket on the localhost port 2000. +The code does not work right now because I did not get the details of +simu_read right yet but, I do plan to make this work at some point. + +I really think that this approach is worthwhile for many reasons, a few +of which are outlined below: +@itemize @bullet +@item makes porting real world application code _much_ easier + +@item makes write applications for new users much easier because they can +read the bsd socket api reference and documentation and write code +directly. + +@item can be used to write applications which work in both simulation and +in the real world at the same time. To do this, all you have to do is +write your application to use the simu_ API, and, then, you can chose at +compile-time which implementation of that API you want to use: you can +pick one implementation which forwards all calls to the system BSD +socket API or another one which forwards all calls to the attached +ProcessManager. Arguably, I did not implement the version which forwards +to system BSD sockets but, that should be pretty trivial. +@end itemize + +So, anyway, comments about the overall API would be welcome. Students +interested in the gsoc project for real-world code integration should +consider looking at this also." + diff --git a/doc/tutorial/tutorial.texi b/doc/tutorial/tutorial.texi index 1af725da1..64185d03c 100644 --- a/doc/tutorial/tutorial.texi +++ b/doc/tutorial/tutorial.texi @@ -95,9 +95,10 @@ Part 4: Creating New or Revised Topologies * Other-network-topologies:: Part 5: Key ns-3 objects and systems * ns-3 Packets:: -Part 6: Extending ns-3 * ns-3 Callbacks:: +* Sockets APIs:: * ns-3 routing overview:: +Part 6: Extending ns-3 * Nonlinear-Thinking:: * Summary:: * Object-Model:: @@ -115,6 +116,7 @@ Part 6: Extending ns-3 @include helpers.texi @include packets.texi @include callbacks.texi +@include sockets.texi @c @include output.texi @include routing.texi @c @include other.texi diff --git a/examples/csma-broadcast.cc b/examples/csma-broadcast.cc index 9585bf06d..0e5c2f5fb 100644 --- a/examples/csma-broadcast.cc +++ b/examples/csma-broadcast.cc @@ -49,6 +49,7 @@ main (int argc, char *argv[]) #if 0 LogComponentEnable ("CsmaBroadcastExample", LOG_LEVEL_INFO); #endif + LogComponentEnable ("CsmaBroadcastExample", LOG_PREFIX_TIME); // // Make the random number generators generate reproducible results. @@ -93,7 +94,7 @@ main (int argc, char *argv[]) // Create the OnOff application to send UDP datagrams of size // 512 bytes (default) at a rate of 500 Kb/s (default) from n0 NS_LOG_INFO ("Create Applications."); - OnOffHelper onoff ("ns3::Udp", + OnOffHelper onoff ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address ("255.255.255.255"), port))); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); @@ -104,7 +105,7 @@ main (int argc, char *argv[]) app.Stop (Seconds (10.0)); // Create an optional packet sink to receive these packets - PacketSinkHelper sink ("ns3::Udp", + PacketSinkHelper sink ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address::GetAny (), port))); sink.Install (c0.Get (1)); sink.Install (c1.Get (1)); diff --git a/examples/csma-multicast.cc b/examples/csma-multicast.cc index 870494809..6a07a3c6b 100644 --- a/examples/csma-multicast.cc +++ b/examples/csma-multicast.cc @@ -140,7 +140,7 @@ main (int argc, char *argv[]) // Configure a multicast packet generator that generates a packet // every few seconds - OnOffHelper onoff ("ns3::Udp", + OnOffHelper onoff ("ns3::UdpSocketFactory", Address (InetSocketAddress (multicastGroup, multicastPort))); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); @@ -156,7 +156,7 @@ main (int argc, char *argv[]) srcC.Stop (Seconds(10.)); // Create an optional packet sink to receive these packets - PacketSinkHelper sink ("ns3::Udp", + PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny(), multicastPort)); ApplicationContainer sinkC = sink.Install (c1.Get (2)); // Node n4 diff --git a/examples/csma-one-subnet.cc b/examples/csma-one-subnet.cc index d75df160c..f90a6ad43 100644 --- a/examples/csma-one-subnet.cc +++ b/examples/csma-one-subnet.cc @@ -95,7 +95,7 @@ main (int argc, char *argv[]) NS_LOG_INFO ("Create Applications."); uint16_t port = 9; // Discard port (RFC 863) - OnOffHelper onoff ("ns3::Udp", + OnOffHelper onoff ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address ("10.1.1.2"), port))); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); @@ -106,7 +106,7 @@ main (int argc, char *argv[]) app.Stop (Seconds (10.0)); // Create an optional packet sink to receive these packets - PacketSinkHelper sink ("ns3::Udp", + PacketSinkHelper sink ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address::GetAny (), port))); sink.Install (c.Get (1)); diff --git a/examples/mixed-global-routing.cc b/examples/mixed-global-routing.cc index b253a66e2..f9f79e8dc 100644 --- a/examples/mixed-global-routing.cc +++ b/examples/mixed-global-routing.cc @@ -110,7 +110,7 @@ main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s NS_LOG_INFO ("Create Applications."); uint16_t port = 9; // Discard port (RFC 863) - OnOffHelper onoff ("ns3::Udp", + OnOffHelper onoff ("ns3::UdpSocketFactory", InetSocketAddress (i5i6.GetAddress (1), port)); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); diff --git a/examples/mixed-wireless.cc b/examples/mixed-wireless.cc index f915c73f6..10e331b44 100644 --- a/examples/mixed-wireless.cc +++ b/examples/mixed-wireless.cc @@ -308,7 +308,7 @@ main (int argc, char *argv[]) Ptr appSink = NodeList::GetNode (13); Ipv4Address remoteAddr = Ipv4Address ("172.16.0.5"); - OnOffHelper onoff ("ns3::Udp", + OnOffHelper onoff ("ns3::UdpSocketFactory", Address (InetSocketAddress (remoteAddr, port))); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); @@ -317,7 +317,7 @@ main (int argc, char *argv[]) apps.Stop (Seconds (20.0)); // Create a packet sink to receive these packets - PacketSinkHelper sink ("ns3::Udp", + PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), port)); apps = sink.Install (appSink); apps.Start (Seconds (3.0)); diff --git a/examples/simple-alternate-routing.cc b/examples/simple-alternate-routing.cc index dd83323c8..0cdc687b0 100644 --- a/examples/simple-alternate-routing.cc +++ b/examples/simple-alternate-routing.cc @@ -141,7 +141,7 @@ main (int argc, char *argv[]) uint16_t port = 9; // Discard port (RFC 863) // Create a flow from n3 to n1, starting at time 1.1 seconds - OnOffHelper onoff ("ns3::Udp", + OnOffHelper onoff ("ns3::UdpSocketFactory", Address (InetSocketAddress (i1i2.GetAddress (0), port))); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); @@ -151,7 +151,7 @@ main (int argc, char *argv[]) apps.Start (Seconds (10.0)); // Create a packet sink to receive these packets - PacketSinkHelper sink ("ns3::Udp", + PacketSinkHelper sink ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address::GetAny (), port))); apps = sink.Install (c.Get (1)); apps.Start (Seconds (1.1)); diff --git a/examples/simple-error-model.cc b/examples/simple-error-model.cc index 617666d12..1c08f3f04 100644 --- a/examples/simple-error-model.cc +++ b/examples/simple-error-model.cc @@ -122,7 +122,7 @@ main (int argc, char *argv[]) NS_LOG_INFO ("Create Applications."); uint16_t port = 9; // Discard port (RFC 863) - OnOffHelper onoff ("ns3::Udp", + OnOffHelper onoff ("ns3::UdpSocketFactory", Address (InetSocketAddress (i3i2.GetAddress (1), port))); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable(1))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable(0))); @@ -132,7 +132,7 @@ main (int argc, char *argv[]) apps.Stop (Seconds(10.0)); // Create an optional packet sink to receive these packets - PacketSinkHelper sink ("ns3::Udp", + PacketSinkHelper sink ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address::GetAny (), port))); apps = sink.Install (c.Get (3)); apps.Start (Seconds (1.0)); diff --git a/examples/simple-global-routing.cc b/examples/simple-global-routing.cc index aa33d090b..e6a7b4eef 100644 --- a/examples/simple-global-routing.cc +++ b/examples/simple-global-routing.cc @@ -122,7 +122,7 @@ main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s NS_LOG_INFO ("Create Applications."); uint16_t port = 9; // Discard port (RFC 863) - OnOffHelper onoff ("ns3::Udp", + OnOffHelper onoff ("ns3::UdpSocketFactory", Address (InetSocketAddress (i3i2.GetAddress (0), port))); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); @@ -131,7 +131,7 @@ main (int argc, char *argv[]) apps.Stop (Seconds (10.0)); // Create a packet sink to receive these packets - PacketSinkHelper sink ("ns3::Udp", + PacketSinkHelper sink ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address::GetAny (), port))); apps = sink.Install (c.Get (3)); apps.Start (Seconds (1.0)); diff --git a/examples/simple-point-to-point-olsr.cc b/examples/simple-point-to-point-olsr.cc index 8c78030a6..bd7b39487 100644 --- a/examples/simple-point-to-point-olsr.cc +++ b/examples/simple-point-to-point-olsr.cc @@ -127,7 +127,7 @@ main (int argc, char *argv[]) NS_LOG_INFO ("Create Applications."); uint16_t port = 9; // Discard port (RFC 863) - OnOffHelper onoff ("ns3::Udp", + OnOffHelper onoff ("ns3::UdpSocketFactory", InetSocketAddress (i34.GetAddress (1), port)); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); @@ -137,7 +137,7 @@ main (int argc, char *argv[]) apps.Stop (Seconds (10.0)); // Create a packet sink to receive these packets - PacketSinkHelper sink ("ns3::Udp", + PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), port)); apps = sink.Install (c.Get (3)); diff --git a/examples/tcp-large-transfer.cc b/examples/tcp-large-transfer.cc index 641de0537..610ad0714 100644 --- a/examples/tcp-large-transfer.cc +++ b/examples/tcp-large-transfer.cc @@ -169,16 +169,15 @@ int main (int argc, char *argv[]) uint16_t servPort = 50000; // Create a packet sink to receive these packets - PacketSinkHelper sink ("ns3::Tcp", + PacketSinkHelper sink ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), servPort)); ApplicationContainer apps = sink.Install (c1.Get (1)); apps.Start (Seconds (0.0)); // and generate traffic to remote sink. - Ptr socketFactory = - c0.Get (0)->GetObject (); - Ptr localSocket = socketFactory->CreateSocket (); + //TypeId tid = TypeId::LookupByName ("ns3::TcpSocketFactory"); + Ptr localSocket = Socket::CreateSocket (c0.Get (0), TcpSocketFactory::GetTypeId ()); localSocket->Bind (); Simulator::ScheduleNow (&StartFlow, localSocket, nBytes, ipInterfs.GetAddress (1), servPort); diff --git a/examples/wifi-adhoc.cc b/examples/wifi-adhoc.cc index 0244d8160..1759f3643 100644 --- a/examples/wifi-adhoc.cc +++ b/examples/wifi-adhoc.cc @@ -38,7 +38,7 @@ public: Experiment (std::string name); GnuplotDataset Run (const WifiHelper &wifi); private: - void ReceivePacket (Ptr socket, Ptr packet, const Address &address); + void ReceivePacket (Ptr socket); void SetPosition (Ptr node, Vector position); Vector GetPosition (Ptr node); void AdvancePosition (Ptr node); @@ -90,17 +90,20 @@ Experiment::AdvancePosition (Ptr node) } void -Experiment::ReceivePacket (Ptr socket, Ptr packet, const Address &address) +Experiment::ReceivePacket (Ptr socket) { - m_bytesTotal += packet->GetSize (); + Ptr packet; + while (packet = socket->Recv ()) + { + m_bytesTotal += packet->GetSize (); + } } Ptr Experiment::SetupPacketReceive (Ptr node) { - TypeId tid = TypeId::LookupByName ("ns3::PacketSocketFactory"); - Ptr socketFactory = node->GetObject (tid); - Ptr sink = socketFactory->CreateSocket (); + TypeId tid = TypeId::LookupByName ("ns3::PacketSocket"); + Ptr sink = Socket::CreateSocket (node, tid); sink->Bind (); sink->SetRecvCallback (MakeCallback (&Experiment::ReceivePacket, this)); return sink; @@ -133,7 +136,7 @@ Experiment::Run (const WifiHelper &wifi) socket.SetPhysicalAddress (devices.Get (1)->GetAddress ()); socket.SetProtocol (1); - OnOffHelper onoff ("ns3::PacketSocketFactory", Address (socket)); + OnOffHelper onoff ("ns3::PacketSocket", Address (socket)); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (250))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); onoff.SetAttribute ("DataRate", DataRateValue (DataRate (60000000))); diff --git a/examples/wifi-ap.cc b/examples/wifi-ap.cc index 7c2c266fa..ecc82eaca 100644 --- a/examples/wifi-ap.cc +++ b/examples/wifi-ap.cc @@ -162,7 +162,7 @@ int main (int argc, char *argv[]) socket.SetPhysicalAddress (staDevs.Get (1)->GetAddress ()); socket.SetProtocol (1); - OnOffHelper onoff ("ns3::PacketSocketFactory", Address (socket)); + OnOffHelper onoff ("ns3::PacketSocket", Address (socket)); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (42))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); diff --git a/samples/main-simple.cc b/samples/main-simple.cc index 2bb339c45..92c6e5c36 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -23,9 +23,13 @@ GenerateTraffic (Ptr socket, uint32_t size) } static void -SocketPrinter (Ptr socket, Ptr packet, const Address &from) +SocketPrinter (Ptr socket) { - std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet->GetSize () << std::endl; + Ptr packet; + while (packet = socket->Recv ()) + { + std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet->GetSize () << std::endl; + } } static void @@ -44,14 +48,12 @@ RunSimulation (void) internet.Install (c); - TypeId tid = TypeId::LookupByName ("ns3::Udp"); - Ptr socketFactory = c.Get (0)->GetObject (tid); - - Ptr sink = socketFactory->CreateSocket (); + TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); + Ptr sink = Socket::CreateSocket (c.Get (0), tid); InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80); sink->Bind (local); - Ptr source = socketFactory->CreateSocket (); + Ptr source = Socket::CreateSocket (c.Get (0), tid); InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetLoopback (), 80); source->Connect (remote); diff --git a/src/applications/onoff/onoff-application.cc b/src/applications/onoff/onoff-application.cc index 311c30519..c4f84277a 100644 --- a/src/applications/onoff/onoff-application.cc +++ b/src/applications/onoff/onoff-application.cc @@ -35,7 +35,7 @@ #include "ns3/uinteger.h" #include "ns3/trace-source-accessor.h" #include "onoff-application.h" -#include "ns3/udp.h" +#include "ns3/udp-socket-factory.h" NS_LOG_COMPONENT_DEFINE ("OnOffApplication"); @@ -79,7 +79,7 @@ OnOffApplication::GetTypeId (void) MakeUintegerAccessor (&OnOffApplication::m_maxBytes), MakeUintegerChecker ()) .AddAttribute ("Protocol", "The type of protocol to use.", - TypeIdValue (Udp::GetTypeId ()), + TypeIdValue (UdpSocketFactory::GetTypeId ()), MakeTypeIdAccessor (&OnOffApplication::m_tid), MakeTypeIdChecker ()) .AddTraceSource ("Tx", "A new packet is created and is sent", @@ -130,8 +130,7 @@ void OnOffApplication::StartApplication() // Called at time specified by Start // Create the socket if not already if (!m_socket) { - Ptr socketFactory = GetNode ()->GetObject (m_tid); - m_socket = socketFactory->CreateSocket (); + m_socket = Socket::CreateSocket (GetNode(), m_tid); m_socket->Bind (); m_socket->Connect (m_peer); } diff --git a/src/applications/packet-sink/packet-sink.cc b/src/applications/packet-sink/packet-sink.cc index 6b768978b..d73ca1f03 100644 --- a/src/applications/packet-sink/packet-sink.cc +++ b/src/applications/packet-sink/packet-sink.cc @@ -26,7 +26,7 @@ #include "ns3/socket-factory.h" #include "ns3/packet.h" #include "ns3/trace-source-accessor.h" -#include "ns3/udp.h" +#include "ns3/udp-socket-factory.h" #include "packet-sink.h" using namespace std; @@ -47,7 +47,7 @@ PacketSink::GetTypeId (void) MakeAddressAccessor (&PacketSink::m_local), MakeAddressChecker ()) .AddAttribute ("Protocol", "The type id of the protocol to use for the rx socket.", - TypeIdValue (Udp::GetTypeId ()), + TypeIdValue (UdpSocketFactory::GetTypeId ()), MakeTypeIdAccessor (&PacketSink::m_tid), MakeTypeIdChecker ()) .AddTraceSource ("Rx", "A packet has been received", @@ -80,14 +80,12 @@ void PacketSink::StartApplication() // Called at time specified by Start // Create the socket if not already if (!m_socket) { - Ptr socketFactory = - GetNode ()->GetObject (m_tid); - m_socket = socketFactory->CreateSocket (); + m_socket = Socket::CreateSocket (GetNode(), m_tid); m_socket->Bind (m_local); m_socket->Listen (0); } - m_socket->SetRecvCallback (MakeCallback(&PacketSink::Receive, this)); + m_socket->SetRecvCallback (MakeCallback(&PacketSink::HandleRead, this)); m_socket->SetAcceptCallback ( MakeNullCallback, const Address &> (), MakeNullCallback, const Address&> (), @@ -98,23 +96,30 @@ void PacketSink::StopApplication() // Called at time specified by Stop { if (m_socket) { - m_socket->SetRecvCallback (MakeNullCallback, - Ptr, const Address &> ()); + m_socket->SetRecvCallback (MakeNullCallback > ()); } } -// This LOG output inspired by the application on Joseph Kopena's wiki -void PacketSink::Receive(Ptr socket, Ptr packet, - const Address &from) +void PacketSink::HandleRead (Ptr socket) { - if (InetSocketAddress::IsMatchingType (from)) + Ptr packet; + while (packet = socket->Recv ()) { - InetSocketAddress address = InetSocketAddress::ConvertFrom (from); - NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " << - address.GetIpv4() << " [" << address << "]---'" << - packet->PeekData() << "'"); + SocketRxAddressTag tag; + bool found; + found = packet->FindFirstMatchingTag (tag); + NS_ASSERT (found); + Address from = tag.GetAddress (); + // XXX packet->RemoveTag (tag); + if (InetSocketAddress::IsMatchingType (from)) + { + InetSocketAddress address = InetSocketAddress::ConvertFrom (from); + NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " << + address.GetIpv4() << " [" << address << "]---'" << + packet->PeekData() << "'"); + } + m_rxTrace (packet, from); } - m_rxTrace (packet, from); } void PacketSink::CloseConnection (Ptr socket) diff --git a/src/applications/packet-sink/packet-sink.h b/src/applications/packet-sink/packet-sink.h index 70f190ab0..638309aad 100644 --- a/src/applications/packet-sink/packet-sink.h +++ b/src/applications/packet-sink/packet-sink.h @@ -65,7 +65,8 @@ private: virtual void StartApplication (void); // Called at time specified by Start virtual void StopApplication (void); // Called at time specified by Stop - virtual void Receive (Ptr socket, Ptr packet, const Address& from); + virtual void HandleRead (Ptr socket); + virtual void CloseConnection (Ptr socket); Ptr m_socket; // Associated socket diff --git a/src/applications/udp-echo/udp-echo-client.cc b/src/applications/udp-echo/udp-echo-client.cc index 46b980949..7dd68701c 100644 --- a/src/applications/udp-echo/udp-echo-client.cc +++ b/src/applications/udp-echo/udp-echo-client.cc @@ -95,15 +95,13 @@ UdpEchoClient::StartApplication (void) if (m_socket == 0) { - TypeId tid = TypeId::LookupByName ("ns3::Udp"); - Ptr socketFactory = - GetNode ()->GetObject (tid); - m_socket = socketFactory->CreateSocket (); + TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); + m_socket = Socket::CreateSocket (GetNode(), tid); m_socket->Bind (); m_socket->Connect (InetSocketAddress (m_peerAddress, m_peerPort)); } - m_socket->SetRecvCallback(MakeCallback(&UdpEchoClient::Receive, this)); + m_socket->SetRecvCallback(MakeCallback(&UdpEchoClient::HandleRead, this)); ScheduleTransmit (Seconds(0.)); } @@ -115,8 +113,7 @@ UdpEchoClient::StopApplication () if (m_socket != 0) { - m_socket->SetRecvCallback(MakeNullCallback, - Ptr, const Address &> ()); + m_socket->SetRecvCallback(MakeNullCallback > ()); } Simulator::Cancel(m_sendEvent); @@ -149,20 +146,25 @@ UdpEchoClient::Send (void) } void -UdpEchoClient::Receive( - Ptr socket, - Ptr packet, - const Address &from) +UdpEchoClient::HandleRead (Ptr socket) { - NS_LOG_FUNCTION (this << socket << packet << from); - - if (InetSocketAddress::IsMatchingType (from)) + NS_LOG_FUNCTION (this << socket); + Ptr packet; + while (packet = socket->Recv ()) { - InetSocketAddress address = InetSocketAddress::ConvertFrom (from); - NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " << - address.GetIpv4()); + SocketRxAddressTag tag; + bool found; + found = packet->FindFirstMatchingTag (tag); + NS_ASSERT (found); + Address from = tag.GetAddress (); + // XXX packet->RemoveTag (tag); + if (InetSocketAddress::IsMatchingType (from)) + { + InetSocketAddress address = InetSocketAddress::ConvertFrom (from); + NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " << + address.GetIpv4()); + } } } - } // Namespace ns3 diff --git a/src/applications/udp-echo/udp-echo-client.h b/src/applications/udp-echo/udp-echo-client.h index 9a924edc2..bfb1c3fcf 100644 --- a/src/applications/udp-echo/udp-echo-client.h +++ b/src/applications/udp-echo/udp-echo-client.h @@ -56,7 +56,7 @@ private: void ScheduleTransmit (Time dt); void Send (void); - void Receive(Ptr socket, Ptr packet, const Address &from); + void HandleRead (Ptr socket); uint32_t m_count; Time m_interval; diff --git a/src/applications/udp-echo/udp-echo-server.cc b/src/applications/udp-echo/udp-echo-server.cc index ce26ee64e..3851a88b7 100644 --- a/src/applications/udp-echo/udp-echo-server.cc +++ b/src/applications/udp-echo/udp-echo-server.cc @@ -71,16 +71,13 @@ UdpEchoServer::StartApplication (void) if (m_socket == 0) { - TypeId tid = TypeId::LookupByName ("ns3::Udp"); - Ptr socketFactory = - GetNode ()->GetObject (tid); - m_socket = socketFactory->CreateSocket (); - InetSocketAddress local = - InetSocketAddress (Ipv4Address::GetAny (), m_port); + TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); + m_socket = Socket::CreateSocket (GetNode(), tid); + InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), m_port); m_socket->Bind (local); } - m_socket->SetRecvCallback(MakeCallback(&UdpEchoServer::Receive, this)); + m_socket->SetRecvCallback(MakeCallback(&UdpEchoServer::HandleRead, this)); } void @@ -90,27 +87,31 @@ UdpEchoServer::StopApplication () if (m_socket != 0) { - m_socket->SetRecvCallback(MakeNullCallback, - Ptr, const Address &> ()); + m_socket->SetRecvCallback(MakeNullCallback > ()); } } -void -UdpEchoServer::Receive( - Ptr socket, - Ptr packet, - const Address &from) +void +UdpEchoServer::HandleRead (Ptr socket) { - NS_LOG_FUNCTION (this << socket << packet << from); - - if (InetSocketAddress::IsMatchingType (from)) + Ptr packet; + while (packet = socket->Recv ()) { - InetSocketAddress address = InetSocketAddress::ConvertFrom (from); - NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " << - address.GetIpv4()); + SocketRxAddressTag tag; + bool found; + found = packet->FindFirstMatchingTag (tag); + NS_ASSERT (found); + Address from = tag.GetAddress (); + // XXX packet->RemoveTag (tag); + if (InetSocketAddress::IsMatchingType (from)) + { + InetSocketAddress address = InetSocketAddress::ConvertFrom (from); + NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " << + address.GetIpv4()); - NS_LOG_LOGIC ("Echoing packet"); - socket->SendTo (from, packet); + NS_LOG_LOGIC ("Echoing packet"); + socket->SendTo (packet, from); + } } } diff --git a/src/applications/udp-echo/udp-echo-server.h b/src/applications/udp-echo/udp-echo-server.h index e0f55b4cd..4e2b09fce 100644 --- a/src/applications/udp-echo/udp-echo-server.h +++ b/src/applications/udp-echo/udp-echo-server.h @@ -49,7 +49,7 @@ private: virtual void StartApplication (void); virtual void StopApplication (void); - void Receive(Ptr socket, Ptr packet, const Address &from); + void HandleRead (Ptr socket); uint16_t m_port; Ptr m_socket; diff --git a/src/common/data-rate.h b/src/common/data-rate.h index 90a81ace8..3ebdbeaab 100644 --- a/src/common/data-rate.h +++ b/src/common/data-rate.h @@ -80,7 +80,6 @@ public: */ uint64_t GetBitRate() const; - ATTRIBUTE_HELPER_HEADER_1 (DataRate); private: uint64_t m_bps; static uint64_t Parse(const std::string); @@ -94,7 +93,7 @@ std::istream &operator >> (std::istream &is, DataRate &rate); * \brief hold objects of type ns3::DataRate */ -ATTRIBUTE_HELPER_HEADER_2 (DataRate); +ATTRIBUTE_HELPER_HEADER (DataRate); /** * \param lhs diff --git a/src/contrib/gtk-config-store.cc b/src/contrib/gtk-config-store.cc index 025d47d3e..966900a03 100644 --- a/src/contrib/gtk-config-store.cc +++ b/src/contrib/gtk-config-store.cc @@ -304,7 +304,7 @@ cell_tooltip_callback (GtkWidget *widget, } break; case ModelNode::NODE_ATTRIBUTE: { - uint32_t attrIndex; + uint32_t attrIndex = 0; TypeId tid; for (tid = node->object->GetInstanceTypeId (); tid.HasParent (); tid = tid.GetParent ()) { diff --git a/src/core/attribute-helper.h b/src/core/attribute-helper.h index 1b31326b0..7e86578a5 100644 --- a/src/core/attribute-helper.h +++ b/src/core/attribute-helper.h @@ -83,8 +83,7 @@ MakeSimpleAttributeChecker (std::string name, std::string underlying) * * The simple macros are implemented in terms of the complex * macros and should generally be prefered over the complex macros: - * - \ref ATTRIBUTE_HELPER_HEADER_1, - * - \ref ATTRIBUTE_HELPER_HEADER_2, and, + * - \ref ATTRIBUTE_HELPER_HEADER, and, * - \ref ATTRIBUTE_HELPER_CPP, */ @@ -232,15 +231,6 @@ MakeSimpleAttributeChecker (std::string name, std::string underlying) #define ATTRIBUTE_CONVERTER_IMPLEMENT(type) -/** - * \ingroup AttributeHelper - * \param type the name of the class - * - * This macro should be invoked from a public section of the class - * declaration. - */ -#define ATTRIBUTE_HELPER_HEADER_1(type) - /** * \ingroup AttributeHelper * \param type the name of the class @@ -248,7 +238,7 @@ MakeSimpleAttributeChecker (std::string name, std::string underlying) * This macro should be invoked outside of the class * declaration in its public header. */ -#define ATTRIBUTE_HELPER_HEADER_2(type) \ +#define ATTRIBUTE_HELPER_HEADER(type) \ ATTRIBUTE_VALUE_DEFINE (type); \ ATTRIBUTE_ACCESSOR_DEFINE (type); \ ATTRIBUTE_CHECKER_DEFINE (type); diff --git a/src/core/attribute-test.cc b/src/core/attribute-test.cc index e1c694a3d..64eee0837 100644 --- a/src/core/attribute-test.cc +++ b/src/core/attribute-test.cc @@ -53,7 +53,7 @@ std::istream & operator >> (std::istream &is, ValueClassTest &v) { return is; } -ATTRIBUTE_HELPER_HEADER_2 (ValueClassTest); +ATTRIBUTE_HELPER_HEADER (ValueClassTest); ATTRIBUTE_HELPER_CPP (ValueClassTest); class AttributeTest : public Test diff --git a/src/core/log.h b/src/core/log.h index fd87ace1a..554d16815 100644 --- a/src/core/log.h +++ b/src/core/log.h @@ -69,7 +69,7 @@ #define NS_LOG_COMPONENT_DEFINE(name) \ static ns3::LogComponent g_log = ns3::LogComponent (name) -#define APPEND_TIME_PREFIX \ +#define NS_LOG_APPEND_TIME_PREFIX \ if (g_log.IsEnabled (ns3::LOG_PREFIX_TIME)) \ { \ LogTimePrinter printer = LogGetTimePrinter (); \ @@ -80,13 +80,17 @@ } \ } -#define APPEND_FUNC_PREFIX \ +#define NS_LOG_APPEND_FUNC_PREFIX \ if (g_log.IsEnabled (ns3::LOG_PREFIX_FUNC)) \ { \ std::clog << g_log.Name () << ":" << \ __FUNCTION__ << "(): "; \ } \ +#ifndef NS_LOG_APPEND_CONTEXT +#define NS_LOG_APPEND_CONTEXT +#endif /* NS_LOG_APPEND_CONTEXT */ + /** * \ingroup logging @@ -107,8 +111,9 @@ { \ if (g_log.IsEnabled (level)) \ { \ - APPEND_TIME_PREFIX; \ - APPEND_FUNC_PREFIX; \ + NS_LOG_APPEND_TIME_PREFIX; \ + NS_LOG_APPEND_CONTEXT; \ + NS_LOG_APPEND_FUNC_PREFIX; \ std::clog << msg << std::endl; \ } \ } \ @@ -160,7 +165,8 @@ { \ if (g_log.IsEnabled (ns3::LOG_FUNCTION)) \ { \ - APPEND_TIME_PREFIX; \ + NS_LOG_APPEND_TIME_PREFIX; \ + NS_LOG_APPEND_CONTEXT; \ std::clog << g_log.Name () << ":" \ << __FUNCTION__ << "()" << std::endl; \ } \ @@ -189,7 +195,8 @@ { \ if (g_log.IsEnabled (ns3::LOG_FUNCTION)) \ { \ - APPEND_TIME_PREFIX; \ + NS_LOG_APPEND_TIME_PREFIX; \ + NS_LOG_APPEND_CONTEXT; \ std::clog << g_log.Name () << ":" \ << __FUNCTION__ << "("; \ ParameterLogger (std::clog) << parameters; \ diff --git a/src/core/object-factory.h b/src/core/object-factory.h index ccfdc4177..01f9341ed 100644 --- a/src/core/object-factory.h +++ b/src/core/object-factory.h @@ -77,7 +77,6 @@ public: template Ptr Create (void) const; - ATTRIBUTE_HELPER_HEADER_1 (ObjectFactory); private: friend std::ostream & operator << (std::ostream &os, const ObjectFactory &factory); friend std::istream & operator >> (std::istream &is, ObjectFactory &factory); @@ -94,7 +93,7 @@ std::istream & operator >> (std::istream &is, ObjectFactory &factory); * \brief hold objects of type ns3::ObjectFactory */ -ATTRIBUTE_HELPER_HEADER_2 (ObjectFactory); +ATTRIBUTE_HELPER_HEADER (ObjectFactory); } // namespace ns3 diff --git a/src/core/type-id.cc b/src/core/type-id.cc index 339cbb368..bd1bbd211 100644 --- a/src/core/type-id.cc +++ b/src/core/type-id.cc @@ -386,7 +386,7 @@ TypeId TypeId::LookupByName (std::string name) { uint16_t uid = Singleton::Get ()->GetUid (name); - NS_ASSERT (uid != 0); + NS_ASSERT_MSG (uid != 0, "Assert in TypeId::LookupByName: " << name << " not found"); return TypeId (uid); } bool diff --git a/src/core/type-id.h b/src/core/type-id.h index 713f8cb5a..48455f06f 100644 --- a/src/core/type-id.h +++ b/src/core/type-id.h @@ -354,7 +354,6 @@ public: TypeId (); ~TypeId (); - ATTRIBUTE_HELPER_HEADER_1 (TypeId); private: friend class AttributeList; friend bool operator == (TypeId a, TypeId b); @@ -388,7 +387,7 @@ bool operator < (TypeId a, TypeId b); */ -ATTRIBUTE_HELPER_HEADER_2 (TypeId); +ATTRIBUTE_HELPER_HEADER (TypeId); } // namespace ns3 diff --git a/src/devices/wifi/ssid.h b/src/devices/wifi/ssid.h index 0feed168b..dc47e0787 100644 --- a/src/devices/wifi/ssid.h +++ b/src/devices/wifi/ssid.h @@ -49,7 +49,6 @@ public: Buffer::Iterator Serialize (Buffer::Iterator i) const; Buffer::Iterator Deserialize (Buffer::Iterator i); - ATTRIBUTE_HELPER_HEADER_1 (Ssid); private: uint8_t m_ssid[33]; uint8_t m_length; @@ -63,7 +62,7 @@ std::istream &operator >> (std::istream &is, Ssid &ssid); * \brief hold objects of type ns3::Ssid */ -ATTRIBUTE_HELPER_HEADER_2 (Ssid); +ATTRIBUTE_HELPER_HEADER (Ssid); } // namespace ns3 diff --git a/src/devices/wifi/wifi-mode.h b/src/devices/wifi/wifi-mode.h index 9b15a203e..24ea1163d 100644 --- a/src/devices/wifi/wifi-mode.h +++ b/src/devices/wifi/wifi-mode.h @@ -107,7 +107,6 @@ class WifiMode */ WifiMode (); - ATTRIBUTE_HELPER_HEADER_1 (WifiMode); private: friend class WifiModeFactory; WifiMode (uint32_t uid); @@ -123,7 +122,7 @@ std::istream & operator >> (std::istream &is, WifiMode &mode); * \brief hold objects of type ns3::WifiMode */ -ATTRIBUTE_HELPER_HEADER_2 (WifiMode); +ATTRIBUTE_HELPER_HEADER (WifiMode); /** * \brief create WifiMode class instances and keep track of them. diff --git a/src/helper/packet-sink-helper.cc b/src/helper/packet-sink-helper.cc index 45f1d17a6..ef2704114 100644 --- a/src/helper/packet-sink-helper.cc +++ b/src/helper/packet-sink-helper.cc @@ -41,13 +41,13 @@ PacketSinkHelper::SetAttribute (std::string name, const AttributeValue &value) void PacketSinkHelper::SetUdpLocal (Ipv4Address ip, uint16_t port) { - m_factory.Set ("Protocol", String ("ns3::Udp")); + m_factory.Set ("Protocol", String ("ns3::UdpSocketFactory")); m_factory.Set ("Local", Address (InetSocketAddress (ip, port))); } void PacketSinkHelper::SetTcpLocal (Ipv4Address ip, uint16_t port) { - m_factory.Set ("Protocol", String ("ns3::Tcp")); + m_factory.Set ("Protocol", String ("ns3::TcpSocketFactory")); m_factory.Set ("Local", Address (InetSocketAddress (ip, port))); } #endif diff --git a/src/internet-node/internet-stack.cc b/src/internet-node/internet-stack.cc index 916f436ac..5b8f3bfd1 100644 --- a/src/internet-node/internet-stack.cc +++ b/src/internet-node/internet-stack.cc @@ -27,8 +27,8 @@ #include "tcp-l4-protocol.h" #include "ipv4-l3-protocol.h" #include "arp-l3-protocol.h" -#include "udp-impl.h" -#include "tcp-impl.h" +#include "udp-socket-factory-impl.h" +#include "tcp-socket-factory-impl.h" #include "ipv4-impl.h" namespace ns3 { @@ -58,19 +58,19 @@ AddInternetStack (Ptr node) ipv4L4Demux->Insert (udp); ipv4L4Demux->Insert (tcp); - Ptr udpImpl = CreateObject (); - Ptr tcpImpl = CreateObject (); + Ptr udpFactory = CreateObject (); + Ptr tcpFactory = CreateObject (); Ptr ipv4Impl = CreateObject (); - udpImpl->SetUdp (udp); - tcpImpl->SetTcp (tcp); + udpFactory->SetUdp (udp); + tcpFactory->SetTcp (tcp); ipv4Impl->SetIpv4 (ipv4); node->AggregateObject (ipv4); node->AggregateObject (arp); node->AggregateObject (ipv4Impl); - node->AggregateObject (udpImpl); - node->AggregateObject (tcpImpl); + node->AggregateObject (udpFactory); + node->AggregateObject (tcpFactory); node->AggregateObject (ipv4L4Demux); } diff --git a/src/internet-node/ipv4-l3-protocol.cc b/src/internet-node/ipv4-l3-protocol.cc index 3067c4747..7892f9bcd 100644 --- a/src/internet-node/ipv4-l3-protocol.cc +++ b/src/internet-node/ipv4-l3-protocol.cc @@ -24,6 +24,7 @@ #include "ns3/ipv4-address.h" #include "ns3/ipv4-route.h" #include "ns3/node.h" +#include "ns3/socket.h" #include "ns3/net-device.h" #include "ns3/uinteger.h" #include "ns3/trace-source-accessor.h" @@ -491,6 +492,34 @@ Ipv4L3Protocol::Send (Ptr packet, m_identification ++; + // Set TTL to 1 if it is a broadcast packet of any type. Otherwise, + // possibly override the default TTL if the packet is tagged + SocketIpTtlTag tag; + bool found = packet->FindFirstMatchingTag (tag); + + if (destination.IsBroadcast ()) + { + ipHeader.SetTtl (1); + } + else if (found) + { + ipHeader.SetTtl (tag.GetTtl ()); + // XXX remove tag here? + } + else + { + uint32_t ifaceIndex = 0; + for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin (); + ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++) + { + Ptr outInterface = *ifaceIter; + if (destination.IsSubnetDirectedBroadcast ( + outInterface->GetNetworkMask ())) + { + ipHeader.SetTtl (1); + } + } + } if (destination.IsBroadcast ()) { uint32_t ifaceIndex = 0; diff --git a/src/internet-node/tcp-header.cc b/src/internet-node/tcp-header.cc index f5c485999..c0f476220 100644 --- a/src/internet-node/tcp-header.cc +++ b/src/internet-node/tcp-header.cc @@ -20,7 +20,7 @@ #include #include -#include "tcp-socket.h" +#include "tcp-socket-impl.h" #include "tcp-header.h" #include "ns3/buffer.h" diff --git a/src/internet-node/tcp-header.h b/src/internet-node/tcp-header.h index 3181b03be..e676287f6 100644 --- a/src/internet-node/tcp-header.h +++ b/src/internet-node/tcp-header.h @@ -24,7 +24,7 @@ #include #include "ns3/header.h" #include "ns3/buffer.h" -#include "ns3/tcp.h" +#include "ns3/tcp-socket-factory.h" #include "ns3/ipv4-address.h" #include "ns3/sequence-number.h" diff --git a/src/internet-node/tcp-l4-protocol.cc b/src/internet-node/tcp-l4-protocol.cc index 653575db0..2898b09f4 100644 --- a/src/internet-node/tcp-l4-protocol.cc +++ b/src/internet-node/tcp-l4-protocol.cc @@ -30,7 +30,7 @@ #include "ipv4-end-point-demux.h" #include "ipv4-end-point.h" #include "ipv4-l3-protocol.h" -#include "tcp-socket.h" +#include "tcp-socket-impl.h" #include "tcp-typedefs.h" @@ -379,7 +379,7 @@ TcpL4Protocol::CreateSocket (void) { NS_LOG_FUNCTION_NOARGS (); Ptr rtt = m_rttFactory.Create (); - Ptr socket = CreateObject (); + Ptr socket = CreateObject (); socket->SetNode (m_node); socket->SetTcp (this); socket->SetRtt (rtt); diff --git a/src/internet-node/tcp-l4-protocol.h b/src/internet-node/tcp-l4-protocol.h index 8936460e3..4555b004e 100644 --- a/src/internet-node/tcp-l4-protocol.h +++ b/src/internet-node/tcp-l4-protocol.h @@ -58,7 +58,7 @@ public: virtual int GetVersion (void) const; /** - * \return A smart Socket pointer to a TcpSocket, allocated by this instance + * \return A smart Socket pointer to a TcpSocketImpl, allocated by this instance * of the TCP protocol */ Ptr CreateSocket (void); @@ -72,7 +72,7 @@ public: void DeAllocate (Ipv4EndPoint *endPoint); -// // called by TcpSocket. +// // called by TcpSocketImpl. // bool Connect (const Ipv4Address& saddr, const Ipv4Address& daddr, // uint16_t sport, uint16_t dport); @@ -106,7 +106,7 @@ private: Ipv4EndPointDemux *m_endPoints; ObjectFactory m_rttFactory; private: - friend class TcpSocket; + friend class TcpSocketImpl; void SendPacket (Ptr, TcpHeader, Ipv4Address, Ipv4Address); static ObjectFactory GetDefaultRttEstimatorFactory (void); diff --git a/src/internet-node/tcp-impl.cc b/src/internet-node/tcp-socket-factory-impl.cc similarity index 78% rename from src/internet-node/tcp-impl.cc rename to src/internet-node/tcp-socket-factory-impl.cc index 5a1ad3954..ef806adf4 100644 --- a/src/internet-node/tcp-impl.cc +++ b/src/internet-node/tcp-socket-factory-impl.cc @@ -17,38 +17,38 @@ * * Author: Raj Bhattacharjea */ -#include "tcp-impl.h" +#include "tcp-socket-factory-impl.h" #include "tcp-l4-protocol.h" #include "ns3/socket.h" #include "ns3/assert.h" namespace ns3 { -TcpImpl::TcpImpl () +TcpSocketFactoryImpl::TcpSocketFactoryImpl () : m_tcp (0) {} -TcpImpl::~TcpImpl () +TcpSocketFactoryImpl::~TcpSocketFactoryImpl () { NS_ASSERT (m_tcp == 0); } void -TcpImpl::SetTcp (Ptr tcp) +TcpSocketFactoryImpl::SetTcp (Ptr tcp) { m_tcp = tcp; } Ptr -TcpImpl::CreateSocket (void) +TcpSocketFactoryImpl::CreateSocket (void) { return m_tcp->CreateSocket (); } void -TcpImpl::DoDispose (void) +TcpSocketFactoryImpl::DoDispose (void) { m_tcp = 0; - Tcp::DoDispose (); + TcpSocketFactory::DoDispose (); } } // namespace ns3 diff --git a/src/internet-node/tcp-impl.h b/src/internet-node/tcp-socket-factory-impl.h similarity index 81% rename from src/internet-node/tcp-impl.h rename to src/internet-node/tcp-socket-factory-impl.h index 9990c7721..38bf123a2 100644 --- a/src/internet-node/tcp-impl.h +++ b/src/internet-node/tcp-socket-factory-impl.h @@ -17,10 +17,10 @@ * * Author: Raj Bhattacharjea */ -#ifndef TCP_IMPL_H -#define TCP_IMPL_H +#ifndef TCP_SOCKET_FACTORY_IMPL_H +#define TCP_SOCKET_FACTORY_IMPL_H -#include "ns3/tcp.h" +#include "ns3/tcp-socket-factory.h" #include "ns3/ptr.h" namespace ns3 { @@ -37,13 +37,13 @@ class TcpL4Protocol; * * Georgia Tech Network Simulator (GTNetS). * - * Most of the logic is in class ns3::TcpSocket. + * Most of the logic is in class ns3::TcpSocketImpl. */ -class TcpImpl : public Tcp +class TcpSocketFactoryImpl : public TcpSocketFactory { public: - TcpImpl (); - virtual ~TcpImpl (); + TcpSocketFactoryImpl (); + virtual ~TcpSocketFactoryImpl (); void SetTcp (Ptr tcp); @@ -57,4 +57,4 @@ private: } // namespace ns3 -#endif /* TCP_IMPL_H */ +#endif /* TCP_SOCKET_FACTORY_IMPL_H */ diff --git a/src/internet-node/tcp-socket.cc b/src/internet-node/tcp-socket-impl.cc similarity index 75% rename from src/internet-node/tcp-socket.cc rename to src/internet-node/tcp-socket-impl.cc index ef6a40dc2..57c0e0d09 100644 --- a/src/internet-node/tcp-socket.cc +++ b/src/internet-node/tcp-socket-impl.cc @@ -23,7 +23,7 @@ #include "ns3/inet-socket-address.h" #include "ns3/log.h" #include "ns3/ipv4.h" -#include "tcp-socket.h" +#include "tcp-socket-impl.h" #include "tcp-l4-protocol.h" #include "ipv4-end-point.h" #include "ipv4-l4-demux.h" @@ -31,31 +31,32 @@ #include "tcp-typedefs.h" #include "ns3/simulator.h" #include "ns3/packet.h" +#include "ns3/uinteger.h" #include "ns3/trace-source-accessor.h" #include -NS_LOG_COMPONENT_DEFINE ("TcpSocket"); +NS_LOG_COMPONENT_DEFINE ("TcpSocketImpl"); using namespace std; namespace ns3 { -NS_OBJECT_ENSURE_REGISTERED (TcpSocket); +NS_OBJECT_ENSURE_REGISTERED (TcpSocketImpl); TypeId -TcpSocket::GetTypeId () +TcpSocketImpl::GetTypeId () { - static TypeId tid = TypeId("ns3::TcpSocket") - .SetParent () + static TypeId tid = TypeId("ns3::TcpSocketImpl") + .SetParent () .AddTraceSource ("CongestionWindow", "The TCP connection's congestion window", - MakeTraceSourceAccessor (&TcpSocket::m_cWnd)) + MakeTraceSourceAccessor (&TcpSocketImpl::m_cWnd)) ; return tid; } - TcpSocket::TcpSocket () + TcpSocketImpl::TcpSocketImpl () : m_skipRetxResched (false), m_dupAckCount (0), m_delAckCount (0), @@ -78,19 +79,20 @@ TcpSocket::GetTypeId () m_nextRxSequence (0), m_pendingData (0), m_rtt (0), - m_lastMeasuredRtt (Seconds(0.0)) + m_lastMeasuredRtt (Seconds(0.0)), + m_rxAvailable (0), + m_wouldBlock (false) { NS_LOG_FUNCTION (this); - } -TcpSocket::TcpSocket(const TcpSocket& sock) - : Socket(sock), //copy the base class callbacks +TcpSocketImpl::TcpSocketImpl(const TcpSocketImpl& sock) + : TcpSocket(sock), //copy the base class callbacks m_skipRetxResched (sock.m_skipRetxResched), m_dupAckCount (sock.m_dupAckCount), m_delAckCount (0), m_delAckMaxCount (sock.m_delAckMaxCount), - m_delAckTimout (sock.m_delAckTimout), + m_delAckTimeout (sock.m_delAckTimeout), m_endPoint (0), m_node (sock.m_node), m_tcp (sock.m_tcp), @@ -122,7 +124,8 @@ TcpSocket::TcpSocket(const TcpSocket& sock) m_rtt (0), m_lastMeasuredRtt (Seconds(0.0)), m_cnTimeout (sock.m_cnTimeout), - m_cnCount (sock.m_cnCount) + m_cnCount (sock.m_cnCount), + m_rxAvailable (0) { NS_LOG_FUNCTION_NOARGS (); NS_LOG_LOGIC("Invoked the copy constructor"); @@ -140,7 +143,7 @@ TcpSocket::TcpSocket(const TcpSocket& sock) //too; this is in SYN_ACK_TX } -TcpSocket::~TcpSocket () +TcpSocketImpl::~TcpSocketImpl () { NS_LOG_FUNCTION(this); m_node = 0; @@ -165,50 +168,42 @@ TcpSocket::~TcpSocket () } void -TcpSocket::SetNode (Ptr node) +TcpSocketImpl::SetNode (Ptr node) { m_node = node; - Ptr t = node->GetObject (); - m_segmentSize = t->GetDefaultSegSize (); - m_rxWindowSize = t->GetDefaultAdvWin (); - m_advertisedWindowSize = t->GetDefaultAdvWin (); - m_cWnd = t->GetDefaultInitialCwnd () * m_segmentSize; - m_ssThresh = t->GetDefaultSsThresh (); - m_initialCWnd = t->GetDefaultInitialCwnd (); - m_cnTimeout = Seconds (t->GetDefaultConnTimeout ()); - m_cnCount = t->GetDefaultConnCount (); - m_delAckTimout = Seconds(t->GetDefaultDelAckTimeout ()); - m_delAckMaxCount = t->GetDefaultDelAckCount (); + // Initialize some variables + m_cWnd = m_initialCWnd * m_segmentSize; + m_rxWindowSize = m_advertisedWindowSize; } void -TcpSocket::SetTcp (Ptr tcp) +TcpSocketImpl::SetTcp (Ptr tcp) { m_tcp = tcp; } void -TcpSocket::SetRtt (Ptr rtt) +TcpSocketImpl::SetRtt (Ptr rtt) { m_rtt = rtt; } enum Socket::SocketErrno -TcpSocket::GetErrno (void) const +TcpSocketImpl::GetErrno (void) const { NS_LOG_FUNCTION_NOARGS (); return m_errno; } Ptr -TcpSocket::GetNode (void) const +TcpSocketImpl::GetNode (void) const { NS_LOG_FUNCTION_NOARGS (); return m_node; } void -TcpSocket::Destroy (void) +TcpSocketImpl::Destroy (void) { NS_LOG_FUNCTION_NOARGS (); m_node = 0; @@ -217,29 +212,29 @@ TcpSocket::Destroy (void) m_retxEvent.Cancel (); } int -TcpSocket::FinishBind (void) +TcpSocketImpl::FinishBind (void) { NS_LOG_FUNCTION_NOARGS (); if (m_endPoint == 0) { return -1; } - m_endPoint->SetRxCallback (MakeCallback (&TcpSocket::ForwardUp, Ptr(this))); - m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocket::Destroy, Ptr(this))); + m_endPoint->SetRxCallback (MakeCallback (&TcpSocketImpl::ForwardUp, Ptr(this))); + m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocketImpl::Destroy, Ptr(this))); m_localAddress = m_endPoint->GetLocalAddress (); m_localPort = m_endPoint->GetLocalPort (); return 0; } int -TcpSocket::Bind (void) +TcpSocketImpl::Bind (void) { NS_LOG_FUNCTION_NOARGS (); m_endPoint = m_tcp->Allocate (); return FinishBind (); } int -TcpSocket::Bind (const Address &address) +TcpSocketImpl::Bind (const Address &address) { NS_LOG_FUNCTION (this<Allocate (); - NS_LOG_LOGIC ("TcpSocket "<Allocate (port); - NS_LOG_LOGIC ("TcpSocket "<Allocate (ipv4); - NS_LOG_LOGIC ("TcpSocket "<Allocate (ipv4, port); - NS_LOG_LOGIC ("TcpSocket "< p) //p here is just data, no headers +TcpSocketImpl::Send (const Ptr p) //p here is just data, no headers { // TCP Does not deal with packets from app, just data return Send(p->PeekData(), p->GetSize()); } -int TcpSocket::Send (const uint8_t* buf, uint32_t size) +int TcpSocketImpl::Send (const uint8_t* buf, uint32_t size) { NS_LOG_FUNCTION (this << buf << size); if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT) - { // Ok to buffer some data to send + { + if (size > GetTxAvailable ()) + { + m_wouldBlock = true; + m_errno = ERROR_MSGSIZE; + return -1; + } if (!m_pendingData) - { - m_pendingData = new PendingData (); // Create if non-existent - m_firstPendingSequence = m_nextTxSequence; // Note seq of first - } + { + m_pendingData = new PendingData (); // Create if non-existent + m_firstPendingSequence = m_nextTxSequence; // Note seq of first + } //PendingData::Add always copies the data buffer, never modifies m_pendingData->Add (size,buf); NS_LOG_DEBUG("TcpSock::Send, pdsize " << m_pendingData->Size() << " state " << m_state); Actions_t action = ProcessEvent (APP_SEND); NS_LOG_DEBUG(" action " << action); - // We do not model any limit to the buffer, so report that the - // maximum is available - NotifySend (std::numeric_limits::max ()); if (!ProcessAction (action)) { return -1; // Failed, return zero @@ -386,7 +384,7 @@ int TcpSocket::Send (const uint8_t* buf, uint32_t size) } } -int TcpSocket::DoSendTo (Ptr p, const Address &address) +int TcpSocketImpl::DoSendTo (Ptr p, const Address &address) { NS_LOG_FUNCTION (this << p << address); InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); @@ -395,7 +393,7 @@ int TcpSocket::DoSendTo (Ptr p, const Address &address) return DoSendTo (p, ipv4, port); } -int TcpSocket::DoSendTo (Ptr p, Ipv4Address ipv4, uint16_t port) +int TcpSocketImpl::DoSendTo (Ptr p, Ipv4Address ipv4, uint16_t port) { NS_LOG_FUNCTION (this << p << ipv4 << port); if (m_endPoint == 0) @@ -419,7 +417,7 @@ int TcpSocket::DoSendTo (Ptr p, Ipv4Address ipv4, uint16_t port) } int -TcpSocket::SendTo (const Address &address, Ptr p) +TcpSocketImpl::SendTo (Ptr p, const Address &address) { NS_LOG_FUNCTION (this << address << p); if (!m_connected) @@ -433,8 +431,25 @@ TcpSocket::SendTo (const Address &address, Ptr p) } } +uint32_t +TcpSocketImpl::GetTxAvailable (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_pendingData != 0) + { + uint32_t unAckedDataSize = + m_pendingData->SizeFromSeq (m_firstPendingSequence, m_highestRxAck); + NS_ASSERT (m_sndBufSize >= unAckedDataSize); //else a logical error + return m_sndBufSize-unAckedDataSize; + } + else + { + return m_sndBufSize; + } +} + int -TcpSocket::Listen (uint32_t q) +TcpSocketImpl::Listen (uint32_t q) { NS_LOG_FUNCTION (this << q); Actions_t action = ProcessEvent (APP_LISTEN); @@ -442,8 +457,38 @@ TcpSocket::Listen (uint32_t q) return 0; } +Ptr +TcpSocketImpl::Recv (uint32_t maxSize, uint32_t flags) +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_deliveryQueue.empty() ) + { + return 0; + } + Ptr p = m_deliveryQueue.front (); + if (p->GetSize () <= maxSize) + { + m_deliveryQueue.pop (); + m_rxAvailable -= p->GetSize (); + } + else + { + p = 0; + } + return p; +} + +uint32_t +TcpSocketImpl::GetRxAvailable (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + // We separately maintain this state to avoid walking the queue + // every time this might be called + return m_rxAvailable; +} + void -TcpSocket::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) +TcpSocketImpl::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) { NS_LOG_DEBUG("Socket " << this << " got forward up" << " dport " << m_endPoint->GetLocalPort() << @@ -477,26 +522,26 @@ TcpSocket::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) ProcessPacketAction (action, packet, tcpHeader, address); } -Actions_t TcpSocket::ProcessEvent (Events_t e) +Actions_t TcpSocketImpl::ProcessEvent (Events_t e) { NS_LOG_FUNCTION (this << e); States_t saveState = m_state; - NS_LOG_LOGIC ("TcpSocket " << this << " processing event " << e); + NS_LOG_LOGIC ("TcpSocketImpl " << this << " processing event " << e); // simulation singleton is a way to get a single global static instance of a // class intended to be a singleton; see simulation-singleton.h SA stateAction = SimulationSingleton::Get ()->Lookup (m_state,e); // debug if (stateAction.action == RST_TX) { - NS_LOG_LOGIC ("TcpSocket " << this << " sending RST from state " + NS_LOG_LOGIC ("TcpSocketImpl " << this << " sending RST from state " << saveState << " event " << e); } bool needCloseNotify = (stateAction.state == CLOSED && m_state != CLOSED && e != TIMEOUT); m_state = stateAction.state; - NS_LOG_LOGIC ("TcpSocket " << this << " moved from state " << saveState + NS_LOG_LOGIC ("TcpSocketImpl " << this << " moved from state " << saveState << " to state " <SetPeer (m_remoteAddress, m_remotePort); - NS_LOG_LOGIC ("TcpSocket " << this << " Connected!"); + NS_LOG_LOGIC ("TcpSocketImpl " << this << " Connected!"); } if (needCloseNotify && !m_closeNotified) { - NS_LOG_LOGIC ("TcpSocket " << this << " transition to CLOSED from " + NS_LOG_LOGIC ("TcpSocketImpl " << this << " transition to CLOSED from " << m_state << " event " << e << " closeNot " << m_closeNotified << " action " << stateAction.action); NotifyCloseCompleted (); m_closeNotified = true; - NS_LOG_LOGIC ("TcpSocket " << this << " calling Closed from PE" + NS_LOG_LOGIC ("TcpSocketImpl " << this << " calling Closed from PE" << " origState " << saveState << " event " << e); - NS_LOG_LOGIC ("TcpSocket " << this << " transition to CLOSED from " + NS_LOG_LOGIC ("TcpSocketImpl " << this << " transition to CLOSED from " << m_state << " event " << e << " set CloseNotif "); } return stateAction.action; } -void TcpSocket::SendEmptyPacket (uint8_t flags) +void TcpSocketImpl::SendEmptyPacket (uint8_t flags) { NS_LOG_FUNCTION (this << flags); Ptr p = Create (); @@ -554,17 +599,17 @@ void TcpSocket::SendEmptyPacket (uint8_t flags) NS_LOG_LOGIC ("Schedule retransmission timeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds ()); - m_retxEvent = Simulator::Schedule (rto, &TcpSocket::ReTxTimeout, this); + m_retxEvent = Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this); } } -bool TcpSocket::ProcessAction (Actions_t a) +bool TcpSocketImpl::ProcessAction (Actions_t a) { // These actions do not require a packet or any TCP Headers NS_LOG_FUNCTION (this << a); switch (a) { case NO_ACT: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action: NO_ACT"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action: NO_ACT"); break; case ACK_TX: SendEmptyPacket (TcpHeader::ACK); @@ -573,11 +618,11 @@ bool TcpSocket::ProcessAction (Actions_t a) NS_ASSERT (false); // This should be processed in ProcessPacketAction break; case RST_TX: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action RST_TX"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action RST_TX"); SendEmptyPacket (TcpHeader::RST); break; case SYN_TX: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_TX"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SYN_TX"); // TCP SYN Flag consumes one byte // is the above correct? we're SENDING a syn, not acking back -- Raj // commented out for now @@ -585,17 +630,17 @@ bool TcpSocket::ProcessAction (Actions_t a) SendEmptyPacket (TcpHeader::SYN); break; case SYN_ACK_TX: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_ACK_TX"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SYN_ACK_TX"); // TCP SYN Flag consumes one byte ++m_nextRxSequence; SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK); break; case FIN_TX: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action FIN_TX"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action FIN_TX"); SendEmptyPacket (TcpHeader::FIN); break; case FIN_ACK_TX: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action FIN_ACK_TX"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action FIN_ACK_TX"); SendEmptyPacket (TcpHeader::FIN | TcpHeader::ACK); break; case NEW_ACK: @@ -605,36 +650,36 @@ bool TcpSocket::ProcessAction (Actions_t a) NS_ASSERT (false); // This should be processed in ProcessPacketAction break; case RETX: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action RETX"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action RETX"); break; case TX_DATA: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action TX_DATA"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action TX_DATA"); SendPendingData (); break; case PEER_CLOSE: NS_ASSERT (false); // This should be processed in ProcessPacketAction - NS_LOG_LOGIC ("TcpSocket " << this <<" Action PEER_CLOSE"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action PEER_CLOSE"); break; case APP_CLOSED: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action APP_CLOSED"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action APP_CLOSED"); break; case CANCEL_TM: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action CANCEL_TM"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action CANCEL_TM"); break; case APP_NOTIFY: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action APP_NOTIFY"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action APP_NOTIFY"); break; case SERV_NOTIFY: NS_ASSERT (false); // This should be processed in ProcessPacketAction break; case LAST_ACTION: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action LAST_ACTION"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action LAST_ACTION"); break; } return true; } -bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr p, +bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr p, const TcpHeader& tcpHeader, const Address& fromAddress) { @@ -644,24 +689,24 @@ bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr p, switch (a) { case SYN_ACK_TX: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_ACK_TX"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SYN_ACK_TX"); // m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort (); // m_remoteAddress = InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 (); // if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex)) // { // m_localAddress = ipv4->GetAddress (localIfIndex); // } - if (m_state == LISTEN) //this means we should fork a new TcpSocket + if (m_state == LISTEN) //this means we should fork a new TcpSocketImpl { NS_LOG_DEBUG("In SYN_ACK_TX, m_state is LISTEN, this " << this); //notify the server that we got a SYN // If server refuses connection do nothing if (!NotifyConnectionRequest(fromAddress)) return true; // Clone the socket - Ptr newSock = Copy (); - NS_LOG_LOGIC ("Cloned a TcpSocket " << newSock); + Ptr newSock = Copy (); + NS_LOG_LOGIC ("Cloned a TcpSocketImpl " << newSock); //this listening socket should do nothing more - Simulator::ScheduleNow (&TcpSocket::CompleteFork, newSock, + Simulator::ScheduleNow (&TcpSocketImpl::CompleteFork, newSock, p, tcpHeader,fromAddress); return true; } @@ -680,26 +725,29 @@ bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr p, SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK); break; case ACK_TX_1: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action ACK_TX_1"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action ACK_TX_1"); // TCP SYN consumes one byte m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1); m_nextTxSequence = tcpHeader.GetAckNumber (); m_firstPendingSequence = m_nextTxSequence; //bug 166 - NS_LOG_DEBUG ("TcpSocket " << this << " ACK_TX_1" << + NS_LOG_DEBUG ("TcpSocketImpl " << this << " ACK_TX_1" << " nextRxSeq " << m_nextRxSequence); SendEmptyPacket (TcpHeader::ACK); m_rxWindowSize = tcpHeader.GetWindowSize (); if (tcpHeader.GetAckNumber () > m_highestRxAck) { m_highestRxAck = tcpHeader.GetAckNumber (); - // We do not model any limit to the buffer, so report that the - // maximum is available - NotifySend (std::numeric_limits::max ()); + // Data freed from the send buffer; notify any blocked sender + if (m_wouldBlock) + { + NotifySend (GetTxAvailable ()); + m_wouldBlock = false; + } } SendPendingData (); break; case NEW_ACK: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action NEW_ACK_TX"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action NEW_ACK_TX"); if (tcpHeader.GetAckNumber () < m_highestRxAck) //old ack, do nothing { break; @@ -717,7 +765,7 @@ bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr p, NewAck (tcpHeader.GetAckNumber ()); break; case NEW_SEQ_RX: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action NEW_SEQ_RX"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action NEW_SEQ_RX"); NewRx (p, tcpHeader, fromAddress); // Process new data received break; case PEER_CLOSE: @@ -728,7 +776,7 @@ bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr p, if (tcpHeader.GetSequenceNumber () != m_nextRxSequence) { // process close later m_pendingClose = true; - NS_LOG_LOGIC ("TcpSocket " << this << " setting pendingClose" + NS_LOG_LOGIC ("TcpSocketImpl " << this << " setting pendingClose" << " rxseq " << tcpHeader.GetSequenceNumber () << " nextRxSeq " << m_nextRxSequence); NewRx (p, tcpHeader, fromAddress); @@ -741,7 +789,7 @@ bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr p, NewRx (p, tcpHeader, fromAddress); } States_t saveState = m_state; // Used to see if app responds - NS_LOG_LOGIC ("TcpSocket " << this + NS_LOG_LOGIC ("TcpSocketImpl " << this << " peer close, state " << m_state); if (!m_closeRequestNotified) { @@ -750,7 +798,7 @@ bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr p, NotifyCloseRequested(); m_closeRequestNotified = true; } - NS_LOG_LOGIC ("TcpSocket " << this + NS_LOG_LOGIC ("TcpSocketImpl " << this << " peer close, state after " << m_state); if (m_state == saveState) { // Need to ack, the application will close later @@ -759,15 +807,15 @@ bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr p, } if (m_state == LAST_ACK) { - NS_LOG_LOGIC ("TcpSocket " << this << " scheduling LATO1"); + NS_LOG_LOGIC ("TcpSocketImpl " << this << " scheduling LATO1"); m_lastAckEvent = Simulator::Schedule (m_rtt->RetransmitTimeout (), - &TcpSocket::LastAckTimeout,this); + &TcpSocketImpl::LastAckTimeout,this); } break; } case SERV_NOTIFY: - NS_LOG_LOGIC ("TcpSocket " << this <<" Action SERV_NOTIFY"); - NS_LOG_LOGIC ("TcpSocket " << this << " Connected!"); + NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SERV_NOTIFY"); + NS_LOG_LOGIC ("TcpSocketImpl " << this << " Connected!"); NotifyNewConnectionCreated (this, fromAddress); m_connected = true; // ! This is bogus; fix when we clone the tcp m_endPoint->SetPeer (m_remoteAddress, m_remotePort); @@ -780,7 +828,7 @@ bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr p, return true; } -void TcpSocket::CompleteFork(Ptr p, const TcpHeader& h, const Address& fromAddress) +void TcpSocketImpl::CompleteFork(Ptr p, const TcpHeader& h, const Address& fromAddress) { // Get port and address from peer (connecting host) m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort (); @@ -792,19 +840,19 @@ void TcpSocket::CompleteFork(Ptr p, const TcpHeader& h, const Address& f //the cloned socket with be in listen state, so manually change state m_state = SYN_RCVD; //equivalent to FinishBind - m_endPoint->SetRxCallback (MakeCallback (&TcpSocket::ForwardUp, Ptr(this))); - m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocket::Destroy, Ptr(this))); + m_endPoint->SetRxCallback (MakeCallback (&TcpSocketImpl::ForwardUp, Ptr(this))); + m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocketImpl::Destroy, Ptr(this))); ProcessPacketAction(SYN_ACK_TX, p, h, fromAddress); } -void TcpSocket::ConnectionSucceeded() +void TcpSocketImpl::ConnectionSucceeded() { // We would preferred to have scheduled an event directly to // NotifyConnectionSucceeded, but (sigh) these are protected // and we can get the address of it :( NotifyConnectionSucceeded(); } -bool TcpSocket::SendPendingData (bool withAck) +bool TcpSocketImpl::SendPendingData (bool withAck) { NS_LOG_FUNCTION (this << withAck); NS_LOG_LOGIC ("ENTERING SendPendingData"); @@ -816,7 +864,7 @@ bool TcpSocket::SendPendingData (bool withAck) while (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence)) { uint32_t w = AvailableWindow ();// Get available window size - NS_LOG_LOGIC ("TcpSocket " << this << " SendPendingData" + NS_LOG_LOGIC ("TcpSocketImpl " << this << " SendPendingData" << " w " << w << " rxwin " << m_rxWindowSize << " cWnd " << m_cWnd @@ -833,7 +881,7 @@ bool TcpSocket::SendPendingData (bool withAck) uint32_t s = std::min (w, m_segmentSize); // Send no more than window Ptr p = m_pendingData->CopyFromSeq (s, m_firstPendingSequence, m_nextTxSequence); - NS_LOG_LOGIC("TcpSocket " << this << " sendPendingData" + NS_LOG_LOGIC("TcpSocketImpl " << this << " sendPendingData" << " txseq " << m_nextTxSequence << " s " << s << " datasize " << p->GetSize() ); @@ -871,7 +919,7 @@ bool TcpSocket::SendPendingData (bool withAck) NS_LOG_LOGIC ("Schedule retransmission timeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds () ); - m_retxEvent = Simulator::Schedule (rto,&TcpSocket::ReTxTimeout,this); + m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this); } NS_LOG_LOGIC ("About to send a packet with flags: " << flags); m_tcp->SendPacket (p, header, @@ -879,7 +927,7 @@ bool TcpSocket::SendPendingData (bool withAck) m_remoteAddress); m_rtt->SentSeq(m_nextTxSequence, sz); // notify the RTT // Notify the application - Simulator::ScheduleNow(&TcpSocket::NotifyDataSent, this, p->GetSize ()); + Simulator::ScheduleNow(&TcpSocketImpl::NotifyDataSent, this, p->GetSize ()); nPacketsSent++; // Count sent this loop m_nextTxSequence += sz; // Advance next tx sequence // Note the high water mark @@ -890,26 +938,26 @@ bool TcpSocket::SendPendingData (bool withAck) return (nPacketsSent>0); } -uint32_t TcpSocket::UnAckDataCount () +uint32_t TcpSocketImpl::UnAckDataCount () { NS_LOG_FUNCTION_NOARGS (); return m_nextTxSequence - m_highestRxAck; } -uint32_t TcpSocket::BytesInFlight () +uint32_t TcpSocketImpl::BytesInFlight () { NS_LOG_FUNCTION_NOARGS (); return m_highTxMark - m_highestRxAck; } -uint32_t TcpSocket::Window () +uint32_t TcpSocketImpl::Window () { NS_LOG_FUNCTION_NOARGS (); - NS_LOG_LOGIC ("TcpSocket::Window() "< p, +void TcpSocketImpl::NewRx (Ptr p, const TcpHeader& tcpHeader, const Address& fromAddress) { NS_LOG_FUNCTION (this << p << "tcpHeader " << fromAddress); - NS_LOG_LOGIC ("TcpSocket " << this << " NewRx," + NS_LOG_LOGIC ("TcpSocketImpl " << this << " NewRx," << " seq " << tcpHeader.GetSequenceNumber() << " ack " << tcpHeader.GetAckNumber() << " p.size is " << p->GetSize () ); - NS_LOG_DEBUG ("TcpSocket " << this << + NS_LOG_DEBUG ("TcpSocketImpl " << this << " NewRx," << " seq " << tcpHeader.GetSequenceNumber() << " ack " << tcpHeader.GetAckNumber() << @@ -956,12 +1004,17 @@ void TcpSocket::NewRx (Ptr p, m_nextRxSequence += s; // Advance next expected sequence //bytesReceived += s; // Statistics NS_LOG_LOGIC("Case 1, advanced nrxs to " << m_nextRxSequence ); - NotifyDataReceived (p, fromAddress); + SocketRxAddressTag tag; + tag.SetAddress (fromAddress); + p->AddTag (tag); + m_deliveryQueue.push (p); + m_rxAvailable += p->GetSize (); + NotifyDataRecv (); if (m_closeNotified) { NS_LOG_LOGIC ("Tcp " << this << " HuH? Got data after closeNotif"); } - NS_LOG_LOGIC ("TcpSocket " << this << " adv rxseq by " << s); + NS_LOG_LOGIC ("TcpSocketImpl " << this << " adv rxseq by " << s); // Look for buffered data UnAckData_t::iterator i; // Note that the bufferedData list DOES contain the tcp header @@ -1008,13 +1061,18 @@ void TcpSocket::NewRx (Ptr p, } s1 = p1->GetSize (); } - NotifyDataReceived (p1, fromAddress); + SocketRxAddressTag tag; + tag.SetAddress (fromAddress); + p1->AddTag (tag); + m_deliveryQueue.push (p1); + m_rxAvailable += p->GetSize (); + NotifyDataRecv (); - NS_LOG_LOGIC ("TcpSocket " << this << " adv rxseq1 by " << s1 ); + NS_LOG_LOGIC ("TcpSocketImpl " << this << " adv rxseq1 by " << s1 ); m_nextRxSequence += s1; // Note data received m_bufferedData.erase (i); // Remove from list if (flags & TcpHeader::FIN) - NS_LOG_LOGIC("TcpSocket " << this + NS_LOG_LOGIC("TcpSocketImpl " << this << " found FIN in buffered"); } @@ -1054,17 +1112,17 @@ void TcpSocket::NewRx (Ptr p, } else { - m_delAckEvent = Simulator::Schedule (m_delAckTimout, &TcpSocket::DelAckTimeout, this); + m_delAckEvent = Simulator::Schedule (m_delAckTimeout, &TcpSocketImpl::DelAckTimeout, this); } } -void TcpSocket::DelAckTimeout () +void TcpSocketImpl::DelAckTimeout () { m_delAckCount = 0; SendEmptyPacket (TcpHeader::ACK); } -void TcpSocket::CommonNewAck (SequenceNumber ack, bool skipTimer) +void TcpSocketImpl::CommonNewAck (SequenceNumber ack, bool skipTimer) { // CommonNewAck is called only for "New" (non-duplicate) acks // and MUST be called by any subclass, from the NewAck function // Always cancel any pending re-tx timer on new acknowledgement @@ -1078,14 +1136,18 @@ void TcpSocket::CommonNewAck (SequenceNumber ack, bool skipTimer) NS_LOG_LOGIC ("Schedule retransmission timeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds ()); - m_retxEvent = Simulator::Schedule (rto, &TcpSocket::ReTxTimeout, this); + m_retxEvent = Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this); } NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack << " numberAck " << (ack - m_highestRxAck)); // Number bytes ack'ed m_highestRxAck = ack; // Note the highest recieved Ack - // We do not model any limit to the buffer, so report that the - // maximum is available - NotifySend (std::numeric_limits::max ()); + if (m_wouldBlock) + { + // m_highestRxAck advancing means some data was acked, and the size + // of free space in the buffer has increased + NotifySend (GetTxAvailable ()); + m_wouldBlock = false; + } if (ack > m_nextTxSequence) { m_nextTxSequence = ack; // If advanced @@ -1106,23 +1168,23 @@ void TcpSocket::CommonNewAck (SequenceNumber ack, bool skipTimer) SendPendingData(); } -Ptr TcpSocket::Copy () +Ptr TcpSocketImpl::Copy () { - return CopyObject (this); + return CopyObject (this); } -void TcpSocket::NewAck (SequenceNumber seq) +void TcpSocketImpl::NewAck (SequenceNumber seq) { // New acknowledgement up to sequence number "seq" // Adjust congestion window in response to new ack's received NS_LOG_FUNCTION (this << seq); - NS_LOG_LOGIC ("TcpSocket " << this << " NewAck " + NS_LOG_LOGIC ("TcpSocketImpl " << this << " NewAck " << " seq " << seq << " cWnd " << m_cWnd << " ssThresh " << m_ssThresh); if (m_cWnd < m_ssThresh) { // Slow start mode, add one segSize to cWnd m_cWnd += m_segmentSize; - NS_LOG_LOGIC ("TcpSocket " << this << " NewCWnd SlowStart, cWnd " << m_cWnd + NS_LOG_LOGIC ("TcpSocketImpl " << this << " NewCWnd SlowStart, cWnd " << m_cWnd << " sst " << m_ssThresh); } else @@ -1139,17 +1201,17 @@ void TcpSocket::NewAck (SequenceNumber seq) CommonNewAck (seq, false); // Complete newAck processing } -void TcpSocket::DupAck (const TcpHeader& t, uint32_t count) +void TcpSocketImpl::DupAck (const TcpHeader& t, uint32_t count) { NS_LOG_FUNCTION (this << "t " << count); - NS_LOG_LOGIC ("TcpSocket " << this << " DupAck " << t.GetAckNumber () + NS_LOG_LOGIC ("TcpSocketImpl " << this << " DupAck " << t.GetAckNumber () << ", count " << count << ", time " << Simulator::Now ()); if (count == 3) { // Count of three indicates triple duplicate ack m_ssThresh = Window () / 2; // Per RFC2581 m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize); - NS_LOG_LOGIC("TcpSocket " << this << "Tahoe TDA, time " << Simulator::Now () + NS_LOG_LOGIC("TcpSocketImpl " << this << "Tahoe TDA, time " << Simulator::Now () << " seq " << t.GetAckNumber () << " in flight " << BytesInFlight () << " new ssthresh " << m_ssThresh); @@ -1161,7 +1223,7 @@ void TcpSocket::DupAck (const TcpHeader& t, uint32_t count) } } -void TcpSocket::ReTxTimeout () +void TcpSocketImpl::ReTxTimeout () { // Retransmit timeout NS_LOG_FUNCTION (this); m_ssThresh = Window () / 2; // Per RFC2581 @@ -1174,7 +1236,7 @@ void TcpSocket::ReTxTimeout () Retransmit (); // Retransmit the packet } -void TcpSocket::LastAckTimeout () +void TcpSocketImpl::LastAckTimeout () { m_lastAckEvent.Cancel (); if (m_state == LAST_ACK) @@ -1188,7 +1250,7 @@ void TcpSocket::LastAckTimeout () } } -void TcpSocket::Retransmit () +void TcpSocketImpl::Retransmit () { NS_LOG_FUNCTION (this); uint8_t flags = TcpHeader::NONE; @@ -1225,14 +1287,14 @@ void TcpSocket::Retransmit () flags = flags | TcpHeader::FIN; } - NS_LOG_LOGIC ("TcpSocket " << this << " retxing seq " << m_highestRxAck); + NS_LOG_LOGIC ("TcpSocketImpl " << this << " retxing seq " << m_highestRxAck); if (m_retxEvent.IsExpired () ) { Time rto = m_rtt->RetransmitTimeout (); NS_LOG_LOGIC ("Schedule retransmission timeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds ()); - m_retxEvent = Simulator::Schedule (rto,&TcpSocket::ReTxTimeout,this); + m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this); } m_rtt->SentSeq (m_highestRxAck,p->GetSize ()); // And send the packet @@ -1248,4 +1310,124 @@ void TcpSocket::Retransmit () m_remoteAddress); } +void +TcpSocketImpl::SetSndBufSize (uint32_t size) +{ + m_sndBufSize = size; +} + +uint32_t +TcpSocketImpl::GetSndBufSize (void) const +{ + return m_sndBufSize; +} + +void +TcpSocketImpl::SetRcvBufSize (uint32_t size) +{ + m_rcvBufSize = size; +} + +uint32_t +TcpSocketImpl::GetRcvBufSize (void) const +{ + return m_rcvBufSize; +} + +void +TcpSocketImpl::SetSegSize (uint32_t size) +{ + m_segmentSize = size; +} + +uint32_t +TcpSocketImpl::GetSegSize (void) const +{ + return m_segmentSize; +} + +void +TcpSocketImpl::SetAdvWin (uint32_t window) +{ + m_advertisedWindowSize = window; +} + +uint32_t +TcpSocketImpl::GetAdvWin (void) const +{ + return m_advertisedWindowSize; +} + +void +TcpSocketImpl::SetSSThresh (uint32_t threshold) +{ + m_ssThresh = threshold; +} + +uint32_t +TcpSocketImpl::GetSSThresh (void) const +{ + return m_ssThresh; +} + +void +TcpSocketImpl::SetInitialCwnd (uint32_t cwnd) +{ + m_initialCWnd = cwnd; +} + +uint32_t +TcpSocketImpl::GetInitialCwnd (void) const +{ + return m_initialCWnd; +} + +void +TcpSocketImpl::SetConnTimeout (Time timeout) +{ + m_cnTimeout = timeout; +} + +Time +TcpSocketImpl::GetConnTimeout (void) const +{ + return m_cnTimeout; +} + +void +TcpSocketImpl::SetConnCount (uint32_t count) +{ + m_cnCount = count; +} + +uint32_t +TcpSocketImpl::GetConnCount (void) const +{ + return m_cnCount; +} + +void +TcpSocketImpl::SetDelAckTimeout (Time timeout) +{ + m_delAckTimeout = timeout; +} + +Time +TcpSocketImpl::GetDelAckTimeout (void) const +{ + return m_delAckTimeout; +} + +void +TcpSocketImpl::SetDelAckMaxCount (uint32_t count) +{ + m_delAckMaxCount = count; +} + +uint32_t +TcpSocketImpl::GetDelAckMaxCount (void) const +{ + return m_delAckMaxCount; +} + }//namespace ns3 diff --git a/src/internet-node/tcp-socket.h b/src/internet-node/tcp-socket-impl.h similarity index 72% rename from src/internet-node/tcp-socket.h rename to src/internet-node/tcp-socket-impl.h index 7499e2a3e..7adc8669e 100644 --- a/src/internet-node/tcp-socket.h +++ b/src/internet-node/tcp-socket-impl.h @@ -17,13 +17,14 @@ * * Author: Raj Bhattacharjea */ -#ifndef TCP_SOCKET_H -#define TCP_SOCKET_H +#ifndef TCP_SOCKET_IMPL_H +#define TCP_SOCKET_IMPL_H #include +#include #include "ns3/callback.h" #include "ns3/traced-value.h" -#include "ns3/socket.h" +#include "ns3/tcp-socket.h" #include "ns3/ptr.h" #include "ns3/ipv4-address.h" #include "ns3/event-id.h" @@ -41,16 +42,16 @@ class Packet; class TcpL4Protocol; class TcpHeader; -class TcpSocket : public Socket +class TcpSocketImpl : public TcpSocket { public: static TypeId GetTypeId (void); /** * Create an unbound tcp socket. */ - TcpSocket (); - TcpSocket (const TcpSocket& sock); - virtual ~TcpSocket (); + TcpSocketImpl (); + TcpSocketImpl (const TcpSocketImpl& sock); + virtual ~TcpSocketImpl (); void SetNode (Ptr node); void SetTcp (Ptr tcp); @@ -66,9 +67,13 @@ public: virtual int Connect(const Address &address); virtual int Send (Ptr p); virtual int Send (const uint8_t* buf, uint32_t size); - virtual int SendTo(const Address &address, Ptr p); + virtual int SendTo(Ptr p, const Address &address); + virtual uint32_t GetTxAvailable (void) const; virtual int Listen(uint32_t queueLimit); + virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual uint32_t GetRxAvailable (void) const; + private: friend class Tcp; // invoked by Tcp class @@ -99,7 +104,7 @@ private: // Manage data tx/rx void NewRx (Ptr, const TcpHeader&, const Address&); // XXX This should be virtual and overridden - Ptr Copy (); + Ptr Copy (); void NewAck (SequenceNumber seq); // XXX This should be virtual and overridden void DupAck (const TcpHeader& t, uint32_t count); @@ -109,6 +114,28 @@ private: void Retransmit (); void CommonNewAck (SequenceNumber seq, bool skipTimer = false); + // attribute related + virtual void SetSndBufSize (uint32_t size); + virtual uint32_t GetSndBufSize (void) const; + virtual void SetRcvBufSize (uint32_t size); + virtual uint32_t GetRcvBufSize (void) const; + virtual void SetSegSize (uint32_t size); + virtual uint32_t GetSegSize (void) const; + virtual void SetAdvWin (uint32_t window); + virtual uint32_t GetAdvWin (void) const; + virtual void SetSSThresh (uint32_t threshold); + virtual uint32_t GetSSThresh (void) const; + virtual void SetInitialCwnd (uint32_t cwnd); + virtual uint32_t GetInitialCwnd (void) const; + virtual void SetConnTimeout (Time timeout); + virtual Time GetConnTimeout (void) const; + virtual void SetConnCount (uint32_t count); + virtual uint32_t GetConnCount (void) const; + virtual void SetDelAckTimeout (Time timeout); + virtual Time GetDelAckTimeout (void) const; + virtual void SetDelAckMaxCount (uint32_t count); + virtual uint32_t GetDelAckMaxCount (void) const; + bool m_skipRetxResched; uint32_t m_dupAckCount; EventId m_retxEvent; @@ -117,7 +144,7 @@ private: EventId m_delAckEvent; uint32_t m_delAckCount; uint32_t m_delAckMaxCount; - Time m_delAckTimout; + Time m_delAckTimeout; Ipv4EndPoint *m_endPoint; Ptr m_node; @@ -150,7 +177,9 @@ private: SequenceNumber m_nextRxSequence; //history data + //this is the incoming data buffer which sorts out of sequence data UnAckData_t m_bufferedData; + //this is kind of the tx buffer PendingData* m_pendingData; SequenceNumber m_firstPendingSequence; @@ -170,8 +199,17 @@ private: Time m_cnTimeout; uint32_t m_cnCount; + // Temporary queue for delivering data to application + std::queue > m_deliveryQueue; + uint32_t m_rxAvailable; + + bool m_wouldBlock; // set to true whenever socket would block on send() + + // Attributes + uint32_t m_rcvBufSize; // maximum receive socket buffer size + uint32_t m_sndBufSize; // buffer limit for the outgoing queue }; }//namespace ns3 -#endif /* UDP_SOCKET_H */ +#endif /* TCP_SOCKET_IMPL_H */ diff --git a/src/internet-node/udp-l4-protocol.cc b/src/internet-node/udp-l4-protocol.cc index 424908712..f3b85e15e 100644 --- a/src/internet-node/udp-l4-protocol.cc +++ b/src/internet-node/udp-l4-protocol.cc @@ -28,7 +28,7 @@ #include "ipv4-end-point-demux.h" #include "ipv4-end-point.h" #include "ipv4-l3-protocol.h" -#include "udp-socket.h" +#include "udp-socket-impl.h" NS_LOG_COMPONENT_DEFINE ("UdpL4Protocol"); @@ -95,7 +95,7 @@ Ptr UdpL4Protocol::CreateSocket (void) { NS_LOG_FUNCTION_NOARGS (); - Ptr socket = CreateObject (); + Ptr socket = CreateObject (); socket->SetNode (m_node); socket->SetUdp (this); return socket; diff --git a/src/internet-node/udp-impl.cc b/src/internet-node/udp-socket-factory-impl.cc similarity index 78% rename from src/internet-node/udp-impl.cc rename to src/internet-node/udp-socket-factory-impl.cc index 9de5259e5..3fd63d6cd 100644 --- a/src/internet-node/udp-impl.cc +++ b/src/internet-node/udp-socket-factory-impl.cc @@ -17,38 +17,38 @@ * * Author: Mathieu Lacage */ -#include "udp-impl.h" +#include "udp-socket-factory-impl.h" #include "udp-l4-protocol.h" #include "ns3/socket.h" #include "ns3/assert.h" namespace ns3 { -UdpImpl::UdpImpl () +UdpSocketFactoryImpl::UdpSocketFactoryImpl () : m_udp (0) {} -UdpImpl::~UdpImpl () +UdpSocketFactoryImpl::~UdpSocketFactoryImpl () { NS_ASSERT (m_udp == 0); } void -UdpImpl::SetUdp (Ptr udp) +UdpSocketFactoryImpl::SetUdp (Ptr udp) { m_udp = udp; } Ptr -UdpImpl::CreateSocket (void) +UdpSocketFactoryImpl::CreateSocket (void) { return m_udp->CreateSocket (); } void -UdpImpl::DoDispose (void) +UdpSocketFactoryImpl::DoDispose (void) { m_udp = 0; - Udp::DoDispose (); + UdpSocketFactory::DoDispose (); } } // namespace ns3 diff --git a/src/internet-node/udp-impl.h b/src/internet-node/udp-socket-factory-impl.h similarity index 71% rename from src/internet-node/udp-impl.h rename to src/internet-node/udp-socket-factory-impl.h index 114edfdbb..b4366fc31 100644 --- a/src/internet-node/udp-impl.h +++ b/src/internet-node/udp-socket-factory-impl.h @@ -17,10 +17,10 @@ * * Author: Mathieu Lacage */ -#ifndef UDP_IMPL_H -#define UDP_IMPL_H +#ifndef UDP_SOCKET_FACTORY_IMPL_H +#define UDP_SOCKET_FACTORY_IMPL_H -#include "ns3/udp.h" +#include "ns3/udp-socket-factory.h" #include "ns3/ptr.h" namespace ns3 { @@ -31,21 +31,19 @@ class UdpL4Protocol; * \brief Object to create UDP socket instances * \internal * - * This class implements the API for UDP sockets. - * It is a socket factory (deriving from class SocketFactory) and can - * also hold global variables used to initialize newly created sockets, - * such as values that are set through the sysctl or proc interfaces in Linux. + * This class implements the API for creating UDP sockets. + * It is a socket factory (deriving from class SocketFactory). */ -class UdpImpl : public Udp +class UdpSocketFactoryImpl : public UdpSocketFactory { public: - UdpImpl (); - virtual ~UdpImpl (); + UdpSocketFactoryImpl (); + virtual ~UdpSocketFactoryImpl (); void SetUdp (Ptr udp); /** - * \brief Implements a method to create a UdpImpl-based socket and return + * \brief Implements a method to create a Udp-based socket and return * a base class smart pointer to the socket. * \internal * @@ -61,4 +59,4 @@ private: } // namespace ns3 -#endif /* UDP_IMPL_H */ +#endif /* UDP_SOCKET_FACTORY_IMPL_H */ diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket-impl.cc similarity index 61% rename from src/internet-node/udp-socket.cc rename to src/internet-node/udp-socket-impl.cc index 951a8c73f..ae9e1f732 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket-impl.cc @@ -23,29 +23,48 @@ #include "ns3/inet-socket-address.h" #include "ns3/ipv4-route.h" #include "ns3/ipv4.h" -#include "udp-socket.h" +#include "ns3/udp-socket-factory.h" +#include "ns3/trace-source-accessor.h" +#include "ns3/uinteger.h" +#include "ns3/boolean.h" +#include "udp-socket-impl.h" #include "udp-l4-protocol.h" #include "ipv4-end-point.h" #include "ipv4-l4-demux.h" -#include "ns3/ipv4.h" -NS_LOG_COMPONENT_DEFINE ("UdpSocket"); +NS_LOG_COMPONENT_DEFINE ("UdpSocketImpl"); namespace ns3 { -UdpSocket::UdpSocket () +static const uint32_t MAX_IPV4_UDP_DATAGRAM_SIZE = 65507; + +// Add attributes generic to all UdpSockets to base class UdpSocket +TypeId +UdpSocketImpl::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::UdpSocketImpl") + .SetParent () + .AddConstructor () + .AddTraceSource ("Drop", "Drop UDP packet due to receive buffer overflow", + MakeTraceSourceAccessor (&UdpSocketImpl::m_dropTrace)) + ; + return tid; +} + +UdpSocketImpl::UdpSocketImpl () : m_endPoint (0), m_node (0), m_udp (0), m_errno (ERROR_NOTERROR), m_shutdownSend (false), m_shutdownRecv (false), - m_connected (false) + m_connected (false), + m_rxAvailable (0) { NS_LOG_FUNCTION_NOARGS (); } -UdpSocket::~UdpSocket () +UdpSocketImpl::~UdpSocketImpl () { NS_LOG_FUNCTION_NOARGS (); @@ -69,33 +88,36 @@ UdpSocket::~UdpSocket () } void -UdpSocket::SetNode (Ptr node) +UdpSocketImpl::SetNode (Ptr node) { + NS_LOG_FUNCTION_NOARGS (); m_node = node; + } void -UdpSocket::SetUdp (Ptr udp) +UdpSocketImpl::SetUdp (Ptr udp) { + NS_LOG_FUNCTION_NOARGS (); m_udp = udp; } enum Socket::SocketErrno -UdpSocket::GetErrno (void) const +UdpSocketImpl::GetErrno (void) const { NS_LOG_FUNCTION_NOARGS (); return m_errno; } Ptr -UdpSocket::GetNode (void) const +UdpSocketImpl::GetNode (void) const { NS_LOG_FUNCTION_NOARGS (); return m_node; } void -UdpSocket::Destroy (void) +UdpSocketImpl::Destroy (void) { NS_LOG_FUNCTION_NOARGS (); m_node = 0; @@ -104,20 +126,20 @@ UdpSocket::Destroy (void) } int -UdpSocket::FinishBind (void) +UdpSocketImpl::FinishBind (void) { NS_LOG_FUNCTION_NOARGS (); if (m_endPoint == 0) { return -1; } - m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this)); - m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this)); + m_endPoint->SetRxCallback (MakeCallback (&UdpSocketImpl::ForwardUp, this)); + m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy, this)); return 0; } int -UdpSocket::Bind (void) +UdpSocketImpl::Bind (void) { NS_LOG_FUNCTION_NOARGS (); m_endPoint = m_udp->Allocate (); @@ -125,7 +147,7 @@ UdpSocket::Bind (void) } int -UdpSocket::Bind (const Address &address) +UdpSocketImpl::Bind (const Address &address) { NS_LOG_FUNCTION (this << address); @@ -158,7 +180,7 @@ UdpSocket::Bind (const Address &address) } int -UdpSocket::ShutdownSend (void) +UdpSocketImpl::ShutdownSend (void) { NS_LOG_FUNCTION_NOARGS (); m_shutdownSend = true; @@ -166,7 +188,7 @@ UdpSocket::ShutdownSend (void) } int -UdpSocket::ShutdownRecv (void) +UdpSocketImpl::ShutdownRecv (void) { NS_LOG_FUNCTION_NOARGS (); m_shutdownRecv = false; @@ -174,7 +196,7 @@ UdpSocket::ShutdownRecv (void) } int -UdpSocket::Close(void) +UdpSocketImpl::Close(void) { NS_LOG_FUNCTION_NOARGS (); NotifyCloseCompleted (); @@ -182,10 +204,9 @@ UdpSocket::Close(void) } int -UdpSocket::Connect(const Address & address) +UdpSocketImpl::Connect(const Address & address) { NS_LOG_FUNCTION (this << address); - Ipv4Route routeToDest; InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); m_defaultAddress = transport.GetIpv4 (); m_defaultPort = transport.GetPort (); @@ -196,7 +217,7 @@ UdpSocket::Connect(const Address & address) } int -UdpSocket::Send (Ptr p) +UdpSocketImpl::Send (Ptr p) { NS_LOG_FUNCTION (this << p); @@ -209,7 +230,7 @@ UdpSocket::Send (Ptr p) } int -UdpSocket::DoSend (Ptr p) +UdpSocketImpl::DoSend (Ptr p) { NS_LOG_FUNCTION_NOARGS (); if (m_endPoint == 0) @@ -231,7 +252,7 @@ UdpSocket::DoSend (Ptr p) } int -UdpSocket::DoSendTo (Ptr p, const Address &address) +UdpSocketImpl::DoSendTo (Ptr p, const Address &address) { NS_LOG_FUNCTION (this << p << address); @@ -252,12 +273,10 @@ UdpSocket::DoSendTo (Ptr p, const Address &address) } int -UdpSocket::DoSendTo (Ptr p, Ipv4Address dest, uint16_t port) +UdpSocketImpl::DoSendTo (Ptr p, Ipv4Address dest, uint16_t port) { NS_LOG_FUNCTION (this << p << dest << port); - Ipv4Route routeToDest; - if (m_endPoint == 0) { if (Bind () == -1) @@ -273,9 +292,36 @@ UdpSocket::DoSendTo (Ptr p, Ipv4Address dest, uint16_t port) return -1; } + if (p->GetSize () > GetTxAvailable () ) + { + m_errno = ERROR_MSGSIZE; + return -1; + } + uint32_t localIfIndex; Ptr ipv4 = m_node->GetObject (); + // Locally override the IP TTL for this socket + // We cannot directly modify the TTL at this stage, so we set a Packet tag + // The destination can be either multicast, unicast/anycast, or + // either all-hosts broadcast or limited (subnet-directed) broadcast. + // For the latter two broadcast types, the TTL will later be set to one + // irrespective of what is set in these socket options. So, this tagging + // may end up setting the TTL of a limited broadcast packet to be + // the same as a unicast, but it will be fixed further down the stack + //NS_LOG_UNCOND ("IPttl: " << m_ipTtl); + if (m_ipMulticastTtl != 0 && dest.IsMulticast ()) + { + SocketIpTtlTag tag; + tag.SetTtl (m_ipMulticastTtl); + p->AddTag (tag); + } + else if (m_ipTtl != 0 && !dest.IsMulticast () && !dest.IsBroadcast ()) + { + SocketIpTtlTag tag; + tag.SetTtl (m_ipTtl); + p->AddTag (tag); + } // // If dest is sent to the limited broadcast address (all ones), // convert it to send a copy of the packet out of every interface @@ -315,8 +361,19 @@ UdpSocket::DoSendTo (Ptr p, Ipv4Address dest, uint16_t port) return 0; } +// XXX maximum message size for UDP broadcast is limited by MTU +// size of underlying link; we are not checking that now. +uint32_t +UdpSocketImpl::GetTxAvailable (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + // No finite send buffer is modelled, but we must respect + // the maximum size of an IP datagram (65535 bytes - headers). + return MAX_IPV4_UDP_DATAGRAM_SIZE; +} + int -UdpSocket::SendTo(const Address &address, Ptr p) +UdpSocketImpl::SendTo (Ptr p, const Address &address) { NS_LOG_FUNCTION (this << address << p); InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); @@ -325,8 +382,38 @@ UdpSocket::SendTo(const Address &address, Ptr p) return DoSendTo (p, ipv4, port); } +Ptr +UdpSocketImpl::Recv (uint32_t maxSize, uint32_t flags) +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_deliveryQueue.empty() ) + { + return 0; + } + Ptr p = m_deliveryQueue.front (); + if (p->GetSize () <= maxSize) + { + m_deliveryQueue.pop (); + m_rxAvailable -= p->GetSize (); + } + else + { + p = 0; + } + return p; +} + +uint32_t +UdpSocketImpl::GetRxAvailable (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + // We separately maintain this state to avoid walking the queue + // every time this might be called + return m_rxAvailable; +} + void -UdpSocket::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) +UdpSocketImpl::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) { NS_LOG_FUNCTION (this << packet << ipv4 << port); @@ -334,9 +421,63 @@ UdpSocket::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) { return; } - - Address address = InetSocketAddress (ipv4, port); - NotifyDataReceived (packet, address); + if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize) + { + Address address = InetSocketAddress (ipv4, port); + SocketRxAddressTag tag; + tag.SetAddress (address); + packet->AddTag (tag); + m_deliveryQueue.push (packet); + m_rxAvailable += packet->GetSize (); + NotifyDataRecv (); + } + else + { + // In general, this case should not occur unless the + // receiving application reads data from this socket slowly + // in comparison to the arrival rate + // + // drop and trace packet + NS_LOG_WARN ("No receive buffer space available. Drop."); + m_dropTrace (packet); + } +} + + +void +UdpSocketImpl::SetRcvBufSize (uint32_t size) +{ + m_rcvBufSize = size; +} + +uint32_t +UdpSocketImpl::GetRcvBufSize (void) const +{ + return m_rcvBufSize; +} + +void +UdpSocketImpl::SetIpTtl (uint32_t ipTtl) +{ + m_ipTtl = ipTtl; +} + +uint32_t +UdpSocketImpl::GetIpTtl (void) const +{ + return m_ipTtl; +} + +void +UdpSocketImpl::SetIpMulticastTtl (uint32_t ipTtl) +{ + m_ipMulticastTtl = ipTtl; +} + +uint32_t +UdpSocketImpl::GetIpMulticastTtl (void) const +{ + return m_ipMulticastTtl; } } //namespace ns3 @@ -346,7 +487,7 @@ UdpSocket::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) #include "ns3/test.h" #include "ns3/socket-factory.h" -#include "ns3/udp.h" +#include "ns3/udp-socket-factory.h" #include "ns3/simulator.h" #include "ns3/simple-channel.h" #include "ns3/simple-net-device.h" @@ -356,36 +497,55 @@ UdpSocket::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) namespace ns3 { -class UdpSocketTest: public Test +class UdpSocketImplTest: public Test { Ptr m_receivedPacket; Ptr m_receivedPacket2; public: virtual bool RunTests (void); - UdpSocketTest (); + UdpSocketImplTest (); void ReceivePacket (Ptr socket, Ptr packet, const Address &from); void ReceivePacket2 (Ptr socket, Ptr packet, const Address &from); + void ReceivePkt (Ptr socket); + void ReceivePkt2 (Ptr socket); }; -UdpSocketTest::UdpSocketTest () - : Test ("UdpSocket") {} +UdpSocketImplTest::UdpSocketImplTest () + : Test ("UdpSocketImpl") +{ +} - -void UdpSocketTest::ReceivePacket (Ptr socket, Ptr packet, const Address &from) +void UdpSocketImplTest::ReceivePacket (Ptr socket, Ptr packet, const Address &from) { m_receivedPacket = packet; } -void UdpSocketTest::ReceivePacket2 (Ptr socket, Ptr packet, const Address &from) +void UdpSocketImplTest::ReceivePacket2 (Ptr socket, Ptr packet, const Address &from) { m_receivedPacket2 = packet; } +void UdpSocketImplTest::ReceivePkt (Ptr socket) +{ + uint32_t availableData; + availableData = socket->GetRxAvailable (); + m_receivedPacket = socket->Recv (std::numeric_limits::max(), 0); + NS_ASSERT (availableData == m_receivedPacket->GetSize ()); +} + +void UdpSocketImplTest::ReceivePkt2 (Ptr socket) +{ + uint32_t availableData; + availableData = socket->GetRxAvailable (); + m_receivedPacket2 = socket->Recv (std::numeric_limits::max(), 0); + NS_ASSERT (availableData == m_receivedPacket2->GetSize ()); +} + bool -UdpSocketTest::RunTests (void) +UdpSocketImplTest::RunTests (void) { bool result = true; @@ -454,16 +614,16 @@ UdpSocketTest::RunTests (void) // Create the UDP sockets - Ptr rxSocketFactory = rxNode->GetObject (); + Ptr rxSocketFactory = rxNode->GetObject (); Ptr rxSocket = rxSocketFactory->CreateSocket (); NS_TEST_ASSERT_EQUAL (rxSocket->Bind (InetSocketAddress (Ipv4Address ("10.0.0.1"), 1234)), 0); - rxSocket->SetRecvCallback (MakeCallback (&UdpSocketTest::ReceivePacket, this)); + rxSocket->SetRecvCallback (MakeCallback (&UdpSocketImplTest::ReceivePkt, this)); Ptr rxSocket2 = rxSocketFactory->CreateSocket (); - rxSocket2->SetRecvCallback (MakeCallback (&UdpSocketTest::ReceivePacket2, this)); + rxSocket2->SetRecvCallback (MakeCallback (&UdpSocketImplTest::ReceivePkt2, this)); NS_TEST_ASSERT_EQUAL (rxSocket2->Bind (InetSocketAddress (Ipv4Address ("10.0.1.1"), 1234)), 0); - Ptr txSocketFactory = txNode->GetObject (); + Ptr txSocketFactory = txNode->GetObject (); Ptr txSocket = txSocketFactory->CreateSocket (); // ------ Now the tests ------------ @@ -471,24 +631,28 @@ UdpSocketTest::RunTests (void) // Unicast test m_receivedPacket = Create (); m_receivedPacket2 = Create (); - NS_TEST_ASSERT_EQUAL (txSocket->SendTo (InetSocketAddress (Ipv4Address("10.0.0.1"), 1234), - Create (123)), 123); + NS_TEST_ASSERT_EQUAL (txSocket->SendTo ( Create (123), + InetSocketAddress (Ipv4Address("10.0.0.1"), 1234)), 123); Simulator::Run (); NS_TEST_ASSERT_EQUAL (m_receivedPacket->GetSize (), 123); NS_TEST_ASSERT_EQUAL (m_receivedPacket2->GetSize (), 0); // second interface should receive it + m_receivedPacket->RemoveAllTags (); + m_receivedPacket2->RemoveAllTags (); // Simple broadcast test m_receivedPacket = Create (); m_receivedPacket2 = Create (); - NS_TEST_ASSERT_EQUAL (txSocket->SendTo (InetSocketAddress (Ipv4Address("255.255.255.255"), 1234), - Create (123)), 123); + NS_TEST_ASSERT_EQUAL (txSocket->SendTo ( Create (123), + InetSocketAddress (Ipv4Address("255.255.255.255"), 1234)), 123); Simulator::Run (); NS_TEST_ASSERT_EQUAL (m_receivedPacket->GetSize (), 123); // second socket should not receive it (it is bound specifically to the second interface's address NS_TEST_ASSERT_EQUAL (m_receivedPacket2->GetSize (), 0); + m_receivedPacket->RemoveAllTags (); + m_receivedPacket2->RemoveAllTags (); // Broadcast test with multiple receiving sockets @@ -497,24 +661,26 @@ UdpSocketTest::RunTests (void) // the socket address matches. rxSocket2->Dispose (); rxSocket2 = rxSocketFactory->CreateSocket (); - rxSocket2->SetRecvCallback (MakeCallback (&UdpSocketTest::ReceivePacket2, this)); + rxSocket2->SetRecvCallback (MakeCallback (&UdpSocketImplTest::ReceivePkt2, this)); NS_TEST_ASSERT_EQUAL (rxSocket2->Bind (InetSocketAddress (Ipv4Address ("0.0.0.0"), 1234)), 0); m_receivedPacket = Create (); m_receivedPacket2 = Create (); - NS_TEST_ASSERT_EQUAL (txSocket->SendTo (InetSocketAddress (Ipv4Address("255.255.255.255"), 1234), - Create (123)), 123); + NS_TEST_ASSERT_EQUAL (txSocket->SendTo (Create (123), +InetSocketAddress (Ipv4Address("255.255.255.255"), 1234)), 123); Simulator::Run (); NS_TEST_ASSERT_EQUAL (m_receivedPacket->GetSize (), 123); NS_TEST_ASSERT_EQUAL (m_receivedPacket2->GetSize (), 123); + m_receivedPacket->RemoveAllTags (); + m_receivedPacket2->RemoveAllTags (); + Simulator::Destroy (); return result; } - -static UdpSocketTest gUdpSocketTest; +static UdpSocketImplTest gUdpSocketImplTest; }; // namespace ns3 diff --git a/src/internet-node/udp-socket.h b/src/internet-node/udp-socket-impl.h similarity index 66% rename from src/internet-node/udp-socket.h rename to src/internet-node/udp-socket-impl.h index 0b662926e..42047a5d0 100644 --- a/src/internet-node/udp-socket.h +++ b/src/internet-node/udp-socket-impl.h @@ -17,14 +17,17 @@ * * Author: Mathieu Lacage */ -#ifndef UDP_SOCKET_H -#define UDP_SOCKET_H +#ifndef UDP_SOCKET_IMPL_H +#define UDP_SOCKET_IMPL_H #include +#include #include "ns3/callback.h" +#include "ns3/traced-callback.h" #include "ns3/socket.h" #include "ns3/ptr.h" #include "ns3/ipv4-address.h" +#include "ns3/udp-socket.h" namespace ns3 { @@ -33,14 +36,15 @@ class Node; class Packet; class UdpL4Protocol; -class UdpSocket : public Socket +class UdpSocketImpl : public UdpSocket { public: + static TypeId GetTypeId (void); /** * Create an unbound udp socket. */ - UdpSocket (); - virtual ~UdpSocket (); + UdpSocketImpl (); + virtual ~UdpSocketImpl (); void SetNode (Ptr node); void SetUdp (Ptr udp); @@ -54,12 +58,22 @@ public: virtual int ShutdownRecv (void); virtual int Connect(const Address &address); virtual int Send (Ptr p); - virtual int SendTo(const Address &address,Ptr p); + virtual int SendTo (Ptr p, const Address &address); + virtual uint32_t GetTxAvailable (void) const; + + virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual uint32_t GetRxAvailable (void) const; private: + // Attributes set through UdpSocket base class + virtual void SetRcvBufSize (uint32_t size); + virtual uint32_t GetRcvBufSize (void) const; + virtual void SetIpTtl (uint32_t ipTtl); + virtual uint32_t GetIpTtl (void) const; + virtual void SetIpMulticastTtl (uint32_t ipTtl); + virtual uint32_t GetIpMulticastTtl (void) const; -private: - friend class Udp; + friend class UdpSocketFactory; // invoked by Udp class int FinishBind (void); void ForwardUp (Ptr p, Ipv4Address ipv4, uint16_t port); @@ -75,12 +89,23 @@ private: uint16_t m_defaultPort; Callback,uint32_t,const Address &> m_dummyRxCallback; Callback,uint8_t const*,uint32_t,const Address &> m_rxCallback; + TracedCallback > m_dropTrace; + enum SocketErrno m_errno; bool m_shutdownSend; bool m_shutdownRecv; bool m_connected; + + std::queue > m_deliveryQueue; + uint32_t m_rxAvailable; + + // Socket attributes + uint32_t m_rcvBufSize; + uint32_t m_ipTtl; + uint32_t m_ipMulticastTtl; + }; }//namespace ns3 -#endif /* UDP_SOCKET_H */ +#endif /* UDP_SOCKET_IMPL_H */ diff --git a/src/internet-node/wscript b/src/internet-node/wscript index 9a7949219..f9687d25a 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -22,12 +22,12 @@ def build(bld): 'arp-ipv4-interface.cc', 'arp-l3-protocol.cc', 'ipv4-loopback-interface.cc', - 'udp-socket.cc', - 'tcp-socket.cc', + 'udp-socket-impl.cc', + 'tcp-socket-impl.cc', 'ipv4-end-point-demux.cc', 'ipv4-impl.cc', - 'udp-impl.cc', - 'tcp-impl.cc', + 'udp-socket-factory-impl.cc', + 'tcp-socket-factory-impl.cc', 'pending-data.cc', 'sequence-number.cc', 'rtt-estimator.cc', diff --git a/src/mobility/rectangle.h b/src/mobility/rectangle.h index 3777ee1a6..d49d5365b 100644 --- a/src/mobility/rectangle.h +++ b/src/mobility/rectangle.h @@ -61,8 +61,6 @@ public: double xMax; double yMin; double yMax; - - ATTRIBUTE_HELPER_HEADER_1 (Rectangle); }; std::ostream &operator << (std::ostream &os, const Rectangle &rectangle); @@ -73,7 +71,7 @@ std::istream &operator >> (std::istream &is, Rectangle &rectangle); * \brief hold objects of type ns3::Rectangle */ -ATTRIBUTE_HELPER_HEADER_2 (Rectangle); +ATTRIBUTE_HELPER_HEADER (Rectangle); } // namespace ns3 diff --git a/src/mobility/vector.h b/src/mobility/vector.h index 3517f7d36..4bf1716d3 100644 --- a/src/mobility/vector.h +++ b/src/mobility/vector.h @@ -57,8 +57,6 @@ public: * z coordinate of vector vector */ double z; - - ATTRIBUTE_HELPER_HEADER_1 (Vector); }; double CalculateDistance (const Vector &a, const Vector &b); @@ -68,7 +66,7 @@ double CalculateDistance (const Vector &a, const Vector &b); * \brief hold objects of type ns3::Vector */ -ATTRIBUTE_HELPER_HEADER_2 (Vector); +ATTRIBUTE_HELPER_HEADER (Vector); std::ostream &operator << (std::ostream &os, const Vector &vector); std::istream &operator >> (std::istream &is, Vector &vector); diff --git a/src/node/address.cc b/src/node/address.cc index 3db5f1c8d..fb49bf8ce 100644 --- a/src/node/address.cc +++ b/src/node/address.cc @@ -107,6 +107,30 @@ Address::Register (void) return type; } +uint32_t +Address::GetSerializedSize (void) const +{ + return 1 + 1 + m_len; +} + +void +Address::Serialize (uint8_t* buf, uint32_t len) const +{ + NS_ASSERT (len >= static_cast (m_len + 2)); + buf[0] = m_type; + buf[1] = m_len; + for (uint8_t i = 0; i < m_len; i++) + { + buf[i+2] = m_data[i]; + } +} + +Address +Address::Deserialize (const uint8_t* buf) +{ + return Address (buf[0], buf + 2, buf[1]); +} + ATTRIBUTE_HELPER_CPP (Address); diff --git a/src/node/address.h b/src/node/address.h index e5b6c82e3..16a8dc555 100644 --- a/src/node/address.h +++ b/src/node/address.h @@ -153,8 +153,28 @@ public: * \returns a new type id. */ static uint8_t Register (void); + /** + * Get the number of bytes needed to serialize the underlying Address + * Typically, this is GetLength () + 2 + * + * \returns the number of bytes required for an Address in serialized form + */ + uint32_t GetSerializedSize (void) const; + /** + * Serialize this address in host byte order to a byte buffer + * + * \param buf output buffer that gets written with this Address + * \param len length of output buffer + */ + void Serialize (uint8_t* buf, uint32_t len) const; + /** + * \param buf buffer to read address from + * \returns an Address + * + * The input address buffer is expected to be in host byte order format. + */ + static Address Deserialize (const uint8_t* buf); - ATTRIBUTE_HELPER_HEADER_1 (Address); private: friend bool operator == (const Address &a, const Address &b); friend bool operator < (const Address &a, const Address &b); @@ -171,7 +191,7 @@ private: * \brief hold objects of type ns3::Address */ -ATTRIBUTE_HELPER_HEADER_2 (Address); +ATTRIBUTE_HELPER_HEADER (Address); bool operator == (const Address &a, const Address &b); bool operator != (const Address &a, const Address &b); diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index fc2dc7fe7..62999fc03 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -142,7 +142,6 @@ public: static Ipv4Address GetBroadcast (void); static Ipv4Address GetLoopback (void); - ATTRIBUTE_HELPER_HEADER_1 (Ipv4Address); private: Address ConvertTo (void) const; static uint8_t GetType (void); @@ -180,7 +179,6 @@ public: static Ipv4Mask GetLoopback (void); static Ipv4Mask GetZero (void); - ATTRIBUTE_HELPER_HEADER_1 (Ipv4Mask); private: uint32_t m_mask; }; @@ -194,8 +192,8 @@ private: * \brief hold objects of type ns3::Ipv4Mask */ -ATTRIBUTE_HELPER_HEADER_2 (Ipv4Address); -ATTRIBUTE_HELPER_HEADER_2 (Ipv4Mask); +ATTRIBUTE_HELPER_HEADER (Ipv4Address); +ATTRIBUTE_HELPER_HEADER (Ipv4Mask); std::ostream& operator<< (std::ostream& os, Ipv4Address const& address); std::ostream& operator<< (std::ostream& os, Ipv4Mask const& mask); diff --git a/src/node/mac48-address.h b/src/node/mac48-address.h index 6227e2e1b..75c356a8e 100644 --- a/src/node/mac48-address.h +++ b/src/node/mac48-address.h @@ -96,7 +96,6 @@ public: */ static Mac48Address GetBroadcast (void); - ATTRIBUTE_HELPER_HEADER_1 (Mac48Address); private: /** * \returns a new Address instance @@ -117,7 +116,7 @@ private: * \brief hold objects of type ns3::Mac48Address */ -ATTRIBUTE_HELPER_HEADER_2 (Mac48Address); +ATTRIBUTE_HELPER_HEADER (Mac48Address); bool operator == (const Mac48Address &a, const Mac48Address &b); bool operator != (const Mac48Address &a, const Mac48Address &b); diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc index f45690ecf..58949a331 100644 --- a/src/node/packet-socket.cc +++ b/src/node/packet-socket.cc @@ -24,12 +24,31 @@ #include "ns3/log.h" #include "ns3/node.h" #include "ns3/packet.h" +#include "ns3/uinteger.h" +#include "ns3/trace-source-accessor.h" NS_LOG_COMPONENT_DEFINE ("PacketSocket"); namespace ns3 { -PacketSocket::PacketSocket () +TypeId +PacketSocket::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::PacketSocket") + .SetParent () + .AddConstructor () + .AddTraceSource ("Drop", "Drop packet due to receive buffer overflow", + MakeTraceSourceAccessor (&PacketSocket::m_dropTrace)) + .AddAttribute ("RcvBufSize", + "PacketSocket maximum receive buffer size (bytes)", + UintegerValue (0xffffffffl), + MakeUintegerAccessor (&PacketSocket::m_rcvBufSize), + MakeUintegerChecker ()) + ; + return tid; +} + +PacketSocket::PacketSocket () : m_rxAvailable (0) { NS_LOG_FUNCTION_NOARGS (); m_state = STATE_OPEN; @@ -41,6 +60,7 @@ PacketSocket::PacketSocket () void PacketSocket::SetNode (Ptr node) { + NS_LOG_FUNCTION_NOARGS (); m_node = node; } @@ -211,11 +231,19 @@ PacketSocket::Send (Ptr p) m_errno = ERROR_NOTCONN; return -1; } - return SendTo (m_destAddr, p); + return SendTo (p, m_destAddr); +} + +// XXX must limit it to interface MTU +uint32_t +PacketSocket::GetTxAvailable (void) const +{ + // Use 65536 for now + return 0xffff; } int -PacketSocket::SendTo(const Address &address, Ptr p) +PacketSocket::SendTo(Ptr p, const Address &address) { NS_LOG_FUNCTION_NOARGS (); PacketSocketAddress ad; @@ -244,6 +272,11 @@ PacketSocket::SendTo(const Address &address, Ptr p) m_errno = ERROR_AFNOSUPPORT; return -1; } + if (p->GetSize () > GetTxAvailable ()) + { + m_errno = ERROR_MSGSIZE; + return -1; + } ad = PacketSocketAddress::ConvertFrom (address); bool error = false; @@ -301,8 +334,56 @@ PacketSocket::ForwardUp (Ptr device, Ptr packet, address.SetSingleDevice (device->GetIfIndex ()); address.SetProtocol (protocol); - NS_LOG_LOGIC ("UID is " << packet->GetUid() << " PacketSocket " << this); - NotifyDataReceived (packet, address); + if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize) + { + SocketRxAddressTag tag; + tag.SetAddress (address); + packet->AddTag (tag); + m_deliveryQueue.push (packet); + m_rxAvailable += packet->GetSize (); + NS_LOG_LOGIC ("UID is " << packet->GetUid() << " PacketSocket " << this); + NotifyDataRecv (); + } + else + { + // In general, this case should not occur unless the + // receiving application reads data from this socket slowly + // in comparison to the arrival rate + // + // drop and trace packet + NS_LOG_WARN ("No receive buffer space available. Drop."); + m_dropTrace (packet); + } +} + +Ptr +PacketSocket::Recv (uint32_t maxSize, uint32_t flags) +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_deliveryQueue.empty() ) + { + return 0; + } + Ptr p = m_deliveryQueue.front (); + if (p->GetSize () <= maxSize) + { + m_deliveryQueue.pop (); + m_rxAvailable -= p->GetSize (); + } + else + { + p = 0; + } + return p; +} + +uint32_t +PacketSocket::GetRxAvailable (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + // We separately maintain this state to avoid walking the queue + // every time this might be called + return m_rxAvailable; } }//namespace ns3 diff --git a/src/node/packet-socket.h b/src/node/packet-socket.h index d94ef7030..680168f1e 100644 --- a/src/node/packet-socket.h +++ b/src/node/packet-socket.h @@ -22,7 +22,9 @@ #define PACKET_SOCKET_H #include +#include #include "ns3/callback.h" +#include "ns3/traced-callback.h" #include "ns3/ptr.h" #include "ns3/socket.h" @@ -71,6 +73,8 @@ class PacketSocketAddress; class PacketSocket : public Socket { public: + static TypeId GetTypeId (void); + PacketSocket (); virtual ~PacketSocket (); @@ -85,8 +89,12 @@ public: virtual int ShutdownRecv (void); virtual int Connect(const Address &address); virtual int Send (Ptr p); - virtual int SendTo(const Address &address,Ptr p); + virtual uint32_t GetTxAvailable (void) const; + virtual int SendTo(Ptr p, const Address &address); + + virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual uint32_t GetRxAvailable (void) const; private: void ForwardUp (Ptr device, Ptr packet, @@ -109,6 +117,15 @@ private: bool m_isSingleDevice; uint32_t m_device; Address m_destAddr; /// Default destination address + + std::queue > m_deliveryQueue; + uint32_t m_rxAvailable; + + TracedCallback > m_dropTrace; + + // Socket options (attributes) + uint32_t m_rcvBufSize; + }; }//namespace ns3 diff --git a/src/node/socket-defaults.cc b/src/node/socket-defaults.cc new file mode 100644 index 000000000..20c97b980 --- /dev/null +++ b/src/node/socket-defaults.cc @@ -0,0 +1,42 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "socket-defaults.h" +#include "ns3/uinteger.h" + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (SocketDefaults); + +TypeId SocketDefaults::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SocketDefaults") + .SetParent () + .AddAttribute ("DefaultSndBufLimit", + "Default maximum receive buffer size (bytes)", + UintegerValue (0xffffffffl), + MakeUintegerAccessor (&SocketDefaults::m_defaultSndBufLimit), + MakeUintegerChecker ()) + .AddAttribute ("DefaultRcvBufLimit", + "Default maximum receive buffer size (bytes)", + UintegerValue (0xffffffffl), + MakeUintegerAccessor (&SocketDefaults::m_defaultRcvBufLimit), + MakeUintegerChecker ()) + ; + return tid; +} + +} // namespace ns3 diff --git a/src/node/socket-defaults.h b/src/node/socket-defaults.h new file mode 100644 index 000000000..e6eb290fb --- /dev/null +++ b/src/node/socket-defaults.h @@ -0,0 +1,42 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef SOCKET_DEFAULTS_H +#define SOCKET_DEFAULTS_H + +#include "ns3/object.h" + +namespace ns3 { + +/** + * \brief Object to hold socket option defaults + * + * This class can be aggregated to a Node and can be used to store + * socket defaults for a Node. + * + */ +class SocketDefaults : public Object +{ +public: + static TypeId GetTypeId (void); + +private: + uint32_t m_defaultSndBufLimit; + uint32_t m_defaultRcvBufLimit; +}; + +} // namespace ns3 + +#endif /* SOCKET_DEFAULTS_H */ diff --git a/src/node/socket.cc b/src/node/socket.cc index 41f09f879..18a15b0e9 100644 --- a/src/node/socket.cc +++ b/src/node/socket.cc @@ -22,17 +22,34 @@ #include "ns3/log.h" #include "ns3/packet.h" +#include "node.h" #include "socket.h" +#include "socket-factory.h" NS_LOG_COMPONENT_DEFINE ("Socket"); namespace ns3 { +Socket::Socket (void) +{ + NS_LOG_FUNCTION_NOARGS (); +} + Socket::~Socket () { NS_LOG_FUNCTION_NOARGS (); } +Ptr +Socket::CreateSocket (Ptr node, TypeId tid) +{ + Ptr s; + Ptr socketFactory = node->GetObject (tid); + s = socketFactory->CreateSocket (); + NS_ASSERT (s != 0); + return s; +} + void Socket::SetCloseCallback (Callback > closeCompleted) { @@ -80,7 +97,7 @@ Socket::SetSendCallback (Callback, uint32_t> sendCb) } void -Socket::SetRecvCallback (Callback, Ptr,const Address&> receivedData) +Socket::SetRecvCallback (Callback > receivedData) { NS_LOG_FUNCTION_NOARGS (); m_receivedData = receivedData; @@ -107,7 +124,21 @@ int Socket::Send (const uint8_t* buf, uint32_t size) return Send (p); } -int Socket::SendTo (const Address &address, const uint8_t* buf, uint32_t size) +Ptr +Socket::Recv (void) +{ + return Recv (std::numeric_limits::max(), 0); +} + +int +Socket::Recv (uint8_t* buf, uint32_t size, uint32_t flags) +{ + Ptr p = Recv (size, flags); // read up to "size" bytes + memcpy (buf, p->PeekData (), p->GetSize()); + return p->GetSize (); +} + +int Socket::SendTo (const uint8_t* buf, uint32_t size, const Address &address) { NS_LOG_FUNCTION_NOARGS (); Ptr p; @@ -119,7 +150,7 @@ int Socket::SendTo (const Address &address, const uint8_t* buf, uint32_t size) { p = Create (size); } - return SendTo (address,p); + return SendTo (p, address); } void @@ -221,13 +252,127 @@ Socket::NotifySend (uint32_t spaceAvailable) } void -Socket::NotifyDataReceived (Ptr p, const Address &from) +Socket::NotifyDataRecv (void) { NS_LOG_FUNCTION_NOARGS (); if (!m_receivedData.IsNull ()) { - m_receivedData (this, p, from); + m_receivedData (this); } } +/*************************************************************** + * Socket Tags + ***************************************************************/ + +SocketRxAddressTag::SocketRxAddressTag () +{ +} + +void +SocketRxAddressTag::SetAddress (Address addr) +{ + m_address = addr; +} + +Address +SocketRxAddressTag::GetAddress (void) const +{ + return m_address; +} + + +TypeId +SocketRxAddressTag::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SocketRxAddressTag") + .SetParent () + .AddConstructor () + ; + return tid; +} +TypeId +SocketRxAddressTag::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} +uint32_t +SocketRxAddressTag::GetSerializedSize (void) const +{ + return m_address.GetSerializedSize (); +} +void +SocketRxAddressTag::Serialize (TagBuffer i) const +{ + uint8_t len = m_address.GetSerializedSize (); + uint8_t* buffer = new uint8_t[len]; + memset (buffer, 0, len); + m_address.Serialize (buffer, len); + i.Write (buffer, len); + delete [] buffer; +} +void +SocketRxAddressTag::Deserialize (TagBuffer i) +{ + uint8_t type = i.ReadU8 (); + uint8_t len = i.ReadU8 (); + // Len is the length of the address starting from buffer[2] + NS_ASSERT (len >= 2); + uint8_t* buffer = new uint8_t[len]; + memset (buffer, 0, len); + buffer[0] = type; + buffer[1] = len; + i.Read (buffer+2, len); // ReadU8 consumes a byte + m_address = Address::Deserialize (buffer); + delete [] buffer; +} + +SocketIpTtlTag::SocketIpTtlTag () +{ +} + +void +SocketIpTtlTag::SetTtl (uint8_t ttl) +{ + m_ttl = ttl; +} + +uint8_t +SocketIpTtlTag::GetTtl (void) const +{ + return m_ttl; +} + + +TypeId +SocketIpTtlTag::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SocketIpTtlTag") + .SetParent () + .AddConstructor () + ; + return tid; +} +TypeId +SocketIpTtlTag::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +uint32_t +SocketIpTtlTag::GetSerializedSize (void) const +{ + return 1; +} +void +SocketIpTtlTag::Serialize (TagBuffer i) const +{ + i.WriteU8 (m_ttl); +} +void +SocketIpTtlTag::Deserialize (TagBuffer i) +{ + m_ttl = i.ReadU8 (); +} + }//namespace ns3 diff --git a/src/node/socket.h b/src/node/socket.h index 07a267ee7..367c09de9 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -25,29 +25,43 @@ #include "ns3/callback.h" #include "ns3/ptr.h" +#include "ns3/tag.h" #include "ns3/object.h" #include "address.h" #include namespace ns3 { + class Node; class Packet; /** - * \brief Define a Socket API based on the BSD Socket API. + * \ingroup node + * \defgroup socket Socket + * \brief A low-level Socket API based loosely on the BSD Socket API. * - * Contrary to the original BSD socket API, this API is asynchronous: - * it does not contain blocking calls. It also uses class ns3::Packet - * as a fancy byte buffer, allowing data to be passed across the API - * using an ns3::Packet instead of a raw data pointer. Other than that, - * it tries to stick to the BSD API to make it easier for those who know - * the BSD API to use this API. + * A few things to keep in mind about this type of socket: + * - it uses ns-3 API constructs such as class ns3::Address instead of + * C-style structs + * - in contrast to the original BSD socket API, this API is asynchronous: + * it does not contain blocking calls. Sending and receiving operations + * must make use of the callbacks provided. + * - It also uses class ns3::Packet as a fancy byte buffer, allowing + * data to be passed across the API using an ns-3 Packet instead of + * a raw data pointer. + * - Not all of the full POSIX sockets API is supported + * + * Other than that, it tries to stick to the BSD API to make it + * easier for those who know the BSD API to use this API. + * More details are provided in the ns-3 tutorial. */ class Socket : public Object { public: - virtual ~Socket(); + + Socket (void); + virtual ~Socket (void); enum SocketErrno { ERROR_NOTERROR, @@ -64,6 +78,17 @@ public: SOCKET_ERRNO_LAST }; + /** + * This method wraps the creation of sockets that is performed + * by a socket factory on a given node based on a TypeId. + * + * \return A smart pointer to a newly created socket. + * + * \param node The node on which to create the socket + * \param tid The TypeId of the socket to create + */ + static Ptr CreateSocket (Ptr node, TypeId tid); + /** * \return the errno associated to the last call which failed in this * socket. Each socket's errno is initialized to zero @@ -151,13 +176,13 @@ public: */ void SetSendCallback (Callback, uint32_t> sendCb); /** - * \brief Receive data - * \param receivedData Invoked whenever new data is received. + * \brief Notify application when new data is available to be read. * + * This callback is intended to notify a socket that would + * have been blocked in a blocking socket model that data + * is available to be read. */ - void SetRecvCallback (Callback, Ptr, - const Address&> receivedData); - + void SetRecvCallback (Callback >); /** * \param address the address to try to allocate * \returns 0 on success, -1 on failure. @@ -212,12 +237,53 @@ public: /** * \brief Send data (or dummy data) to the remote host - * \param p packet to send - * \returns -1 in case of error or the number of bytes copied in the - * internal buffer and accepted for transmission. + * + * This function matches closely in semantics to the send() function + * call in the standard C library (libc): + * ssize_t send (int s, const void *msg, size_t len, int flags); + * except that the function call is asynchronous. + * + * In a typical blocking sockets model, this call would block upon + * lack of space to hold the message to be sent. In ns-3 at this + * API, the call returns immediately in such a case, but the callback + * registered with SetSendCallback() is invoked when the socket + * has space (when it conceptually unblocks); this is an asynchronous + * I/O model for send(). + * + * This variant of Send() uses class ns3::Packet to encapsulate + * data, rather than providing a raw pointer and length field. + * This allows an ns-3 application to attach tags if desired (such + * as a flow ID) and may allow the simulator to avoid some data + * copies. Despite the appearance of sending Packets on a stream + * socket, just think of it as a fancy byte buffer with streaming + * semantics. + * + * If either the message buffer within the Packet is too long to pass + * atomically through the underlying protocol (for datagram sockets), + * or the message buffer cannot entirely fit in the transmit buffer + * (for stream sockets), -1 is returned and SocketErrno is set + * to ERROR_MSGSIZE. If the packet does not fit, the caller can + * split the Packet (based on information obtained from + * GetTxAvailable) and reattempt to send the data. + * + * \param p ns3::Packet to send + * \returns the number of bytes accepted for transmission if no error + * occurs, and -1 otherwise. */ virtual int Send (Ptr p) = 0; + /** + * \brief Returns the number of bytes which can be sent in a single call + * to Send. + * + * For datagram sockets, this returns the number of bytes that + * can be passed atomically through the underlying protocol. + * + * For stream sockets, this returns the available space in bytes + * left in the transmit buffer. + */ + virtual uint32_t GetTxAvailable (void) const = 0; + /** * \brief Send data (or dummy data) to the remote host * \param buf A pointer to a raw byte buffer of some data to send. If this @@ -231,27 +297,66 @@ public: /** * \brief Send data to a specified peer. - * \param address IP Address of remote host * \param p packet to send + * \param address IP Address of remote host * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - virtual int SendTo (const Address &address,Ptr p) = 0; + virtual int SendTo (Ptr p, const Address &address) = 0; /** * \brief Send data to a specified peer. - * \param address IP Address of remote host * \param buf A pointer to a raw byte buffer of some data to send. If this * is 0, we send dummy data whose size is specified by the third parameter * \param size the number of bytes to copy from the buffer + * \param address IP Address of remote host * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. * * This is provided so as to have an API which is closer in appearance * to that of real network or BSD sockets. */ - int SendTo (const Address &address, const uint8_t* buf, uint32_t size); + int SendTo (const uint8_t* buf, uint32_t size, const Address &address); + /** + * \brief Read a single packet from the socket + * \param maxSize reader will accept packet up to maxSize + * \param flags Socket recv flags + * \returns Ptr of the next in-sequence packet. Returns + * 0 if the socket cannot return a next in-sequence packet conforming + * to the maxSize and flags. + */ + virtual Ptr Recv (uint32_t maxSize, uint32_t flags) = 0; + /** + * \brief Read a single packet from the socket + * + * Overloaded version of Recv(maxSize, flags) with maxSize + * implicitly set to maximum sized integer, and flags set to zero. + * + * \returns Ptr of the next in-sequence packet. Returns + * 0 if the socket cannot return a next in-sequence packet. + */ + Ptr Recv (void); + /** + * \brief Recv data (or dummy data) from the remote host + * \param buf A pointer to a raw byte buffer to write the data to. + * If the underlying packet was carring null (fake) data, this buffer + * will be zeroed up to the length specified by the return value. + * \param size Number of bytes (at most) to copy to buf + * \param flags any flags to pass to the socket + * \returns number of bytes copied into buf + * + * This is provided so as to have an API which is closer in appearance + * to that of real network or BSD sockets. + */ + int Recv (uint8_t* buf, uint32_t size, uint32_t flags); + /** + * Return number of bytes which can be returned from one or + * multiple calls to Recv. + * Must be possible to call this method from the Recv callback. + */ + virtual uint32_t GetRxAvailable (void) const = 0; + protected: void NotifyCloseCompleted (void); void NotifyConnectionSucceeded (void); @@ -262,7 +367,7 @@ protected: void NotifyCloseRequested (void); void NotifyDataSent (uint32_t size); void NotifySend (uint32_t spaceAvailable); - void NotifyDataReceived (Ptr p, const Address &from); + void NotifyDataRecv (void); Callback > m_closeCompleted; Callback > m_connectionSucceeded; @@ -273,7 +378,50 @@ protected: Callback, const Address&> m_newConnectionCreated; Callback, uint32_t> m_dataSent; Callback, uint32_t > m_sendCb; - Callback, Ptr,const Address&> m_receivedData; + Callback > m_receivedData; + +}; + +/** + * \brief This class implements a tag that carries the source address + * of a packet across the receiving socket interface. + */ +class SocketRxAddressTag : public Tag +{ +public: + SocketRxAddressTag (); + void SetAddress (Address addr); + Address GetAddress (void) const; + + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (TagBuffer i) const; + virtual void Deserialize (TagBuffer i); + +private: + Address m_address; +}; + +/** + * \brief This class implements a tag that carries the socket-specific + * TTL of a packet to the IP layer + */ +class SocketIpTtlTag : public Tag +{ +public: + SocketIpTtlTag (); + void SetTtl (uint8_t ttl); + uint8_t GetTtl (void) const; + + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (TagBuffer i) const; + virtual void Deserialize (TagBuffer i); + +private: + uint8_t m_ttl; }; } //namespace ns3 diff --git a/src/node/tcp-socket-factory.cc b/src/node/tcp-socket-factory.cc new file mode 100644 index 000000000..ca1ae25b8 --- /dev/null +++ b/src/node/tcp-socket-factory.cc @@ -0,0 +1,37 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 Georgia Tech Research Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Raj Bhattacharjea + */ +#include "tcp-socket-factory.h" +#include "ns3/uinteger.h" +#include "ns3/double.h" + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (TcpSocketFactory); + +TypeId +TcpSocketFactory::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::TcpSocketFactory") + .SetParent () + ; + return tid; +} + +} // namespace ns3 diff --git a/src/node/tcp.h b/src/node/tcp-socket-factory.h similarity index 59% rename from src/node/tcp.h rename to src/node/tcp-socket-factory.h index 91923cb62..35909cb54 100644 --- a/src/node/tcp.h +++ b/src/node/tcp-socket-factory.h @@ -17,8 +17,8 @@ * * Author: Raj Bhattacharjea */ -#ifndef TCP_H -#define TCP_H +#ifndef TCP_SOCKET_FACTORY_H +#define TCP_SOCKET_FACTORY_H #include "socket-factory.h" @@ -34,44 +34,22 @@ class Socket; * initialize newly created sockets, such as values that are * set through the sysctl or proc interfaces in Linux. - * All TCP implementations must provide an implementation of CreateSocket + * All TCP socket factory implementations must provide an implementation + * of CreateSocket * below, and should make use of the default values configured below. * - * \see TcpImpl + * \see TcpSocketFactoryImpl * */ -class Tcp : public SocketFactory +class TcpSocketFactory : public SocketFactory { public: static TypeId GetTypeId (void); virtual Ptr CreateSocket (void) = 0; - uint32_t GetDefaultSegSize (void) const; - uint32_t GetDefaultAdvWin (void) const; - uint32_t GetDefaultSsThresh (void) const; - uint32_t GetDefaultTxBuffer (void) const; - uint32_t GetDefaultRxBuffer (void) const; - uint32_t GetDefaultInitialCwnd (void) const; - uint32_t GetDefaultConnTimeout (void) const; - uint32_t GetDefaultConnCount (void) const; - double GetDefaultDelAckTimeout (void) const; - uint32_t GetDefaultDelAckCount (void) const; - -private: - uint32_t m_defaultSegSize; - uint32_t m_defaultAdvWin; - uint32_t m_defaultSsThresh; - uint32_t m_defaultTxBuffer; - uint32_t m_defaultRxBuffer; - uint32_t m_defaultInitialCwnd; - uint32_t m_defaultConnTimeout; - uint32_t m_defaultConnCount; - double m_defaultDelAckTimeout; - uint32_t m_defaultDelAckCount; - }; } // namespace ns3 -#endif /* TCP_H */ +#endif /* TCP_SOCKET_FACTORY_H */ diff --git a/src/node/tcp-socket.cc b/src/node/tcp-socket.cc new file mode 100644 index 000000000..1dd3d4057 --- /dev/null +++ b/src/node/tcp-socket.cc @@ -0,0 +1,114 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "ns3/object.h" +#include "ns3/log.h" +#include "ns3/uinteger.h" +#include "ns3/double.h" +#include "ns3/trace-source-accessor.h" +#include "ns3/nstime.h" +#include "tcp-socket.h" + +NS_LOG_COMPONENT_DEFINE ("TcpSocket"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (TcpSocket); + +TypeId +TcpSocket::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::TcpSocket") + .SetParent () + .AddAttribute ("SndBufSize", + "TcpSocket maximum transmit buffer size (bytes)", + UintegerValue (0xffffffffl), + MakeUintegerAccessor (&TcpSocket::GetSndBufSize, + &TcpSocket::SetSndBufSize), + MakeUintegerChecker ()) + .AddAttribute ("RcvBufSize", + "TcpSocket maximum receive buffer size (bytes)", + UintegerValue (0xffffffffl), + MakeUintegerAccessor (&TcpSocket::GetRcvBufSize, + &TcpSocket::SetRcvBufSize), + MakeUintegerChecker ()) + .AddAttribute ("SegmentSize", + "TCP maximum segment size in bytes (may be adjusted based on MTU discovery)", + UintegerValue (536), + MakeUintegerAccessor (&TcpSocket::GetSegSize, + &TcpSocket::SetSegSize), + MakeUintegerChecker ()) + .AddAttribute ("AdvertisedWindowSize", + "TCP advertised window size (bytes)", + UintegerValue (0xffff), + MakeUintegerAccessor (&TcpSocket::GetAdvWin, + &TcpSocket::SetAdvWin), + MakeUintegerChecker ()) + .AddAttribute ("SlowStartThreshold", + "TCP slow start threshold (bytes)", + UintegerValue (0xffff), + MakeUintegerAccessor (&TcpSocket::GetSSThresh, + &TcpSocket::SetSSThresh), + MakeUintegerChecker ()) + .AddAttribute ("InitialCwnd", + "TCP initial congestion window size (segments)", + UintegerValue (1), + MakeUintegerAccessor (&TcpSocket::GetInitialCwnd, + &TcpSocket::SetInitialCwnd), + MakeUintegerChecker ()) + .AddAttribute ("ConnTimeout", + "TCP retransmission timeout when opening connection (seconds)", + TimeValue (Seconds (3)), + MakeTimeAccessor (&TcpSocket::GetConnTimeout, + &TcpSocket::SetConnTimeout), + MakeTimeChecker ()) + .AddAttribute ("ConnCount", + "Number of connection attempts (SYN retransmissions) before returning failure", + UintegerValue (6), + MakeUintegerAccessor (&TcpSocket::GetConnCount, + &TcpSocket::SetConnCount), + MakeUintegerChecker ()) + .AddAttribute ("DelAckTimeout", + "Timeout value for TCP delayed acks, in seconds", + TimeValue (Seconds (0.2)), + MakeTimeAccessor (&TcpSocket::GetDelAckTimeout, + &TcpSocket::SetDelAckTimeout), + MakeTimeChecker ()) + .AddAttribute ("DelAckCount", + "Number of packets to wait before sending a TCP ack", + UintegerValue (2), + MakeUintegerAccessor (&TcpSocket::GetDelAckMaxCount, + &TcpSocket::SetDelAckMaxCount), + MakeUintegerChecker ()) + ; + return tid; +} + +TcpSocket::TcpSocket () +{ + NS_LOG_FUNCTION_NOARGS (); +} + +TcpSocket::~TcpSocket () +{ + NS_LOG_FUNCTION_NOARGS (); +} + +}; // namespace ns3 diff --git a/src/node/tcp-socket.h b/src/node/tcp-socket.h new file mode 100644 index 000000000..9092474f4 --- /dev/null +++ b/src/node/tcp-socket.h @@ -0,0 +1,94 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 Georgia Tech Research Corporation + * 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: George F. Riley + * Mathieu Lacage + */ + +#ifndef __TCP_SOCKET_H__ +#define __TCP_SOCKET_H__ + +#include "socket.h" +#include "ns3/traced-callback.h" +#include "ns3/callback.h" +#include "ns3/ptr.h" +#include "ns3/object.h" +#include "ns3/nstime.h" + +namespace ns3 { + +class Node; +class Packet; + +/** + * \brief (abstract) base class of all TcpSockets + * + * This class exists solely for hosting TcpSocket attributes that can + * be reused across different implementations. + */ +class TcpSocket : public Socket +{ +public: + static TypeId GetTypeId (void); + + TcpSocket (void); + virtual ~TcpSocket (void); + + virtual enum Socket::SocketErrno GetErrno (void) const = 0; + virtual Ptr GetNode (void) const = 0; + virtual int Bind () = 0; + virtual int Close (void) = 0; + virtual int ShutdownSend (void) = 0; + virtual int ShutdownRecv (void) = 0; + virtual int Connect (const Address &address) = 0; + virtual int Send (Ptr p) = 0; + virtual uint32_t GetTxAvailable (void) const = 0; + virtual int SendTo (Ptr p, const Address &address) = 0; + virtual Ptr Recv (uint32_t maxSize, uint32_t flags) = 0; + virtual uint32_t GetRxAvailable (void) const = 0; + +private: + // Indirect the attribute setting and getting through private virtual methods + virtual void SetSndBufSize (uint32_t size) = 0; + virtual uint32_t GetSndBufSize (void) const = 0; + virtual void SetRcvBufSize (uint32_t size) = 0; + virtual uint32_t GetRcvBufSize (void) const = 0; + virtual void SetSegSize (uint32_t size) = 0; + virtual uint32_t GetSegSize (void) const = 0; + virtual void SetAdvWin (uint32_t window) = 0; + virtual uint32_t GetAdvWin (void) const = 0; + virtual void SetSSThresh (uint32_t threshold) = 0; + virtual uint32_t GetSSThresh (void) const = 0; + virtual void SetInitialCwnd (uint32_t count) = 0; + virtual uint32_t GetInitialCwnd (void) const = 0; + virtual void SetConnTimeout (Time timeout) = 0; + virtual Time GetConnTimeout (void) const = 0; + virtual void SetConnCount (uint32_t count) = 0; + virtual uint32_t GetConnCount (void) const = 0; + virtual void SetDelAckTimeout (Time timeout) = 0; + virtual Time GetDelAckTimeout (void) const = 0; + virtual void SetDelAckMaxCount (uint32_t count) = 0; + virtual uint32_t GetDelAckMaxCount (void) const = 0; + +}; + +} //namespace ns3 + +#endif /* TCP_SOCKET_H */ + + diff --git a/src/node/tcp.cc b/src/node/tcp.cc deleted file mode 100644 index 77e02362f..000000000 --- a/src/node/tcp.cc +++ /dev/null @@ -1,140 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 Georgia Tech Research Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Raj Bhattacharjea - */ -#include "tcp.h" -#include "ns3/uinteger.h" -#include "ns3/double.h" - -namespace ns3 { - -NS_OBJECT_ENSURE_REGISTERED (Tcp); - -TypeId -Tcp::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::Tcp") - .SetParent () - .AddAttribute ("DefaultSegmentSize", - "Default TCP maximum segment size in bytes (may be adjusted based on MTU discovery)", - UintegerValue (536), - MakeUintegerAccessor (&Tcp::m_defaultSegSize), - MakeUintegerChecker ()) - .AddAttribute ("DefaultAdvertisedWindowSize", - "Default TCP advertised window size (bytes)", - UintegerValue (0xffff), - MakeUintegerAccessor (&Tcp::m_defaultAdvWin), - MakeUintegerChecker ()) - .AddAttribute ("DefaultSlowStartThreshold", - "Default TCP slow start threshold (bytes)", - UintegerValue (0xffff), - MakeUintegerAccessor (&Tcp::m_defaultSsThresh), - MakeUintegerChecker ()) - .AddAttribute ("DefaultTxBufferSize", - "Default TCP maximum transmit buffer size (bytes)", - UintegerValue (0xffffffffl), - MakeUintegerAccessor (&Tcp::m_defaultTxBuffer), - MakeUintegerChecker ()) - .AddAttribute ("DefaultRxBufferSize", - "Default TCP maximum receive buffer size (bytes)", - UintegerValue (0xffffffffl), - MakeUintegerAccessor (&Tcp::m_defaultRxBuffer), - MakeUintegerChecker ()) - .AddAttribute ("DefaultInitialCongestionWindowSize", - "Default TCP initial congestion window size (segments)", - UintegerValue (1), - MakeUintegerAccessor (&Tcp::m_defaultInitialCwnd), - MakeUintegerChecker ()) - .AddAttribute ("DefaultConnTimeout", - "Default TCP retransmission timeout when opening connection (seconds)", - UintegerValue (3), - MakeUintegerAccessor (&Tcp::m_defaultConnTimeout), - MakeUintegerChecker ()) - .AddAttribute ("DefaultConnCount", - "Default number of connection attempts (SYN retransmissions) before returning failure", - UintegerValue (6), - MakeUintegerAccessor (&Tcp::m_defaultConnCount), - MakeUintegerChecker ()) - .AddAttribute ("DefaultDelAckTimeout", - "Default timeout value for TCP delayed acks, in seconds", - DoubleValue (0.2), - MakeDoubleAccessor (&Tcp::m_defaultDelAckTimeout), - MakeDoubleChecker ()) - .AddAttribute ("DefaultDelAckCount", - "Default number of packets to wait before sending a TCP ack", - UintegerValue (2), - MakeUintegerAccessor (&Tcp::m_defaultDelAckCount), - MakeUintegerChecker ()) - ; - return tid; -} - -uint32_t -Tcp::GetDefaultSegSize (void) const -{ - return m_defaultSegSize; -} -uint32_t -Tcp::GetDefaultAdvWin (void) const -{ - return m_defaultAdvWin; -} -uint32_t -Tcp::GetDefaultSsThresh (void) const -{ - return m_defaultSsThresh; -} -uint32_t -Tcp::GetDefaultTxBuffer (void) const -{ - return m_defaultTxBuffer; -} -uint32_t -Tcp::GetDefaultRxBuffer (void) const -{ - return m_defaultRxBuffer; -} -uint32_t -Tcp::GetDefaultInitialCwnd (void) const -{ - return m_defaultInitialCwnd; -} -uint32_t -Tcp::GetDefaultConnTimeout (void) const -{ - return m_defaultConnTimeout; -} -uint32_t -Tcp::GetDefaultConnCount (void) const -{ - return m_defaultConnCount; -} - -double -Tcp::GetDefaultDelAckTimeout (void) const -{ - return m_defaultDelAckTimeout; -} - -uint32_t -Tcp::GetDefaultDelAckCount (void) const -{ - return m_defaultDelAckCount; -} - -} // namespace ns3 diff --git a/src/node/udp.cc b/src/node/udp-socket-factory.cc similarity index 78% rename from src/node/udp.cc rename to src/node/udp-socket-factory.cc index 989dd95f8..d95b0068a 100644 --- a/src/node/udp.cc +++ b/src/node/udp-socket-factory.cc @@ -17,20 +17,19 @@ * * Author: Mathieu Lacage */ -#include "udp.h" +#include "udp-socket-factory.h" +#include "ns3/uinteger.h" namespace ns3 { -NS_OBJECT_ENSURE_REGISTERED (Udp); +NS_OBJECT_ENSURE_REGISTERED (UdpSocketFactory); -TypeId Udp::GetTypeId (void) +TypeId UdpSocketFactory::GetTypeId (void) { - static TypeId tid = TypeId ("ns3::Udp") - .SetParent (); + static TypeId tid = TypeId ("ns3::UdpSocketFactory") + .SetParent () + ; return tid; } -Udp::Udp () -{} - } // namespace ns3 diff --git a/src/node/udp.h b/src/node/udp-socket-factory.h similarity index 78% rename from src/node/udp.h rename to src/node/udp-socket-factory.h index a539eb94a..32789c35a 100644 --- a/src/node/udp.h +++ b/src/node/udp-socket-factory.h @@ -17,8 +17,8 @@ * * Author: Mathieu Lacage */ -#ifndef UDP_H -#define UDP_H +#ifndef UDP_SOCKET_FACTORY_H +#define UDP_SOCKET_FACTORY_H #include "socket-factory.h" @@ -29,23 +29,17 @@ class Socket; /** * \brief API to create UDP socket instances * - * This abstract class defines the API for UDP sockets. - * This class also can hold the global default variables used to - * initialize newly created sockets, such as values that are - * set through the sysctl or proc interfaces in Linux. - + * This abstract class defines the API for UDP socket factory. * All UDP implementations must provide an implementation of CreateSocket * below. * - * \see UdpImpl + * \see UdpSocketFactoryImpl */ -class Udp : public SocketFactory +class UdpSocketFactory : public SocketFactory { public: static TypeId GetTypeId (void); - Udp (); - /** * \return smart pointer to Socket * @@ -53,8 +47,9 @@ public: * implementations.. */ virtual Ptr CreateSocket (void) = 0; + }; } // namespace ns3 -#endif /* UDP_H */ +#endif /* UDP_SOCKET_FACTORY_H */ diff --git a/src/node/udp-socket.cc b/src/node/udp-socket.cc new file mode 100644 index 000000000..8fc5ea8b1 --- /dev/null +++ b/src/node/udp-socket.cc @@ -0,0 +1,70 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "ns3/object.h" +#include "ns3/log.h" +#include "ns3/uinteger.h" +#include "ns3/trace-source-accessor.h" +#include "udp-socket.h" + +NS_LOG_COMPONENT_DEFINE ("UdpSocket"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (UdpSocket); + +TypeId +UdpSocket::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::UdpSocket") + .SetParent () + .AddAttribute ("RcvBufSize", + "UdpSocket maximum receive buffer size (bytes)", + UintegerValue (0xffffffffl), + MakeUintegerAccessor (&UdpSocket::GetRcvBufSize, + &UdpSocket::SetRcvBufSize), + MakeUintegerChecker ()) + .AddAttribute ("IpTtl", + "socket-specific TTL for unicast IP packets (if non-zero)", + UintegerValue (0), + MakeUintegerAccessor (&UdpSocket::GetIpTtl, + &UdpSocket::SetIpTtl), + MakeUintegerChecker ()) + .AddAttribute ("IpMulticastTtl", + "socket-specific TTL for multicast IP packets (if non-zero)", + UintegerValue (0), + MakeUintegerAccessor (&UdpSocket::GetIpMulticastTtl, + &UdpSocket::SetIpMulticastTtl), + MakeUintegerChecker ()) + ; + return tid; +} + +UdpSocket::UdpSocket () +{ + NS_LOG_FUNCTION_NOARGS (); +} + +UdpSocket::~UdpSocket () +{ + NS_LOG_FUNCTION_NOARGS (); +} + +}; // namespace ns3 diff --git a/src/node/udp-socket.h b/src/node/udp-socket.h new file mode 100644 index 000000000..1c81916c2 --- /dev/null +++ b/src/node/udp-socket.h @@ -0,0 +1,79 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 Georgia Tech Research Corporation + * 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: George F. Riley + * Mathieu Lacage + */ + +#ifndef __UDP_SOCKET_H__ +#define __UDP_SOCKET_H__ + +#include "socket.h" +#include "ns3/traced-callback.h" +#include "ns3/callback.h" +#include "ns3/ptr.h" +#include "ns3/object.h" + +namespace ns3 { + +class Node; +class Packet; + +/** + * \brief (abstract) base class of all UdpSockets + * + * This class exists solely for hosting UdpSocket attributes that can + * be reused across different implementations. + */ +class UdpSocket : public Socket +{ +public: + static TypeId GetTypeId (void); + + UdpSocket (void); + virtual ~UdpSocket (void); + + virtual enum Socket::SocketErrno GetErrno (void) const = 0; + virtual Ptr GetNode (void) const = 0; + virtual int Bind () = 0; + virtual int Close (void) = 0; + virtual int ShutdownSend (void) = 0; + virtual int ShutdownRecv (void) = 0; + virtual int Connect (const Address &address) = 0; + virtual int Send (Ptr p) = 0; + virtual uint32_t GetTxAvailable (void) const = 0; + virtual int SendTo (Ptr p, const Address &address) = 0; + virtual Ptr Recv (uint32_t maxSize, uint32_t flags) = 0; + virtual uint32_t GetRxAvailable (void) const = 0; + +private: + // Indirect the attribute setting and getting through private virtual methods + virtual void SetRcvBufSize (uint32_t size) = 0; + virtual uint32_t GetRcvBufSize (void) const = 0; + virtual void SetIpTtl (uint32_t ipTtl) = 0; + virtual uint32_t GetIpTtl (void) const = 0; + virtual void SetIpMulticastTtl (uint32_t ipTtl) = 0; + virtual uint32_t GetIpMulticastTtl (void) const = 0; + +}; + +} //namespace ns3 + +#endif /* UDP_SOCKET_H */ + + diff --git a/src/node/wscript b/src/node/wscript index 770b1edb9..2f91f1e2a 100644 --- a/src/node/wscript +++ b/src/node/wscript @@ -25,8 +25,10 @@ def build(bld): 'socket-factory.cc', 'packet-socket-factory.cc', 'packet-socket.cc', - 'udp.cc', - 'tcp.cc', + 'udp-socket.cc', + 'udp-socket-factory.cc', + 'tcp-socket.cc', + 'tcp-socket-factory.cc', 'ipv4.cc', 'application.cc', 'simple-channel.cc', @@ -57,8 +59,10 @@ def build(bld): 'socket.h', 'socket-factory.h', 'packet-socket-factory.h', - 'udp.h', - 'tcp.h', + 'udp-socket.h', + 'udp-socket-factory.h', + 'tcp-socket.h', + 'tcp-socket-factory.h', 'ipv4.h', 'application.h', 'simple-channel.h', diff --git a/src/routing/olsr/olsr-agent-impl.cc b/src/routing/olsr/olsr-agent-impl.cc index 5c27a7d6b..2d240e897 100644 --- a/src/routing/olsr/olsr-agent-impl.cc +++ b/src/routing/olsr/olsr-agent-impl.cc @@ -31,7 +31,7 @@ #include "olsr-agent-impl.h" #include "ns3/socket-factory.h" -#include "ns3/udp.h" +#include "ns3/udp-socket-factory.h" #include "ns3/simulator.h" #include "ns3/log.h" #include "ns3/random-variable.h" @@ -258,9 +258,7 @@ void AgentImpl::Start () // Add OLSR as routing protocol, with slightly higher priority than // static routing. m_ipv4->AddRoutingProtocol (m_routingTable, 10); - - Ptr socketFactory = GetObject (Udp::GetTypeId ()); - + Ipv4Address loopback ("127.0.0.1"); for (uint32_t i = 0; i < m_ipv4->GetNInterfaces (); i++) { @@ -281,7 +279,8 @@ void AgentImpl::Start () } // Create a socket to listen only on this interface - Ptr socket = socketFactory->CreateSocket (); + Ptr socket = Socket::CreateSocket (GetObject (), + UdpSocketFactory::GetTypeId()); socket->SetRecvCallback (MakeCallback (&AgentImpl::RecvOlsr, this)); if (socket->Bind (InetSocketAddress (addr, OLSR_PORT_NUMBER))) { @@ -307,10 +306,17 @@ void AgentImpl::SetMainInterface (uint32_t interface) // // \brief Processes an incoming %OLSR packet following RFC 3626 specification. void -AgentImpl::RecvOlsr (Ptr socket, - Ptr receivedPacket, - const Address &sourceAddress) +AgentImpl::RecvOlsr (Ptr socket) { + Ptr receivedPacket; + receivedPacket = socket->Recv (); + + SocketRxAddressTag tag; + bool found; + found = receivedPacket->FindFirstMatchingTag (tag); + NS_ASSERT (found); + Address sourceAddress = tag.GetAddress (); + InetSocketAddress inetSourceAddr = InetSocketAddress::ConvertFrom (sourceAddress); Ipv4Address senderIfaceAddr = inetSourceAddr.GetIpv4 (); Ipv4Address receiverIfaceAddr = m_socketAddresses[socket]; diff --git a/src/routing/olsr/olsr-agent-impl.h b/src/routing/olsr/olsr-agent-impl.h index 6c4f4b68a..01e486d35 100644 --- a/src/routing/olsr/olsr-agent-impl.h +++ b/src/routing/olsr/olsr-agent-impl.h @@ -98,9 +98,7 @@ protected: /// Increments message sequence number and returns the new value. inline uint16_t GetMessageSequenceNumber (); - void RecvOlsr (Ptr socket, - Ptr receivedPacket, - const Address &sourceAddress); + void RecvOlsr (Ptr socket); void MprComputation (); void RoutingTableComputation (); diff --git a/utils/print-introspected-doxygen.cc b/utils/print-introspected-doxygen.cc index e76629571..24f8b944f 100644 --- a/utils/print-introspected-doxygen.cc +++ b/utils/print-introspected-doxygen.cc @@ -236,8 +236,8 @@ int main (int argc, char *argv[]) NodeContainer c; c.Create (1); StaticInformation info; - info.RecordAggregationInfo ("ns3::Node", "ns3::Tcp"); - info.RecordAggregationInfo ("ns3::Node", "ns3::Udp"); + info.RecordAggregationInfo ("ns3::Node", "ns3::TcpSocketFactory"); + info.RecordAggregationInfo ("ns3::Node", "ns3::UdpSocketFactory"); info.RecordAggregationInfo ("ns3::Node", "ns3::PacketSocketFactory"); info.RecordAggregationInfo ("ns3::Node", "ns3::olsr::Agent"); info.RecordAggregationInfo ("ns3::Node", "ns3::MobilityModel");