forked from benoitc/gunicorn
/
sock.py
144 lines (115 loc) · 3.89 KB
/
sock.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# -*- coding: utf-8 -
#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
import errno
import os
import socket
import sys
import time
from gunicorn import util
class BaseSocket(object):
def __init__(self, conf, log, fd=None):
self.log = log
self.conf = conf
self.address = conf.address
if fd is None:
sock = socket.socket(self.FAMILY, socket.SOCK_STREAM)
else:
sock = socket.fromfd(fd, self.FAMILY, socket.SOCK_STREAM)
self.sock = self.set_options(sock, bound=(fd is not None))
def __str__(self, name):
return "<socket %d>" % self.sock.fileno()
def __getattr__(self, name):
return getattr(self.sock, name)
def set_options(self, sock, bound=False):
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if not bound:
self.bind(sock)
sock.setblocking(0)
sock.listen(self.conf.backlog)
return sock
def bind(self, sock):
sock.bind(self.address)
def close(self):
try:
self.sock.close()
except socket.error, e:
self.log.info("Error while closing socket %s", str(e))
time.sleep(0.3)
del self.sock
class TCPSocket(BaseSocket):
FAMILY = socket.AF_INET
def __str__(self):
return "http://%s:%d" % self.sock.getsockname()
def set_options(self, sock, bound=False):
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
return super(TCPSocket, self).set_options(sock, bound=bound)
class TCP6Socket(TCPSocket):
FAMILY = socket.AF_INET6
def __str__(self):
(host, port, fl, sc) = self.sock.getsockname()
return "http://[%s]:%d" % (host, port)
class UnixSocket(BaseSocket):
FAMILY = socket.AF_UNIX
def __init__(self, conf, log, fd=None):
if fd is None:
try:
os.remove(conf.address)
except OSError:
pass
super(UnixSocket, self).__init__(conf, log, fd=fd)
def __str__(self):
return "unix:%s" % self.address
def bind(self, sock):
old_umask = os.umask(self.conf.umask)
sock.bind(self.address)
util.chown(self.address, self.conf.uid, self.conf.gid)
os.umask(old_umask)
def close(self):
super(UnixSocket, self).close()
os.unlink(self.address)
def create_socket(conf, log):
"""
Create a new socket for the given address. If the
address is a tuple, a TCP socket is created. If it
is a string, a Unix socket is created. Otherwise
a TypeError is raised.
"""
# get it only once
addr = conf.address
if isinstance(addr, tuple):
if util.is_ipv6(addr[0]):
sock_type = TCP6Socket
else:
sock_type = TCPSocket
elif isinstance(addr, basestring):
sock_type = UnixSocket
else:
raise TypeError("Unable to create socket from: %r" % addr)
if 'GUNICORN_FD' in os.environ:
fd = int(os.environ.pop('GUNICORN_FD'))
try:
return sock_type(conf, log, fd=fd)
except socket.error, e:
if e[0] == errno.ENOTCONN:
log.error("GUNICORN_FD should refer to an open socket.")
else:
raise
# If we fail to create a socket from GUNICORN_FD
# we fall through and try and open the socket
# normally.
for i in range(5):
try:
return sock_type(conf, log)
except socket.error, e:
if e[0] == errno.EADDRINUSE:
log.error("Connection in use: %s", str(addr))
if e[0] == errno.EADDRNOTAVAIL:
log.error("Invalid address: %s", str(addr))
sys.exit(1)
if i < 5:
log.error("Retrying in 1 second.")
time.sleep(1)
log.error("Can't connect to %s", str(addr))
sys.exit(1)