1"""
2websocket - WebSocket client library for Python
3
4Copyright (C) 2010 Hiroki Ohtani(liris)
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with this library; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street, Fifth Floor,
19    Boston, MA 02110-1335  USA
20
21"""
22import socket
23
24import six
25
26from ._exceptions import *
27from ._ssl_compat import *
28from ._utils import *
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(object):
47
48    def __init__(self, sockopt, sslopt):
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):
59    """
60    Set the global timeout setting to connect.
61
62    timeout: default socket timeout time. This value is second.
63    """
64    global _default_timeout
65    _default_timeout = timeout
66
67
68def getdefaulttimeout():
69    """
70    Return the global timeout setting(second) to connect.
71    """
72    return _default_timeout
73
74
75def recv(sock, bufsize):
76    if not sock:
77        raise WebSocketConnectionClosedException("socket is already closed.")
78
79    try:
80        bytes_ = sock.recv(bufsize)
81    except socket.timeout as e:
82        message = extract_err_message(e)
83        raise WebSocketTimeoutException(message)
84    except SSLError as e:
85        message = extract_err_message(e)
86        if message == "The read operation timed out":
87            raise WebSocketTimeoutException(message)
88        else:
89            raise
90
91    if not bytes_:
92        raise WebSocketConnectionClosedException(
93            "Connection is already closed.")
94
95    return bytes_
96
97
98def recv_line(sock):
99    line = []
100    while True:
101        c = recv(sock, 1)
102        line.append(c)
103        if c == six.b("\n"):
104            break
105    return six.b("").join(line)
106
107
108def send(sock, data):
109    if isinstance(data, six.text_type):
110        data = data.encode('utf-8')
111
112    if not sock:
113        raise WebSocketConnectionClosedException("socket is already closed.")
114
115    try:
116        return sock.send(data)
117    except socket.timeout as e:
118        message = extract_err_message(e)
119        raise WebSocketTimeoutException(message)
120    except Exception as e:
121        message = extract_err_message(e)
122        if isinstance(message, str) and "timed out" in message:
123            raise WebSocketTimeoutException(message)
124        else:
125            raise
126