github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/pkg/lisafs/fd.go (about) 1 // Copyright 2021 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 package lisafs 16 17 import ( 18 "golang.org/x/sys/unix" 19 "github.com/MerlinKodo/gvisor/pkg/abi/linux" 20 "github.com/MerlinKodo/gvisor/pkg/context" 21 "github.com/MerlinKodo/gvisor/pkg/refs" 22 "github.com/MerlinKodo/gvisor/pkg/sync" 23 ) 24 25 // FDID (file descriptor identifier) is used to identify FDs on a connection. 26 // Each connection has its own FDID namespace. 27 // 28 // +marshal boundCheck slice:FDIDSlice 29 type FDID uint64 30 31 // InvalidFDID represents an invalid FDID. 32 const InvalidFDID FDID = 0 33 34 // Ok returns true if f is a valid FDID. 35 func (f FDID) Ok() bool { 36 return f != InvalidFDID 37 } 38 39 // genericFD can represent any type of FD. 40 type genericFD interface { 41 refs.RefCounter 42 } 43 44 // A ControlFD is the gateway to the backing filesystem tree node. It is an 45 // unusual concept. This exists to provide a safe way to do path-based 46 // operations on the file. It performs operations that can modify the 47 // filesystem tree and synchronizes these operations. See ControlFDImpl for 48 // supported operations. 49 // 50 // It is not an inode, because multiple control FDs are allowed to exist on the 51 // same file. It is not a file descriptor because it is not tied to any access 52 // mode, i.e. a control FD can change its access mode based on the operation 53 // being performed. 54 // 55 // Reference Model: 56 // - Each control FD holds a ref on its Node for its entire lifetime. 57 type ControlFD struct { 58 controlFDRefs 59 controlFDEntry 60 61 // node is the filesystem node this FD is immutably associated with. 62 node *Node 63 64 // openFDs is a linked list of all FDs opened on this FD. As per reference 65 // model, all open FDs hold a ref on this FD. 66 openFDsMu sync.RWMutex 67 openFDs openFDList 68 69 // All the following fields are immutable. 70 71 // id is the unique FD identifier which identifies this FD on its connection. 72 id FDID 73 74 // conn is the backing connection owning this FD. 75 conn *Connection 76 77 // ftype is the file type of the backing inode. ftype.FileType() == ftype. 78 ftype linux.FileMode 79 80 // impl is the control FD implementation which embeds this struct. It 81 // contains all the implementation specific details. 82 impl ControlFDImpl 83 } 84 85 var _ genericFD = (*ControlFD)(nil) 86 87 // DecRef implements refs.RefCounter.DecRef. Note that the context 88 // parameter should never be used. It exists solely to comply with the 89 // refs.RefCounter interface. 90 func (fd *ControlFD) DecRef(context.Context) { 91 fd.controlFDRefs.DecRef(func() { 92 fd.conn.server.renameMu.RLock() 93 defer fd.conn.server.renameMu.RUnlock() 94 fd.destroyLocked() 95 }) 96 } 97 98 // decRefLocked is the same as DecRef except the added precondition. 99 // 100 // Precondition: server's rename mutex must be at least read locked. 101 func (fd *ControlFD) decRefLocked() { 102 fd.controlFDRefs.DecRef(func() { 103 fd.destroyLocked() 104 }) 105 } 106 107 // Precondition: server's rename mutex must be at least read locked. 108 func (fd *ControlFD) destroyLocked() { 109 // Update node's control FD list. 110 fd.node.removeFD(fd) 111 112 // Drop ref on node. 113 fd.node.DecRef(nil) 114 115 // Let the FD implementation clean up. 116 fd.impl.Close() 117 } 118 119 // Init must be called before first use of fd. It inserts fd into the 120 // filesystem tree. 121 // 122 // Preconditions: 123 // - server's rename mutex must be at least read locked. 124 // - The caller must take a ref on node which is transferred to fd. 125 func (fd *ControlFD) Init(c *Connection, node *Node, mode linux.FileMode, impl ControlFDImpl) { 126 fd.conn = c 127 fd.node = node 128 fd.impl = impl 129 fd.ftype = mode.FileType() 130 // Initialize fd with 1 ref which is transferred to c via c.insertFD(). 131 fd.controlFDRefs.InitRefs() 132 // Make fd reachable/discoverable. 133 fd.id = c.insertFD(fd) 134 node.insertFD(fd) 135 } 136 137 // Conn returns the fd's owning connection. 138 func (fd *ControlFD) Conn() *Connection { 139 return fd.conn 140 } 141 142 // FileType returns the file mode only containing the file type bits. 143 func (fd *ControlFD) FileType() linux.FileMode { 144 return fd.ftype 145 } 146 147 // IsDir indicates whether fd represents a directory. 148 func (fd *ControlFD) IsDir() bool { 149 return fd.ftype == unix.S_IFDIR 150 } 151 152 // IsRegular indicates whether fd represents a regular file. 153 func (fd *ControlFD) IsRegular() bool { 154 return fd.ftype == unix.S_IFREG 155 } 156 157 // IsSymlink indicates whether fd represents a symbolic link. 158 func (fd *ControlFD) IsSymlink() bool { 159 return fd.ftype == unix.S_IFLNK 160 } 161 162 // IsSocket indicates whether fd represents a socket. 163 func (fd *ControlFD) IsSocket() bool { 164 return fd.ftype == unix.S_IFSOCK 165 } 166 167 // Node returns the node this FD was opened on. 168 func (fd *ControlFD) Node() *Node { 169 return fd.node 170 } 171 172 // RemoveFromConn removes this control FD from its owning connection. 173 // 174 // Preconditions: 175 // - fd should not have been returned to the client. Otherwise the client can 176 // still refer to it. 177 // - server's rename mutex must at least be read locked. 178 func (fd *ControlFD) RemoveFromConn() { 179 fd.conn.removeControlFDLocked(fd.id) 180 } 181 182 // safelyRead executes the given operation with the local path node locked. 183 // This guarantees that fd's path will not change. fn may not any change paths. 184 func (fd *ControlFD) safelyRead(fn func() error) error { 185 fd.conn.server.renameMu.RLock() 186 defer fd.conn.server.renameMu.RUnlock() 187 fd.node.opMu.RLock() 188 defer fd.node.opMu.RUnlock() 189 return fn() 190 } 191 192 // safelyWrite executes the given operation with the local path node locked in 193 // a writable fashion. This guarantees that no other operation is executing on 194 // this path node. fn may change paths inside fd.node. 195 func (fd *ControlFD) safelyWrite(fn func() error) error { 196 fd.conn.server.renameMu.RLock() 197 defer fd.conn.server.renameMu.RUnlock() 198 fd.node.opMu.Lock() 199 defer fd.node.opMu.Unlock() 200 return fn() 201 } 202 203 // safelyGlobal executes the given operation with the global path lock held. 204 // This guarantees that no other operations is executing concurrently on this 205 // server. fn may change any path. 206 func (fd *ControlFD) safelyGlobal(fn func() error) (err error) { 207 fd.conn.server.renameMu.Lock() 208 defer fd.conn.server.renameMu.Unlock() 209 return fn() 210 } 211 212 // forEachOpenFD executes fn on each FD opened on fd. 213 func (fd *ControlFD) forEachOpenFD(fn func(ofd *OpenFD)) { 214 fd.openFDsMu.RLock() 215 defer fd.openFDsMu.RUnlock() 216 for ofd := fd.openFDs.Front(); ofd != nil; ofd = ofd.Next() { 217 fn(ofd) 218 } 219 } 220 221 // OpenFD represents an open file descriptor on the protocol. It resonates 222 // closely with a Linux file descriptor. Its operations are limited to the 223 // file. Its operations are not allowed to modify or traverse the filesystem 224 // tree. See OpenFDImpl for the supported operations. 225 // 226 // Reference Model: 227 // - An OpenFD takes a reference on the control FD it was opened on. 228 type OpenFD struct { 229 openFDRefs 230 openFDEntry 231 232 // All the following fields are immutable. 233 234 // controlFD is the ControlFD on which this FD was opened. OpenFD holds a ref 235 // on controlFD for its entire lifetime. 236 controlFD *ControlFD 237 238 // id is the unique FD identifier which identifies this FD on its connection. 239 id FDID 240 241 // Access mode for this FD. 242 readable bool 243 writable bool 244 245 // impl is the open FD implementation which embeds this struct. It 246 // contains all the implementation specific details. 247 impl OpenFDImpl 248 } 249 250 var _ genericFD = (*OpenFD)(nil) 251 252 // ControlFD returns the control FD on which this FD was opened. 253 func (fd *OpenFD) ControlFD() ControlFDImpl { 254 return fd.controlFD.impl 255 } 256 257 // DecRef implements refs.RefCounter.DecRef. Note that the context 258 // parameter should never be used. It exists solely to comply with the 259 // refs.RefCounter interface. 260 func (fd *OpenFD) DecRef(context.Context) { 261 fd.openFDRefs.DecRef(func() { 262 fd.controlFD.openFDsMu.Lock() 263 fd.controlFD.openFDs.Remove(fd) 264 fd.controlFD.openFDsMu.Unlock() 265 fd.controlFD.DecRef(nil) // Drop the ref on the control FD. 266 fd.impl.Close() 267 }) 268 } 269 270 // Init must be called before first use of fd. 271 func (fd *OpenFD) Init(cfd *ControlFD, flags uint32, impl OpenFDImpl) { 272 // Initialize fd with 1 ref which is transferred to c via c.insertFD(). 273 fd.openFDRefs.InitRefs() 274 fd.controlFD = cfd 275 fd.id = cfd.conn.insertFD(fd) 276 accessMode := flags & unix.O_ACCMODE 277 fd.readable = accessMode == unix.O_RDONLY || accessMode == unix.O_RDWR 278 fd.writable = accessMode == unix.O_WRONLY || accessMode == unix.O_RDWR 279 fd.impl = impl 280 cfd.IncRef() // Holds a ref on cfd for its lifetime. 281 cfd.openFDsMu.Lock() 282 cfd.openFDs.PushBack(fd) 283 cfd.openFDsMu.Unlock() 284 } 285 286 // BoundSocketFD represents a bound socket on the server. 287 // 288 // Reference Model: 289 // - A BoundSocketFD takes a reference on the control FD it is bound to. 290 type BoundSocketFD struct { 291 boundSocketFDRefs 292 293 // All the following fields are immutable. 294 295 // controlFD is the ControlFD on which this FD was bound. BoundSocketFD 296 // holds a ref on controlFD for its entire lifetime. 297 controlFD *ControlFD 298 299 // id is the unique FD identifier which identifies this FD on its connection. 300 id FDID 301 302 // impl is the socket FD implementation which embeds this struct. It 303 // contains all the implementation specific details. 304 impl BoundSocketFDImpl 305 } 306 307 var _ genericFD = (*BoundSocketFD)(nil) 308 309 // ControlFD returns the control FD on which this FD was bound. 310 func (fd *BoundSocketFD) ControlFD() ControlFDImpl { 311 return fd.controlFD.impl 312 } 313 314 // DecRef implements refs.RefCounter.DecRef. Note that the context 315 // parameter should never be used. It exists solely to comply with the 316 // refs.RefCounter interface. 317 func (fd *BoundSocketFD) DecRef(context.Context) { 318 fd.boundSocketFDRefs.DecRef(func() { 319 fd.controlFD.DecRef(nil) // Drop the ref on the control FD. 320 fd.impl.Close() 321 }) 322 } 323 324 // Init must be called before first use of fd. 325 func (fd *BoundSocketFD) Init(cfd *ControlFD, impl BoundSocketFDImpl) { 326 // Initialize fd with 1 ref which is transferred to c via c.insertFD(). 327 fd.boundSocketFDRefs.InitRefs() 328 fd.controlFD = cfd 329 fd.id = cfd.conn.insertFD(fd) 330 fd.impl = impl 331 cfd.IncRef() // Holds a ref on cfd for its lifetime. 332 } 333 334 // There are four different types of guarantees provided: 335 // 336 // none: There is no concurrency guarantee. The method may be invoked 337 // concurrently with any other method on any other FD. 338 // 339 // read: The method is guaranteed to be exclusive of any write or global 340 // operation that is mutating the state of the directory tree starting at this 341 // node. For example, this means creating new files, symlinks, directories or 342 // renaming a directory entry (or renaming in to this target), but the method 343 // may be called concurrently with other read methods. 344 // 345 // write: The method is guaranteed to be exclusive of any read, write or global 346 // operation that is mutating the state of the directory tree starting at this 347 // node, as described in read above. There may however, be other write 348 // operations executing concurrently on other components in the directory tree. 349 // 350 // global: The method is guaranteed to be exclusive of any read, write or 351 // global operation. 352 353 // ControlFDImpl contains implementation details for a ControlFD. 354 // Implementations of ControlFDImpl should contain their associated ControlFD 355 // by value as their first field. 356 // 357 // The operations that perform path traversal or any modification to the 358 // filesystem tree must synchronize those modifications with the server's 359 // rename mutex. 360 type ControlFDImpl interface { 361 // FD returns a pointer to the embedded ControlFD. 362 FD() *ControlFD 363 364 // Close should clean up resources used by the control FD implementation. 365 // Close is called after all references on the FD have been dropped and its 366 // FDID has been released. 367 // 368 // On the server, Close has no concurrency guarantee. 369 Close() 370 371 // Stat returns the stat(2) results for this FD. 372 // 373 // On the server, Stat has a read concurrency guarantee. 374 Stat() (linux.Statx, error) 375 376 // SetStat sets file attributes on the backing file. This does not correspond 377 // to any one Linux syscall. On Linux, this operation is performed using 378 // multiple syscalls like fchmod(2), fchown(2), ftruncate(2), futimesat(2) 379 // and so on. The implementation must only set attributes for fields 380 // indicated by stat.Mask. Failure to set an attribute may or may not 381 // terminate the entire operation. SetStat must return a uint32 which is 382 // interpreted as a stat mask to indicate which attribute setting attempts 383 // failed. If multiple attribute setting attempts failed, the returned error 384 // may be from any one of them. 385 // 386 // On the server, SetStat has a write concurrency guarantee. 387 SetStat(stat SetStatReq) (uint32, error) 388 389 // Walk walks one path component from the directory represented by this FD. 390 // Walk must open a ControlFD on the walked file. 391 // 392 // On the server, Walk has a read concurrency guarantee. 393 Walk(name string) (*ControlFD, linux.Statx, error) 394 395 // WalkStat is capable of walking multiple path components and returning the 396 // stat results for each path component walked via recordStat. Stat results 397 // must be returned in the order of walk. 398 // 399 // In case a symlink is encountered, the walk must terminate successfully on 400 // the symlink including its stat result. 401 // 402 // The first path component of path may be "" which indicates that the first 403 // stat result returned must be of this starting directory. 404 // 405 // On the server, WalkStat has a read concurrency guarantee. 406 WalkStat(path StringArray, recordStat func(linux.Statx)) error 407 408 // Open opens the control FD with the flags passed. The flags should be 409 // interpreted as open(2) flags. 410 // 411 // Open may also optionally return a host FD for the opened file whose 412 // lifecycle is independent of the OpenFD. Returns -1 if not available. 413 // 414 // N.B. The server must resolve any lazy paths when open is called. 415 // After this point, read and write may be called on files with no 416 // deletion check, so resolving in the data path is not viable. 417 // 418 // On the server, Open has a read concurrency guarantee. 419 Open(flags uint32) (*OpenFD, int, error) 420 421 // OpenCreate creates a regular file inside the directory represented by this 422 // FD and then also opens the file. The created file has perms as specified 423 // by mode and owners as specified by uid and gid. The file is opened with 424 // the specified flags. 425 // 426 // OpenCreate may also optionally return a host FD for the opened file whose 427 // lifecycle is independent of the OpenFD. Returns -1 if not available. 428 // 429 // N.B. The server must resolve any lazy paths when open is called. 430 // After this point, read and write may be called on files with no 431 // deletion check, so resolving in the data path is not viable. 432 // 433 // On the server, OpenCreate has a write concurrency guarantee. 434 OpenCreate(mode linux.FileMode, uid UID, gid GID, name string, flags uint32) (*ControlFD, linux.Statx, *OpenFD, int, error) 435 436 // Mkdir creates a directory inside the directory represented by this FD. The 437 // created directory has perms as specified by mode and owners as specified 438 // by uid and gid. 439 // 440 // On the server, Mkdir has a write concurrency guarantee. 441 Mkdir(mode linux.FileMode, uid UID, gid GID, name string) (*ControlFD, linux.Statx, error) 442 443 // Mknod creates a file inside the directory represented by this FD. The file 444 // type and perms are specified by mode and owners are specified by uid and 445 // gid. If the newly created file is a character or block device, minor and 446 // major specify its device number. 447 // 448 // On the server, Mkdir has a write concurrency guarantee. 449 Mknod(mode linux.FileMode, uid UID, gid GID, name string, minor uint32, major uint32) (*ControlFD, linux.Statx, error) 450 451 // Symlink creates a symlink inside the directory represented by this FD. The 452 // symlink has owners as specified by uid and gid and points to target. 453 // 454 // On the server, Symlink has a write concurrency guarantee. 455 Symlink(name string, target string, uid UID, gid GID) (*ControlFD, linux.Statx, error) 456 457 // Link creates a hard link to the file represented by this FD. The hard link 458 // is created inside dir with the specified name. 459 // 460 // On the server, Link has a write concurrency guarantee for dir and read 461 // concurrency guarantee for this file. 462 Link(dir ControlFDImpl, name string) (*ControlFD, linux.Statx, error) 463 464 // StatFS returns information about the file system associated with 465 // this file. 466 // 467 // On the server, StatFS has read concurrency guarantee. 468 StatFS() (StatFS, error) 469 470 // Readlink reads the symlink's target and writes the string into the buffer 471 // returned by getLinkBuf which can be used to request buffer for some size. 472 // It returns the number of bytes written into the buffer. 473 // 474 // On the server, Readlink has a read concurrency guarantee. 475 Readlink(getLinkBuf func(uint32) []byte) (uint16, error) 476 477 // Connect establishes a new host-socket backed connection with a unix domain 478 // socket. On success it returns a non-blocking host socket FD whose 479 // lifecycle is independent of this ControlFD. 480 // 481 // sockType indicates the requested type of socket and can be passed as type 482 // argument to socket(2). 483 // 484 // On the server, Connect has a read concurrency guarantee. 485 Connect(sockType uint32) (int, error) 486 487 // BindAt creates a host unix domain socket of type sockType, bound to 488 // the given namt of type sockType, bound to the given name. It returns 489 // a ControlFD that can be used for path operations on the socket, a 490 // BoundSocketFD that can be used to Accept/Listen on the socket, and a 491 // host FD that can be used for event notifications (like new 492 // connections). 493 // 494 // On the server, BindAt has a write concurrency guarantee. 495 BindAt(name string, sockType uint32, mode linux.FileMode, uid UID, gid GID) (*ControlFD, linux.Statx, *BoundSocketFD, int, error) 496 497 // UnlinkAt the file identified by name in this directory. 498 // 499 // Flags are Linux unlinkat(2) flags. 500 // 501 // On the server, UnlinkAt has a write concurrency guarantee. 502 Unlink(name string, flags uint32) error 503 504 // RenameAt renames a given file to a new name in a potentially new directory. 505 // 506 // oldName must be a name relative to this file, which must be a directory. 507 // newName is a name relative to newDir. 508 // 509 // On the server, RenameAt has a global concurrency guarantee. 510 RenameAt(oldName string, newDir ControlFDImpl, newName string) error 511 512 // Renamed is called to notify the FD implementation that the file has been 513 // renamed. FD implementation may update its state accordingly. 514 // 515 // On the server, Renamed has a global concurrency guarantee. 516 Renamed() 517 518 // GetXattr returns extended attributes of this file. It returns the number 519 // of bytes written into the buffer returned by getValueBuf which can be used 520 // to request buffer for some size. 521 // 522 // If the value is larger than size, implementations may return ERANGE to 523 // indicate that the buffer is too small. 524 // 525 // N.B. size may be 0, in which can the implementation must first find out 526 // the attribute value size using getxattr(2) by passing size=0. Then request 527 // a buffer large enough using getValueBuf and write the value there. 528 // 529 // On the server, GetXattr has a read concurrency guarantee. 530 GetXattr(name string, size uint32, getValueBuf func(uint32) []byte) (uint16, error) 531 532 // SetXattr sets extended attributes on this file. 533 // 534 // On the server, SetXattr has a write concurrency guarantee. 535 SetXattr(name string, value string, flags uint32) error 536 537 // ListXattr lists the names of the extended attributes on this file. 538 // 539 // Size indicates the size of the buffer that has been allocated to hold the 540 // attribute list. If the list would be larger than size, implementations may 541 // return ERANGE to indicate that the buffer is too small, but they are also 542 // free to ignore the hint entirely (i.e. the value returned may be larger 543 // than size). All size checking is done independently at the syscall layer. 544 // 545 // On the server, ListXattr has a read concurrency guarantee. 546 ListXattr(size uint64) (StringArray, error) 547 548 // RemoveXattr removes extended attributes on this file. 549 // 550 // On the server, RemoveXattr has a write concurrency guarantee. 551 RemoveXattr(name string) error 552 } 553 554 // OpenFDImpl contains implementation details for a OpenFD. Implementations of 555 // OpenFDImpl should contain their associated OpenFD by value as their first 556 // field. 557 // 558 // Since these operations do not perform any path traversal or any modification 559 // to the filesystem tree, there is no need to synchronize with rename 560 // operations. 561 type OpenFDImpl interface { 562 // FD returns a pointer to the embedded OpenFD. 563 FD() *OpenFD 564 565 // Close should clean up resources used by the open FD implementation. 566 // Close is called after all references on the FD have been dropped and its 567 // FDID has been released. 568 // 569 // On the server, Close has no concurrency guarantee. 570 Close() 571 572 // Stat returns the stat(2) results for this FD. 573 // 574 // On the server, Stat has a read concurrency guarantee. 575 Stat() (linux.Statx, error) 576 577 // Sync is simialr to fsync(2). 578 // 579 // On the server, Sync has a read concurrency guarantee. 580 Sync() error 581 582 // Write writes buf at offset off to the backing file via this open FD. Write 583 // attempts to write len(buf) bytes and returns the number of bytes written. 584 // 585 // On the server, Write has a write concurrency guarantee. See Open for 586 // additional requirements regarding lazy path resolution. 587 Write(buf []byte, off uint64) (uint64, error) 588 589 // Read reads at offset off into buf from the backing file via this open FD. 590 // Read attempts to read len(buf) bytes and returns the number of bytes read. 591 // 592 // On the server, Read has a read concurrency guarantee. See Open for 593 // additional requirements regarding lazy path resolution. 594 Read(buf []byte, off uint64) (uint64, error) 595 596 // Allocate allows the caller to directly manipulate the allocated disk space 597 // for the file. See fallocate(2) for more details. 598 // 599 // On the server, Allocate has a write concurrency guarantee. 600 Allocate(mode, off, length uint64) error 601 602 // Flush can be used to clean up the file state. Behavior is 603 // implementation-specific. 604 // 605 // On the server, Flush has a read concurrency guarantee. 606 Flush() error 607 608 // Getdent64 fetches directory entries for this directory and calls 609 // recordDirent for each dirent read. If seek0 is true, then the directory FD 610 // is seeked to 0 and iteration starts from the beginning. 611 // 612 // On the server, Getdent64 has a read concurrency guarantee. 613 Getdent64(count uint32, seek0 bool, recordDirent func(Dirent64)) error 614 615 // Renamed is called to notify the FD implementation that the file has been 616 // renamed. FD implementation may update its state accordingly. 617 // 618 // On the server, Renamed has a global concurrency guarantee. 619 Renamed() 620 } 621 622 // BoundSocketFDImpl represents a socket on the host filesystem that has been 623 // created by the sandboxed application via Bind. 624 type BoundSocketFDImpl interface { 625 // FD returns a pointer to the embedded BoundSocketFD. 626 FD() *BoundSocketFD 627 628 // Listen marks the socket as accepting incoming connections. 629 // 630 // On the server, Listen has a read concurrency guarantee. 631 Listen(backlog int32) error 632 633 // Accept takes the first pending connection and creates a new socket 634 // for it. The new socket FD is returned along with the peer address of 635 // the connecting socket (which may be empty string). 636 // 637 // On the server, Accept has a read concurrency guarantee. 638 Accept() (int, string, error) 639 640 // Close should clean up resources used by the bound socket FD 641 // implementation. 642 // 643 // Close is called after all references on the FD have been dropped and its 644 // FDID has been released. 645 // 646 // On the server, Close has no concurrency guarantee. 647 Close() 648 }