github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/control/server/server.go (about)

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