gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 "gvisor.dev/gvisor/pkg/abi/linux" 31 "gvisor.dev/gvisor/pkg/sync" 32 "gvisor.dev/gvisor/pkg/unet" 33 "gvisor.dev/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 }