github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/api/server/server_unix.go (about)

     1  // +build freebsd linux
     2  
     3  package server
     4  
     5  import (
     6  	"fmt"
     7  	"net"
     8  	"net/http"
     9  	"strconv"
    10  
    11  	"github.com/docker/docker/daemon"
    12  	"github.com/docker/docker/pkg/sockets"
    13  	"github.com/docker/libnetwork/portallocator"
    14  
    15  	systemdActivation "github.com/coreos/go-systemd/activation"
    16  	systemdDaemon "github.com/coreos/go-systemd/daemon"
    17  )
    18  
    19  // newServer sets up the required serverClosers and does protocol specific checking.
    20  func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
    21  	var (
    22  		err error
    23  		ls  []net.Listener
    24  	)
    25  	switch proto {
    26  	case "fd":
    27  		ls, err = listenFD(addr)
    28  		if err != nil {
    29  			return nil, err
    30  		}
    31  		// We don't want to start serving on these sockets until the
    32  		// daemon is initialized and installed. Otherwise required handlers
    33  		// won't be ready.
    34  		<-s.start
    35  	case "tcp":
    36  		l, err := s.initTCPSocket(addr)
    37  		if err != nil {
    38  			return nil, err
    39  		}
    40  		ls = append(ls, l)
    41  	case "unix":
    42  		l, err := sockets.NewUnixSocket(addr, s.cfg.SocketGroup, s.start)
    43  		if err != nil {
    44  			return nil, err
    45  		}
    46  		ls = append(ls, l)
    47  	default:
    48  		return nil, fmt.Errorf("Invalid protocol format: %q", proto)
    49  	}
    50  	var res []serverCloser
    51  	for _, l := range ls {
    52  		res = append(res, &HTTPServer{
    53  			&http.Server{
    54  				Addr:    addr,
    55  				Handler: s.router,
    56  			},
    57  			l,
    58  		})
    59  	}
    60  	return res, nil
    61  }
    62  
    63  // AcceptConnections allows clients to connect to the API server.
    64  // Referenced Daemon is notified about this server, and waits for the
    65  // daemon acknowledgement before the incoming connections are accepted.
    66  func (s *Server) AcceptConnections(d *daemon.Daemon) {
    67  	// Tell the init daemon we are accepting requests
    68  	s.daemon = d
    69  	s.registerSubRouter()
    70  	go systemdDaemon.SdNotify("READY=1")
    71  	// close the lock so the listeners start accepting connections
    72  	select {
    73  	case <-s.start:
    74  	default:
    75  		close(s.start)
    76  	}
    77  }
    78  
    79  func allocateDaemonPort(addr string) error {
    80  	host, port, err := net.SplitHostPort(addr)
    81  	if err != nil {
    82  		return err
    83  	}
    84  
    85  	intPort, err := strconv.Atoi(port)
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	var hostIPs []net.IP
    91  	if parsedIP := net.ParseIP(host); parsedIP != nil {
    92  		hostIPs = append(hostIPs, parsedIP)
    93  	} else if hostIPs, err = net.LookupIP(host); err != nil {
    94  		return fmt.Errorf("failed to lookup %s address in host specification", host)
    95  	}
    96  
    97  	pa := portallocator.Get()
    98  	for _, hostIP := range hostIPs {
    99  		if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil {
   100  			return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  // listenFD returns the specified socket activated files as a slice of
   107  // net.Listeners or all of the activated files if "*" is given.
   108  func listenFD(addr string) ([]net.Listener, error) {
   109  	// socket activation
   110  	listeners, err := systemdActivation.Listeners(false)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	if listeners == nil || len(listeners) == 0 {
   116  		return nil, fmt.Errorf("No sockets found")
   117  	}
   118  
   119  	// default to all fds just like unix:// and tcp://
   120  	if addr == "" {
   121  		addr = "*"
   122  	}
   123  
   124  	fdNum, _ := strconv.Atoi(addr)
   125  	fdOffset := fdNum - 3
   126  	if (addr != "*") && (len(listeners) < int(fdOffset)+1) {
   127  		return nil, fmt.Errorf("Too few socket activated files passed in")
   128  	}
   129  
   130  	if addr == "*" {
   131  		return listeners, nil
   132  	}
   133  
   134  	return []net.Listener{listeners[fdOffset]}, nil
   135  }