Skip to content

Commit

Permalink
fix race connection at secure_open for client (FreeOpcUa#1042)
Browse files Browse the repository at this point in the history
* fix race connection at secure_open for client

* more robust code to secure_open

* fix waiting logic

* remove leftover print
  • Loading branch information
oroulet authored Jun 3, 2020
1 parent b2d4ba3 commit 12acba3
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 5 deletions.
20 changes: 15 additions & 5 deletions opcua/client/ua_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,15 @@ def _receive(self):
msg = self._connection.receive_from_socket(self._socket)
if msg is None:
return
elif isinstance(msg, ua.Message):
if isinstance(msg, ua.Message):
self._call_callback(msg.request_id(), msg.body())
elif isinstance(msg, ua.Acknowledge):
self._call_callback(0, msg)
elif isinstance(msg, ua.ErrorMessage):
self.logger.fatal("Received an error: %s", msg)
self._call_callback(0, ua.UaStatusCodeError(msg.Error.value))
else:
raise ua.UaError("Unsupported message type: %s", msg)
raise ua.UaError("Unsupported message type: {}".format(msg))

def _call_callback(self, request_id, body):
with self._lock:
Expand Down Expand Up @@ -194,11 +194,21 @@ def open_secure_channel(self, params):
self.logger.info("open_secure_channel")
request = ua.OpenSecureChannelRequest()
request.Parameters = params
future = self._send_request(request, message_type=ua.MessageType.SecureOpen)

response = struct_from_binary(ua.OpenSecureChannelResponse, future.result(self.timeout))
# use callback to make sure channel security parameters are set immedialty
# and we do no get race conditions
def clb(future):
response = struct_from_binary(ua.OpenSecureChannelResponse, future.result())
response.ResponseHeader.ServiceResult.check()
self._connection.set_channel(response.Parameters, params.RequestType, params.ClientNonce)
clb.future.set_result(response)
clb.future = Future() # hack to have a variable only shared between a callback and us

self._send_request(request, message_type=ua.MessageType.SecureOpen, callback=clb)
# wait for our callbackto finish rexecuting before returning
response = clb.future.result(self.timeout)
response.ResponseHeader.ServiceResult.check()
self._connection.set_channel(response.Parameters, params.RequestType, params.ClientNonce)

return response.Parameters

def close_secure_channel(self):
Expand Down
8 changes: 8 additions & 0 deletions opcua/ua/uaprotocol_hand.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,14 @@ class Message(object):
def __init__(self, chunks):
self._chunks = chunks

def __str__(self):
return 'Message(' + str(self._chunks) + ')'

__repr__ = __str__

def message_type(self):
return self._chunks[0].MessageHeader.MessageType

def request_id(self):
return self._chunks[0].SequenceHeader.RequestId

Expand Down

0 comments on commit 12acba3

Please sign in to comment.