Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/websocket/_socket.py: 47%

107 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:34 +0000

1import errno 

2import selectors 

3import socket 

4 

5from typing import Union 

6 

7from ._exceptions import * 

8from ._ssl_compat import * 

9from ._utils import * 

10 

11""" 

12_socket.py 

13websocket - WebSocket client library for Python 

14 

15Copyright 2023 engn33r 

16 

17Licensed under the Apache License, Version 2.0 (the "License"); 

18you may not use this file except in compliance with the License. 

19You may obtain a copy of the License at 

20 

21 http://www.apache.org/licenses/LICENSE-2.0 

22 

23Unless required by applicable law or agreed to in writing, software 

24distributed under the License is distributed on an "AS IS" BASIS, 

25WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

26See the License for the specific language governing permissions and 

27limitations under the License. 

28""" 

29 

30DEFAULT_SOCKET_OPTION = [(socket.SOL_TCP, socket.TCP_NODELAY, 1)] 

31if hasattr(socket, "SO_KEEPALIVE"): 

32 DEFAULT_SOCKET_OPTION.append((socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)) 

33if hasattr(socket, "TCP_KEEPIDLE"): 

34 DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPIDLE, 30)) 

35if hasattr(socket, "TCP_KEEPINTVL"): 

36 DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPINTVL, 10)) 

37if hasattr(socket, "TCP_KEEPCNT"): 

38 DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPCNT, 3)) 

39 

40_default_timeout = None 

41 

42__all__ = ["DEFAULT_SOCKET_OPTION", "sock_opt", "setdefaulttimeout", "getdefaulttimeout", 

43 "recv", "recv_line", "send"] 

44 

45 

46class sock_opt: 

47 

48 def __init__(self, sockopt: list, sslopt: dict) -> None: 

49 if sockopt is None: 

50 sockopt = [] 

51 if sslopt is None: 

52 sslopt = {} 

53 self.sockopt = sockopt 

54 self.sslopt = sslopt 

55 self.timeout = None 

56 

57 

58def setdefaulttimeout(timeout: Union[int, float, None]) -> None: 

59 """ 

60 Set the global timeout setting to connect. 

61 

62 Parameters 

63 ---------- 

64 timeout: int or float 

65 default socket timeout time (in seconds) 

66 """ 

67 global _default_timeout 

68 _default_timeout = timeout 

69 

70 

71def getdefaulttimeout() -> Union[int, float, None]: 

72 """ 

73 Get default timeout 

74 

75 Returns 

76 ---------- 

77 _default_timeout: int or float 

78 Return the global timeout setting (in seconds) to connect. 

79 """ 

80 return _default_timeout 

81 

82 

83def recv(sock: socket.socket, bufsize: int) -> bytes: 

84 if not sock: 

85 raise WebSocketConnectionClosedException("socket is already closed.") 

86 

87 def _recv(): 

88 try: 

89 return sock.recv(bufsize) 

90 except SSLWantReadError: 

91 pass 

92 except socket.error as exc: 

93 error_code = extract_error_code(exc) 

94 if error_code != errno.EAGAIN and error_code != errno.EWOULDBLOCK: 

95 raise 

96 

97 sel = selectors.DefaultSelector() 

98 sel.register(sock, selectors.EVENT_READ) 

99 

100 r = sel.select(sock.gettimeout()) 

101 sel.close() 

102 

103 if r: 

104 return sock.recv(bufsize) 

105 

106 try: 

107 if sock.gettimeout() == 0: 

108 bytes_ = sock.recv(bufsize) 

109 else: 

110 bytes_ = _recv() 

111 except TimeoutError: 

112 raise WebSocketTimeoutException("Connection timed out") 

113 except socket.timeout as e: 

114 message = extract_err_message(e) 

115 raise WebSocketTimeoutException(message) 

116 except SSLError as e: 

117 message = extract_err_message(e) 

118 if isinstance(message, str) and 'timed out' in message: 

119 raise WebSocketTimeoutException(message) 

120 else: 

121 raise 

122 

123 if not bytes_: 

124 raise WebSocketConnectionClosedException( 

125 "Connection to remote host was lost.") 

126 

127 return bytes_ 

128 

129 

130def recv_line(sock: socket.socket) -> bytes: 

131 line = [] 

132 while True: 

133 c = recv(sock, 1) 

134 line.append(c) 

135 if c == b'\n': 

136 break 

137 return b''.join(line) 

138 

139 

140def send(sock: socket.socket, data: Union[bytes, str]) -> int: 

141 if isinstance(data, str): 

142 data = data.encode('utf-8') 

143 

144 if not sock: 

145 raise WebSocketConnectionClosedException("socket is already closed.") 

146 

147 def _send(): 

148 try: 

149 return sock.send(data) 

150 except SSLWantWriteError: 

151 pass 

152 except socket.error as exc: 

153 error_code = extract_error_code(exc) 

154 if error_code is None: 

155 raise 

156 if error_code != errno.EAGAIN and error_code != errno.EWOULDBLOCK: 

157 raise 

158 

159 sel = selectors.DefaultSelector() 

160 sel.register(sock, selectors.EVENT_WRITE) 

161 

162 w = sel.select(sock.gettimeout()) 

163 sel.close() 

164 

165 if w: 

166 return sock.send(data) 

167 

168 try: 

169 if sock.gettimeout() == 0: 

170 return sock.send(data) 

171 else: 

172 return _send() 

173 except socket.timeout as e: 

174 message = extract_err_message(e) 

175 raise WebSocketTimeoutException(message) 

176 except Exception as e: 

177 message = extract_err_message(e) 

178 if isinstance(message, str) and "timed out" in message: 

179 raise WebSocketTimeoutException(message) 

180 else: 

181 raise