github.com/rsampaio/docker@v0.7.2-0.20150827203920-fdc73cc3fc31/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  // getContainersByNameDownlevel performs processing for pre 1.20 APIs. This
   107  // is only relevant on non-Windows daemons.
   108  func getContainersByNameDownlevel(w http.ResponseWriter, s *Server, namevar string) error {
   109  	containerJSONRaw, err := s.daemon.ContainerInspectPre120(namevar)
   110  	if err != nil {
   111  		return err
   112  	}
   113  	return writeJSON(w, http.StatusOK, containerJSONRaw)
   114  }
   115  
   116  // listenFD returns the specified socket activated files as a slice of
   117  // net.Listeners or all of the activated files if "*" is given.
   118  func listenFD(addr string) ([]net.Listener, error) {
   119  	// socket activation
   120  	listeners, err := systemdActivation.Listeners(false)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	if listeners == nil || len(listeners) == 0 {
   126  		return nil, fmt.Errorf("No sockets found")
   127  	}
   128  
   129  	// default to all fds just like unix:// and tcp://
   130  	if addr == "" {
   131  		addr = "*"
   132  	}
   133  
   134  	fdNum, _ := strconv.Atoi(addr)
   135  	fdOffset := fdNum - 3
   136  	if (addr != "*") && (len(listeners) < int(fdOffset)+1) {
   137  		return nil, fmt.Errorf("Too few socket activated files passed in")
   138  	}
   139  
   140  	if addr == "*" {
   141  		return listeners, nil
   142  	}
   143  
   144  	return []net.Listener{listeners[fdOffset]}, nil
   145  }