2008-03-05 09:52:00 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Microsoft Research Singularity
|
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
//
|
|
|
|
// Note: Contract definition for TCP channels
|
|
|
|
//
|
|
|
|
|
|
|
|
using Microsoft.Singularity.Channels;
|
|
|
|
using System;
|
|
|
|
|
|
|
|
namespace NetStack.Contracts
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
public enum TcpError
|
|
|
|
{
|
|
|
|
Unknown = 1,
|
|
|
|
AlreadyConnected, // this connection is already in use
|
|
|
|
Refused, // the receiving host actively refused the connection
|
|
|
|
Reset, // the connection was reset
|
|
|
|
Timeout, // no response was received
|
|
|
|
ProtocolViolation, // we received a TCP segment that is not acceptable in the current state
|
|
|
|
ResourcesExhausted, // out of memory, etc.
|
|
|
|
Closed, // remote peer has closed socket
|
|
|
|
}
|
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
public contract TcpConnectionContract
|
|
|
|
{
|
|
|
|
// Requests
|
|
|
|
in message Connect(uint dstIP, ushort dstPort);
|
|
|
|
in message BindLocalEndPoint(uint dstIP, ushort dstPort);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initial state; there is a gratuitous Ready message to
|
|
|
|
// ensure the Exp side has been connected before it accepts
|
|
|
|
// any messages.
|
|
|
|
//
|
|
|
|
out message Ready();
|
|
|
|
|
|
|
|
state Start : Ready! -> ReadyState;
|
|
|
|
|
|
|
|
state ReadyState : one
|
|
|
|
{
|
|
|
|
Connect? -> ConnectResult; // Can connect without binding first
|
|
|
|
BindLocalEndPoint? -> BindResult; // Can't listen without binding first
|
|
|
|
Close? -> Closed;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Binding to a local endpoint
|
|
|
|
//
|
|
|
|
state BindResult : one
|
|
|
|
{
|
|
|
|
OK! -> Bound;
|
|
|
|
InvalidEndPoint! -> ReadyState;
|
|
|
|
}
|
|
|
|
|
|
|
|
in message Listen(int backlog);
|
|
|
|
|
|
|
|
state Bound : one
|
|
|
|
{
|
|
|
|
Listen? -> ListenResult;
|
|
|
|
Connect? -> ConnectResult;
|
|
|
|
Close? -> Closed;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Attempts to connect to a remote host
|
|
|
|
//
|
|
|
|
out message OK();
|
|
|
|
out message CouldNotConnect(TcpError error);
|
|
|
|
|
|
|
|
state ConnectResult : one
|
|
|
|
{
|
|
|
|
CouldNotConnect! -> ReadyState;
|
|
|
|
OK! -> Connected;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Attempts to listen for inbound connections
|
|
|
|
//
|
|
|
|
out message CouldNotListen();
|
|
|
|
|
|
|
|
state ListenResult : one
|
|
|
|
{
|
|
|
|
CouldNotListen! -> ReadyState;
|
|
|
|
OK! -> Listening;
|
|
|
|
}
|
|
|
|
|
|
|
|
out message InvalidEndPoint();
|
|
|
|
|
|
|
|
in message GetLocalAddress();
|
|
|
|
in message GetLocalPort();
|
|
|
|
in message Accept(TcpConnectionContract.Exp:PreConnected! newConnection);
|
|
|
|
in message IsSessionAvailable(); // Is there a new session waiting to be serviced?
|
|
|
|
|
|
|
|
out message IPAddress(uint ip);
|
|
|
|
out message Port(ushort port);
|
|
|
|
out message SessionIsAvailable(bool isAvailable);
|
|
|
|
|
|
|
|
state Listening : one
|
|
|
|
{
|
|
|
|
GetLocalAddress? -> IPAddress! -> Listening;
|
|
|
|
GetLocalPort? -> Port! -> Listening;
|
|
|
|
IsSessionAvailable? -> SessionIsAvailable! -> Listening;
|
|
|
|
Accept? -> OK! -> Listening; // Blocks until a connection is received
|
|
|
|
|
|
|
|
Close? -> Closed;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// The pre-connected state exists so we can confirm that the endpoint
|
|
|
|
// has been wired to the NetStack before accepting messages on it
|
|
|
|
//
|
|
|
|
state PreConnected : Ready! -> Connected;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Operations on an established connection
|
|
|
|
//
|
|
|
|
|
|
|
|
// Requests
|
|
|
|
in message Read(); // Read as much data as possible without blocking
|
|
|
|
in message PollRead(int timeout); // Wait up to timeout ms for data
|
|
|
|
in message IsDataAvailable(); // Is there queued data that can be read immediately?
|
|
|
|
in message Write(byte[]! in ExHeap data);
|
|
|
|
in message Close(); // Performs a non-blocking but graceful shutdown
|
|
|
|
in message Abort(); // Performs an immediate, hard close (unsent data is discarded)
|
|
|
|
in message GetRemoteAddress();
|
|
|
|
in message GetRemotePort();
|
|
|
|
in message DoneSending();
|
|
|
|
in message DoneReceiving();
|
|
|
|
|
|
|
|
// Response messages
|
|
|
|
out message ConnectionClosed(); // Connection has been shut down
|
|
|
|
out message NoData(); // There was nothing to read
|
|
|
|
out message NoMoreData(); // Will never be more data
|
|
|
|
out message CantSend(); // Remote side refuses more data
|
|
|
|
out message Data(byte[]! in ExHeap data);
|
|
|
|
out message DataIsAvailable(bool isAvailable);
|
|
|
|
|
|
|
|
state Connected : one
|
|
|
|
{
|
|
|
|
Read? -> ReadResult;
|
|
|
|
PollRead? -> PollReadResult;
|
|
|
|
Write? -> WriteResult;
|
|
|
|
|
|
|
|
IsDataAvailable? -> (DataIsAvailable!) -> Connected;
|
|
|
|
GetLocalAddress? -> IPAddress! -> Connected;
|
|
|
|
GetLocalPort? -> Port! -> Connected;
|
|
|
|
GetRemoteAddress? -> IPAddress! -> Connected;
|
|
|
|
GetRemotePort? -> Port! -> Connected;
|
|
|
|
|
|
|
|
DoneSending? -> ReceiveOnly;
|
|
|
|
DoneReceiving? -> SendOnly;
|
|
|
|
Close? -> Closed;
|
|
|
|
Abort? -> Closed;
|
|
|
|
}
|
|
|
|
|
|
|
|
state ReadResult : one
|
|
|
|
{
|
|
|
|
Data! -> Connected;
|
|
|
|
// This indicates that there will never be any more
|
|
|
|
// data, but that sending is still allowed
|
|
|
|
NoMoreData! -> SendOnly;
|
|
|
|
// This indicates that sending has been closed by the
|
|
|
|
// remote side
|
|
|
|
ConnectionClosed! -> Zombie;
|
|
|
|
}
|
|
|
|
|
|
|
|
state PollReadResult : one
|
|
|
|
{
|
|
|
|
Data! -> Connected;
|
|
|
|
// No data available within the poll window; try again
|
|
|
|
NoData! -> Connected;
|
|
|
|
NoMoreData! -> SendOnly;
|
|
|
|
ConnectionClosed! -> Zombie;
|
|
|
|
}
|
|
|
|
|
|
|
|
state WriteResult : one
|
|
|
|
{
|
|
|
|
OK! -> Connected;
|
|
|
|
// This indicates that writing has been closed by the
|
|
|
|
// remote side, but reading is still allowed.
|
|
|
|
CantSend! -> ReceiveOnly;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Operations on a receive-only connection (send side has been closed)
|
|
|
|
//
|
|
|
|
state ReceiveOnly : one
|
|
|
|
{
|
|
|
|
Read? -> ROReadResult;
|
|
|
|
PollRead? -> ROPollReadResult;
|
|
|
|
|
|
|
|
IsDataAvailable? -> (DataIsAvailable!) -> ReceiveOnly;
|
|
|
|
GetLocalAddress? -> IPAddress! -> ReceiveOnly;
|
|
|
|
GetLocalPort? -> Port! -> ReceiveOnly;
|
|
|
|
GetRemoteAddress? -> IPAddress! -> ReceiveOnly;
|
|
|
|
GetRemotePort? -> Port! -> ReceiveOnly;
|
|
|
|
|
|
|
|
DoneReceiving? -> Zombie;
|
|
|
|
Close? -> Closed;
|
|
|
|
Abort? -> Closed;
|
|
|
|
}
|
|
|
|
|
|
|
|
state ROReadResult : one
|
|
|
|
{
|
|
|
|
Data! -> ReceiveOnly;
|
|
|
|
// If there is no more data, there's nothing more to do.
|
|
|
|
NoMoreData! -> Zombie;
|
|
|
|
}
|
|
|
|
|
|
|
|
state ROPollReadResult : one
|
|
|
|
{
|
|
|
|
Data! -> ReceiveOnly;
|
|
|
|
NoData! -> ReceiveOnly;
|
|
|
|
NoMoreData! -> Zombie;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Operations on a send-only connection (receive side has been closed)
|
|
|
|
//
|
|
|
|
state SendOnly : one
|
|
|
|
{
|
|
|
|
Write? -> SOWriteResult;
|
|
|
|
|
|
|
|
GetLocalAddress? -> IPAddress! -> SendOnly;
|
|
|
|
GetLocalPort? -> Port! -> SendOnly;
|
|
|
|
GetRemoteAddress? -> IPAddress! -> SendOnly;
|
|
|
|
GetRemotePort? -> Port! -> SendOnly;
|
|
|
|
|
|
|
|
DoneSending? -> Zombie;
|
|
|
|
Close? -> Closed;
|
|
|
|
Abort? -> Closed;
|
|
|
|
}
|
|
|
|
|
|
|
|
state SOWriteResult : one
|
|
|
|
{
|
|
|
|
OK! -> SendOnly;
|
|
|
|
// Remote side refuses further data
|
|
|
|
CantSend! -> Zombie;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Zombied connection (nothing left to do but user hasn't explicitly
|
|
|
|
// closed yet)
|
|
|
|
//
|
|
|
|
state Zombie : one
|
|
|
|
{
|
|
|
|
Close? -> Closed; // Wrap up gracefully
|
|
|
|
Abort? -> Closed; // Drop any unsent data
|
|
|
|
}
|
|
|
|
|
|
|
|
state Closed : {} // Nothing is acceptable here
|
|
|
|
}
|
|
|
|
}
|