bindings, docs: pass strings via char* to CommandLine.AddValue
And supplement memory-management issues section
This commit is contained in:
@@ -319,14 +319,6 @@ def load_modules():
|
||||
setattr(cppyy.gbl.ns3, "addressFromIpv4Address", cppyy.gbl.addressFromIpv4Address)
|
||||
setattr(cppyy.gbl.ns3, "addressFromInetSocketAddress", cppyy.gbl.addressFromInetSocketAddress)
|
||||
setattr(cppyy.gbl.ns3, "addressFromPacketSocketAddress", cppyy.gbl.addressFromPacketSocketAddress)
|
||||
cppyy.cppdef(
|
||||
"""using namespace ns3; CommandLine& getCommandLine(std::string filename){ static CommandLine g_cmd = CommandLine(filename); return g_cmd; };""")
|
||||
setattr(cppyy.gbl.ns3, "getCommandLine", cppyy.gbl.getCommandLine)
|
||||
cppyy.cppdef(
|
||||
"""using namespace ns3; template Callback<bool, std::string> ns3::MakeNullCallback<bool, std::string>(void);""")
|
||||
cppyy.cppdef(
|
||||
"""using namespace ns3; Callback<bool, std::string> null_callback(){ return MakeNullCallback<bool, std::string>(); };""")
|
||||
setattr(cppyy.gbl.ns3, "null_callback", cppyy.gbl.null_callback)
|
||||
|
||||
cppyy.cppdef("""
|
||||
using namespace ns3;
|
||||
|
||||
@@ -159,29 +159,105 @@ For example, when handling command-line arguments, we could set additional param
|
||||
# Import the ns-3 C++ modules with Cppyy
|
||||
from ns import ns
|
||||
|
||||
# ns.cppyy.cppdef compiles the code defined in the block
|
||||
# The defined types, values and functions are available in ns.cppyy.gbl
|
||||
ns.cppyy.cppdef("""
|
||||
using namespace ns3;
|
||||
|
||||
CommandLine& GetCommandLine(std::string filename, int& nCsma, bool& verbose)
|
||||
{
|
||||
static CommandLine cmd = CommandLine(filename);
|
||||
cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", nCsma);
|
||||
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose);
|
||||
return cmd;
|
||||
}
|
||||
""")
|
||||
|
||||
# To pass the addresses of the Python variables to c++, we need to use ctypes
|
||||
from ctypes import c_int, c_bool
|
||||
nCsma = c_int(3)
|
||||
from ctypes import c_bool, c_int, c_double, c_char_p, create_string_buffer
|
||||
verbose = c_bool(True)
|
||||
nCsma = c_int(3)
|
||||
throughputKbps = c_double(3.1415)
|
||||
BUFFLEN = 4096
|
||||
outputFileBuffer = create_string_buffer(b"default_output_file.xml", BUFFLEN)
|
||||
outputFile = c_char_p(outputFileBuffer.raw)
|
||||
|
||||
# Pass the addresses of Python variables to C++
|
||||
cmd = ns.cppyy.gbl.GetCommandLine(__file__, nCsma, verbose)
|
||||
# Cppyy will transform the ctype types into the appropriate reference or raw pointers
|
||||
cmd = ns.CommandLine(__file__)
|
||||
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose)
|
||||
cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", nCsma)
|
||||
cmd.AddValue("throughputKbps", "Throughput of nodes", throughputKbps)
|
||||
cmd.AddValue("outputFile", "Output file name", outputFile, BUFFLEN)
|
||||
cmd.Parse(sys.argv)
|
||||
|
||||
# Printing values of the different ctypes passed as arguments post parsing
|
||||
print("Verbose:", verbose.value)
|
||||
print("nCsma:", nCsma.value)
|
||||
print("throughputKbps:", throughputKbps.value)
|
||||
print("outputFile:", outputFile.value)
|
||||
|
||||
Note that the variables are passed as references or raw pointers. Reassigning them on the Python side
|
||||
(e.g. ``verbose = verbose.value``) can result in the Python garbage collector destroying the object
|
||||
since its only reference has been overwritten, allowing the garbage collector to reclaim that memory space.
|
||||
The C++ side will then have a dangling reference to the variable, which can be overwritten with
|
||||
unexpected values, which can be read later, causing ns-3 to behave erratically due to the memory corruption.
|
||||
|
||||
String values are problematic since Python and C++ string lifetimes are handled differently.
|
||||
To workaround that, we need to use null-terminated C strings (``char*``) to exchange strings between
|
||||
the bindings and ns-3 module libraries. However, C strings are particularly dangerous, since
|
||||
overwriting the null-terminator can also result in memory corruption. When passing a C string, remember
|
||||
to allocate a large buffer and perform bounds checking whenever possible. The CommandLine::AddValue
|
||||
variant for ``char*`` performs bounds checking and aborts the execution in case the parsed value
|
||||
does not fit in the buffer. Make sure to pass the complete size of the buffer, including the null terminator.
|
||||
|
||||
There is an example below demonstrating how the memory corruption could happen in case there was
|
||||
no bounds checking in CommandLine::AddValue variant for ``char*``.
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
from ns import ns
|
||||
from ctypes import c_char_p, c_char, create_string_buffer, byref, cast
|
||||
|
||||
# The following buffer represent the memory contents
|
||||
# of a program containing two adjacent C strings
|
||||
# This could be the result of two subsequent variables
|
||||
# on the stack or dynamically allocated
|
||||
memoryContents = create_string_buffer(b"SHORT_STRING_CONTENTS\0"+b"DoNotWriteHere_"*5+b"\0")
|
||||
lenShortString = len(b"SHORT_STRING_CONTENTS\0")
|
||||
|
||||
# In the next lines, we pick pointers to these two C strings
|
||||
shortStringBuffer = cast(byref(memoryContents, 0), c_char_p)
|
||||
victimBuffer = cast(byref(memoryContents, lenShortString), c_char_p)
|
||||
|
||||
cmd = ns.core.CommandLine(__file__)
|
||||
# in the real implementation, the buffer size of 21+1 bytes containing SHORT_STRING_CONTENTS\0 is passed
|
||||
cmd.AddValue("shortString", "", shortStringBuffer)
|
||||
|
||||
print("Memory contents before the memory corruption")
|
||||
print("Full Memory contents", memoryContents.raw)
|
||||
print("shortStringBuffer contents: ", shortStringBuffer.value)
|
||||
print("victimBuffer contents: ", victimBuffer.value)
|
||||
|
||||
# The following block should print to the terminal.
|
||||
# Note that the strings are correctly
|
||||
# identified due to the null terminator (\x00)
|
||||
#
|
||||
# Memory contents before the memory corruption
|
||||
# Full Memory contents b'SHORT_STRING_CONTENTS\x00DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_\x00\x00'
|
||||
# shortStringBuffer size=21, contents: b'SHORT_STRING_CONTENTS'
|
||||
# victimBuffer size=75, contents: b'DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_'
|
||||
|
||||
# Write a very long string to a small buffer of size lenShortString = 22
|
||||
cmd.Parse(["python", "--shortString="+("OkToWrite"*lenShortString)[:lenShortString]+"CORRUPTED_"*3])
|
||||
|
||||
print("\n\nMemory contents after the memory corruption")
|
||||
print("Full Memory contents", memoryContents.raw)
|
||||
print("shortStringBuffer contents: ", shortStringBuffer.value)
|
||||
print("victimBuffer contents: ", victimBuffer.value)
|
||||
|
||||
# The following block should print to the terminal.
|
||||
#
|
||||
# Memory contents after the memory corruption
|
||||
# Full Memory contents b'OkToWriteOkToWriteOkToCORRUPTED_CORRUPTED_CORRUPTED_\x00oNotWriteHere_DoNotWriteHere_DoNotWriteHere_\x00\x00'
|
||||
# shortStringBuffer size=52, contents: b'OkToWriteOkToWriteOkToCORRUPTED_CORRUPTED_CORRUPTED_'
|
||||
# victimBuffer size=30, contents: b'CORRUPTED_CORRUPTED_CORRUPTED_'
|
||||
#
|
||||
# Note that shortStringBuffer invaded the victimBuffer since the
|
||||
# string being written was bigger than the shortStringBuffer.
|
||||
#
|
||||
# Since no bounds checks were performed, the adjacent memory got
|
||||
# overwritten and both buffers are now corrupted.
|
||||
#
|
||||
# We also have a memory leak of the final block in the memory
|
||||
# 'oNotWriteHere_DoNotWriteHere_DoNotWriteHere_\x00\x00', caused
|
||||
# by the null terminator written at the middle of the victimBuffer.
|
||||
|
||||
If you find a segmentation violation, be sure to wait for the stacktrace provided by Cppyy
|
||||
and try to find the root cause of the issue. If you have multiple cores, the number of
|
||||
stacktraces will correspond to the number of threads being executed by Cppyy. To limit them,
|
||||
|
||||
@@ -26,37 +26,26 @@ import sys
|
||||
# // point-to-point | | | |
|
||||
# // ================
|
||||
# // LAN 10.1.2.0
|
||||
ns.cppyy.cppdef("""
|
||||
using namespace ns3;
|
||||
|
||||
CommandLine& GetCommandLine(std::string filename, int& nCsma, bool& verbose)
|
||||
{
|
||||
static CommandLine cmd = CommandLine(filename);
|
||||
cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", nCsma);
|
||||
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose);
|
||||
return cmd;
|
||||
}
|
||||
""")
|
||||
from ctypes import c_int, c_bool
|
||||
nCsma = c_int(3)
|
||||
verbose = c_bool(True)
|
||||
cmd = ns.cppyy.gbl.GetCommandLine(__file__, nCsma, verbose)
|
||||
cmd = ns.CommandLine(__file__)
|
||||
cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", nCsma)
|
||||
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose)
|
||||
cmd.Parse(sys.argv)
|
||||
|
||||
nCsma = nCsma.value
|
||||
verbose = verbose.value
|
||||
|
||||
if verbose == "True":
|
||||
if verbose.value:
|
||||
ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
|
||||
ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)
|
||||
nCsma = 1 if nCsma == 0 else nCsma
|
||||
nCsma.value = 1 if nCsma.value == 0 else nCsma.value
|
||||
|
||||
p2pNodes = ns.network.NodeContainer()
|
||||
p2pNodes.Create(2)
|
||||
|
||||
csmaNodes = ns.network.NodeContainer()
|
||||
csmaNodes.Add(p2pNodes.Get(1))
|
||||
csmaNodes.Create(nCsma)
|
||||
csmaNodes.Create(nCsma.value)
|
||||
|
||||
pointToPoint = ns.point_to_point.PointToPointHelper()
|
||||
pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
|
||||
@@ -83,11 +72,11 @@ csmaInterfaces = address.Assign(csmaDevices)
|
||||
|
||||
echoServer = ns.applications.UdpEchoServerHelper(9)
|
||||
|
||||
serverApps = echoServer.Install(csmaNodes.Get(nCsma))
|
||||
serverApps = echoServer.Install(csmaNodes.Get(nCsma.value))
|
||||
serverApps.Start(ns.core.Seconds(1.0))
|
||||
serverApps.Stop(ns.core.Seconds(10.0))
|
||||
|
||||
echoClient = ns.applications.UdpEchoClientHelper(ns.addressFromIpv4Address(csmaInterfaces.GetAddress(nCsma)), 9)
|
||||
echoClient = ns.applications.UdpEchoClientHelper(ns.addressFromIpv4Address(csmaInterfaces.GetAddress(nCsma.value)), 9)
|
||||
echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1))
|
||||
echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds (1.0)))
|
||||
echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))
|
||||
|
||||
@@ -30,30 +30,28 @@ import sys
|
||||
# // ================
|
||||
# // LAN 10.1.2.0
|
||||
|
||||
cmd = ns.getCommandLine(__file__)
|
||||
nCsma ="3"
|
||||
verbose = "True"
|
||||
nWifi = "3"
|
||||
tracing = "False"
|
||||
from ctypes import c_bool, c_int
|
||||
nCsma = c_int(3)
|
||||
verbose = c_bool(True)
|
||||
nWifi = c_int(3)
|
||||
tracing = c_bool(False)
|
||||
|
||||
cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", ns.null_callback(), nCsma)
|
||||
cmd.AddValue("nWifi", "Number of wifi STA devices", ns.null_callback(), nWifi)
|
||||
cmd.AddValue("verbose", "Tell echo applications to log if true", ns.null_callback(), verbose)
|
||||
cmd.AddValue("tracing", "Enable pcap tracing", ns.null_callback(), tracing)
|
||||
cmd = ns.CommandLine(__file__)
|
||||
cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", nCsma)
|
||||
cmd.AddValue("nWifi", "Number of wifi STA devices", nWifi)
|
||||
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose)
|
||||
cmd.AddValue("tracing", "Enable pcap tracing", tracing)
|
||||
|
||||
cmd.Parse(sys.argv)
|
||||
|
||||
nCsma = int(nCsma)
|
||||
nWifi = int(nWifi)
|
||||
|
||||
# The underlying restriction of 18 is due to the grid position
|
||||
# allocator's configuration; the grid layout will exceed the
|
||||
# bounding box if more than 18 nodes are provided.
|
||||
if nWifi > 18:
|
||||
if nWifi.value > 18:
|
||||
print("nWifi should be 18 or less; otherwise grid layout exceeds the bounding box")
|
||||
sys.exit(1)
|
||||
|
||||
if verbose == "True":
|
||||
if verbose.value:
|
||||
ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
|
||||
ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)
|
||||
|
||||
@@ -68,7 +66,7 @@ p2pDevices = pointToPoint.Install(p2pNodes)
|
||||
|
||||
csmaNodes = ns.network.NodeContainer()
|
||||
csmaNodes.Add(p2pNodes.Get(1))
|
||||
csmaNodes.Create(nCsma)
|
||||
csmaNodes.Create(nCsma.value)
|
||||
|
||||
csma = ns.csma.CsmaHelper()
|
||||
csma.SetChannelAttribute("DataRate", ns.core.StringValue("100Mbps"))
|
||||
@@ -77,7 +75,7 @@ csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.NanoSeconds(6560)))
|
||||
csmaDevices = csma.Install(csmaNodes)
|
||||
|
||||
wifiStaNodes = ns.network.NodeContainer()
|
||||
wifiStaNodes.Create(nWifi)
|
||||
wifiStaNodes.Create(nWifi.value)
|
||||
wifiApNode = p2pNodes.Get(0)
|
||||
|
||||
channel = ns.wifi.YansWifiChannelHelper.Default()
|
||||
@@ -124,16 +122,16 @@ address.Assign(apDevices)
|
||||
|
||||
echoServer = ns.applications.UdpEchoServerHelper(9)
|
||||
|
||||
serverApps = echoServer.Install(csmaNodes.Get(nCsma))
|
||||
serverApps = echoServer.Install(csmaNodes.Get(nCsma.value))
|
||||
serverApps.Start(ns.core.Seconds(1.0))
|
||||
serverApps.Stop(ns.core.Seconds(10.0))
|
||||
|
||||
echoClient = ns.applications.UdpEchoClientHelper(ns.addressFromIpv4Address(csmaInterfaces.GetAddress(nCsma)), 9)
|
||||
echoClient = ns.applications.UdpEchoClientHelper(ns.addressFromIpv4Address(csmaInterfaces.GetAddress(nCsma.value)), 9)
|
||||
echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1))
|
||||
echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds (1.0)))
|
||||
echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))
|
||||
|
||||
clientApps = echoClient.Install(wifiStaNodes.Get (nWifi - 1))
|
||||
clientApps = echoClient.Install(wifiStaNodes.Get (nWifi.value - 1))
|
||||
clientApps.Start(ns.core.Seconds(2.0))
|
||||
clientApps.Stop(ns.core.Seconds(10.0))
|
||||
|
||||
@@ -141,7 +139,7 @@ ns.internet.Ipv4GlobalRoutingHelper.PopulateRoutingTables()
|
||||
|
||||
ns.core.Simulator.Stop(ns.core.Seconds(10.0))
|
||||
|
||||
if tracing == "True":
|
||||
if tracing.value:
|
||||
phy.SetPcapDataLinkType(phy.DLT_IEEE802_11_RADIO)
|
||||
pointToPoint.EnablePcapAll ("third")
|
||||
phy.EnablePcap ("third", apDevices.Get (0))
|
||||
|
||||
@@ -68,12 +68,12 @@ def main(argv):
|
||||
# First, we initialize a few local variables that control some
|
||||
# simulation parameters.
|
||||
#
|
||||
|
||||
cmd = ns.getCommandLine(__file__)
|
||||
cmd.backboneNodes = "10"
|
||||
cmd.infraNodes = "2"
|
||||
cmd.lanNodes = "2"
|
||||
cmd.stopTime = "20"
|
||||
from ctypes import c_int, c_double
|
||||
backboneNodes = c_int(10)
|
||||
infraNodes = c_int(2)
|
||||
lanNodes = c_int(2)
|
||||
stopTime = c_double(20)
|
||||
cmd = ns.CommandLine(__file__)
|
||||
|
||||
#
|
||||
# Simulation defaults are typically set next, before command line
|
||||
@@ -88,10 +88,10 @@ def main(argv):
|
||||
# "--backboneNodes=20"
|
||||
#
|
||||
|
||||
cmd.AddValue("backboneNodes", "number of backbone nodes", ns.null_callback(), cmd.backboneNodes)
|
||||
cmd.AddValue("infraNodes", "number of leaf nodes", ns.null_callback(), cmd.infraNodes)
|
||||
cmd.AddValue("lanNodes", "number of LAN nodes", ns.null_callback(), cmd.lanNodes)
|
||||
cmd.AddValue("stopTime", "simulation stop time(seconds)", ns.null_callback(), cmd.stopTime)
|
||||
cmd.AddValue("backboneNodes", "number of backbone nodes", backboneNodes)
|
||||
cmd.AddValue("infraNodes", "number of leaf nodes", infraNodes)
|
||||
cmd.AddValue("lanNodes", "number of LAN nodes", lanNodes)
|
||||
cmd.AddValue("stopTime", "simulation stop time(seconds)", stopTime)
|
||||
|
||||
#
|
||||
# The system global variables and the local values added to the argument
|
||||
@@ -99,12 +99,7 @@ def main(argv):
|
||||
#
|
||||
cmd.Parse(argv)
|
||||
|
||||
backboneNodes = int(cmd.backboneNodes)
|
||||
infraNodes = int(cmd.infraNodes)
|
||||
lanNodes = int(cmd.lanNodes)
|
||||
stopTime = int(cmd.stopTime)
|
||||
|
||||
if (stopTime < 10):
|
||||
if (stopTime.value < 10):
|
||||
print ("Use a simulation stop time >= 10 seconds")
|
||||
exit(1)
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # /
|
||||
@@ -118,7 +113,7 @@ def main(argv):
|
||||
# Later we'll create the rest of the nodes we'll need.
|
||||
#
|
||||
backbone = ns.network.NodeContainer()
|
||||
backbone.Create(backboneNodes)
|
||||
backbone.Create(backboneNodes.value)
|
||||
#
|
||||
# Create the backbone wifi net devices and install them into the nodes in
|
||||
# our container
|
||||
@@ -179,7 +174,7 @@ def main(argv):
|
||||
# the "172.16 address space
|
||||
ipAddrs.SetBase(ns.network.Ipv4Address("172.16.0.0"), ns.network.Ipv4Mask("255.255.255.0"))
|
||||
|
||||
for i in range(backboneNodes):
|
||||
for i in range(backboneNodes.value):
|
||||
print ("Configuring local area network for backbone node ", i)
|
||||
#
|
||||
# Create a container to manage the nodes of the LAN. We need
|
||||
@@ -187,7 +182,7 @@ def main(argv):
|
||||
# with all of the nodes including new and existing nodes
|
||||
#
|
||||
newLanNodes = ns.network.NodeContainer()
|
||||
newLanNodes.Create(lanNodes - 1)
|
||||
newLanNodes.Create(lanNodes.value - 1)
|
||||
# Now, create the container with all nodes on this link
|
||||
lan = ns.network.NodeContainer(ns.network.NodeContainer(backbone.Get(i)), newLanNodes)
|
||||
#
|
||||
@@ -236,7 +231,7 @@ def main(argv):
|
||||
# the "10.0" address space
|
||||
ipAddrs.SetBase(ns.network.Ipv4Address("10.0.0.0"), ns.network.Ipv4Mask("255.255.255.0"))
|
||||
tempRef = [] # list of references to be held to prevent garbage collection
|
||||
for i in range(backboneNodes):
|
||||
for i in range(backboneNodes.value):
|
||||
print ("Configuring wireless network for backbone node ", i)
|
||||
#
|
||||
# Create a container to manage the nodes of the LAN. We need
|
||||
@@ -244,7 +239,7 @@ def main(argv):
|
||||
# with all of the nodes including new and existing nodes
|
||||
#
|
||||
stas = ns.network.NodeContainer()
|
||||
stas.Create(infraNodes - 1)
|
||||
stas.Create(infraNodes.value - 1)
|
||||
# Now, create the container with all nodes on this link
|
||||
infra = ns.network.NodeContainer(ns.network.NodeContainer(backbone.Get(i)), stas)
|
||||
#
|
||||
@@ -313,8 +308,8 @@ def main(argv):
|
||||
print ("Create Applications.")
|
||||
port = 9 # Discard port(RFC 863)
|
||||
|
||||
appSource = ns.network.NodeList.GetNode(backboneNodes)
|
||||
lastNodeIndex = backboneNodes + backboneNodes*(lanNodes - 1) + backboneNodes*(infraNodes - 1) - 1
|
||||
appSource = ns.network.NodeList.GetNode(backboneNodes.value)
|
||||
lastNodeIndex = backboneNodes.value + backboneNodes.value*(lanNodes.value - 1) + backboneNodes.value*(infraNodes.value - 1) - 1
|
||||
appSink = ns.network.NodeList.GetNode(lastNodeIndex)
|
||||
|
||||
ns.cppyy.cppdef("""
|
||||
@@ -329,7 +324,7 @@ def main(argv):
|
||||
onoff = ns.applications.OnOffHelper("ns3::UdpSocketFactory", genericAddress)
|
||||
apps = onoff.Install(ns.network.NodeContainer(appSource))
|
||||
apps.Start(ns.core.Seconds(3))
|
||||
apps.Stop(ns.core.Seconds(stopTime - 1))
|
||||
apps.Stop(ns.core.Seconds(stopTime.value - 1))
|
||||
|
||||
# Create a packet sink to receive these packets
|
||||
sink = ns.applications.PacketSinkHelper("ns3::UdpSocketFactory",
|
||||
@@ -374,7 +369,7 @@ def main(argv):
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
print ("Run Simulation.")
|
||||
ns.core.Simulator.Stop(ns.core.Seconds(stopTime))
|
||||
ns.core.Simulator.Stop(ns.core.Seconds(stopTime.value))
|
||||
ns.core.Simulator.Run()
|
||||
ns.core.Simulator.Destroy()
|
||||
|
||||
|
||||
@@ -103,9 +103,9 @@ ns.cppyy.cppdef("""
|
||||
""")
|
||||
|
||||
|
||||
def main(dummy_argv):
|
||||
cmd = ns.getCommandLine(__file__)
|
||||
cmd.Parse(dummy_argv)
|
||||
def main(argv):
|
||||
cmd = ns.CommandLine(__file__)
|
||||
cmd.Parse(argv)
|
||||
|
||||
model = ns.cppyy.gbl.MyModel()
|
||||
v = ns.CreateObject("UniformRandomVariable")
|
||||
|
||||
@@ -24,30 +24,21 @@ from ns import ns
|
||||
DISTANCE = 20 # (m)
|
||||
NUM_NODES_SIDE = 3
|
||||
|
||||
ns.cppyy.cppdef("""
|
||||
using namespace ns3;
|
||||
|
||||
CommandLine& GetCommandLine(std::string filename, int& NumNodesSide, bool& Plot, std::string Results)
|
||||
{
|
||||
static CommandLine cmd = CommandLine(filename);
|
||||
cmd.AddValue("NumNodesSide", "Grid side number of nodes (total number of nodes will be this number squared)", NumNodesSide);
|
||||
cmd.AddValue("Results", "Write XML results to file", Results);
|
||||
cmd.AddValue("Plot", "Plot the results using the matplotlib python module", Plot);
|
||||
return cmd;
|
||||
}
|
||||
""")
|
||||
|
||||
def main(argv):
|
||||
|
||||
from ctypes import c_int, c_bool
|
||||
from ctypes import c_int, c_bool, c_char_p, create_string_buffer
|
||||
NumNodesSide = c_int(2)
|
||||
Plot = c_bool(False)
|
||||
Results = "output.xml"
|
||||
cmd = ns.cppyy.gbl.GetCommandLine(__file__, NumNodesSide, Plot, Results)
|
||||
cmd.Parse(argv)
|
||||
BUFFLEN = 4096
|
||||
ResultsBuffer = create_string_buffer(b"output.xml", BUFFLEN)
|
||||
Results = c_char_p(ResultsBuffer.raw)
|
||||
|
||||
Plot = Plot.value
|
||||
NumNodesSide = NumNodesSide.value
|
||||
cmd = ns.CommandLine(__file__)
|
||||
cmd.AddValue("NumNodesSide", "Grid side number of nodes (total number of nodes will be this number squared)", NumNodesSide)
|
||||
cmd.AddValue("Results", "Write XML results to file", Results, BUFFLEN)
|
||||
cmd.AddValue("Plot", "Plot the results using the matplotlib python module", Plot)
|
||||
cmd.Parse(argv)
|
||||
|
||||
wifi = ns.CreateObject("WifiHelper")
|
||||
wifiMac = ns.CreateObject("WifiMacHelper")
|
||||
@@ -80,10 +71,10 @@ def main(argv):
|
||||
addresses = []
|
||||
nodes = []
|
||||
|
||||
if NumNodesSide is None:
|
||||
if NumNodesSide.value == 2:
|
||||
num_nodes_side = NUM_NODES_SIDE
|
||||
else:
|
||||
num_nodes_side = NumNodesSide
|
||||
num_nodes_side = NumNodesSide.value
|
||||
|
||||
nodes = ns.NodeContainer(num_nodes_side*num_nodes_side)
|
||||
accumulator = 0
|
||||
@@ -159,7 +150,7 @@ def main(argv):
|
||||
monitor.CheckForLostPackets()
|
||||
classifier = flowmon_helper.GetClassifier()
|
||||
|
||||
if Results is None:
|
||||
if Results.value != b"output.xml":
|
||||
for flow_id, flow_stats in monitor.GetFlowStats():
|
||||
t = classifier.FindFlow(flow_id)
|
||||
proto = {6: 'TCP', 17: 'UDP'} [t.protocol]
|
||||
@@ -167,10 +158,11 @@ def main(argv):
|
||||
(flow_id, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort))
|
||||
print_stats(sys.stdout, flow_stats)
|
||||
else:
|
||||
print (monitor.SerializeToXmlFile(Results, True, True))
|
||||
res = monitor.SerializeToXmlFile(Results.value.decode("utf-8"), True, True)
|
||||
print (res)
|
||||
|
||||
|
||||
if Plot:
|
||||
if Plot.value:
|
||||
import pylab
|
||||
delays = []
|
||||
for flow_id, flow_stats in monitor.GetFlowStats():
|
||||
|
||||
@@ -277,30 +277,39 @@ class TestSimulator(unittest.TestCase):
|
||||
ok, typeId1 = ns.LookupByNameFailSafe("ns3::__InvalidTypeName__")
|
||||
self.assertFalse(ok)
|
||||
|
||||
# def testCommandLine(self):
|
||||
# """! Test command line
|
||||
# @param self this object
|
||||
# @return none
|
||||
# """
|
||||
# cmd = ns.core.CommandLine(__file__)
|
||||
# cmd.AddValue("Test1", "this is a test option")
|
||||
# cmd.AddValue("Test2", "this is a test option")
|
||||
# cmd.AddValue("Test3", "this is a test option", variable="test_xxx")
|
||||
# cmd.Test1 = None
|
||||
# cmd.Test2 = None
|
||||
# cmd.test_xxx = None
|
||||
# class Foo:
|
||||
# pass
|
||||
# foo = Foo()
|
||||
# foo.test_foo = None
|
||||
# cmd.AddValue("Test4", "this is a test option", variable="test_foo", namespace=foo)
|
||||
#
|
||||
# cmd.Parse(["python", "--Test1=value1", "--Test2=value2", "--Test3=123", "--Test4=xpto"])
|
||||
#
|
||||
# self.assertEqual(cmd.Test1, "value1")
|
||||
# self.assertEqual(cmd.Test2, "value2")
|
||||
# self.assertEqual(cmd.test_xxx, "123")
|
||||
# self.assertEqual(foo.test_foo, "xpto")
|
||||
def testCommandLine(self):
|
||||
"""! Test command line
|
||||
@param self this object
|
||||
@return none
|
||||
"""
|
||||
from ctypes import c_bool, c_int, c_double, c_char_p, create_string_buffer
|
||||
|
||||
test1 = c_bool(True)
|
||||
test2 = c_int(42)
|
||||
test3 = c_double(3.1415)
|
||||
BUFFLEN = 40
|
||||
test4Buffer = create_string_buffer(b"this is a test option", BUFFLEN)
|
||||
test4 = c_char_p(test4Buffer.raw)
|
||||
|
||||
cmd = ns.core.CommandLine(__file__)
|
||||
cmd.AddValue("Test1", "this is a test option", test1)
|
||||
cmd.AddValue("Test2", "this is a test option", test2)
|
||||
cmd.AddValue("Test3", "this is a test option", test3)
|
||||
cmd.AddValue("Test4", "this is a test option", test4, BUFFLEN)
|
||||
|
||||
cmd.Parse(["python"])
|
||||
self.assertEqual(test1.value, True)
|
||||
self.assertEqual(test2.value, 42)
|
||||
self.assertEqual(test3.value, 3.1415)
|
||||
self.assertEqual(test4.value, b"this is a test option")
|
||||
|
||||
cmd.Parse(["python", "--Test1=false", "--Test2=0", "--Test3=0.0"])
|
||||
self.assertEqual(test1.value, False)
|
||||
self.assertEqual(test2.value, 0)
|
||||
self.assertEqual(test3.value, 0.0)
|
||||
|
||||
cmd.Parse(["python", "--Test4=new_string"])
|
||||
self.assertEqual(test4.value, b"new_string")
|
||||
|
||||
def testSubclass(self):
|
||||
"""! Test subclass
|
||||
|
||||
Reference in New Issue
Block a user