mirror of
https://github.com/golang/go
synced 2024-11-23 04:00:03 -07:00
Unix domain socket support, Linux and Darwin.
R=r DELTA=534 (353 added, 99 deleted, 82 changed) OCL=28783 CL=28783
This commit is contained in:
parent
533dfd6291
commit
cc1d4b7e1b
@ -20,6 +20,83 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// Conn is a generic network connection.
|
||||||
|
type Conn interface {
|
||||||
|
// Read blocks until data is ready from the connection
|
||||||
|
// and then reads into b. It returns the number
|
||||||
|
// of bytes read, or 0 if the connection has been closed.
|
||||||
|
Read(b []byte) (n int, err os.Error);
|
||||||
|
|
||||||
|
// Write writes the data in b to the connection.
|
||||||
|
Write(b []byte) (n int, err os.Error);
|
||||||
|
|
||||||
|
// Close closes the connection.
|
||||||
|
Close() os.Error;
|
||||||
|
|
||||||
|
// For packet-based protocols such as UDP,
|
||||||
|
// ReadFrom reads the next packet from the network,
|
||||||
|
// returning the number of bytes read and the remote
|
||||||
|
// address that sent them.
|
||||||
|
ReadFrom(b []byte) (n int, addr string, err os.Error);
|
||||||
|
|
||||||
|
// For packet-based protocols such as UDP,
|
||||||
|
// WriteTo writes the byte buffer b to the network
|
||||||
|
// as a single payload, sending it to the target address.
|
||||||
|
WriteTo(addr string, b []byte) (n int, err os.Error);
|
||||||
|
|
||||||
|
// SetReadBuffer sets the size of the operating system's
|
||||||
|
// receive buffer associated with the connection.
|
||||||
|
SetReadBuffer(bytes int) os.Error;
|
||||||
|
|
||||||
|
// SetReadBuffer sets the size of the operating system's
|
||||||
|
// transmit buffer associated with the connection.
|
||||||
|
SetWriteBuffer(bytes int) os.Error;
|
||||||
|
|
||||||
|
// SetTimeout sets the read and write deadlines associated
|
||||||
|
// with the connection.
|
||||||
|
SetTimeout(nsec int64) os.Error;
|
||||||
|
|
||||||
|
// SetReadTimeout sets the time (in nanoseconds) that
|
||||||
|
// Read will wait for data before returning os.EAGAIN.
|
||||||
|
// Setting nsec == 0 (the default) disables the deadline.
|
||||||
|
SetReadTimeout(nsec int64) os.Error;
|
||||||
|
|
||||||
|
// SetWriteTimeout sets the time (in nanoseconds) that
|
||||||
|
// Write will wait to send its data before returning os.EAGAIN.
|
||||||
|
// Setting nsec == 0 (the default) disables the deadline.
|
||||||
|
// Even if write times out, it may return n > 0, indicating that
|
||||||
|
// some of the data was successfully written.
|
||||||
|
SetWriteTimeout(nsec int64) os.Error;
|
||||||
|
|
||||||
|
// SetLinger sets the behavior of Close() on a connection
|
||||||
|
// which still has data waiting to be sent or to be acknowledged.
|
||||||
|
//
|
||||||
|
// If sec < 0 (the default), Close returns immediately and
|
||||||
|
// the operating system finishes sending the data in the background.
|
||||||
|
//
|
||||||
|
// If sec == 0, Close returns immediately and the operating system
|
||||||
|
// discards any unsent or unacknowledged data.
|
||||||
|
//
|
||||||
|
// If sec > 0, Close blocks for at most sec seconds waiting for
|
||||||
|
// data to be sent and acknowledged.
|
||||||
|
SetLinger(sec int) os.Error;
|
||||||
|
|
||||||
|
// SetReuseAddr sets whether it is okay to reuse addresses
|
||||||
|
// from recent connections that were not properly closed.
|
||||||
|
SetReuseAddr(reuseaddr bool) os.Error;
|
||||||
|
|
||||||
|
// SetDontRoute sets whether outgoing messages should
|
||||||
|
// bypass the system routing tables.
|
||||||
|
SetDontRoute(dontroute bool) os.Error;
|
||||||
|
|
||||||
|
// SetKeepAlive sets whether the operating system should send
|
||||||
|
// keepalive messages on the connection.
|
||||||
|
SetKeepAlive(keepalive bool) os.Error;
|
||||||
|
|
||||||
|
// BindToDevice binds a connection to a particular network device.
|
||||||
|
BindToDevice(dev string) os.Error;
|
||||||
|
}
|
||||||
|
|
||||||
// Should we try to use the IPv4 socket interface if we're
|
// Should we try to use the IPv4 socket interface if we're
|
||||||
// only dealing with IPv4 sockets? As long as the host system
|
// only dealing with IPv4 sockets? As long as the host system
|
||||||
// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
|
// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
|
||||||
@ -160,9 +237,7 @@ func boolint(b bool) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generic socket creation.
|
// Generic socket creation.
|
||||||
func socket(net, laddr, raddr string, f, p, t int64, la, ra *syscall.Sockaddr)
|
func socket(net, laddr, raddr string, f, p, t int64, la, ra *syscall.Sockaddr) (fd *netFD, err os.Error) {
|
||||||
(fd *netFD, err os.Error)
|
|
||||||
{
|
|
||||||
// See ../syscall/exec.go for description of ForkLock.
|
// See ../syscall/exec.go for description of ForkLock.
|
||||||
syscall.ForkLock.RLock();
|
syscall.ForkLock.RLock();
|
||||||
s, e := syscall.Socket(f, p, t);
|
s, e := syscall.Socket(f, p, t);
|
||||||
@ -318,9 +393,7 @@ func (c *connBase) SetLinger(sec int) os.Error {
|
|||||||
|
|
||||||
// Internet sockets (TCP, UDP)
|
// Internet sockets (TCP, UDP)
|
||||||
|
|
||||||
func internetSocket(net, laddr, raddr string, proto int64, mode string)
|
func internetSocket(net, laddr, raddr string, proto int64, mode string) (fd *netFD, err os.Error) {
|
||||||
(fd *netFD, err os.Error)
|
|
||||||
{
|
|
||||||
// Parse addresses (unless they are empty).
|
// Parse addresses (unless they are empty).
|
||||||
var lip, rip IP;
|
var lip, rip IP;
|
||||||
var lport, rport int;
|
var lport, rport int;
|
||||||
@ -388,6 +461,8 @@ func internetSocket(net, laddr, raddr string, proto int64, mode string)
|
|||||||
|
|
||||||
// TCP connections.
|
// TCP connections.
|
||||||
|
|
||||||
|
// ConnTCP is an implementation of the Conn interface
|
||||||
|
// for TCP network connections.
|
||||||
type ConnTCP struct {
|
type ConnTCP struct {
|
||||||
connBase
|
connBase
|
||||||
}
|
}
|
||||||
@ -407,6 +482,8 @@ func newConnTCP(fd *netFD, raddr string) *ConnTCP {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DialTCP is like Dial but can only connect to TCP networks
|
||||||
|
// and returns a ConnTCP structure.
|
||||||
func DialTCP(net, laddr, raddr string) (c *ConnTCP, err os.Error) {
|
func DialTCP(net, laddr, raddr string) (c *ConnTCP, err os.Error) {
|
||||||
if raddr == "" {
|
if raddr == "" {
|
||||||
return nil, MissingAddress
|
return nil, MissingAddress
|
||||||
@ -423,6 +500,8 @@ func DialTCP(net, laddr, raddr string) (c *ConnTCP, err os.Error) {
|
|||||||
|
|
||||||
// TODO(rsc): UDP headers mode
|
// TODO(rsc): UDP headers mode
|
||||||
|
|
||||||
|
// ConnUDP is an implementation of the Conn interface
|
||||||
|
// for UDP network connections.
|
||||||
type ConnUDP struct {
|
type ConnUDP struct {
|
||||||
connBase
|
connBase
|
||||||
}
|
}
|
||||||
@ -434,6 +513,8 @@ func newConnUDP(fd *netFD, raddr string) *ConnUDP {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DialUDP is like Dial but can only connect to UDP networks
|
||||||
|
// and returns a ConnUDP structure.
|
||||||
func DialUDP(net, laddr, raddr string) (c *ConnUDP, err os.Error) {
|
func DialUDP(net, laddr, raddr string) (c *ConnUDP, err os.Error) {
|
||||||
if raddr == "" {
|
if raddr == "" {
|
||||||
return nil, MissingAddress
|
return nil, MissingAddress
|
||||||
@ -450,81 +531,172 @@ func DialUDP(net, laddr, raddr string) (c *ConnUDP, err os.Error) {
|
|||||||
|
|
||||||
// TODO: raw ethernet connections
|
// TODO: raw ethernet connections
|
||||||
|
|
||||||
// A Conn is a generic network connection.
|
|
||||||
type Conn interface {
|
|
||||||
// Read blocks until data is ready from the connection
|
|
||||||
// and then reads into b. It returns the number
|
|
||||||
// of bytes read, or 0 if the connection has been closed.
|
|
||||||
Read(b []byte) (n int, err os.Error);
|
|
||||||
|
|
||||||
// Write writes the data in b to the connection.
|
// Unix domain sockets
|
||||||
Write(b []byte) (n int, err os.Error);
|
|
||||||
|
|
||||||
// Close closes the connection.
|
func unixSocket(net, laddr, raddr string, mode string) (fd *netFD, err os.Error) {
|
||||||
Close() os.Error;
|
var proto int64;
|
||||||
|
switch net {
|
||||||
|
default:
|
||||||
|
return nil, UnknownNetwork;
|
||||||
|
case "unix":
|
||||||
|
proto = syscall.SOCK_STREAM;
|
||||||
|
case "unix-dgram":
|
||||||
|
proto = syscall.SOCK_DGRAM;
|
||||||
|
}
|
||||||
|
|
||||||
// For packet-based protocols such as UDP,
|
var la, ra *syscall.Sockaddr;
|
||||||
// ReadFrom reads the next packet from the network,
|
switch mode {
|
||||||
// returning the number of bytes read and the remote
|
case "dial":
|
||||||
// address that sent them.
|
if laddr != "" {
|
||||||
ReadFrom(b []byte) (n int, addr string, err os.Error);
|
return nil, BadAddress;
|
||||||
|
}
|
||||||
|
if raddr == "" {
|
||||||
|
return nil, MissingAddress;
|
||||||
|
}
|
||||||
|
ra, err = unixToSockaddr(raddr);
|
||||||
|
if err != nil {
|
||||||
|
return nil, err;
|
||||||
|
}
|
||||||
|
|
||||||
// For packet-based protocols such as UDP,
|
case "listen":
|
||||||
// WriteTo writes the byte buffer b to the network
|
if laddr == "" {
|
||||||
// as a single payload, sending it to the target address.
|
return nil, MissingAddress;
|
||||||
WriteTo(addr string, b []byte) (n int, err os.Error);
|
}
|
||||||
|
la, err = unixToSockaddr(laddr);
|
||||||
|
if err != nil {
|
||||||
|
return nil, err;
|
||||||
|
}
|
||||||
|
if raddr != "" {
|
||||||
|
return nil, BadAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetReadBuffer sets the size of the operating system's
|
fd, err = socket(net, laddr, raddr, syscall.AF_UNIX, proto, 0, la, ra);
|
||||||
// receive buffer associated with the connection.
|
return fd, err
|
||||||
SetReadBuffer(bytes int) os.Error;
|
}
|
||||||
|
|
||||||
// SetReadBuffer sets the size of the operating system's
|
// ConnUnix is an implementation of the Conn interface
|
||||||
// transmit buffer associated with the connection.
|
// for connections to Unix domain sockets.
|
||||||
SetWriteBuffer(bytes int) os.Error;
|
type ConnUnix struct {
|
||||||
|
connBase
|
||||||
|
}
|
||||||
|
|
||||||
// SetTimeout sets the read and write deadlines associated
|
func newConnUnix(fd *netFD, raddr string) *ConnUnix {
|
||||||
// with the connection.
|
c := new(ConnUnix);
|
||||||
SetTimeout(nsec int64) os.Error;
|
c.fd = fd;
|
||||||
|
c.raddr = raddr;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
// SetReadTimeout sets the time (in nanoseconds) that
|
// DialUnix is like Dial but can only connect to Unix domain sockets
|
||||||
// Read will wait for data before returning os.EAGAIN.
|
// and returns a ConnUnix structure. The laddr argument must be
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
// the empty string; it is included only to match the signature of
|
||||||
SetReadTimeout(nsec int64) os.Error;
|
// the other dial routines.
|
||||||
|
func DialUnix(net, laddr, raddr string) (c *ConnUnix, err os.Error) {
|
||||||
|
fd, e := unixSocket(net, laddr, raddr, "dial");
|
||||||
|
if e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return newConnUnix(fd, raddr), nil;
|
||||||
|
}
|
||||||
|
|
||||||
// SetWriteTimeout sets the time (in nanoseconds) that
|
// ListenerUnix is a Unix domain socket listener.
|
||||||
// Write will wait to send its data before returning os.EAGAIN.
|
// Clients should typically use variables of type Listener
|
||||||
// Setting nsec == 0 (the default) disables the deadline.
|
// instead of assuming Unix domain sockets.
|
||||||
// Even if write times out, it may return n > 0, indicating that
|
type ListenerUnix struct {
|
||||||
// some of the data was successfully written.
|
fd *netFD;
|
||||||
SetWriteTimeout(nsec int64) os.Error;
|
laddr string
|
||||||
|
}
|
||||||
|
|
||||||
// SetLinger sets the behavior of Close() on a connection
|
// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
|
||||||
// which still has data waiting to be sent or to be acknowledged.
|
// Net can be either "unix" (stream sockets) or "unix-dgram" (datagram sockets).
|
||||||
//
|
func ListenUnix(net, laddr string) (l *ListenerUnix, err os.Error) {
|
||||||
// If sec < 0 (the default), Close returns immediately and
|
fd, e := unixSocket(net, laddr, "", "listen");
|
||||||
// the operating system finishes sending the data in the background.
|
if e != nil {
|
||||||
//
|
// Check for socket ``in use'' but ``refusing connections,''
|
||||||
// If sec == 0, Close returns immediately and the operating system
|
// which means some program created it and exited
|
||||||
// discards any unsent or unacknowledged data.
|
// without unlinking it from the file system.
|
||||||
//
|
// Clean up on that program's behalf and try again.
|
||||||
// If sec > 0, Close blocks for at most sec seconds waiting for
|
// Don't do this for Linux's ``abstract'' sockets, which begin with @.
|
||||||
// data to be sent and acknowledged.
|
if e != os.EADDRINUSE || laddr[0] == '@' {
|
||||||
SetLinger(sec int) os.Error;
|
return nil, e;
|
||||||
|
}
|
||||||
|
fd1, e1 := unixSocket(net, "", laddr, "dial");
|
||||||
|
if e1 == nil {
|
||||||
|
fd1.Close();
|
||||||
|
}
|
||||||
|
if e1 != os.ECONNREFUSED {
|
||||||
|
return nil, e;
|
||||||
|
}
|
||||||
|
syscall.Unlink(laddr);
|
||||||
|
fd1, e1 = unixSocket(net, laddr, "", "listen");
|
||||||
|
if e1 != nil {
|
||||||
|
return nil, e;
|
||||||
|
}
|
||||||
|
fd = fd1;
|
||||||
|
}
|
||||||
|
r, e1 := syscall.Listen(fd.fd, 8); // listenBacklog());
|
||||||
|
if e1 != 0 {
|
||||||
|
syscall.Close(fd.fd);
|
||||||
|
return nil, os.ErrnoToError(e1);
|
||||||
|
}
|
||||||
|
return &ListenerUnix{fd, laddr}, nil;
|
||||||
|
}
|
||||||
|
|
||||||
// SetReuseAddr sets whether it is okay to reuse addresses
|
// AcceptUnix accepts the next incoming call and returns the new connection
|
||||||
// from recent connections that were not properly closed.
|
// and the remote address.
|
||||||
SetReuseAddr(reuseaddr bool) os.Error;
|
func (l *ListenerUnix) AcceptUnix() (c *ConnUnix, raddr string, err os.Error) {
|
||||||
|
if l == nil || l.fd == nil || l.fd.fd < 0 {
|
||||||
|
return nil, "", os.EINVAL
|
||||||
|
}
|
||||||
|
var sa syscall.Sockaddr;
|
||||||
|
fd, e := l.fd.Accept(&sa);
|
||||||
|
if e != nil {
|
||||||
|
return nil, "", e
|
||||||
|
}
|
||||||
|
raddr, err = sockaddrToUnix(&sa);
|
||||||
|
if err != nil {
|
||||||
|
fd.Close();
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
return newConnUnix(fd, raddr), raddr, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetDontRoute sets whether outgoing messages should
|
// Accept implements the Accept method in the Listener interface;
|
||||||
// bypass the system routing tables.
|
// it waits for the next call and returns a generic Conn.
|
||||||
SetDontRoute(dontroute bool) os.Error;
|
func (l *ListenerUnix) Accept() (c Conn, raddr string, err os.Error) {
|
||||||
|
// TODO(rsc): 6g bug prevents saying
|
||||||
|
// c, raddr, err = l.AcceptUnix();
|
||||||
|
// return;
|
||||||
|
c1, r1, e1 := l.AcceptUnix();
|
||||||
|
return c1, r1, e1;
|
||||||
|
}
|
||||||
|
|
||||||
// SetKeepAlive sets whether the operating system should send
|
|
||||||
// keepalive messages on the connection.
|
|
||||||
SetKeepAlive(keepalive bool) os.Error;
|
|
||||||
|
|
||||||
// BindToDevice binds a connection to a particular network device.
|
// Close stops listening on the Unix address.
|
||||||
BindToDevice(dev string) os.Error;
|
// Already accepted connections are not closed.
|
||||||
|
func (l *ListenerUnix) Close() os.Error {
|
||||||
|
if l == nil || l.fd == nil {
|
||||||
|
return os.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
// The operating system doesn't clean up
|
||||||
|
// the file that announcing created, so
|
||||||
|
// we have to clean it up ourselves.
|
||||||
|
// There's a race here--we can't know for
|
||||||
|
// sure whether someone else has come along
|
||||||
|
// and replaced our socket name already--
|
||||||
|
// but this sequence (remove then close)
|
||||||
|
// is at least compatible with the auto-remove
|
||||||
|
// sequence in ListenUnix. It's only non-Go
|
||||||
|
// programs that can mess us up.
|
||||||
|
if l.laddr[0] != '@' {
|
||||||
|
syscall.Unlink(l.laddr);
|
||||||
|
}
|
||||||
|
err := l.fd.Close();
|
||||||
|
l.fd = nil;
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial connects to the remote address raddr on the network net.
|
// Dial connects to the remote address raddr on the network net.
|
||||||
@ -553,6 +725,9 @@ func Dial(net, laddr, raddr string) (c Conn, err os.Error) {
|
|||||||
case "udp", "udp4", "upd6":
|
case "udp", "udp4", "upd6":
|
||||||
c, err := DialUDP(net, laddr, raddr);
|
c, err := DialUDP(net, laddr, raddr);
|
||||||
return c, err;
|
return c, err;
|
||||||
|
case "unix", "unix-dgram":
|
||||||
|
c, err := DialUnix(net, laddr, raddr);
|
||||||
|
return c, err;
|
||||||
/*
|
/*
|
||||||
case "ether":
|
case "ether":
|
||||||
c, err := DialEther(net, laddr, raddr);
|
c, err := DialEther(net, laddr, raddr);
|
||||||
@ -619,7 +794,7 @@ func (l *ListenerTCP) AcceptTCP() (c *ConnTCP, raddr string, err os.Error) {
|
|||||||
return newConnTCP(fd, raddr), raddr, nil
|
return newConnTCP(fd, raddr), raddr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept implements the accept method in the Listener interface;
|
// Accept implements the Accept method in the Listener interface;
|
||||||
// it waits for the next call and returns a generic Conn.
|
// it waits for the next call and returns a generic Conn.
|
||||||
func (l *ListenerTCP) Accept() (c Conn, raddr string, err os.Error) {
|
func (l *ListenerTCP) Accept() (c Conn, raddr string, err os.Error) {
|
||||||
c1, r1, e1 := l.AcceptTCP();
|
c1, r1, e1 := l.AcceptTCP();
|
||||||
@ -639,15 +814,22 @@ func (l *ListenerTCP) Close() os.Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Listen announces on the local network address laddr.
|
// Listen announces on the local network address laddr.
|
||||||
// The network string net must be "tcp", "tcp4", or "tcp6".
|
// The network string net must be "tcp", "tcp4", "tcp6",
|
||||||
|
// "unix", or "unix-dgram".
|
||||||
func Listen(net, laddr string) (l Listener, err os.Error) {
|
func Listen(net, laddr string) (l Listener, err os.Error) {
|
||||||
switch net {
|
switch net {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
l, err := ListenTCP(net, laddr);
|
l, err := ListenTCP(net, laddr);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err;
|
||||||
}
|
}
|
||||||
return l, nil
|
return l, nil;
|
||||||
|
case "unix", "unix-dgram":
|
||||||
|
l, err := ListenUnix(net, laddr);
|
||||||
|
if err != nil {
|
||||||
|
return nil, err;
|
||||||
|
}
|
||||||
|
return l, nil;
|
||||||
/*
|
/*
|
||||||
more here
|
more here
|
||||||
*/
|
*/
|
||||||
|
@ -43,7 +43,6 @@ func v6ToSockaddr(p IP, port int) (sa1 *syscall.Sockaddr, err os.Error) {
|
|||||||
return (*syscall.Sockaddr)(unsafe.Pointer(sa)), nil
|
return (*syscall.Sockaddr)(unsafe.Pointer(sa)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func sockaddrToIP(sa1 *syscall.Sockaddr) (p IP, port int, err os.Error) {
|
func sockaddrToIP(sa1 *syscall.Sockaddr) (p IP, port int, err os.Error) {
|
||||||
switch sa1.Family {
|
switch sa1.Family {
|
||||||
case syscall.AF_INET:
|
case syscall.AF_INET:
|
||||||
@ -70,3 +69,32 @@ func listenBacklog() int64 {
|
|||||||
return syscall.SOMAXCONN
|
return syscall.SOMAXCONN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unixToSockaddr(name string) (sa1 *syscall.Sockaddr, err os.Error) {
|
||||||
|
sa := new(syscall.SockaddrUnix);
|
||||||
|
n := len(name);
|
||||||
|
if n >= len(sa.Path) || n == 0 {
|
||||||
|
return nil, os.EINVAL;
|
||||||
|
}
|
||||||
|
sa.Len = byte(3 + n); // 2 for Family, Len; 1 for NUL
|
||||||
|
sa.Family = syscall.AF_UNIX;
|
||||||
|
for i := 0; i < len(name); i++ {
|
||||||
|
sa.Path[i] = name[i];
|
||||||
|
}
|
||||||
|
return (*syscall.Sockaddr)(unsafe.Pointer(sa)), nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
func sockaddrToUnix(sa1 *syscall.Sockaddr) (string, os.Error) {
|
||||||
|
if sa1.Family != syscall.AF_UNIX || sa1.Len < 3 || sa1.Len > syscall.SizeofSockaddrUnix {
|
||||||
|
return "", os.EINVAL;
|
||||||
|
}
|
||||||
|
sa := (*syscall.SockaddrUnix)(unsafe.Pointer(sa1));
|
||||||
|
n := int(sa.Len) - 3; // subtract leading Family, Len, terminating NUL
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
if sa.Path[i] == 0 {
|
||||||
|
// found early NUL; assume Len is overestimating
|
||||||
|
n = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(sa.Path[0:n]), nil;
|
||||||
|
}
|
||||||
|
@ -77,3 +77,47 @@ func listenBacklog() int64 {
|
|||||||
return syscall.SOMAXCONN
|
return syscall.SOMAXCONN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unixToSockaddr(name string) (sa1 *syscall.Sockaddr, err os.Error) {
|
||||||
|
sa := new(syscall.SockaddrUnix);
|
||||||
|
n := len(name);
|
||||||
|
if n >= len(sa.Path) || n == 0 {
|
||||||
|
return nil, os.EINVAL;
|
||||||
|
}
|
||||||
|
sa.Family = syscall.AF_UNIX;
|
||||||
|
for i := 0; i < len(name); i++ {
|
||||||
|
sa.Path[i] = name[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case: @ in first position indicates
|
||||||
|
// an abstract socket, which has no file system
|
||||||
|
// representation and starts with a NUL byte
|
||||||
|
// when talking to the kernel about it.
|
||||||
|
if sa.Path[0] == '@' {
|
||||||
|
sa.Path[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*syscall.Sockaddr)(unsafe.Pointer(sa)), nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
func sockaddrToUnix(sa1 *syscall.Sockaddr) (string, os.Error) {
|
||||||
|
if sa1.Family != syscall.AF_UNIX {
|
||||||
|
return "", os.EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sa := (*syscall.SockaddrUnix)(unsafe.Pointer(sa1));
|
||||||
|
|
||||||
|
// @ special case (see comment in unixToSockaddr).
|
||||||
|
if sa.Path[0] == 0 {
|
||||||
|
// Not friendly to overwrite in place but
|
||||||
|
// okay in an internal function.
|
||||||
|
// The caller doesn't care if we do.
|
||||||
|
sa.Path[0] = '@';
|
||||||
|
}
|
||||||
|
|
||||||
|
// count length of path
|
||||||
|
n := 0;
|
||||||
|
for n < len(sa.Path) && sa.Path[n] != 0 {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return string(sa.Path[0:n]), nil;
|
||||||
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"io";
|
"io";
|
||||||
"net";
|
"net";
|
||||||
"os";
|
"os";
|
||||||
|
"syscall";
|
||||||
"testing";
|
"testing";
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -83,3 +84,10 @@ func TestTcpServer(t *testing.T) {
|
|||||||
doTest(t, "tcp", "0.0.0.0:9997", "[::ffff:127.0.0.1]:9997");
|
doTest(t, "tcp", "0.0.0.0:9997", "[::ffff:127.0.0.1]:9997");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnixServer(t *testing.T) {
|
||||||
|
doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net");
|
||||||
|
if syscall.OS == "linux" {
|
||||||
|
// Test abstract unix domain socket, a Linux-ism
|
||||||
|
doTest(t, "unix", "@gotest/net", "@gotest/net");
|
||||||
|
}
|
||||||
|
}
|
@ -77,5 +77,7 @@ var (
|
|||||||
EAGAIN Error = Errno(syscall.EAGAIN);
|
EAGAIN Error = Errno(syscall.EAGAIN);
|
||||||
EDOM Error = Errno(syscall.EDOM);
|
EDOM Error = Errno(syscall.EDOM);
|
||||||
ERANGE Error = Errno(syscall.ERANGE);
|
ERANGE Error = Errno(syscall.ERANGE);
|
||||||
|
EADDRINUSE Error = Errno(syscall.EADDRINUSE);
|
||||||
|
ECONNREFUSED Error = Errno(syscall.ECONNREFUSED);
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,11 +16,6 @@ import (
|
|||||||
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
||||||
var SocketDisableIPv6 bool
|
var SocketDisableIPv6 bool
|
||||||
|
|
||||||
func SockaddrToSockaddrInet4(s *Sockaddr) *SockaddrInet4;
|
|
||||||
func SockaddrToSockaddrInet6(s *Sockaddr) *SockaddrInet6;
|
|
||||||
func SockaddrInet4ToSockaddr(s *SockaddrInet4) *Sockaddr;
|
|
||||||
func SockaddrInet6ToSockaddr(s *SockaddrInet6) *Sockaddr;
|
|
||||||
|
|
||||||
func Socket(domain, proto, typ int64) (ret int64, err int64) {
|
func Socket(domain, proto, typ int64) (ret int64, err int64) {
|
||||||
if domain == AF_INET6 && SocketDisableIPv6 {
|
if domain == AF_INET6 && SocketDisableIPv6 {
|
||||||
return -1, EAFNOSUPPORT
|
return -1, EAFNOSUPPORT
|
||||||
|
@ -16,11 +16,6 @@ import (
|
|||||||
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
||||||
var SocketDisableIPv6 bool
|
var SocketDisableIPv6 bool
|
||||||
|
|
||||||
func SockaddrToSockaddrInet4(s *Sockaddr) *SockaddrInet4;
|
|
||||||
func SockaddrToSockaddrInet6(s *Sockaddr) *SockaddrInet6;
|
|
||||||
func SockaddrInet4ToSockaddr(s *SockaddrInet4) *Sockaddr;
|
|
||||||
func SockaddrInet6ToSockaddr(s *SockaddrInet6) *Sockaddr;
|
|
||||||
|
|
||||||
func saLen(s *Sockaddr) int64 {
|
func saLen(s *Sockaddr) int64 {
|
||||||
switch s.Family {
|
switch s.Family {
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
|
Loading…
Reference in New Issue
Block a user