|
@@ -1,9 +1,9 @@
|
|
|
using System;
|
|
|
+using System.Collections.Generic;
|
|
|
using System.IO;
|
|
|
using System.Net;
|
|
|
using System.Net.Sockets;
|
|
|
using System.Threading;
|
|
|
-using TftpServer.Utils;
|
|
|
|
|
|
namespace TftpServer
|
|
|
{
|
|
@@ -11,24 +11,32 @@ namespace TftpServer
|
|
|
{
|
|
|
private static bool _isRunning;
|
|
|
private static string Root;
|
|
|
+ private static int TimeOutSecond = 10;
|
|
|
+
|
|
|
private static void Main(string[] args)
|
|
|
{
|
|
|
Console.WriteLine("Starting...");
|
|
|
|
|
|
Root = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Properties.Settings.Default.Root);
|
|
|
+ if (false == Directory.Exists(Root))
|
|
|
+ {
|
|
|
+ Console.WriteLine("Error: Root path no exist");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var tWorker = new Thread(Working);
|
|
|
+ _isRunning = true;
|
|
|
+ tWorker.Start();
|
|
|
|
|
|
- var tWorker = new Thread(Working);
|
|
|
- _isRunning = true;
|
|
|
- tWorker.Start();
|
|
|
-
|
|
|
- Console.WriteLine("Press ENTER to Stop.");
|
|
|
- Console.ReadLine();
|
|
|
+ Console.WriteLine("Press ENTER to Stop.");
|
|
|
+ Console.ReadLine();
|
|
|
|
|
|
- Console.Write("Shutting down...");
|
|
|
- _isRunning = false;
|
|
|
- tWorker.Join();
|
|
|
+ Console.Write("Shutting down...");
|
|
|
+ _isRunning = false;
|
|
|
+ tWorker.Join();
|
|
|
|
|
|
- Console.Write("Stopped.");
|
|
|
+ Console.Write("Stopped.");
|
|
|
+ }
|
|
|
|
|
|
Console.WriteLine();
|
|
|
Console.Write("Press ENTER to Exit.");
|
|
@@ -46,48 +54,150 @@ namespace TftpServer
|
|
|
};
|
|
|
socket.Bind(listenEndPoint);
|
|
|
|
|
|
+ var dicSessions = new Dictionary<EndPoint, TftpTransferSession>();
|
|
|
+ var dicBlockReaders = new Dictionary<string, BlockReader>();
|
|
|
+
|
|
|
+ BlockReader GetBlockReader(string path)
|
|
|
+ {
|
|
|
+ if (dicBlockReaders.TryGetValue(path, out var br))
|
|
|
+ {
|
|
|
+ return br;
|
|
|
+ }
|
|
|
+
|
|
|
+ br = new BlockReader(path);
|
|
|
+ dicBlockReaders[path] = br;
|
|
|
+ return br;
|
|
|
+ }
|
|
|
+
|
|
|
var upTime = DateTime.Now;
|
|
|
|
|
|
Console.WriteLine($"TFTP Server started, listing on: {listenEndPoint}");
|
|
|
|
|
|
var buffer = new byte[65536];
|
|
|
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 68);
|
|
|
- var polling = DateTime.Now;
|
|
|
+ var pollingTime = DateTime.Now;
|
|
|
while (_isRunning)
|
|
|
{
|
|
|
Console.CursorLeft = 0;
|
|
|
+
|
|
|
+ //TODO: Timeout
|
|
|
+
|
|
|
if (false == socket.Poll(500 * 1000, SelectMode.SelectRead))
|
|
|
{
|
|
|
- var timeSpan = DateTime.Now - polling;
|
|
|
+ var polling = DateTime.Now - pollingTime;
|
|
|
var up = DateTime.Now - upTime;
|
|
|
Console.Write($"Polling..." +
|
|
|
- $" {timeSpan.Days:00}D {timeSpan.Hours:00}H {timeSpan.Minutes:00}M {timeSpan.Seconds:00}S {timeSpan.Milliseconds:000}" +
|
|
|
+ $" {polling.Days:00}D {polling.Hours:00}H {polling.Minutes:00}M {polling.Seconds:00}S {polling.Milliseconds:000}" +
|
|
|
$" / UP {up.Days:00}D {up.Hours:00}H {up.Minutes:00}M {up.Seconds:00}S {up.Milliseconds:000}");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- polling = DateTime.Now;
|
|
|
Console.WriteLine();
|
|
|
|
|
|
- var bytes = socket.ReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref remoteEndPoint);
|
|
|
- Console.Write($"Receive {bytes} byte From {remoteEndPoint}");
|
|
|
-
|
|
|
- try
|
|
|
+ do
|
|
|
{
|
|
|
- var packet = new TftpPacket(buffer, bytes);
|
|
|
- switch (packet.OpCode)
|
|
|
- {
|
|
|
- default:
|
|
|
+ var bytes = socket.ReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref remoteEndPoint);
|
|
|
+ Console.Write($"Receive {bytes} byte From {remoteEndPoint}");
|
|
|
|
|
|
- break;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var packet = new TftpPacket(buffer, bytes);
|
|
|
+ Console.Write($" OpCode:{packet.OpCode}");
|
|
|
+
|
|
|
+ TftpTransferSession session;
|
|
|
+ switch (packet.OpCode)
|
|
|
+ {
|
|
|
+ default: throw new NotImplementedException();
|
|
|
+
|
|
|
+ case TftpOpCode.Error:
|
|
|
+ Console.Write($" {packet.ErrorNumber} 0x{(short)packet.ErrorNumber:X4} {packet.ErrorMessage}");
|
|
|
+ if (dicSessions.Remove(remoteEndPoint))
|
|
|
+ {
|
|
|
+ Console.Write(" Session closed");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TftpOpCode.Read:
|
|
|
+ Console.Write($" FileName:{packet.FileName} [{packet.Mode}] BlockSize:{packet.BlockSize}");
|
|
|
+ var path = Path.Combine(Root, packet.FileName.TrimStart('/'));
|
|
|
+ if (false == File.Exists(path))
|
|
|
+ {
|
|
|
+ Console.Write(" ** File Not Found");
|
|
|
+ var response = new TftpPacket("File Not Found", TftpErrorNumber.FileNoFound);
|
|
|
+ bytes = response.WriteToBuffer(buffer);
|
|
|
+
|
|
|
+ Console.WriteLine();
|
|
|
+ Console.Write($"Send {bytes} bytes to {remoteEndPoint} OpCode:{response.OpCode} Message:{response.ErrorMessage}");
|
|
|
+ socket.SendTo(buffer, 0, bytes, SocketFlags.None, remoteEndPoint);
|
|
|
+ }
|
|
|
+ else if (0 == packet.TransferSize)
|
|
|
+ {
|
|
|
+ var response = new TftpPacket(TftpOpCode.OptionAck) { TransferSize = (int?)new FileInfo(path).Length };
|
|
|
+ bytes = response.WriteToBuffer(buffer);
|
|
|
+
|
|
|
+ Console.WriteLine();
|
|
|
+ Console.Write($"Send {bytes} bytes to {remoteEndPoint} OpCode:{response.OpCode} TransferSize:{response.TransferSize}");
|
|
|
+ socket.SendTo(buffer, 0, bytes, SocketFlags.None, remoteEndPoint);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ session = new TftpTransferSession(path, packet.BlockSize);
|
|
|
+ var response = new TftpPacket(1, session.BlockBuffer, session.Read(1, GetBlockReader(path)));
|
|
|
+ bytes = response.WriteToBuffer(buffer);
|
|
|
+ Console.WriteLine();
|
|
|
+ Console.Write($"Transfer session <{remoteEndPoint}> start. Path: <{session.FilePath}>");
|
|
|
+
|
|
|
+ Console.WriteLine();
|
|
|
+ Console.Write($"Send {bytes} bytes to {remoteEndPoint} OpCode:{response.OpCode} BlockNumber:{response.BlockNumber}/{session.BlockCount}");
|
|
|
+ socket.SendTo(buffer, 0, bytes, SocketFlags.None, remoteEndPoint);
|
|
|
+ dicSessions[remoteEndPoint] = session;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TftpOpCode.Ack:
|
|
|
+ Console.Write($" BlockNumber:{packet.BlockNumber}");
|
|
|
+ if (dicSessions.TryGetValue(remoteEndPoint, out session))
|
|
|
+ {
|
|
|
+ if (packet.BlockNumber == session.BlockCount)
|
|
|
+ {
|
|
|
+ Console.WriteLine();
|
|
|
+ Console.Write($"Transfer complete session <{remoteEndPoint}> closed");
|
|
|
+ dicSessions.Remove(remoteEndPoint);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var nextBlockNumber = packet.BlockNumber;
|
|
|
+ ++nextBlockNumber;
|
|
|
+
|
|
|
+ var response = new TftpPacket(nextBlockNumber, session.BlockBuffer, session.Read(nextBlockNumber, GetBlockReader(session.FilePath)));
|
|
|
+ bytes = response.WriteToBuffer(buffer);
|
|
|
+
|
|
|
+ Console.WriteLine();
|
|
|
+ Console.Write($"Send {bytes} bytes to {remoteEndPoint} OpCode:{response.OpCode} BlockNumber:{response.BlockNumber}/{session.BlockCount}");
|
|
|
+ socket.SendTo(buffer, 0, bytes, SocketFlags.None, remoteEndPoint);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Console.Write(" ** Transfer session Not Found");
|
|
|
+ var response = new TftpPacket("Session not found", TftpErrorNumber.UnknownTransferId);
|
|
|
+ bytes = response.WriteToBuffer(buffer);
|
|
|
+
|
|
|
+ Console.WriteLine();
|
|
|
+ Console.Write($"Send {bytes} bytes to {remoteEndPoint} OpCode:{response.OpCode} Message:{response.ErrorMessage}");
|
|
|
+ socket.SendTo(buffer, 0, bytes, SocketFlags.None, remoteEndPoint);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ Console.Write(e);
|
|
|
}
|
|
|
+ Console.WriteLine();
|
|
|
+ } while (socket.Poll(50 * 1000, SelectMode.SelectRead));
|
|
|
|
|
|
- }
|
|
|
- catch (Exception e)
|
|
|
- {
|
|
|
- Console.WriteLine(e);
|
|
|
- }
|
|
|
- Console.WriteLine();
|
|
|
+ pollingTime = DateTime.Now;
|
|
|
}
|
|
|
}
|
|
|
}
|