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 unix || js || wasip1 || windows
16 func unixSocket(ctx context.Context, net string, laddr, raddr sockaddr, mode string, ctxCtrlFn func(context.Context, 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, ctxCtrlFn)
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 ctrlCtxFn := sd.Dialer.ControlContext
159 if ctrlCtxFn == nil && sd.Dialer.Control != nil {
160 ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error {
161 return sd.Dialer.Control(network, address, c)
164 fd, err := unixSocket(ctx, sd.network, laddr, raddr, "dial", ctrlCtxFn)
168 return newUnixConn(fd), nil
171 func (ln *UnixListener) accept() (*UnixConn, error) {
172 fd, err := ln.fd.accept()
176 return newUnixConn(fd), nil
179 func (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)
199 func (ln *UnixListener) file() (*os.File, error) {
200 f, err := ln.fd.dup()
207 // SetUnlinkOnClose sets whether the underlying socket file should be removed
208 // from the file system when the listener is closed.
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.
215 func (l *UnixListener) SetUnlinkOnClose(unlink bool) {
219 func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixListener, error) {
220 var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error
221 if sl.ListenConfig.Control != nil {
222 ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error {
223 return sl.ListenConfig.Control(network, address, c)
226 fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", ctrlCtxFn)
230 return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
233 func (sl *sysListener) listenUnixgram(ctx context.Context, laddr *UnixAddr) (*UnixConn, error) {
234 var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error
235 if sl.ListenConfig.Control != nil {
236 ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error {
237 return sl.ListenConfig.Control(network, address, c)
240 fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", ctrlCtxFn)
244 return newUnixConn(fd), nil