SAM .net lib work in progress - dm and firerabbit
This commit is contained in:
58
apps/sam/csharp/src/SAM.NET/SAM.NET.Test/AssemblyInfo.cs
Normal file
58
apps/sam/csharp/src/SAM.NET/SAM.NET.Test/AssemblyInfo.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
//
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
//
|
||||||
|
[assembly: AssemblyTitle("")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("")]
|
||||||
|
[assembly: AssemblyCopyright("")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
//
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Revision and Build Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
|
||||||
|
[assembly: AssemblyVersion("1.0.*")]
|
||||||
|
|
||||||
|
//
|
||||||
|
// In order to sign your assembly you must specify a key to use. Refer to the
|
||||||
|
// Microsoft .NET Framework documentation for more information on assembly signing.
|
||||||
|
//
|
||||||
|
// Use the attributes below to control which key is used for signing.
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// (*) If no key is specified, the assembly is not signed.
|
||||||
|
// (*) KeyName refers to a key that has been installed in the Crypto Service
|
||||||
|
// Provider (CSP) on your machine. KeyFile refers to a file which contains
|
||||||
|
// a key.
|
||||||
|
// (*) If the KeyFile and the KeyName values are both specified, the
|
||||||
|
// following processing occurs:
|
||||||
|
// (1) If the KeyName can be found in the CSP, that key is used.
|
||||||
|
// (2) If the KeyName does not exist and the KeyFile does exist, the key
|
||||||
|
// in the KeyFile is installed into the CSP and used.
|
||||||
|
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
|
||||||
|
// When specifying the KeyFile, the location of the KeyFile should be
|
||||||
|
// relative to the project output directory which is
|
||||||
|
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
|
||||||
|
// located in the project directory, you would specify the AssemblyKeyFile
|
||||||
|
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
|
||||||
|
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
|
||||||
|
// documentation for more information on this.
|
||||||
|
//
|
||||||
|
[assembly: AssemblyDelaySign(false)]
|
||||||
|
[assembly: AssemblyKeyFile("")]
|
||||||
|
[assembly: AssemblyKeyName("")]
|
52
apps/sam/csharp/src/SAM.NET/SAM.NET.Test/SAM.NET.Test.cs
Normal file
52
apps/sam/csharp/src/SAM.NET/SAM.NET.Test/SAM.NET.Test.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace SAM.NET
|
||||||
|
{
|
||||||
|
class SAMTester
|
||||||
|
{
|
||||||
|
[STAThread]
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
new SAMTester();
|
||||||
|
}
|
||||||
|
public SAMTester ()
|
||||||
|
{
|
||||||
|
SAMConnection connection1 = new SAMConnection(IPAddress.Parse("127.0.0.1"),7656);
|
||||||
|
SAMSession session1 = new SAMSession(connection1,SAM.NET.SamSocketType.Stream,"alice");
|
||||||
|
|
||||||
|
SAMConnection connection2 = new SAMConnection(IPAddress.Parse("127.0.0.1"),7656);
|
||||||
|
SAMSession session2 = new SAMSession(connection2,SAM.NET.SamSocketType.Stream,"bob");
|
||||||
|
|
||||||
|
SAMStream stream1 = new SAMStream(connection1,session1,233);
|
||||||
|
stream1.Connect(session2.getKey());
|
||||||
|
|
||||||
|
//Wait till we are connected to destination
|
||||||
|
while (!stream1.isConnected)
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
|
||||||
|
//Send some bytes
|
||||||
|
stream1.Write(Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString() + "Hi!!!!!!"));
|
||||||
|
|
||||||
|
//Wait till a stream magically appears on the other side
|
||||||
|
while (session2.getStreams().Count == 0) Thread.Sleep(1000);
|
||||||
|
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
while (true) {}
|
||||||
|
foreach (SAMStream stream in session2.getStreams().Values)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Text received on " + stream.getID() + " at " + DateTime.Now.ToLongTimeString());
|
||||||
|
Console.WriteLine(Encoding.ASCII.GetString(stream.ReadToEnd()));
|
||||||
|
stream.Close();
|
||||||
|
}
|
||||||
|
while (true) {}
|
||||||
|
|
||||||
|
stream1.Close();
|
||||||
|
connection1.Close();
|
||||||
|
connection2.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
apps/sam/csharp/src/SAM.NET/SAM.NET/AssemblyInfo.cs
Normal file
58
apps/sam/csharp/src/SAM.NET/SAM.NET/AssemblyInfo.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
//
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
//
|
||||||
|
[assembly: AssemblyTitle("")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("")]
|
||||||
|
[assembly: AssemblyCopyright("")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
//
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Revision and Build Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
|
||||||
|
[assembly: AssemblyVersion("1.0.*")]
|
||||||
|
|
||||||
|
//
|
||||||
|
// In order to sign your assembly you must specify a key to use. Refer to the
|
||||||
|
// Microsoft .NET Framework documentation for more information on assembly signing.
|
||||||
|
//
|
||||||
|
// Use the attributes below to control which key is used for signing.
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// (*) If no key is specified, the assembly is not signed.
|
||||||
|
// (*) KeyName refers to a key that has been installed in the Crypto Service
|
||||||
|
// Provider (CSP) on your machine. KeyFile refers to a file which contains
|
||||||
|
// a key.
|
||||||
|
// (*) If the KeyFile and the KeyName values are both specified, the
|
||||||
|
// following processing occurs:
|
||||||
|
// (1) If the KeyName can be found in the CSP, that key is used.
|
||||||
|
// (2) If the KeyName does not exist and the KeyFile does exist, the key
|
||||||
|
// in the KeyFile is installed into the CSP and used.
|
||||||
|
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
|
||||||
|
// When specifying the KeyFile, the location of the KeyFile should be
|
||||||
|
// relative to the project output directory which is
|
||||||
|
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
|
||||||
|
// located in the project directory, you would specify the AssemblyKeyFile
|
||||||
|
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
|
||||||
|
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
|
||||||
|
// documentation for more information on this.
|
||||||
|
//
|
||||||
|
[assembly: AssemblyDelaySign(false)]
|
||||||
|
[assembly: AssemblyKeyFile("")]
|
||||||
|
[assembly: AssemblyKeyName("")]
|
271
apps/sam/csharp/src/SAM.NET/SAM.NET/SAM.NET.cs
Normal file
271
apps/sam/csharp/src/SAM.NET/SAM.NET/SAM.NET.cs
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace SAM.NET
|
||||||
|
{
|
||||||
|
public enum SamSocketType
|
||||||
|
{
|
||||||
|
Stream,
|
||||||
|
Datagram,
|
||||||
|
Raw
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SAMConnection
|
||||||
|
{
|
||||||
|
private const string propertyMinVersion = "1.0";
|
||||||
|
private const string propertyMaxVersion = "1.0";
|
||||||
|
|
||||||
|
private Socket _sock;
|
||||||
|
private NetworkStream _sockStream;
|
||||||
|
private StreamReader _sockStreamIn;
|
||||||
|
private StreamWriter _sockStreamOut;
|
||||||
|
|
||||||
|
public SAMConnection(IPAddress routerIP, int port)
|
||||||
|
{
|
||||||
|
_sock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
|
||||||
|
IPEndPoint rEP = new IPEndPoint(routerIP,port);
|
||||||
|
_sock.Connect(rEP);
|
||||||
|
_sockStream = new NetworkStream(_sock);
|
||||||
|
_sockStreamIn = new StreamReader(_sockStream);
|
||||||
|
_sockStreamOut = new StreamWriter(_sockStream);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sendVersion(propertyMinVersion,propertyMinVersion);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_sock.Close();
|
||||||
|
throw (new Exception("No SAM for you :("));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendVersion(string min, string max)
|
||||||
|
{
|
||||||
|
_sockStreamOut.WriteLine("HELLO VERSION MIN=" + propertyMinVersion + " MAX=" + propertyMaxVersion);
|
||||||
|
_sockStreamOut.Flush();
|
||||||
|
Hashtable response = SAMUtil.parseKeyValues(_sockStreamIn.ReadLine(),2);
|
||||||
|
if (response["RESULT"].ToString() != "OK") throw (new Exception("Version mismatch"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamWriter getOutputStream()
|
||||||
|
{
|
||||||
|
return _sockStreamOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamReader getInputStream()
|
||||||
|
{
|
||||||
|
return _sockStreamIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkStream getStream()
|
||||||
|
{
|
||||||
|
return _sockStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
_sock.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creating a SAMSession object will automatically:
|
||||||
|
* 1) create a sesion on SAM
|
||||||
|
* 1) query for the base64key
|
||||||
|
* 2) start a listening thread to catch all stream commands
|
||||||
|
*/
|
||||||
|
public class SAMSession
|
||||||
|
{
|
||||||
|
private Hashtable _streams;
|
||||||
|
private string _sessionKey;
|
||||||
|
|
||||||
|
public SAMSession (SAMConnection connection, SamSocketType type, string destination)
|
||||||
|
{
|
||||||
|
_streams = new Hashtable();
|
||||||
|
StreamWriter writer = connection.getOutputStream();
|
||||||
|
StreamReader reader = connection.getInputStream();
|
||||||
|
writer.WriteLine("SESSION CREATE STYLE=STREAM DESTINATION=" + destination);
|
||||||
|
writer.Flush();
|
||||||
|
Hashtable response = SAMUtil.parseKeyValues(reader.ReadLine(),2);
|
||||||
|
if (response["RESULT"].ToString() != "OK")
|
||||||
|
{
|
||||||
|
throw (new Exception(response["MESSAGE"].ToString()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.WriteLine("NAMING LOOKUP NAME=ME");
|
||||||
|
writer.Flush();
|
||||||
|
response = SAMUtil.parseKeyValues(reader.ReadLine(),2);
|
||||||
|
_sessionKey = response["VALUE"].ToString();
|
||||||
|
SAMSessionListener listener = new SAMSessionListener(connection,this,_streams);
|
||||||
|
new Thread(new ThreadStart(listener.startListening)).Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void addStream(SAMStream stream)
|
||||||
|
{
|
||||||
|
_streams.Add(stream.getID(),stream);
|
||||||
|
}
|
||||||
|
public string getKey()
|
||||||
|
{
|
||||||
|
return _sessionKey;
|
||||||
|
}
|
||||||
|
public Hashtable getStreams()
|
||||||
|
{
|
||||||
|
return _streams;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SAMSessionListener
|
||||||
|
{
|
||||||
|
private Hashtable _streams;
|
||||||
|
private SAMConnection _connection;
|
||||||
|
private SAMSession _session;
|
||||||
|
private bool stayAlive = true;
|
||||||
|
|
||||||
|
public SAMSessionListener(SAMConnection connection,SAMSession session, Hashtable streams)
|
||||||
|
{
|
||||||
|
_streams = streams;
|
||||||
|
_connection = connection;
|
||||||
|
_session = session;
|
||||||
|
}
|
||||||
|
public void startListening()
|
||||||
|
{
|
||||||
|
StreamReader reader = _connection.getInputStream();
|
||||||
|
while (stayAlive)
|
||||||
|
{
|
||||||
|
string response = reader.ReadLine();
|
||||||
|
if (response.StartsWith("STREAM STATUS"))
|
||||||
|
{
|
||||||
|
Hashtable values = SAMUtil.parseKeyValues(response,2);
|
||||||
|
SAMStream theStream = (SAMStream)_streams[int.Parse(values["ID"].ToString())];
|
||||||
|
if (theStream != null) theStream.ReceivedStatus(values);
|
||||||
|
}
|
||||||
|
if (response.StartsWith("STREAM CONNECTED"))
|
||||||
|
{
|
||||||
|
Hashtable values = SAMUtil.parseKeyValues(response,2);
|
||||||
|
SAMStream theStream = (SAMStream)_streams[int.Parse(values["ID"].ToString())];
|
||||||
|
if (theStream != null) theStream.isConnected = true;
|
||||||
|
}
|
||||||
|
if (response.StartsWith("STREAM RECEIVED"))
|
||||||
|
{
|
||||||
|
Hashtable values = SAMUtil.parseKeyValues(response,2);
|
||||||
|
int streamID = int.Parse(values["ID"].ToString());
|
||||||
|
SAMStream theStream = (SAMStream)_streams[streamID];
|
||||||
|
if (theStream == null) new SAMStream(_connection,_session,streamID);
|
||||||
|
theStream = (SAMStream)_streams[streamID];
|
||||||
|
theStream.ReceivedData(int.Parse(values["SIZE"].ToString()));
|
||||||
|
}
|
||||||
|
if (response.StartsWith("STREAM CLOSE"))
|
||||||
|
{
|
||||||
|
Hashtable values = SAMUtil.parseKeyValues(response,2);
|
||||||
|
SAMStream theStream = (SAMStream)_streams[int.Parse(values["ID"].ToString())];
|
||||||
|
if (theStream != null) theStream.isConnected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SAMStream
|
||||||
|
{
|
||||||
|
private int _ID;
|
||||||
|
private byte[] _data;
|
||||||
|
private int _position=0;
|
||||||
|
private int _size=0;
|
||||||
|
private SAMSession _session;
|
||||||
|
private SAMConnection _connection;
|
||||||
|
public bool isConnected=false;
|
||||||
|
|
||||||
|
public SAMStream (SAMConnection connection,SAMSession session, int ID)
|
||||||
|
{
|
||||||
|
_data = new byte[100000]; //FIXME: change to non-static structure for storing stream data
|
||||||
|
_ID = ID;
|
||||||
|
_connection = connection;
|
||||||
|
_session = session;
|
||||||
|
_session.addStream(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Connect(string destination)
|
||||||
|
{
|
||||||
|
StreamWriter writer = _connection.getOutputStream();
|
||||||
|
writer.WriteLine("STREAM CONNECT ID=" + _ID.ToString() + " DESTINATION=" + destination);
|
||||||
|
writer.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReceivedData(int size) //FIXME: WTF is going on when reading the payload here? All zeros and way too many of them.
|
||||||
|
{
|
||||||
|
NetworkStream stream = _connection.getStream();
|
||||||
|
int bytesRead = stream.Read(_data,_size,size);
|
||||||
|
_size = _size + bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReceivedStatus(Hashtable response)
|
||||||
|
{
|
||||||
|
if (response["RESULT"].ToString() != "OK")
|
||||||
|
{
|
||||||
|
throw (new Exception(response["RESULT"].ToString()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isConnected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getID() {return _ID;}
|
||||||
|
|
||||||
|
public bool DataAvailable()
|
||||||
|
{
|
||||||
|
return _position != _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(byte[] buf)
|
||||||
|
{
|
||||||
|
NetworkStream stream = _connection.getStream();
|
||||||
|
int sent = 0;
|
||||||
|
while (sent < buf.Length)
|
||||||
|
{
|
||||||
|
int toSend = Math.Min(buf.Length - sent,32768);
|
||||||
|
string header = "STREAM SEND ID=" + _ID.ToString() + " SIZE=" + toSend.ToString() + "\n";
|
||||||
|
byte[] headerbytes = Encoding.ASCII.GetBytes(header);
|
||||||
|
stream.Write(headerbytes,0,headerbytes.Length);
|
||||||
|
stream.Write(buf,sent,toSend);
|
||||||
|
sent = sent + toSend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] ReadToEnd()
|
||||||
|
{
|
||||||
|
byte[] ret = new byte[_size - _position];
|
||||||
|
Array.Copy(_data,_position,ret,0,_size - _position);
|
||||||
|
_position = _size;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
StreamWriter writer = _connection.getOutputStream();
|
||||||
|
writer.WriteLine("STREAM CLOSE " + _ID.ToString());
|
||||||
|
writer.Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SAMUtil
|
||||||
|
{
|
||||||
|
public static Hashtable parseKeyValues(string str, int startingWord)
|
||||||
|
{
|
||||||
|
Hashtable hash = new Hashtable();
|
||||||
|
string strTruncated = string.Join(" ",str.Split(' '),startingWord,str.Split(' ').Length - startingWord);
|
||||||
|
string[] sets = strTruncated.Split('=',' ');
|
||||||
|
for (int i=0; i<sets.Length; i=i+2)
|
||||||
|
{
|
||||||
|
hash.Add(sets[i],sets[i+1]);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user