190 lines
6.3 KiB
C#
190 lines
6.3 KiB
C#
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: UdpGulp.cs
|
||
|
//
|
||
|
// 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="Receive UDP data from a ipAddress, 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("t", Mandatory = false, HelpMessage = "Seconds to send packets for", Default = 30)]
|
||
|
internal long seconds;
|
||
|
|
||
|
[StringParameter("a", Mandatory = false, HelpMessage = "Local address to bind to.", Default = "0.0.0.0")]
|
||
|
internal string address;
|
||
|
|
||
|
[LongParameter("port", Mandatory = true, Position = 0, HelpMessage = "port to gulp from")]
|
||
|
internal long port;
|
||
|
|
||
|
reflective internal Parameters();
|
||
|
|
||
|
internal int AppMain()
|
||
|
{
|
||
|
return UdpGulp.AppMain(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public class UdpGulp
|
||
|
{
|
||
|
private const int FixedHeaderBytes = 42; // Ether + IP + UDP
|
||
|
|
||
|
private static void
|
||
|
ReceivePackets(
|
||
|
UdpConnectionContract.Imp:ReadyState! udpConn,
|
||
|
long totalSeconds
|
||
|
)
|
||
|
{
|
||
|
int bytesThisRound = 0;
|
||
|
|
||
|
DateTime now = DateTime.Now;
|
||
|
DateTime epochEnd = now + TimeSpan.FromSeconds(1);
|
||
|
DateTime epochStart = now;
|
||
|
|
||
|
while (--totalSeconds >= 0) {
|
||
|
while (now < epochEnd) {
|
||
|
udpConn.SendPollRead((epochEnd - now).Milliseconds);
|
||
|
switch receive {
|
||
|
case udpConn.NoData() :
|
||
|
// No data to read. This doesn't
|
||
|
// necessarily mean the connection
|
||
|
// is closed.
|
||
|
Thread.Yield();
|
||
|
break;
|
||
|
case udpConn.Data(uint addr, ushort port2,
|
||
|
byte[]! in ExHeap data):
|
||
|
bytesThisRound += data.Length + FixedHeaderBytes;
|
||
|
delete data;
|
||
|
break;
|
||
|
case udpConn.ChannelClosed():
|
||
|
throw new Exception("udpConn channel closed");
|
||
|
}
|
||
|
now = DateTime.Now;
|
||
|
}
|
||
|
|
||
|
TimeSpan delta = now - epochStart;
|
||
|
Console.WriteLine(
|
||
|
"Duration(s) {0:f2} rate(bps) {1:e3} bps",
|
||
|
delta.TotalSeconds,
|
||
|
8.0 * bytesThisRound / delta.TotalSeconds);
|
||
|
bytesThisRound = 0;
|
||
|
epochStart = DateTime.Now;
|
||
|
epochEnd = epochStart + TimeSpan.FromSeconds(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static int
|
||
|
Gulp([Claims] UdpConnectionContract.Imp:ReadyState! udpConn,
|
||
|
IPv4 address,
|
||
|
ushort port,
|
||
|
long totalSeconds)
|
||
|
{
|
||
|
Console.WriteLine("UdpGulp({0}, {1})", address, port);
|
||
|
|
||
|
try {
|
||
|
// Bind local endpoint
|
||
|
udpConn.SendBindLocalEndPoint((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");
|
||
|
}
|
||
|
|
||
|
ReceivePackets(udpConn, totalSeconds);
|
||
|
|
||
|
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 > 0xffff || config.port < 0) {
|
||
|
Console.WriteLine("Port number out of range: {0}",
|
||
|
config.port);
|
||
|
return -1;
|
||
|
}
|
||
|
ushort port = (ushort) config.port;
|
||
|
|
||
|
UdpContract.Imp udpConn = (config.udpRef).Acquire();
|
||
|
if (udpConn == null) {
|
||
|
Console.WriteLine("Could not initialize TCP endpoint.");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
Console.WriteLine("Waiting for ready");
|
||
|
udpConn.RecvReady();
|
||
|
|
||
|
UdpConnectionContract.Imp! connImp;
|
||
|
UdpConnectionContract.Exp! connExp;
|
||
|
UdpConnectionContract.NewChannel(out connImp, out connExp);
|
||
|
|
||
|
Console.WriteLine("Creating session");
|
||
|
udpConn.SendCreateUdpSession(connExp);
|
||
|
connImp.RecvReady();
|
||
|
delete udpConn;
|
||
|
Console.WriteLine("Ready");
|
||
|
return Gulp(connImp, host, port, config.seconds);
|
||
|
}
|
||
|
} // end class UdpGulp
|
||
|
}
|