singrdk/base/Services/Smb/Shared/NetUtil.sg

178 lines
5.5 KiB
Plaintext
Raw Normal View History

2008-11-17 18:29:00 -05:00
// ----------------------------------------------------------------------------
2008-03-05 09:52:00 -05:00
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
2008-11-17 18:29:00 -05:00
// ----------------------------------------------------------------------------
2008-03-05 09:52:00 -05:00
#pragma warning disable 0618
using System;
using System.Diagnostics;
using System.Net;
using System.Net.IP;
using System.Net.Sockets;
using System.Collections;
using Microsoft.SingSharp;
using Microsoft.Singularity;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Directory;
using NetStack.Contracts;
using NetStack.Channels.Public;
namespace Smb.Shared
{
class NetUtil
{
public static TcpContract.Imp:ReadyState! BindTcp()
{
TcpContract.Imp! tcp_imp;
TcpContract.Exp! tcp_exp;
TcpContract.NewChannel(out tcp_imp, out tcp_exp);
try {
DirectoryUtil.BindService(TcpContract.ModuleName, tcp_exp);
tcp_imp.RecvReady();
return tcp_imp;
2008-11-17 18:29:00 -05:00
}
catch (Exception ex) {
2008-03-05 09:52:00 -05:00
delete tcp_imp;
throw ex;
}
}
public static TcpConnectionContract.Imp:ReadyState! CreateTcpConnection()
{
TcpContract.Imp! tcp = BindTcp();
TcpConnectionContract.Imp! connection_imp;
TcpConnectionContract.Exp! connection_exp;
TcpConnectionContract.NewChannel(out connection_imp, out connection_exp);
tcp.SendCreateTcpSession(connection_exp);
2008-11-17 18:29:00 -05:00
switch receive {
2008-03-05 09:52:00 -05:00
case tcp.Ack():
delete tcp;
connection_imp.RecvReady();
// DebugStub.WriteLine("Successfully created TCP connection.");
return connection_imp;
case tcp.ChannelClosed():
delete tcp;
throw new Exception("A TCP connection could not be created. The TCP module closed its channel.");
case unsatisfiable:
delete tcp;
throw new Exception("A TCP connection could not be created. Unsatisfiable select.");
}
}
public static TcpConnectionContract.Imp:Connected! ConnectAny(string! hostname, int port)
{
try {
IPv4 ip_address;
if (IPv4.Parse(hostname, out ip_address)) {
// A single address.
return Connect((uint)ip_address, port);
}
IPHostEntry hostentry = Dns.GetHostByName(hostname);
if (hostentry == null)
throw new Exception("DNS resolution failed.");
IPAddress[] addresses = hostentry.AddressList;
if (addresses == null)
throw new Exception("Host entry did not return addresses.");
if (addresses.Length == 0)
throw new Exception("This hostname does not have any addresses.");
if (addresses.Length == 1) {
return Connect((uint)((!)addresses[0]).Address, port);
}
foreach (IPAddress addr in addresses) {
IPAddress address = (!)addr;
TcpConnectionContract.Imp:ReadyState! conn = CreateTcpConnection();
conn.SendConnect((uint)address.Address, (ushort)port);
switch receive {
case conn.OK():
return conn;
case unsatisfiable:
delete conn;
throw new Exception("Unsatisfiable read");
case conn.CouldNotConnect(error):
delete conn;
continue;
}
}
throw new Exception(String.Format("All attempts to connect to the host failed. {0} addresses were attempted.", addresses.Length));
2008-11-17 18:29:00 -05:00
}
catch (Exception ex) {
2008-03-05 09:52:00 -05:00
throw new Exception(String.Format("Failed to connect to hostname '{0}'.", hostname), ex);
}
}
public static TcpConnectionContract.Imp:Connected! Connect(uint ipv4_address, int port)
{
TcpConnectionContract.Imp:ReadyState! conn = CreateTcpConnection();
// The TCP/IP stack currently does not properly handle dynamic client endpoints.
// It will will reuse a local TCP port before it ought to. So if you are attempting
// to connect to the same remote address:port as a previous connection, you'll wind
// up with the exact same TCP tuple. The remote endpoint will either reset the
// connection, or will simply not respond. So, for now, we just pick a random local
// port, in the dynamic range. The right thing to do is to fix the Singularity
// TCP/IP service; this is just a temporary work-around.
// conn.SendBindLocalEndPoint(0, 0);
Random rand = new Random();
int localPort = rand.Next(30000) + 1024;
conn.SendBindLocalEndPoint(0, (ushort)localPort);
switch receive {
case conn.OK():
// DebugStub.WriteLine("Socket bound");
break;
case conn.InvalidEndPoint():
DebugStub.WriteLine("bind: InvalidEndPoint");
throw new Exception("The TCP/IP driver refused the bind request.");
case conn.ChannelClosed():
throw new Exception("TCP/IP driver closed channel during bind!");
}
conn.SendConnect(ipv4_address, (ushort)port);
IPv4 addr = new IPv4(ipv4_address);
switch receive {
case conn.OK():
return conn;
case unsatisfiable:
delete conn;
throw new Exception(String.Format("Could not connect to TCP destination '{0}'. Unsatisfiable read.", addr.ToString()));
case conn.CouldNotConnect(error):
delete conn;
throw new Exception(String.Format("Could not connect to TCP destination '{0}:{1}': {2}", addr.ToString(), port.ToString(), TcpException.GetMessageForTcpError(error)));
}
}
}
}