Files
shadowsocks-windows/shadowsocks-csharp/Local.cs
T
2013-01-14 18:31:17 +08:00

300 lines
8.8 KiB
C#
Executable File

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace shadowsocks_csharp
{
class Local
{
private int port;
private Encryptor encryptor;
Socket listener;
public Local(int port)
{
this.port = port;
this.encryptor = new Encryptor("barfoo!");
}
public void Start()
{
// Create a TCP/IP socket.
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndPoint = new IPEndPoint(0, port);
// Bind the socket to the local endpoint and listen for incoming connections.
listener.Bind(localEndPoint);
listener.Listen(100);
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
}
public void Stop()
{
listener.Close();
}
public void AcceptCallback(IAsyncResult ar)
{
try
{
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
Socket conn = listener.EndAccept(ar);
// Create the state object.
Handler handler = new Handler();
handler.connection = conn;
handler.encryptor = encryptor;
handler.Start();
//handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
// new AsyncCallback(ReadCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
class Handler
{
public Encryptor encryptor;
// Client socket.
public Socket remote;
public Socket connection;
// Size of receive buffer.
public const int BufferSize = 1500;
// remote receive buffer
public byte[] remoteBuffer = new byte[BufferSize];
// connection receive buffer
public byte[] connetionBuffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
public void Start()
{
// TODO async resolving
IPHostEntry ipHostInfo = Dns.GetHostEntry("127.0.0.1");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 8388);
remote = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
remote.BeginConnect(remoteEP,
new AsyncCallback(connectCallback), null);
}
private void connectCallback(IAsyncResult ar)
{
try
{
// Complete the connection.
remote.EndConnect(ar);
Console.WriteLine("Socket connected to {0}",
remote.RemoteEndPoint.ToString());
handshakeReceive();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void handshakeReceive()
{
try
{
connection.BeginReceive(new byte[256], 0, 256, 0,
new AsyncCallback(handshakeReceiveCallback), null);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void handshakeReceiveCallback(IAsyncResult ar)
{
try
{
int bytesRead = connection.EndReceive(ar);
if (bytesRead > 0)
{
byte[] response = { 5, 0 };
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(handshakeSendCallback), null);
}
else
{
// TODO error
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void handshakeSendCallback(IAsyncResult ar)
{
try
{
connection.EndSend(ar);
// +----+-----+-------+------+----------+----------+
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
// +----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +----+-----+-------+------+----------+----------+
// Skip first 3 bytes
// TODO validate
connection.BeginReceive(new byte[3], 0, 3, 0,
new AsyncCallback(handshakeReceive2Callback), null);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void handshakeReceive2Callback(IAsyncResult ar)
{
try
{
int bytesRead = connection.EndReceive(ar);
if (bytesRead > 0)
{
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(startPipe), null);
}
else
{
// TODO error
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void startPipe(IAsyncResult ar)
{
try
{
connection.EndReceive(ar);
remote.BeginReceive(remoteBuffer, 0, BufferSize, 0,
new AsyncCallback(pipeRemoteReceiveCallback), null);
connection.BeginReceive(connetionBuffer, 0, BufferSize, 0,
new AsyncCallback(pipeConnectionReceiveCallback), null);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void pipeRemoteReceiveCallback(IAsyncResult ar)
{
try
{
int bytesRead = remote.EndReceive(ar);
if (bytesRead > 0)
{
encryptor.Decrypt(remoteBuffer, bytesRead);
connection.BeginSend(remoteBuffer, 0, bytesRead, 0, new AsyncCallback(pipeConnectionSendCallback), null);
}
else
{
// TODO error
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void pipeConnectionReceiveCallback(IAsyncResult ar)
{
try
{
int bytesRead = connection.EndReceive(ar);
if (bytesRead > 0)
{
encryptor.Encrypt(connetionBuffer, bytesRead);
remote.BeginSend(connetionBuffer, 0, bytesRead, 0, new AsyncCallback(pipeRemoteSendCallback), null);
}
else
{
// TODO error
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void pipeRemoteSendCallback(IAsyncResult ar)
{
try
{
remote.EndSend(ar);
connection.BeginReceive(this.connetionBuffer, 0, BufferSize, 0,
new AsyncCallback(pipeConnectionReceiveCallback), null);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void pipeConnectionSendCallback(IAsyncResult ar)
{
try
{
connection.EndSend(ar);
remote.BeginReceive(this.remoteBuffer, 0, BufferSize, 0,
new AsyncCallback(pipeRemoteReceiveCallback), null);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}