/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: UdpExpConnection.sg // // Note: Provider-side helper for the Udp Channel Contract // // #define DEBUG_UDPEXPCONNECTION using System.Threading; using System.Net.IP; using Microsoft.SingSharp; using Microsoft.Singularity; using Microsoft.Singularity.Channels; using NetStack.Contracts; using NetStack.Runtime; using System.Collections; using System; namespace NetStack.Channels.Private { public class UdpConnectionExpThread { private TRef! chanEP; private UdpSession! session; [ System.Diagnostics.Conditional("DEBUG_UDPEXPCONNECTION") ] static void DebugPrint(string format, params object [] args) { DebugStub.Print( "UdpConnectionExpThread [{0}]: {1}", __arglist( Thread.CurrentThread.GetThreadId(), string.Format(format, args) ) ); } public void Run() { UdpConnectionContract.Exp! ep = chanEP.Acquire(); while(true) { switch receive { case ep.BindLocalEndPoint(uint srcIP, ushort srcPort) : { DebugPrint("BindLocalEndPoint ({0:x8}/{1} ->)\n", srcIP, srcPort); IPv4 srcAddr = new IPv4(srcIP); if (srcAddr != IPv4.Any && session.IsLocalAddress(srcAddr) == false) { ep.SendInvalidEndPoint(srcIP, srcPort); } else { session.BindLocalEndPoint(srcAddr, srcPort); ep.SendOK(); } } break; case ep.ConnectWithAnyLocalEndPoint(uint dstIP, ushort dstPort) : { DebugPrint( "ConnectWithAnyLocalEndPoint (-> {0:x8}/{1})\n", dstIP, dstPort ); session.BindRemoteEndPoint(new IPv4(dstIP), dstPort); ep.SendOK(); } break; case ep.Connect(uint srcIP, ushort srcPort, uint dstIP, ushort dstPort) : { DebugPrint( "BindLocalEndPoint ({0:x8}/{1} -> {2:x8}/{3})\n", srcIP, srcPort, dstIP, dstPort ); session.BindEndPoints(new IPv4(srcIP), srcPort, new IPv4(dstIP), dstPort); ep.SendOK(); } break; case ep.PollSelectRead(int millis) : { if (ep.InState(UdpConnectionContract.Start.Value)) { ep.SendPollSelectResult(false); } else { bool result = session.PollSelectRead(millis); ep.SendPollSelectResult(result); } } break; case ep.PollSelectWrite(int millis) : { bool result = session.PollSelectWrite(millis); ep.SendPollSelectResult(result); } break; case ep.Read() : { byte[] in ExHeap data = session.ReadData(); // Currently, there is no way of // detecting that the connection has // been closed underneath us. We should // fix that. if (data == null) { ep.SendNoData(); } else { ep.SendData(0, 0, data); } } break; case ep.PollRead(int timeoutMillis) : { byte[] in ExHeap data = session.PollData(timeoutMillis); // Currently, there is no way of // detecting that the connection has // been closed underneath us. We should // fix that. if (data == null) { ep.SendNoData(); } else { ep.SendData(0, 0, data); } } break; case ep.Write(byte[]! in ExHeap data) : { DebugPrint("Write {0} bytes.\n", data.Length); if (session.WriteData(data) == data.Length) { ep.SendOK(); } else { ep.SendDataTooLarge(); } delete data; } break; case ep.WriteTo(uint dstIP, dstPort, byte[]! in ExHeap data) : { DebugPrint("WriteTo {0} bytes -> {1:x8}/{2}.\n", data.Length, dstIP, dstPort); int written = session.WriteDataTo(new IPv4(dstIP), dstPort, data); if (written == data.Length) { ep.SendOK(); } else { ep.SendDataTooLarge(); } delete data; } break; case ep.Close() : session.Close(); break; case ep.GetLocalAddress() : ep.SendIPAddress((uint)session.LocalAddress); break; case ep.GetLocalPort() : ep.SendPort(session.LocalPort); break; case ep.GetRemoteAddress() : ep.SendIPAddress((uint)session.RemoteAddress); break; case ep.GetRemotePort() : ep.SendPort(session.RemotePort); break; case unsatisfiable : // Exit this thread session.Dispose(); delete ep; return; break; } } } public UdpConnectionExpThread([Claims]UdpConnectionContract.Exp:Start! ep) { chanEP = new TRef(ep); session = (UdpSession!)Core.Instance().CreateSession("UDP"); } private UdpConnectionExpThread([Claims]UdpConnectionContract.Exp:Connected! ep, UdpSession! newSession) { chanEP = new TRef(ep); this.session = newSession; } public void Start() { Thread newThread = new Thread(new ThreadStart(Run)); newThread.Start(); } } }