Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sock.py 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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 fcntl
  7. import os
  8. import socket
  9. import stat
  10. import sys
  11. import time
  12. from gunicorn import util
  13. from gunicorn.six import string_types
  14. SD_LISTEN_FDS_START = 3
  15. class BaseSocket(object):
  16. def __init__(self, address, conf, log, fd=None):
  17. self.log = log
  18. self.conf = conf
  19. self.cfg_addr = address
  20. if fd is None:
  21. sock = socket.socket(self.FAMILY, socket.SOCK_STREAM)
  22. else:
  23. sock = socket.fromfd(fd, self.FAMILY, socket.SOCK_STREAM)
  24. self.sock = self.set_options(sock, bound=(fd is not None))
  25. def __str__(self, name):
  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 not bound:
  32. self.bind(sock)
  33. sock.setblocking(0)
  34. # make sure that the socket can be inherited
  35. if hasattr(sock, "set_inheritable"):
  36. sock.set_inheritable(True)
  37. sock.listen(self.conf.backlog)
  38. return sock
  39. def bind(self, sock):
  40. sock.bind(self.cfg_addr)
  41. def close(self):
  42. if self.sock is None:
  43. return
  44. try:
  45. self.sock.close()
  46. except socket.error as e:
  47. self.log.info("Error while closing socket %s", str(e))
  48. self.sock = None
  49. class TCPSocket(BaseSocket):
  50. FAMILY = socket.AF_INET
  51. def __str__(self):
  52. if self.conf.is_ssl:
  53. scheme = "https"
  54. else:
  55. scheme = "http"
  56. addr = self.sock.getsockname()
  57. return "%s://%s:%d" % (scheme, addr[0], addr[1])
  58. def set_options(self, sock, bound=False):
  59. sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
  60. return super(TCPSocket, self).set_options(sock, bound=bound)
  61. class TCP6Socket(TCPSocket):
  62. FAMILY = socket.AF_INET6
  63. def __str__(self):
  64. (host, port, fl, sc) = self.sock.getsockname()
  65. return "http://[%s]:%d" % (host, port)
  66. class UnixSocket(BaseSocket):
  67. FAMILY = socket.AF_UNIX
  68. def __init__(self, addr, conf, log, fd=None):
  69. if fd is None:
  70. try:
  71. st = os.stat(addr)
  72. except OSError as e:
  73. if e.args[0] != errno.ENOENT:
  74. raise
  75. else:
  76. if stat.S_ISSOCK(st.st_mode):
  77. os.remove(addr)
  78. else:
  79. raise ValueError("%r is not a socket" % addr)
  80. super(UnixSocket, self).__init__(addr, conf, log, fd=fd)
  81. def __str__(self):
  82. return "unix:%s" % self.cfg_addr
  83. def bind(self, sock):
  84. old_umask = os.umask(self.conf.umask)
  85. sock.bind(self.cfg_addr)
  86. util.chown(self.cfg_addr, self.conf.uid, self.conf.gid)
  87. os.umask(old_umask)
  88. def close(self):
  89. os.unlink(self.cfg_addr)
  90. super(UnixSocket, self).close()
  91. def _sock_type(addr):
  92. if isinstance(addr, tuple):
  93. if util.is_ipv6(addr[0]):
  94. sock_type = TCP6Socket
  95. else:
  96. sock_type = TCPSocket
  97. elif isinstance(addr, string_types):
  98. sock_type = UnixSocket
  99. else:
  100. raise TypeError("Unable to create socket from: %r" % addr)
  101. return sock_type
  102. def create_sockets(conf, log):
  103. """
  104. Create a new socket for the given address. If the
  105. address is a tuple, a TCP socket is created. If it
  106. is a string, a Unix socket is created. Otherwise
  107. a TypeError is raised.
  108. """
  109. # Systemd support, use the sockets managed by systemd and passed to
  110. # gunicorn.
  111. # http://www.freedesktop.org/software/systemd/man/systemd.socket.html
  112. listeners = []
  113. if ('LISTEN_PID' in os.environ
  114. and int(os.environ.get('LISTEN_PID')) == os.getpid()):
  115. for i in range(int(os.environ.get('LISTEN_FDS', 0))):
  116. fd = i + SD_LISTEN_FDS_START
  117. try:
  118. sock = socket.fromfd(fd, socket.AF_UNIX, socket.SOCK_STREAM)
  119. sockname = sock.getsockname()
  120. if isinstance(sockname, str) and sockname.startswith('/'):
  121. listeners.append(UnixSocket(sockname, conf, log, fd=fd))
  122. elif len(sockname) == 2 and '.' in sockname[0]:
  123. listeners.append(TCPSocket("%s:%s" % sockname, conf, log,
  124. fd=fd))
  125. elif len(sockname) == 4 and ':' in sockname[0]:
  126. listeners.append(TCP6Socket("[%s]:%s" % sockname[:2], conf,
  127. log, fd=fd))
  128. except socket.error:
  129. pass
  130. del os.environ['LISTEN_PID'], os.environ['LISTEN_FDS']
  131. if listeners:
  132. log.debug('Socket activation sockets: %s',
  133. ",".join([str(l) for l in listeners]))
  134. return listeners
  135. # get it only once
  136. laddr = conf.address
  137. # check ssl config early to raise the error on startup
  138. # only the certfile is needed since it can contains the keyfile
  139. if conf.certfile and not os.path.exists(conf.certfile):
  140. raise ValueError('certfile "%s" does not exist' % conf.certfile)
  141. if conf.keyfile and not os.path.exists(conf.keyfile):
  142. raise ValueError('keyfile "%s" does not exist' % conf.keyfile)
  143. # sockets are already bound
  144. if 'GUNICORN_FD' in os.environ:
  145. fds = os.environ.pop('GUNICORN_FD').split(',')
  146. for i, fd in enumerate(fds):
  147. fd = int(fd)
  148. addr = laddr[i]
  149. sock_type = _sock_type(addr)
  150. try:
  151. listeners.append(sock_type(addr, conf, log, fd=fd))
  152. except socket.error as e:
  153. if e.args[0] == errno.ENOTCONN:
  154. log.error("GUNICORN_FD should refer to an open socket.")
  155. else:
  156. raise
  157. return listeners
  158. # no sockets is bound, first initialization of gunicorn in this env.
  159. for addr in laddr:
  160. sock_type = _sock_type(addr)
  161. # If we fail to create a socket from GUNICORN_FD
  162. # we fall through and try and open the socket
  163. # normally.
  164. sock = None
  165. for i in range(5):
  166. try:
  167. sock = sock_type(addr, conf, log)
  168. except socket.error as e:
  169. if e.args[0] == errno.EADDRINUSE:
  170. log.error("Connection in use: %s", str(addr))
  171. if e.args[0] == errno.EADDRNOTAVAIL:
  172. log.error("Invalid address: %s", str(addr))
  173. if i < 5:
  174. msg = "connection to {addr} failed: {error}"
  175. log.debug(msg.format(addr=str(addr), error=str(e)))
  176. log.error("Retrying in 1 second.")
  177. time.sleep(1)
  178. else:
  179. break
  180. if sock is None:
  181. log.error("Can't connect to %s", str(addr))
  182. sys.exit(1)
  183. listeners.append(sock)
  184. return listeners