| """ |
| 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 |