262 lines
9.1 KiB
C#
262 lines
9.1 KiB
C#
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// Note: Simple Singularity test program.
|
|
//
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Net.IP;
|
|
using System.Threading;
|
|
|
|
using Microsoft.Singularity;
|
|
using Microsoft.SingSharp;
|
|
using Microsoft.Singularity.Channels;
|
|
using Microsoft.Singularity.Directory;
|
|
using NetStack.Contracts;
|
|
using NetStack.Channels.Public;
|
|
|
|
using Microsoft.Contracts;
|
|
using Microsoft.SingSharp.Reflection;
|
|
using Microsoft.Singularity.Applications;
|
|
using Microsoft.Singularity.Io;
|
|
using Microsoft.Singularity.Configuration;
|
|
[assembly: Transform(typeof(ApplicationResourceTransform))]
|
|
|
|
namespace Microsoft.Singularity.Applications.Network
|
|
{
|
|
[ConsoleCategory(HelpMessage="Send UDP data to and ipAddress and port",
|
|
DefaultAction=true)]
|
|
internal class Parameters {
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[Endpoint]
|
|
public readonly TRef<UdpContract.Imp:Start> udpRef;
|
|
|
|
[LongParameter("p", Mandatory=false, HelpMessage="Packet size (bytes)", Default = 1500)]
|
|
internal long packetBytes;
|
|
|
|
[LongParameter("r", Mandatory=false, HelpMessage="Transmission rate in bits per second", Default = 64000)]
|
|
internal long bitsPerSecond;
|
|
|
|
[LongParameter("t", Mandatory=false, HelpMessage="Seconds to send packets for", Default = 30)]
|
|
internal long seconds;
|
|
|
|
[BoolParameter("v", Mandatory=false, HelpMessage="Verbose output", Default = true)]
|
|
internal bool verbose;
|
|
|
|
[StringParameter("Address", Mandatory=true, Position=0, HelpMessage="Destination IP Address")]
|
|
internal string address;
|
|
|
|
[LongParameter("port", Mandatory=true, Position=1, HelpMessage="Destination UDP port")]
|
|
internal long port;
|
|
|
|
reflective internal Parameters();
|
|
|
|
internal int AppMain() {
|
|
return UdpBlast.AppMain(this);
|
|
}
|
|
}
|
|
|
|
public class UdpBlast
|
|
{
|
|
private const uint FixedHeaderBytes = 42; // Ether + IP + UDP
|
|
|
|
private static bool verbose;
|
|
|
|
public static void VerboseWriteLine(string format,
|
|
params Object [] args)
|
|
{
|
|
string msg = String.Format(format, args);
|
|
DebugStub.WriteLine(msg);
|
|
if (verbose) {
|
|
Console.WriteLine(format, args);
|
|
}
|
|
}
|
|
|
|
private static void
|
|
SendPackets(
|
|
UdpConnectionContract.Imp:ReadyState! udpConn,
|
|
long bitsPerSecond,
|
|
uint bytesPerPacket,
|
|
long durationSeconds
|
|
)
|
|
{
|
|
DateTime startTime = DateTime.Now;
|
|
DateTime endTime = (startTime +
|
|
TimeSpan.FromSeconds(durationSeconds));
|
|
|
|
DateTime secondStart = startTime;
|
|
DateTime secondEnd = startTime + TimeSpan.FromSeconds(1);
|
|
|
|
DateTime now = startTime;
|
|
|
|
uint second = 0;
|
|
long bitsThisSecond = 0;
|
|
long totalBits = 0;
|
|
int totalPackets = 0;
|
|
|
|
VerboseWriteLine("UdpBlast: {0} bytesPerPacket, Limiting transfer to {1} bitsPerSecond, for {2} seconds",
|
|
bytesPerPacket, bitsPerSecond, durationSeconds);
|
|
|
|
while (now < endTime) {
|
|
int pps = 0;
|
|
|
|
while (now < secondEnd && bitsThisSecond < bitsPerSecond) {
|
|
// XXX: Just bursting packets out for
|
|
// now rather than pacing them,
|
|
// interested mainly in saturation case.
|
|
byte[] in ExHeap pkt;
|
|
uint pktSize;
|
|
if ((long)bytesPerPacket * 8 < bitsPerSecond - bitsThisSecond) {
|
|
pktSize = bytesPerPacket;
|
|
}
|
|
else {
|
|
// Send a final runt packet for this cycle to keep us under
|
|
// the agreed total bits per second rate.
|
|
pktSize = (uint)((bitsPerSecond - bitsThisSecond) / 8);
|
|
if (pktSize <= FixedHeaderBytes) {
|
|
pktSize = FixedHeaderBytes + 1;
|
|
}
|
|
}
|
|
pkt = new [ExHeap] byte [pktSize - FixedHeaderBytes];
|
|
udpConn.SendWrite(pkt);
|
|
udpConn.RecvOK();
|
|
bitsThisSecond += pktSize * 8;
|
|
now = DateTime.Now;
|
|
pps++;
|
|
totalPackets++;
|
|
}
|
|
|
|
while (now < secondEnd) {
|
|
Thread.Sleep(0);
|
|
now = DateTime.Now;
|
|
}
|
|
|
|
TimeSpan tau = secondEnd - secondStart;
|
|
|
|
long bytesPerSecond = (bitsThisSecond / tau.TotalSeconds) / 8;
|
|
|
|
VerboseWriteLine(
|
|
"Round {0} duration(secs) {1:f2} rate (pps) {2} rate (bps) {3:e3}, bytes/sec {4:e3}",
|
|
second, tau.TotalSeconds,
|
|
pps,
|
|
bitsThisSecond / tau.TotalSeconds,
|
|
bytesPerSecond);
|
|
|
|
second++;
|
|
totalBits += bitsThisSecond;
|
|
bitsThisSecond = 0;
|
|
secondStart = now;
|
|
secondEnd = now + TimeSpan.FromSeconds(1);
|
|
}
|
|
|
|
Console.WriteLine(
|
|
"Average rate: packets/sec {0}, bits/sec {1:e3}, bytes/sec {2:e3}",
|
|
totalPackets / (now - startTime).TotalSeconds,
|
|
totalBits / (now - startTime).TotalSeconds,
|
|
(totalBits / (now - startTime).TotalSeconds) / 8
|
|
);
|
|
}
|
|
|
|
public static int
|
|
Blast(
|
|
[Claims] UdpConnectionContract.Imp:ReadyState! udpConn,
|
|
IPv4 address,
|
|
ushort port,
|
|
long bitsPerSecond,
|
|
long bytesPerPacket,
|
|
long durationSeconds
|
|
)
|
|
{
|
|
Console.WriteLine("UdpBlast({0}, {1})", address, port);
|
|
|
|
try {
|
|
udpConn.SendConnectWithAnyLocalEndPoint((uint)address, port);
|
|
|
|
switch receive {
|
|
case udpConn.OK() :
|
|
// success;
|
|
Console.WriteLine("Connected");
|
|
break;
|
|
|
|
case udpConn.InvalidEndPoint(ip, rejectedPort) :
|
|
throw new Exception("udpConn address and port rejected");
|
|
|
|
case udpConn.ChannelClosed() :
|
|
throw new Exception("udpConn channel closed");
|
|
}
|
|
|
|
SendPackets(udpConn,
|
|
bitsPerSecond,
|
|
(uint)bytesPerPacket,
|
|
durationSeconds);
|
|
Console.WriteLine("Closing connection");
|
|
|
|
udpConn.SendClose();
|
|
}
|
|
catch (Exception e) {
|
|
Console.WriteLine("Unexpected exception: {0}", e);
|
|
}
|
|
finally {
|
|
delete udpConn;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
internal static int AppMain(Parameters! config)
|
|
{
|
|
IPv4 host;
|
|
try {
|
|
host = IPv4.Parse(config.address);
|
|
}
|
|
catch (FormatException e) {
|
|
Console.WriteLine("{0}: {1}", e, config.address);
|
|
return -1;
|
|
}
|
|
|
|
if (config.port > 65536 || config.port < 0) {
|
|
Console.WriteLine("Port number out of range: {0}", config.port);
|
|
return -1;
|
|
}
|
|
ushort port = (ushort) config.port;
|
|
|
|
if ((uint)config.packetBytes < FixedHeaderBytes) {
|
|
Console.WriteLine("Packet size needs to be larger than fixed header size ({0} bytes)", FixedHeaderBytes);
|
|
return -1;
|
|
}
|
|
|
|
UdpBlast.verbose = config.verbose;
|
|
|
|
UdpContract.Imp udpConn = ((!)config.udpRef).Acquire();
|
|
if (udpConn == null) {
|
|
Console.WriteLine("Could not initialize TCP endpoint.");
|
|
return 1;
|
|
}
|
|
udpConn.RecvReady();
|
|
|
|
UdpConnectionContract.Imp! connImp;
|
|
UdpConnectionContract.Exp! connExp;
|
|
UdpConnectionContract.NewChannel(out connImp, out connExp);
|
|
|
|
udpConn.SendCreateUdpSession(connExp);
|
|
connImp.RecvReady();
|
|
delete udpConn;
|
|
|
|
return Blast(connImp,
|
|
host, port,
|
|
config.bitsPerSecond,
|
|
config.packetBytes,
|
|
config.seconds
|
|
);
|
|
}
|
|
} // end class UdpBlast
|
|
}
|