// This file is part of BOINC. // http://boinc.berkeley.edu // Copyright (C) 2013 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License // as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // BOINC is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with BOINC. If not, see . #ifndef BOINC_ASYNCRPC_H #define BOINC_ASYNCRPC_H #if defined(__GNUG__) && !defined(__APPLE__) #pragma interface "AsyncRPC.cpp" #endif #ifndef __WXMAC__ #define BOINC_Condition wxCondition #define BOINC_Mutex wxMutex #else // Adapted from wxMac-2.8.10 #include #if 1 #define BOINC_Mutex wxMutex #define BOINC_Condition wxCondition #else class BOINC_Mutex { public: BOINC_Mutex( wxMutexType mutexType = wxMUTEX_DEFAULT ); ~BOINC_Mutex(); wxMutexError Lock(); wxMutexError TryLock(); wxMutexError Unlock(); bool IsOk() const { return m_isOk; } private: pthread_mutex_t m_mutex; bool m_isOk; // BOINC_Condition uses our m_mutex friend class BOINC_Condition; }; // Adapted from wxMac-2.8.10 but using native pthread_cond_*() class BOINC_Condition { public: BOINC_Condition(BOINC_Mutex& mutex); ~BOINC_Condition(); bool IsOk() const { return (m_BOINC_Mutex.IsOk() && mb_initOK); } wxCondError Wait(); wxCondError WaitTimeout(unsigned long milliseconds); void Signal(); void Broadcast(); private: BOINC_Mutex& m_BOINC_Mutex; pthread_cond_t m_cond; bool mb_initOK; DECLARE_NO_COPY_CLASS(BOINC_Condition) }; #endif #endif class CMainDocument; // Forward declaration enum RPC_SELECTOR { RPC_AUTHORIZE = 1, RPC_EXCHANGE_VERSIONS, RPC_GET_STATE, RPC_GET_RESULTS, RPC_GET_FILE_TRANSFERS, RPC_GET_SIMPLE_GUI_INFO1, RPC_GET_SIMPLE_GUI_INFO2, RPC_GET_PROJECT_STATUS1, RPC_GET_PROJECT_STATUS2, RPC_GET_ALL_PROJECTS_LIST, // 10 RPC_GET_DISK_USAGE, RPC_PROJECT_OP, RPC_SET_RUN_MODE, RPC_SET_GPU_MODE, RPC_SET_NETWORK_MODE, RPC_GET_SCREENSAVER_TASKS, RPC_RUN_BENCHMARKS, RPC_SET_PROXY_SETTINGS, RPC_GET_PROXY_SETTINGS, RPC_GET_MESSAGES, // 20 RPC_FILE_TRANSFER_OP, RPC_RESULT_OP, RPC_GET_HOST_INFO, RPC_QUIT, RPC_ACCT_MGR_INFO, RPC_GET_STATISTICS, RPC_NETWORK_AVAILABLE, RPC_GET_PROJECT_INIT_STATUS, RPC_GET_PROJECT_CONFIG, RPC_GET_PROJECT_CONFIG_POLL, // 30 RPC_LOOKUP_ACCOUNT, RPC_LOOKUP_ACCOUNT_POLL, RPC_CREATE_ACCOUNT, RPC_CREATE_ACCOUNT_POLL, RPC_PROJECT_ATTACH, RPC_PROJECT_ATTACH_FROM_FILE, RPC_PROJECT_ATTACH_POLL, RPC_ACCT_MGR_RPC, RPC_ACCT_MGR_RPC_POLL, RPC_GET_NEWER_VERSION, // 40 RPC_READ_GLOBAL_PREFS_OVERRIDE, RPC_READ_CC_CONFIG, RPC_GET_CC_STATUS, RPC_GET_GLOBAL_PREFS_FILE, RPC_GET_GLOBAL_PREFS_WORKING, RPC_GET_GLOBAL_PREFS_WORKING_STRUCT, RPC_GET_GLOBAL_PREFS_OVERRIDE, RPC_SET_GLOBAL_PREFS_OVERRIDE, RPC_GET_GLOBAL_PREFS_OVERRIDE_STRUCT, RPC_SET_GLOBAL_PREFS_OVERRIDE_STRUCT, // 50 RPC_GET_NOTICES, RPC_GET_CC_CONFIG, RPC_SET_CC_CONFIG, RPC_SET_LANGUAGE, NUM_RPC_SELECTORS }; enum ASYNC_RPC_TYPE { // Demand RPC: wait for completion before returning (usually // a user-initiated request.) RPC_TYPE_WAIT_FOR_COMPLETION = 1, // Periodic RPC: post request on queue and return immediately // (requested due to a timer interrupt.) RPC_TYPE_ASYNC_NO_REFRESH, // Periodic RPC as above, but on completion also process a // wxEVT_FRAME_REFRESHVIEW event to refresh the display. RPC_TYPE_ASYNC_WITH_REFRESH_AFTER, // Periodic RPC as above, but on completion also process a // wxEVT_FRAME_REFRESHVIEW event to refresh the display. RPC_TYPE_ASYNC_WITH_REFRESH_EVENT_LOG_AFTER, // Periodic RPC as above, but on completion also process a // wxEVT_TASKBAR_REFRESH event to refresh the taskbar icon. RPC_TYPE_ASYNC_WITH_UPDATE_TASKBAR_ICON_AFTER, NUM_RPC_TYPES }; // Pass the following structure to CMainDocument::RequestRPC() // The members are as follows: // // arg1 is usually the buffer to read into // // exchangeBuf is the (optional) buffer to exchange with after // completing the RPC, the buffer used by the Manager code. // Pass NULL if you don't want the buffer exchanged. // // arg2, arg3, arg4 are additional arguments when needed by the // RPC call; their usage varies for different RPC requests. // // rpcType is as described above // // completionTime is a pointer to a wxDateTime variable into which // to write the completion time of the RPC. It may be NULL. // // resultPtr is a pointer to an int into which to write the result // returned by the RPC call. It may be NULL. // // retval is for internal use by the async RPC logic; do not use. // // isActive is for internal use by the async RPC logic; do not use. // struct ASYNC_RPC_REQUEST { RPC_SELECTOR which_rpc; void *arg1; void *exchangeBuf; void *arg2; void *arg3; void *arg4; ASYNC_RPC_TYPE rpcType; wxDateTime *completionTime; double *RPCExecutionTime; int *resultPtr; int retval; bool isActive; ASYNC_RPC_REQUEST(); ~ASYNC_RPC_REQUEST(); void clear(); bool isSameAs(ASYNC_RPC_REQUEST& otherRequest); }; class AsyncRPC { public: AsyncRPC(CMainDocument *pDoc); ~AsyncRPC(); int RPC_Wait( RPC_SELECTOR which_rpc, void* arg1 = NULL, void* arg2 = NULL, void* arg3 = NULL, void* arg4 = NULL, bool hasPriority = false ); // Manager must do all RPC data transfers through AsyncRPC calls, so // this class must have methods corresponding to all RPC_CLIENT data // transfer operations, but NOT init(), init_async(), close(), etc. int authorize(const char* passwd) { return RPC_Wait(RPC_AUTHORIZE, (void*)passwd); } int exchange_versions(std::string client_name, VERSION_INFO& server) { return RPC_Wait(RPC_EXCHANGE_VERSIONS, (void*)&client_name, (void*)&server); } int get_state(CC_STATE& arg1) { return RPC_Wait(RPC_GET_STATE, (void*)&arg1); } int get_results(RESULTS& arg1, bool& arg2) { return RPC_Wait(RPC_GET_RESULTS, (void*)&arg1, (void*)&arg2); } int get_file_transfers(FILE_TRANSFERS& arg1) { return RPC_Wait(RPC_GET_FILE_TRANSFERS, (void*)&arg1); } int get_simple_gui_info(SIMPLE_GUI_INFO& arg1) { return RPC_Wait(RPC_GET_SIMPLE_GUI_INFO1, (void*)&arg1); } int get_simple_gui_info(PROJECTS& arg1, CC_STATE& ccbuf, RESULTS& rbuf, bool& activeTasksOnly) { return RPC_Wait(RPC_GET_SIMPLE_GUI_INFO2, (void*)&arg1, (void*)&ccbuf, (void*)&rbuf, (void*)&activeTasksOnly); } int get_project_status(PROJECTS& arg1, CC_STATE& arg2) { return RPC_Wait(RPC_GET_PROJECT_STATUS1, (void*)&arg1, (void*)&arg2); } int get_project_status(PROJECTS& arg1) { return RPC_Wait(RPC_GET_PROJECT_STATUS2, (void*)&arg1); } int get_all_projects_list(ALL_PROJECTS_LIST& arg1) { return RPC_Wait(RPC_GET_ALL_PROJECTS_LIST, (void*)&arg1); } int get_disk_usage(DISK_USAGE& arg1) { return RPC_Wait(RPC_GET_DISK_USAGE, (void*)&arg1); } int project_op(PROJECT& arg1, const char* op) { return RPC_Wait(RPC_PROJECT_OP, (void*)&arg1, (void*)op); } int set_run_mode(int mode, double duration) { return RPC_Wait(RPC_SET_RUN_MODE, (void*)&mode, (void*)&duration); } // if duration is zero, change is permanent. // otherwise, after duration expires, // restore last permanent mode int set_gpu_mode(int mode, double duration) { return RPC_Wait(RPC_SET_GPU_MODE, (void*)&mode, (void*)&duration); } int set_network_mode(int mode, double duration) { return RPC_Wait(RPC_SET_NETWORK_MODE, (void*)&mode, (void*)&duration); } int get_screensaver_tasks(int& suspend_reason, RESULTS& rbuf) { return RPC_Wait(RPC_GET_SCREENSAVER_TASKS, (void*)&suspend_reason, (void*)&rbuf); } int run_benchmarks() { return RPC_Wait(RPC_RUN_BENCHMARKS); } int set_proxy_settings(GR_PROXY_INFO& arg1) { return RPC_Wait(RPC_SET_PROXY_SETTINGS, (void*)&arg1); } int get_proxy_settings(GR_PROXY_INFO& arg1) { return RPC_Wait(RPC_GET_PROXY_SETTINGS, (void*)&arg1); } int get_messages(int seqno, MESSAGES& arg1) { return RPC_Wait(RPC_GET_MESSAGES, (void*)&seqno, (void*)&arg1); } int get_notices(int seqno, NOTICES& arg1) { return RPC_Wait(RPC_GET_NOTICES, (void*)&seqno, (void*)&arg1); } int file_transfer_op(FILE_TRANSFER& arg1, const char* op) { return RPC_Wait(RPC_FILE_TRANSFER_OP, (void*)&arg1, (void*)op); } int result_op(RESULT& arg1, const char* op) { return RPC_Wait(RPC_RESULT_OP, (void*)&arg1, (void*)op); } int get_host_info(HOST_INFO& arg1) { return RPC_Wait(RPC_GET_HOST_INFO, (void*)&arg1); } int quit() { return RPC_Wait(RPC_QUIT); } int acct_mgr_info(ACCT_MGR_INFO& arg1) { return RPC_Wait(RPC_ACCT_MGR_INFO, (void*)&arg1); } int get_statistics(PROJECTS& arg1) { return RPC_Wait(RPC_GET_STATISTICS, (void*)&arg1); } int network_available() { return RPC_Wait(RPC_NETWORK_AVAILABLE); } int get_project_init_status(PROJECT_INIT_STATUS& pis) { return RPC_Wait(RPC_GET_PROJECT_INIT_STATUS, (void*)&pis); } // the following are asynch operations. // Make the first call to start the op, // call the second one periodically until it returns zero. // TODO: do project update // int get_project_config(std::string url) { return RPC_Wait(RPC_GET_PROJECT_CONFIG, (void*)&url); } int get_project_config_poll(PROJECT_CONFIG& arg1) { return RPC_Wait(RPC_GET_PROJECT_CONFIG_POLL, (void*)&arg1); } int lookup_account(ACCOUNT_IN& arg1) { return RPC_Wait(RPC_LOOKUP_ACCOUNT, (void*)&arg1); } int lookup_account_poll(ACCOUNT_OUT& arg1) { return RPC_Wait(RPC_LOOKUP_ACCOUNT_POLL, (void*)&arg1); } int create_account(ACCOUNT_IN& arg1) { return RPC_Wait(RPC_CREATE_ACCOUNT, (void*)&arg1); } int create_account_poll(ACCOUNT_OUT& arg1) { return RPC_Wait(RPC_CREATE_ACCOUNT_POLL, (void*)&arg1); } int project_attach( const char* url, const char* auth, const char* project_name ) { return RPC_Wait(RPC_PROJECT_ATTACH, (void*)url, (void*)auth, (void*)project_name); } int project_attach_from_file() { return RPC_Wait(RPC_PROJECT_ATTACH_FROM_FILE); } int project_attach_poll(PROJECT_ATTACH_REPLY& arg1) { return RPC_Wait(RPC_PROJECT_ATTACH_POLL, (void*)&arg1); } int acct_mgr_rpc( const char* url, const char* name, const char* passwd, bool use_config_file=false ) { return RPC_Wait(RPC_ACCT_MGR_RPC, (void*)url, (void*)name, (void*)passwd, (void*)use_config_file); } int acct_mgr_rpc_poll(ACCT_MGR_RPC_REPLY& arg1) { return RPC_Wait(RPC_ACCT_MGR_RPC_POLL, (void*)&arg1); } int get_newer_version(std::string& version, std::string& version_download_url) { return RPC_Wait(RPC_GET_NEWER_VERSION, (void*)&version, (void*)&version_download_url); } int read_global_prefs_override() { return RPC_Wait(RPC_READ_GLOBAL_PREFS_OVERRIDE); } int read_cc_config() { return RPC_Wait(RPC_READ_CC_CONFIG); } int get_cc_status(CC_STATUS& arg1) { return RPC_Wait(RPC_GET_CC_STATUS, (void*)&arg1); } int get_global_prefs_file(std::string& arg1) { return RPC_Wait(RPC_GET_GLOBAL_PREFS_FILE, (void*)&arg1); } int get_global_prefs_working(std::string& arg1) { return RPC_Wait(RPC_GET_GLOBAL_PREFS_WORKING, (void*)&arg1); } int get_global_prefs_working_struct(GLOBAL_PREFS& arg1, GLOBAL_PREFS_MASK& arg2) { return RPC_Wait(RPC_GET_GLOBAL_PREFS_WORKING_STRUCT, (void*)&arg1, (void*)&arg2); } int get_global_prefs_override(std::string& arg1) { return RPC_Wait(RPC_GET_GLOBAL_PREFS_OVERRIDE, (void*)&arg1); } int set_global_prefs_override(std::string& arg1) { return RPC_Wait(RPC_SET_GLOBAL_PREFS_OVERRIDE, (void*)&arg1); } int get_global_prefs_override_struct(GLOBAL_PREFS& arg1, GLOBAL_PREFS_MASK& arg2) { return RPC_Wait(RPC_GET_GLOBAL_PREFS_OVERRIDE_STRUCT, (void*)&arg1, (void*)&arg2); } int set_global_prefs_override_struct(GLOBAL_PREFS& arg1, GLOBAL_PREFS_MASK& arg2) { return RPC_Wait(RPC_SET_GLOBAL_PREFS_OVERRIDE_STRUCT, (void*)&arg1, (void*)&arg2); } int get_cc_config(CC_CONFIG& arg1, LOG_FLAGS& arg2) { return RPC_Wait(RPC_GET_CC_CONFIG, (void*)&arg1, (void*)&arg2); } int set_cc_config(CC_CONFIG& arg1, LOG_FLAGS& arg2) { return RPC_Wait(RPC_SET_CC_CONFIG, (void*)&arg1, (void*)&arg2); } private: CMainDocument* m_pDoc; }; class RPCThread : public wxThread { public: RPCThread(CMainDocument *pDoc, BOINC_Mutex* pRPC_Thread_Mutex, BOINC_Condition* pRPC_Thread_Condition, BOINC_Mutex* pRPC_Request_Mutex, BOINC_Condition* RPC_Request_Condition ); virtual void *Entry(); private: int ProcessRPCRequest(); CMainDocument* m_pDoc; BOINC_Mutex* m_pRPC_Thread_Mutex; BOINC_Condition* m_pRPC_Thread_Condition; BOINC_Mutex* m_pRPC_Request_Mutex; BOINC_Condition* m_pRPC_Request_Condition; }; class AsyncRPCDlg : public wxDialog { DECLARE_DYNAMIC_CLASS( AsyncRPCDlg ) DECLARE_EVENT_TABLE() public: AsyncRPCDlg(); void OnRPCDlgTimer(wxTimerEvent &event); void OnExit(wxCommandEvent& event); }; class CRPCFinishedEvent : public wxEvent { public: CRPCFinishedEvent(wxEventType evtType) : wxEvent(-1, evtType) { SetEventObject(wxTheApp); } virtual wxEvent *Clone() const { return new CRPCFinishedEvent(*this); } }; BEGIN_DECLARE_EVENT_TYPES() DECLARE_EVENT_TYPE( wxEVT_RPC_FINISHED, -1 ) END_DECLARE_EVENT_TYPES() #define EVT_RPC_FINISHED(fn) \ DECLARE_EVENT_TABLE_ENTRY(wxEVT_RPC_FINISHED, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL), #endif