...
Run Format

Source file src/net/unixsock_posix.go

     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	}
   205	

View as plain text