server_unix.go 3.2 KB

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