Skip to content

Instantly share code, notes, and snippets.

@afish
Created March 11, 2023 12:19
Show Gist options
  • Save afish/4cc0c6c879b0a463909d3a1867fc2971 to your computer and use it in GitHub Desktop.
Save afish/4cc0c6c879b0a463909d3a1867fc2971 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace FileProxy
{
class Program
{
static void Main(string[] args)
{
if (args.Length < 2)
{
Exit(Usage());
}
if (args[0] == "client")
{
Client.Start(args);
}
else if (args[0] == "server")
{
Server.Start(args);
}
else
{
Exit(Usage());
}
}
private static string Usage()
{
return "FileProxy.exe client local_port client_directory server_directory\nFileProxy.exe server destination_ip:destination_port client_directory server_directory";
}
private static void Exit(string message)
{
Console.WriteLine(message);
Environment.Exit(0);
}
}
class Server
{
public static void Start(string[] args)
{
var destinationIp = args[1].Split(':')[0];
var destinationPort = int.Parse(args[1].Split(':')[1]);
var clientDirectory = args[2];
var serverDirectory = args[3];
Console.WriteLine($"Routing to {destinationIp}:{destinationPort} via {clientDirectory}<=>{serverDirectory}");
var existingFiles = new HashSet<string>();
while (true)
{
try
{
while (true)
{
foreach (var file in Directory.EnumerateFiles(serverDirectory).Select(Path.GetFileName))
{
if (existingFiles.Add(file))
{
Console.WriteLine("New connection accepted to be scattered: " + file);
// I'm forcing IPv4 (IPv6 breaks with Cisco AnyConnect)
IPEndPoint remoteEP = new IPEndPoint(Dns.GetHostEntry(destinationIp).AddressList.First(a => a.AddressFamily == AddressFamily.InterNetwork), destinationPort);
Socket senderSocket = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
senderSocket.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}", senderSocket.RemoteEndPoint);
new Thread(() =>
{
var socket = new FileSocket(senderSocket, int.Parse(file), serverDirectory,
clientDirectory, r => { }, s => { });
socket.Start();
}).Start();
}
}
Thread.Sleep(1000);
}
}
catch (Exception e)
{
Console.WriteLine("Exception " + e);
}
}
}
}
public class Client
{
private static Random random = new Random();
public static void Start(string[] args)
{
var localPort = int.Parse(args[1]);
var clientDirectory = args[2];
var serverDirectory = args[3];
Console.WriteLine($"Routing from {localPort} via {clientDirectory}<=>{serverDirectory}");
IPEndPoint localEndPoint = new IPEndPoint(0, localPort);
Socket listener = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(100);
var totalSent = new Dictionary<string, long>();
var totalReceived = new Dictionary<string, long>();
var totalExceptions = new Dictionary<string, long>();
var localDnss = new[] {"localhost"};
foreach (var localDns in localDnss)
{
totalSent[localDns] = 0;
totalReceived[localDns] = 0;
totalExceptions[localDns] = 0;
}
new Thread(() =>
{
while (true)
{
Console.Write(DateTime.Now);
Console.Write(" E/S/R:\t");
Console.WriteLine(string.Join("\t", localDnss.Select(dns => $"{dns}: {totalExceptions[dns]}/{totalSent[dns]}/{totalReceived[dns]}")));
Thread.Sleep(3000);
}
}).Start();
while (true)
{
try
{
while (true)
{
Socket socket = listener.Accept();
Console.WriteLine("New connection accepted to be scattered");
new Thread(() => Start(socket, localDnss, clientDirectory, serverDirectory, random.Next(), totalSent, totalReceived, totalExceptions)).Start();
}
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e);
}
}
}
private static void Start(Socket clientSocket,string[] localDnss, string clientDirectory, string serverDirectory, int identifier,
Dictionary<string, long> sent, Dictionary<string, long> received, Dictionary<string, long> exceptions)
{
try
{
var fileSocket = new FileSocket(clientSocket, identifier, clientDirectory, serverDirectory, r => received[localDnss[0]]+= r, s => sent[localDnss[0]]+=s);
fileSocket.Start();
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e);
}
}
}
public class FileSocket
{
private Socket clientSocket;
private int identifier;
string readingDirectory;
private string writingDirectory;
private Action<int> received;
private Action<int> sent;
public FileSocket(Socket socket, int identifier, string readingDirectory, string writingDirectory, Action<int> received, Action<int> sent)
{
this.clientSocket = socket;
this.identifier = identifier;
this.readingDirectory = readingDirectory;
this.writingDirectory = writingDirectory;
this.received = received;
this.sent = sent;
}
public void Start()
{
Thread clientThread = new Thread(() =>
{
try
{
var buffer = new byte[100000];
var path = Path.Combine(writingDirectory, identifier + "");
while (true)
{
var read = clientSocket.Receive(buffer);
if (read == 0)
{
throw new Exception("Socket was closed");
}
while (true)
{
try
{
using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
stream.Write(buffer, 0, read);
sent(read);
break;
}
}
catch (Exception e2)
{
Console.WriteLine("Exception when writing to file" + e2);
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Exception " + e);
clientSocket.Close();
}
});
try
{
Thread senderThread = new Thread(KeepReading);
senderThread.Start();
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e);
}
clientThread.Start();
clientThread.Join();
}
private void KeepReading()
{
int totalRead = 0;
int toRead = 100024;
var locker = new ManualResetEventSlim();
var watcher = new FileSystemWatcher(readingDirectory);
watcher.NotifyFilter = NotifyFilters.LastWrite
| NotifyFilters.Size;
watcher.Changed += (e, s) => { locker.Set(); };
watcher.Error += (e, s) => { locker.Set(); };
watcher.EnableRaisingEvents = true;
byte[] bytes = new byte[toRead];
while (true)
{
try
{
using (FileStream fileStream = new FileStream(Path.Combine(readingDirectory, identifier + ""), FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
while (true)
{
fileStream.Seek(totalRead, SeekOrigin.Begin);
int howMuchRead = fileStream.Read(bytes, 0, toRead);
if (howMuchRead == 0)
break;
totalRead += howMuchRead;
received(howMuchRead);
clientSocket.Send(bytes, 0, howMuchRead, SocketFlags.None);
}
}
}
catch (Exception e)
{
Console.WriteLine("Exception while reading: " + e);
}
locker.Wait();
locker.Reset();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment