github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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 (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) { 98 var addr *UnixAddr 99 n, sa, err := c.fd.readFrom(b) 100 switch sa := sa.(type) { 101 case *syscall.SockaddrUnix: 102 if sa.Name != "" { 103 addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)} 104 } 105 } 106 return n, addr, err 107 } 108 109 func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) { 110 var sa syscall.Sockaddr 111 n, oobn, flags, sa, err = c.fd.readMsg(b, oob) 112 switch sa := sa.(type) { 113 case *syscall.SockaddrUnix: 114 if sa.Name != "" { 115 addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)} 116 } 117 } 118 return 119 } 120 121 func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) { 122 if c.fd.isConnected { 123 return 0, ErrWriteToConnected 124 } 125 if addr == nil { 126 return 0, errMissingAddress 127 } 128 if addr.Net != sotypeToNet(c.fd.sotype) { 129 return 0, syscall.EAFNOSUPPORT 130 } 131 sa := &syscall.SockaddrUnix{Name: addr.Name} 132 return c.fd.writeTo(b, sa) 133 } 134 135 func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) { 136 if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected { 137 return 0, 0, ErrWriteToConnected 138 } 139 var sa syscall.Sockaddr 140 if addr != nil { 141 if addr.Net != sotypeToNet(c.fd.sotype) { 142 return 0, 0, syscall.EAFNOSUPPORT 143 } 144 sa = &syscall.SockaddrUnix{Name: addr.Name} 145 } 146 return c.fd.writeMsg(b, oob, sa) 147 } 148 149 func dialUnix(ctx context.Context, net string, laddr, raddr *UnixAddr) (*UnixConn, error) { 150 fd, err := unixSocket(ctx, net, laddr, raddr, "dial") 151 if err != nil { 152 return nil, err 153 } 154 return newUnixConn(fd), nil 155 } 156 157 func (ln *UnixListener) accept() (*UnixConn, error) { 158 fd, err := ln.fd.accept() 159 if err != nil { 160 return nil, err 161 } 162 return newUnixConn(fd), nil 163 } 164 165 func (ln *UnixListener) close() error { 166 // The operating system doesn't clean up 167 // the file that announcing created, so 168 // we have to clean it up ourselves. 169 // There's a race here--we can't know for 170 // sure whether someone else has come along 171 // and replaced our socket name already-- 172 // but this sequence (remove then close) 173 // is at least compatible with the auto-remove 174 // sequence in ListenUnix. It's only non-Go 175 // programs that can mess us up. 176 if ln.path[0] != '@' && ln.unlink { 177 syscall.Unlink(ln.path) 178 } 179 return ln.fd.Close() 180 } 181 182 func (ln *UnixListener) file() (*os.File, error) { 183 f, err := ln.fd.dup() 184 if err != nil { 185 return nil, err 186 } 187 return f, nil 188 } 189 190 func listenUnix(ctx context.Context, network string, laddr *UnixAddr) (*UnixListener, error) { 191 fd, err := unixSocket(ctx, network, laddr, nil, "listen") 192 if err != nil { 193 return nil, err 194 } 195 return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil 196 } 197 198 func listenUnixgram(ctx context.Context, network string, laddr *UnixAddr) (*UnixConn, error) { 199 fd, err := unixSocket(ctx, network, laddr, nil, "listen") 200 if err != nil { 201 return nil, err 202 } 203 return newUnixConn(fd), nil 204 }