package net
import (
"context"
"internal/poll"
"os"
"runtime"
"syscall"
)
const (
readSyscallName = "read"
readFromSyscallName = "recvfrom"
readMsgSyscallName = "recvmsg"
writeSyscallName = "write"
writeToSyscallName = "sendto"
writeMsgSyscallName = "sendmsg"
)
func newFD(sysfd , family , sotype int , net string ) (*netFD , error ) {
ret := &netFD {
pfd : poll .FD {
Sysfd : sysfd ,
IsStream : sotype == syscall .SOCK_STREAM ,
ZeroReadIsEOF : sotype != syscall .SOCK_DGRAM && sotype != syscall .SOCK_RAW ,
},
family : family ,
sotype : sotype ,
net : net ,
}
return ret , nil
}
func (fd *netFD ) init () error {
return fd .pfd .Init (fd .net , true )
}
func (fd *netFD ) name () string {
var ls , rs string
if fd .laddr != nil {
ls = fd .laddr .String ()
}
if fd .raddr != nil {
rs = fd .raddr .String ()
}
return fd .net + ":" + ls + "->" + rs
}
func (fd *netFD ) connect (ctx context .Context , la , ra syscall .Sockaddr ) (rsa syscall .Sockaddr , ret error ) {
switch err := connectFunc (fd .pfd .Sysfd , ra ); err {
case syscall .EINPROGRESS , syscall .EALREADY , syscall .EINTR :
case nil , syscall .EISCONN :
select {
case <- ctx .Done ():
return nil , mapErr (ctx .Err ())
default :
}
if err := fd .pfd .Init (fd .net , true ); err != nil {
return nil , err
}
runtime .KeepAlive (fd )
return nil , nil
case syscall .EINVAL :
if runtime .GOOS == "solaris" || runtime .GOOS == "illumos" {
return nil , nil
}
fallthrough
default :
return nil , os .NewSyscallError ("connect" , err )
}
if err := fd .pfd .Init (fd .net , true ); err != nil {
return nil , err
}
if deadline , hasDeadline := ctx .Deadline (); hasDeadline {
fd .pfd .SetWriteDeadline (deadline )
defer fd .pfd .SetWriteDeadline (noDeadline )
}
ctxDone := ctx .Done ()
if ctxDone != nil {
done := make (chan struct {})
interruptRes := make (chan error )
defer func () {
close (done )
if ctxErr := <-interruptRes ; ctxErr != nil && ret == nil {
ret = mapErr (ctxErr )
fd .Close ()
}
}()
go func () {
select {
case <- ctxDone :
fd .pfd .SetWriteDeadline (aLongTimeAgo )
testHookCanceledDial ()
interruptRes <- ctx .Err ()
case <- done :
interruptRes <- nil
}
}()
}
for {
if err := fd .pfd .WaitWrite (); err != nil {
select {
case <- ctxDone :
return nil , mapErr (ctx .Err ())
default :
}
return nil , err
}
nerr , err := getsockoptIntFunc (fd .pfd .Sysfd , syscall .SOL_SOCKET , syscall .SO_ERROR )
if err != nil {
return nil , os .NewSyscallError ("getsockopt" , err )
}
switch err := syscall .Errno (nerr ); err {
case syscall .EINPROGRESS , syscall .EALREADY , syscall .EINTR :
case syscall .EISCONN :
return nil , nil
case syscall .Errno (0 ):
if rsa , err := syscall .Getpeername (fd .pfd .Sysfd ); err == nil {
return rsa , nil
}
default :
return nil , os .NewSyscallError ("connect" , err )
}
runtime .KeepAlive (fd )
}
}
func (fd *netFD ) accept () (netfd *netFD , err error ) {
d , rsa , errcall , err := fd .pfd .Accept ()
if err != nil {
if errcall != "" {
err = wrapSyscallError (errcall , err )
}
return nil , err
}
if netfd , err = newFD (d , fd .family , fd .sotype , fd .net ); err != nil {
poll .CloseFunc (d )
return nil , err
}
if err = netfd .init (); err != nil {
netfd .Close ()
return nil , err
}
lsa , _ := syscall .Getsockname (netfd .pfd .Sysfd )
netfd .setAddr (netfd .addrFunc ()(lsa ), netfd .addrFunc ()(rsa ))
return netfd , nil
}
func newUnixFile(fd int , name string ) *os .File
func (fd *netFD ) dup () (f *os .File , err error ) {
ns , call , err := fd .pfd .Dup ()
if err != nil {
if call != "" {
err = os .NewSyscallError (call , err )
}
return nil , err
}
return newUnixFile (ns , fd .name ()), nil
}
The pages are generated with Golds v0.7.3-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .