Exemple #1
0
// Write the client_state.xml file
//
int CLIENT_STATE::write_state_file() {
    MFILE mf;
    int retval, ret1, ret2, attempt;
#ifdef _WIN32
    char win_error_msg[4096];
#endif

    for (attempt=1; attempt<=MAX_STATE_FILE_WRITE_ATTEMPTS; attempt++) {
        if (attempt > 1) boinc_sleep(1.0);
            
        if (log_flags.statefile_debug) {
            msg_printf(0, MSG_INFO,
                "[statefile] Writing state file"
            );
        }
#ifdef _WIN32
        retval = mf.open(STATE_FILE_NEXT, "wc");
#else
        retval = mf.open(STATE_FILE_NEXT, "w");
#endif
        if (retval) {
            if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) {
                msg_printf(0, MSG_INTERNAL_ERROR,
                    "Can't open %s: %s",
                    STATE_FILE_NEXT, boincerror(retval)
                );
            }
            if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue;
            return ERR_FOPEN;
        }
        MIOFILE miof;
        miof.init_mfile(&mf);
        ret1 = write_state(miof);
        ret2 = mf.close();
        if (ret1) {
            if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) {
                msg_printf(NULL, MSG_INTERNAL_ERROR,
                    "Couldn't write state file: %s", boincerror(retval)
                );
            }
            if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue;
            return ret1;
        }
        if (ret2) {
            if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue;
            return ret2;
        }

        // only attempt to rename the current state file if it exists.
        //
        if (boinc_file_exists(STATE_FILE_NAME)) {
            if (boinc_file_exists(STATE_FILE_PREV)) {
                retval = boinc_delete_file(STATE_FILE_PREV);
                if (retval) {
                    if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) {
#ifdef _WIN32
                        msg_printf(0, MSG_INFO,
                            "Can't delete previous state file; %s",
                            windows_format_error_string(GetLastError(), win_error_msg, sizeof(win_error_msg))
                        );
#else
                        msg_printf(0, MSG_INFO,
                            "Can't delete previous state file: %s",
                            strerror(errno)
                        );
#endif
                    }
                    if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue;
                }
            }
            
            retval = boinc_rename(STATE_FILE_NAME, STATE_FILE_PREV);
            if (retval) {
                if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) {
#ifdef _WIN32
                    msg_printf(0, MSG_INFO,
                        "Can't rename current state file to previous state file; %s",
                        windows_format_error_string(GetLastError(), win_error_msg, sizeof(win_error_msg))
                    );
#else
                    msg_printf(0, MSG_INFO, 
                        "Can't rename current state file to previous state file: %s", 
                        strerror(errno)
                    );
#endif
                }
                if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue;
            }
        }

        retval = boinc_rename(STATE_FILE_NEXT, STATE_FILE_NAME);
        if (log_flags.statefile_debug) {
            msg_printf(0, MSG_INFO,
                "[statefile] Done writing state file"
            );
        }
        if (!retval) break;     // Success!
        
        if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) {
#ifdef _WIN32
            msg_printf(0, MSG_INFO,
                "rename error: %s",
                windows_format_error_string(GetLastError(), win_error_msg, sizeof(win_error_msg))
            );
#elif defined (__APPLE__)
            if (log_flags.statefile_debug) {
                system("ls -al /Library/Application\\ Support/BOINC\\ Data/client*.*");
            }
#endif
        }
        if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue;
        return ERR_RENAME;
    }
    return 0;
}
int GUI_RPC_CONN::handle_rpc() {
    int n, retval=0;
    MIOFILE mf;
    MFILE m;
    char* p;
    mf.init_mfile(&m);

    int left = GUI_RPC_REQ_MSG_SIZE - request_nbytes;
#ifdef _WIN32
        n = recv(sock, request_msg+request_nbytes, left, 0);
#else
        n = read(sock, request_msg+request_nbytes, left);
#endif
    if (n <= 0) {
        request_nbytes = 0;
        return ERR_READ;
    }
    request_nbytes += n;

    // buffer full?
    if (request_nbytes >= GUI_RPC_REQ_MSG_SIZE) {
        request_nbytes = 0;
        return ERR_READ;
    }
    request_msg[request_nbytes] = 0;
    if (!strncmp(request_msg, "OPTIONS", 7)) {
        char buf[1024];
        sprintf(buf, "HTTP/1.1 200 OK\n"
            "Server: BOINC client\n"
            "Access-Control-Allow-Origin: *\n"
            "Access-Control-Allow-Methods: POST, GET, OPTIONS\n"
            "Content-Length: 0\n"
            "Keep-Alive: timeout=2, max=100\n"
            "Connection: Keep-Alive\n"
            "Content-Type: text/plain\n\n"
        );
        send(sock, buf, strlen(buf), 0);
        request_nbytes = 0;
        if (log_flags.gui_rpc_debug) {
            msg_printf(0, MSG_INFO,
                "[gui_rpc] processed OPTIONS"
            );
        }
        return 0;
    }
    bool http_request;
    if (complete_post_request(request_msg)) {
        http_request = true;
    } else {
        p = strchr(request_msg, 3);
        if (p) {
            *p = 0;
            http_request = false;
        } else {
            if (log_flags.gui_rpc_debug) {
                msg_printf(0, MSG_INFO,
                    "[gui_rpc] partial GUI RPC Command = '%s'\n", request_msg
                );
            }
            return 0;
        }
    }
    request_nbytes = 0;

    if (log_flags.gui_rpc_debug) {
        msg_printf(0, MSG_INFO,
            "[gui_rpc] GUI RPC Command = '%s'\n", request_msg
        );
    }

    // Policy:
    // - the first auth failure gets an error message; after that, disconnect
    // - if we get an unexpected auth1 or auth2, disconnect

    mf.printf("<boinc_gui_rpc_reply>\n");
    if (match_req(request_msg, "auth1")) {
        if (got_auth1 && auth_needed) {
            retval = ERR_AUTHENTICATOR;
        } else {
            handle_auth1(mf);
            got_auth1 = true;
        }
    } else if (match_req(request_msg, "auth2")) {
        if ((!got_auth1 || got_auth2) && auth_needed) {
            retval = ERR_AUTHENTICATOR;
        } else {
            retval = handle_auth2(request_msg, mf);
            got_auth2 = true;
        }
    } else if (auth_needed && !is_local) {
        auth_failure(mf);
        if (sent_unauthorized) {
            retval = ERR_AUTHENTICATOR;
        }
        sent_unauthorized = true;

    // operations that require authentication only for non-local clients start here.
    // Use this only for information that should be available to people
    // sharing this computer (e.g. what jobs are running)
    // but not for anything sensitive (passwords etc.)

    } else if (match_req(request_msg, "exchange_versions")) {
        handle_exchange_versions(mf);
    } else if (match_req(request_msg, "get_state")) {
        gstate.write_state_gui(mf);
    } else if (match_req(request_msg, "get_results")) {
        bool active_only = false;
        parse_bool(request_msg, "active_only", active_only);
        mf.printf("<results>\n");
        gstate.write_tasks_gui(mf, active_only);
        mf.printf("</results>\n");
    } else if (match_req(request_msg, "get_screensaver_tasks")) {
        handle_get_screensaver_tasks(mf);
    } else if (match_req(request_msg, "result_show_graphics")) {
        handle_result_show_graphics(request_msg, mf);
    } else if (match_req(request_msg, "get_file_transfers")) {
        gstate.write_file_transfers_gui(mf);
    } else if (match_req(request_msg, "get_simple_gui_info")) {
        handle_get_simple_gui_info(mf);
    } else if (match_req(request_msg, "get_project_status")) {
        handle_get_project_status(mf);
    } else if (match_req(request_msg, "get_disk_usage")) {
        handle_get_disk_usage(mf);
    } else if (match_req(request_msg, "get_messages")) {
        handle_get_messages(request_msg, mf);
    } else if (match_req(request_msg, "get_message_count")) {
        handle_get_message_count(request_msg, mf);
    } else if (match_req(request_msg, "get_host_info")) {
        handle_get_host_info(request_msg, mf);
    } else if (match_req(request_msg, "get_statistics")) {
        handle_get_statistics(request_msg, mf);
    } else if (match_req(request_msg, "get_newer_version")) {
        handle_get_newer_version(mf);
    } else if (match_req(request_msg, "get_cc_status")) {
        handle_get_cc_status(this, mf);
    } else if (match_req(request_msg, "get_all_projects_list")) {
        read_all_projects_list_file(mf);
    } else if (match_req(request_msg, "get_notices_public")) {
        handle_get_notices(request_msg, *this, mf, true);
        clear_notice_refresh();

    // Operations that require authentication start here

    } else if (auth_needed) {
        auth_failure(mf);
        if (sent_unauthorized) {
            retval = ERR_AUTHENTICATOR;
        }
        sent_unauthorized = true;
    } else if (match_req(request_msg, "project_nomorework")) {
         handle_project_op(request_msg, mf, "nomorework");
    } else if (match_req(request_msg, "project_allowmorework")) {
         handle_project_op(request_msg, mf, "allowmorework");
    } else if (match_req(request_msg, "project_detach_when_done")) {
         handle_project_op(request_msg, mf, "detach_when_done");
    } else if (match_req(request_msg, "project_dont_detach_when_done")) {
         handle_project_op(request_msg, mf, "dont_detach_when_done");
    } else if (match_req(request_msg, "set_network_mode")) {
        handle_set_network_mode(request_msg, mf);
    } else if (match_req(request_msg, "run_benchmarks")) {
        handle_run_benchmarks(request_msg, mf);
    } else if (match_req(request_msg, "get_proxy_settings")) {
        handle_get_proxy_settings(request_msg, mf);
    } else if (match_req(request_msg, "set_proxy_settings")) {
        handle_set_proxy_settings(request_msg, mf);
    } else if (match_req(request_msg, "network_available")) {
        handle_network_available(request_msg, mf);
    } else if (match_req(request_msg, "abort_file_transfer")) {
        handle_file_transfer_op(request_msg, mf, "abort");
    } else if (match_req(request_msg, "project_detach")) {
        handle_project_op(request_msg, mf, "detach");
    } else if (match_req(request_msg, "abort_result")) {
        handle_result_op(request_msg, mf, "abort");
    } else if (match_req(request_msg, "suspend_result")) {
        handle_result_op(request_msg, mf, "suspend");
    } else if (match_req(request_msg, "resume_result")) {
        handle_result_op(request_msg, mf, "resume");
    } else if (match_req(request_msg, "project_suspend")) {
        handle_project_op(request_msg, mf, "suspend");
    } else if (match_req(request_msg, "project_resume")) {
        handle_project_op(request_msg, mf, "resume");
    } else if (match_req(request_msg, "set_run_mode")) {
        handle_set_run_mode(request_msg, mf);
    } else if (match_req(request_msg, "set_gpu_mode")) {
        handle_set_gpu_mode(request_msg, mf);
    } else if (match_req(request_msg, "quit")) {
        handle_quit(request_msg, mf);
    } else if (match_req(request_msg, "auth_monitor")) {
        handle_auth_monitor(request_msg, is_local, mf);
    } else if (match_req(request_msg, "update_project_apps")) {
        handle_update_projects_apps(request_msg, is_local, mf);
    } else if (match_req(request_msg, "update_project_apps_poll")) {
        handle_update_projects_apps_poll(request_msg, is_local, mf);
    } else if (match_req(request_msg, "acct_mgr_info")) {
        handle_acct_mgr_info(request_msg, mf);
    } else if (match_req(request_msg, "read_global_prefs_override")) {
        mf.printf("<success/>\n");
        gstate.read_global_prefs();
        gstate.request_schedule_cpus("Preferences override");
        gstate.request_work_fetch("Preferences override");
    } else if (match_req(request_msg, "get_project_init_status")) {
        handle_get_project_init_status(request_msg, mf);
    } else if (match_req(request_msg, "get_global_prefs_file")) {
        handle_get_global_prefs_file(mf);
    } else if (match_req(request_msg, "get_global_prefs_working")) {
        handle_get_global_prefs_working(mf);
    } else if (match_req(request_msg, "get_global_prefs_override")) {
        handle_get_global_prefs_override(mf);
    } else if (match_req(request_msg, "set_global_prefs_override")) {
        handle_set_global_prefs_override(request_msg, mf);
    } else if (match_req(request_msg, "get_cc_config")) {
        handle_get_cc_config(mf);
    } else if (match_req(request_msg, "set_cc_config")) {
        handle_set_cc_config(request_msg, mf);
    } else if (match_req(request_msg, "read_cc_config")) {
        mf.printf("<success/>\n");
        read_config_file(false);
        config.show();
        log_flags.show();
        gstate.set_ncpus();
        gstate.request_schedule_cpus("Core client configuration");
        gstate.request_work_fetch("Core client configuration");
#ifndef USE_REC
    } else if (match_req(request_msg, "set_debts")) {
        handle_set_debts(request_msg, mf);
#endif
    } else if (match_req(request_msg, "get_notices")) {
        handle_get_notices(request_msg, *this, mf, false);
        clear_notice_refresh();
    } else if (match_req(request_msg, "battery_info")) {
        handle_battery_info(request_msg, is_local, mf);
    } else {

        // RPCs after this point require authentication,
        // and enable network communication for 5 minutes,
        // overriding other factors.
        // Things like attaching projects, etc.
        //

        double saved_time = gstate.gui_rpcs.time_of_last_rpc_needing_network;
        gstate.gui_rpcs.time_of_last_rpc_needing_network = gstate.now;

        if (match_req(request_msg, "retry_file_transfer")) {
            handle_file_transfer_op(request_msg, mf, "retry");
        } else if (match_req(request_msg, "project_reset")) {
            handle_project_op(request_msg, mf, "reset");
        } else if (match_req(request_msg, "project_update")) {
            handle_project_op(request_msg, mf, "update");
        } else if (match_req(request_msg, "get_project_config")) {
            handle_get_project_config(request_msg, mf);
        } else if (match_req(request_msg, "get_project_config_poll")) {
            handle_get_project_config_poll(request_msg, mf);
        } else if (match_req(request_msg, "lookup_account")) {
            handle_lookup_account(request_msg, mf);
        } else if (match_req(request_msg, "lookup_account_poll")) {
            handle_lookup_account_poll(request_msg, mf);
        } else if (match_req(request_msg, "create_account")) {
            handle_create_account(request_msg, mf);
        } else if (match_req(request_msg, "create_account_poll")) {
            handle_create_account_poll(request_msg, mf);
        } else if (match_req(request_msg, "project_attach")) {
            handle_project_attach(request_msg, mf);
        } else if (match_req(request_msg, "project_attach_poll")) {
            handle_project_attach_poll(request_msg, mf);
        } else if (match_req(request_msg, "acct_mgr_rpc")) {
            handle_acct_mgr_rpc(request_msg, mf);
        } else if (match_req(request_msg, "acct_mgr_rpc_poll")) {
            handle_acct_mgr_rpc_poll(request_msg, mf);

        // DON'T JUST ADD NEW RPCS HERE - THINK ABOUT THEIR
        // AUTHENTICATION AND NETWORK REQUIREMENTS FIRST

        } else {
            mf.printf("<error>unrecognized op: %s</error>\n", request_msg);
            gstate.gui_rpcs.time_of_last_rpc_needing_network = saved_time;
        }
    }

    mf.printf("</boinc_gui_rpc_reply>\n\003");
    m.get_buf(p, n);
    if (http_request) {
        char buf[1024];
        sprintf(buf,
            "HTTP/1.1 200 OK\n"
            "Date: Fri, 31 Dec 1999 23:59:59 GMT\n"
            "Server: BOINC client\n"
            "Connection: close\n"
            "Content-Type: text/xml; charset=utf-8\n"
            "Content-Length: %d\n\n",
            n
        );
        send(sock, buf, strlen(buf), 0);
    }
    if (p) {
        send(sock, p, n, 0);
        p[n-1]=0;   // replace 003 with NULL
        if (log_flags.gui_rpc_debug) {
            if (n > 128) p[128] = 0;
            msg_printf(0, MSG_INFO,
                "[gui_rpc] GUI RPC reply: '%s'\n", p
            );
        }
        free(p);
    }
    return retval;
}
int GUI_RPC_CONN::handle_rpc() {
    char request_msg[4096];
    int n, retval=0;
    MIOFILE mf;
    MFILE m;
    char* p;
    mf.init_mfile(&m);

    // read the request message in one read()
    // so that the core client won't hang because
    // of malformed request msgs
    //
#ifdef _WIN32
        n = recv(sock, request_msg, 4095, 0);
#else
        n = read(sock, request_msg, 4095);
#endif
    if (n <= 0) return ERR_READ;
    request_msg[n-1] = 0;   // replace 003 with NULL

    if (log_flags.guirpc_debug) {
        msg_printf(0, MSG_INFO,
            "[guirpc_debug] GUI RPC Command = '%s'\n", request_msg
        );
    }

    // Policy:
    // - the first auth failure gets an error message; after that, disconnect
    // - if we get an unexpected auth1 or auth2, disconnect

    mf.printf("<boinc_gui_rpc_reply>\n");
    if (match_req(request_msg, "auth1")) {
        if (got_auth1 && auth_needed) {
            retval = ERR_AUTHENTICATOR;
        } else {
            handle_auth1(mf);
            got_auth1 = true;
        }
    } else if (match_req(request_msg, "auth2")) {
        if ((!got_auth1 || got_auth2) && auth_needed) {
            retval = ERR_AUTHENTICATOR;
        } else {
            retval = handle_auth2(request_msg, mf);
            got_auth2 = true;
        }
    } else if (auth_needed && !is_local) {
        auth_failure(mf);
        if (sent_unauthorized) {
            retval = ERR_AUTHENTICATOR;
        }
        sent_unauthorized = true;

    // operations that require authentication only for non-local clients start here.
    // Use this only for information that should be available to people
    // sharing this computer (e.g. what jobs are running)
    // but not for anything sensitive (passwords etc.)

    } else if (match_req(request_msg, "exchange_versions")) {
        handle_exchange_versions(mf);
    } else if (match_req(request_msg, "get_state")) {
        gstate.write_state_gui(mf);
    } else if (match_req(request_msg, "get_results")) {
        bool active_only = false;
        parse_bool(request_msg, "active_only", active_only);
        mf.printf("<results>\n");
        gstate.write_tasks_gui(mf, active_only);
        mf.printf("</results>\n");
    } else if (match_req(request_msg, "get_screensaver_tasks")) {
        handle_get_screensaver_tasks(mf);
    } else if (match_req(request_msg, "result_show_graphics")) {
        handle_result_show_graphics(request_msg, mf);
    } else if (match_req(request_msg, "get_file_transfers")) {
        gstate.write_file_transfers_gui(mf);
    } else if (match_req(request_msg, "get_simple_gui_info")) {
        handle_get_simple_gui_info(mf);
    } else if (match_req(request_msg, "get_project_status")) {
        handle_get_project_status(mf);
    } else if (match_req(request_msg, "get_disk_usage")) {
        handle_get_disk_usage(mf);
    } else if (match_req(request_msg, "get_messages")) {
        handle_get_messages(request_msg, mf);
    } else if (match_req(request_msg, "get_message_count")) {
        handle_get_message_count(request_msg, mf);
    } else if (match_req(request_msg, "get_host_info")) {
        handle_get_host_info(request_msg, mf);
    } else if (match_req(request_msg, "get_statistics")) {
        handle_get_statistics(request_msg, mf);
    } else if (match_req(request_msg, "get_newer_version")) {
        handle_get_newer_version(mf);
    } else if (match_req(request_msg, "get_cc_status")) {
        handle_get_cc_status(this, mf);
    } else if (match_req(request_msg, "get_all_projects_list")) {
        read_all_projects_list_file(mf);

    // Operations that require authentication start here

    } else if (auth_needed) {
        auth_failure(mf);
        if (sent_unauthorized) {
            retval = ERR_AUTHENTICATOR;
        }
        sent_unauthorized = true;
    } else if (match_req(request_msg, "project_nomorework")) {
         handle_project_op(request_msg, mf, "nomorework");
     } else if (match_req(request_msg, "project_allowmorework")) {
         handle_project_op(request_msg, mf, "allowmorework");
    } else if (match_req(request_msg, "project_detach_when_done")) {
         handle_project_op(request_msg, mf, "detach_when_done");
    } else if (match_req(request_msg, "project_dont_detach_when_done")) {
         handle_project_op(request_msg, mf, "dont_detach_when_done");
    } else if (match_req(request_msg, "set_network_mode")) {
        handle_set_network_mode(request_msg, mf);
    } else if (match_req(request_msg, "run_benchmarks")) {
        handle_run_benchmarks(request_msg, mf);
    } else if (match_req(request_msg, "get_proxy_settings")) {
        handle_get_proxy_settings(request_msg, mf);
    } else if (match_req(request_msg, "set_proxy_settings")) {
        handle_set_proxy_settings(request_msg, mf);
    } else if (match_req(request_msg, "network_available")) {
        handle_network_available(request_msg, mf);
    } else if (match_req(request_msg, "abort_file_transfer")) {
        handle_file_transfer_op(request_msg, mf, "abort");
    } else if (match_req(request_msg, "project_detach")) {
        handle_project_op(request_msg, mf, "detach");
    } else if (match_req(request_msg, "abort_result")) {
        handle_result_op(request_msg, mf, "abort");
    } else if (match_req(request_msg, "suspend_result")) {
        handle_result_op(request_msg, mf, "suspend");
    } else if (match_req(request_msg, "resume_result")) {
        handle_result_op(request_msg, mf, "resume");
    } else if (match_req(request_msg, "project_suspend")) {
        handle_project_op(request_msg, mf, "suspend");
    } else if (match_req(request_msg, "project_resume")) {
        handle_project_op(request_msg, mf, "resume");
    } else if (match_req(request_msg, "set_run_mode")) {
        handle_set_run_mode(request_msg, mf);
    } else if (match_req(request_msg, "set_gpu_mode")) {
        handle_set_gpu_mode(request_msg, mf);
    } else if (match_req(request_msg, "quit")) {
        handle_quit(request_msg, mf);
    } else if (match_req(request_msg, "acct_mgr_info")) {
        handle_acct_mgr_info(request_msg, mf);
    } else if (match_req(request_msg, "read_global_prefs_override")) {
        mf.printf("<success/>\n");
        gstate.read_global_prefs();
        gstate.request_schedule_cpus("Preferences override");
        gstate.request_work_fetch("Preferences override");
    } else if (match_req(request_msg, "get_project_init_status")) {
        handle_get_project_init_status(request_msg, mf);
    } else if (match_req(request_msg, "get_global_prefs_file")) {
        handle_get_global_prefs_file(mf);
    } else if (match_req(request_msg, "get_global_prefs_working")) {
        handle_get_global_prefs_working(mf);
    } else if (match_req(request_msg, "get_global_prefs_override")) {
        handle_get_global_prefs_override(mf);
    } else if (match_req(request_msg, "set_global_prefs_override")) {
        handle_set_global_prefs_override(request_msg, mf);
    } else if (match_req(request_msg, "get_cc_config")) {
        handle_get_cc_config(mf);
    } else if (match_req(request_msg, "set_cc_config")) {
        handle_set_cc_config(request_msg, mf);
    } else if (match_req(request_msg, "read_cc_config")) {
        mf.printf("<success/>\n");
        read_config_file(false);
        msg_printf(0, MSG_INFO, "Re-read config file");
        config.show();
        log_flags.show();
        gstate.set_ncpus();
        gstate.request_schedule_cpus("Core client configuration");
        gstate.request_work_fetch("Core client configuration");
    } else if (match_req(request_msg, "set_debts")) {
        handle_set_debts(request_msg, mf);
    } else {

        // RPCs after this point require authentication,
        // and enable network communication for 5 minutes, overriding other factors.
        // Things like attaching projects, etc.
        //

        double saved_time = gstate.gui_rpcs.time_of_last_rpc_needing_network;
        gstate.gui_rpcs.time_of_last_rpc_needing_network = gstate.now;

        if (match_req(request_msg, "retry_file_transfer")) {
            handle_file_transfer_op(request_msg, mf, "retry");
        } else if (match_req(request_msg, "project_reset")) {
            handle_project_op(request_msg, mf, "reset");
        } else if (match_req(request_msg, "project_update")) {
            handle_project_op(request_msg, mf, "update");
        } else if (match_req(request_msg, "get_project_config")) {
            handle_get_project_config(request_msg, mf);
        } else if (match_req(request_msg, "get_project_config_poll")) {
            handle_get_project_config_poll(request_msg, mf);
        } else if (match_req(request_msg, "lookup_account")) {
            handle_lookup_account(request_msg, mf);
        } else if (match_req(request_msg, "lookup_account_poll")) {
            handle_lookup_account_poll(request_msg, mf);
        } else if (match_req(request_msg, "create_account")) {
            handle_create_account(request_msg, mf);
        } else if (match_req(request_msg, "create_account_poll")) {
            handle_create_account_poll(request_msg, mf);
        } else if (match_req(request_msg, "project_attach")) {
            handle_project_attach(request_msg, mf);
        } else if (match_req(request_msg, "project_attach_poll")) {
            handle_project_attach_poll(request_msg, mf);
        } else if (match_req(request_msg, "acct_mgr_rpc")) {
            handle_acct_mgr_rpc(request_msg, mf);
        } else if (match_req(request_msg, "acct_mgr_rpc_poll")) {
            handle_acct_mgr_rpc_poll(request_msg, mf);

        // DON'T JUST ADD NEW RPCS HERE - THINK ABOUT THEIR
        // AUTHENTICATION AND NETWORK REQUIREMENTS FIRST

        } else {
            mf.printf("<error>unrecognized op: %s</error>\n", request_msg);
            gstate.gui_rpcs.time_of_last_rpc_needing_network = saved_time;
        }
    }

    mf.printf("</boinc_gui_rpc_reply>\n\003");
    m.get_buf(p, n);
    if (p) {
        send(sock, p, n, 0);
        p[n-1]=0;   // replace 003 with NULL
        if (log_flags.guirpc_debug) {
            if (n > 50) p[50] = 0;
            msg_printf(0, MSG_INFO,
                "[guirpc_debug] GUI RPC reply: '%s'\n", p
            );
        }
        free(p);
    }
    return retval;
}