Commit 3f750a92 authored by AlexejStukov's avatar AlexejStukov Committed by ORD

Prevent the UASocketClient from hanging (#316)

* Prevent the UASocketClient from hanging

Added a timeout to the socket connection that prevents the ``UASocketClient`` from hanging on  ``_receive`` in ``_run``.

* introduces new socket_timeout

* added socket_timeout to Client

* fixed small bug

* added timeout handling to SocketWrapper
parent 158c0fbc
......@@ -79,7 +79,7 @@ class Client(object):
which offers the raw OPC-UA services interface.
"""
def __init__(self, url, timeout=4):
def __init__(self, url, timeout=4, socket_timeout=10):
"""
:param url: url of the server.
......@@ -101,7 +101,7 @@ class Client(object):
self.secure_channel_timeout = 3600000 # 1 hour
self.session_timeout = 3600000 # 1 hour
self._policy_ids = []
self.uaclient = UaClient(timeout)
self.uaclient = UaClient(timeout, socket_timeout)
self.user_certificate = None
self.user_private_key = None
self._session_counter = 1
......
......@@ -18,11 +18,12 @@ class UASocketClient(object):
handle socket connection and send ua messages
timeout is the timeout used while waiting for an ua answer from server
"""
def __init__(self, timeout=1, security_policy=ua.SecurityPolicy()):
def __init__(self, timeout=1, security_policy=ua.SecurityPolicy(), socket_timeout=10):
self.logger = logging.getLogger(__name__ + ".Socket")
self._thread = None
self._lock = Lock()
self.timeout = timeout
self.socket_timeout = socket_timeout
self._socket = None
self._do_stop = False
self.authentication_token = ua.NodeId()
......@@ -132,7 +133,7 @@ class UASocketClient(object):
connect to server socket and start receiving thread
"""
self.logger.info("opening connection")
sock = socket.create_connection((host, port))
sock = socket.create_connection((host, port), timeout=self.socket_timeout)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # nodelay ncessary to avoid packing in one frame, some servers do not like it
self._socket = utils.SocketWrapper(sock)
self.start()
......@@ -194,11 +195,12 @@ class UaClient(object):
uaprotocol_auto.py and uaprotocol_hand.py available under opcua.ua
"""
def __init__(self, timeout=1):
def __init__(self, timeout=1, socket_timeout=10):
self.logger = logging.getLogger(__name__)
# _publishcallbacks should be accessed in recv thread only
self._publishcallbacks = {}
self._timeout = timeout
self._socket_timeout = socket_timeout
self._uasocket = None
self._security_policy = ua.SecurityPolicy()
......@@ -209,7 +211,7 @@ class UaClient(object):
"""
connect to server socket and start receiving thread
"""
self._uasocket = UASocketClient(self._timeout, security_policy=self._security_policy)
self._uasocket = UASocketClient(self._timeout, security_policy=self._security_policy, socket_timeout=self._socket_timeout)
return self._uasocket.connect_socket(host, port)
def disconnect_socket(self):
......
......@@ -4,6 +4,7 @@ from concurrent.futures import Future
import functools
import threading
from socket import error as SocketError
from socket import timeout as SocketTimeout
try:
# we prefer to use bundles asyncio version, otherwise fallback to trollius
......@@ -29,6 +30,10 @@ class SocketClosedException(UaError):
pass
class SocketTimeoutException(UaError):
pass
class Buffer(object):
"""
......@@ -102,6 +107,8 @@ class SocketWrapper(object):
while size > 0:
try:
chunk = self.socket.recv(size)
except SocketTimeout as ex:
raise SocketTimeoutException("Server socket has timed out")
except (OSError, SocketError) as ex:
raise SocketClosedException("Server socket has closed", ex)
if not chunk:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment