# Technical Documentation: mobile-shell/mosh

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/mobile-shell/mosh)

### Overview (`README.md`)

[](https://github.com/mobile-shell/mosh/actions/workflows/ci.yml)

Mosh: the mobile shell
======================

Mosh is a remote terminal application that supports intermittent
connectivity, allows roaming, and provides speculative local echo
and line editing of user keystrokes.

It aims to support the typical interactive uses of SSH, plus:

   * Mosh keeps the session alive if the client goes to sleep and
     wakes up later, or temporarily loses its Internet connection.

   * Mosh allows the client and server to "roam" and change IP
     addresses, while keeping the connection alive. Unlike SSH, Mosh
     can be used while switching between Wi-Fi networks or from Wi-Fi
     to cellular data to wired Ethernet.

   * The Mosh client runs a predictive model of the server's behavior
     in the background and tries to guess intelligently how each
     keystroke will affect the screen state. When it is confident in
     its predictions, it will show them to the user while waiting for
     confirmation from the server. Most typing and uses of the left-
     and right-arrow keys can be echoed immediately.

     As a result, Mosh is usable on high-latency links, e.g. on a
     cellular data connection or spotty Wi-Fi. In distinction from
     previous attempts at local echo modes in other protocols, Mosh
     works properly with full-screen applications such as emacs, vi,
     alpine, and irssi, and automatically recovers from occasional
     prediction errors within an RTT. On high-latency links, Mosh
     underlines its predictions while they are outstanding and removes
     the underline when they are confirmed by the server.

Mosh does not support X forwarding or the non-interactive uses of SSH,
including port forwarding.

Other features
--------------

   * Mosh adjusts its frame rate so as not to fill up network queues
     on slow links, so "Control-C" always works within an RTT to halt
     a runaway process.

   * Mosh warns the user when it has not heard from the server
     in a while.

   * Mosh supports lossy links that lose a significant fraction
     of their packets.

   * Mosh handles some Unicode edge cases better than SSH and existing
     terminal emulators by themselves, but requires a UTF-8
     environment to run.

   * Mosh leverages SSH to set up the connection and authenticate
     users. Mosh does not contain any privileged (root) code.

Getting Mosh
------------

  [The Mosh web site](https://mosh.org/#getting) has information about
  packages for many operating systems, as well as instructions for building
  from source.

  Note that `mosh-client` receives an AES session key as an environment
  variable.  If you are porting Mosh to a new operating system, please make
  sure that a running process's environment variables are not readable by other
  users.  We have confirmed that this is the case on GNU/Linux, OS X, and
  FreeBSD.

Usage
-----

  The `mosh-client` binary must exist on the user's machine, and the
  `mosh-server` binary on the remote host.

  The user runs:

    $ mosh [user@]host

  If the `mosh-client` or `mosh-server` binaries live outside the user's
  `$PATH`, `mosh` accepts the arguments `--client=PATH` and `--server=PATH` to
  select alternate locations. More options are documented in the mosh(1) manual
  page.

  There are [more examples](https://mosh.org/#usage) and a
  [FAQ](https://mosh.org/#faq) on the Mosh web site.

How it works
------------

  The `mosh` program will SSH to `user@host` to establish the connection.
  SSH may prompt the user for a password or use public-key
  authentication to log in.

  From this point, `mosh` runs the `mosh-server` process (as the user)
  on the server machine. The server process listens on a high UDP port
  and sends its port number and an AES-128 secret key back to the
  client over SSH. The SSH connection is then shut down and the
  terminal session begins over UDP.

  If the client changes IP addresses, the server will begin sending
  to the client on the new IP address within a few seconds.

  To function, Mosh requires UDP datagrams to be passed between client
  and server. By default, `mosh` uses a port number between 60000 and
  61000, but the user can select a particular port with the -p option.
  Please note that the -p option has no effect on the port used by SSH.

Advice to distributors
----------------------

A note on compiler flags: Mosh is security-sensitive code. When making
automated builds for a binary package, we recommend passing the option
`--enable-compile-warnings=error` to `./configure`. On GNU/Linux with
`g++` or `clang++`, the package should compile cleanly with
`-Werror`. Please report a bug if it doesn't.

Where available, Mosh builds with a variety of binary hardening flags
such as `-fstack-protector-all`, `-D_FORTIFY_SOURCE=2`, etc.  These
provide proactive security against the possibility of a memory
corruption bug in Mosh or one of the libraries it uses.  For a full
list of flags, search for `HARDEN` in `configure.ac`.  The `configure`
script detects which flags are supported by your compiler, and enables
them automatically.  To disable this detection, pass
`--disable-hardening` to `./configure`.  Please report a bug if you
have trouble with the default settings; we would like as many users as
possible to be running a configuration as secure as possible.

Mosh ships with a default optimization setting of `-O2`. Some
distributors have asked about changing this to `-Os` (which causes a
compiler to prefer space optimizations to time optimizations). We have
benchmarked with the included `src/examples/benchmark` program to test
this. The results are that `-O2` is 40% faster than `-Os` with g++ 4.6
on GNU/Linux, and 16% faster than `-Os` with clang++ 3.1 on Mac OS
X. In both cases, `-Os` did produce a smaller binary (by up to 40%,
saving almost 200 kilobytes on disk). While Mosh is not especially CPU
intensive and mostly sits idle when the user is not typing, we think
the results suggest that `-O2` (the default) is preferable.

Our Debian and Fedora packaging presents Mosh as a single package.
Mosh has a Perl dependency that is only required for client use.  For
some platforms, it may make sense to have separate mosh-server and
mosh-client packages to allow mosh-server usage without Perl.

Notes for developers
--------------------

To start contributing to Mosh, install the following dependencies:

Debian, Windows Subsystem for Linux:

```
$ sudo apt install -y build-essential protobuf-compiler \
    libprotobuf-dev pkg-config libutempter-dev zlib1g-dev libncurses5-dev \
    libssl-dev bash-completion tmux less
```

Fedora, RHEL:

```
$ sudo dnf group install development-tools
$ sudo dnf install automake protobuf-compiler protobuf-devel libutempter-devel \
    zlib-ng-compat-devel ncurses-devel openssl-devel bash-completion tmux less \
    perl-diagnostics
```

MacOS:

```
$ brew install protobuf automake
```

Once you have forked the repository, run the following to build and test Mosh:

```
$ ./autogen.sh
$ ./configure
$ make
$ make check
```

Mosh supports producing code coverage reports by tests, but this feature is
disabled by default. To enable it, make sure `lcov` is installed on your
system. Then, configure and run tests:

```
$ ./configure --enable-code-coverage
$ make check-code-coverage
```

This will run all tests and produce a coverage report in HTML form that can be
opened with your favorite browser. Ideally, newly added code should strive for
90% (or better) incremental test coverage.

More info
---------

  * Mosh Web site:

    <https://mosh.org>

  * `mosh-devel@mit.edu` mailing list:

    <https://mailman.mit.edu/mailman/listinfo/mosh-devel>

  * `mosh-users@mit.edu` mailing list:

    <https://mailman.mit.edu/mailman/listinfo/mosh-users>

  * `#mosh` channel on [Libera Chat](https://libera.chat/)

    https://web.libera.chat/#mosh

---

### Overview (`src/tests/README.md`)

# Mosh Tests

## ocb-aes

This is a unit test for the OCB-AES encryption used in mosh, including
Rogaway's OCB implementation and some of mosh's surrounding C++
support code.

## encrypt-decrypt

This is a simple functional test of mosh's implementation of encrypted
messages.

## base64

This tests Mosh's homegrown base64 functionality.  The associated
`genbase64.pl` script is used to independently generate validated test
vectors.

## e2e-test

This is a test framework for end-to-end testing of mosh.  It uses tmux
to invoke mosh in a nicely stable interactive pty, and also uses
tmux's `capture-pane` command to get a dump of the terminal screen
that mosh-client has drawn, neatly getting around Mosh's somewhat
non-deterministic display redraw.

There are four essential parts to the framework:

* your test script
* `e2e-test`
* `e2e-test-server`
* `e2e-test-subrs`

The test script has two roles: when invoked without arguments, it is a
wrapper script for the overall test, and when invoked with an
argument, it performs a testing-related action.  In wrapper mode, it
invokes e2e-test with action arguments, which are used to invoke the
test script for actions at appropriate points by e2e-test.  These
provide a suite of behaviors that you can use to test various mosh
behaviors.

`e2e-test` is the heart of the framework.  It runs actions as
requested, logs their output, compares and/or validates their results,
and generates the final result (exitstatus, mostly) for the Automake
testing framework used by the mosh build.  For test execution, it runs
an action in an interactive session, in a tmux `screen`, to exercise
some behavior.  The action can optionally be run in a mosh session, or
directly in tmux (doing both and comparing the result is a useful way
to test complex terminal emulation behaviors).  The action generally
writes some output to the terminal that can later be verified by
another action.  Optionally, a client action can generate tty input or
otherwise exercise mosh in some fashion (this capability is untested,
but it's a useful place to use `expect` or other interactive
simulations).  The action is run by `e2e-test-server`, which is a
relatively small wrapper script to capture errors, and capture the
tmux screen.

There are several different categories of actions:

### Execution

`baseline` is an action that almost all tests will use.  This invokes
the test script inside mosh, where it can generate some output, and
then captures the client-side tmux display with `tmux capture-pane`.

`direct` is the same as the above, except that mosh is not used--
`e2e-wrapper-script` and the test script are invoked directly inside
tmux.

`variant` can be used to provide a slightly different action from
`baseline`.

### Verification

`verify` compares captures from the `baseline` and `direct` test
actions, which are expected to be identical.

`same` compares captures from the `baseline` and `variant` test
actions, which are expected to be identical.

`different` compares captures from the `baseline` and `variant` test
actions, which are expected to be different.

`post` is a catchall script hook which allows custom verification
acions to be coded.

### Client wrappers

`tmux` injects a wrapper command into the test command before tmux.
If this is not run, a default command called `hold-stdin` is run
instead.  These commands are expected to hold tmux's stdin open,
possibly injecting tmux commands, while the test runs.  See
`window-resize.test` for an example of this that manipulates tmux
state.  Alternately, this could use expect or something similar.

`client` simply injects a wrapper command into the (long) test command
between tmux and mosh.  It's expected to interact with its wrapped
command line as `expect` might do.  This is not actually tested yet.

### Flags

`mosh-args`, `client-args` and `server-args` inject extra arguments
into the invocations of the respective commands.

## Logging and error reporting

Each execution action is run, and recorded in
`<testname>.test.d/<action>.*`. `<action>.exitstatus` is the
exitstatus from the server wrapper.  `<action>.tmux.log` is the output
of tmux for the entire test run for that action; `<action>.capture` is
a capture of the Mosh client screen after the test action is complete,
generated with `tmux capture-pane`.

In accordance with GNU Automake's test framework, the test should
return these exit status values:

* 0 test success
* 1 test failure
* 77 test skipped (tmux or ssh is unavailable if needed)
* 99 hard error

These values are also used internally between the various scripts;
errors are conveyed out to the build test framework.


## Sample tests

A few tests have been implemented so far to test the framework itself,
and to provide examples for further development.

`e2e-success` is a simple test that executes `baseline` and `direct`
with the same stimulus (simply clearing the screen), and expects to
see identical results.

`e2e-failure` is similar to `e2e-success`, but expects to see
different results from `baseline` and `variant`.  Since it uses the
same stimulus for the two execution action, it fails.  A more
realistic test might be to have `variant` execute some escape sequence
that is absent from `baseline`; this would verify that the escape
sequence actually does something.

`emulation-back-tab` tests an escape sequence that mosh does not
support.  It expects the test to produce the output that would be
generated if the escape sequence were implemented.  If it gets output
as expected when the escape sequence is *not* implemented, the test
fails.  But if the output does not match one of these two cases, the
test returns an error.  This is an example of error handling within
the test framework.

`unicode-later-combining` demonstrates mosh's handling of a Unicode
edge case, a combining character drawn without a printing character in
the same cell.  It verifies the output in the `post` action; since
there are a couple of different Unicode renderings that are reasonable
in this case, a regex that covers both is used.  It also implements an
unused `variant` action that draws blank-space+combiner in a correct
fashion.

## Notes

The shell command `printf` is generally used in place of
`echo` in this framework, because of its more precisely-specified and
portable behavior.  But beware, even `printf` varies between systems--
GNU printf, for example, implements `\e`, which is a non-POSIX
extension unavailable in BSD implementations

It's fairly simple to test each of these scripts independently, but
the entire chain is a bit prone to behaving oddly in hard-to-debug
ways.  `set -x` is your friend here.

The test scripts are a bit fragile about timeouts.  They will
generally run correctly on an unloaded machine without the `make -j`
flag.  Using `make -j` is obviously very convenient for development,
and it works fine on faster machines, but I don't recommend it for
automated testing.

---

--- METRICS ---
- Files Extracted: 2
- Estimated Token Budget: ~3736 tokens
- Canonical Reference: https://codewiki.google/github.com/mobile-shell/mosh
