v0.1.0 cbb8ad6

connect.go RawHistoryFolder

1// SPDX-License-Identifier: MIT
2
3package guest
4
5import (
6	"context"
7	"fmt"
8	"io"
9	"net"
10	"strconv"
11	"strings"
12	"time"
13
14	"golang.org/x/sys/unix"
15)
16
17// Target is where the executor connects back to: "unix:/path" (container) or
18// "vsock:PORT" (vm; the host is CID 2).
19type Target struct {
20	Network string // "unix" or "vsock"
21	Addr    string // socket path, or the vsock port
22}
23
24// ParseTarget parses "unix:/path" or "vsock:port".
25func ParseTarget(s string) (Target, error) {
26	kind, rest, ok := strings.Cut(s, ":")
27	if !ok || rest == "" {
28		return Target{}, fmt.Errorf("connect target %q: want unix:PATH or vsock:PORT", s)
29	}
30	switch kind {
31	case "unix":
32		return Target{Network: "unix", Addr: rest}, nil
33	case "vsock":
34		if p, err := strconv.ParseUint(rest, 10, 32); err != nil || p == 0 {
35			return Target{}, fmt.Errorf("connect target %q: bad vsock port", s)
36		}
37		return Target{Network: "vsock", Addr: rest}, nil
38	}
39	return Target{}, fmt.Errorf("connect target %q: unknown kind %q", s, kind)
40}
41
42func (t Target) String() string { return t.Network + ":" + t.Addr }
43
44// Dial connects to the host, retrying until ctx ends or timeout elapses: the
45// host listens before the sandbox starts, but a vsock device may take a moment.
46func (t Target) Dial(ctx context.Context, timeout time.Duration) (io.ReadWriteCloser, error) {
47	ctx, cancel := context.WithTimeout(ctx, timeout)
48	defer cancel()
49	var last error
50	for {
51		var c io.ReadWriteCloser
52		var err error
53		if t.Network == "unix" {
54			var d net.Dialer
55			c, err = d.DialContext(ctx, "unix", t.Addr)
56		} else {
57			c, err = dialVsock(t.Addr)
58		}
59		if err == nil {
60			return c, nil
61		}
62		last = err
63		select {
64		case <-ctx.Done():
65			return nil, fmt.Errorf("connect to %s: %w (last error: %v)", t, ctx.Err(), last)
66		case <-time.After(100 * time.Millisecond):
67		}
68	}
69}
70
71// vsockHostCID is the well-known CID of the host.
72const vsockHostCID = 2
73
74func dialVsock(port string) (io.ReadWriteCloser, error) {
75	p, _ := strconv.ParseUint(port, 10, 32)
76	fd, err := unix.Socket(unix.AF_VSOCK, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
77	if err != nil {
78		return nil, err
79	}
80	// A blocking connect is fine: a Firecracker vsock either connects to the
81	// host listener at once or fails.
82	if err := unix.Connect(fd, &unix.SockaddrVM{CID: vsockHostCID, Port: uint32(p)}); err != nil {
83		_ = unix.Close(fd)
84		return nil, err
85	}
86	return newFDConn(fd)
87}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 4

Tags 11

↑↓ moveenter openesc close