private void OnTimer(object state)
        {
            bool notify = false;

            lock (m_Lock)
            {
                if (!m_Disposed)
                {
                    if (m_BlockRetry < m_Parent.m_MaxRetries)
                    {
                        m_BlockRetry++;
                        SendResponse();
                    }
                    else
                    {
                        TFTPServer.SendError(m_Socket, m_RemoteEndPoint, TFTPServer.ErrorCode.Undefined, "Timeout");
                        notify = true;
                    }
                }
            }

            if (notify)
            {
                Stop(true, new TimeoutException("Remote side didn't respond in time"));
            }
        }
        public override void Start()
        {
            var sessionLogConfiguration = new SessionLogEntry.TConfiguration()
            {
                FileLength     = -1,
                Filename       = m_Filename,
                IsUpload       = false,
                LocalEndPoint  = m_LocalEndPoint,
                RemoteEndPoint = m_RemoteEndPoint,
                StartTime      = DateTime.Now,
                WindowSize     = m_WindowSize
            };

            try
            {
                lock (m_Lock)
                {
                    try
                    {
                        m_Stream = m_Parent.GetReadStream(m_Filename);
                        m_Length = m_Stream.Length;
                        sessionLogConfiguration.FileLength = m_Length;
                        m_Position = 0;
                    }
                    catch (Exception e)
                    {
                        TFTPServer.SendError(m_Socket, m_RemoteEndPoint, TFTPServer.ErrorCode.FileNotFound, e.Message);
                        throw;
                    }
                    finally
                    {
                        m_SessionLog = m_Parent.SessionLog.CreateSession(sessionLogConfiguration);
                    }

                    // handle tsize option
                    if (m_RequestedOptions.ContainsKey(TFTPServer.Option_TransferSize))
                    {
                        if (m_Length >= 0)
                        {
                            m_AcceptedOptions.Add(TFTPServer.Option_TransferSize, m_Length.ToString());
                        }
                    }

                    if (m_AcceptedOptions.Count > 0)
                    {
                        m_BlockNumber = 0;
                        SendOptionsAck();
                    }
                    else
                    {
                        m_BlockNumber = 1;
                        SendData();
                    }
                }
            }
            catch (Exception e)
            {
                Stop(true, e);
            }
        }
 protected override void SendResponse()
 {
     // resend blocks in the window
     for (int t = 0; t < m_Window.Count; t++)
     {
         TFTPServer.Send(m_Socket, m_RemoteEndPoint, m_Window[t].Segment);
     }
     StartTimer();
 }
 public DownloadSession(
     TFTPServer parent,
     UDPSocket socket,
     IPEndPoint remoteEndPoint,
     Dictionary <string, string> requestedOptions,
     string filename,
     ushort windowSize,
     UDPSocket.OnReceiveDelegate onReceive)
     : base(parent, socket, remoteEndPoint, requestedOptions, filename, onReceive, 0)
 {
     m_WindowSize = windowSize;
 }
        private void SendOptionsAck()
        {
            var seg = TFTPServer.GetOptionsAckPacket(m_AcceptedOptions);

            m_Window.Add(new WindowEntry()
            {
                IsData = false, Length = 0, Segment = seg
            });
            TFTPServer.Send(m_Socket, m_RemoteEndPoint, seg);
            m_BlockRetry = 0;
            StartTimer();
        }
 private void SendData()
 {
     // fill the window up to the window size & send all the new packets
     while (m_Window.Count < m_WindowSize && !m_LastBlock)
     {
         byte[] buffer   = new byte[m_CurrentBlockSize];
         int    dataSize = m_Stream.Read(buffer, 0, m_CurrentBlockSize);
         var    seg      = TFTPServer.GetDataPacket((ushort)(m_BlockNumber + m_Window.Count), buffer, dataSize);
         m_Window.Add(new WindowEntry()
         {
             IsData = true, Length = dataSize, Segment = seg
         });
         m_LastBlock = (dataSize < m_CurrentBlockSize);
         TFTPServer.Send(m_Socket, m_RemoteEndPoint, seg);
         m_BlockRetry = 0;
         StartTimer();
     }
 }
        public override void ProcessData(ushort blockNr, ArraySegment <byte> data)
        {
            bool isComplete = false;

            lock (m_Lock)
            {
                if (blockNr == ((ushort)(m_BlockNumber + 1)))
                {
                    m_BlockNumber = blockNr;
                    m_LastBlock   = data.Count < m_CurrentBlockSize;
                    isComplete    = m_LastBlock;
                    m_Stream.Write(data.Array, data.Offset, data.Count);

                    m_Position += data.Count;
                    m_SessionLog.Progress(m_Position);

                    // send ack for current block, client will respond with next block
                    m_Window = TFTPServer.GetDataAckPacket(m_BlockNumber);
                    TFTPServer.Send(m_Socket, m_RemoteEndPoint, m_Window);
                    m_BlockRetry = 0;

                    if (m_LastBlock)
                    {
                        StopTimer();
                        m_SessionLog.Complete();
                    }
                    else
                    {
                        StartTimer();
                    }
                }
            }

            if (isComplete)
            {
                Stop(true, null);
            }
        }
        public override void Start()
        {
            var sessionLogConfiguration = new SessionLogEntry.TConfiguration()
            {
                FileLength     = -1,
                Filename       = m_Filename,
                IsUpload       = true,
                LocalEndPoint  = m_LocalEndPoint,
                RemoteEndPoint = m_RemoteEndPoint,
                StartTime      = DateTime.Now,
                WindowSize     = 1
            };

            try
            {
                lock (m_Lock)
                {
                    try
                    {
                        m_Length = m_RequestedOptions.ContainsKey(TFTPServer.Option_TransferSize) ? Int64.Parse(m_RequestedOptions[TFTPServer.Option_TransferSize]) : -1;
                        sessionLogConfiguration.FileLength = m_Length;
                        m_Stream   = m_Parent.GetWriteStream(m_Filename, m_Length);
                        m_Position = 0;
                    }
                    catch (Exception e)
                    {
                        TFTPServer.SendError(m_Socket, m_RemoteEndPoint, TFTPServer.ErrorCode.FileNotFound, e.Message);
                        throw;
                    }
                    finally
                    {
                        // always create a SessionLog (even if the file couldn't be opened), so Stop() will have somewhere to store its errors
                        m_SessionLog = m_Parent.SessionLog.CreateSession(sessionLogConfiguration);
                    }

                    // handle tsize option
                    if (m_RequestedOptions.ContainsKey(TFTPServer.Option_TransferSize))
                    {
                        // rfc2349: in Write Request packets, the size of the file, in octets, is specified in the
                        // request and echoed back in the OACK
                        m_AcceptedOptions.Add(TFTPServer.Option_TransferSize, m_RequestedOptions[TFTPServer.Option_TransferSize]);
                    }

                    if (m_AcceptedOptions.Count > 0)
                    {
                        // send options ack, client will respond with block number 1
                        m_Window = TFTPServer.GetOptionsAckPacket(m_AcceptedOptions);
                    }
                    else
                    {
                        // send ack for current block, client will respond with next block
                        m_Window = TFTPServer.GetDataAckPacket(m_BlockNumber);
                    }

                    TFTPServer.Send(m_Socket, m_RemoteEndPoint, m_Window);
                    m_BlockRetry = 0;
                    StartTimer();
                }
            }
            catch (Exception e)
            {
                Stop(true, e);
            }
        }
 public UploadSession(TFTPServer parent, UDPSocket socket, IPEndPoint remoteEndPoint, Dictionary <string, string> requestedOptions, string filename, UDPSocket.OnReceiveDelegate onReceive)
     : base(parent, socket, remoteEndPoint, requestedOptions, filename, onReceive, 1000)
 {
 }
 protected override void SendResponse()
 {
     TFTPServer.Send(m_Socket, m_RemoteEndPoint, m_Window);
     StartTimer();
 }
        public TFTPSession(TFTPServer parent, UDPSocket socket, IPEndPoint remoteEndPoint, Dictionary <string, string> requestedOptions, string filename, UDPSocket.OnReceiveDelegate onReceive, int socketDisposeDelay)
        {
            m_Parent             = parent;
            m_CurrentBlockSize   = TFTPServer.DefaultBlockSize;
            m_ResponseTimeout    = m_Parent.m_ResponseTimeout;
            m_RemoteEndPoint     = remoteEndPoint;
            m_Timer              = new Timer(new System.Threading.TimerCallback(OnTimer), this, Timeout.Infinite, Timeout.Infinite);
            m_RequestedOptions   = requestedOptions;
            m_Filename           = filename;
            m_SocketDisposeDelay = socketDisposeDelay;

            m_Length      = 0;
            m_LastBlock   = false;
            m_BlockNumber = 0;
            m_BlockRetry  = 0;

            foreach (var kvp in m_RequestedOptions)
            {
                switch (kvp.Key)
                {
                case TFTPServer.Option_Multicast:
                    // not supported
                    break;

                case TFTPServer.Option_Timeout:
                    //Console.WriteLine("Timeout of {0}", kvp.Value);
                    int requestedTimeout = int.Parse(kvp.Value);
                    // rfc2349 : valid values range between "1" and "255" seconds
                    if (requestedTimeout >= 1 && requestedTimeout <= 255)
                    {
                        m_ResponseTimeout = requestedTimeout * 1000;
                        m_AcceptedOptions.Add(TFTPServer.Option_Timeout, kvp.Value);
                    }
                    break;

                case TFTPServer.Option_TransferSize:
                    // handled in inherited classes
                    break;

                case TFTPServer.Option_BlockSize:
                    //Console.WriteLine("Blocksize of {0}", kvp.Value);
                    int requestedBlockSize = int.Parse(kvp.Value);
                    // rfc2348 : valid values range between "8" and "65464" octets, inclusive
                    if (requestedBlockSize >= 8 && requestedBlockSize <= 65464)
                    {
                        m_CurrentBlockSize = Math.Min(TFTPServer.MaxBlockSize, requestedBlockSize);
                        m_AcceptedOptions.Add(TFTPServer.Option_BlockSize, m_CurrentBlockSize.ToString());
                    }
                    break;
                }
            }

            if (socket != null)
            {
                m_OwnSocket = false;
                m_Socket    = socket;
            }
            else
            {
                m_OwnSocket = true;
                m_Socket    = new UDPSocket(
                    new IPEndPoint(m_Parent.m_ServerEndPoint.Address, 0),
                    m_CurrentBlockSize + 4,
                    m_Parent.m_DontFragment,
                    m_Parent.m_Ttl,
                    onReceive,
                    (sender, reason) => { Stop(true, reason); });
            }
            m_LocalEndPoint = (IPEndPoint)m_Socket.LocalEndPoint;
        }