diff --git a/examples/tcp-nsc-lfn.cc b/examples/tcp-nsc-lfn.cc new file mode 100644 index 000000000..a57e2b633 --- /dev/null +++ b/examples/tcp-nsc-lfn.cc @@ -0,0 +1,145 @@ +/* -*- 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 + * + */ + +// +// Network topology +// +// 6Mb/s, 500ms +// n0-----------------n1 +// +// - a 'lossy' network with long delay +// - TCP flow from n0 to n1 and from n1 to n0 +// - pcap traces generated as tcp-nsc-lfn-0-0.pcap and tcp-nsc-lfn-1-0.pcap +// Usage (e.g.): ./waf --run 'tcp-nsc-lfn --TCP_CONGESTION=hybla --runtime=30' + +#include +#include +#include +#include +#include + +#include "ns3/core-module.h" +#include "ns3/common-module.h" +#include "ns3/helper-module.h" +#include "ns3/node-module.h" +#include "ns3/global-route-manager.h" +#include "ns3/simulator-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TcpNscLfn"); + + +int main (int argc, char *argv[]) +{ + RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); + + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (4096)); + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("6Mbps")); + + // cubic is the default congestion algorithm in Linux 2.6.26 + std::string tcpCong = "cubic"; + // this is the default error rate of our link, that is, the the probability of a single + // byte being 'corrupted' during transfer. + double errRate = 0.000001; + // how long the sender should be running, in seconds. + unsigned int runtime = 120; + // the name of the NSC stack library that should be used + std::string nscStack = "liblinux2.6.26.so"; + + CommandLine cmd; + // Here, we define additional command line options. + // This allows a user to override the defaults set above from the command line. + cmd.AddValue("TCP_CONGESTION", "Linux 2.6.26 Tcp Congestion control algorithm to use", tcpCong); + cmd.AddValue("error-rate", "Error rate to apply to link", errRate); + cmd.AddValue("runtime", "How long the applications should send data (default 120 seconds)", runtime); + cmd.AddValue("nscstack", "Set name of NSC stack (shared library) to use (default liblinux2.6.26.so)", nscStack); + cmd.Parse (argc, argv); + + NodeContainer n; + n.Create (2); + + PointToPointHelper p2p; + // create point-to-point link with a bandwidth of 6MBit/s and a large delay (0.5 seconds) + p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate(6 * 1000 * 1000))); + p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds(500))); + + NetDeviceContainer p2pInterfaces = p2p.Install (n); + // The default MTU of the p2p link would be 65535, which doesn't work + // well with our default errRate (most packets would arrive corrupted). + p2pInterfaces.Get(0)->SetMtu(1500); + p2pInterfaces.Get(1)->SetMtu(1500); + + InternetStackHelper internet; + // The next statement switches the nodes to 'NSC'-Mode. + // It disables the native ns-3 TCP model and loads the NSC library. + internet.SetNscStack (nscStack); + internet.Install (n); + + if (tcpCong != "cubic") // make sure we only fail if both --nscstack and --TCP_CONGESTION are used + { + // This uses ns-3s attribute system to set the 'net.ipv4.tcp_congestion_control' sysctl of the + // stack. + // The same mechanism could be used to e.g. disable TCP timestamps: + // Config::Set ("/NodeList/*/$ns3::Ns3NscStack/net.ipv4.tcp_timestamps", StringValue ("0")); + Config::Set ("/NodeList/*/$ns3::Ns3NscStack/net.ipv4.tcp_congestion_control", StringValue (tcpCong)); + } + Ipv4AddressHelper ipv4; + ipv4.SetBase ("10.0.0.0", "255.255.255.0"); + Ipv4InterfaceContainer ipv4Interfaces = ipv4.Assign (p2pInterfaces); + + DoubleValue rate(errRate); + RandomVariableValue u01(UniformVariable (0.0, 1.0)); + Ptr em1 = + CreateObject ("RanVar", u01, "ErrorRate", rate); + Ptr em2 = + CreateObject ("RanVar", u01, "ErrorRate", rate); + + // This enables the specified errRate on both link endpoints. + p2pInterfaces.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue (em1)); + p2pInterfaces.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue (em2)); + + GlobalRouteManager::PopulateRoutingTables (); + + uint16_t servPort = 8080; + PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), servPort)); + ApplicationContainer sinkApp = sinkHelper.Install (n); + sinkApp.Start (Seconds (0.0)); + // this makes sure that the receiver will run one minute longer than the sender applicaton. + sinkApp.Stop (Seconds (runtime + 60.0)); + + // This sets up two TCP flows, one from A -> B, one from B -> A. + for (int i = 0, j = 1; i < 2; j--, i++) + { + Address remoteAddress(InetSocketAddress(ipv4Interfaces.GetAddress (i), servPort)); + OnOffHelper clientHelper ("ns3::TcpSocketFactory", remoteAddress); + clientHelper.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); + clientHelper.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); + ApplicationContainer clientApp = clientHelper.Install(n.Get(j)); + clientApp.Start (Seconds (1.0 + i)); + clientApp.Stop (Seconds (runtime + 1.0 + i)); + } + + // This tells ns-3 to generate pcap traces. + PointToPointHelper::EnablePcapAll ("tcp-nsc-lfn"); + + Simulator::Stop (Seconds(900)); + Simulator::Run (); + Simulator::Destroy (); + + return 0; +} diff --git a/examples/tcp-nsc-zoo.cc b/examples/tcp-nsc-zoo.cc new file mode 100644 index 000000000..d8bbe735e --- /dev/null +++ b/examples/tcp-nsc-zoo.cc @@ -0,0 +1,131 @@ +/* -*- 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 + * + */ + + +// Network topology +// +// n0 n1 n2 n3 +// | | | | +// ================= +// LAN +// +// - Pcap traces are saved as tcp-nsc-zoo-$n-0.pcap, where $n represents the node number +// - TCP flows from n0 to n1, n2, n3, from n1 to n0, n2, n3, etc. +// Usage (e.g.): ./waf --run 'tcp-nsc-zoo --Nodes=5' + +#include +#include + +#include "ns3/core-module.h" +#include "ns3/helper-module.h" +#include "ns3/node-module.h" +#include "ns3/global-route-manager.h" +#include "ns3/simulator-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TcpNscZoo"); + +// Simulates a diverse network with various stacks supported by NSC. +int main(int argc, char *argv[]) +{ + CsmaHelper csma; + unsigned int MaxNodes = 4; + + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (4096)); + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("1Mb/s")); + CommandLine cmd; + // this allows the user to raise the number of nodes using --Nodes=X command-line argument. + cmd.AddValue("Nodes", "Number of nodes in the network", MaxNodes); + cmd.Parse (argc, argv); + + csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate(100 * 1000 * 1000))); + csma.SetChannelAttribute ("Delay", TimeValue (MicroSeconds (200))); + + NodeContainer n; + n.Create(MaxNodes); + NetDeviceContainer ethInterfaces = csma.Install (n); + + InternetStackHelper internetStack; + + internetStack.SetNscStack ("liblinux2.6.26.so"); + // this switches nodes 0 and 1 to NSCs Linux 2.6.26 stack. + internetStack.Install (n.Get(0)); + internetStack.Install (n.Get(1)); + // this disables TCP SACK, wscale and timestamps on node 1 (the attributes represent sysctl-values). + Config::Set ("/NodeList/1/$ns3::Ns3NscStack/net.ipv4.tcp_sack", StringValue ("0")); + Config::Set ("/NodeList/1/$ns3::Ns3NscStack/net.ipv4.tcp_timestamps", StringValue ("0")); + Config::Set ("/NodeList/1/$ns3::Ns3NscStack/net.ipv4.tcp_window_scaling", StringValue ("0")); + internetStack.Install (n.Get(2)); + // the next statement doesn't change anything for the nodes 0, 1, and 2; since they + // already have a stack assigned. + internetStack.SetNscStack ("liblinux2.6.18.so"); + // this switches node 3 to NSCs Linux 2.6.18 stack. + internetStack.Install (n.Get(3)); + // and then agains disables sack/timestamps/wscale on node 3. + Config::Set ("/NodeList/3/$ns3::Ns3NscStack/net.ipv4.tcp_sack", StringValue ("0")); + Config::Set ("/NodeList/3/$ns3::Ns3NscStack/net.ipv4.tcp_timestamps", StringValue ("0")); + Config::Set ("/NodeList/3/$ns3::Ns3NscStack/net.ipv4.tcp_window_scaling", StringValue ("0")); + // the freebsd stack is not yet built by default, so its commented out for now. + // internetStack.SetNscStack ("libfreebsd5.so"); + for (unsigned int i =4; i < MaxNodes; i++) + { + internetStack.Install (n.Get(i)); + } + Ipv4AddressHelper ipv4; + + ipv4.SetBase ("10.0.0.0", "255.255.255.0"); + Ipv4InterfaceContainer ipv4Interfaces = ipv4.Assign (ethInterfaces); + + GlobalRouteManager::PopulateRoutingTables (); + + uint16_t servPort = 8080; + PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), servPort)); + // start a sink client on all nodes + ApplicationContainer sinkApp = sinkHelper.Install (n); + sinkApp.Start (Seconds (1.0)); + sinkApp.Stop (Seconds (30.0)); + + // This tells every node on the network to start a flow to all other nodes on the network ... + for (unsigned int i = 0 ; i < MaxNodes;i++) + { + for (unsigned int j = 0 ; j < MaxNodes;j++) + { + if (i == j) + { // ...but we don't want a node to talk to itself. + continue; + } + Address remoteAddress(InetSocketAddress(ipv4Interfaces.GetAddress (j), servPort)); + OnOffHelper clientHelper ("ns3::TcpSocketFactory", remoteAddress); + clientHelper.SetAttribute + ("OnTime", RandomVariableValue (ConstantVariable (1))); + clientHelper.SetAttribute + ("OffTime", RandomVariableValue (ConstantVariable (0))); + ApplicationContainer clientApp = clientHelper.Install(n.Get(i)); + clientApp.Start (Seconds (j + 1.0)); /* delay startup depending on node number */ + clientApp.Stop (Seconds (j + 10.0)); + } + } + + CsmaHelper::EnablePcapAll ("tcp-nsc-zoo"); + + Simulator::Stop (Seconds(1000)); + Simulator::Run (); + Simulator::Destroy (); + + return 0; +} diff --git a/examples/wscript b/examples/wscript index b0930a29a..199a5566b 100644 --- a/examples/wscript +++ b/examples/wscript @@ -64,6 +64,14 @@ def build(bld): ['point-to-point', 'internet-stack']) obj.source = 'tcp-errors.cc' + obj = bld.create_ns3_program('tcp-nsc-lfn', + ['point-to-point', 'internet-stack']) + obj.source = 'tcp-nsc-lfn.cc' + + obj = bld.create_ns3_program('tcp-nsc-zoo', + ['csma', 'internet-stack']) + obj.source = 'tcp-nsc-zoo.cc' + obj = bld.create_ns3_program('tcp-star-server', ['point-to-point', 'internet-stack']) obj.source = 'tcp-star-server.cc' diff --git a/src/helper/internet-stack-helper.cc b/src/helper/internet-stack-helper.cc index 792f6e528..ac4523848 100644 --- a/src/helper/internet-stack-helper.cc +++ b/src/helper/internet-stack-helper.cc @@ -33,6 +33,10 @@ namespace ns3 { std::vector InternetStackHelper::m_traces; std::string InternetStackHelper::m_pcapBaseFilename; +InternetStackHelper::InternetStackHelper() : m_nscLibrary("") +{ +} + void InternetStackHelper::Cleanup (void) { @@ -48,6 +52,12 @@ InternetStackHelper::Cleanup (void) m_traces.clear (); } +void +InternetStackHelper::SetNscStack(const std::string soname) +{ + m_nscLibrary = soname; +} + void InternetStackHelper::Install (NodeContainer c) { @@ -59,8 +69,12 @@ InternetStackHelper::Install (NodeContainer c) NS_FATAL_ERROR ("InternetStackHelper::Install(): Aggregating " "an InternetStack to a node with an existing Ipv4 object"); return; - } - AddInternetStack (node); + } + if (m_nscLibrary != "") + AddNscInternetStack (node, m_nscLibrary); + else + AddInternetStack (node); + Ptr factory = CreateObject (); node->AggregateObject (factory); } diff --git a/src/helper/internet-stack-helper.h b/src/helper/internet-stack-helper.h index 74f1054e0..59b397a34 100644 --- a/src/helper/internet-stack-helper.h +++ b/src/helper/internet-stack-helper.h @@ -33,6 +33,8 @@ namespace ns3 { class InternetStackHelper { public: + InternetStackHelper(void); + /** * \param c the set of nodes * @@ -44,6 +46,13 @@ public: */ void Install (NodeContainer c); + /** + * \param soname name of the shared library with the nsc tcp stack + * to use, e.g. 'liblinux2.6.26.so'. The empty string resets + * the InternetStackHelper to use the ns-3 models again. + */ + void SetNscStack(std::string soname); + /** * \param filename filename prefix to use for pcap files. * @@ -60,6 +69,7 @@ public: static void EnablePcapAll (std::string filename); private: + std::string m_nscLibrary; static void Cleanup (void); static void LogRxIp (std::string context, Ptr packet, uint32_t deviceId); static void LogTxIp (std::string context, Ptr packet, uint32_t deviceId); diff --git a/src/internet-stack/internet-stack.cc b/src/internet-stack/internet-stack.cc index 6070daab9..56d287ebf 100644 --- a/src/internet-stack/internet-stack.cc +++ b/src/internet-stack/internet-stack.cc @@ -21,6 +21,7 @@ #include "ns3/net-device.h" #include "ns3/callback.h" #include "ns3/node.h" +#include "ns3/core-config.h" #include "ipv4-l4-demux.h" #include "udp-l4-protocol.h" @@ -31,41 +32,105 @@ #include "tcp-socket-factory-impl.h" #include "ipv4-impl.h" +#ifdef NETWORK_SIMULATION_CRADLE +#include "nsc-tcp-socket-factory-impl.h" +#include "nsc-tcp-l4-protocol.h" +#endif + namespace ns3 { -void +static void +AddArpStack (Ptr node) +{ + Ptr arp = CreateObject (); + arp->SetNode (node); + node->AggregateObject (arp); +} + +static void +AddUdpStack(Ptr node, Ptr ipv4L4Demux) +{ + Ptr udp = CreateObject (); + udp->SetNode (node); + ipv4L4Demux->Insert (udp); + Ptr udpFactory = CreateObject (); + udpFactory->SetUdp (udp); + node->AggregateObject (udpFactory); +} + +static void +AddTcpStack(Ptr node, Ptr ipv4L4Demux) +{ + Ptr tcp = CreateObject (); + tcp->SetNode (node); + ipv4L4Demux->Insert (tcp); + Ptr tcpFactory = CreateObject (); + tcpFactory->SetTcp (tcp); + node->AggregateObject (tcpFactory); +} + +static void +AddIpv4Impl(Ptr node, Ptr ipv4) +{ + Ptr ipv4Impl = CreateObject (); + ipv4Impl->SetIpv4 (ipv4); + node->AggregateObject (ipv4); + node->AggregateObject (ipv4Impl); +} + +void AddInternetStack (Ptr node) { + AddArpStack(node); Ptr ipv4 = CreateObject (); - Ptr arp = CreateObject (); ipv4->SetNode (node); - arp->SetNode (node); Ptr ipv4L4Demux = CreateObject (); - Ptr udp = CreateObject (); - Ptr tcp = CreateObject (); - ipv4L4Demux->SetNode (node); - udp->SetNode (node); - tcp->SetNode (node); - ipv4L4Demux->Insert (udp); - ipv4L4Demux->Insert (tcp); + AddUdpStack (node, ipv4L4Demux); + AddTcpStack (node, ipv4L4Demux); - Ptr udpFactory = CreateObject (); - Ptr tcpFactory = CreateObject (); - Ptr ipv4Impl = CreateObject (); - - udpFactory->SetUdp (udp); - tcpFactory->SetTcp (tcp); - ipv4Impl->SetIpv4 (ipv4); - - node->AggregateObject (ipv4); - node->AggregateObject (arp); - node->AggregateObject (ipv4Impl); - node->AggregateObject (udpFactory); - node->AggregateObject (tcpFactory); + AddIpv4Impl (node, ipv4); node->AggregateObject (ipv4L4Demux); } + +#ifdef NETWORK_SIMULATION_CRADLE +static void +AddNscStack(Ptr node, Ptr ipv4L4Demux, const std::string &soname) +{ + Ptr tcp = CreateObject (); + tcp->SetNscLibrary(soname); + tcp->SetNode (node); + ipv4L4Demux->Insert (tcp); + Ptr tcpFactory = CreateObject (); + tcpFactory->SetTcp (tcp); + node->AggregateObject (tcpFactory); +} + + +void +AddNscInternetStack (Ptr node, const std::string &soname) +{ + AddArpStack(node); + Ptr ipv4 = CreateObject (); + ipv4->SetNode (node); + + Ptr ipv4L4Demux = CreateObject (); + ipv4L4Demux->SetNode (node); + + AddUdpStack (node, ipv4L4Demux); + AddNscStack (node, ipv4L4Demux, soname); + + AddIpv4Impl (node, ipv4); + node->AggregateObject (ipv4L4Demux); +} +#else +void +AddNscInternetStack (Ptr node, const std::string &soname) +{ + NS_ASSERT_MSG(false, "ERROR: ns-3 was compiled without Network Simulation Cradle support"); +} +#endif }//namespace ns3 diff --git a/src/internet-stack/internet-stack.h b/src/internet-stack/internet-stack.h index 9997d862f..41ff375ad 100644 --- a/src/internet-stack/internet-stack.h +++ b/src/internet-stack/internet-stack.h @@ -27,6 +27,7 @@ namespace ns3 { class Node; void AddInternetStack (Ptr node); +void AddNscInternetStack (Ptr node, const std::string &soname); }//namespace ns3 diff --git a/src/internet-stack/ipv4-end-point-demux.cc b/src/internet-stack/ipv4-end-point-demux.cc index 3d3f779be..54ed3fbbe 100644 --- a/src/internet-stack/ipv4-end-point-demux.cc +++ b/src/internet-stack/ipv4-end-point-demux.cc @@ -168,6 +168,24 @@ Ipv4EndPointDemux::DeAllocate (Ipv4EndPoint *endPoint) } } +/* + * return list of all available Endpoints + */ +Ipv4EndPointDemux::EndPoints +Ipv4EndPointDemux::GetAllEndPoints (void) +{ + NS_LOG_FUNCTION_NOARGS (); + EndPoints ret; + + for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++) + { + Ipv4EndPoint* endP = *i; + ret.push_back(endP); + } + return ret; +} + + /* * If we have an exact match, we return it. * Otherwise, if we find a generic match, we return it. diff --git a/src/internet-stack/ipv4-end-point-demux.h b/src/internet-stack/ipv4-end-point-demux.h index 61e580e3c..58a417264 100644 --- a/src/internet-stack/ipv4-end-point-demux.h +++ b/src/internet-stack/ipv4-end-point-demux.h @@ -48,6 +48,7 @@ public: Ipv4EndPointDemux (); ~Ipv4EndPointDemux (); + EndPoints GetAllEndPoints (void); bool LookupPortLocal (uint16_t port); bool LookupLocal (Ipv4Address addr, uint16_t port); EndPoints Lookup (Ipv4Address daddr, diff --git a/src/internet-stack/nsc-sysctl.cc b/src/internet-stack/nsc-sysctl.cc new file mode 100644 index 000000000..32a0cb347 --- /dev/null +++ b/src/internet-stack/nsc-sysctl.cc @@ -0,0 +1,154 @@ +/* -*- 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 + * + * Author: Mathieu Lacage + */ + +#include "ns3/string.h" +#include "nsc-sysctl.h" + +#include "nsc/sim/sim_interface.h" + +namespace ns3 { + +class NscStackStringAccessor : public AttributeAccessor +{ + public: + NscStackStringAccessor (std::string name) : m_name (name) {} + + virtual bool Set (ObjectBase * object, const AttributeValue &val) const; + virtual bool Get (const ObjectBase * object, AttributeValue &val) const; + virtual bool HasGetter (void) const; + virtual bool HasSetter (void) const; + private: + std::string m_name; +}; + +bool NscStackStringAccessor::HasGetter(void) const +{ + return true; +} + +bool NscStackStringAccessor::HasSetter(void) const +{ + return true; +} + + +bool NscStackStringAccessor::Set (ObjectBase * object, const AttributeValue & val) const +{ + const StringValue *value = dynamic_cast (&val); + if (value == 0) + { + return false; + } + Ns3NscStack *obj = dynamic_cast (object); + if (obj == 0) + { + return false; + } + obj->Set (m_name, value->Get ()); + return true; +} + +bool NscStackStringAccessor::Get (const ObjectBase * object, AttributeValue &val) const +{ + StringValue *value = dynamic_cast (&val); + if (value == 0) + { + return false; + } + const Ns3NscStack *obj = dynamic_cast (object); + if (obj == 0) + { + return false; + } + value->Set (obj->Get (m_name)); + return true; +} + + +TypeId +Ns3NscStack::GetInstanceTypeId (void) const +{ + if (m_stack == 0) + { + // if we have no stack, we are a normal NscStack without any attributes. + return GetTypeId (); + } + std::string name = "ns3::Ns3NscStack<"; + name += m_stack->get_name (); + name += ">"; + TypeId tid; + if (TypeId::LookupByNameFailSafe (name, &tid)) + { + // if the relevant TypeId has already been registered, no need to do it again. + return tid; + } + else + { + // Now, we register a new TypeId for this stack which will look + // like a subclass of the Ns3NscStack. The class Ns3NscStack is effectively + // mutating into a subclass of itself from the point of view of the TypeId + // system _here_ + tid = TypeId (name.c_str ()); + tid.SetParent (); + char buf[256]; + for (int i=0; m_stack->sysctl_getnum(i, buf, sizeof(buf)) > 0 ;i++) + { + char value[256]; + if (m_stack->sysctl_get (buf, value, sizeof(value)) > 0) + { + tid.AddAttribute (buf, "Help text", + StringValue (value), + Create (buf), + MakeStringChecker ()); + } + } + return tid; + } +} + +std::string +Ns3NscStack::Get (std::string name) const +{ + char buf[512]; + if (m_stack->sysctl_get (name.c_str (), buf, sizeof(buf)) <= 0) + { // name.c_str () is not a valid sysctl name, or internal NSC error (eg. error converting value) + return NULL; + } + return std::string(buf); +} + +void +Ns3NscStack::Set (std::string name, std::string value) +{ + int ret = m_stack->sysctl_set (name.c_str (), value.c_str ()); + if (ret < 0) + { + NS_FATAL_ERROR ("setting " << name << " to " << value << "failed (retval " << ret << ")"); + } +} + +TypeId +Ns3NscStack::Ns3NscStack::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::Ns3NscStack") + .SetParent () + ; + return tid; +} + +} // namespace ns3 diff --git a/src/internet-stack/nsc-sysctl.h b/src/internet-stack/nsc-sysctl.h new file mode 100644 index 000000000..3c2691967 --- /dev/null +++ b/src/internet-stack/nsc-sysctl.h @@ -0,0 +1,44 @@ +/* -*- 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 + * + * Author: Mathieu Lacage + */ + +#include + +#include "ns3/attribute.h" +#include "ns3/object.h" + +struct INetStack; + +namespace ns3 { + +// This object represents the underlying nsc stack, +// which is aggregated to a Node object, and which provides access to the +// sysctls of the nsc stack through attributes. +class Ns3NscStack : public Object +{ +public: + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + void SetStack (INetStack *stack) {m_stack = stack;} + +private: + friend class NscStackStringAccessor; + void Set (std::string name, std::string value); + std::string Get (std::string name) const; + INetStack *m_stack; +}; +} // namespace ns3 diff --git a/src/internet-stack/nsc-tcp-l4-protocol.cc b/src/internet-stack/nsc-tcp-l4-protocol.cc new file mode 100644 index 000000000..5f713213f --- /dev/null +++ b/src/internet-stack/nsc-tcp-l4-protocol.cc @@ -0,0 +1,368 @@ +/* -*- 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 + * + * based on earlier integration work by Tom Henderson and Sam Jansen. + * 2008 Florian Westphal + */ + +#include "ns3/assert.h" +#include "ns3/log.h" +#include "ns3/nstime.h" + +#include "ns3/packet.h" +#include "ns3/node.h" + +#include "tcp-header.h" +#include "ipv4-end-point-demux.h" +#include "ipv4-end-point.h" +#include "ipv4-l3-protocol.h" +#include "nsc-tcp-l4-protocol.h" +#include "nsc-tcp-socket-impl.h" +#include "nsc-sysctl.h" + +#include "tcp-typedefs.h" + +#include +#include +#include +#include + +#include +#include + +NS_LOG_COMPONENT_DEFINE ("NscTcpL4Protocol"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (NscTcpL4Protocol); + +/* see http://www.iana.org/assignments/protocol-numbers */ +const uint8_t NscTcpL4Protocol::PROT_NUMBER = 6; + +ObjectFactory +NscTcpL4Protocol::GetDefaultRttEstimatorFactory (void) +{ + ObjectFactory factory; + factory.SetTypeId (RttMeanDeviation::GetTypeId ()); + return factory; +} + +TypeId +NscTcpL4Protocol::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::NscTcpL4Protocol") + .SetParent () + + .AddAttribute ("RttEstimatorFactory", + "How RttEstimator objects are created.", + ObjectFactoryValue (GetDefaultRttEstimatorFactory ()), + MakeObjectFactoryAccessor (&NscTcpL4Protocol::m_rttFactory), + MakeObjectFactoryChecker ()) + ; + return tid; +} + +int external_rand() +{ + return 1; // TODO +} + +NscTcpL4Protocol::NscTcpL4Protocol () + : m_endPoints (new Ipv4EndPointDemux ()), + m_nscStack (0), + m_nscInterfacesSetUp(false), + m_softTimer (Timer::CANCEL_ON_DESTROY) +{ + m_dlopenHandle = NULL; + NS_LOG_FUNCTION_NOARGS (); + NS_LOG_LOGIC("Made a NscTcpL4Protocol "< node) +{ + m_node = node; + + if (m_nscStack) + { // stack has already been loaded... + return; + } + + NS_ASSERT(m_dlopenHandle); + + FCreateStack create = (FCreateStack)dlsym(m_dlopenHandle, "nsc_create_stack"); + NS_ASSERT(create); + m_nscStack = create(this, this, external_rand); + int hzval = m_nscStack->get_hz(); + + NS_ASSERT(hzval > 0); + + m_softTimer.SetFunction (&NscTcpL4Protocol::SoftInterrupt, this); + m_softTimer.SetDelay (MilliSeconds (1000/hzval)); + m_nscStack->init(hzval); + // This enables stack and NSC debug messages + // m_nscStack->set_diagnostic(1000); + + Ptr nscStack = Create (); + nscStack->SetStack (m_nscStack); + node->AggregateObject (nscStack); + + m_softTimer.Schedule (); +} + +int +NscTcpL4Protocol::GetProtocolNumber (void) const +{ + return PROT_NUMBER; +} +int +NscTcpL4Protocol::GetVersion (void) const +{ + return 2; +} + +void +NscTcpL4Protocol::DoDispose (void) +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_endPoints != 0) + { + delete m_endPoints; + m_endPoints = 0; + } + m_node = 0; + Ipv4L4Protocol::DoDispose (); +} + +Ptr +NscTcpL4Protocol::CreateSocket (void) +{ + NS_LOG_FUNCTION_NOARGS (); + if (!m_nscInterfacesSetUp) + { + Ptr ip = m_node->GetObject (); + + const uint32_t nInterfaces = ip->GetNInterfaces (); + // start from 1, ignore the loopback interface (HACK) + + NS_ASSERT_MSG (nInterfaces <= 2, "nsc does not support multiple interfaces per node"); + + for (uint32_t i = 1; i < nInterfaces; i++) + { + Ipv4Address addr = ip->GetAddress(i); + Ipv4Mask mask = ip->GetNetworkMask(i); + uint16_t mtu = ip->GetMtu (i); + + std::ostringstream addrOss, maskOss; + + addr.Print(addrOss); + mask.Print(maskOss); + + NS_LOG_LOGIC ("if_attach " << addrOss.str().c_str() << " " << maskOss.str().c_str() << " " << mtu); + + std::string addrStr = addrOss.str(); + std::string maskStr = maskOss.str(); + const char* addrCStr = addrStr.c_str(); + const char* maskCStr = maskStr.c_str(); + m_nscStack->if_attach(addrCStr, maskCStr, mtu); + + if (i == 1) + { + // We need to come up with a default gateway here. Can't guarantee this to be + // correct really... + + uint8_t addrBytes[4]; + addr.Serialize(addrBytes); + + // XXX: this is all a bit of a horrible hack + // + // Just increment the last octet, this gives a decent chance of this being + // 'enough'. + // + // All we need is another address on the same network as the interface. This + // will force the stack to output the packet out of the network interface. + addrBytes[3]++; + addr.Deserialize(addrBytes); + addrOss.str(""); + addr.Print(addrOss); + m_nscStack->add_default_gateway(addrOss.str().c_str()); + } + } + m_nscInterfacesSetUp = true; + } + + Ptr rtt = m_rttFactory.Create (); + Ptr socket = CreateObject (); + socket->SetNode (m_node); + socket->SetTcp (this); + socket->SetRtt (rtt); + return socket; +} + +Ipv4EndPoint * +NscTcpL4Protocol::Allocate (void) +{ + NS_LOG_FUNCTION_NOARGS (); + return m_endPoints->Allocate (); +} + +Ipv4EndPoint * +NscTcpL4Protocol::Allocate (Ipv4Address address) +{ + NS_LOG_FUNCTION (this << address); + return m_endPoints->Allocate (address); +} + +Ipv4EndPoint * +NscTcpL4Protocol::Allocate (uint16_t port) +{ + NS_LOG_FUNCTION (this << port); + return m_endPoints->Allocate (port); +} + +Ipv4EndPoint * +NscTcpL4Protocol::Allocate (Ipv4Address address, uint16_t port) +{ + NS_LOG_FUNCTION (this << address << port); + return m_endPoints->Allocate (address, port); +} + +Ipv4EndPoint * +NscTcpL4Protocol::Allocate (Ipv4Address localAddress, uint16_t localPort, + Ipv4Address peerAddress, uint16_t peerPort) +{ + NS_LOG_FUNCTION (this << localAddress << localPort << peerAddress << peerPort); + return m_endPoints->Allocate (localAddress, localPort, + peerAddress, peerPort); +} + +void +NscTcpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint) +{ + NS_LOG_FUNCTION (this << endPoint); + // NSC m_endPoints->DeAllocate (endPoint); +} + +void +NscTcpL4Protocol::Receive (Ptr packet, + Ipv4Address const &source, + Ipv4Address const &destination, + Ptr incomingInterface) +{ + NS_LOG_FUNCTION (this << packet << source << destination << incomingInterface); + Ipv4Header ipHeader; + uint32_t packetSize = packet->GetSize(); + + // The way things work at the moment, the IP header has been removed + // by the ns-3 IPv4 processing code. However, the NSC stack expects + // a complete IP packet, so we add the IP header back. + // Since the original header is already gone, we create a new one + // based on the information we have. + ipHeader.SetSource (source); + ipHeader.SetDestination (destination); + ipHeader.SetProtocol (PROT_NUMBER); + ipHeader.SetPayloadSize (packetSize); + ipHeader.SetTtl (1); + // all NSC stacks check the IP checksum + ipHeader.EnableChecksum (); + + packet->AddHeader(ipHeader); + packetSize = packet->GetSize(); + + const uint8_t *data = const_cast(packet->PeekData()); + + // deliver complete packet to the NSC network stack + m_nscStack->if_receive_packet(0, data, packetSize); + wakeup (); +} + +void NscTcpL4Protocol::SoftInterrupt (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_nscStack->timer_interrupt (); + m_nscStack->increment_ticks (); + m_softTimer.Schedule (); +} + +void NscTcpL4Protocol::send_callback(const void* data, int datalen) +{ + Ptr p; + + NS_ASSERT(datalen > (int)sizeof(struct iphdr)); + + const uint8_t *rawdata = reinterpret_cast(data); + rawdata += sizeof(struct iphdr); + + const struct iphdr *ipHdr = reinterpret_cast(data); + + // create packet, without IP header. The TCP header is not touched. + // Not using the IP header makes integration easier, but it destroys + // eg. ECN. + p = Create (rawdata, datalen - sizeof(struct iphdr)); + + Ipv4Address saddr(ntohl(ipHdr->saddr)); + Ipv4Address daddr(ntohl(ipHdr->daddr)); + + Ptr ipv4 = m_node->GetObject (); + if (ipv4 != 0) + { + ipv4->Send (p, saddr, daddr, PROT_NUMBER); + } + m_nscStack->if_send_finish(0); +} + +void NscTcpL4Protocol::wakeup() +{ + // TODO + // this should schedule a timer to read from all tcp sockets now... this is + // an indication that data might be waiting on the socket + + Ipv4EndPointDemux::EndPoints endPoints = m_endPoints->GetAllEndPoints (); + for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin (); + endPoint != endPoints.end (); endPoint++) { + // NSC HACK: (ab)use TcpSocket::ForwardUp for signalling + (*endPoint)->ForwardUp (NULL, Ipv4Address(), 0); + } +} + +void NscTcpL4Protocol::gettime(unsigned int* sec, unsigned int* usec) +{ + // Only used by the Linux network stack, e.g. during ISN generation + // and in the kernel rng initialization routine. Also used in Linux + // printk output. + Time t = Simulator::Now (); + int64_t us = t.GetMicroSeconds (); + *sec = us / (1000*1000); + *usec = us - *sec * (1000*1000); +} + + +}; // namespace ns3 + diff --git a/src/internet-stack/nsc-tcp-l4-protocol.h b/src/internet-stack/nsc-tcp-l4-protocol.h new file mode 100644 index 000000000..22e168298 --- /dev/null +++ b/src/internet-stack/nsc-tcp-l4-protocol.h @@ -0,0 +1,121 @@ +/* -*- 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 NSC_TCP_L4_PROTOCOL_H +#define NSC_TCP_L4_PROTOCOL_H + +#include + +#include "ns3/packet.h" +#include "ns3/ipv4-address.h" +#include "ns3/ptr.h" +#include "ns3/object-factory.h" +#include "ipv4-end-point-demux.h" +#include "ipv4-l4-protocol.h" +#include "ipv4-interface.h" + +#include "tcp-header.h" + +#include "ns3/timer.h" +#include "nsc/sim/sim_interface.h" + +namespace ns3 { + +class Node; +class Socket; +class TcpHeader; +/** + * \brief Nsc wrapper glue. + */ +class NscTcpL4Protocol : public Ipv4L4Protocol, ISendCallback, IInterruptCallback { +public: + static const uint8_t PROT_NUMBER; + static TypeId GetTypeId (void); + /** + * \brief Constructor + */ + NscTcpL4Protocol (); + virtual ~NscTcpL4Protocol (); + + void SetNode (Ptr node); + void SetNscLibrary(const std::string &lib); + + virtual int GetProtocolNumber (void) const; + virtual int GetVersion (void) const; + + /** + * \return A smart Socket pointer to a NscTcpSocketImpl, allocated by this instance + * of the TCP protocol + */ + Ptr CreateSocket (void); + + Ipv4EndPoint *Allocate (void); + Ipv4EndPoint *Allocate (Ipv4Address address); + Ipv4EndPoint *Allocate (uint16_t port); + Ipv4EndPoint *Allocate (Ipv4Address address, uint16_t port); + Ipv4EndPoint *Allocate (Ipv4Address localAddress, uint16_t localPort, + Ipv4Address peerAddress, uint16_t peerPort); + + void DeAllocate (Ipv4EndPoint *endPoint); + + /** + * \brief Recieve a packet up the protocol stack + * \param p The Packet to dump the contents into + * \param source The source's Ipv4Address + * \param destination The destinations Ipv4Address + * \param incomingInterface The Ipv4Interface it was received on + */ + virtual void Receive (Ptr p, + Ipv4Address const &source, + Ipv4Address const &destination, + Ptr incomingInterface); + + // NSC callbacks. + // NSC invokes these hooks to interact with the simulator. + // In any case, these methods are only to be called by NSC. + // + // send_callback is invoked by NSCs 'ethernet driver' to re-inject + // a packet (i.e. an octet soup consisting of an IP Header, TCP Header + // and user payload, if any), into ns-3. + virtual void send_callback(const void *data, int datalen); + // This is called by the NSC stack whenever something of interest + // has happened, e.g. when data arrives on a socket, a listen socket + // has a new connection pending, etc. + virtual void wakeup(); + // This is called by the Linux stack RNG initialization. + // Its also used by the cradle code to add a timestamp to + // printk/printf/debug output. + virtual void gettime(unsigned int *, unsigned int *); + +protected: + virtual void DoDispose (void); +private: + Ptr m_node; + Ipv4EndPointDemux *m_endPoints; + ObjectFactory m_rttFactory; +private: + void SoftInterrupt (void); + static ObjectFactory GetDefaultRttEstimatorFactory (void); + friend class NscTcpSocketImpl; + INetStack* m_nscStack; + void *m_dlopenHandle; + bool m_nscInterfacesSetUp; + Timer m_softTimer; +}; + +}; // namespace ns3 + +#endif /* NSC_TCP_L4_PROTOCOL_H */ diff --git a/src/internet-stack/nsc-tcp-socket-factory-impl.cc b/src/internet-stack/nsc-tcp-socket-factory-impl.cc new file mode 100644 index 000000000..60bcbac8d --- /dev/null +++ b/src/internet-stack/nsc-tcp-socket-factory-impl.cc @@ -0,0 +1,50 @@ +/* -*- 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 "nsc-tcp-socket-factory-impl.h" +#include "nsc-tcp-l4-protocol.h" +#include "ns3/socket.h" +#include "ns3/assert.h" + +namespace ns3 { + +NscTcpSocketFactoryImpl::NscTcpSocketFactoryImpl () + : m_tcp (0) +{} +NscTcpSocketFactoryImpl::~NscTcpSocketFactoryImpl () +{ + NS_ASSERT (m_tcp == 0); +} + +void +NscTcpSocketFactoryImpl::SetTcp (Ptr tcp) +{ + m_tcp = tcp; +} + +Ptr +NscTcpSocketFactoryImpl::CreateSocket (void) +{ + return m_tcp->CreateSocket (); +} + +void +NscTcpSocketFactoryImpl::DoDispose (void) +{ + m_tcp = 0; + TcpSocketFactory::DoDispose (); +} + +} // namespace ns3 diff --git a/src/internet-stack/nsc-tcp-socket-factory-impl.h b/src/internet-stack/nsc-tcp-socket-factory-impl.h new file mode 100644 index 000000000..76ad02137 --- /dev/null +++ b/src/internet-stack/nsc-tcp-socket-factory-impl.h @@ -0,0 +1,44 @@ +/* -*- 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 NSC_TCP_SOCKET_FACTORY_IMPL_H +#define NSC_TCP_SOCKET_FACTORY_IMPL_H + +#include "ns3/tcp-socket-factory.h" +#include "ns3/ptr.h" + +namespace ns3 { + +class NscTcpL4Protocol; + +class NscTcpSocketFactoryImpl : public TcpSocketFactory +{ +public: + NscTcpSocketFactoryImpl (); + virtual ~NscTcpSocketFactoryImpl (); + + void SetTcp (Ptr tcp); + + virtual Ptr CreateSocket (void); + +protected: + virtual void DoDispose (void); +private: + Ptr m_tcp; +}; + +} // namespace ns3 + +#endif /* NSC_TCP_SOCKET_FACTORY_IMPL_H */ diff --git a/src/internet-stack/nsc-tcp-socket-impl.cc b/src/internet-stack/nsc-tcp-socket-impl.cc new file mode 100644 index 000000000..14df13916 --- /dev/null +++ b/src/internet-stack/nsc-tcp-socket-impl.cc @@ -0,0 +1,842 @@ +/* -*- 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 + * + * based on tcp-socket-impl.cc, Author: Raj Bhattacharjea + * Author: Florian Westphal + */ + +#include "ns3/node.h" +#include "ns3/inet-socket-address.h" +#include "ns3/log.h" +#include "ns3/ipv4.h" +#include "ipv4-end-point.h" +#include "ipv4-l4-demux.h" +#include "nsc-tcp-l4-protocol.h" +#include "nsc-tcp-socket-impl.h" +#include "ns3/simulation-singleton.h" +#include "tcp-typedefs.h" +#include "ns3/simulator.h" +#include "ns3/packet.h" +#include "ns3/uinteger.h" +#include "ns3/trace-source-accessor.h" + +#include + +#include +#include +#include +#include +#include + +#include "nsc/sim/sim_errno.h" + +NS_LOG_COMPONENT_DEFINE ("NscTcpSocketImpl"); + +using namespace std; + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (NscTcpSocketImpl); + +TypeId +NscTcpSocketImpl::GetTypeId () +{ + static TypeId tid = TypeId("ns3::NscTcpSocketImpl") + .SetParent () + .AddTraceSource ("CongestionWindow", + "The TCP connection's congestion window", + MakeTraceSourceAccessor (&NscTcpSocketImpl::m_cWnd)) + ; + return tid; +} + + NscTcpSocketImpl::NscTcpSocketImpl () + : m_endPoint (0), + m_node (0), + m_tcp (0), + m_peerAddress ("0.0.0.0", 0), + m_errno (ERROR_NOTERROR), + m_shutdownSend (false), + m_shutdownRecv (false), + m_connected (false), + m_state (CLOSED), + m_closeOnEmpty (false), + m_txBufferSize (0), + m_rtt (0), + m_lastMeasuredRtt (Seconds(0.0)) +{ + NS_LOG_FUNCTION (this); +} + +NscTcpSocketImpl::NscTcpSocketImpl(const NscTcpSocketImpl& sock) + : TcpSocket(sock), //copy the base class callbacks + m_delAckMaxCount (sock.m_delAckMaxCount), + m_delAckTimeout (sock.m_delAckTimeout), + m_endPoint (0), + m_node (sock.m_node), + m_tcp (sock.m_tcp), + m_remoteAddress (sock.m_remoteAddress), + m_remotePort (sock.m_remotePort), + m_localAddress (sock.m_localAddress), + m_localPort (sock.m_localPort), + m_peerAddress (sock.m_peerAddress), + m_errno (sock.m_errno), + m_shutdownSend (sock.m_shutdownSend), + m_shutdownRecv (sock.m_shutdownRecv), + m_connected (sock.m_connected), + m_state (sock.m_state), + m_closeOnEmpty (sock.m_closeOnEmpty), + m_segmentSize (sock.m_segmentSize), + m_rxWindowSize (sock.m_rxWindowSize), + m_advertisedWindowSize (sock.m_advertisedWindowSize), + m_cWnd (sock.m_cWnd), + m_ssThresh (sock.m_ssThresh), + m_initialCWnd (sock.m_initialCWnd), + m_rtt (0), + m_lastMeasuredRtt (Seconds(0.0)), + m_cnTimeout (sock.m_cnTimeout), + m_cnCount (sock.m_cnCount), + m_rxAvailable (0), + m_nscTcpSocket (0), + m_sndBufSize (sock.m_sndBufSize) +{ + NS_LOG_FUNCTION_NOARGS (); + NS_LOG_LOGIC("Invoked the copy constructor"); + //copy the pending data if necessary + if(!sock.m_txBuffer.empty () ) + { + m_txBuffer = sock.m_txBuffer; + } + //copy the rtt if necessary + if (sock.m_rtt) + { + m_rtt = sock.m_rtt->Copy(); + } + //can't "copy" the endpoint just yes, must do this when we know the peer info + //too; this is in SYN_ACK_TX +} + +NscTcpSocketImpl::~NscTcpSocketImpl () +{ + NS_LOG_FUNCTION(this); + m_node = 0; + if (m_endPoint != 0) + { + NS_ASSERT (m_tcp != 0); + /** + * Note that this piece of code is a bit tricky: + * when DeAllocate is called, it will call into + * Ipv4EndPointDemux::Deallocate which triggers + * a delete of the associated endPoint which triggers + * in turn a call to the method ::Destroy below + * will will zero the m_endPoint field. + */ + NS_ASSERT (m_endPoint != 0); + m_tcp->DeAllocate (m_endPoint); + NS_ASSERT (m_endPoint == 0); + } + m_tcp = 0; +} + +void +NscTcpSocketImpl::SetNode (Ptr node) +{ + m_node = node; + // Initialize some variables + m_cWnd = m_initialCWnd * m_segmentSize; + m_rxWindowSize = m_advertisedWindowSize; +} + +void +NscTcpSocketImpl::SetTcp (Ptr tcp) +{ + m_nscTcpSocket = tcp->m_nscStack->new_tcp_socket(); + m_tcp = tcp; +} +void +NscTcpSocketImpl::SetRtt (Ptr rtt) +{ + m_rtt = rtt; +} + + +enum Socket::SocketErrno +NscTcpSocketImpl::GetErrno (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_errno; +} + +Ptr +NscTcpSocketImpl::GetNode (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_node; +} + +void +NscTcpSocketImpl::Destroy (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_node = 0; + m_endPoint = 0; + m_tcp = 0; +} +int +NscTcpSocketImpl::FinishBind (void) +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_endPoint == 0) + { + return -1; + } + m_endPoint->SetRxCallback (MakeCallback (&NscTcpSocketImpl::ForwardUp, Ptr(this))); + m_endPoint->SetDestroyCallback (MakeCallback (&NscTcpSocketImpl::Destroy, Ptr(this))); + m_localAddress = m_endPoint->GetLocalAddress (); + m_localPort = m_endPoint->GetLocalPort (); + return 0; +} + +int +NscTcpSocketImpl::Bind (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_endPoint = m_tcp->Allocate (); + return FinishBind (); +} +int +NscTcpSocketImpl::Bind (const Address &address) +{ + NS_LOG_FUNCTION (this<Allocate (); + NS_LOG_LOGIC ("TcpSocketImpl "<Allocate (port); + NS_LOG_LOGIC ("TcpSocketImpl "<Allocate (ipv4); + NS_LOG_LOGIC ("TcpSocketImpl "<Allocate (ipv4, port); + NS_LOG_LOGIC ("TcpSocketImpl "<disconnect(); + m_state = CLOSED; + ShutdownSend (); + return 0; +} + +int +NscTcpSocketImpl::Connect (const Address & address) +{ + NS_LOG_FUNCTION (this << address); + if (m_endPoint == 0) + { + if (Bind () == -1) + { + NS_ASSERT (m_endPoint == 0); + return -1; + } + NS_ASSERT (m_endPoint != 0); + } + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); + m_remoteAddress = transport.GetIpv4 (); + m_remotePort = transport.GetPort (); + + struct in_addr remoteAddr; + uint32_t addr32; + + m_remoteAddress.Serialize((uint8_t*)&addr32); + remoteAddr.s_addr = addr32; + + m_nscTcpSocket->connect(inet_ntoa(remoteAddr), m_remotePort); + m_state = SYN_SENT; + return 0; +} + +int +NscTcpSocketImpl::Send (const Ptr p, uint32_t flags) +{ + NS_LOG_FUNCTION (this << p); + + NS_ASSERT (p->GetSize () > 0); + if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT) + { + if (p->GetSize () > GetTxAvailable ()) + { + m_errno = ERROR_MSGSIZE; + return -1; + } + + bool txEmpty = m_txBuffer.empty(); + if (m_state == ESTABLISHED) + { + if (txEmpty) + { + m_txBuffer.push(p); + m_txBufferSize += p->GetSize (); + } + if (!SendPendingData()) + { + if (m_errno == ERROR_AGAIN) + { + return txEmpty ? p->GetSize () : -1; + } + if (txEmpty) + { + m_txBuffer.pop (); + m_txBufferSize = 0; + } + return -1; + } + } + else + { // SYN_SET -- Queue Data + m_txBuffer.push(p); + m_txBufferSize += p->GetSize (); + } + return p->GetSize (); + } + else + { + m_errno = ERROR_NOTCONN; + return -1; + } +} + +int +NscTcpSocketImpl::SendTo (Ptr p, uint32_t flags, const Address &address) +{ + NS_LOG_FUNCTION (this << address << p); + if (!m_connected) + { + m_errno = ERROR_NOTCONN; + return -1; + } + else + { + return Send (p, flags); //drop the address according to BSD manpages + } +} + +uint32_t +NscTcpSocketImpl::GetTxAvailable (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_txBufferSize != 0) + { + NS_ASSERT (m_txBufferSize <= m_sndBufSize); + return m_sndBufSize - m_txBufferSize; + } + else + { + return m_sndBufSize; + } +} + +int +NscTcpSocketImpl::Listen (uint32_t q) +{ + NS_LOG_FUNCTION (this << q); + m_nscTcpSocket->listen(m_localPort); + m_state = LISTEN; + return 0; +} + + +void +NscTcpSocketImpl::NSCWakeup () +{ + switch (m_state) { + case SYN_SENT: + if (!m_nscTcpSocket->is_connected()) + break; + m_state = ESTABLISHED; + Simulator::ScheduleNow(&NscTcpSocketImpl::ConnectionSucceeded, this); + // fall through to schedule read/write events + case ESTABLISHED: + if (!m_txBuffer.empty ()) + Simulator::ScheduleNow(&NscTcpSocketImpl::SendPendingData, this); + Simulator::ScheduleNow(&NscTcpSocketImpl::ReadPendingData, this); + break; + case LISTEN: + Simulator::ScheduleNow(&NscTcpSocketImpl::Accept, this); + break; + case CLOSED: break; + default: + NS_LOG_DEBUG (this << " invalid state: " << m_state); + } +} + +Ptr +NscTcpSocketImpl::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; +} + +Ptr +NscTcpSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags, + Address &fromAddress) +{ + NS_LOG_FUNCTION (this << maxSize << flags); + Ptr packet = Recv (maxSize, flags); + if (packet != 0) + { + SocketAddressTag tag; + bool found; + found = packet->FindFirstMatchingTag (tag); + NS_ASSERT (found); + fromAddress = tag.GetAddress (); + } + return packet; +} + +uint32_t +NscTcpSocketImpl::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 +NscTcpSocketImpl::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) +{ + NSCWakeup(); +} + +void NscTcpSocketImpl::CompleteFork(void) +{ + // The address pairs (m_localAddress, m_localPort, m_remoteAddress, m_remotePort) + // are bogus, but this isn't important at the moment, because + // address <-> Socket handling is done by NSC internally. + // We only need to add the new ns-3 socket to the list of sockets, so + // we use plain Allocate() instead of Allocate(m_localAddress, ... ) + uint8_t buf[4]; + int port; + size_t buflen = sizeof(buf); + + if (0 == m_nscTcpSocket->getpeername((void *) buf, &buflen, &port)) { + m_remotePort = ntohs(port); + m_remoteAddress = m_remoteAddress.Deserialize(buf); + m_peerAddress = InetSocketAddress(m_remoteAddress, m_remotePort); + } + + m_endPoint = m_tcp->Allocate (); + + //the cloned socket with be in listen state, so manually change state + NS_ASSERT(m_state == LISTEN); + m_state = ESTABLISHED; + + buflen = sizeof(buf); + if (0 == m_nscTcpSocket->getsockname((void *) &buf, &buflen, &port)) + m_localAddress = m_localAddress.Deserialize(buf); + + NS_LOG_LOGIC ("NscTcpSocketImpl " << this << " accepted connection from " + << m_remoteAddress << ":" << m_remotePort + << " to " << m_localAddress << ":" << m_localPort); + //equivalent to FinishBind + m_endPoint->SetRxCallback (MakeCallback (&NscTcpSocketImpl::ForwardUp, Ptr(this))); + m_endPoint->SetDestroyCallback (MakeCallback (&NscTcpSocketImpl::Destroy, Ptr(this))); + + NotifyNewConnectionCreated (this, m_peerAddress); +} + +void NscTcpSocketImpl::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 :( + + uint8_t buf[4]; + int port; + size_t buflen = sizeof(buf); + if (0 == m_nscTcpSocket->getsockname((void *) &buf, &buflen, &port)) { + m_localAddress = m_localAddress.Deserialize(buf); + m_localPort = ntohs(port); + } + + NS_LOG_LOGIC ("NscTcpSocketImpl " << this << " connected to " + << m_remoteAddress << ":" << m_remotePort + << " from " << m_localAddress << ":" << m_localPort); + NotifyConnectionSucceeded(); +} + + +bool NscTcpSocketImpl::Accept (void) +{ + if (m_state == CLOSED) + { // Happens if application closes listening socket after Accept() was scheduled. + return false; + } + NS_ASSERT (m_state == LISTEN); + + if (!m_nscTcpSocket->is_listening()) + { + return false; + } + INetStreamSocket *newsock; + int res = m_nscTcpSocket->accept(&newsock); + if (res != 0) + { + return false; + } +// We could obtain a fromAddress using getpeername, but we've already +// finished the tcp handshake here, i.e. this is a new connection +// and not a connection request. +// if (!NotifyConnectionRequest(fromAddress)) +// return true; + + // Clone the socket + Ptr newSock = Copy (); + newSock->m_nscTcpSocket = newsock; + NS_LOG_LOGIC ("Cloned a NscTcpSocketImpl " << newSock); + + Simulator::ScheduleNow (&NscTcpSocketImpl::CompleteFork, newSock); + return true; +} + +bool NscTcpSocketImpl::ReadPendingData (void) +{ + if (m_state != ESTABLISHED) + { + return false; + } + int len, err; + uint8_t buffer[8192]; + len = sizeof(buffer); + m_errno = ERROR_NOTERROR; + err = m_nscTcpSocket->read_data(buffer, &len); + if (err == 0 && len == 0) + { + NS_LOG_LOGIC ("ReadPendingData got EOF from socket"); + m_state = CLOSED; + return false; + } + m_errno = GetNativeNs3Errno(err); + switch (m_errno) + { + case ERROR_NOTERROR: break; // some data was sent + case ERROR_AGAIN: return false; + default: + NS_LOG_WARN ("Error (" << err << ") " << + "during read_data, ns-3 errno set to" << m_errno); + m_state = CLOSED; + return false; + } + + Ptr p = Create (buffer, len); + + SocketAddressTag tag; + + tag.SetAddress (m_peerAddress); + p->AddTag (tag); + m_deliveryQueue.push (p); + m_rxAvailable += p->GetSize (); + + NotifyDataRecv (); + return true; +} + +bool NscTcpSocketImpl::SendPendingData (void) +{ + NS_LOG_FUNCTION (this); + NS_LOG_LOGIC ("ENTERING SendPendingData"); + + if (m_txBuffer.empty ()) + { + return false; + } + + int ret; + size_t size, written = 0; + + do { + Ptr &p = m_txBuffer.front (); + size = p->GetSize (); + NS_ASSERT (size > 0); + + m_errno = ERROR_NOTERROR; + ret = m_nscTcpSocket->send_data((const char *)p->PeekData (), size); + if (ret <= 0) + { + m_errno = GetNativeNs3Errno(ret); + if (m_errno != ERROR_AGAIN) + { + NS_LOG_WARN ("Error (" << ret << ") " << + "during send_data, ns-3 errno set to" << m_errno); + } + break; + } + written += ret; + + NS_ASSERT (m_txBufferSize >= (size_t)ret); + m_txBufferSize -= ret; + + if ((size_t)ret < size) + { + p->RemoveAtStart(ret); + break; + } + + m_txBuffer.pop (); + + if (m_txBuffer.empty ()) + { + if (m_closeOnEmpty) + { + m_nscTcpSocket->disconnect(); + m_state = CLOSED; + } + break; + } + } while ((size_t) ret == size); + + if (written > 0) + { + Simulator::ScheduleNow(&NscTcpSocketImpl::NotifyDataSent, this, ret); + return true; + } + return false; +} + +Ptr NscTcpSocketImpl::Copy () +{ + return CopyObject (this); +} + +void +NscTcpSocketImpl::SetSndBufSize (uint32_t size) +{ + m_sndBufSize = size; +} + +uint32_t +NscTcpSocketImpl::GetSndBufSize (void) const +{ + return m_sndBufSize; +} + +void +NscTcpSocketImpl::SetRcvBufSize (uint32_t size) +{ + m_rcvBufSize = size; +} + +uint32_t +NscTcpSocketImpl::GetRcvBufSize (void) const +{ + return m_rcvBufSize; +} + +void +NscTcpSocketImpl::SetSegSize (uint32_t size) +{ + m_segmentSize = size; +} + +uint32_t +NscTcpSocketImpl::GetSegSize (void) const +{ + return m_segmentSize; +} + +void +NscTcpSocketImpl::SetAdvWin (uint32_t window) +{ + m_advertisedWindowSize = window; +} + +uint32_t +NscTcpSocketImpl::GetAdvWin (void) const +{ + return m_advertisedWindowSize; +} + +void +NscTcpSocketImpl::SetSSThresh (uint32_t threshold) +{ + m_ssThresh = threshold; +} + +uint32_t +NscTcpSocketImpl::GetSSThresh (void) const +{ + return m_ssThresh; +} + +void +NscTcpSocketImpl::SetInitialCwnd (uint32_t cwnd) +{ + m_initialCWnd = cwnd; +} + +uint32_t +NscTcpSocketImpl::GetInitialCwnd (void) const +{ + return m_initialCWnd; +} + +void +NscTcpSocketImpl::SetConnTimeout (Time timeout) +{ + m_cnTimeout = timeout; +} + +Time +NscTcpSocketImpl::GetConnTimeout (void) const +{ + return m_cnTimeout; +} + +void +NscTcpSocketImpl::SetConnCount (uint32_t count) +{ + m_cnCount = count; +} + +uint32_t +NscTcpSocketImpl::GetConnCount (void) const +{ + return m_cnCount; +} + +void +NscTcpSocketImpl::SetDelAckTimeout (Time timeout) +{ + m_delAckTimeout = timeout; +} + +Time +NscTcpSocketImpl::GetDelAckTimeout (void) const +{ + return m_delAckTimeout; +} + +void +NscTcpSocketImpl::SetDelAckMaxCount (uint32_t count) +{ + m_delAckMaxCount = count; +} + +uint32_t +NscTcpSocketImpl::GetDelAckMaxCount (void) const +{ + return m_delAckMaxCount; +} + +enum Socket::SocketErrno +NscTcpSocketImpl::GetNativeNs3Errno(int error) const +{ + enum nsc_errno err; + + if (error >= 0) + { + return ERROR_NOTERROR; + } + err = (enum nsc_errno) error; + switch (err) + { + case NSC_EADDRINUSE: // fallthrough + case NSC_EADDRNOTAVAIL: return ERROR_AFNOSUPPORT; + case NSC_EINPROGRESS: // Altough nsc sockets are nonblocking, we pretend they're not. + case NSC_EAGAIN: return ERROR_AGAIN; + case NSC_EISCONN: // fallthrough + case NSC_EALREADY: return ERROR_ISCONN; + case NSC_ECONNREFUSED: return ERROR_NOROUTETOHOST; // XXX, better mapping? + case NSC_ECONNRESET: // for no, all of these fall through + case NSC_EHOSTDOWN: + case NSC_ENETUNREACH: + case NSC_EHOSTUNREACH: return ERROR_NOROUTETOHOST; + case NSC_EMSGSIZE: return ERROR_MSGSIZE; + case NSC_ENOTCONN: return ERROR_NOTCONN; + case NSC_ESHUTDOWN: return ERROR_SHUTDOWN; + case NSC_ETIMEDOUT: return ERROR_NOTCONN; // XXX - this mapping isn't correct + case NSC_ENOTDIR: // used by eg. sysctl(2). Shouldn't happen normally, + // but is triggered by e.g. show_config(). + case NSC_EUNKNOWN: return ERROR_INVAL; // Catches stacks that 'return -1' without real mapping + } + NS_ASSERT_MSG(0, "Unknown NSC error"); + return ERROR_INVAL; +} + +}//namespace ns3 diff --git a/src/internet-stack/nsc-tcp-socket-impl.h b/src/internet-stack/nsc-tcp-socket-impl.h new file mode 100644 index 000000000..10a4fce8b --- /dev/null +++ b/src/internet-stack/nsc-tcp-socket-impl.h @@ -0,0 +1,171 @@ +/* -*- 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 NSC_TCP_SOCKET_IMPL_H +#define NSC_TCP_SOCKET_IMPL_H + +#include +#include +#include + +#include "ns3/callback.h" +#include "ns3/traced-value.h" +#include "ns3/tcp-socket.h" +#include "ns3/ptr.h" +#include "ns3/ipv4-address.h" +#include "ns3/inet-socket-address.h" +#include "ns3/event-id.h" +#include "tcp-typedefs.h" +#include "pending-data.h" +#include "sequence-number.h" +#include "rtt-estimator.h" + +#include "nsc/sim/sim_interface.h" + +namespace ns3 { + +class Ipv4EndPoint; +class Node; +class Packet; +class NscTcpL4Protocol; +class TcpHeader; + +class NscTcpSocketImpl : public TcpSocket +{ +public: + static TypeId GetTypeId (void); + /** + * Create an unbound tcp socket. + */ + NscTcpSocketImpl (); + NscTcpSocketImpl (const NscTcpSocketImpl& sock); + virtual ~NscTcpSocketImpl (); + + void SetNode (Ptr node); + void SetTcp (Ptr tcp); + void SetRtt (Ptr rtt); + + virtual enum SocketErrno GetErrno (void) const; + virtual Ptr GetNode (void) const; + virtual int Bind (void); + virtual int Bind (const Address &address); + virtual int Close (void); + virtual int ShutdownSend (void); + virtual int ShutdownRecv (void); + virtual int Connect(const Address &address); + virtual int Listen(uint32_t queueLimit); + virtual uint32_t GetTxAvailable (void) const; + virtual int Send (Ptr p, uint32_t flags); + virtual int SendTo(Ptr p, uint32_t flags, const Address &toAddress); + virtual uint32_t GetRxAvailable (void) const; + virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual Ptr RecvFrom (uint32_t maxSize, uint32_t flags, + Address &fromAddress); + +private: + void NSCWakeup(void); + friend class Tcp; + // invoked by Tcp class + int FinishBind (void); + void ForwardUp (Ptr p, Ipv4Address ipv4, uint16_t port); + void Destroy (void); + //methods for state + bool SendPendingData(void); + bool ReadPendingData(void); + bool Accept(void); + void CompleteFork(void); + void ConnectionSucceeded(); + + // Manage data tx/rx + // XXX This should be virtual and overridden + Ptr Copy (); + + // 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; + + enum Socket::SocketErrno GetNativeNs3Errno(int err) const; + uint32_t m_delAckMaxCount; + Time m_delAckTimeout; + + Ipv4EndPoint *m_endPoint; + Ptr m_node; + Ptr m_tcp; + Ipv4Address m_remoteAddress; + uint16_t m_remotePort; + //these two are so that the socket/endpoint cloning works + Ipv4Address m_localAddress; + uint16_t m_localPort; + InetSocketAddress m_peerAddress; + enum SocketErrno m_errno; + bool m_shutdownSend; + bool m_shutdownRecv; + bool m_connected; + + //manage the state infomation + States_t m_state; + bool m_closeOnEmpty; + + //needed to queue data when in SYN_SENT state + std::queue > m_txBuffer; + uint32_t m_txBufferSize; + + // Window management + uint32_t m_segmentSize; //SegmentSize + uint32_t m_rxWindowSize; + uint32_t m_advertisedWindowSize; //Window to advertise + TracedValue m_cWnd; //Congestion window + uint32_t m_ssThresh; //Slow Start Threshold + uint32_t m_initialCWnd; //Initial cWnd value + + // Round trip time estimation + Ptr m_rtt; + Time m_lastMeasuredRtt; + + // Timer-related members + Time m_cnTimeout; + uint32_t m_cnCount; + + // Temporary queue for delivering data to application + std::queue > m_deliveryQueue; + uint32_t m_rxAvailable; + INetStreamSocket* m_nscTcpSocket; + + // Attributes + uint32_t m_sndBufSize; // buffer limit for the outgoing queue + uint32_t m_rcvBufSize; // maximum receive socket buffer size +}; + +}//namespace ns3 + +#endif /* NSC_TCP_SOCKET_IMPL_H */ diff --git a/src/internet-stack/wscript b/src/internet-stack/wscript index 6f1b7bbd7..1a4c615b0 100644 --- a/src/internet-stack/wscript +++ b/src/internet-stack/wscript @@ -1,4 +1,61 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +import Params +import os + +# Mercurial repository of the network simulation cradle +NETWORK_SIMULATION_CRADLE_REPO = "https://secure.wand.net.nz/mercurial/nsc" +def nsc_fetch(): + def nsc_clone(): + print "Retrieving nsc from " + NETWORK_SIMULATION_CRADLE_REPO + if os.system("hg version > /dev/null 2>&1") != 0: + Params.fatal("Mercurial not installed, http fallback not yet implemented") + if os.system("hg -q clone " + NETWORK_SIMULATION_CRADLE_REPO) != 0: + Params.fatal("hg -q clone %s failed" % NETWORK_SIMULATION_CRADLE_REPO) + + def nsc_update(): + if os.system("hg version > /dev/null 2>&1") != 0: + Params.warning("Mercurial not installed, not updating nsc source") + + print "Pulling nsc updates from " + NETWORK_SIMULATION_CRADLE_REPO + if os.system("cd nsc && hg -q pull %s && hg -q update" % NETWORK_SIMULATION_CRADLE_REPO) != 0: + Params.warning("Updating nsc using mercurial failed") + + if not os.path.exists("nsc"): + nsc_clone() + else: + nsc_update() + +def configure(conf): + # checks for flex and bison, which is needed to build NSCs globaliser + def check_nsc_buildutils(): + import flex + import bison + conf.check_tool('flex bison') + e = conf.create_library_configurator() + e.mandatory = True + e.name = 'fl' + e.run() + + if not Params.g_options.nsc: + return + + check_nsc_buildutils() + + arch = os.uname()[4] + ok = False + if arch == 'x86_64' or arch == 'i686' or arch == 'i586' or arch == 'i486' or arch == 'i386': + conf.env['NSC_ENABLED'] = 'yes' + conf.define('NETWORK_SIMULATION_CRADLE', 1) + conf.write_config_header('ns3/core-config.h') + e = conf.create_library_configurator() + e.mandatory = True + e.name = 'dl' + e.define = 'HAVE_DL' + e.uselib = 'DL' + e.run() + ok = True + conf.check_message('NSC supported architecture', arch, ok) + nsc_fetch() def build(bld): @@ -43,3 +100,9 @@ def build(bld): 'ipv4-l3-protocol.h', 'ipv4-static-routing.h', ] + + if bld.env()['NSC_ENABLED']: + obj.source.append ('nsc-tcp-socket-impl.cc') + obj.source.append ('nsc-tcp-l4-protocol.cc') + obj.source.append ('nsc-tcp-socket-factory-impl.cc') + obj.source.append ('nsc-sysctl.cc') diff --git a/src/wscript b/src/wscript index 96c029ef6..bc8c87689 100644 --- a/src/wscript +++ b/src/wscript @@ -50,6 +50,7 @@ def configure(conf): conf.sub_config('core') conf.sub_config('simulator') conf.sub_config('contrib') + conf.sub_config('internet-stack') blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant())) conf.env.append_value('NS3_MODULE_PATH', blddir) diff --git a/wscript b/wscript index 68e942b18..5f6c0657c 100644 --- a/wscript +++ b/wscript @@ -55,6 +55,8 @@ REGRESSION_SUFFIX = "-ref-traces" # TRACEBALL_SUFFIX = ".tar.bz2" +# directory that contains network simulation cradle source +NSC_DIR = "nsc" def dist_hook(): import tarfile @@ -165,6 +167,10 @@ def set_options(opt): help=('For regression testing, only run/generate the indicated regression tests, ' 'specified as a comma separated list of test names'), dest='regression_tests', type="string") + opt.add_option('--nsc', + help=('Enable Network Simulation Cradle to allow the use real-world network stacks'), + action="store_true", default=False, + dest='nsc') # options provided in a script in a subdirectory named "src" opt.sub_options('src') @@ -193,6 +199,7 @@ def check_compilation_flag(conf, flag): def configure(conf): + conf.env['NS3_BUILDDIR'] = conf.m_blddir conf.check_tool('compiler_cxx') # create the second environment, set the variant and set its name @@ -304,6 +311,28 @@ def _exec_command_interact_win32(s): return stat >> 8 +def nsc_build(bld): + # XXX: Detect gcc major version(s) available to build supported stacks + kernels = [['linux-2.6.18', 'linux2.6.18'], + ['linux-2.6.26', 'linux2.6.26']] + for dir,name in kernels: + soname = 'lib' + name + '.so' + tmp = NSC_DIR + '/' + dir +'/' + soname + if not os.path.exists(tmp): + if os.system('cd ' + NSC_DIR + ' && python scons.py ' + dir) != 0: + Params.fatal("Building NSC stack failed") + builddir = os.path.abspath(os.path.join(bld.env()['NS3_BUILDDIR'], bld.env ().variant())) + if not os.path.exists(builddir + '/nsc'): + try: + os.symlink('../../' + NSC_DIR, builddir + '/nsc') + except: + Params.fatal("Error linkink " + builddir + '/nsc') + if not os.path.exists(builddir + '/' + soname): + try: + os.symlink('../../' + NSC_DIR + '/' + dir + '/' + soname, builddir + '/' + soname) + except: + Params.fatal("Error linking " + builddir + '/' + soname) + def build(bld): if Params.g_options.no_task_lines: import Runner @@ -393,6 +422,9 @@ def build(bld): bld.add_subdirs('bindings/python') + if env['NSC_ENABLED'] == 'yes': + nsc_build(bld) + def get_command_template(): if Params.g_options.valgrind: if Params.g_options.command_template: