github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/src/net/unixsock_posix.go (about) 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 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows 6 7 package net 8 9 import ( 10 "context" 11 "errors" 12 "os" 13 "syscall" 14 ) 15 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) 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) 46 if err != nil { 47 return nil, err 48 } 49 return fd, nil 50 } 51 52 func 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 59 func 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 66 func 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 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") 83 } 84 } 85 86 func (a *UnixAddr) family() int { 87 return syscall.AF_UNIX 88 } 89 90 func (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 97 func (a *UnixAddr) toLocal(net string) sockaddr { 98 return a 99 } 100 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)} 108 } 109 } 110 return n, addr, err 111 } 112 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)} 120 } 121 } 122 return 123 } 124 125 func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) { 126 if c.fd.isConnected { 127 return 0, ErrWriteToConnected 128 } 129 if addr == nil { 130 return 0, errMissingAddress 131 } 132 if addr.Net != sotypeToNet(c.fd.sotype) { 133 return 0, syscall.EAFNOSUPPORT 134 } 135 sa := &syscall.SockaddrUnix{Name: addr.Name} 136 return c.fd.writeTo(b, sa) 137 } 138 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 142 } 143 var sa syscall.Sockaddr 144 if addr != nil { 145 if addr.Net != sotypeToNet(c.fd.sotype) { 146 return 0, 0, syscall.EAFNOSUPPORT 147 } 148 sa = &syscall.SockaddrUnix{Name: addr.Name} 149 } 150 return c.fd.writeMsg(b, oob, sa) 151 } 152 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 157 } 158 return newUnixConn(fd), nil 159 } 160 161 func (ln *UnixListener) accept() (*UnixConn, error) { 162 fd, err := ln.fd.accept() 163 if err != nil { 164 return nil, err 165 } 166 return newUnixConn(fd), nil 167 } 168 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) 184 } 185 }) 186 return ln.fd.Close() 187 } 188 189 func (ln *UnixListener) file() (*os.File, error) { 190 f, err := ln.fd.dup() 191 if err != nil { 192 return nil, err 193 } 194 return f, nil 195 } 196 197 // SetUnlinkOnClose sets whether the underlying socket file should be removed 198 // from the file system when the listener is closed. 199 // 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 207 } 208 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 213 } 214 return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil 215 } 216 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 221 } 222 return newUnixConn(fd), nil 223 }