bindings: add Python-based UdpEchoServer application to python-unit-tests.py
This commit is contained in:
@@ -39,16 +39,17 @@ class TestSimulator(unittest.TestCase):
|
||||
def testScheduleNow(self):
|
||||
"""! Test schedule now
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
|
||||
def callback(args: ns.cppyy.gbl.std.vector) -> None:
|
||||
"""! Callback function
|
||||
@param args arguments
|
||||
return none
|
||||
@return None
|
||||
"""
|
||||
import copy
|
||||
self._args_received = list(map(lambda x: x.decode("utf-8"), args))
|
||||
self._cb_time = ns.Simulator.Now()
|
||||
|
||||
ns.Simulator.Destroy()
|
||||
self._args_received = None
|
||||
self._cb_time = None
|
||||
@@ -67,15 +68,17 @@ class TestSimulator(unittest.TestCase):
|
||||
def testSchedule(self):
|
||||
"""! Test schedule
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
|
||||
def callback(args: ns.cppyy.gbl.std.vector):
|
||||
"""! Callback function
|
||||
@param args arguments
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
self._args_received = list(map(lambda x: x.decode("utf-8"), args))
|
||||
self._cb_time = ns.Simulator.Now()
|
||||
|
||||
ns.Simulator.Destroy()
|
||||
self._args_received = None
|
||||
self._cb_time = None
|
||||
@@ -94,15 +97,17 @@ class TestSimulator(unittest.TestCase):
|
||||
def testScheduleDestroy(self):
|
||||
"""! Test schedule destroy
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
|
||||
def callback(args: ns.cppyy.gbl.std.vector):
|
||||
"""! Callback function
|
||||
@param args
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
self._args_received = list(map(lambda x: x.decode("utf-8"), args))
|
||||
self._cb_time = ns.Simulator.Now()
|
||||
|
||||
ns.Simulator.Destroy()
|
||||
self._args_received = None
|
||||
self._cb_time = None
|
||||
@@ -124,17 +129,19 @@ class TestSimulator(unittest.TestCase):
|
||||
def testScheduleWithContext(self):
|
||||
"""! Test schedule with context
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
|
||||
def callback(context, args: ns.cppyy.gbl.std.vector):
|
||||
"""! Callback
|
||||
@param context the cntet
|
||||
@param context the context
|
||||
@param args the arguments
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
self._context_received = context
|
||||
self._args_received = list(map(lambda x: x.decode("utf-8"), args))
|
||||
self._cb_time = ns.Simulator.Now()
|
||||
|
||||
ns.Simulator.Destroy()
|
||||
self._args_received = None
|
||||
self._cb_time = None
|
||||
@@ -155,7 +162,7 @@ class TestSimulator(unittest.TestCase):
|
||||
def testTimeComparison(self):
|
||||
"""! Test time comparison
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
self.assertTrue(ns.Seconds(123) == ns.Seconds(123))
|
||||
self.assertTrue(ns.Seconds(123) >= ns.Seconds(123))
|
||||
@@ -166,18 +173,18 @@ class TestSimulator(unittest.TestCase):
|
||||
def testTimeNumericOperations(self):
|
||||
"""! Test numeric operations
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
self.assertEqual(ns.Seconds(10) + ns.Seconds(5), ns.Seconds(15))
|
||||
self.assertEqual(ns.Seconds(10) - ns.Seconds(5), ns.Seconds(5))
|
||||
|
||||
v1 = ns.int64x64_t(5.0)*ns.int64x64_t(10)
|
||||
v1 = ns.int64x64_t(5.0) * ns.int64x64_t(10)
|
||||
self.assertEqual(v1, ns.int64x64_t(50))
|
||||
|
||||
def testConfig(self):
|
||||
"""! Test configuration
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
ns.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.core.UintegerValue(123))
|
||||
# hm.. no Config.Get?
|
||||
@@ -185,7 +192,7 @@ class TestSimulator(unittest.TestCase):
|
||||
def testSocket(self):
|
||||
"""! Test socket
|
||||
@param self
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
nc = ns.NodeContainer(1)
|
||||
node = nc.Get(0)
|
||||
@@ -197,7 +204,7 @@ class TestSimulator(unittest.TestCase):
|
||||
self._received_packet = socket.Recv(maxSize=UINT32_MAX, flags=0)
|
||||
|
||||
ns.cppyy.cppdef("""
|
||||
Callback<void,ns3::Ptr<ns3::Socket> > make_rx_callback(void(*func)(Ptr<Socket>))
|
||||
Callback<void,ns3::Ptr<ns3::Socket> > make_rx_callback_test_socket(void(*func)(Ptr<Socket>))
|
||||
{
|
||||
return MakeCallback(func);
|
||||
}
|
||||
@@ -205,10 +212,11 @@ class TestSimulator(unittest.TestCase):
|
||||
|
||||
sink = ns.network.Socket.CreateSocket(node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
|
||||
sink.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 80).ConvertTo())
|
||||
sink.SetRecvCallback(ns.cppyy.gbl.make_rx_callback(python_rx_callback))
|
||||
sink.SetRecvCallback(ns.cppyy.gbl.make_rx_callback_test_socket(python_rx_callback))
|
||||
|
||||
source = ns.network.Socket.CreateSocket(node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
|
||||
source.SendTo(ns.network.Packet(19), 0, ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80).ConvertTo())
|
||||
source.SendTo(ns.network.Packet(19), 0,
|
||||
ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80).ConvertTo())
|
||||
|
||||
ns.Simulator.Run()
|
||||
self.assertTrue(self._received_packet is not None)
|
||||
@@ -220,16 +228,16 @@ class TestSimulator(unittest.TestCase):
|
||||
def testAttributes(self):
|
||||
"""! Test attributes function
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
# Templated class DropTailQueue<Packet> in C++
|
||||
queue = ns.CreateObject("DropTailQueue<Packet>")
|
||||
queueSizeValue = ns.network.QueueSizeValue (ns.network.QueueSize ("500p"))
|
||||
queueSizeValue = ns.network.QueueSizeValue(ns.network.QueueSize("500p"))
|
||||
queue.SetAttribute("MaxSize", queueSizeValue)
|
||||
|
||||
limit = ns.network.QueueSizeValue()
|
||||
queue.GetAttribute("MaxSize", limit)
|
||||
self.assertEqual(limit.Get(), ns.network.QueueSize ("500p"))
|
||||
self.assertEqual(limit.Get(), ns.network.QueueSize("500p"))
|
||||
|
||||
## -- object pointer values
|
||||
mobility = ns.CreateObject("RandomWaypointMobilityModel")
|
||||
@@ -251,7 +259,7 @@ class TestSimulator(unittest.TestCase):
|
||||
def testIdentity(self):
|
||||
"""! Test identify
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
csma = ns.CreateObject("CsmaNetDevice")
|
||||
channel = ns.CreateObject("CsmaChannel")
|
||||
@@ -268,11 +276,11 @@ class TestSimulator(unittest.TestCase):
|
||||
def testTypeId(self):
|
||||
"""! Test type ID
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
ok, typeId1 = ns.LookupByNameFailSafe("ns3::UdpSocketFactory")
|
||||
self.assertTrue(ok)
|
||||
self.assertEqual(typeId1.GetName (), "ns3::UdpSocketFactory")
|
||||
self.assertEqual(typeId1.GetName(), "ns3::UdpSocketFactory")
|
||||
|
||||
ok, typeId1 = ns.LookupByNameFailSafe("ns3::__InvalidTypeName__")
|
||||
self.assertFalse(ok)
|
||||
@@ -280,14 +288,14 @@ class TestSimulator(unittest.TestCase):
|
||||
def testCommandLine(self):
|
||||
"""! Test command line
|
||||
@param self this object
|
||||
@return none
|
||||
@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
|
||||
BUFFLEN = 40 # noqa
|
||||
test4Buffer = create_string_buffer(b"this is a test option", BUFFLEN)
|
||||
test4 = c_char_p(test4Buffer.raw)
|
||||
|
||||
@@ -314,8 +322,9 @@ class TestSimulator(unittest.TestCase):
|
||||
def testSubclass(self):
|
||||
"""! Test subclass
|
||||
@param self this object
|
||||
@return none
|
||||
@return None
|
||||
"""
|
||||
|
||||
## MyNode class
|
||||
class MyNode(ns.network.Node):
|
||||
def GetLocalTime(self) -> ns.Time:
|
||||
@@ -326,6 +335,156 @@ class TestSimulator(unittest.TestCase):
|
||||
self.assertEqual(forced_local_time, ns.Seconds(10))
|
||||
del node
|
||||
|
||||
def testEchoServerApplication(self):
|
||||
"""! Test python-based application
|
||||
@param self this object
|
||||
@return None
|
||||
"""
|
||||
ns.Simulator.Destroy()
|
||||
|
||||
nodes = ns.network.NodeContainer()
|
||||
nodes.Create(2)
|
||||
|
||||
pointToPoint = ns.point_to_point.PointToPointHelper()
|
||||
pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
|
||||
pointToPoint.SetChannelAttribute("Delay", ns.core.StringValue("2ms"))
|
||||
|
||||
devices = pointToPoint.Install(nodes)
|
||||
|
||||
stack = ns.internet.InternetStackHelper()
|
||||
stack.Install(nodes)
|
||||
|
||||
address = ns.internet.Ipv4AddressHelper()
|
||||
address.SetBase(ns.network.Ipv4Address("10.1.1.0"),
|
||||
ns.network.Ipv4Mask("255.255.255.0"))
|
||||
|
||||
interfaces = address.Assign(devices)
|
||||
|
||||
ns.cppyy.cppdef("""
|
||||
namespace ns3
|
||||
{
|
||||
Callback<void,Ptr<Socket> > make_rx_callback(void(*func)(Ptr<Socket>))
|
||||
{
|
||||
return MakeCallback(func);
|
||||
}
|
||||
EventImpl* pythonMakeEventSend(void (*f)(Ptr<Socket>, Ptr<Packet>, Address&), Ptr<Socket> socket, Ptr<Packet> packet, Address address)
|
||||
{
|
||||
return MakeEvent(f, socket, packet, address);
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
## EchoServer application class
|
||||
class EchoServer(ns.applications.Application):
|
||||
LOGGING = False
|
||||
ECHO_PORT = 1234
|
||||
socketToInstanceDict = {}
|
||||
|
||||
def __init__(self, node: ns.Node, port=ECHO_PORT):
|
||||
"""! Constructor needs to call first the constructor to Application (super class)
|
||||
@param self this object
|
||||
@param node node where this application will be executed
|
||||
@param port port to listen
|
||||
return None
|
||||
"""
|
||||
super().__init__()
|
||||
self.__python_owns__ = False # Let C++ destroy this on Simulator::Destroy
|
||||
## Listen port for the server
|
||||
self.port = port
|
||||
## Socket used by the server to listen to port
|
||||
self.m_socket = ns.network.Socket.CreateSocket(node,
|
||||
ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
|
||||
self.m_socket.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), self.port).ConvertTo())
|
||||
self.m_socket.SetRecvCallback(ns.make_rx_callback(EchoServer._Receive))
|
||||
EchoServer.socketToInstanceDict[self.m_socket] = self
|
||||
|
||||
def __del__(self):
|
||||
"""! Destructor
|
||||
@param self this object
|
||||
return None
|
||||
"""
|
||||
del EchoServer.socketToInstanceDict[self.m_socket]
|
||||
|
||||
def Send(self, packet: ns.Packet, address: ns.Address) -> None:
|
||||
"""! Function to send a packet to an address
|
||||
@param self this object
|
||||
@param packet packet to send
|
||||
@param address destination address
|
||||
return None
|
||||
"""
|
||||
self.m_socket.SendTo(packet, 0, address)
|
||||
if EchoServer.LOGGING:
|
||||
inetAddress = ns.InetSocketAddress.ConvertFrom(address)
|
||||
print("At time +{s}s server sent {b} bytes from {ip} port {port}"
|
||||
.format(s=ns.Simulator.Now().GetSeconds(),
|
||||
b=packet.__deref__().GetSize(),
|
||||
ip=inetAddress.GetIpv4(),
|
||||
port=inetAddress.GetPort()),
|
||||
file=sys.stderr,
|
||||
flush=True)
|
||||
|
||||
def Receive(self):
|
||||
"""! Function to receive a packet from an address
|
||||
@param self this object
|
||||
@return None
|
||||
"""
|
||||
address = ns.Address()
|
||||
packet = self.m_socket.RecvFrom(address)
|
||||
if EchoServer.LOGGING:
|
||||
inetAddress = ns.InetSocketAddress.ConvertFrom(address)
|
||||
print("At time +{s}s server received {b} bytes from {ip} port {port}"
|
||||
.format(s=ns.Simulator.Now().GetSeconds(),
|
||||
b=packet.__deref__().GetSize(),
|
||||
ip=inetAddress.GetIpv4(),
|
||||
port=inetAddress.GetPort()),
|
||||
file=sys.stderr,
|
||||
flush=True)
|
||||
event = ns.pythonMakeEventSend(EchoServer._Send, self.m_socket, packet, address)
|
||||
ns.Simulator.Schedule(ns.Seconds(1), event)
|
||||
|
||||
@staticmethod
|
||||
def _Send(socket: ns.Socket, packet: ns.Packet, address: ns.Address):
|
||||
"""! Static send function, which matches the output socket
|
||||
to the EchoServer instance to call the instance Send function
|
||||
@param socket socket from the instance that should send the packet
|
||||
@param packet packet to send
|
||||
@param address destination address
|
||||
return None
|
||||
"""
|
||||
instance = EchoServer.socketToInstanceDict[socket]
|
||||
instance.Send(packet, address)
|
||||
|
||||
@staticmethod
|
||||
def _Receive(socket: ns.Socket) -> None:
|
||||
"""! Static receive function, which matches the input socket
|
||||
to the EchoServer instance to call the instance Receive function
|
||||
@param socket socket from the instance that should receive the packet
|
||||
return None
|
||||
"""
|
||||
instance = EchoServer.socketToInstanceDict[socket]
|
||||
instance.Receive()
|
||||
|
||||
echoServer = EchoServer(nodes.Get(1))
|
||||
nodes.Get(1).AddApplication(echoServer)
|
||||
|
||||
serverApps = ns.ApplicationContainer()
|
||||
serverApps.Add(echoServer)
|
||||
serverApps.Start(ns.core.Seconds(1.0))
|
||||
serverApps.Stop(ns.core.Seconds(10.0))
|
||||
|
||||
address = interfaces.GetAddress(1).ConvertTo()
|
||||
echoClient = ns.applications.UdpEchoClientHelper(address, EchoServer.ECHO_PORT)
|
||||
echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(10))
|
||||
echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
|
||||
echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(101))
|
||||
|
||||
clientApps = echoClient.Install(nodes.Get(0))
|
||||
clientApps.Start(ns.core.Seconds(2.0))
|
||||
clientApps.Stop(ns.core.Seconds(10.0))
|
||||
|
||||
ns.Simulator.Run()
|
||||
ns.Simulator.Destroy()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(verbosity=1, failfast=True)
|
||||
|
||||
Reference in New Issue
Block a user