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 }