www.pudn.com > TFTPUtil_Source_Version_1.3.0.zip > TFTPServerProcess.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; 
using System.Diagnostics; 
using System.Reflection; 
 
namespace TFTPUtil 
{ 
    ///  
    /// The TFTPUtil Server Class 
    ///  
    public class TFTPServerProcess 
    { 
        #region VARS 
        private TFTPState State; 
        ///  
        /// The GUID for this connection 
        ///  
        public readonly Guid ident = Guid.NewGuid(); 
        private Logger logger; 
        private int TimeoutCounter = 0; 
        private int ResendInterval = 1;                     //How many seconds before resending 
        private int Timeout = 10;                           //How many seconds before counting TID timedout 
        private bool sentOACK = false; 
        ///  
        /// 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 const int DefaultBlockSize = 512; 
        private bool ClientMode = false; 
        private bool PutClientMode = false; 
        private string ClientHost; 
        private string FullPath = System.IO.Directory.GetCurrentDirectory(); 
        ///  
        /// The TFTP server event handler 
        ///  
        public event TFTPServerProcessEventHandler TFTPServerProcessEvent; 
        private readonly object CurrStatesLock = new object(); 
        private Level EventLevel = Level.Info; 
        private Level LogLevel = Level.Info; 
        ///  
        /// 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 }; 
        #endregion 
 
        ///  
        /// Initalizes an instance of the TFTPServerProcess class with defaults values 
        ///  
        public TFTPServerProcess() 
        { 
            //randomly generate the port to connect 
            Random rnd = new Random(); 
 
            IPHostEntry localMachineInfo = Dns.GetHostEntry(Dns.GetHostName()); 
            myEndpoint = new IPEndPoint(localMachineInfo.AddressList[0], 0); 
        } 
 
        ///  
        /// Initalizes an instance of the TFTPServerProcess class 
        ///  
        /// 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 
        /// Allow read requests 
        /// Allow write requests 
        /// Allow write requests to overwrite existing 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 NSpring logger to use 
        /// An IPAddress that we should listen on 
        public TFTPServerProcess(string FilePath, 
            Level LoggingLevel, 
            Level DisplayLevel, 
            bool AllowRRQ, 
            bool AllowWRQ, 
            bool AllowWRQOverwrite, 
            bool AllowTFTPOptions, 
            bool CheckReadWriteState, 
            int ResendInterval, 
            int TimeoutInterval, 
            Logger logger, 
            IPAddress srvaddr) 
        { 
            //randomly generate the port to connect 
            Random rnd = new Random(); 
 
            IPHostEntry localMachineInfo = Dns.GetHostEntry(Dns.GetHostName()); 
 
            myEndpoint = new IPEndPoint(localMachineInfo.AddressList[0], 0); 
            for (int i = 0; i < localMachineInfo.AddressList.Length; i++) 
            { 
                if (localMachineInfo.AddressList[i].Equals(srvaddr)) 
                { 
                    myEndpoint = new IPEndPoint(localMachineInfo.AddressList[i], 0); 
                    i = localMachineInfo.AddressList.Length; 
                } 
            } 
 
            FullPath = FilePath; 
            this.LogLevel = LoggingLevel; 
            EventLevel = DisplayLevel; 
            AllowOptions = AllowTFTPOptions; 
            this.AllowRRQ = AllowRRQ; ; 
            this.AllowWRQ = AllowWRQ; 
            this.AllowWRQOverwrite = AllowWRQOverwrite; 
            RRQWRQStateCheck = CheckReadWriteState; 
            this.ResendInterval = ResendInterval; 
            Timeout = TimeoutInterval; 
            this.logger = logger; 
        } 
 
        ///  
        /// Stops the TFTP server from listening for requests 
        ///  
        public void StopListener() 
        { 
            //System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(2, true); 
            //System.Diagnostics.StackFrame sf = st.GetFrame(0); 
            //AddMsg(Level.Debug, ident.ToString() + ": StopListener called by " + sf.ToString()); 
 
            AddMsg(Level.Verbose, ident.ToString() + ": Process stopping Listening.");             
            Loop = false; 
 
            try 
            { 
                // We only need to stop receiving so we can still send our last packet 
                if (mySocket != null) 
                { 
                    mySocket.Shutdown(SocketShutdown.Receive); 
                    //mySocket.Close(Timeout*ResendInterval); 
                } 
            } 
            catch (ObjectDisposedException ex) 
            { 
                StackFrame stackFrame = new StackFrame(); 
                MethodBase methodBase = stackFrame.GetMethod(); 
                AddMsg(Level.Verbose, "Caught socket object disposed exception in " + methodBase.Name); 
                AddMsg(Level.Debug, "Socket exception: " + ex.Message + "\n" + ex.StackTrace); 
            } 
 
            lock (CurrStatesLock) 
            { 
                if (State != null) 
                { 
                    State.Close(); 
                    //State = null; 
                } 
            } 
            AddMsg(Level.Debug, ident.ToString() + ": TFTPServer Process Thread stopped listening on " + myEndpoint.Address.ToString() + ":" + ListenerPort.ToString()); 
        } 
 
        ///  
        /// Deconstructor 
        ///  
        ~TFTPServerProcess() 
        { 
            //CurrStates.Clear(); 
            if (State != null) 
            { 
                State.Close(); 
                State = null; 
            } 
            if ((mySocket != null)) 
            { 
                try 
                { 
                    mySocket.Shutdown(SocketShutdown.Both); 
                    mySocket.Close(); 
                } 
                catch (ObjectDisposedException ex) 
                { 
                    StackFrame stackFrame = new StackFrame(); 
                    MethodBase methodBase = stackFrame.GetMethod(); 
                    AddMsg(Level.Verbose, "Caught socket object disposed exception in " + methodBase.Name); 
                    AddMsg(Level.Debug, "Socket exception: " + ex.Message + "\n" + ex.StackTrace); 
                } 
            } 
        } 
 
        public void MyClose() 
        { 
            mySocket.Close(); 
            mySocket = null; 
        } 
         
        ///  
        /// Starts the TFTP server listening for requests 
        ///  
        public void StartListener() 
        { 
            try 
            { 
                AddMsg(Level.Verbose, ident.ToString() + ": Creating Socket"); 
                mySocket = new Socket(myEndpoint.Address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); 
 
                AddMsg(Level.Verbose, ident.ToString() + ": Binding Socket"); 
                mySocket.Bind(myEndpoint); 
                ListenerPort = ((IPEndPoint)mySocket.LocalEndPoint).Port; 
 
                Loop = true; 
 
                AddMsg(Level.Verbose, ident.ToString() + ": Process starting to Listen"); 
                AddMsg(Level.Debug, ident.ToString() + ": TFTPServer Process Thread 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 
                { 
                    StackFrame stackFrame = new StackFrame(); 
                    MethodBase methodBase = stackFrame.GetMethod(); 
                    AddMsg(Level.Verbose, ident.ToString() + ": Handled " + methodBase.Name + " socket exception: " + ex.Message); 
                    AddMsg(Level.Debug, ident.ToString() + ": Handled " + methodBase.Name + " socket exception at: " + ex.StackTrace); 
                    Loop = false; 
                } 
            } 
        } 
 
        ///  
        /// Check the state of the current TFTP session 
        ///  
        public void CheckStates() 
        { 
            //System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(2, true); 
            //System.Diagnostics.StackFrame sf = st.GetFrame(0); 
            //AddMsg(Level.Debug, ident.ToString() + ": Process CheckStates" + sf.ToString()); 
 
            AddMsg(Level.Debug, ident.ToString() + ": " + DateTime.Now.ToString() + "Process CheckStates timer callback started."); 
            lock (CurrStatesLock) 
            { 
                if (State != null) 
                { 
                    if (State.TransferState.Closed) 
                    { 
                        AddMsg(Level.Verbose, ident.ToString() + ": " + DateTime.Now.ToString() + " CheckStates timer calling stoplistener because the state is closed."); 
                        StopListener(); 
                    } 
                    else 
                    { 
                        if ((DateTime.Now.Ticks - State.Timestamp) > 0) 
                        { 
                            if (((DateTime.Now.Ticks - State.Timestamp) / 10000000) > State.TimeoutSeconds) 
                            { 
                                //If a state has had no activity for the specified interval remove it 
                                AddMsg(Level.Info, "Timeout for " + State.TransferType + " request of file " + State.Filename + " connection " + State.RemoteIPAddress.ToString() + ":" + State.RemotePortNumber.ToString()); 
                                AddMsg(Level.Verbose, "Timeout was " + ((DateTime.Now.Ticks - State.Timestamp) / 10000000).ToString() + " seconds"); 
                                State.ErrorOccurred = true; 
                                State.ErrorMsg = "Timeout occured for " + State.TransferType + " request of file " + State.Filename + " from " + State.RemoteIPAddress.ToString(); 
                                State.Close(); 
                            } 
                            else if ((((DateTime.Now.Ticks - State.Timestamp) / 10000000) > State.TimeoutSeconds) && (State.OriginalOpcode == 2)) 
                            { 
                                //If we didn't get another DATA packet since our last ACK resend 
                                AddMsg(Level.Info, "Resending ACK to " + State.RemoteIPAddress.ToString() + ":" + State.RemotePortNumber.ToString()); 
                                IPEndPoint RemoteEndPoint = new IPEndPoint(IPAddress.Parse(State.RemoteIPAddress), State.RemotePortNumber); 
                                Send(RemoteEndPoint, new byte[] { 0, 4, State.BlockIDByte1, State.BlockIDByte2 }); 
                            } 
                        } 
                    } 
                } 
                else if (TimeoutCounter > Timeout) 
                { 
                    AddMsg(Level.Verbose, ident.ToString() + ": Stopping listener because no active sessions for timeout peroid."); 
                    this.StopListener(); 
                } 
                else 
                { 
                    //The listener should not be running if there is not an active session 
                    ++TimeoutCounter; 
                } 
            } 
            AddMsg(Level.Debug, ident.ToString() + ": " + "Process 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) 
                { 
                    //10004 occurs when we close the socket and we were still blocking on receivefrom 
                    if (ex.GetType().FullName == "System.Net.Sockets.SocketException" && ((SocketException)ex).ErrorCode != 10004) 
                    { 
                        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); 
                        } 
                        this.StopListener(); 
                    } 
                } 
 
                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; 
                        try 
                        { 
                            IPAddress HostAddr = IPAddress.Parse(ClientHost); 
                            IsIP = true; 
                            if (RemoteEndPoint.Address.Equals(HostAddr)) 
                                FoundMatch = true; 
                        } 
                        catch 
                        { 
                            AddMsg(Level.Debug, "ClientHost \"" + ClientHost + "\" was not an IP address"); 
                        } 
                        if (IsIP == false) 
                        { 
                            foreach (IPAddress ip in Dns.GetHostAddresses(ClientHost)) 
                            { 
                                if (ip == RemoteEndPoint.Address) 
                                    FoundMatch = true; 
                            } 
                        } 
                    } 
 
                    if (FoundMatch) 
                    { 
                        ProcessDatagram(ReceivedBytes, NumBytesReceived, RemoteEndPoint); 
                    } 
                } 
            } 
        } 
 
        ///  
        /// Processes TFTP bytes 
        ///  
        /// The array of bytes received from the RemoteEndPoint 
        /// The number of bytes received from the RemoteEndPoint 
        /// An IPEndPoint that is the remote TFTP device 
        public 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, ident.ToString() + ": Found Opcode " + CurrOpcode.ToString() + " from " + EndPointString); 
 
            bool StateChk = true; 
 
            lock (CurrStatesLock) 
            { 
                StateChk = CheckForExistingTID(RemoteEndPoint); 
            } 
            string[] FilenameType = new string[2]; 
 
            switch (CurrOpcode) 
            { 
                case 1: //RRQ 
                    #region RRQ 
                    if (AllowRRQ && (NumBytesReceived <= 516)) 
                    { 
                        lock (CurrStatesLock) 
                        { 
                            AddMsg(Level.Verbose, ident.ToString() + ": Processing RRQ from " + EndPointString); 
                            string[] FoundOptions = FindOptions(ReceivedBytes, NumBytesReceived); 
                            if (RRQWRQStateCheck && (StateChk)) 
                            { 
                                //If we find an existing TID we should send them an error and delete he state 
                                //We should not have an existing TID for an RRQ or WRQ request 
                                AddMsg(Level.Verbose, ident.ToString() + ": Sending unknown error generated in RRQ because of TID check to " + EndPointString); 
                                SendUnknownError(RemoteEndPoint); 
                                State.Close(); 
                            } 
                            else if ((StateChk == false) && (FoundOptions[0] != "") && ((FoundOptions[1] == "octet") || (FoundOptions[1] == "netascii"))) 
                            { 
                                State = CreateNewState(RemoteEndPoint, CurrOpcode, FoundOptions[0], FoundOptions[1], DefaultBlockSize); 
 
                                if (SendOptions(FoundOptions, State, RemoteEndPoint) != false) 
                                { 
                                    byte[] DataBytes = { }; 
                                    try 
                                    { 
                                        DataBytes = State.GetData(0, 0); 
                                        byte[] SendBytes = new byte[DataBytes.Length + 4]; 
                                        DataBytes.CopyTo(SendBytes, 4); 
                                        SendBytes[1] = 3;   //DATA 
                                        SendBytes[3] = 1;   //Block ID 1 
                                        AddMsg(Level.Verbose, ident.ToString() + ": Sending first data to " + EndPointString); 
                                        Send(RemoteEndPoint, SendBytes); 
                                    } 
                                    catch (System.IO.IOException ex) 
                                    { 
                                        State.ErrorOccurred = true; 
                                        //I hate searching for text in a message but I don't want to keep a list of IDs to handle either 
                                        if (ex.Message.ToLower().Contains("could not find")) 
                                        { 
                                            AddMsg(Level.Info, ex.Message + " requested by " + EndPointString); 
                                            State.ErrorMsg = ex.Message + " requested by " + EndPointString; 
                                        } 
                                        else 
                                        { 
                                            AddMsg(Level.Info, "A problem occurred during a read request from " + EndPointString); 
                                            State.ErrorMsg = "A problem occurred during a read request from " + EndPointString; 
                                        } 
 
                                        AddMsg(Level.Verbose, "Handled RRQ file exception: " + ex.Message); 
                                        AddMsg(Level.Debug, "Handled RRQ file exception: " + ex.StackTrace); 
 
                                        //Send file not found error 
                                        Send(RemoteEndPoint, Error1); 
                                        State.Close(); 
                                    } 
                                } 
                                else 
                                { 
                                    AddMsg(Level.Verbose, ident.ToString() + ": Sending tftp error 8 generated in RRQ to " + EndPointString); 
                                    Send(RemoteEndPoint, Error8); 
                                    State.ErrorOccurred = true; 
                                    State.ErrorMsg = "An error occured while processing TFTP options from " + EndPointString; 
                                    State.Close(); 
                                } 
                            } 
                            else 
                            { 
                                AddMsg(Level.Verbose, ident.ToString() + ": Sending unknown error generated in RRQ to " + EndPointString); 
                                State.ErrorOccurred = true; 
                                State.ErrorMsg = "An unknown error occured while processing a write request from " + EndPointString; 
                                SendUnknownError(RemoteEndPoint); 
                                State.Close(); 
                            } 
                        } 
                    } 
                    else 
                    { 
                        Send(RemoteEndPoint, Error2); 
                    } 
                    break; 
                    #endregion 
                case 2: //WRQ 
                    #region WRQ 
                    if (AllowWRQ && (NumBytesReceived <= 516)) 
                    { 
                        lock (CurrStatesLock) 
                        { 
                            AddMsg(Level.Verbose, ident.ToString() + ": Processing WRQ from " + EndPointString); 
                            //FilenameType = GetFilenameType(ReceivedBytes); 
 
                            string[] FoundOptions = FindOptions(ReceivedBytes, NumBytesReceived); 
                            if (RRQWRQStateCheck && (StateChk)) 
                            { 
                                //If we find an existing TID we should send them an error and delete he state 
                                //We should not have an existing TID for an RRQ or WRQ request 
                                AddMsg(Level.Verbose, ident.ToString() + ": Sending unknown error generated in WRQ to " + EndPointString); 
                                SendUnknownError(RemoteEndPoint); 
                                State.Close(); 
                            } 
                            else if ((StateChk == false) && (FoundOptions[0] != "") && ((FoundOptions[1] == "octet") || (FoundOptions[1] == "netascii"))) 
                            { 
                                State = CreateNewState(RemoteEndPoint, CurrOpcode, FoundOptions[0], FoundOptions[1], DefaultBlockSize); 
 
                                if (SendOptions(FoundOptions, State, RemoteEndPoint) != false) 
                                { 
                                    // Only sent ack to wrq if you are not doing options 
                                    if (sentOACK == false) 
                                    { 
                                        AddMsg(Level.Verbose, ident.ToString() + ": Sending ACK for WRQ to " + EndPointString); 
                                        Send(RemoteEndPoint, new byte[] { 0, 4, 0, 0 });    //ACK with Block ID 0 
                                    } 
                                } 
                                else 
                                { 
                                    AddMsg(Level.Verbose, ident.ToString() + ": Sending tftp error 8 generated in RRQ to " + EndPointString); 
                                    Send(RemoteEndPoint, Error8); 
                                    State.ErrorOccurred = true; 
                                    State.ErrorMsg = "An error occured while processing TFTP options from " + EndPointString; 
                                    State.Close(); 
                                } 
                            } 
                            else 
                            { 
                                AddMsg(Level.Verbose, ident.ToString() + ": Sending unknown error generated in WRQ to " + EndPointString); 
                                State.ErrorOccurred = true; 
                                State.ErrorMsg = "An unknown error occured while processing a write request from " + EndPointString; 
                                SendUnknownError(RemoteEndPoint); 
                            } 
                        } 
                    } 
                    else 
                    { 
                        Send(RemoteEndPoint, Error2); 
                    } 
                    break; 
                    #endregion 
                case 3: //DATA 
                    #region DATA 
                    AddMsg(Level.Verbose, ident.ToString() + ": Processing DATA for block " + ReceivedBytes[3].ToString() + " from " + EndPointString); 
 
                    if (StateChk) 
                    { 
                        if (NumBytesReceived <= (State.BlockSize + 4)) 
                        { 
                                try 
                                { 
                                    if ((ReceivedBytes[2] == 0) && (ReceivedBytes[3] == 1) && (State.BlocksizeOption || State.TimeoutOption)) 
                                    { 
                                        AddMsg(Level.Debug, ident.ToString() + ": Got a data packet so options were accepted"); 
                                        lock (CurrStatesLock) 
                                        { 
                                            if (State.BlocksizeOption) 
                                                State.BlocksizeOptionACK = true; 
                                            if (State.TimeoutOption) 
                                                State.TimeoutOptionACK = true; 
                                        } 
                                    } 
 
                                    AddMsg(Level.Verbose, ident.ToString() + ": Starting to write DATA received form " + EndPointString); 
                                    byte[] WriteBytes = new byte[NumBytesReceived - 4]; 
                                    Array.ConstrainedCopy(ReceivedBytes, 4, WriteBytes, 0, NumBytesReceived - 4); 
                                    lock (CurrStatesLock) 
                                    { 
                                        State.WriteData(WriteBytes, ReceivedBytes[2], ReceivedBytes[3]); 
                                        State.BlockIDByte1 = ReceivedBytes[2]; 
                                        State.BlockIDByte2 = ReceivedBytes[3]; 
                                    } 
 
                                    //Send ACK for last DATA block 
                                    AddMsg(Level.Verbose, ident.ToString() + ": Sending ACK for DATA to " + EndPointString); 
                                    Send(RemoteEndPoint, new byte[] { 0, 4, ReceivedBytes[2], ReceivedBytes[3] }); 
 
                                    lock (CurrStatesLock) 
                                    { 
                                        if ((NumBytesReceived - 4) < State.BlockSize) 
                                        { 
                                            long TotalTime = (State.StopTransferTicks - State.StartTransferTicks) / 10000000; 
                                            long Rate; 
                                            if (TotalTime > 0) 
                                                Rate = State.Filesize / TotalTime; 
                                            else 
                                                Rate = State.Filesize; 
                                            AddMsg(Level.Info, "Successfully received file " + State.Filename + " (" + State.Filesize.ToString() + " bytes) from " + State.RemoteIPAddress + " in " + TotalTime.ToString() + " seconds (" + (Rate).ToString() + " bytes/sec)."); 
                                            //This is the last block so go ahead and setup to delete state 
                                            State.Close(); 
                                            StopListener(); 
                                        } 
                                    } 
                                } 
                                catch (System.IO.IOException ex) 
                                { 
                                    //We probably need to come back to this later and make find what exception we got and send the right tftp error 
                                    AddMsg(Level.Info, "A problem occurred while trying to write to the file from " + EndPointString); 
                                    AddMsg(Level.Verbose, "Handled DATA exception: " + ex.Message); 
                                    AddMsg(Level.Debug, "Handled DATA exception: " + ex.StackTrace); 
                                    Send(RemoteEndPoint, Error1); 
                                    lock (CurrStatesLock) 
                                    { 
                                        State.ErrorOccurred = true; 
                                        State.ErrorMsg = "A problem occurred while trying to write to the file from " + EndPointString; 
                                        State.Close(); 
                                    } 
                                } 
                        } 
                        else 
                        { 
                            AddMsg(Level.Info, EndPointString + " sent us more data than we expected, dropping packet."); 
                        } 
                    } 
                    else 
                    { 
                        //Couldn't find TID so send ERR 
                        AddMsg(Level.Verbose, ident.ToString() + ": Sending ERR because we found no TID for " + EndPointString); 
                        lock (CurrStatesLock) 
                        { 
                            if (State != null) 
                            { 
                                State.ErrorOccurred = true; 
                                State.ErrorMsg = "Could not find an existing session for TFTP request"; 
                            } 
                        } 
                        Send(RemoteEndPoint, Error5); 
                    } 
                    break; 
                    #endregion 
                case 4: //ACK 
                    #region ACK 
                    AddMsg(Level.Verbose, "Processing ACK for block " + ReceivedBytes[3].ToString() + " from " + EndPointString); 
                    if (StateChk) 
                    { 
                        lock (CurrStatesLock) 
                        { 
                            if (State.SentRecvLastBlock) 
                            { 
                                //We got an ACK for the last block so go ahead and delete the state 
                                long TotalTime = (State.StopTransferTicks - State.StartTransferTicks) / 10000000; 
                                long Rate; 
                                if (TotalTime > 0) 
                                    Rate = State.Filesize / TotalTime; 
                                else 
                                    Rate = State.Filesize; 
                                AddMsg(Level.Info, "Successfully sent file " + State.Filename + " (" + State.Filesize.ToString() + " bytes) to " + State.RemoteIPAddress + " in " + TotalTime.ToString() + " seconds (" + (Rate).ToString() + " bytes/sec)."); 
                                AddMsg(Level.Verbose, "Removing state for " + State.RemoteIPAddress + ":" + State.RemotePortNumber); 
                                //CurrStates.RemoveAt(StateIndex); 
                                State.Close(); 
                                StopListener(); 
                            } 
                            else 
                            { 
                                if ((ReceivedBytes[3] == 0) && (ReceivedBytes[4] == 0) && (State.BlocksizeOption || State.TimeoutOption)) 
                                { 
                                    AddMsg(Level.Debug, ident.ToString() + ": Got an ACK so options were accepted"); 
                                    if (State.BlocksizeOption) 
                                        State.BlocksizeOptionACK = true; 
                                    if (State.TimeoutOption) 
                                        State.TimeoutOptionACK = true; 
                                } 
                                SendNextDataDatagram(ReceivedBytes, RemoteEndPoint, EndPointString); 
                            } 
                        } 
                    } 
                    else 
                    { 
                        //Couldn't find TID so send ERR 
                        AddMsg(Level.Verbose, ident.ToString() + ": Sending error generated in ACK to " + EndPointString); 
                        Send(RemoteEndPoint, Error5); 
                        if (StateChk) 
                        { 
                            lock (CurrStatesLock) 
                            { 
                                State.Close(); 
                            } 
                        } 
                    } 
                    break; 
                    #endregion 
                case 5: //ERROR 
                    #region ERROR 
                    lock (CurrStatesLock) 
                    { 
                        State.ErrorOccurred = true; 
                        ArrayList ErrorCharList = new ArrayList(5); 
                        for (int index = 4; index < NumBytesReceived; index++) 
                        { 
                            if (ReceivedBytes[index] != 0) 
                            { 
                                ErrorCharList.Add(ReceivedBytes[index]); 
                            } 
                            else 
                            { 
                                break; 
                            } 
                        } 
 
                        string errorMsg = System.Text.Encoding.ASCII.GetString((byte[])ErrorCharList.ToArray(typeof(byte))); 
                        State.ErrorMsg = "Received TFTP error message \"" + errorMsg + "\" from " + EndPointString; 
                        AddMsg(Level.Info, "Received TFTP error message \"" + errorMsg + "\" from " + EndPointString); 
                        StopListener(); 
                        if (StateChk) 
                        { 
                            State.Close(); 
                        } 
                    } 
                    break; 
                    #endregion 
                case 6: //OACK 
                    #region OACK 
                    string[] OACKOptions = FindOptions(ReceivedBytes, NumBytesReceived); 
                    if (AllowOptions && (OACKOptions.Length > 2)) 
                    { 
                        try 
                        { 
                            for (int i = 2; i < OACKOptions.Length; i++) 
                            { 
                                switch (OACKOptions[i].ToLower()) 
                                { 
                                    case "tsize":   //RFC 2349 
                                        lock (CurrStatesLock) 
                                        { 
                                            State.TransferSizeOption = true; 
                                        } 
                                        break; 
                                    case "timeout": //RFC 2349 
                                        lock (CurrStatesLock) 
                                        { 
                                            State.TimeoutOptionACK = true; 
                                        } 
                                        break; 
                                    case "blksize": //RFC 2348 
                                        lock (CurrStatesLock) 
                                        { 
                                            State.BlocksizeOptionACK = true; 
                                        } 
                                        break; 
                                    case "multicast":   //RFC 2090 
                                        break; 
                                    case "sbroadcast":  //Saw this in some IBM doc but can't find an RFC 
                                        break; 
                                    default: 
                                        AddMsg(Level.Debug, "Found unknown option: " + OACKOptions[i]); 
                                        break; 
                                } 
                                i++;    //Increment because we use them in pairs 
                            } 
                        } 
                        catch (Exception ex) 
                        { 
                            AddMsg(Level.Warning, "A problem occurred when parsing the received packet"); 
                            AddMsg(Level.Verbose, "Handled exception in oack : " + ex.Message); 
                            AddMsg(Level.Debug, "Handled oack exception: " + ex.StackTrace); 
                        } 
                    } 
                    if (ClientMode && PutClientMode) 
                    { 
                        SendNextDataDatagram(new byte[] { 0, 0, 0, 0, }, RemoteEndPoint, EndPointString); 
                    } 
                    break; 
                    #endregion 
                default: 
                    AddMsg(Level.Verbose, ident.ToString() + ": Sending error4 generated in default case " + EndPointString); 
                    Send(RemoteEndPoint, Error4); 
                    StopListener(); 
                    break; 
            } 
        } 
 
        private void SendNextDataDatagram(byte[] ReceivedBytes, IPEndPoint RemoteEndPoint, string EndPointString) 
        { 
            try 
            { 
                byte[] DataBytes = State.GetData(ReceivedBytes[2], ReceivedBytes[3]); 
                byte[] SendBytes = new byte[DataBytes.Length + 4]; 
                DataBytes.CopyTo(SendBytes, 4); 
                SendBytes[1] = 3; 
                SendBytes[2] = State.BlockIDByte1; 
                SendBytes[3] = State.BlockIDByte2; 
                AddMsg(Level.Verbose, ident.ToString() + ": Sending bytes to " + EndPointString); 
                Send(RemoteEndPoint, SendBytes); 
            } 
            catch (System.IO.IOException ex) 
            { 
                AddMsg(Level.Info, "A problem occurred while trying to read the file and send to " + EndPointString); 
                AddMsg(Level.Info, ex.Message); 
                AddMsg(Level.Verbose, "Handled ACK exception: " + ex.Message); 
                AddMsg(Level.Debug, "Handled ACK exception: " + ex.StackTrace); 
                Send(RemoteEndPoint, Error1); 
                State.Close(); 
                StopListener(); 
            } 
        } 
 
        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 bool CheckForExistingTID(IPEndPoint RemoteEndPoint) 
        { 
            bool ReturnVal = false; 
            if (State != null) 
            { 
                //The TFTP server may change the remote port on the first packet when we are the client 
                if (ClientMode && 
                    (RemoteEndPoint.Address.ToString() == State.RemoteIPAddress) && 
                    (myEndpoint.Address.ToString() == State.LocalIPAddress) && 
                    (myEndpoint.Port == State.LocalPortNumber)) 
                { 
                    //If we find a TID update the timestamp 
                    State.Timestamp = DateTime.Now.Ticks; 
 
                    //ReturnIndex = StateIndex; 
                    //StateIndex = CurrStates.Count; 
                    ReturnVal = true; 
 
                    State.RemotePortNumber = RemoteEndPoint.Port; 
                } 
                else if ((RemoteEndPoint.Address.ToString() == State.RemoteIPAddress) && 
                    (RemoteEndPoint.Port == State.RemotePortNumber) && 
                    (myEndpoint.Address.ToString() == State.LocalIPAddress) && 
                    (myEndpoint.Port == State.LocalPortNumber)) 
                { 
                    //If we find a TID update the timestamp 
                    State.Timestamp = DateTime.Now.Ticks; 
 
                    //ReturnIndex = StateIndex; 
                    //StateIndex = CurrStates.Count; 
                    ReturnVal = true; 
                } 
            } 
            return ReturnVal; 
        } 
 
        private TFTPState CreateNewState(IPEndPoint RemoteEndPoint, int CurrOpcode, string filename, string type, int BlockSize) 
        { 
            TFTPState NewState = new TFTPState(myEndpoint.Address, 
                myEndpoint.Port, 
                RemoteEndPoint.Address, 
                RemoteEndPoint.Port, 
                CurrOpcode, 
                filename, 
                type, 
                FullPath, 
                AllowWRQOverwrite, 
                ResendInterval, 
                Timeout, 
                ClientMode, 
                BlockSize); 
 
            return NewState; 
        } 
 
        private void SendCallback(IAsyncResult result) 
        { 
            try 
            { 
                ((Socket)result.AsyncState).EndSendTo(result); 
            } 
            catch (ObjectDisposedException) 
            { } 
        } 
 
        private string[] FindOptions(byte[] ReceivedBytes, int NumReceivedBytes) 
        { 
            ArrayList ReturnList = new ArrayList(5); 
            ArrayList TempList = new ArrayList(10); 
            for (int index = 2; index < NumReceivedBytes; index++) 
            { 
                if (ReceivedBytes[index] == 0) 
                { 
                    ReturnList.Add(System.Text.Encoding.ASCII.GetString((byte[])TempList.ToArray(typeof(byte)))); 
                    TempList.Clear(); 
                } 
                else 
                { 
                    TempList.Add(ReceivedBytes[index]); 
                } 
            } 
            return (string[])ReturnList.ToArray(typeof(string)); 
        } 
 
        private bool SendOptions(string[] FoundOptions, TFTPState ChkState, IPEndPoint RemoteEndPoint) 
        { 
            bool returnval = false; 
            if (AllowOptions && (FoundOptions.Length > 2)) 
            { 
                ArrayList DataBytes = new ArrayList(20); 
                try 
                { 
                    DataBytes.Add(Convert.ToByte(0)); 
                    DataBytes.Add(Convert.ToByte(6)); 
                    for (int i = 2; i < FoundOptions.Length; i++) 
                    { 
                        //I'm not sure if this is the best way to implement setting up option responses but it works 
                        switch (FoundOptions[i].ToLower()) 
                        { 
                            case "tsize":       //RFC 2349 
                                #region tsize 
                                AddMsg(Level.Verbose, "Found tsize option"); 
                                if (State.Filesize > 0) 
                                { 
                                    State.TransferSizeOption = true; 
                                    DataBytes.Add(Convert.ToByte('t')); 
                                    DataBytes.Add(Convert.ToByte('s')); 
                                    DataBytes.Add(Convert.ToByte('i')); 
                                    DataBytes.Add(Convert.ToByte('z')); 
                                    DataBytes.Add(Convert.ToByte('e')); 
                                    DataBytes.Add(Convert.ToByte(0)); 
 
                                    byte[] sizebytes = System.Text.Encoding.ASCII.GetBytes(State.Filesize.ToString()); 
                                    foreach (byte SizeByte in sizebytes) 
                                    { 
                                        DataBytes.Add(SizeByte); 
                                    } 
                                    DataBytes.Add(Convert.ToByte(0)); 
 
                                    if ((ClientMode == false) && (State.TransferType == "write")) 
                                        State.FileLength = Convert.ToInt32(FoundOptions[i + 1]); 
                                    AddMsg(Level.Debug, "sending tsize = " + State.Filesize.ToString()); 
                                    AddMsg(Level.Debug, "Setup tsize reponse"); 
                                    returnval = true; 
                                } 
                                break; 
                                #endregion 
                            case "timeout":     //RFC 2349 
                                #region timeout 
                                AddMsg(Level.Verbose, "Found timeout option"); 
                                int RecvTimeout = Convert.ToInt32(FoundOptions[i + 1]); 
                                AddMsg(Level.Debug, "Timeout = " + RecvTimeout.ToString()); 
                                if ((RecvTimeout >= 1) && (RecvTimeout <= 255)) 
                                { 
                                    State.ResendIntervalSeconds = RecvTimeout; 
                                    State.TimeoutOption = true; 
                                    State.TimeoutOptionACK = true; 
 
                                    DataBytes.Add(Convert.ToByte('t')); 
                                    DataBytes.Add(Convert.ToByte('i')); 
                                    DataBytes.Add(Convert.ToByte('m')); 
                                    DataBytes.Add(Convert.ToByte('e')); 
                                    DataBytes.Add(Convert.ToByte('o')); 
                                    DataBytes.Add(Convert.ToByte('u')); 
                                    DataBytes.Add(Convert.ToByte('t')); 
                                    DataBytes.Add(Convert.ToByte(0)); 
                                    byte[] timeoutbytes = System.Text.Encoding.ASCII.GetBytes(RecvTimeout.ToString()); 
                                    foreach (byte TimeByte in timeoutbytes) 
                                    { 
                                        DataBytes.Add(TimeByte); 
                                    } 
                                    DataBytes.Add(Convert.ToByte(0)); 
                                    AddMsg(Level.Debug, "Setup timeout reponse"); 
 
                                    returnval = true; 
                                } 
                                break; 
                                #endregion 
                            case "blksize":     //RFC 2348 
                                #region blksize 
                                AddMsg(Level.Verbose, "Found blksize option"); 
                                int RecvBlocksize = Convert.ToInt32(FoundOptions[i + 1]); 
                                AddMsg(Level.Debug, "Blksize option = " + RecvBlocksize.ToString()); 
                                if ((RecvBlocksize >= 8) && (RecvBlocksize <= 65464)) 
                                { 
                                    State.BlocksizeOption = true; 
                                    State.BlocksizeOptionACK = true; 
                                    State.BlockSize = RecvBlocksize; 
 
                                    DataBytes.Add(Convert.ToByte('b')); 
                                    DataBytes.Add(Convert.ToByte('l')); 
                                    DataBytes.Add(Convert.ToByte('k')); 
                                    DataBytes.Add(Convert.ToByte('s')); 
                                    DataBytes.Add(Convert.ToByte('i')); 
                                    DataBytes.Add(Convert.ToByte('z')); 
                                    DataBytes.Add(Convert.ToByte('e')); 
                                    DataBytes.Add(Convert.ToByte(0)); 
                                    byte[] blocksizebytes = System.Text.Encoding.ASCII.GetBytes(RecvBlocksize.ToString()); 
                                    foreach (byte BlockByte in blocksizebytes) 
                                    { 
                                        DataBytes.Add(BlockByte); 
                                    } 
                                    DataBytes.Add(Convert.ToByte(0)); 
 
                                    AddMsg(Level.Debug, "Setup blksize reponse"); 
 
                                    returnval = true; 
                                } 
                                break; 
                                #endregion 
                            case "multicast":   //RFC 2090 
                                #region multicast 
                                AddMsg(Level.Verbose, "Found multicast option"); 
                                break; 
                                #endregion 
                            case "sbroadcast":  //Saw this in some IBM doc but can't find an RFC 
                                #region sbroadcast 
                                AddMsg(Level.Verbose, "Found sbroadcast option"); 
                                break; 
                                #endregion 
                            default: 
                                AddMsg(Level.Debug, "Found unknown option: " + FoundOptions[i]); 
                                break; 
                        } 
                        i++;    //Increment because we use them in pairs 
                    } 
                    if (returnval) 
                    { 
                        AddMsg(Level.Verbose, "Sending OACK to " + RemoteEndPoint.Address.ToString() + ":" + RemoteEndPoint.Port.ToString()); 
                        Send(RemoteEndPoint, (byte[])DataBytes.ToArray(typeof(byte))); 
                        sentOACK = true; 
                    } 
                } 
                catch (Exception ex) 
                { 
                    returnval = false; 
                    sentOACK = false; 
                    AddMsg(Level.Warning, "A problem occurred when parsing the received packet"); 
                    AddMsg(Level.Verbose, "Handled exception in send : " + ex.Message); 
                    AddMsg(Level.Debug, "Handled RRQ file exception: " + ex.StackTrace); 
                } 
            } 
            else 
            { 
                //An error did not occur while processing options 
                returnval = true; 
            } 
            return returnval; 
        } 
 
        ///  
        ///  
        ///  
        /// 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) 
        { 
            ClientMode = true; 
            ClientHost = Host; 
            IPEndPoint RemoteEndPoint = new IPEndPoint(IPAddress.Parse(Host), Port); 
 
            ArrayList DataBytes = new ArrayList(20); 
            DataBytes.Add(Convert.ToByte(0)); 
            DataBytes.Add(Convert.ToByte(1)); 
            byte[] filebytes = System.Text.Encoding.ASCII.GetBytes(Filename); 
            foreach (byte FileByte in filebytes) 
            { 
                DataBytes.Add(FileByte); 
            } 
            DataBytes.Add(Convert.ToByte(0)); 
            DataBytes.Add(Convert.ToByte(Convert.ToChar("o"))); 
            DataBytes.Add(Convert.ToByte(Convert.ToChar("c"))); 
            DataBytes.Add(Convert.ToByte(Convert.ToChar("t"))); 
            DataBytes.Add(Convert.ToByte(Convert.ToChar("e"))); 
            DataBytes.Add(Convert.ToByte(Convert.ToChar("t"))); 
            DataBytes.Add(Convert.ToByte(0)); 
            if (Filesize) 
            { 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("t"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("s"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("i"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("z"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("e"))); 
                DataBytes.Add(Convert.ToByte(0)); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("0"))); 
                DataBytes.Add(Convert.ToByte(0)); 
            } 
            if (TransferSize != 512) 
            { 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("b"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("l"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("k"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("s"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("i"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("z"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("e"))); 
                DataBytes.Add(Convert.ToByte(0)); 
                string size = TransferSize.ToString(); 
                foreach (char character in size) 
                    DataBytes.Add(Convert.ToByte(character)); 
                DataBytes.Add(Convert.ToByte(0)); 
            } 
            if (Timeout != 1) 
            { 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("t"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("i"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("m"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("e"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("o"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("u"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("t"))); 
                DataBytes.Add(Convert.ToByte(0)); 
                string time = Timeout.ToString(); 
                foreach (char character in time) 
                    DataBytes.Add(Convert.ToByte(character)); 
                DataBytes.Add(Convert.ToByte(0)); 
            } 
 
            AddMsg(Level.Info, "Sending get request for file " + Filename + " to " + Host + ":" + Port.ToString()); 
            Send(RemoteEndPoint, (byte[])DataBytes.ToArray(typeof(byte))); 
            State = CreateNewState(RemoteEndPoint, 2, Filename, "octet", TransferSize); 
        } 
 
        ///  
        ///  
        ///  
        /// 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) 
        { 
            string FixedFilename = Filename; 
            System.IO.FileInfo info = new System.IO.FileInfo(Filename); 
 
            if (info.Exists) 
            { 
 
                int slashLoc = Filename.LastIndexOf('\\'); 
                if (slashLoc >= 0) 
                { 
                    FullPath = Filename.Substring(0, slashLoc); 
                    FixedFilename = Filename.Substring(slashLoc + 1); 
                } 
 
                ClientMode = true; 
                PutClientMode = true; 
                ClientHost = Host; 
                IPEndPoint RemoteEndPoint = new IPEndPoint(IPAddress.Parse(Host), Port); 
 
                ArrayList DataBytes = new ArrayList(20); 
                DataBytes.Add(Convert.ToByte(0)); 
                DataBytes.Add(Convert.ToByte(2)); 
                byte[] filebytes = System.Text.Encoding.ASCII.GetBytes(FixedFilename); 
                foreach (byte FileByte in filebytes) 
                { 
                    DataBytes.Add(FileByte); 
                } 
                DataBytes.Add(Convert.ToByte(0)); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("o"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("c"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("t"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("e"))); 
                DataBytes.Add(Convert.ToByte(Convert.ToChar("t"))); 
                DataBytes.Add(Convert.ToByte(0)); 
                if (Filesize) 
                { 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("t"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("s"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("i"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("z"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("e"))); 
                    DataBytes.Add(Convert.ToByte(0)); 
                    string size = info.Length.ToString(); 
                    foreach (char character in size) 
                        DataBytes.Add(Convert.ToByte(character)); 
                    DataBytes.Add(Convert.ToByte(0)); 
                } 
                if (TransferSize != 512) 
                { 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("b"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("l"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("k"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("s"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("i"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("z"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("e"))); 
                    DataBytes.Add(Convert.ToByte(0)); 
                    string size = TransferSize.ToString(); 
                    foreach (char character in size) 
                        DataBytes.Add(Convert.ToByte(character)); 
                    DataBytes.Add(Convert.ToByte(0)); 
                } 
                if (Timeout != 1) 
                { 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("t"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("i"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("m"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("e"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("o"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("u"))); 
                    DataBytes.Add(Convert.ToByte(Convert.ToChar("t"))); 
                    DataBytes.Add(Convert.ToByte(0)); 
                    string time = Timeout.ToString(); 
                    foreach (char character in time) 
                        DataBytes.Add(Convert.ToByte(character)); 
                    DataBytes.Add(Convert.ToByte(0)); 
                } 
 
                info = null; 
 
                AddMsg(Level.Info, "Sending put request for file " + FixedFilename + " to " + Host); 
                Send(RemoteEndPoint, (byte[])DataBytes.ToArray(typeof(byte))); 
                State = CreateNewState(RemoteEndPoint, 1, FixedFilename, "octet", TransferSize); 
            } 
            else 
            { 
                AddMsg(Level.Info, "File " + Filename.ToString() + " does not exist."); 
            } 
        } 
 
        private void OnTFTPServerEvent(TFTPServerProcessEventArgs e) 
        { 
            if (TFTPServerProcessEvent != null) 
            { 
                TFTPServerProcessEvent(null, e); 
            } 
            else if (logger != null && logger.IsOpen) 
            { 
                logger.Log(e.EventLevel, e.EventString); 
            } 
        } 
 
        private void AddMsg(Level level, string text) 
        { 
            //TFTPServer handles actually logging the messages, just send them an event 
            OnTFTPServerEvent(new TFTPServerProcessEventArgs(text, level)); 
        } 
 
        ///  
        /// Gets whether we are listening for TFTP requests 
        ///  
        public bool IsListening 
        { 
            get 
            { 
                return Loop; 
            } 
        } 
 
        ///  
        /// The current TFTPState instance for this TFTP Server Process thread 
        ///  
        public TFTPState CurrState 
        { 
            get 
            { 
                return State; 
            } 
        } 
 
        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; 
            } 
        } 
    } 
}