Skip to content

Apps that do network communication

David Anderson edited this page May 25, 2026 · 3 revisions

BOINC apps may need to do network communication, either sporadically or constantly. For example:

  • Docker apps, on startup, download Docker image files and install libraries (apt-get) over the network.
  • LHC@home apps download files from project servers.
  • Parallel distributed computing apps do constant peer-to-peer communication.

This doc discusses how BOINC makes such apps work in the volunteer computing environment, where

  • Hosts may sometimes be disconnected (no Wi-Fi, no Ethernet).
  • Network usage may be suspended due to user time-of-day preferences or the 'suspend network' GUI command.

Network disconnection

Apps must figure out when there's a disconnection. They might do this as follows:

  • A network operations fails; e.g. a connect, transfer, or Docker command fails with an error message suggesting network failure.
  • The app then attempts a connection to an always-up server (e.g. Google). If this fails there's almost certainly a network disconnection; otherwise it's a problem with a non-BOINC server.

If there is a disconnection, the app should:

  • Call boinc_waiting_for_network(true). This tells the client that the job is blocked by a network disconnection. The client can then show a notice telling the user this, and suggesting that they reconnect. The GUI shows the job status as 'waiting for network connection'

  • Periodically ping Google (maybe every 10 sec); if this succeeds, call boinc_waiting_for_network(false) and retry the network operation.

Network suspension

An app can learn that communication is suspended by calling boinc_get_status() and checking for BOINC_STATUS::network_suspended in the result. If this is set, and it needs to communicate, it should call boinc_waiting_for_network(true), wait until the suspension is over, then call boinc_waiting_for_network(false),

If the client gets a waiting-for-network message from an app that isn't already waiting, and the network is suspended, it notifies the user with a suggestion that they unsuspend the network or change their time-of-day prefs.

App logic

An example of app logic for doing a short network operation; see build_image() in docker_wrapper.cpp. network_connected() returns true if berkeley.edu could be pinged.

bool connected = true
while (1) {
    boinc_get_status(&status)
    if status.suspend_network:
        boinc_waiting_for_network(true)
        boinc_report_app_status(0,0,0)
        boinc_sleep(10)
        continue
    if not connected:
        if not network_connected()
            sleep(10)
            continue
    try the operation
    if it failed due to no network connection:
        if network_connected()
            return failure
        connected = false
        boinc_waiting_for_network(true)
        boinc_report_app_status(0,0,0)
        sleep(10)
        continue
    if it failed for another reason
        return failure
    boinc_waiting_for_network(false)
    boinc_report_app_status(0,0,0)
return success

The logic for doing a long operation is analogous; the app must periodically check whether network access is suspended.

Note: we ping Google every 10 sec, but only as long as we're disconnected. So (even if there are lots of hosts) we're not going to overload Google.

Notes

  • In the current implementation, jobs that are waiting for the network are not suspended or exited. This can cause device starvation: e.g. all the CPUs might be committed to blocked jobs, even though there are runnable jobs that don't use network. We could fix this, but it would be a bit complex; we'd need to avoid having an unbounded number of suspended jobs.

  • BOINC has a user preference for capping the amount network transfer in a given time period. The client tries to enforce this, by keeping track of file upload/download sizes and not starting transfers as needed. But we currently don't include network usage from apps in this. Doing so would be messy, and probably not worth it; AFAIK most ISP services, these days, are not capped.

Getting proxy info

If the host is using a proxy (HTTP or SOCKS5), the app can learn this using get_init_data(). TODO: what should it do with this, e.g. in Docker commands?

Implementation

messages

Client->app: the heartbeat message includes

  • suspend_network flag: set if time-of-day or GUI network suspension.

App->client: the app_progress message includes a want_network flag. This means the app wants to communicate but can't, due either to suspension or disconnection. The boinc_waiting_for_network(bool) API call sets want_network to the given value.

GUI->client: there is a network_available() GUI RPC. This is sent when the user clicks 'Retry pending transfers' in the Manager. Typically this means that the user has reconnected the network. When it receives this, the client retries file transfers. It doesn't forward it to apps; it's up to apps to poll.

Client logic

The client keeps track of

  • the last want_network status from each job.
  • a flag network_notice_active (initially false)

When a job transitions want_network from false to true, and network_notice_active is false, post a notice (which one depends on whether network is suspended) and set network_notice_active.

clear network_notice_active (and clear all network notices) when

  • a job transitions want_network from true to false,
  • an HTTP op succeeds

Testing

On laptop:

  • In Powershell: wsl -d boinc-buda-runner -u root
  • podman system prune -a (forces a fetch of base image)
  • Build Win docker_wrapper w/ debugging output
  • Upload to isaac

On isaac:

  • Deploy as new BUDA app version on test proj

On laptop:

  • Build/run client, Manager
  • Suspend computing

On test project web site:

  • Submit BUDA job

On laptop:

  • Manager: update project (should fetch job)
  • turn off wifi
  • Manager: enable computing
  • Should post notice, show job status; check wrapper log
  • Turn on wifi
  • Should remove notice, run job

Then: same thing except suspend network instead of turning off WiFi.

Clone this wiki locally