From 00ccb0df613d9f66e6cc77aa1646262f618a0eec Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 1 Dec 2005 08:07:07 +0000 Subject: [PATCH] -detach option for core client on Windows svn path=/trunk/boinc/; revision=9016 --- checkin_notes | 328 ++++++++++++++++++++++-------------------- client/client_state.C | 11 +- client/client_state.h | 5 +- client/cs_cmdline.C | 3 + client/main.C | 89 ++++++++++-- 5 files changed, 258 insertions(+), 178 deletions(-) diff --git a/checkin_notes b/checkin_notes index b68ccb3153..a9d9231574 100755 --- a/checkin_notes +++ b/checkin_notes @@ -12015,12 +12015,12 @@ David 22 Sept 2005 gui_rpc_server_ops.C David 22 Sept 2005 - - we were assuming that if a scheduler RPC reply didn't - have a user ID, it must be because of a bad account key. - Not so - could also be major version mismatch with old schedulers + - we were assuming that if a scheduler RPC reply didn't + have a user ID, it must be because of a bad account key. + Not so - could also be major version mismatch with old schedulers - client/ - scheduler_op.C + client/ + scheduler_op.C David 22 Sept 2005 - Change "Macedonia, The Former Yugoslav Republic of" to "Macedonia" @@ -12205,37 +12205,37 @@ Janus 27 Sept 2005 util.inc user/ forum_post.php - forum_edit.php + forum_edit.php languages/translations en.po David 27 Sept 2005 - - code cleanup: - - remove bool has_* from PROJECT_INIT - (just use string length) - - in PROJECT_INIT, always keep URL in canonical form - - PROJECT_INIT: clear it if delete file - - in acct_mgr_info GUI RPC reply, use - instead of . - - in project_attach and acct_mgr_rpc GUI RPC requests, use - instead of - - in ACCT_MGR_INFO, rename cached_credentials to have_credentials + - code cleanup: + - remove bool has_* from PROJECT_INIT + (just use string length) + - in PROJECT_INIT, always keep URL in canonical form + - PROJECT_INIT: clear it if delete file + - in acct_mgr_info GUI RPC reply, use + instead of . + - in project_attach and acct_mgr_rpc GUI RPC requests, use + instead of + - in ACCT_MGR_INFO, rename cached_credentials to have_credentials - client/ - acct_setup.C,h - client_state.C - gui_rpc_server_ops.C - clientgui/ - MainFrame.cpp - lib/ - gui_rpc_client.h - gui_rpc_client_ops.C + client/ + acct_setup.C,h + client_state.C + gui_rpc_server_ops.C + clientgui/ + MainFrame.cpp + lib/ + gui_rpc_client.h + gui_rpc_client_ops.C David 27 Sept 2005 - if doing CPU benchmarks, don't call most poll functions - client/ - client_state.C + client/ + client_state.C Rom 27 Sept 2005 - Some more cleanup. @@ -12250,23 +12250,23 @@ Rom 27 Sept 2005 gui_rpc_client_ops.C David 27 Sept 2005 - - finish the code to pass messages back to the Manager from - 1) project attach - 2) acct mgr RPC - 3) get project config + - finish the code to pass messages back to the Manager from + 1) project attach + 2) acct mgr RPC + 3) get project config - Rom: please add code to show these messages in Manager. + Rom: please add code to show these messages in Manager. - client/ - acct_setup.h - cs_scheduler.C - gui_rpc_server_ops.C - clientgui/wizards/ - AccountManagerProcessingPage.cpp - ProjectProcessingPage.cpp - lib/ - gui_rpc_client.h - gui_rpc_client_ops.C + client/ + acct_setup.h + cs_scheduler.C + gui_rpc_server_ops.C + clientgui/wizards/ + AccountManagerProcessingPage.cpp + ProjectProcessingPage.cpp + lib/ + gui_rpc_client.h + gui_rpc_client_ops.C Rom 27 Sept 2005 - Add server message support to the attach to project wizard. @@ -12390,9 +12390,9 @@ Reinhard 29 Sept 2005 client/ Makefile.am m4/ - sah_check_lib.m4 + sah_check_lib.m4 tools/ - Makefile.am + Makefile.am Rom 29 Sept 2005 - Account not found page should show a finish button instead of a next @@ -13145,29 +13145,29 @@ David 13 Oct 2005 David 13 Oct 2005 - Fix a moderate security loophole in GUI RPC. - Old: by default, core client doesn't create a password file - (gui_rpc_auth.cfg). - Therefore any process on the local host can connect to it; - even processes belonging to other users. - So if user X is running BOINC, evil user Y can use GUI - RPCs to attach BOINC to a rogue project, - causing bad code to run as user X. - New: on startup, if the core client doesn't find a password file, - it creates one, writes a long random string to it, - and (on Unix) makes it user-read/write only. - The BOINC Manager, when connecting to the local host, - looks for a password file in the current directory. + Old: by default, core client doesn't create a password file + (gui_rpc_auth.cfg). + Therefore any process on the local host can connect to it; + even processes belonging to other users. + So if user X is running BOINC, evil user Y can use GUI + RPCs to attach BOINC to a rogue project, + causing bad code to run as user X. + New: on startup, if the core client doesn't find a password file, + it creates one, writes a long random string to it, + and (on Unix) makes it user-read/write only. + The BOINC Manager, when connecting to the local host, + looks for a password file in the current directory. - Bottom line: a user running BOINC is now protected against - other users on the same host. + Bottom line: a user running BOINC is now protected against + other users on the same host. - NOTE: this could cause some angst for Mac users, - if they expect things to work the same for all users. + NOTE: this could cause some angst for Mac users, + if they expect things to work the same for all users. - client/ - gui_rpc_server.C - clientgui/ - MainDocument.cpp + client/ + gui_rpc_server.C + clientgui/ + MainDocument.cpp David 16 Oct 2005 - User web: fix bug that caused very few profiles to @@ -13224,11 +13224,11 @@ Reinhard 19 Oct 2005 ./_autosetup David 20 Oct 2005 - - removed declaration of g_hIdleDetectionDll from lib/hostinfo.h - (what the heck was it doing there??) + - removed declaration of g_hIdleDetectionDll from lib/hostinfo.h + (what the heck was it doing there??) - lib/ - hostinfo.h + lib/ + hostinfo.h David 20 Oct 2005 - core client: delete project_init.xml only on detach via GUI RPC @@ -13299,22 +13299,22 @@ Charlie 21 Oct 2005 project.pbxproj David 22 Oct 2005 - - Prevent the "merge host" feature from being used - to merge distinct hosts - (and create host records with exaggerated credit totals). - Hosts X and Y are considered "compatible" (for merging) - only if X.rpc_time < Y.create_time or vice-versa. - - When merging hosts X and Y, - a) decay their expavg_credit prior to adding and updating - b) set create_time to the min of the two - c) if the target is older, update its rpc_time and rpc_seqno + - Prevent the "merge host" feature from being used + to merge distinct hosts + (and create host records with exaggerated credit totals). + Hosts X and Y are considered "compatible" (for merging) + only if X.rpc_time < Y.create_time or vice-versa. + - When merging hosts X and Y, + a) decay their expavg_credit prior to adding and updating + b) set create_time to the min of the two + c) if the target is older, update its rpc_time and rpc_seqno - html/ - inc/ - host.inc - user/ - host_edit_action.php - host_edit_form.php + html/ + inc/ + host.inc + user/ + host_edit_action.php + host_edit_form.php David 23 Oct 2005 - fix compile warnings @@ -13364,12 +13364,12 @@ Charlie 25 Oct 2005 gui_rpc_server.C David 25 Oct 2005 - - "boinc_cmd" looks for a password in gui_rpc_auth.cfg + - "boinc_cmd" looks for a password in gui_rpc_auth.cfg - client/ - acct_setup.C - lib/ - boinc_cmd.C + client/ + acct_setup.C + lib/ + boinc_cmd.C David 25 Oct 2005 - avoid SQL injection attack @@ -13405,18 +13405,18 @@ David 27 Oct 2005 util.C,h David 27 Oct 2005 - - core client: parse fpops_per_cpu_sec, fpops_cumulative from app - (This way of assigning credit didn't work because of this) + - core client: parse fpops_per_cpu_sec, fpops_cumulative from app + (This way of assigning credit didn't work because of this) - client/ - app_control.C + client/ + app_control.C David 27 Oct 2005 - - file upload handler: in file size query, reject names with ".." - - fix possible buffer overruns in file upload handler + - file upload handler: in file size query, reject names with ".." + - fix possible buffer overruns in file upload handler - sched/ - file_upload_handler.C + sched/ + file_upload_handler.C David 28 Oct 2005 - user web: updates to reflect client version 5.x @@ -13534,10 +13534,10 @@ Rom 2 Nov 2005 ViewWork.cpp David 2 Nov 2005 - - core client: fix bad formula for computing CPU time remaining + - core client: fix bad formula for computing CPU time remaining - client/ - app.C,h + client/ + app.C,h David 2 Nov 2005 - user web: the line @@ -13646,23 +13646,23 @@ Rom 8 Nov 2005 cs_apps.C David 9 Nov 2005 - - Core client: every 2 weeks, contact the BOINC web site, - see if there's a newer version, and print a message if so. - Only do this while a scheduler RPC is happening - (to avoid unnecessary dialups, e.g.) - - Core client: if a scheduler returns a new host ID - (indicating that our statefile was copied from another host) - generate a new host CPID - (suggested by Rob Oglivie) + - Core client: every 2 weeks, contact the BOINC web site, + see if there's a newer version, and print a message if so. + Only do this while a scheduler RPC is happening + (to avoid unnecessary dialups, e.g.) + - Core client: if a scheduler returns a new host ID + (indicating that our statefile was copied from another host) + generate a new host CPID + (suggested by Rob Oglivie) - client/ - acct_setup.C,h - client_state.C,h - cs_benchmark.C - cs_scheduler.C - cs_statefile.C - file_names.h - scheduler_op.C + client/ + acct_setup.C,h + client_state.C,h + cs_benchmark.C + cs_scheduler.C + cs_statefile.C + file_names.h + scheduler_op.C Charlie 11 nov 2005 - Update BOINC Manager web page @@ -13678,18 +13678,18 @@ Charlie 11 nov 2005 mgrsystraymenu.png David 11 Nov 05 - - Core client: when do a "get newer version" RPC, - save the results in the client state file. - - Add GUI RPC for getting the newer version number. + - Core client: when do a "get newer version" RPC, + save the results in the client state file. + - Add GUI RPC for getting the newer version number. - client/ - acct_setup.C - client_state.h - cs_statefile.C - gui_rpc_server_ops.C - lib/ - gui_rpc_client.h - gui_rpc_client_ops.C + client/ + acct_setup.C + client_state.h + cs_statefile.C + gui_rpc_server_ops.C + lib/ + gui_rpc_client.h + gui_rpc_client_ops.C David 12 Nov 2005 - typo fix @@ -13860,37 +13860,37 @@ Janus 24 Nov 2005 - Added the needed DB update query to db_update in ops. html/ - ops/ + ops/ db_update.php - inc/ + inc/ forum.inc - text_transform.inc + text_transform.inc user/ forum_thread.php white.css - edit_forum_preferences_form.php + edit_forum_preferences_form.php edit_forum_preferences_action.php David 24 Nov 2005 - - Manager: improvements to Statistics tab + - Manager: improvements to Statistics tab - clientgui/ - ViewStatistics.cpp + clientgui/ + ViewStatistics.cpp David 25 Nov 2005 - - Fixed measurements of network bandwidth: - - Do measurements only while file transfers are active, - not scheduler or other RPCs. - Move the up_active and down_active flags from - NET_XFER_SET to FILE_XFER_SET. - - use a decay of 1 hour instead of 24 - - reset delta_t and delta_nbytes after using them + - Fixed measurements of network bandwidth: + - Do measurements only while file transfers are active, + not scheduler or other RPCs. + Move the up_active and down_active flags from + NET_XFER_SET to FILE_XFER_SET. + - use a decay of 1 hour instead of 24 + - reset delta_t and delta_nbytes after using them - client/ - client_state.C - file_xfer.C,h - net_stats.C,h - net_xfer_curl.C,h + client/ + client_state.C + file_xfer.C,h + net_stats.C,h + net_xfer_curl.C,h David 25 Nov 2005 - Core client: if we're currently using an account manager @@ -14001,15 +14001,15 @@ David 27 Nov 2005 acct_mgr.C David 27 Nov 2005 - - Manager: more improvements to the Statistics tab - (from Mifistor) - - Account manager: don't try RPC every second + - Manager: more improvements to the Statistics tab + (from Mifistor) + - Account manager: don't try RPC every second - client/ - acct_mgr.C - clientgui/ - Events.h - ViewStatistics.cpp,h + client/ + acct_mgr.C + clientgui/ + Events.h + ViewStatistics.cpp,h Rom 28 Nov 2005 - Bug Fix: Fix the URL validator so that it won't modify the user @@ -14088,11 +14088,23 @@ Eric K. 30 Nov 2005 - minor mods to allow BOINC applications to compile under MINGW. lib/ boinc_win.h - diagnostics.C - diagnostics.h - util.C - stackwalker_win.h + diagnostics.C + diagnostics.h + util.C + stackwalker_win.h api/ boinc_gl.h - gutil.h + gutil.h + +David 30 Nov 2005 + - core client: add -detach option (Windows). + Runs completely detached from the console. + This allows users who can't start it as a service + to be able to run boinc.exe "invisibly". + (from David Goodenough) + + client/ + client_state.C,h + cs_cmdline.C + main.C diff --git a/client/client_state.C b/client/client_state.C index 6c261c0808..44169cc9ee 100644 --- a/client/client_state.C +++ b/client/client_state.C @@ -124,6 +124,7 @@ CLIENT_STATE::CLIENT_STATE() { no_gui_rpc = false; have_tentative_project = false; new_version_check_time = 0; + detach_console = false; } #if 0 @@ -192,21 +193,21 @@ void CLIENT_STATE::free_mem() { void CLIENT_STATE::show_host_info() { char buf[256], buf2[256]; - msg_printf(NULL, MSG_INFO, + msg_printf(NULL, MSG_INFO, "Processor: %d %s %s", host_info.p_ncpus, host_info.p_vendor, host_info.p_model ); nbytes_to_string(host_info.m_nbytes, 0, buf, sizeof(buf)); nbytes_to_string(host_info.m_swap, 0, buf2, sizeof(buf2)); - msg_printf(NULL, MSG_INFO, + msg_printf(NULL, MSG_INFO, "Memory: %s physical, %s virtual", buf, buf2 ); nbytes_to_string(host_info.d_total, 0, buf, sizeof(buf)); nbytes_to_string(host_info.d_free, 0, buf2, sizeof(buf2)); - msg_printf(NULL, MSG_INFO, + msg_printf(NULL, MSG_INFO, "Disk: %s total, %s free", buf, buf2 ); @@ -250,7 +251,7 @@ int CLIENT_STATE::init() { #ifdef _WIN32 DWORD buf_size = sizeof(buf); LPTSTR pbuf = buf; - + GetUserName(pbuf, &buf_size); if (executing_as_daemon && (0 != strcmp("SYSTEM", pbuf))) { msg_printf(NULL, MSG_INFO, @@ -281,7 +282,7 @@ int CLIENT_STATE::init() { host_info.get_host_info(); set_ncpus(); show_host_info(); - + // Check to see if we can write the state file. // retval = write_state_file(); diff --git a/client/client_state.h b/client/client_state.h index e8f25753be..b1fe2b7a75 100644 --- a/client/client_state.h +++ b/client/client_state.h @@ -138,6 +138,7 @@ public: bool size_overflow; bool redirect_io; // redirect stdout, stderr to log files + bool detach_console; double now; const char* platform_name; @@ -388,7 +389,7 @@ public: // ------------------ cs_data.C: // mechanisms for managing data saved on host // -public: +public: bool get_more_disk_space(PROJECT*, double); int anything_free(double &); int calc_proj_size(PROJECT*); @@ -406,7 +407,7 @@ private: int reset_checks(); int delete_inactive_results(PROJECT*); int unstick_result_files(RESULT*); - double delete_next_file(PROJECT*, int); + double delete_next_file(PROJECT*, int); double delete_expired(PROJECT*); double offender(PROJECT*); double proj_potentially_free(PROJECT*); diff --git a/client/cs_cmdline.C b/client/cs_cmdline.C index ca13a61df5..33ef7799fd 100644 --- a/client/cs_cmdline.C +++ b/client/cs_cmdline.C @@ -48,6 +48,7 @@ static void print_options(char* prog) { " -check_all_logins for idle detection, check remote logins\n too" " -allow_remote_gui_rpc allow remote GUI RPC connections\n" " -redirectio redirect stdout and stderr to log files\n" + " -detach detach from console (Windows)\n" " -dir use given dir as BOINC home\n" " -no_gui_rpc don't allow GUI RPC, don't make socket\n" , @@ -129,6 +130,8 @@ void CLIENT_STATE::parse_cmdline(int argc, char** argv) { else pers_giveup = atoi(argv[++i]); } else if (ARG(debug_fake_exponential_backoff)) { debug_fake_exponential_backoff = true; + } else if (ARG(detach_phase_two)) { + detach_console = true; // the above options are private (i.e. not shown by -help) // Public options follow. diff --git a/client/main.C b/client/main.C index f4745855fc..74067ae985 100644 --- a/client/main.C +++ b/client/main.C @@ -109,7 +109,7 @@ void show_message(PROJECT *p, char* msg, int priority) { _stprintf(event_message, TEXT("%s [%s] %s\n"), time_string, x, message); ::OutputDebugString(event_message); // TODO: Refactor messages so that we do not overload the event log - // RTW 08/24/2004 + // RTW 08/24/2004 //LogEventErrorMessage(event_message); #endif } @@ -122,7 +122,7 @@ void show_message(PROJECT *p, char* msg, int priority) { _stprintf(event_message, TEXT("%s [%s] %s\n"), time_string, x, message); ::OutputDebugString(event_message); // TODO: Refactor messages so that we do not overload the event log - // RTW 08/24/2004 + // RTW 08/24/2004 //LogEventInfoMessage(event_message); #endif } @@ -171,9 +171,9 @@ DWORD WINAPI Win9xMonitorSystemThread( LPVOID lpParam ) { MSG msg; wc.style = CS_GLOBALCLASS; - wc.lpfnWndProc = (WNDPROC)Win9xMonitorSystemWndProc; + wc.lpfnWndProc = (WNDPROC)Win9xMonitorSystemWndProc; wc.cbClsExtra = 0; - wc.cbWndExtra = 0; + wc.cbWndExtra = 0; wc.hInstance = NULL; wc.hIcon = NULL; wc.hCursor = NULL; @@ -181,7 +181,7 @@ DWORD WINAPI Win9xMonitorSystemThread( LPVOID lpParam ) { wc.lpszMenuName = NULL; wc.lpszClassName = "BOINCWin9xMonitorSystem"; - if (!RegisterClass(&wc)) + if (!RegisterClass(&wc)) { fprintf(stderr, "Failed to register the Win9xMonitorSystem window class.\n"); return 1; @@ -189,7 +189,7 @@ DWORD WINAPI Win9xMonitorSystemThread( LPVOID lpParam ) { /* Create an invisible window */ hwndMain = CreateWindow( - wc.lpszClassName, + wc.lpszClassName, "BOINC Monitor System", WS_OVERLAPPEDWINDOW & ~WS_VISIBLE, CW_USEDEFAULT, @@ -206,8 +206,8 @@ DWORD WINAPI Win9xMonitorSystemThread( LPVOID lpParam ) { fprintf(stderr, "Failed to create the Win9xMonitorSystem window.\n"); return 0; } - - while (GetMessage(&msg, NULL, 0, 0)) + + while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); @@ -325,14 +325,14 @@ static void init_core_client(int argc, char** argv) { // Initialize the BOINC Diagnostics Framework int dwDiagnosticsFlags = - BOINC_DIAG_DUMPCALLSTACKENABLED | + BOINC_DIAG_DUMPCALLSTACKENABLED | BOINC_DIAG_HEAPCHECKENABLED | BOINC_DIAG_HEAPCHECKEVERYALLOC | BOINC_DIAG_TRACETOSTDOUT; - if (gstate.redirect_io || gstate.executing_as_daemon) { - dwDiagnosticsFlags |= - BOINC_DIAG_REDIRECTSTDERR | + if (gstate.redirect_io || gstate.executing_as_daemon || gstate.detach_console) { + dwDiagnosticsFlags |= + BOINC_DIAG_REDIRECTSTDERR | BOINC_DIAG_REDIRECTSTDOUT; } @@ -348,6 +348,13 @@ static void init_core_client(int argc, char** argv) { exit(1); } + // Win32 - detach from console if requested +#ifdef _WIN32 + if (gstate.detach_console) { + FreeConsole(); + } +#endif + // Unix: install signal handlers #ifndef _WIN32 // Handle quit signals gracefully @@ -419,6 +426,62 @@ int boinc_main_loop() { int main(int argc, char** argv) { int retval = 0; +#ifdef _WIN32 + // This bit of silliness is required to properly detach when run from within a command + // prompt under Win32. The root cause of the problem is that CMD.EXE does not return + // control to the user until the spawned program exits, detaching from the console is + // not enough. So we need to do the following. If the -detach flag is given, trap it + // prior to the main setup in init_core_client. Reinvoke the program, changing the + // -detach into -detach_phase_two, and then exit. At this point, cmd.exe thinks all is + // well, and returns control to the user. Meanwhile the second invocation will grok the + // -detach_phase_two flag, and detach itself from the console, finally getting us to + // where we want to be. + + int i; + int len; + char *commandLine; + STARTUPINFO si; + PROCESS_INFORMATION pi; + + for (i = 1; i < argc; i++) { + // FIXME FIXME. Duplicate instances of -detach may cause this to be + // executed unnecessarily. At worst, I think it leads to a few extra + // processes being created and destroyed. + if (strcmp(argv[i], "-detach") == 0 || strcmp(argv[i], "--detach") == 0) { + argv[i] = "-detach_phase_two"; + + // start with space for two '"'s + len = 2; + for (i = 0; i < argc; i++) { + len += strlen(argv[i]) + 1; + } + if ((commandLine = (char *) malloc(len)) == NULL) { + // Drop back ten and punt. Can't do the detach thing, so we just carry on. + // At least the program will start. + break; + } + commandLine[0] = '"'; + // OK, we can safely use strcpy and strcat, since we know that we allocated enough + strcpy(&commandLine[1], argv[0]); + strcat(commandLine, "\""); + for (i = 1; i < argc; i++) { + strcat(commandLine, " "); + strcat(commandLine, argv[i]); + } + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + + // If process creation succeeds, we exit, if it fails punt and continue + // as usual. We won't detach properly, but the program will run. + if (CreateProcess(NULL, commandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { + exit(0); + } + break; + } + } +#endif + boinc_cleanup_completed = false; init_core_client(argc, argv); @@ -428,7 +491,7 @@ int main(int argc, char** argv) { #ifdef _WIN32 // Figure out if we're on Win9x - OSVERSIONINFO osvi; + OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx(&osvi); g_bIsWin9x = osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS;