sock.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. # -*- coding: utf-8 -
  2. #
  3. # This file is part of gunicorn released under the MIT license.
  4. # See the NOTICE for more information.
  5. import errno
  6. import os
  7. import socket
  8. import stat
  9. import sys
  10. import time
  11. from gunicorn import util
  12. class BaseSocket(object):
  13. def __init__(self, address, conf, log, fd=None):
  14. self.log = log
  15. self.conf = conf
  16. self.cfg_addr = address
  17. if fd is None:
  18. sock = socket.socket(self.FAMILY, socket.SOCK_STREAM)
  19. bound = False
  20. else:
  21. sock = socket.fromfd(fd, self.FAMILY, socket.SOCK_STREAM)
  22. os.close(fd)
  23. bound = True
  24. self.sock = self.set_options(sock, bound=bound)
  25. def __str__(self):
  26. return "<socket %d>" % self.sock.fileno()
  27. def __getattr__(self, name):
  28. return getattr(self.sock, name)
  29. def set_options(self, sock, bound=False):
  30. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  31. if (self.conf.reuse_port
  32. and hasattr(socket, 'SO_REUSEPORT')): # pragma: no cover
  33. try:
  34. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  35. except socket.error as err:
  36. if err.errno not in (errno.ENOPROTOOPT, errno.EINVAL):
  37. raise
  38. if not bound:
  39. self.bind(sock)
  40. sock.setblocking(0)
  41. # make sure that the socket can be inherited
  42. if hasattr(sock, "set_inheritable"):
  43. sock.set_inheritable(True)
  44. sock.listen(self.conf.backlog)
  45. return sock
  46. def bind(self, sock):
  47. sock.bind(self.cfg_addr)
  48. def close(self):
  49. if self.sock is None:
  50. return
  51. try:
  52. self.sock.close()
  53. except socket.error as e:
  54. self.log.info("Error while closing socket %s", str(e))
  55. self.sock = None
  56. class TCPSocket(BaseSocket):
  57. FAMILY = socket.AF_INET
  58. def __str__(self):
  59. if self.conf.is_ssl:
  60. scheme = "https"
  61. else:
  62. scheme = "http"
  63. addr = self.sock.getsockname()
  64. return "%s://%s:%d" % (scheme, addr[0], addr[1])
  65. def set_options(self, sock, bound=False):
  66. sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
  67. return super().set_options(sock, bound=bound)
  68. class TCP6Socket(TCPSocket):
  69. FAMILY = socket.AF_INET6
  70. def __str__(self):
  71. (host, port, _, _) = self.sock.getsockname()
  72. return "http://[%s]:%d" % (host, port)
  73. class UnixSocket(BaseSocket):
  74. FAMILY = socket.AF_UNIX
  75. def __init__(self, addr, conf, log, fd=None):
  76. if fd is None:
  77. try:
  78. st = os.stat(addr)
  79. except OSError as e:
  80. if e.args[0] != errno.ENOENT:
  81. raise
  82. else:
  83. if stat.S_ISSOCK(st.st_mode):
  84. os.remove(addr)
  85. else:
  86. raise ValueError("%r is not a socket" % addr)
  87. super().__init__(addr, conf, log, fd=fd)
  88. def __str__(self):
  89. return "unix:%s" % self.cfg_addr
  90. def bind(self, sock):
  91. old_umask = os.umask(self.conf.umask)
  92. sock.bind(self.cfg_addr)
  93. util.chown(self.cfg_addr, self.conf.uid, self.conf.gid)
  94. os.umask(old_umask)
  95. def _sock_type(addr):
  96. if isinstance(addr, tuple):
  97. if util.is_ipv6(addr[0]):
  98. sock_type = TCP6Socket
  99. else:
  100. sock_type = TCPSocket
  101. elif isinstance(addr, (str, bytes)):
  102. sock_type = UnixSocket
  103. else:
  104. raise TypeError("Unable to create socket from: %r" % addr)
  105. return sock_type
  106. def create_sockets(conf, log, fds=None):
  107. """
  108. Create a new socket for the configured addresses or file descriptors.
  109. If a configured address is a tuple then a TCP socket is created.
  110. If it is a string, a Unix socket is created. Otherwise, a TypeError is
  111. raised.
  112. """
  113. listeners = []
  114. # get it only once
  115. addr = conf.address
  116. fdaddr = [bind for bind in addr if isinstance(bind, int)]
  117. if fds:
  118. fdaddr += list(fds)
  119. laddr = [bind for bind in addr if not isinstance(bind, int)]
  120. # check ssl config early to raise the error on startup
  121. # only the certfile is needed since it can contains the keyfile
  122. if conf.certfile and not os.path.exists(conf.certfile):
  123. raise ValueError('certfile "%s" does not exist' % conf.certfile)
  124. if conf.keyfile and not os.path.exists(conf.keyfile):
  125. raise ValueError('keyfile "%s" does not exist' % conf.keyfile)
  126. # sockets are already bound
  127. if fdaddr:
  128. for fd in fdaddr:
  129. sock = socket.fromfd(fd, socket.AF_UNIX, socket.SOCK_STREAM)
  130. sock_name = sock.getsockname()
  131. sock_type = _sock_type(sock_name)
  132. listener = sock_type(sock_name, conf, log, fd=fd)
  133. listeners.append(listener)
  134. return listeners
  135. # no sockets is bound, first initialization of gunicorn in this env.
  136. for addr in laddr:
  137. sock_type = _sock_type(addr)
  138. sock = None
  139. for i in range(5):
  140. try:
  141. sock = sock_type(addr, conf, log)
  142. except socket.error as e:
  143. if e.args[0] == errno.EADDRINUSE:
  144. log.error("Connection in use: %s", str(addr))
  145. if e.args[0] == errno.EADDRNOTAVAIL:
  146. log.error("Invalid address: %s", str(addr))
  147. if i < 5:
  148. msg = "connection to {addr} failed: {error}"
  149. log.debug(msg.format(addr=str(addr), error=str(e)))
  150. log.error("Retrying in 1 second.")
  151. time.sleep(1)
  152. else:
  153. break
  154. if sock is None:
  155. log.error("Can't connect to %s", str(addr))
  156. sys.exit(1)
  157. listeners.append(sock)
  158. return listeners
  159. def close_sockets(listeners, unlink=True):
  160. for sock in listeners:
  161. sock_name = sock.getsockname()
  162. sock.close()
  163. if unlink and _sock_type(sock_name) is UnixSocket:
  164. os.unlink(sock_name)