Bind binds the socket to the given address. Internally, it uses a dummy temporary socket in order to check if the address is bindable and also reserve the address for future operations.
(addr netip.AddrPort)
| 390 | // temporary socket in order to check if the address is bindable and also |
| 391 | // reserve the address for future operations. |
| 392 | func (s *Socket) Bind(addr netip.AddrPort) (syscall.Errno, error) { |
| 393 | if !s.FD.IncRef() { |
| 394 | return unix.EBADF, nil |
| 395 | } |
| 396 | defer s.FD.DecRef() |
| 397 | |
| 398 | prev := s.Inode.state.Load() |
| 399 | switch prev.state { |
| 400 | case StatePassive: |
| 401 | break |
| 402 | case StateConnected, StateConnecting, StateListening: |
| 403 | return unix.EINVAL, nil |
| 404 | case StateClosed: |
| 405 | return unix.EBADF, nil |
| 406 | } |
| 407 | |
| 408 | if s.Inode.Domain == unix.AF_INET && !addr.Addr().Is4() { |
| 409 | return unix.EINVAL, nil |
| 410 | } |
| 411 | if s.Inode.Domain == unix.AF_INET6 && !addr.Addr().Is6() { |
| 412 | return unix.EINVAL, nil |
| 413 | } |
| 414 | |
| 415 | next := &ImmutableState{state: StatePassive} |
| 416 | next.passive.bind = prev.passive.bind |
| 417 | if next.passive.bind == nil { |
| 418 | var err error |
| 419 | next.passive.bind, err = newTempBindSocket(s.Inode.Domain) |
| 420 | if err != nil { |
| 421 | return 0, fmt.Errorf("create temp bind socket: %w", err) |
| 422 | } |
| 423 | } |
| 424 | |
| 425 | if !next.passive.bind.IncRef() { |
| 426 | return unix.EBADF, nil |
| 427 | } |
| 428 | defer next.passive.bind.DecRef() |
| 429 | |
| 430 | var sa unix.Sockaddr |
| 431 | switch s.Inode.Domain { |
| 432 | case unix.AF_INET: |
| 433 | sa = &unix.SockaddrInet4{Addr: addr.Addr().As4(), Port: int(addr.Port())} |
| 434 | case unix.AF_INET6: |
| 435 | sa = &unix.SockaddrInet6{Addr: addr.Addr().As16(), Port: int(addr.Port())} |
| 436 | } |
| 437 | |
| 438 | if err := unix.Bind(next.passive.bind.FD(), sa); err != nil { |
| 439 | if prev.passive.bind == nil { |
| 440 | unix.Close(next.passive.bind.FD()) |
| 441 | } |
| 442 | next := &ImmutableState{state: StatePassive} |
| 443 | next.passive.bind = prev.passive.bind |
| 444 | if !errors.As(err, &next.passive.errno) { |
| 445 | return 0, fmt.Errorf("bind: %w", err) |
| 446 | } |
| 447 | if !s.Inode.state.CompareAndSwap(prev, next) { |
| 448 | return unix.ERESTART, nil |
| 449 | } |