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

106 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:48 +0000

1import errno 

2import selectors 

3import socket 

4 

5from ._exceptions import * 

6from ._ssl_compat import * 

7from ._utils import * 

8 

9""" 

10_socket.py 

11websocket - WebSocket client library for Python 

12 

13Copyright 2022 engn33r 

14 

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

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

17You may obtain a copy of the License at 

18 

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

20 

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

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

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

24See the License for the specific language governing permissions and 

25limitations under the License. 

26""" 

27 

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

29if hasattr(socket, "SO_KEEPALIVE"): 

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

31if hasattr(socket, "TCP_KEEPIDLE"): 

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

33if hasattr(socket, "TCP_KEEPINTVL"): 

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

35if hasattr(socket, "TCP_KEEPCNT"): 

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

37 

38_default_timeout = None 

39 

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

41 "recv", "recv_line", "send"] 

42 

43 

44class sock_opt: 

45 

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

47 if sockopt is None: 

48 sockopt = [] 

49 if sslopt is None: 

50 sslopt = {} 

51 self.sockopt = sockopt 

52 self.sslopt = sslopt 

53 self.timeout = None 

54 

55 

56def setdefaulttimeout(timeout: int or float) -> None: 

57 """ 

58 Set the global timeout setting to connect. 

59 

60 Parameters 

61 ---------- 

62 timeout: int or float 

63 default socket timeout time (in seconds) 

64 """ 

65 global _default_timeout 

66 _default_timeout = timeout 

67 

68 

69def getdefaulttimeout() -> int or float: 

70 """ 

71 Get default timeout 

72 

73 Returns 

74 ---------- 

75 _default_timeout: int or float 

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

77 """ 

78 return _default_timeout 

79 

80 

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

82 if not sock: 

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

84 

85 def _recv(): 

86 try: 

87 return sock.recv(bufsize) 

88 except SSLWantReadError: 

89 pass 

90 except socket.error as exc: 

91 error_code = extract_error_code(exc) 

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

93 raise 

94 

95 sel = selectors.DefaultSelector() 

96 sel.register(sock, selectors.EVENT_READ) 

97 

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

99 sel.close() 

100 

101 if r: 

102 return sock.recv(bufsize) 

103 

104 try: 

105 if sock.gettimeout() == 0: 

106 bytes_ = sock.recv(bufsize) 

107 else: 

108 bytes_ = _recv() 

109 except TimeoutError: 

110 raise WebSocketTimeoutException("Connection timed out") 

111 except socket.timeout as e: 

112 message = extract_err_message(e) 

113 raise WebSocketTimeoutException(message) 

114 except SSLError as e: 

115 message = extract_err_message(e) 

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

117 raise WebSocketTimeoutException(message) 

118 else: 

119 raise 

120 

121 if not bytes_: 

122 raise WebSocketConnectionClosedException( 

123 "Connection to remote host was lost.") 

124 

125 return bytes_ 

126 

127 

128def recv_line(sock: socket) -> bytes: 

129 line = [] 

130 while True: 

131 c = recv(sock, 1) 

132 line.append(c) 

133 if c == b'\n': 

134 break 

135 return b''.join(line) 

136 

137 

138def send(sock: socket, data: bytes) -> int: 

139 if isinstance(data, str): 

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

141 

142 if not sock: 

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

144 

145 def _send(): 

146 try: 

147 return sock.send(data) 

148 except SSLWantWriteError: 

149 pass 

150 except socket.error as exc: 

151 error_code = extract_error_code(exc) 

152 if error_code is None: 

153 raise 

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

155 raise 

156 

157 sel = selectors.DefaultSelector() 

158 sel.register(sock, selectors.EVENT_WRITE) 

159 

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

161 sel.close() 

162 

163 if w: 

164 return sock.send(data) 

165 

166 try: 

167 if sock.gettimeout() == 0: 

168 return sock.send(data) 

169 else: 

170 return _send() 

171 except socket.timeout as e: 

172 message = extract_err_message(e) 

173 raise WebSocketTimeoutException(message) 

174 except Exception as e: 

175 message = extract_err_message(e) 

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

177 raise WebSocketTimeoutException(message) 

178 else: 

179 raise