bpo-37027: Return a proxy socket object from transp.get_extra_info('s… · python/cpython@8cd5165

1+

import socket

2+

import warnings

3+4+5+

class TransportSocket:

6+7+

"""A socket-like wrapper for exposing real transport sockets.

8+9+

These objects can be safely returned by APIs like

10+

`transport.get_extra_info('socket')`. All potentially disruptive

11+

operations (like "socket.close()") are banned.

12+

"""

13+14+

__slots__ = ('_sock',)

15+16+

def __init__(self, sock: socket.socket):

17+

self._sock = sock

18+19+

def _na(self, what):

20+

warnings.warn(

21+

f"Using {what} on sockets returned from get_extra_info('socket') "

22+

f"will be prohibited in asyncio 3.9. Please report your use case "

23+

f"to bugs.python.org.",

24+

DeprecationWarning, source=self)

25+26+

@property

27+

def family(self):

28+

return self._sock.family

29+30+

@property

31+

def type(self):

32+

return self._sock.type

33+34+

@property

35+

def proto(self):

36+

return self._sock.proto

37+38+

def __repr__(self):

39+

s = (

40+

f"<asyncio.TransportSocket fd={self.fileno()}, "

41+

f"family={self.family!s}, type={self.type!s}, "

42+

f"proto={self.proto}"

43+

)

44+45+

if self.fileno() != -1:

46+

try:

47+

laddr = self.getsockname()

48+

if laddr:

49+

s = f"{s}, laddr={laddr}"

50+

except socket.error:

51+

pass

52+

try:

53+

raddr = self.getpeername()

54+

if raddr:

55+

s = f"{s}, raddr={raddr}"

56+

except socket.error:

57+

pass

58+59+

return f"{s}>"

60+61+

def __getstate__(self):

62+

raise TypeError("Cannot serialize asyncio.TransportSocket object")

63+64+

def fileno(self):

65+

return self._sock.fileno()

66+67+

def dup(self):

68+

return self._sock.dup()

69+70+

def get_inheritable(self):

71+

return self._sock.get_inheritable()

72+73+

def shutdown(self, how):

74+

# asyncio doesn't currently provide a high-level transport API

75+

# to shutdown the connection.

76+

self._sock.shutdown(how)

77+78+

def getsockopt(self, *args, **kwargs):

79+

return self._sock.getsockopt(*args, **kwargs)

80+81+

def setsockopt(self, *args, **kwargs):

82+

self._sock.setsockopt(*args, **kwargs)

83+84+

def getpeername(self):

85+

return self._sock.getpeername()

86+87+

def getsockname(self):

88+

return self._sock.getsockname()

89+90+

def getsockbyname(self):

91+

return self._sock.getsockbyname()

92+93+

def accept(self):

94+

self._na('accept() method')

95+

return self._sock.accept()

96+97+

def connect(self, *args, **kwargs):

98+

self._na('connect() method')

99+

return self._sock.connect(*args, **kwargs)

100+101+

def connect_ex(self, *args, **kwargs):

102+

self._na('connect_ex() method')

103+

return self._sock.connect_ex(*args, **kwargs)

104+105+

def bind(self, *args, **kwargs):

106+

self._na('bind() method')

107+

return self._sock.bind(*args, **kwargs)

108+109+

def ioctl(self, *args, **kwargs):

110+

self._na('ioctl() method')

111+

return self._sock.ioctl(*args, **kwargs)

112+113+

def listen(self, *args, **kwargs):

114+

self._na('listen() method')

115+

return self._sock.listen(*args, **kwargs)

116+117+

def makefile(self):

118+

self._na('makefile() method')

119+

return self._sock.makefile()

120+121+

def sendfile(self, *args, **kwargs):

122+

self._na('sendfile() method')

123+

return self._sock.sendfile(*args, **kwargs)

124+125+

def close(self):

126+

self._na('close() method')

127+

return self._sock.close()

128+129+

def detach(self):

130+

self._na('detach() method')

131+

return self._sock.detach()

132+133+

def sendmsg_afalg(self, *args, **kwargs):

134+

self._na('sendmsg_afalg() method')

135+

return self._sock.sendmsg_afalg(*args, **kwargs)

136+137+

def sendmsg(self, *args, **kwargs):

138+

self._na('sendmsg() method')

139+

return self._sock.sendmsg(*args, **kwargs)

140+141+

def sendto(self, *args, **kwargs):

142+

self._na('sendto() method')

143+

return self._sock.sendto(*args, **kwargs)

144+145+

def send(self, *args, **kwargs):

146+

self._na('send() method')

147+

return self._sock.send(*args, **kwargs)

148+149+

def sendall(self, *args, **kwargs):

150+

self._na('sendall() method')

151+

return self._sock.sendall(*args, **kwargs)

152+153+

def set_inheritable(self, *args, **kwargs):

154+

self._na('set_inheritable() method')

155+

return self._sock.set_inheritable(*args, **kwargs)

156+157+

def share(self, process_id):

158+

self._na('share() method')

159+

return self._sock.share(process_id)

160+161+

def recv_into(self, *args, **kwargs):

162+

self._na('recv_into() method')

163+

return self._sock.recv_into(*args, **kwargs)

164+165+

def recvfrom_into(self, *args, **kwargs):

166+

self._na('recvfrom_into() method')

167+

return self._sock.recvfrom_into(*args, **kwargs)

168+169+

def recvmsg_into(self, *args, **kwargs):

170+

self._na('recvmsg_into() method')

171+

return self._sock.recvmsg_into(*args, **kwargs)

172+173+

def recvmsg(self, *args, **kwargs):

174+

self._na('recvmsg() method')

175+

return self._sock.recvmsg(*args, **kwargs)

176+177+

def recvfrom(self, *args, **kwargs):

178+

self._na('recvfrom() method')

179+

return self._sock.recvfrom(*args, **kwargs)

180+181+

def recv(self, *args, **kwargs):

182+

self._na('recv() method')

183+

return self._sock.recv(*args, **kwargs)

184+185+

def settimeout(self, value):

186+

if value == 0:

187+

return

188+

raise ValueError(

189+

'settimeout(): only 0 timeout is allowed on transport sockets')

190+191+

def gettimeout(self):

192+

return 0

193+194+

def setblocking(self, flag):

195+

if not flag:

196+

return

197+

raise ValueError(

198+

'setblocking(): transport sockets cannot be blocking')

199+200+

def __enter__(self):

201+

self._na('context manager protocol')

202+

return self._sock.__enter__()

203+204+

def __exit__(self, *err):

205+

self._na('context manager protocol')

206+

return self._sock.__exit__(*err)