""" websocket - WebSocket client library for Python Copyright (C) 2010 Hiroki Ohtani(liris) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA """ import errno import select import socket import six import sys from ._exceptions import * from ._ssl_compat import * from ._utils import * DEFAULT_SOCKET_OPTION = [(socket.SOL_TCP, socket.TCP_NODELAY, 1)] if hasattr(socket, "SO_KEEPALIVE"): DEFAULT_SOCKET_OPTION.append((socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)) if hasattr(socket, "TCP_KEEPIDLE"): DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPIDLE, 30)) if hasattr(socket, "TCP_KEEPINTVL"): DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPINTVL, 10)) if hasattr(socket, "TCP_KEEPCNT"): DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPCNT, 3)) _default_timeout = None __all__ = ["DEFAULT_SOCKET_OPTION", "sock_opt", "setdefaulttimeout", "getdefaulttimeout", "recv", "recv_line", "send"] class sock_opt(object): def __init__(self, sockopt, sslopt): if sockopt is None: sockopt = [] if sslopt is None: sslopt = {} self.sockopt = sockopt self.sslopt = sslopt self.timeout = None def setdefaulttimeout(timeout): """ Set the global timeout setting to connect. timeout: default socket timeout time. This value is second. """ global _default_timeout _default_timeout = timeout def getdefaulttimeout(): """ Return the global timeout setting(second) to connect. """ return _default_timeout def recv(sock, bufsize): if not sock: raise WebSocketConnectionClosedException("socket is already closed.") def _recv(): try: return sock.recv(bufsize) except SSLWantReadError: pass except socket.error as exc: error_code = extract_error_code(exc) if error_code is None: raise if error_code != errno.EAGAIN or error_code != errno.EWOULDBLOCK: raise r, w, e = select.select((sock, ), (), (), sock.gettimeout()) if r: return sock.recv(bufsize) try: if sock.gettimeout() == 0: bytes_ = sock.recv(bufsize) else: bytes_ = _recv() except socket.timeout as e: message = extract_err_message(e) raise WebSocketTimeoutException(message) except SSLError as e: message = extract_err_message(e) if isinstance(message, str) and 'timed out' in message: raise WebSocketTimeoutException(message) else: raise if not bytes_: raise WebSocketConnectionClosedException( "Connection is already closed.") return bytes_ def recv_line(sock): line = [] while True: c = recv(sock, 1) line.append(c) if c == six.b("\n"): break return six.b("").join(line) def send(sock, data): if isinstance(data, six.text_type): data = data.encode('utf-8') if not sock: raise WebSocketConnectionClosedException("socket is already closed.") def _send(): try: return sock.send(data) except SSLWantWriteError: pass except socket.error as exc: error_code = extract_error_code(exc) if error_code is None: raise if error_code != errno.EAGAIN or error_code != errno.EWOULDBLOCK: raise r, w, e = select.select((), (sock, ), (), sock.gettimeout()) if w: return sock.send(data) try: if sock.gettimeout() == 0: return sock.send(data) else: return _send() except socket.timeout as e: message = extract_err_message(e) raise WebSocketTimeoutException(message) except Exception as e: message = extract_err_message(e) if isinstance(message, str) and "timed out" in message: raise WebSocketTimeoutException(message) else: raise