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.
5 //go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
16 func unixSocket(ctx context
.Context
, net
string, laddr
, raddr sockaddr
, mode
string, ctrlFn
func(string, string, syscall
.RawConn
) error
) (*netFD
, error
) {
20 sotype
= syscall
.SOCK_STREAM
22 sotype
= syscall
.SOCK_DGRAM
24 sotype
= syscall
.SOCK_SEQPACKET
26 return nil, UnknownNetworkError(net
)
31 if laddr
!= nil && laddr
.isWildcard() {
34 if raddr
!= nil && raddr
.isWildcard() {
37 if raddr
== nil && (sotype
!= syscall
.SOCK_DGRAM || laddr
== nil) {
38 return nil, errMissingAddress
42 return nil, errors
.New("unknown mode: " + mode
)
45 fd
, err
:= socket(ctx
, net
, syscall
.AF_UNIX
, sotype
, 0, false, laddr
, raddr
, ctrlFn
)
52 func sockaddrToUnix(sa syscall
.Sockaddr
) Addr
{
53 if s
, ok
:= sa
.(*syscall
.SockaddrUnix
); ok
{
54 return &UnixAddr
{Name
: s
.Name
, Net
: "unix"}
59 func sockaddrToUnixgram(sa syscall
.Sockaddr
) Addr
{
60 if s
, ok
:= sa
.(*syscall
.SockaddrUnix
); ok
{
61 return &UnixAddr
{Name
: s
.Name
, Net
: "unixgram"}
66 func sockaddrToUnixpacket(sa syscall
.Sockaddr
) Addr
{
67 if s
, ok
:= sa
.(*syscall
.SockaddrUnix
); ok
{
68 return &UnixAddr
{Name
: s
.Name
, Net
: "unixpacket"}
73 func sotypeToNet(sotype
int) string {
75 case syscall
.SOCK_STREAM
:
77 case syscall
.SOCK_DGRAM
:
79 case syscall
.SOCK_SEQPACKET
:
82 panic("sotypeToNet unknown socket type")
86 func (a
*UnixAddr
) family() int {
87 return syscall
.AF_UNIX
90 func (a
*UnixAddr
) sockaddr(family
int) (syscall
.Sockaddr
, error
) {
94 return &syscall
.SockaddrUnix
{Name
: a
.Name
}, nil
97 func (a
*UnixAddr
) toLocal(net
string) sockaddr
{
101 func (c
*UnixConn
) readFrom(b
[]byte) (int, *UnixAddr
, error
) {
103 n
, sa
, err
:= c
.fd
.readFrom(b
)
104 switch sa
:= sa
.(type) {
105 case *syscall
.SockaddrUnix
:
107 addr
= &UnixAddr
{Name
: sa
.Name
, Net
: sotypeToNet(c
.fd
.sotype
)}
113 func (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
])
120 switch sa
:= sa
.(type) {
121 case *syscall
.SockaddrUnix
:
123 addr
= &UnixAddr
{Name
: sa
.Name
, Net
: sotypeToNet(c
.fd
.sotype
)}
129 func (c
*UnixConn
) writeTo(b
[]byte, addr
*UnixAddr
) (int, error
) {
130 if c
.fd
.isConnected
{
131 return 0, ErrWriteToConnected
134 return 0, errMissingAddress
136 if addr
.Net
!= sotypeToNet(c
.fd
.sotype
) {
137 return 0, syscall
.EAFNOSUPPORT
139 sa
:= &syscall
.SockaddrUnix
{Name
: addr
.Name
}
140 return c
.fd
.writeTo(b
, sa
)
143 func (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
147 var sa syscall
.Sockaddr
149 if addr
.Net
!= sotypeToNet(c
.fd
.sotype
) {
150 return 0, 0, syscall
.EAFNOSUPPORT
152 sa
= &syscall
.SockaddrUnix
{Name
: addr
.Name
}
154 return c
.fd
.writeMsg(b
, oob
, sa
)
157 func (sd
*sysDialer
) dialUnix(ctx context
.Context
, laddr
, raddr
*UnixAddr
) (*UnixConn
, error
) {
158 fd
, err
:= unixSocket(ctx
, sd
.network
, laddr
, raddr
, "dial", sd
.Dialer
.Control
)
162 return newUnixConn(fd
), nil
165 func (ln
*UnixListener
) accept() (*UnixConn
, error
) {
166 fd
, err
:= ln
.fd
.accept()
170 return newUnixConn(fd
), nil
173 func (ln
*UnixListener
) close() error
{
174 // The operating system doesn't clean up
175 // the file that announcing created, so
176 // we have to clean it up ourselves.
177 // There's a race here--we can't know for
178 // sure whether someone else has come along
179 // and replaced our socket name already--
180 // but this sequence (remove then close)
181 // is at least compatible with the auto-remove
182 // sequence in ListenUnix. It's only non-Go
183 // programs that can mess us up.
184 // Even if there are racy calls to Close, we want to unlink only for the first one.
185 ln
.unlinkOnce
.Do(func() {
186 if ln
.path
[0] != '@' && ln
.unlink
{
187 syscall
.Unlink(ln
.path
)
193 func (ln
*UnixListener
) file() (*os
.File
, error
) {
194 f
, err
:= ln
.fd
.dup()
201 // SetUnlinkOnClose sets whether the underlying socket file should be removed
202 // from the file system when the listener is closed.
204 // The default behavior is to unlink the socket file only when package net created it.
205 // That is, when the listener and the underlying socket file were created by a call to
206 // Listen or ListenUnix, then by default closing the listener will remove the socket file.
207 // but if the listener was created by a call to FileListener to use an already existing
208 // socket file, then by default closing the listener will not remove the socket file.
209 func (l
*UnixListener
) SetUnlinkOnClose(unlink
bool) {
213 func (sl
*sysListener
) listenUnix(ctx context
.Context
, laddr
*UnixAddr
) (*UnixListener
, error
) {
214 fd
, err
:= unixSocket(ctx
, sl
.network
, laddr
, nil, "listen", sl
.ListenConfig
.Control
)
218 return &UnixListener
{fd
: fd
, path
: fd
.laddr
.String(), unlink
: true}, nil
221 func (sl
*sysListener
) listenUnixgram(ctx context
.Context
, laddr
*UnixAddr
) (*UnixConn
, error
) {
222 fd
, err
:= unixSocket(ctx
, sl
.network
, laddr
, nil, "listen", sl
.ListenConfig
.Control
)
226 return newUnixConn(fd
), nil