1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Package server provides a basic control server interface.
Note that no objects are registered by default. Users must provide their own
implementations of the control interface.
*/
package server
import (
"fmt"
"os"
"path/filepath"
"sync/atomic"
"time"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/unet"
"gvisor.dev/gvisor/pkg/urpc"
)
// curUID is the unix user ID of the user that the control server is running as.
var curUID = os.Getuid()
// Server is a basic control server.
type Server struct {
// socket is our bound socket.
socket *unet.ServerSocket
// server is our rpc server.
server atomic.Pointer[urpc.Server]
// wg waits for the accept loop to terminate.
wg sync.WaitGroup
}
// New returns a new bound control server.
func New(socket *unet.ServerSocket) *Server {
s := &Server{
socket: socket,
}
s.server.Store(urpc.NewServer())
return s
}
// ResetServer resets the server, clearing all registered objects. It stops the
// old server asynchronously.
func (s *Server) ResetServer() {
if old := s.server.Swap(urpc.NewServer()); old != nil {
go old.Stop(0)
}
}
// FD returns the file descriptor that the server is running on.
func (s *Server) FD() int {
return s.socket.FD()
}
// Wait waits for the main server goroutine to exit. This should be
// called after a call to Serve.
func (s *Server) Wait() {
s.wg.Wait()
}
// Stop stops the server. Note that this function should only be called once
// and the server should not be used afterwards.
func (s *Server) Stop(timeout time.Duration) {
s.socket.Close()
s.Wait()
// This will cause existing clients to be terminated safely. If the
// registered handlers have a Stop callback, it will be called.
s.server.Load().Stop(timeout)
}
// StartServing starts listening for connect and spawns the main service
// goroutine for handling incoming control requests. StartServing does not
// block; to wait for the control server to exit, call Wait.
func (s *Server) StartServing() error {
// Actually start listening.
if err := s.socket.Listen(); err != nil {
return err
}
s.wg.Add(1)
go func() { // S/R-SAFE: does not impact state directly.
s.serve()
s.wg.Done()
}()
return nil
}
// serve is the body of the main service goroutine. It handles incoming control
// connections and dispatches requests to registered objects.
func (s *Server) serve() {
for {
// Accept clients.
conn, err := s.socket.Accept()
if err != nil {
return
}
// Handle the connection non-blockingly.
s.server.Load().StartHandling(conn)
}
}
// Register registers a specific control interface with the server.
func (s *Server) Register(obj any) {
s.server.Load().Register(obj)
}
// CreateFromFD creates a new control bound to the given 'fd'. It has no
// registered interfaces and will not start serving until StartServing is
// called.
func CreateFromFD(fd int) (*Server, error) {
socket, err := unet.NewServerSocket(fd)
if err != nil {
return nil, err
}
return New(socket), nil
}
// Create creates a new control server with an abstract unix socket
// with the given address, which must must be unique and a valid
// abstract socket name.
func Create(addr string) (*Server, error) {
socket, err := CreateSocket(addr)
if err != nil {
return nil, err
}
return CreateFromFD(socket)
}
// CreateSocket creates a socket that can be used with control server,
// but doesn't start control server. 'addr' must be a valid and unique
// abstract socket name. Returns socket's FD, -1 in case of error.
func CreateSocket(addr string) (int, error) {
if addr[0] != 0 && len(addr) >= linux.UnixPathMax {
// This is not an abstract socket path. It is a filesystem path.
// UDS bind fails when the len(socket path) >= UNIX_PATH_MAX. Instead
// try opening the parent and attempt to shorten the path via procfs.
dirFD, err := unix.Open(filepath.Dir(addr), unix.O_RDONLY|unix.O_DIRECTORY, 0)
if err != nil {
return -1, fmt.Errorf("failed to open parent directory of %q", addr)
}
defer unix.Close(dirFD)
name := filepath.Base(addr)
addr = fmt.Sprintf("/proc/self/fd/%d/%s", dirFD, name)
if len(addr) >= linux.UnixPathMax {
// Urgh... This is just doomed to fail. Ask caller to use a shorter name.
return -1, fmt.Errorf("socket name %q is too long, use a shorter name", name)
}
}
socket, err := unet.Bind(addr, false)
if err != nil {
return -1, err
}
return socket.Release()
}
|