()
| 706 | } |
| 707 | |
| 708 | func (s *Socket) Close() syscall.Errno { |
| 709 | if !s.FD.ClosingIncRef() { |
| 710 | return unix.EBADF |
| 711 | } |
| 712 | defer s.FD.DecRef() |
| 713 | |
| 714 | s.FD.Lock() |
| 715 | if err := unix.Close(s.FD.FD()); err != nil { |
| 716 | var errno syscall.Errno |
| 717 | if !errors.As(err, &errno) { |
| 718 | panic(fmt.Errorf("cannot interpret close(2) error as errno: %w", err)) |
| 719 | } |
| 720 | return errno |
| 721 | } |
| 722 | |
| 723 | if last := s.Inode.remove(s); !last { |
| 724 | return 0 |
| 725 | } |
| 726 | |
| 727 | var errs []error |
| 728 | var prev *ImmutableState |
| 729 | for { |
| 730 | prev = s.Inode.state.Load() |
| 731 | if prev.state == StateClosed { |
| 732 | panic(fmt.Errorf("final socket close for inode %d: inode state is already closed", s.Inode.Number)) |
| 733 | } |
| 734 | |
| 735 | next := &ImmutableState{state: StateClosed} |
| 736 | if s.Inode.state.CompareAndSwap(prev, next) { |
| 737 | break |
| 738 | } |
| 739 | } |
| 740 | |
| 741 | switch prev.state { |
| 742 | case StatePassive: |
| 743 | if prev.passive.bind != nil && prev.passive.bind.ClosingIncRef() { |
| 744 | defer prev.passive.bind.DecRef() |
| 745 | prev.passive.bind.Lock() |
| 746 | if err := unix.Close(prev.passive.bind.FD()); err != nil { |
| 747 | errs = append(errs, fmt.Errorf("close temp bind socket: %w", err)) |
| 748 | } |
| 749 | } |
| 750 | |
| 751 | case StateConnected: |
| 752 | if prev.connected.proxy.skipCloseTCP.CompareAndSwap(false, true) { |
| 753 | // We can't close the two underlying TCP connections yet because the |
| 754 | // proxy might still have some unflushed bytes in a buffer somewhere. The |
| 755 | // connections will be closed when the (*proxy).start() goroutine ends. |
| 756 | // See the equivalent CAS in proxy.go for the process.Close() and |
| 757 | // external.Close() calls. |
| 758 | } else { |
| 759 | if err := prev.connected.proxy.process.Close(); err != nil && !errors.Is(err, net.ErrClosed) { |
| 760 | errs = append(errs, fmt.Errorf("close process conn: %w", err)) |
| 761 | } |
| 762 | if err := prev.connected.proxy.external.Close(); err != nil && !errors.Is(err, net.ErrClosed) { |
| 763 | errs = append(errs, fmt.Errorf("close external conn: %w", err)) |
| 764 | } |
| 765 | } |
no test coverage detected