// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build unix || js || wasip1 || windows

package net

import (
	
	
	
	
)

func unixSocket( context.Context,  string, ,  sockaddr,  string,  func(context.Context, string, string, syscall.RawConn) error) (*netFD, error) {
	var  int
	switch  {
	case "unix":
		 = syscall.SOCK_STREAM
	case "unixgram":
		 = syscall.SOCK_DGRAM
	case "unixpacket":
		 = syscall.SOCK_SEQPACKET
	default:
		return nil, UnknownNetworkError()
	}

	switch  {
	case "dial":
		if  != nil && .isWildcard() {
			 = nil
		}
		if  != nil && .isWildcard() {
			 = nil
		}
		if  == nil && ( != syscall.SOCK_DGRAM ||  == nil) {
			return nil, errMissingAddress
		}
	case "listen":
	default:
		return nil, errors.New("unknown mode: " + )
	}

	,  := socket(, , syscall.AF_UNIX, , 0, false, , , )
	if  != nil {
		return nil, 
	}
	return , nil
}

func sockaddrToUnix( syscall.Sockaddr) Addr {
	if ,  := .(*syscall.SockaddrUnix);  {
		return &UnixAddr{Name: .Name, Net: "unix"}
	}
	return nil
}

func sockaddrToUnixgram( syscall.Sockaddr) Addr {
	if ,  := .(*syscall.SockaddrUnix);  {
		return &UnixAddr{Name: .Name, Net: "unixgram"}
	}
	return nil
}

func sockaddrToUnixpacket( syscall.Sockaddr) Addr {
	if ,  := .(*syscall.SockaddrUnix);  {
		return &UnixAddr{Name: .Name, Net: "unixpacket"}
	}
	return nil
}

func sotypeToNet( int) string {
	switch  {
	case syscall.SOCK_STREAM:
		return "unix"
	case syscall.SOCK_DGRAM:
		return "unixgram"
	case syscall.SOCK_SEQPACKET:
		return "unixpacket"
	default:
		panic("sotypeToNet unknown socket type")
	}
}

func ( *UnixAddr) () int {
	return syscall.AF_UNIX
}

func ( *UnixAddr) ( int) (syscall.Sockaddr, error) {
	if  == nil {
		return nil, nil
	}
	return &syscall.SockaddrUnix{Name: .Name}, nil
}

func ( *UnixAddr) ( string) sockaddr {
	return 
}

func ( *UnixConn) ( []byte) (int, *UnixAddr, error) {
	var  *UnixAddr
	, ,  := .fd.readFrom()
	switch sa := .(type) {
	case *syscall.SockaddrUnix:
		if .Name != "" {
			 = &UnixAddr{Name: .Name, Net: sotypeToNet(.fd.sotype)}
		}
	}
	return , , 
}

func ( *UnixConn) (,  []byte) (, ,  int,  *UnixAddr,  error) {
	var  syscall.Sockaddr
	, , , ,  = .fd.readMsg(, , readMsgFlags)
	if readMsgFlags == 0 &&  == nil &&  > 0 {
		setReadMsgCloseOnExec([:])
	}

	switch sa := .(type) {
	case *syscall.SockaddrUnix:
		if .Name != "" {
			 = &UnixAddr{Name: .Name, Net: sotypeToNet(.fd.sotype)}
		}
	}
	return
}

func ( *UnixConn) ( []byte,  *UnixAddr) (int, error) {
	if .fd.isConnected {
		return 0, ErrWriteToConnected
	}
	if  == nil {
		return 0, errMissingAddress
	}
	if .Net != sotypeToNet(.fd.sotype) {
		return 0, syscall.EAFNOSUPPORT
	}
	 := &syscall.SockaddrUnix{Name: .Name}
	return .fd.writeTo(, )
}

func ( *UnixConn) (,  []byte,  *UnixAddr) (,  int,  error) {
	if .fd.sotype == syscall.SOCK_DGRAM && .fd.isConnected {
		return 0, 0, ErrWriteToConnected
	}
	var  syscall.Sockaddr
	if  != nil {
		if .Net != sotypeToNet(.fd.sotype) {
			return 0, 0, syscall.EAFNOSUPPORT
		}
		 = &syscall.SockaddrUnix{Name: .Name}
	}
	return .fd.writeMsg(, , )
}

func ( *sysDialer) ( context.Context, ,  *UnixAddr) (*UnixConn, error) {
	 := .Dialer.ControlContext
	if  == nil && .Dialer.Control != nil {
		 = func( context.Context, ,  string,  syscall.RawConn) error {
			return .Dialer.Control(, , )
		}
	}
	,  := unixSocket(, .network, , , "dial", )
	if  != nil {
		return nil, 
	}
	return newUnixConn(), nil
}

func ( *UnixListener) () (*UnixConn, error) {
	,  := .fd.accept()
	if  != nil {
		return nil, 
	}
	return newUnixConn(), nil
}

func ( *UnixListener) () error {
	// The operating system doesn't clean up
	// the file that announcing created, so
	// we have to clean it up ourselves.
	// There's a race here--we can't know for
	// sure whether someone else has come along
	// and replaced our socket name already--
	// but this sequence (remove then close)
	// is at least compatible with the auto-remove
	// sequence in ListenUnix. It's only non-Go
	// programs that can mess us up.
	// Even if there are racy calls to Close, we want to unlink only for the first one.
	.unlinkOnce.Do(func() {
		if .path[0] != '@' && .unlink {
			syscall.Unlink(.path)
		}
	})
	return .fd.Close()
}

func ( *UnixListener) () (*os.File, error) {
	,  := .fd.dup()
	if  != nil {
		return nil, 
	}
	return , nil
}

// SetUnlinkOnClose sets whether the underlying socket file should be removed
// from the file system when the listener is closed.
//
// The default behavior is to unlink the socket file only when package net created it.
// That is, when the listener and the underlying socket file were created by a call to
// Listen or ListenUnix, then by default closing the listener will remove the socket file.
// but if the listener was created by a call to FileListener to use an already existing
// socket file, then by default closing the listener will not remove the socket file.
func ( *UnixListener) ( bool) {
	.unlink = 
}

func ( *sysListener) ( context.Context,  *UnixAddr) (*UnixListener, error) {
	var  func( context.Context, ,  string,  syscall.RawConn) error
	if .ListenConfig.Control != nil {
		 = func( context.Context, ,  string,  syscall.RawConn) error {
			return .ListenConfig.Control(, , )
		}
	}
	,  := unixSocket(, .network, , nil, "listen", )
	if  != nil {
		return nil, 
	}
	return &UnixListener{fd: , path: .laddr.String(), unlink: true}, nil
}

func ( *sysListener) ( context.Context,  *UnixAddr) (*UnixConn, error) {
	var  func( context.Context, ,  string,  syscall.RawConn) error
	if .ListenConfig.Control != nil {
		 = func( context.Context, ,  string,  syscall.RawConn) error {
			return .ListenConfig.Control(, , )
		}
	}
	,  := unixSocket(, .network, , nil, "listen", )
	if  != nil {
		return nil, 
	}
	return newUnixConn(), nil
}