// 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

package net

import (
	
	
	
	
	
)

const (
	readSyscallName     = "read"
	readFromSyscallName = "recvfrom"
	readMsgSyscallName  = "recvmsg"
	writeSyscallName    = "write"
	writeToSyscallName  = "sendto"
	writeMsgSyscallName = "sendmsg"
)

func newFD(, ,  int,  string) (*netFD, error) {
	 := &netFD{
		pfd: poll.FD{
			Sysfd:         ,
			IsStream:       == syscall.SOCK_STREAM,
			ZeroReadIsEOF:  != syscall.SOCK_DGRAM &&  != syscall.SOCK_RAW,
		},
		family: ,
		sotype: ,
		net:    ,
	}
	return , nil
}

func ( *netFD) () error {
	return .pfd.Init(.net, true)
}

func ( *netFD) ( context.Context, ,  syscall.Sockaddr) ( syscall.Sockaddr,  error) {
	// Do not need to call fd.writeLock here,
	// because fd is not yet accessible to user,
	// so no concurrent operations are possible.
	switch  := connectFunc(.pfd.Sysfd, );  {
	case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
	case nil, syscall.EISCONN:
		select {
		case <-.Done():
			return nil, mapErr(.Err())
		default:
		}
		if  := .pfd.Init(.net, true);  != nil {
			return nil, 
		}
		runtime.KeepAlive()
		return nil, nil
	case syscall.EINVAL:
		// On Solaris and illumos we can see EINVAL if the socket has
		// already been accepted and closed by the server.  Treat this
		// as a successful connection--writes to the socket will see
		// EOF.  For details and a test case in C see
		// https://golang.org/issue/6828.
		if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" {
			return nil, nil
		}
		fallthrough
	default:
		return nil, os.NewSyscallError("connect", )
	}
	if  := .pfd.Init(.net, true);  != nil {
		return nil, 
	}

	 := .Done()
	if  != nil {
		if ,  := .Deadline();  {
			.pfd.SetWriteDeadline()
			defer .pfd.SetWriteDeadline(noDeadline)
		}

		// Load the hook function synchronously to prevent a race
		// with test code that restores the old value.
		 := testHookCanceledDial
		 := context.AfterFunc(, func() {
			// Force the runtime's poller to immediately give up
			// waiting for writability, unblocking waitWrite
			// below.
			_ = .pfd.SetWriteDeadline(aLongTimeAgo)
			()
		})
		defer func() {
			if !() &&  == nil {
				// The context.AfterFunc has called or is about to call
				// SetWriteDeadline, but the connect code below had
				// returned from waitWrite already and did a successful
				// connect (ret == nil). Because we've now poisoned the
				// connection by making it unwritable, don't return a
				// successful dial. This was issue 16523.
				 = mapErr(.Err())
				// The caller closes fd on error, so there's no need to
				// wait for the SetWriteDeadline call to return.
			}
		}()
	}

	for {
		// Performing multiple connect system calls on a
		// non-blocking socket under Unix variants does not
		// necessarily result in earlier errors being
		// returned. Instead, once runtime-integrated network
		// poller tells us that the socket is ready, get the
		// SO_ERROR socket option to see if the connection
		// succeeded or failed. See issue 7474 for further
		// details.
		if  := .pfd.WaitWrite();  != nil {
			select {
			case <-:
				return nil, mapErr(.Err())
			default:
			}
			return nil, 
		}
		,  := getsockoptIntFunc(.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
		if  != nil {
			return nil, os.NewSyscallError("getsockopt", )
		}
		switch  := syscall.Errno();  {
		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
		case syscall.EISCONN:
			return nil, nil
		case syscall.Errno(0):
			// The runtime poller can wake us up spuriously;
			// see issues 14548 and 19289. Check that we are
			// really connected; if not, wait again.
			if ,  := syscall.Getpeername(.pfd.Sysfd);  == nil {
				return , nil
			}
		default:
			return nil, os.NewSyscallError("connect", )
		}
		runtime.KeepAlive()
	}
}

func ( *netFD) () ( *netFD,  error) {
	, , ,  := .pfd.Accept()
	if  != nil {
		if  != "" {
			 = wrapSyscallError(, )
		}
		return nil, 
	}

	if ,  = newFD(, .family, .sotype, .net);  != nil {
		poll.CloseFunc()
		return nil, 
	}
	if  = .init();  != nil {
		.Close()
		return nil, 
	}
	,  := syscall.Getsockname(.pfd.Sysfd)
	.setAddr(.addrFunc()(), .addrFunc()())
	return , nil
}

// Defined in os package.
func newUnixFile( int,  string) *os.File

func ( *netFD) () ( *os.File,  error) {
	, ,  := .pfd.Dup()
	if  != nil {
		if  != "" {
			 = os.NewSyscallError(, )
		}
		return nil, 
	}

	return newUnixFile(, .name()), nil
}