/// <summary> /// Erzeugen des Datenkanals. /// </summary> /// <param name="result">Aktuelle Informationen zum zugehörigen Steuerkanal.</param> private void OnAcceptPassive(IAsyncResult result) { // Report FTPMain.Log("OnAcceptPassive"); // We are terminating if (null == m_Passive) { return; } // What to do Processor processor; // Synchronize lock (m_DataLock) { // Get the communication socket m_Data = new DataChannel(m_Passive.EndAccept(result), OnDataChannelFinished); // Load processor processor = m_DelayedProcessor; // Reset m_DelayedProcessor = null; } // Nothing to do if (null != processor) { processor(m_DelayedCommand); } }
/// <summary> /// Scließt einen <see cref="Socket"/>. /// </summary> /// <param name="socket">Die Netzwerkverbindung.</param> /// <param name="shutdown">Gesetzt, wenn ein <see cref="Socket.Shutdown"/> ausgeführt werden soll (nicht /// für Steuerkanäle).</param> /// <returns>Gesetzt, wenn die Netzwerkverbindung tatsächlich geschlossen wurde.</returns> private bool Close(ref Socket socket, bool shutdown) { // Report FTPMain.Log("FTPClient closing"); // Start cleanup using (Socket cleanup = socket) if (null != cleanup) { // Forget socket = null; // Close if (shutdown) { cleanup.Shutdown(SocketShutdown.Both); } cleanup.Close(); // Did it return(true); } // Did nothing return(false); }
/// <summary> /// Beendet die Nutzung dieses Datenkanals endgültig. /// </summary> private void Close() { // Report FTPMain.Log("DataChannel closing"); // Process using (Socket cleanup = m_Socket) if (null != cleanup) { // Wipe out m_Socket = null; // Shutdown cleanup.Shutdown(SocketShutdown.Both); cleanup.Close(); // Report if (null != m_OnFinished) { m_OnFinished(this); } } // Check file using (Stream file = m_File) if (null != file) { // Forget m_File = null; // Close file.Close(); } }
/// <summary> /// Erkennt das Ende des Versendens eines Stücks aus einer Datei. /// </summary> /// <param name="result">Informationen zum Ergebnis des Versendens.</param> private void FinishChunk(IAsyncResult result) { // Report FTPMain.Log("FinishChunk"); // Be safe try { // Attach to socket Socket socket = (Socket)result.AsyncState; // Terminate request socket.EndSend(result); // Send next chunk if (m_Abort.WaitOne(0, false)) { // Stop right now Close(); } else { // Continue with next chunk Send(m_File); } } catch { // Close all Close(); } }
/// <summary> /// Beendet dieses Datenkanal vorzeitig. /// </summary> public void Abort() { // Report FTPMain.Log("DataChannel aborted"); // Signal the very end m_Abort.Set(); }
/// <summary> /// Beendet den Datenkanal. /// </summary> public void Abort() { // Report FTPMain.Log("FTPClient aborting"); // Synchronized lock (m_DataLock) if (null != m_Data) { m_Data.Abort(); } }
/// <summary> /// Schließt den Datenkanal. /// </summary> private void CloseData() { // Report FTPMain.Log("CloseData"); // Reset m_DelayedProcessor = null; // Start cleanup data channel lock (m_DataLock) using (DataChannel cleanup = m_Data) m_Data = null; }
/// <summary> /// Erzeugt eine neue Datenkanalinstanz. /// </summary> /// <param name="socket">Der zugehörige Datenkanal.</param> /// <param name="onFinished">Methode, die nach dem Schliessen des Datenkanals aufgerufen werden soll.</param> public DataChannel(Socket socket, FinishedHandler onFinished) { // Remember m_OnFinished = onFinished; // Attach to socket m_Socket = socket; // Use asynchronous m_Socket.Blocking = false; // Report FTPMain.Log("DataChannel created"); }
/// <summary> /// Schließt die Verbindung zum Client. /// </summary> public void Close() { // Report FTPMain.Log("FTPClient Close() called"); // Close passive socket ClosePassive(); // Start cleanup if (Close(ref m_Socket, true)) { if (null != m_OnFinished) { m_OnFinished(this); } } }
/// <summary> /// Meldet das Ergebnis einer Operation. /// </summary> /// <param name="toSend">Die zu übermittelnden Daten.</param> /// <returns>Informationen zum gestarteten Netzwerkvorgang.</returns> private IAsyncResult Send(byte[] toSend) { // Be safe try { // Report FTPMain.Log("FTPClient started to send {0} bytes", toSend.Length); // Start return(m_Socket.BeginSend(toSend, 0, toSend.Length, SocketFlags.None, OnSendCompleteControl, null)); } catch { // In error return(null); } }
/// <summary> /// Wird vom Datenkanal <see cref="DataChannel"/> aufgerufen, sobald alle Daten übertragen wurden. /// </summary> /// <param name="data">Der abgeschlossene Datenkanal.</param> private void OnDataChannelFinished(DataChannel data) { // Report Send(226, "Transfer Complete"); // Terminate on empty file if (!data.GotData) { // Report FTPMain.Log("Detected empty File"); // Remember m_EmptyFile = true; // Terminate Close(); } }
/// <summary> /// Das übermitteln der Nachricht wurde abgeschlossen. /// </summary> /// <param name="result">Ergebnis zur gerade abgeschlossenen Operation.</param> private void OnSendCompleteControl(IAsyncResult result) { // Report FTPMain.Log("OnSendCompleteControl"); // Be safe try { // Finish m_Socket.EndSend(result); // Primary communication m_Socket.BeginReceive(m_Buffer, 0, m_Buffer.Length, SocketFlags.None, OnReceive, null); } catch { // All done Close(); } }
/// <summary> /// Versendet eine Zeichenkette über den Datenkanal. /// </summary> /// <param name="text">Der Inhalt der zu verwendenden Zeichenkette.</param> public void Send(string text) { // Report FTPMain.Log("Send {0}", text); // To byte array byte[] toSend = Encoding.Default.GetBytes(text); // Be safe try { // Start sending m_Socket.BeginSend(toSend, 0, toSend.Length, SocketFlags.None, FinishString, m_Socket); } catch { // Terminate on any error Close(); } }
/// <summary> /// Erkennt das Ende des Versendens einer Zeichenkette. /// </summary> /// <param name="result">Informationen über das Ergebnis des Versendens.</param> private void FinishString(IAsyncResult result) { // Report FTPMain.Log("FinishString"); // Be safe try { // Attach to socket Socket socket = (Socket)result.AsyncState; // Terminate request socket.EndSend(result); } catch { // Ignore any error } // Close all Close(); }
/// <summary> /// Es wurde ein FTP Befehl empfangen. /// </summary> /// <param name="result">Informationen zu den Daten des Befehls.</param> private void OnReceive(IAsyncResult result) { // Report FTPMain.Log("OnReceive"); // Already done if (null == m_Socket) { // Report FTPMain.Log("! No socket"); // Done return; } // The command string command; // Be safe try { // Get data int bytes = m_Socket.EndReceive(result); // Report FTPMain.Log("Received {0} Bytes", bytes); // Finished if (bytes < 1) { // Terminate Close(); // Done return; } // Get the command command = Encoding.Default.GetString(m_Buffer, 0, bytes); // Report FTPMain.Log("Received Command {0}", command); } catch { // Terminate Close(); // Done return; } // Report Debug.Write(string.Format("{1}:{2} {0}", command, Thread.CurrentThread.ManagedThreadId, DateTime.Now.Ticks)); // Dispatch string key = command.Split(' ', '\r', '\n')[0]; // Process Processor processor; if (m_Processors.TryGetValue(key, out processor)) { processor(command.Substring(4, command.Length - 6).Trim()); } }
/// <summary> /// Sendet die nächsten Bytes der angegebenen Datei über den Datenkanal. Wurde dieser Teil /// erfolgreich verschickt, dann wird der nächste Teil abgerufen. /// </summary> /// <param name="file">Zu versendende Datei.</param> public void Send(Stream file) { // Report FTPMain.Log("Send Stream"); // At least we tried if (!m_GotData.HasValue) { m_GotData = false; } // Create buffer if (null == m_Buffer) { m_Buffer = new byte[100000]; } // May retry - give us 30 seconds to detect end of live recording for (int retry = FTPMain.ShutdownDelay; retry-- > 0;) { // Report FTPMain.Log("Awaiting Data"); // Read bytes int bytes = file.Read(m_Buffer, 0, m_Buffer.Length); // Report FTPMain.Log("Got {0} Bytes", bytes); // Wait a bit if (bytes < 1) { // Delay if (m_Abort.WaitOne(1000, true)) { break; } // Next continue; } // Report FTPMain.ReportDataFromFile(bytes); // At least anything m_GotData = true; // Restart retry counter retry = FTPMain.ShutdownDelay; // Try to send this chunk try { // Remember file for next chunk m_File = file; // Try to send m_Socket.BeginSend(m_Buffer, 0, bytes, SocketFlags.None, FinishChunk, m_Socket); // Report FTPMain.Log("BeginSend {0} called", bytes); // Wait for next chunk return; } catch { // Terminate on any error break; } } // Terminate Close(); }