2018-23-01 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / libgo / go / net / unixsock_posix.go
blob945aa031fac6836f0f471d01a962c4959fd4b8a7
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 // +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
7 package net
9 import (
10 "context"
11 "errors"
12 "os"
13 "syscall"
16 func unixSocket(ctx context.Context, net string, laddr, raddr sockaddr, mode string) (*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)
29 switch mode {
30 case "dial":
31 if laddr != nil && laddr.isWildcard() {
32 laddr = nil
34 if raddr != nil && raddr.isWildcard() {
35 raddr = nil
37 if raddr == nil && (sotype != syscall.SOCK_DGRAM || laddr == nil) {
38 return nil, errMissingAddress
40 case "listen":
41 default:
42 return nil, errors.New("unknown mode: " + mode)
45 fd, err := socket(ctx, net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr)
46 if err != nil {
47 return nil, err
49 return fd, nil
52 func sockaddrToUnix(sa syscall.Sockaddr) Addr {
53 if s, ok := sa.(*syscall.SockaddrUnix); ok {
54 return &UnixAddr{Name: s.Name, Net: "unix"}
56 return nil
59 func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
60 if s, ok := sa.(*syscall.SockaddrUnix); ok {
61 return &UnixAddr{Name: s.Name, Net: "unixgram"}
63 return nil
66 func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
67 if s, ok := sa.(*syscall.SockaddrUnix); ok {
68 return &UnixAddr{Name: s.Name, Net: "unixpacket"}
70 return nil
73 func 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")
86 func (a *UnixAddr) family() int {
87 return syscall.AF_UNIX
90 func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
91 if a == nil {
92 return nil, nil
94 return &syscall.SockaddrUnix{Name: a.Name}, nil
97 func (a *UnixAddr) toLocal(net string) sockaddr {
98 return a
101 func (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)}
110 return n, addr, err
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)
116 switch sa := sa.(type) {
117 case *syscall.SockaddrUnix:
118 if sa.Name != "" {
119 addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
122 return
125 func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
126 if c.fd.isConnected {
127 return 0, ErrWriteToConnected
129 if addr == nil {
130 return 0, errMissingAddress
132 if addr.Net != sotypeToNet(c.fd.sotype) {
133 return 0, syscall.EAFNOSUPPORT
135 sa := &syscall.SockaddrUnix{Name: addr.Name}
136 return c.fd.writeTo(b, sa)
139 func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
140 if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
141 return 0, 0, ErrWriteToConnected
143 var sa syscall.Sockaddr
144 if addr != nil {
145 if addr.Net != sotypeToNet(c.fd.sotype) {
146 return 0, 0, syscall.EAFNOSUPPORT
148 sa = &syscall.SockaddrUnix{Name: addr.Name}
150 return c.fd.writeMsg(b, oob, sa)
153 func dialUnix(ctx context.Context, net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
154 fd, err := unixSocket(ctx, net, laddr, raddr, "dial")
155 if err != nil {
156 return nil, err
158 return newUnixConn(fd), nil
161 func (ln *UnixListener) accept() (*UnixConn, error) {
162 fd, err := ln.fd.accept()
163 if err != nil {
164 return nil, err
166 return newUnixConn(fd), nil
169 func (ln *UnixListener) close() error {
170 // The operating system doesn't clean up
171 // the file that announcing created, so
172 // we have to clean it up ourselves.
173 // There's a race here--we can't know for
174 // sure whether someone else has come along
175 // and replaced our socket name already--
176 // but this sequence (remove then close)
177 // is at least compatible with the auto-remove
178 // sequence in ListenUnix. It's only non-Go
179 // programs that can mess us up.
180 // Even if there are racy calls to Close, we want to unlink only for the first one.
181 ln.unlinkOnce.Do(func() {
182 if ln.path[0] != '@' && ln.unlink {
183 syscall.Unlink(ln.path)
186 return ln.fd.Close()
189 func (ln *UnixListener) file() (*os.File, error) {
190 f, err := ln.fd.dup()
191 if err != nil {
192 return nil, err
194 return f, nil
197 // SetUnlinkOnClose sets whether the underlying socket file should be removed
198 // from the file system when the listener is closed.
200 // The default behavior is to unlink the socket file only when package net created it.
201 // That is, when the listener and the underlying socket file were created by a call to
202 // Listen or ListenUnix, then by default closing the listener will remove the socket file.
203 // but if the listener was created by a call to FileListener to use an already existing
204 // socket file, then by default closing the listener will not remove the socket file.
205 func (l *UnixListener) SetUnlinkOnClose(unlink bool) {
206 l.unlink = unlink
209 func listenUnix(ctx context.Context, network string, laddr *UnixAddr) (*UnixListener, error) {
210 fd, err := unixSocket(ctx, network, laddr, nil, "listen")
211 if err != nil {
212 return nil, err
214 return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
217 func listenUnixgram(ctx context.Context, network string, laddr *UnixAddr) (*UnixConn, error) {
218 fd, err := unixSocket(ctx, network, laddr, nil, "listen")
219 if err != nil {
220 return nil, err
222 return newUnixConn(fd), nil