277 lines
9.1 KiB
C#
277 lines
9.1 KiB
C#
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: TcpBlast.cs
|
|
//
|
|
// Note: Simple Singularity test program.
|
|
//
|
|
|
|
using System;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Threading;
|
|
using System.Collections;
|
|
|
|
#if SINGULARITY
|
|
using Microsoft.Contracts;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
|
|
using Microsoft.SingSharp;
|
|
using Microsoft.Singularity;
|
|
using Microsoft.Singularity.Channels;
|
|
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))]
|
|
#endif
|
|
|
|
|
|
namespace Microsoft.Singularity.Applications.Network
|
|
{
|
|
#if SINGULARITY
|
|
[ConsoleCategory(HelpMessage="BlastServer TCP data to 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<TcpContract.Imp:Start> tcpRef;
|
|
|
|
|
|
[LongParameter( "port", Mandatory=true, Position=0, HelpMessage="port to gulp from ")]
|
|
internal long port;
|
|
|
|
|
|
[LongParameter( "numBytes", Mandatory=true, Position=1, HelpMessage="Total bytes to send")]
|
|
internal long numBytes;
|
|
|
|
|
|
[LongParameter( "chunkSize", Mandatory=true, Position=2, HelpMessage="Chunks size to send")]
|
|
internal long chunkSize;
|
|
|
|
reflective internal Parameters();
|
|
|
|
internal int AppMain() {
|
|
return BlastServer.AppMain(this);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
public class BlastServer
|
|
{
|
|
///////////////////////////////////////////////////////////////////////
|
|
// Constants
|
|
private const int WorkerThreads = 32;
|
|
private const int MaxWorkItems = 32 * WorkerThreads;
|
|
private const string RepeatPattern = "Here is a repeating string of text that serves as content. ";
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// class variables
|
|
ushort port;
|
|
uint numBytes;
|
|
uint chunkSize;
|
|
byte[] chunkBuffer;
|
|
ThreadPool threadPool;
|
|
|
|
private void DispatchRequest(object dispatchObject)
|
|
{
|
|
Console.WriteLine(dispatchObject as string);
|
|
Console.WriteLine("We should Never get here");
|
|
#if SINGULARITY
|
|
DebugStub.Break();
|
|
#endif
|
|
}
|
|
|
|
private void test (object dispatchObject)
|
|
{
|
|
Console.Write(dispatchObject as string);
|
|
}
|
|
|
|
private void Blaster (object sock)
|
|
{
|
|
Socket socket = sock as Socket;
|
|
#if SINGULARITY
|
|
assert socket != null;
|
|
#endif
|
|
int bytesSent = 0;
|
|
int iterations =0;
|
|
|
|
|
|
uint bytesLeft = numBytes, patternLength = (uint)RepeatPattern.Length;
|
|
try {
|
|
while (bytesLeft > 0) {
|
|
uint thisPass = chunkSize < bytesLeft ? chunkSize : bytesLeft;
|
|
if (thisPass == chunkSize) {
|
|
socket.Send(chunkBuffer);
|
|
}
|
|
else {
|
|
byte[] thisPassBuffer = new byte[thisPass];
|
|
for (uint i = 0; i < thisPass; i++) {
|
|
thisPassBuffer [(int)i] = (byte)RepeatPattern[(int)i % (int)patternLength];
|
|
}
|
|
socket.Send(thisPassBuffer);
|
|
}
|
|
bytesLeft -= thisPass;
|
|
bytesSent += (int) thisPass;
|
|
iterations++;
|
|
}
|
|
} catch(ArgumentNullException ae) {
|
|
Console.WriteLine("ArgumentNullException : {0}", ae.ToString());
|
|
} catch(SocketException se) {
|
|
Console.WriteLine("SocketException : {0}", se.ToString());
|
|
} catch(Exception e) {
|
|
Console.WriteLine("Unexpected exception : {0}", e.ToString());
|
|
}
|
|
//Console.WriteLine("Sent {0} bytes in {1} iterations",bytesSent,iterations);
|
|
|
|
socket.Shutdown(SocketShutdown.Both);
|
|
socket.Close();
|
|
Thread.Sleep(2);
|
|
}
|
|
|
|
private void Listen() {
|
|
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
|
socket.Bind(new IPEndPoint(IPAddress.Any, (int)this.port));
|
|
socket.Listen((int)SocketOptionName.MaxConnections);
|
|
while (true) {
|
|
Socket s = socket.Accept();
|
|
threadPool.QueueUserWorkItem(new ThreadPool.WorkCallback(Blaster), s);
|
|
}
|
|
}
|
|
|
|
#if SINGULARITY
|
|
[NotDelayed]
|
|
#endif
|
|
public BlastServer (ushort port, uint numBytes, uint chunkSize)
|
|
{
|
|
this.port = port;
|
|
this.numBytes = numBytes;
|
|
this.chunkSize = chunkSize;
|
|
|
|
chunkBuffer = new byte[chunkSize];
|
|
for (uint i = 0; i < chunkSize; i++) {
|
|
chunkBuffer [(int)i] = (byte)RepeatPattern[(int)i % (int)RepeatPattern.Length];
|
|
}
|
|
|
|
Console.WriteLine("BlastServer listening on port {0} for {1} bytes in {2}-byte chunks",
|
|
port, numBytes, chunkSize);
|
|
|
|
threadPool = new ThreadPool(
|
|
WorkerThreads, MaxWorkItems,
|
|
new ThreadPool.WorkCallback(DispatchRequest)
|
|
);
|
|
#if blee
|
|
for (int i=0; i < 50 ; i++) {
|
|
for (int j = 0; j < 40; j++) {
|
|
bool isFull = threadPool.QueueUserWorkItem(new ThreadPool.WorkCallback(test), ".");
|
|
while (isFull) {
|
|
Thread.Sleep(2);
|
|
isFull = threadPool.QueueUserWorkItem(new ThreadPool.WorkCallback(test), "yes\n");
|
|
}
|
|
}
|
|
Thread.Sleep(300);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
public static void Usage()
|
|
{
|
|
Console.WriteLine("blastserver <port> <numBytes> <chunkSize>");
|
|
}
|
|
|
|
public void Shutdown()
|
|
{
|
|
threadPool.Shutdown();
|
|
}
|
|
#if SINGULARITY
|
|
internal static int AppMain(Parameters! config)
|
|
{
|
|
|
|
if (config.port > 65536 || config.port < 0) {
|
|
Console.WriteLine("Port number out of range: {0}", config.port);
|
|
return -1;
|
|
}
|
|
|
|
ushort port = (ushort) config.port;
|
|
uint numBytes = (uint) config.numBytes;
|
|
uint chunkSize = (uint) config.chunkSize;
|
|
BlastServer bs = new BlastServer( port, numBytes, chunkSize);
|
|
|
|
bs.Listen();
|
|
bs.Shutdown();
|
|
return 0;
|
|
}
|
|
#else
|
|
public static int Main(string[] /*!*/ args)
|
|
{
|
|
int start = -1;
|
|
if (args.Length < 4 + start)
|
|
{
|
|
Usage();
|
|
return 1;
|
|
}
|
|
|
|
ushort port;
|
|
|
|
try {
|
|
port = UInt16.Parse(args[1+start]);
|
|
}
|
|
catch (FormatException) {
|
|
Console.WriteLine("Malformed port number: {0}", args[1+start]);
|
|
return -1;
|
|
}
|
|
catch (OverflowException) {
|
|
Console.WriteLine("Port number out of range: {0}", args[1+start]);
|
|
return -1;
|
|
}
|
|
|
|
uint numBytes;
|
|
|
|
try {
|
|
numBytes = UInt32.Parse(args[2+start]);
|
|
}
|
|
|
|
catch (FormatException) {
|
|
Console.WriteLine("Malformed number of bytes: {0}", args[2+start]);
|
|
return -1;
|
|
}
|
|
catch (OverflowException) {
|
|
Console.WriteLine("Byte count out of range: {0}", args[2+start]);
|
|
return -1;
|
|
}
|
|
|
|
uint chunkSize;
|
|
|
|
try {
|
|
chunkSize = UInt32.Parse(args[3+start]);
|
|
}
|
|
catch (FormatException) {
|
|
Console.WriteLine("Malformed chunk size: {0}", args[3+start]);
|
|
return -1;
|
|
}
|
|
catch (OverflowException) {
|
|
Console.WriteLine("Chunk size out of range: {0}", args[3+start]);
|
|
return -1;
|
|
}
|
|
BlastServer bs = new BlastServer( port, numBytes, chunkSize);
|
|
|
|
bs.Listen();
|
|
bs.Shutdown();
|
|
return 0;
|
|
}
|
|
#endif
|
|
} // end class TcpBlast
|
|
}
|