www.pudn.com > TFTPUtil_Class_Version_1.3.0.zip > TFTPServer.cs


using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Collections; 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 
using NSpring.Logging; 
using NSpring.Logging.Loggers; 
 
namespace TFTPUtil 
{ 
    ///  
    /// The TFTPUtil Server Main Listener Class 
    ///  
    public class TFTPServer 
    { 
        #region VARS 
        private struct ProcessStruct 
        { 
            public Thread thread; 
            public TFTPServerProcess process; 
            public ThreadStart threadStart; 
 
            public ProcessStruct(ref Thread thread_, ref ThreadStart threadStart_, ref TFTPServerProcess process_) 
            { 
                thread = thread_; 
                process = process_; 
                threadStart = threadStart_; 
            } 
        } 
        private string LoggingMethodOptions = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; 
        private int ResendInterval = 1;                     //How many seconds before resending 
        private int Timeout = 10;                           //How many seconds before counting TID timedout 
        ///  
        /// Allow RFC 2347 (TFTP Option Extension) 
        ///  
        public bool AllowOptions = true; 
        ///  
        /// Specifies if we allow read requests 
        ///  
        public bool AllowRRQ = true; 
        ///  
        /// Specifies if we allow write requests 
        ///  
        public bool AllowWRQ = false; 
        ///  
        /// Specifies if write requests can overwrite an existing file 
        ///  
        public bool AllowWRQOverwrite = false; 
        private int ListenerPort = 69;                      //The UDP port we should be listening for requests on 
        private const int MaxRecvSize = 65468;              //Maximum  receive size in bytes 
        private bool Loop = false;                          //Controls if we should be receiving datagrams 
        ///  
        /// Check for existing TIDs in RRQ and WRQ requests 
        ///  
        public bool RRQWRQStateCheck = true; 
        private IPEndPoint myEndpoint;                      //The IPEndPoint that the server is using 
        private Socket mySocket;                            //The socket the server is using 
        private Timer CheckTimer;                           //Timer object that goes through active states 
        private List CurrStates = new List(10);   //List to keep track of currently spawned TFTPServerProcess 
        //private List CurrStates = new List(10); 
        Logger logger = new WindowsEventLogger(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name); 
        private bool ClientMode = false; 
        private string ClientHost; 
        private string FullPath = System.IO.Directory.GetCurrentDirectory(); 
        ///  
        /// The TFTP server event handler 
        ///  
        public event TFTPServerEventHandler TFTPServerEvent; 
        public event TFTPServerTransferEventHandler TFTPServerTransferEvent; 
        private readonly object CurrStatesLock = new object(); 
        private Level EventLevel = Level.Info; 
        private Level LogLevel = Level.Info; 
        private IPAddress[] BadIPs; 
        //public delegate void TFTPStateEventHandler(object o, TFTPServerTransferEventArgs e); 
        public delegate void TFTPServerProcessHandler(object o, TFTPServerProcessEventArgs e); 
        ///  
        /// A byte array of ASCII characters representing the TFTP error number 1 
        ///  
        public readonly byte[] Error1 = { 0, 5, 0, 1, 70, 105, 108, 101, 32, 110, 111, 116, 32, 102, 111, 117, 110, 100, 46, 0 }; 
        ///  
        /// A byte array of ASCII characters representing the TFTP error number 2 
        ///  
        public readonly byte[] Error2 = { 0, 5, 0, 2, 65, 99, 99, 101, 115, 115, 32, 118, 105, 111, 108, 97, 116, 105, 111, 110, 46, 0 }; 
        ///  
        /// A byte array of ASCII characters representing the TFTP error number 3 
        ///  
        public readonly byte[] Error3 = { 0, 5, 0, 3, 68, 105, 115, 107, 32, 102, 117, 108, 108, 32, 111, 114, 32, 97, 108, 108, 111, 99, 97, 116, 105, 111, 110, 32, 101, 120, 99, 101, 101, 100, 101, 100, 46, 0 }; 
        ///  
        /// A byte array of ASCII characters representing the TFTP error number 4 
        ///  
        public readonly byte[] Error4 = { 0, 5, 0, 4, 73, 108, 108, 101, 103, 97, 108, 32, 84, 70, 84, 80, 32, 111, 112, 101, 114, 97, 116, 105, 111, 110, 46, 0 }; 
        ///  
        /// A byte array of ASCII characters representing the TFTP error number 5 
        ///  
        public readonly byte[] Error5 = { 0, 5, 0, 5, 85, 110, 107, 110, 111, 119, 110, 32, 116, 114, 97, 110, 115, 102, 101, 114, 32, 73, 68, 46, 0 }; 
        ///  
        /// A byte array of ASCII characters representing the TFTP error number 6 
        ///  
        public readonly byte[] Error6 = { 0, 5, 0, 6, 70, 105, 108, 101, 32, 97, 108, 114, 101, 97, 100, 121, 32, 101, 120, 105, 115, 116, 115, 46, 0 }; 
        ///  
        /// A byte array of ASCII characters representing the TFTP error number 7 
        ///  
        public readonly byte[] Error7 = { 0, 5, 0, 7, 78, 111, 32, 115, 117, 99, 104, 32, 117, 115, 101, 114, 46, 0 }; 
        ///  
        /// A byte array of ASCII characters representing the TFTP error number 8 
        ///  
        public readonly byte[] Error8 = { 0, 5, 0, 8, 84, 114, 97, 110, 115, 102, 101, 114, 32, 116, 101, 114, 109, 105, 110, 97, 116, 101, 100, 32, 100, 117, 101, 32, 116, 111, 32, 111, 112, 116, 105, 111, 110, 32, 110, 101, 116, 105, 97, 116, 105, 111, 110, 46, 0}; 
        ///  
        /// A byte array of ASCII characters representing the "unknown error" 
        ///  
        public readonly byte[] ErrorUnknown = { 0, 5, 0, 0, 65, 110, 32, 117, 110, 107, 110, 107, 110, 111, 119, 110, 32, 101, 114, 114, 111, 114, 32, 111, 99, 99, 117, 114, 114, 101, 100, 46, 0 }; 
        Thread testthread; 
        #endregion 
 
        ///  
        /// Creates an instance of the TFTPServer class 
        ///  
        public TFTPServer() 
        { 
            SetIPAddr(); 
            AddMsg(Level.Verbose, myEndpoint.ToString()); 
        } 
 
        ///  
        /// Creates an instance of the TFTPServer class 
        ///  
        /// A string specifying the path the TFTP server should retrieve files from 
        public TFTPServer(string FilePath) 
        { 
            if (System.IO.Directory.Exists(FilePath)) 
                FullPath = FilePath; 
            SetIPAddr(); 
            AddMsg(Level.Verbose, myEndpoint.ToString()); 
        } 
 
        ///  
        /// Creates an instance of the TFTPServer class 
        ///  
        /// An integer specifying the UDP Port the TFTP server should listen on 
        public TFTPServer(int UDP_Port) 
        { 
            ListenerPort = UDP_Port; 
            SetIPAddr(); 
        } 
 
        ///  
        /// Creates an instance of the TFTPServer class 
        ///  
        /// An IPAddress specifying the local IP address the TFTP seerver should listen on 
        public TFTPServer(IPAddress IPAddr) 
        { 
            SetIPAddr(IPAddr); 
        } 
 
        ///  
        /// Creates an instance of the TFTPServer class 
        ///  
        /// An integer specifying the UDP Port the TFTP server should listen on 
        /// An IPAddress specifying the local IP address the TFTP seerver should listen on 
        public TFTPServer(int UDP_Port, IPAddress IPAddr) 
        { 
            ListenerPort = UDP_Port; 
            SetIPAddr(IPAddr); 
        } 
 
        ///  
        /// Creates an instance of the TFTPServer class 
        ///  
        /// An integer specifying the UDP Port the TFTP server should listen on 
        /// A string specifying the path the TFTP server should retrieve files from 
        public TFTPServer(int UDP_Port, string FilePath) 
        { 
            ListenerPort = UDP_Port; 
            if (System.IO.Directory.Exists(FilePath)) 
                FullPath = FilePath; 
            SetIPAddr(); 
            AddMsg(Level.Verbose, myEndpoint.ToString()); 
        } 
 
        ///  
        /// Creates an instance of the TFTPServer class 
        ///  
        /// An integer specifying the UDP Port the TFTP server should listen on 
        /// An IPAddress specifying the local IP address the TFTP seerver should listen on 
        /// A string specifying the path the TFTP server should retrieve files from 
        public TFTPServer(int UDP_Port, IPAddress IPAddr, string FilePath) 
        { 
            ListenerPort = UDP_Port; 
            if (System.IO.Directory.Exists(FilePath)) 
                FullPath = FilePath; 
            SetIPAddr(IPAddr); 
        } 
 
        ///  
        /// Creates an instance of the TFTPServer class 
        ///  
        /// An integer specifying the UDP Port the TFTP server should listen on 
        /// A string specifying the path the TFTP server should retrieve files from 
        /// The NSpring level to log messages via the specified method 
        /// The NSpring level to log messages 
        /// A string representing what access clients have to files 
        /// If we shoud allow TFTP option extensions from TFTP clients 
        /// Defines if we should check for TIDs in read and write requests 
        /// An integer in milliseconds specifying how long before resending the last packet 
        /// An integer in milliseconds specifying how long before the request is timed out 
        /// A string specifying the parameters to use with the logging method 
        /// A string containing IP addresses to block 
        public TFTPServer(int UDP_Port, 
            string FilePath, 
            string LoggingLevel, 
            string DisplayLevel, 
            string FileAccess, 
            bool AllowTFTPOptions, 
            bool CheckReadWriteState, 
            int ResendInterval, 
            int TimeoutInterval, 
            string[] LoggingMethodInfo, 
            string IPs) 
        { 
            ListenerPortNumber = UDP_Port; 
            SetIPAddr(); 
            Path = FilePath; 
            this.LoggingLevel = LoggingLevel; 
            SendEventLevel = DisplayLevel; 
            AllowOptions = AllowTFTPOptions; 
            this.FileAccess(FileAccess); 
            RRQWRQStateCheck = CheckReadWriteState; 
            ResendIntervalSeconds = ResendInterval; 
            TimeoutSeconds = TimeoutInterval; 
            logger = new WindowsEventLogger(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name); 
            LoggingMethod = LoggingMethodInfo; 
            BlockedIPs = IPs; 
        } 
 
        ///  
        /// Creates an instance of the TFTPServer class 
        ///  
        /// An integer specifying the UDP Port the TFTP server should listen on 
        /// A string specifying the path the TFTP server should retrieve files from 
        /// The NSpring level to log messages via the specified method 
        /// The NSpring level to log messages 
        /// A string representing what access clients have to files 
        /// If we shoud allow TFTP option extensions from TFTP clients 
        /// Defines if we should check for TIDs in read and write requests 
        /// An integer in milliseconds specifying how long before resending the last packet 
        /// An integer in milliseconds specifying how long before the request is timed out 
        /// A string specifying the parameters to use with the logging method 
        /// A string containing IP addresses to block 
        /// An IPAddress specifying the local IP address the TFTP seerver should listen on 
        public TFTPServer(int UDP_Port, 
            string FilePath, 
            string LoggingLevel, 
            string DisplayLevel, 
            string FileAccess, 
            bool AllowTFTPOptions, 
            bool CheckReadWriteState, 
            int ResendInterval, 
            int TimeoutInterval, 
            string[] LoggingMethodInfo, 
            string IPs, 
            IPAddress IPAddr) 
        { 
            ListenerPortNumber = UDP_Port; 
            SetIPAddr(IPAddr); 
            Path = FilePath; 
            this.LoggingLevel = LoggingLevel; 
            SendEventLevel = DisplayLevel; 
            AllowOptions = AllowTFTPOptions; 
            this.FileAccess(FileAccess); 
            RRQWRQStateCheck = CheckReadWriteState; 
            ResendIntervalSeconds = ResendInterval; 
            TimeoutSeconds = TimeoutInterval; 
            logger = new WindowsEventLogger(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name); 
            LoggingMethod = LoggingMethodInfo; 
            BlockedIPs = IPs; 
        } 
 
        ///  
        /// Cleans up everything 
        ///  
        ~TFTPServer() 
        { 
            if (CheckTimer != null) 
                CheckTimer.Dispose(); 
 
            try 
            { 
                if (mySocket != null) 
                    mySocket.Shutdown(SocketShutdown.Receive); 
            } 
            catch (ObjectDisposedException ex) 
            { } 
            CurrStates.Clear(); 
            if (logger != null) 
                logger.Close(); 
        } 
 
        ///  
        /// Stops the TFTP server from listening for requests 
        ///  
        public void StopListener() 
        { 
            AddMsg(Level.Verbose, "Stopping Listening...");             
            Loop = false; 
            if (CheckTimer != null) 
                CheckTimer.Dispose(); 
 
            try 
            { 
                if (mySocket != null) 
                { 
                    mySocket.Shutdown(SocketShutdown.Both); //I think we want both here unlike the process 
                    mySocket.Close(); 
                } 
            } 
            catch (ObjectDisposedException ex) 
            { 
                AddMsg(Level.Verbose, "Caught socket object disposed exception"); 
                AddMsg(Level.Debug, "Socket exception: " + ex.Message); 
            } 
 
            lock (CurrStatesLock) 
            { 
                for (int StateIndex = 0; StateIndex < CurrStates.Count; StateIndex++) 
                { 
                    //CurrStates[StateIndex].StartListener(); 
                    CurrStates[StateIndex].process.StopListener(); 
                    CurrStates[StateIndex].process.MyClose(); 
                } 
                CurrStates.Clear(); 
            } 
            AddMsg(Level.Info, "Stopped Listening"); 
            logger.Close(); 
        } 
         
        ///  
        /// Starts the TFTP server listening for requests 
        ///  
        public void StartListener() 
        { 
            try 
            { 
                try 
                { 
                    logger.Open(); 
                } 
                catch 
                { 
                } 
                AddMsg(Level.Verbose, "Creating Socket"); 
                mySocket = new Socket(myEndpoint.Address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); 
 
                AddMsg(Level.Verbose, "Binding Socket"); 
                mySocket.Bind(myEndpoint); 
 
                StartCheckTimer(); 
 
                Loop = true; 
 
                AddMsg(Level.Verbose, "Starting to Listen"); 
                AddMsg(Level.Info, "Listening for requests on IP address " + myEndpoint.Address.ToString() + " port " + myEndpoint.Port.ToString()); 
                StartReceive(); 
            } 
            catch (SocketException ex) 
            { 
                Loop = false; 
                if (ex.ErrorCode == 10048) 
                { 
                    AddMsg(Level.Exception, "Unable to start listening on " + myEndpoint.Address.ToString() + " port " + myEndpoint.Port.ToString() + ". There maybe another service listening on that port."); 
                } 
                else 
                { 
                    AddMsg(Level.Verbose, "Handled StartListener socket exception: " + ex.Message); 
                    AddMsg(Level.Debug, "Handled StartListener socket exception at: " + ex.StackTrace); 
                    Loop = false; 
                } 
            } 
        } 
 
        private void StartCheckTimer() 
        { 
            CheckTimer = new Timer( 
                new TimerCallback(CheckStates), //Name of the method to call 
                null,   // Don't send a state object 
                1000,   // Start timer in 1 second 
                1000);  // Do callback every 1 second 
        } 
 
        private void CheckStates(object state) 
        { 
            AddMsg(Level.Debug, DateTime.Now.ToString() + " Server CheckStates timer callback started..."); 
            lock (CurrStatesLock) 
            { 
                if (CurrStates.Count > 0) 
                { 
                    List RemoveList = new List(CurrStates.Count); 
 
                    for (int StateIndex = 0; StateIndex < CurrStates.Count; StateIndex++) 
                    { 
                        //if (CurrStates[StateIndex] != null && CurrStates[StateIndex].IsListening) 
                        if (CurrStates[StateIndex].process != null && CurrStates[StateIndex].process.IsListening) 
                        { 
                            //CurrStates[StateIndex].CheckStates(); 
                            CurrStates[StateIndex].process.CheckStates(); 
                        } 
                        else 
                        { 
                            RemoveList.Add(StateIndex); 
                        } 
                    } 
 
                    for (int RemoveIndex = 0; RemoveIndex < RemoveList.Count; RemoveIndex++) 
                    { 
                        try 
                        { 
                            AddMsg(Level.Verbose, "Removing state at index " + ((int)RemoveList[RemoveIndex]).ToString()); 
                            //ProcessStruct currStruct = CurrStates[RemoveList[RemoveIndex]]; 
                            //if (CurrStates[RemoveList[RemoveIndex]] != null && CurrStates[RemoveList[RemoveIndex]].IsListening) 
                            if (CurrStates[RemoveList[RemoveIndex]].process != null) 
                            { 
                                CurrStates[RemoveList[RemoveIndex]].process.MyClose(); 
                            } 
 
                            if (CurrStates[RemoveList[RemoveIndex]].thread != null) 
                            { 
                                CurrStates[RemoveList[RemoveIndex]].thread.Interrupt(); 
                                //CurrStates[RemoveList[RemoveIndex]].thread.Abort(); 
                            } 
 
                            CurrStates[RemoveList[RemoveIndex]].threadStart = null; 
                            CurrStates[RemoveList[RemoveIndex]].process =null ; 
                            CurrStates[RemoveList[RemoveIndex]].thread = null; 
 
                            CurrStates.RemoveAt(RemoveList[RemoveIndex]); 
                            AddMsg(Level.Debug, "CheckStates Count after " + CurrStates.Count.ToString()); 
                        } 
                        catch 
                        { 
                            AddMsg(Level.Verbose, "An error occurred while trying to remove a state"); 
                        } 
                    } 
                } 
            } 
            AddMsg(Level.Debug, "...Server CheckStates timer callback finished " + DateTime.Now.ToString()); 
        } 
 
        private void StartReceive() 
        { 
            while (Loop) 
            { 
                bool ReceivedWorked = false; 
 
                //Setup maximum bytes to receive 
                Byte[] ReceivedBytes = new Byte[MaxRecvSize]; 
 
                //Create an EndPoint that will connect to any IP and any port 
                EndPoint tempPoint = new IPEndPoint(IPAddress.Any, 0); 
 
                AddMsg(Level.Verbose, "Waiting for datagram..."); 
                int NumBytesReceived = 0; 
                try 
                { 
                    NumBytesReceived = mySocket.ReceiveFrom(ReceivedBytes, ref tempPoint); 
 
                    ReceivedWorked = true; 
                } 
                catch (Exception ex) 
                { 
                    if (Loop) 
                    { 
                        AddMsg(Level.Info, "An error occurred while trying receive a packet"); 
                        AddMsg(Level.Verbose, "Handled receive packet exception: " + ex.Message); 
                        AddMsg(Level.Debug, "Handled receive packet exception at: " + ex.StackTrace); 
                    } 
                } 
 
                if (ReceivedWorked) 
                { 
                    IPEndPoint RemoteEndPoint = (IPEndPoint)tempPoint; 
 
                    AddMsg(Level.Verbose, "Received datagram from " + ((IPEndPoint)RemoteEndPoint).Address.ToString() + ":" + ((IPEndPoint)RemoteEndPoint).Port.ToString()); 
 
                    bool FoundMatch = true; 
                    if (ClientMode) 
                    { 
                        AddMsg(Level.Debug, "Entered ClientMode"); 
                        FoundMatch = false; 
                        bool IsIP = false; 
                        IPAddress HostAddr; 
 
                        IsIP = IPAddress.TryParse(ClientHost, out HostAddr); 
 
                        if ((HostAddr != null) && IsIP) 
                        { 
                            if (RemoteEndPoint.Address.Equals(HostAddr)) 
                                FoundMatch = true; 
                        } 
 
                        if (IsIP == false) 
                        { 
                            foreach (IPAddress ip in Dns.GetHostAddresses(ClientHost)) 
                            { 
                                if (RemoteEndPoint.Address.Equals(ip)) 
                                    FoundMatch = true; 
                            } 
                        } 
                    } 
 
                    bool FoundBadIPMatch = false; 
                    if (BadIPs.Length > 0) 
                    { 
                        AddMsg(Level.Debug, "Checking to see if IP is in list of bad IPs"); 
                        foreach (IPAddress addr in BadIPs) 
                        { 
                            if (RemoteEndPoint.Address.Equals(addr)) 
                                FoundBadIPMatch = true; 
                        } 
                        AddMsg(Level.Debug, "Finished bad IP check"); 
                    } 
 
                    if (FoundMatch) 
                    { 
                        if (FoundBadIPMatch == false) 
                        { 
                            ProcessDatagram(ReceivedBytes, NumBytesReceived, RemoteEndPoint); 
                        } 
                        else 
                        { 
                            AddMsg(Level.Info, "Blocking TFTP request from " + RemoteEndPoint.Address.ToString()); 
                        } 
                    } 
                } 
            } 
        } 
 
        private void ProcessDatagram(byte[] ReceivedBytes, int NumBytesReceived, IPEndPoint RemoteEndPoint) 
        { 
            int CurrOpcode = Convert.ToInt16(ReceivedBytes[1]); 
            string EndPointString = ((IPEndPoint)RemoteEndPoint).Address.ToString() + ":" + ((IPEndPoint)RemoteEndPoint).Port.ToString(); 
 
            AddMsg(Level.Verbose, "Found Opcode " + CurrOpcode.ToString() + " from " + EndPointString); 
 
            if ((CurrOpcode == 1) || (CurrOpcode == 2)) 
            { 
                TFTPServerProcessContainer container = new TFTPServerProcessContainer(); 
 
                container.process = new TFTPServerProcess(FullPath, 
                    LogLevel, 
                    EventLevel, 
                    AllowRRQ, 
                    AllowWRQ, 
                    AllowWRQOverwrite, 
                    AllowOptions, 
                    RRQWRQStateCheck, 
                    ResendInterval, 
                    Timeout, 
                    logger, 
                    myEndpoint.Address); 
 
                container.threadStart = new ThreadStart(container.process.StartListener); 
                container.thread = new Thread(container.threadStart); 
                container.thread.Name = "TFTP Server Process Thread: " + container.process.ident.ToString(); 
                container.thread.IsBackground = true; 
                container.thread.Start(); 
 
                lock (CurrStatesLock) 
                { 
                    //CurrStates.Add(tftpproc); 
                    CurrStates.Add(container); 
                } 
 
                for (int SleepCounter = 0; SleepCounter <= 5; SleepCounter++) 
                { 
                    if (container.process.IsListening) 
                    { 
                        container.process.ProcessDatagram(ReceivedBytes, NumBytesReceived, RemoteEndPoint); 
 
                        OnTFTPServerTransferEvent(new TFTPServerTransferEventArgs(container.process)); 
                        container.process.TFTPServerProcessEvent += new TFTPServerProcessEventHandler(this.TFTPProcessEventListener); 
 
                        SleepCounter = 10; 
                    } 
                    else 
                    { 
                        //Wait a little bit for the thread to start listening 
                        Thread.Sleep(100); 
                    } 
                } 
            } 
            else 
            { 
                AddMsg(Level.Verbose, "Sending error4 generated in default case " + EndPointString); 
                Send(RemoteEndPoint, Error4); 
            } 
        } 
 
        ///  
        ///  
        ///  
        ///  
        ///  
        public void TFTPProcessEventListener(object sender, TFTPServerProcessEventArgs e) 
        { 
            AddMsg(e.EventLevel, e.EventString); 
        } 
         
        private void Send(IPEndPoint RemoteEndPoint, byte[] Data) 
        { 
            try 
            { 
                mySocket.BeginSendTo(Data, 0, Data.Length, SocketFlags.None, RemoteEndPoint, new AsyncCallback(SendCallback), mySocket); 
            } 
            catch (Exception ex) 
            { 
                AddMsg(Level.Info, "A problem occurred while trying to send a packet to " + RemoteEndPoint.Address.ToString() + ":" + RemoteEndPoint.Port.ToString()); 
                AddMsg(Level.Verbose, "Handled exception in send : " + ex.Message); 
                AddMsg(Level.Debug, "Handled RRQ file exception: " + ex.StackTrace); 
            } 
        } 
 
        private void SendUnknownError(IPEndPoint RemoteEndPoint) 
        { 
            Send(RemoteEndPoint, ErrorUnknown); 
        } 
 
        private void SendCallback(IAsyncResult result) 
        { 
            //Socket s = (Socket)result.AsyncState; 
 
            //int send = s.EndSendTo(result); 
            ((Socket)result.AsyncState).EndSendTo(result); 
        } 
 
        ///  
        ///  
        ///  
        /// A string representing the DNS hostname or IP address to retrieve the file from 
        /// The port the Host TFTP server is listening o n 
        /// The filename to request from the Host 
        /// Indicates if we should request the file size 
        ///  
        ///  
        public void GetFile(string Host, int Port, string Filename, bool Filesize, int Timeout, int TransferSize) 
        { 
            TFTPServerProcessContainer container = new TFTPServerProcessContainer(); 
 
            container.process = new TFTPServerProcess(FullPath, 
                    LogLevel, 
                    EventLevel, 
                    AllowRRQ, 
                    AllowWRQ, 
                    AllowWRQOverwrite, 
                    AllowOptions, 
                    RRQWRQStateCheck, 
                    ResendInterval, 
                    Timeout, 
                    logger, 
                    myEndpoint.Address); 
 
            OnTFTPServerTransferEvent(new TFTPServerTransferEventArgs(container.process)); 
            container.process.TFTPServerProcessEvent += new TFTPServerProcessEventHandler(this.TFTPProcessEventListener); 
 
            ClientMode = true; 
            ClientHost = Host; 
            IPEndPoint RemoteEndPoint = new IPEndPoint(IPAddress.Parse(Host), Port); 
 
            container.threadStart = new ThreadStart(container.process.StartListener); 
            container.thread = new Thread(container.threadStart); 
            container.thread.Name = "TFTP Server Process Thread"; 
            container.thread.IsBackground = true; 
            container.thread.Start(); 
 
            lock (CurrStatesLock) 
            { 
                //CurrStates.Add(tftpproc); 
                CurrStates.Add(container); 
            } 
 
            for (int SleepCounter = 0; SleepCounter <= 5; SleepCounter++) 
            { 
                if (container.process.IsListening) 
                { 
                    container.process.GetFile(Host, Port, Filename, Filesize, Timeout, TransferSize); 
 
                    SleepCounter = 10; 
 
                    StartCheckTimer(); 
                } 
                else 
                { 
                    //Wait a little bit for the thread to start listening 
                    Thread.Sleep(100); 
                } 
            } 
        } 
 
        ///  
        ///  
        ///  
        /// A string representing the DNS hostname or IP address of the TFTP server to put the file on 
        /// The port the Host TFTP server is listening o n 
        /// The filename to put on the specified Host 
        /// Indicates if we should send the file size 
        ///  
        ///  
        public void PutFile(string Host, int Port, string Filename, bool Filesize, int Timeout, int TransferSize) 
        { 
            TFTPServerProcessContainer container = new TFTPServerProcessContainer(); 
 
            TFTPServerProcess tftpproc = new TFTPServerProcess(FullPath, 
                                LogLevel, 
                                EventLevel, 
                                AllowRRQ, 
                                AllowWRQ, 
                                AllowWRQOverwrite, 
                                AllowOptions, 
                                RRQWRQStateCheck, 
                                ResendInterval, 
                                Timeout, 
                                logger, 
                                myEndpoint.Address); 
 
            OnTFTPServerTransferEvent(new TFTPServerTransferEventArgs(tftpproc)); 
            tftpproc.TFTPServerProcessEvent += new TFTPServerProcessEventHandler(this.TFTPProcessEventListener); 
 
            ClientMode = true; 
            ClientHost = Host; 
            IPEndPoint RemoteEndPoint = new IPEndPoint(IPAddress.Parse(Host), Port); 
 
            container.threadStart = new ThreadStart(container.process.StartListener); 
            container.thread = new Thread(container.threadStart); 
            container.thread.Name = "TFTP Server Process Thread"; 
            container.thread.IsBackground = true; 
            container.thread.Start(); 
 
            lock (CurrStatesLock) 
            { 
                //CurrStates.Add(tftpproc); 
                CurrStates.Add(container); 
            } 
 
            for (int SleepCounter = 0; SleepCounter <= 5; SleepCounter++) 
            { 
                if (container.process.IsListening) 
                { 
                    container.process.PutFile(Host, Port, Filename, Filesize, Timeout, TransferSize); 
                    SleepCounter = 10; 
                    StartCheckTimer(); 
                } 
                else 
                { 
                    //Wait a little bit for the thread to start listening 
                    Thread.Sleep(100); 
                } 
            } 
        } 
 
        private void OnTFTPServerEvent(TFTPServerEventArgs e) 
        { 
            if (TFTPServerEvent != null) 
                TFTPServerEvent(null, e); 
        } 
 
        private void OnTFTPServerTransferEvent(TFTPServerTransferEventArgs e) 
        { 
            if (TFTPServerTransferEvent != null) 
                TFTPServerTransferEvent(null, e); 
        } 
 
        private void AddMsg(Level level, string text) 
        { 
            if (level >= EventLevel) 
                OnTFTPServerEvent(new TFTPServerEventArgs(text)); 
 
            if (logger.IsOpen && (level >= LogLevel)) 
                logger.Log(level, text); 
        } 
 
        private void SetIPAddr() 
        { 
            try 
            { 
                IPHostEntry localMachineInfo = Dns.GetHostEntry(Dns.GetHostName()); 
                foreach (IPAddress ipAddr in localMachineInfo.AddressList) 
                { 
                    //Find the first IPv4 address 
                    if (ipAddr.AddressFamily == AddressFamily.InterNetwork) 
                    { 
                        myEndpoint = new IPEndPoint(ipAddr, ListenerPort); 
                    } 
                } 
            } 
            catch (SocketException) 
            { 
                myEndpoint = new IPEndPoint(IPAddress.Any, ListenerPort); 
            } 
            AddMsg(Level.Verbose, myEndpoint.ToString()); 
        } 
 
        private void SetIPAddr(IPAddress IPAddr) 
        { 
            try 
            { 
                if (IPAddress.Any == IPAddr) 
                { 
                    myEndpoint = new IPEndPoint(IPAddress.Any, ListenerPort); 
                } 
                else 
                { 
                    IPHostEntry localMachineInfo = Dns.GetHostEntry(Dns.GetHostName()); 
                    bool IPMatch = false; 
 
                    for (int i = 0; i < localMachineInfo.AddressList.Length; i++) 
                    { 
                        if (localMachineInfo.AddressList[i].Equals(IPAddr)) 
                        { 
                            IPMatch = true; 
                            myEndpoint = new IPEndPoint(localMachineInfo.AddressList[i], ListenerPort); 
                            AddMsg(Level.Debug, "SetIPAddr found match and setting to " + localMachineInfo.AddressList[i].ToString()); 
                        } 
                    } 
                    if (!IPMatch) 
                        myEndpoint = new IPEndPoint(localMachineInfo.AddressList[0], ListenerPort); 
                } 
            } 
            catch (SocketException) 
            { 
                myEndpoint = new IPEndPoint(IPAddress.Any, ListenerPort); 
            } 
 
            AddMsg(Level.Verbose, myEndpoint.ToString()); 
        } 
 
        ///  
        /// Gets whether we are listening for TFTP requests 
        ///  
        public bool IsListening 
        { 
            get 
            { 
                return Loop; 
            } 
        } 
 
        ///  
        /// Gets or sets the Path where to retrieve or put files 
        ///  
        public string Path 
        { 
            get 
            { 
                return FullPath; 
            } 
            set 
            { 
                if (System.IO.Directory.Exists(value)) 
                    FullPath = value; 
            } 
        } 
 
        ///  
        /// Gets or sets the NSpring level indicating whent to send events 
        ///  
        public string SendEventLevel 
        { 
            get 
            { 
                return EventLevel.ToString(); 
            } 
            set 
            { 
                switch (value) 
                { 
                    case "Debug": 
                        EventLevel = Level.Debug; 
                        break; 
                    case "Verbose": 
                        EventLevel = Level.Verbose; 
                        break; 
                    case "Config": 
                        EventLevel = Level.Config; 
                        break; 
                    case "Info": 
                        EventLevel = Level.Info; 
                        break; 
                    case "Warning": 
                        EventLevel = Level.Warning; 
                        break; 
                    case "Exception": 
                        EventLevel = Level.Exception; 
                        break; 
                } 
            } 
        } 
 
        ///  
        /// Gets or sets the NSpring logging level 
        ///  
        public string LoggingLevel 
        { 
            get 
            { 
                return LogLevel.ToString(); 
            } 
            set 
            { 
                switch (value) 
                { 
                    case "Debug": 
                        logger.Level = Level.Debug; 
                        LogLevel = Level.Debug; 
                        break; 
                    case "Verbose": 
                        logger.Level = Level.Verbose; 
                        LogLevel = Level.Verbose; 
                        break; 
                    case "Config": 
                        logger.Level = Level.Config; 
                        LogLevel = Level.Config; 
                        break; 
                    case "Info": 
                        logger.Level = Level.Info; 
                        LogLevel = Level.Info; 
                        break; 
                    case "Warning": 
                        logger.Level = Level.Warning; 
                        LogLevel = Level.Warning; 
                        break; 
                    case "Exception": 
                        logger.Level = Level.Exception; 
                        LogLevel = Level.Exception; 
                        break; 
                } 
            } 
        } 
 
        ///  
        /// Gets or sets the listener IP addresses 
        ///  
        public IPAddress[] ListenerIPAddresses 
        { 
            get 
            { 
                //Currently we only listen on one IP but we want to listen on more 
                if (myEndpoint != null) 
                { 
                    IPAddress[] list = new IPAddress[] { myEndpoint.Address }; 
                    return list; 
                } 
                else 
                { 
                    return new IPAddress[] { }; 
                } 
            } 
            set 
            { 
                if (!IsListening) 
                    SetIPAddr(value[0]); 
                    //myEndpoint = new IPEndPoint(value[0], ListenerPort); 
            } 
        } 
 
        ///  
        /// Gets or sets the port to listen to TFTP requests on 
        ///  
        public int ListenerPortNumber 
        { 
            get 
            { 
                return myEndpoint.Port; 
            } 
            set 
            { 
                if (!IsListening) 
                    SetIPAddr(); 
                    //myEndpoint = new IPEndPoint(ListenerIPAddresses[0], value); 
            } 
        } 
 
        ///  
        /// Gets the current number of active sessions 
        ///  
        public int NumberSessions 
        { 
            get 
            { 
                return CurrStates.Count; 
            } 
        } 
 
        private void FileAccess(string access) 
        { 
            switch (access) 
            { 
                case "No Access": 
                    AllowRRQ = false; 
                    AllowWRQ = false; 
                    AllowWRQOverwrite = false; 
                    break; 
                case "Read Only": 
                    AllowRRQ = true; 
                    AllowWRQ = false; 
                    AllowWRQOverwrite = false; 
                    break; 
                case "Write": 
                    AllowRRQ = false; 
                    AllowWRQ = true; 
                    AllowWRQOverwrite = false; 
                    break; 
                case "Read and Write": 
                    AllowRRQ = true; 
                    AllowWRQ = true; 
                    AllowWRQOverwrite = false; 
                    break; 
                case "Read and Overwrite": 
                    AllowRRQ = true; 
                    AllowWRQ = true; 
                    AllowWRQOverwrite = true; 
                    break; 
            } 
        } 
 
        ///  
        /// Gets or sets an integer in seconds specifying the interval before resending the last packet 
        ///  
        public int ResendIntervalSeconds 
        { 
            get 
            { 
                return ResendInterval; 
            } 
            set 
            { 
                if ((value >= 1) && (value <= 255)) 
                    ResendInterval = value; 
            } 
        } 
 
        ///  
        /// Gets or set an integer in seconds specifying how longer before the connection is considered to be timed out 
        ///  
        public int TimeoutSeconds 
        { 
            get 
            { 
                return Timeout; 
            } 
            set 
            { 
                if ((value >= 1) && (value <= 255)) 
                    Timeout = value; 
            } 
        } 
 
        ///  
        /// Gets or sets the logging method and parameters 
        ///  
        public string[] LoggingMethod 
        { 
            get 
            { 
                return new string[] { logger.GetType().ToString(), LoggingMethodOptions }; 
            } 
            set 
            { 
                try 
                { 
                    if (value.Length == 2) 
                    { 
                        AddMsg(Level.Debug, "Changing logger to " + value[0] + " with options " + value[1]); 
                        if (logger.IsOpen) 
                            logger.Close(); 
                        switch (value[0].ToLower()) 
                        { 
                            case "windows event": 
                                logger = new WindowsEventLogger(value[1]); 
                                break; 
                            case "sql": 
                                System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(value[1]); 
                                logger = new DatabaseLogger(conn, "INSERT INTO [" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + " Log] ([EventDatetime], [EventLevel], [EventMessage]) VALUES ('{ts}', '{ln}', '{msg}')"); 
                                logger.EventFormatter = new NSpring.Logging.EventFormatters.PatternEventFormatter("{ts} {msg}"); 
                                break; 
                            case "text file": 
                                if (logger.GetType().ToString() != "NSpring.Logging.Loggers.FileLogger") 
                                    logger = new FileLogger(value[1]); 
                                break; 
                            case "xml file": 
                                if (logger.GetType().ToString() != "NSpring.Logging.Loggers.StreamLogger") 
                                { 
                                    System.IO.FileStream LoggerStream = new System.IO.FileStream(value[1], System.IO.FileMode.Append); 
                                    logger = new StreamLogger(LoggerStream); 
                                } 
                                break; 
                            case "email": 
                                string[] emailparams = value[1].Split(','); 
                                if (emailparams.Length == 3) 
                                    logger = new EmailLogger(emailparams[0], emailparams[1], emailparams[2]); 
                                break; 
                            default: 
                                logger.Open(); 
                                AddMsg(Level.Debug, "Someone tried changing the logger to some type we don't know: " + value[0]); 
                                break; 
                        } 
                        if (!logger.IsOpen) 
                            logger.Open(); 
                        LoggingMethodOptions = value[1]; 
                    } 
                    else 
                    { 
                        AddMsg(Level.Debug, "Someone tried changing the logger and had " + value.Length.ToString() + " items in the array so we didn't do anything."); 
                    } 
                } 
                catch (Exception ex) 
                { 
                    AddMsg(Level.Info, "An error occurred while trying to change the logging method"); 
                    AddMsg(Level.Verbose, "Handled exception: " + ex.Message); 
                    AddMsg(Level.Debug, "Handled exception at: " + ex.StackTrace); 
                } 
            } 
        } 
 
        public string BlockedIPs 
        { 
            get 
            { 
                string tempips = ""; 
                if (BadIPs != null) 
                { 
                    for (int i = 0; i < BadIPs.Length; i++) 
                    { 
                        if (BadIPs[i] != null) 
                        { 
                            tempips += BadIPs[i].ToString(); 
                            if (i != (BadIPs.Length - 1)) 
                                tempips += ";"; 
                        } 
                    } 
                } 
                return tempips; 
            } 
            set 
            { 
                int i = 0; 
                string[] tempips = value.Split(';'); 
                IPAddress[] tempIPAddrs = new IPAddress[tempips.Length]; 
                foreach (string ip in tempips) 
                { 
                    IPAddress tempaddr; 
                    if (IPAddress.TryParse(ip, out tempaddr)) 
                    { 
                        tempIPAddrs[i] = tempaddr; 
                        i++; 
                    } 
                } 
 
                BadIPs = tempIPAddrs; 
            } 
        } 
    } 
}