1// Copyright 2009 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5//go:build unix || js || wasip1 || windows 6 7package net 8 9import ( 10 "context" 11 "errors" 12 "os" 13 "syscall" 14) 15 16func unixSocket(ctx context.Context, net string, laddr, raddr sockaddr, mode string, ctxCtrlFn func(context.Context, string, string, syscall.RawConn) error) (*netFD, error) { 17 var sotype int 18 switch net { 19 case "unix": 20 sotype = syscall.SOCK_STREAM 21 case "unixgram": 22 sotype = syscall.SOCK_DGRAM 23 case "unixpacket": 24 sotype = syscall.SOCK_SEQPACKET 25 default: 26 return nil, UnknownNetworkError(net) 27 } 28 29 switch mode { 30 case "dial": 31 if laddr != nil && laddr.isWildcard() { 32 laddr = nil 33 } 34 if raddr != nil && raddr.isWildcard() { 35 raddr = nil 36 } 37 if raddr == nil && (sotype != syscall.SOCK_DGRAM || laddr == nil) { 38 return nil, errMissingAddress 39 } 40 case "listen": 41 default: 42 return nil, errors.New("unknown mode: " + mode) 43 } 44 45 fd, err := socket(ctx, net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, ctxCtrlFn) 46 if err != nil { 47 return nil, err 48 } 49 return fd, nil 50} 51 52func sockaddrToUnix(sa syscall.Sockaddr) Addr { 53 if s, ok := sa.(*syscall.SockaddrUnix); ok { 54 return &UnixAddr{Name: s.Name, Net: "unix"} 55 } 56 return nil 57} 58 59func sockaddrToUnixgram(sa syscall.Sockaddr) Addr { 60 if s, ok := sa.(*syscall.SockaddrUnix); ok { 61 return &UnixAddr{Name: s.Name, Net: "unixgram"} 62 } 63 return nil 64} 65 66func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr { 67 if s, ok := sa.(*syscall.SockaddrUnix); ok { 68 return &UnixAddr{Name: s.Name, Net: "unixpacket"} 69 } 70 return nil 71} 72 73func sotypeToNet(sotype int) string { 74 switch sotype { 75 case syscall.SOCK_STREAM: 76 return "unix" 77 case syscall.SOCK_DGRAM: 78 return "unixgram" 79 case syscall.SOCK_SEQPACKET: 80 return "unixpacket" 81 default: 82 panic("sotypeToNet unknown socket type") 83 } 84} 85 86func (a *UnixAddr) family() int { 87 return syscall.AF_UNIX 88} 89 90func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) { 91 if a == nil { 92 return nil, nil 93 } 94 return &syscall.SockaddrUnix{Name: a.Name}, nil 95} 96 97func (a *UnixAddr) toLocal(net string) sockaddr { 98 return a 99} 100 101func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) { 102 var addr *UnixAddr 103 n, sa, err := c.fd.readFrom(b) 104 switch sa := sa.(type) { 105 case *syscall.SockaddrUnix: 106 if sa.Name != "" { 107 addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)} 108 } 109 } 110 return n, addr, err 111} 112 113func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) { 114 var sa syscall.Sockaddr 115 n, oobn, flags, sa, err = c.fd.readMsg(b, oob, readMsgFlags) 116 if readMsgFlags == 0 && err == nil && oobn > 0 { 117 setReadMsgCloseOnExec(oob[:oobn]) 118 } 119 120 switch sa := sa.(type) { 121 case *syscall.SockaddrUnix: 122 if sa.Name != "" { 123 addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)} 124 } 125 } 126 return 127} 128 129func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) { 130 if c.fd.isConnected { 131 return 0, ErrWriteToConnected 132 } 133 if addr == nil { 134 return 0, errMissingAddress 135 } 136 if addr.Net != sotypeToNet(c.fd.sotype) { 137 return 0, syscall.EAFNOSUPPORT 138 } 139 sa := &syscall.SockaddrUnix{Name: addr.Name} 140 return c.fd.writeTo(b, sa) 141} 142 143func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) { 144 if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected { 145 return 0, 0, ErrWriteToConnected 146 } 147 var sa syscall.Sockaddr 148 if addr != nil { 149 if addr.Net != sotypeToNet(c.fd.sotype) { 150 return 0, 0, syscall.EAFNOSUPPORT 151 } 152 sa = &syscall.SockaddrUnix{Name: addr.Name} 153 } 154 return c.fd.writeMsg(b, oob, sa) 155} 156 157func (sd *sysDialer) dialUnix(ctx context.Context, laddr, raddr *UnixAddr) (*UnixConn, error) { 158 ctrlCtxFn := sd.Dialer.ControlContext 159 if ctrlCtxFn == nil && sd.Dialer.Control != nil { 160 ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { 161 return sd.Dialer.Control(network, address, c) 162 } 163 } 164 fd, err := unixSocket(ctx, sd.network, laddr, raddr, "dial", ctrlCtxFn) 165 if err != nil { 166 return nil, err 167 } 168 return newUnixConn(fd), nil 169} 170 171func (ln *UnixListener) accept() (*UnixConn, error) { 172 fd, err := ln.fd.accept() 173 if err != nil { 174 return nil, err 175 } 176 return newUnixConn(fd), nil 177} 178 179func (ln *UnixListener) close() error { 180 // The operating system doesn't clean up 181 // the file that announcing created, so 182 // we have to clean it up ourselves. 183 // There's a race here--we can't know for 184 // sure whether someone else has come along 185 // and replaced our socket name already-- 186 // but this sequence (remove then close) 187 // is at least compatible with the auto-remove 188 // sequence in ListenUnix. It's only non-Go 189 // programs that can mess us up. 190 // Even if there are racy calls to Close, we want to unlink only for the first one. 191 ln.unlinkOnce.Do(func() { 192 if ln.path[0] != '@' && ln.unlink { 193 syscall.Unlink(ln.path) 194 } 195 }) 196 return ln.fd.Close() 197} 198 199func (ln *UnixListener) file() (*os.File, error) { 200 f, err := ln.fd.dup() 201 if err != nil { 202 return nil, err 203 } 204 return f, nil 205} 206 207// SetUnlinkOnClose sets whether the underlying socket file should be removed 208// from the file system when the listener is closed. 209// 210// The default behavior is to unlink the socket file only when package net created it. 211// That is, when the listener and the underlying socket file were created by a call to 212// Listen or ListenUnix, then by default closing the listener will remove the socket file. 213// but if the listener was created by a call to FileListener to use an already existing 214// socket file, then by default closing the listener will not remove the socket file. 215func (l *UnixListener) SetUnlinkOnClose(unlink bool) { 216 l.unlink = unlink 217} 218 219func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixListener, error) { 220 var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error 221 if sl.ListenConfig.Control != nil { 222 ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { 223 return sl.ListenConfig.Control(network, address, c) 224 } 225 } 226 fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", ctrlCtxFn) 227 if err != nil { 228 return nil, err 229 } 230 return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil 231} 232 233func (sl *sysListener) listenUnixgram(ctx context.Context, laddr *UnixAddr) (*UnixConn, error) { 234 var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error 235 if sl.ListenConfig.Control != nil { 236 ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { 237 return sl.ListenConfig.Control(network, address, c) 238 } 239 } 240 fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", ctrlCtxFn) 241 if err != nil { 242 return nil, err 243 } 244 return newUnixConn(fd), nil 245} 246