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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
16 func unixSocket(net
string, laddr
, raddr sockaddr
, mode
string, deadline time
.Time
) (*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
)
46 if sotype
== syscall
.SOCK_DGRAM
{
47 f
= sockaddrToUnixgram
48 } else if sotype
== syscall
.SOCK_SEQPACKET
{
49 f
= sockaddrToUnixpacket
52 fd
, err
:= socket(net
, syscall
.AF_UNIX
, sotype
, 0, false, laddr
, raddr
, deadline
, f
)
59 func sockaddrToUnix(sa syscall
.Sockaddr
) Addr
{
60 if s
, ok
:= sa
.(*syscall
.SockaddrUnix
); ok
{
61 return &UnixAddr
{Name
: s
.Name
, Net
: "unix"}
66 func sockaddrToUnixgram(sa syscall
.Sockaddr
) Addr
{
67 if s
, ok
:= sa
.(*syscall
.SockaddrUnix
); ok
{
68 return &UnixAddr
{Name
: s
.Name
, Net
: "unixgram"}
73 func sockaddrToUnixpacket(sa syscall
.Sockaddr
) Addr
{
74 if s
, ok
:= sa
.(*syscall
.SockaddrUnix
); ok
{
75 return &UnixAddr
{Name
: s
.Name
, Net
: "unixpacket"}
80 func sotypeToNet(sotype
int) string {
82 case syscall
.SOCK_STREAM
:
84 case syscall
.SOCK_DGRAM
:
86 case syscall
.SOCK_SEQPACKET
:
89 panic("sotypeToNet unknown socket type")
93 func (a
*UnixAddr
) family() int {
94 return syscall
.AF_UNIX
97 func (a
*UnixAddr
) isWildcard() bool {
98 return a
== nil || a
.Name
== ""
101 func (a
*UnixAddr
) sockaddr(family
int) (syscall
.Sockaddr
, error
) {
105 return &syscall
.SockaddrUnix
{Name
: a
.Name
}, nil
108 // UnixConn is an implementation of the Conn interface for connections
109 // to Unix domain sockets.
110 type UnixConn
struct {
114 func newUnixConn(fd
*netFD
) *UnixConn
{ return &UnixConn
{conn
{fd
}} }
116 // ReadFromUnix reads a packet from c, copying the payload into b. It
117 // returns the number of bytes copied into b and the source address of
120 // ReadFromUnix can be made to time out and return an error with
121 // Timeout() == true after a fixed time limit; see SetDeadline and
123 func (c
*UnixConn
) ReadFromUnix(b
[]byte) (n
int, addr
*UnixAddr
, err error
) {
125 return 0, nil, syscall
.EINVAL
127 n
, sa
, err
:= c
.fd
.readFrom(b
)
128 switch sa
:= sa
.(type) {
129 case *syscall
.SockaddrUnix
:
131 addr
= &UnixAddr
{Name
: sa
.Name
, Net
: sotypeToNet(c
.fd
.sotype
)}
137 // ReadFrom implements the PacketConn ReadFrom method.
138 func (c
*UnixConn
) ReadFrom(b
[]byte) (int, Addr
, error
) {
140 return 0, nil, syscall
.EINVAL
142 n
, addr
, err
:= c
.ReadFromUnix(b
)
143 return n
, addr
.toAddr(), err
146 // ReadMsgUnix reads a packet from c, copying the payload into b and
147 // the associated out-of-band data into oob. It returns the number of
148 // bytes copied into b, the number of bytes copied into oob, the flags
149 // that were set on the packet, and the source address of the packet.
150 func (c
*UnixConn
) ReadMsgUnix(b
, oob
[]byte) (n
, oobn
, flags
int, addr
*UnixAddr
, err error
) {
152 return 0, 0, 0, nil, syscall
.EINVAL
154 n
, oobn
, flags
, sa
, err
:= c
.fd
.readMsg(b
, oob
)
155 switch sa
:= sa
.(type) {
156 case *syscall
.SockaddrUnix
:
158 addr
= &UnixAddr
{Name
: sa
.Name
, Net
: sotypeToNet(c
.fd
.sotype
)}
164 // WriteToUnix writes a packet to addr via c, copying the payload from b.
166 // WriteToUnix can be made to time out and return an error with
167 // Timeout() == true after a fixed time limit; see SetDeadline and
168 // SetWriteDeadline. On packet-oriented connections, write timeouts
170 func (c
*UnixConn
) WriteToUnix(b
[]byte, addr
*UnixAddr
) (n
int, err error
) {
172 return 0, syscall
.EINVAL
174 if c
.fd
.isConnected
{
175 return 0, &OpError
{Op
: "write", Net
: c
.fd
.net
, Addr
: addr
, Err
: ErrWriteToConnected
}
178 return 0, &OpError
{Op
: "write", Net
: c
.fd
.net
, Addr
: nil, Err
: errMissingAddress
}
180 if addr
.Net
!= sotypeToNet(c
.fd
.sotype
) {
181 return 0, syscall
.EAFNOSUPPORT
183 sa
:= &syscall
.SockaddrUnix
{Name
: addr
.Name
}
184 return c
.fd
.writeTo(b
, sa
)
187 // WriteTo implements the PacketConn WriteTo method.
188 func (c
*UnixConn
) WriteTo(b
[]byte, addr Addr
) (n
int, err error
) {
190 return 0, syscall
.EINVAL
192 a
, ok
:= addr
.(*UnixAddr
)
194 return 0, &OpError
{"write", c
.fd
.net
, addr
, syscall
.EINVAL
}
196 return c
.WriteToUnix(b
, a
)
199 // WriteMsgUnix writes a packet to addr via c, copying the payload
200 // from b and the associated out-of-band data from oob. It returns
201 // the number of payload and out-of-band bytes written.
202 func (c
*UnixConn
) WriteMsgUnix(b
, oob
[]byte, addr
*UnixAddr
) (n
, oobn
int, err error
) {
204 return 0, 0, syscall
.EINVAL
206 if c
.fd
.sotype
== syscall
.SOCK_DGRAM
&& c
.fd
.isConnected
{
207 return 0, 0, &OpError
{Op
: "write", Net
: c
.fd
.net
, Addr
: addr
, Err
: ErrWriteToConnected
}
210 if addr
.Net
!= sotypeToNet(c
.fd
.sotype
) {
211 return 0, 0, syscall
.EAFNOSUPPORT
213 sa
:= &syscall
.SockaddrUnix
{Name
: addr
.Name
}
214 return c
.fd
.writeMsg(b
, oob
, sa
)
216 return c
.fd
.writeMsg(b
, oob
, nil)
219 // CloseRead shuts down the reading side of the Unix domain connection.
220 // Most callers should just use Close.
221 func (c
*UnixConn
) CloseRead() error
{
223 return syscall
.EINVAL
225 return c
.fd
.closeRead()
228 // CloseWrite shuts down the writing side of the Unix domain connection.
229 // Most callers should just use Close.
230 func (c
*UnixConn
) CloseWrite() error
{
232 return syscall
.EINVAL
234 return c
.fd
.closeWrite()
237 // DialUnix connects to the remote address raddr on the network net,
238 // which must be "unix", "unixgram" or "unixpacket". If laddr is not
239 // nil, it is used as the local address for the connection.
240 func DialUnix(net
string, laddr
, raddr
*UnixAddr
) (*UnixConn
, error
) {
242 case "unix", "unixgram", "unixpacket":
244 return nil, &OpError
{Op
: "dial", Net
: net
, Addr
: raddr
, Err
: UnknownNetworkError(net
)}
246 return dialUnix(net
, laddr
, raddr
, noDeadline
)
249 func dialUnix(net
string, laddr
, raddr
*UnixAddr
, deadline time
.Time
) (*UnixConn
, error
) {
250 fd
, err
:= unixSocket(net
, laddr
, raddr
, "dial", deadline
)
252 return nil, &OpError
{Op
: "dial", Net
: net
, Addr
: raddr
, Err
: err
}
254 return newUnixConn(fd
), nil
257 // UnixListener is a Unix domain socket listener. Clients should
258 // typically use variables of type Listener instead of assuming Unix
260 type UnixListener
struct {
265 // ListenUnix announces on the Unix domain socket laddr and returns a
266 // Unix listener. The network net must be "unix" or "unixpacket".
267 func ListenUnix(net
string, laddr
*UnixAddr
) (*UnixListener
, error
) {
269 case "unix", "unixpacket":
271 return nil, &OpError
{Op
: "listen", Net
: net
, Addr
: laddr
, Err
: UnknownNetworkError(net
)}
274 return nil, &OpError
{Op
: "listen", Net
: net
, Addr
: nil, Err
: errMissingAddress
}
276 fd
, err
:= unixSocket(net
, laddr
, nil, "listen", noDeadline
)
278 return nil, &OpError
{Op
: "listen", Net
: net
, Addr
: laddr
, Err
: err
}
280 return &UnixListener
{fd
, fd
.laddr
.String()}, nil
283 // AcceptUnix accepts the next incoming call and returns the new
285 func (l
*UnixListener
) AcceptUnix() (*UnixConn
, error
) {
286 if l
== nil || l
.fd
== nil {
287 return nil, syscall
.EINVAL
289 toAddr
:= sockaddrToUnix
290 if l
.fd
.sotype
== syscall
.SOCK_SEQPACKET
{
291 toAddr
= sockaddrToUnixpacket
293 fd
, err
:= l
.fd
.accept(toAddr
)
301 // Accept implements the Accept method in the Listener interface; it
302 // waits for the next call and returns a generic Conn.
303 func (l
*UnixListener
) Accept() (c Conn
, err error
) {
304 c1
, err
:= l
.AcceptUnix()
311 // Close stops listening on the Unix address. Already accepted
312 // connections are not closed.
313 func (l
*UnixListener
) Close() error
{
314 if l
== nil || l
.fd
== nil {
315 return syscall
.EINVAL
318 // The operating system doesn't clean up
319 // the file that announcing created, so
320 // we have to clean it up ourselves.
321 // There's a race here--we can't know for
322 // sure whether someone else has come along
323 // and replaced our socket name already--
324 // but this sequence (remove then close)
325 // is at least compatible with the auto-remove
326 // sequence in ListenUnix. It's only non-Go
327 // programs that can mess us up.
328 if l
.path
[0] != '@' {
329 syscall
.Unlink(l
.path
)
334 // Addr returns the listener's network address.
335 func (l
*UnixListener
) Addr() Addr
{ return l
.fd
.laddr
}
337 // SetDeadline sets the deadline associated with the listener.
338 // A zero time value disables the deadline.
339 func (l
*UnixListener
) SetDeadline(t time
.Time
) (err error
) {
340 if l
== nil || l
.fd
== nil {
341 return syscall
.EINVAL
343 return l
.fd
.setDeadline(t
)
346 // File returns a copy of the underlying os.File, set to blocking
347 // mode. It is the caller's responsibility to close f when finished.
348 // Closing l does not affect f, and closing f does not affect l.
350 // The returned os.File's file descriptor is different from the
351 // connection's. Attempting to change properties of the original
352 // using this duplicate may or may not have the desired effect.
353 func (l
*UnixListener
) File() (f
*os
.File
, err error
) { return l
.fd
.dup() }
355 // ListenUnixgram listens for incoming Unix datagram packets addressed
356 // to the local address laddr. The network net must be "unixgram".
357 // The returned connection's ReadFrom and WriteTo methods can be used
358 // to receive and send packets with per-packet addressing.
359 func ListenUnixgram(net
string, laddr
*UnixAddr
) (*UnixConn
, error
) {
363 return nil, &OpError
{Op
: "listen", Net
: net
, Addr
: laddr
, Err
: UnknownNetworkError(net
)}
366 return nil, &OpError
{Op
: "listen", Net
: net
, Addr
: nil, Err
: errMissingAddress
}
368 fd
, err
:= unixSocket(net
, laddr
, nil, "listen", noDeadline
)
370 return nil, &OpError
{Op
: "listen", Net
: net
, Addr
: laddr
, Err
: err
}
372 return newUnixConn(fd
), nil