#ifndef __FILEZILLAENGINEPRIVATE_H__ #define __FILEZILLAENGINEPRIVATE_H__ #include #include #include #include #include "engine_context.h" #include "FileZillaEngine.h" #include "option_change_event_handler.h" #include class CControlSocket; class CLogging; class CRateLimiter; enum EngineNotificationType { engineCancel, engineTransferEnd }; struct filezilla_engine_event_type; typedef fz::simple_event CFileZillaEngineEvent; class CTransferStatusManager final { public: CTransferStatusManager(CFileZillaEnginePrivate& engine); CTransferStatusManager(CTransferStatusManager const&) = delete; CTransferStatusManager& operator=(CTransferStatusManager const&) = delete; bool empty(); void Init(wxFileOffset totalSize, wxFileOffset startOffset, bool list); void Reset(); void SetStartTime(); void SetMadeProgress(); void Update(wxFileOffset transferredBytes); CTransferStatus Get(bool &changed); protected: fz::mutex mutex_; CTransferStatus status_; std::atomic currentOffset_{}; int send_state_{}; CFileZillaEnginePrivate& engine_; }; class CFileZillaEnginePrivate final : public fz::event_handler, COptionChangeEventHandler { public: CFileZillaEnginePrivate(CFileZillaEngineContext& engine_context, CFileZillaEngine& parent); virtual ~CFileZillaEnginePrivate(); int Init(wxEvtHandler *pEventHandler); int Execute(CCommand const& command); int Cancel(); int ResetOperation(int nErrorCode); const CCommand *GetCurrentCommand() const; Command GetCurrentCommandId() const; bool IsBusy() const; bool IsConnected() const; bool IsPendingAsyncRequestReply(std::unique_ptr const& pNotification); bool SetAsyncRequestReply(std::unique_ptr && pNotification); unsigned int GetNextAsyncRequestNumber(); CTransferStatus GetTransferStatus(bool &changed); int CacheLookup(CServerPath const& path, CDirectoryListing& listing); static bool IsActive(CFileZillaEngine::_direction direction); void SetActive(int direction); // Add new pending notification void AddNotification(CNotification *pNotification); void AddLogNotification(CLogmsgNotification *pNotification); std::unique_ptr GetNextNotification(); COptionsBase& GetOptions() { return m_options; } CRateLimiter& GetRateLimiter() { return m_rateLimiter; } CDirectoryCache& GetDirectoryCache() { return directory_cache_; } CPathCache& GetPathCache() { return path_cache_; } void SendDirectoryListingNotification(const CServerPath& path, bool onList, bool modified, bool failed); // If deleting or renaming a directory, it could be possible that another // engine's CControlSocket instance still has that directory as // current working directory (m_CurrentPath) // Since this would cause problems, this function interate over all engines // connected ot the same server and invalidates the current working // directories if they match or if it is a subdirectory of the changed // directory. void InvalidateCurrentWorkingDirs(const CServerPath& path); int GetEngineId() const {return m_engine_id; } CTransferStatusManager transfer_status_; protected: virtual void OnOptionsChanged(changed_options_t const& options); void SendQueuedLogs(bool reset_flag = false); void ClearQueuedLogs(bool reset_flag); bool ShouldQueueLogsFromOptions() const; int CheckCommandPreconditions(CCommand const& command, bool checkBusy); bool CheckAsyncRequestReplyPreconditions(std::unique_ptr const& reply); void OnSetAsyncRequestReplyEvent(std::unique_ptr const& reply); // Command handlers, only called by CFileZillaEngine::Command int Connect(const CConnectCommand &command); int Disconnect(const CDisconnectCommand &command); int List(const CListCommand &command); int FileTransfer(const CFileTransferCommand &command); int RawCommand(const CRawCommand& command); int Delete(CDeleteCommand& command); int RemoveDir(const CRemoveDirCommand& command); int Mkdir(const CMkdirCommand& command); int Rename(const CRenameCommand& command); int Chmod(const CChmodCommand& command); void DoCancel(); int ContinueConnect(); void operator()(fz::event_base const& ev); void OnEngineEvent(EngineNotificationType type); void OnTimer(int timer_id); void OnCommandEvent(); // General mutex for operations on the engine // Todo: More fine-grained locking, a global mutex isn't nice static fz::mutex mutex_; // Used to synchronize access to the notification list fz::mutex notification_mutex_; wxEvtHandler *m_pEventHandler{}; int m_engine_id; static std::vector m_engineList; // Indicicates if data has been received/sent and whether to send any notifications static std::atomic_int m_activeStatus[2]; // Remember last path used in a dirlisting. CServerPath m_lastListDir; fz::monotonic_clock m_lastListTime; std::unique_ptr m_pControlSocket; std::unique_ptr m_pCurrentCommand; // Protect access to these three with notification_mutex_ std::list m_NotificationList; bool m_maySendNotificationEvent{true}; unsigned int m_asyncRequestCounter{}; bool m_bIsInCommand{}; //true if Command is on the callstack int m_nControlSocketError{}; COptionsBase& m_options; CLogging* m_pLogging; // Everything related to the retry code // ------------------------------------ void RegisterFailedLoginAttempt(const CServer& server, bool critical); // Get the amount of time to wait till next reconnection attempt in milliseconds unsigned int GetRemainingReconnectDelay(const CServer& server); struct t_failedLogins final { CServer server; fz::datetime time; bool critical{}; }; static std::list m_failedLogins; int m_retryCount{}; fz::timer_id m_retryTimer{}; CRateLimiter& m_rateLimiter; CDirectoryCache& directory_cache_; CPathCache& path_cache_; CFileZillaEngine& parent_; bool queue_logs_{true}; std::deque queued_logs_; }; struct command_event_type{}; typedef fz::simple_event CCommandEvent; struct async_request_reply_event_type{}; typedef fz::simple_event> CAsyncRequestReplyEvent; #endif //__FILEZILLAENGINEPRIVATE_H__