/* This file is part of IFS. IFS is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. IFS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with IFS. If not, see . */ using IFS.BSP; using IFS.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.IO; namespace IFS.EFTP { /// /// EFTP: It's like a really limited version of BSP. /// This is not a standalone server like FTP but provides routines for sending / receiving data /// via EFTP, so that actual servers (Boot, Printing, etc.) can serve their clients. /// public static class EFTPManager { static EFTPManager() { _activeChannels = new Dictionary(); } public static void Shutdown() { foreach(EFTPChannel channel in _activeChannels.Values) { channel.Destroy(); } } public static void SendFile(PUPPort destination, Stream data) { UInt32 socketID = SocketIDGenerator.GetNextSocketID(); EFTPChannel newChannel = new EFTPChannel(destination, socketID); _activeChannels.Add(socketID, newChannel); EFTPSend.StartSend(newChannel, data); } public static void RecvData(PUP p) { EFTPChannel channel = FindChannelForPup(p); if (channel == null) { Log.Write(LogType.Error, LogComponent.EFTP, "Received EFTP PUP on an unconnected socket, ignoring."); return; } switch (p.Type) { case PupType.EFTPData: { channel.RecvData(p); } break; case PupType.EFTPAck: { channel.RecvAck(p); } break; case PupType.EFTPEnd: { channel.End(p); } break; case PupType.EFTPAbort: { string abortMessage = Helpers.ArrayToString(p.Contents); Log.Write(LogType.Warning, LogComponent.RTP, String.Format("EFTP aborted, message: '{0}'", abortMessage)); DestroyChannel(channel); } break; default: throw new NotImplementedException(String.Format("Unhandled EFTP PUP type {0}.", p.Type)); } } /// /// Indicates whether a channel exists for the socket specified by the given PUP. /// /// /// public static bool ChannelExistsForSocket(PUP p) { return FindChannelForPup(p) != null; } /// /// Destroys and unregisters the specified channel. /// /// public static void DestroyChannel(EFTPChannel channel) { channel.Destroy(); _activeChannels.Remove(channel.ServerPort.Socket); } public static IEnumerable EnumerateActiveChannels() { return _activeChannels.Values; } /// /// Finds the appropriate channel for the given PUP. /// /// /// private static EFTPChannel FindChannelForPup(PUP p) { if (_activeChannels.ContainsKey(p.DestinationPort.Socket)) { return _activeChannels[p.DestinationPort.Socket]; } else { return null; } } /// /// Map from socket address to BSP channel /// private static Dictionary _activeChannels; } }