//////////////////////////////////////////////////////////////////////////////// // // 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 Stdin; [OutputEndpoint("data")] public readonly TRef Stdout; [Endpoint] public readonly TRef 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 }