uaprotocol_hand.py
Go to the documentation of this file.
1 import struct
2 import logging
3 import hashlib
4 from datetime import datetime
5 
6 from opcua.ua import uaprotocol_auto as auto
7 from opcua.ua import uatypes
8 from opcua.ua import ua_binary as uabin
9 from opcua.ua import UaError
10 from opcua.common import utils
11 
12 logger = logging.getLogger('opcua.uaprotocol')
13 
14 OPC_TCP_SCHEME = 'opc.tcp'
15 
16 
17 class Hello(uatypes.FrozenClass):
18 
19  def __init__(self):
20  self.ProtocolVersion = 0
21  self.ReceiveBufferSize = 65536
22  self.SendBufferSize = 65536
23  self.MaxMessageSize = 0
24  self.MaxChunkCount = 0
25  self.EndpointUrl = ""
26  self._freeze = True
27 
28  def to_binary(self):
29  b = []
30  b.append(uabin.Primitives.UInt32.pack(self.ProtocolVersion))
31  b.append(uabin.Primitives.UInt32.pack(self.ReceiveBufferSize))
32  b.append(uabin.Primitives.UInt32.pack(self.SendBufferSize))
33  b.append(uabin.Primitives.UInt32.pack(self.MaxMessageSize))
34  b.append(uabin.Primitives.UInt32.pack(self.MaxChunkCount))
35  b.append(uabin.Primitives.String.pack(self.EndpointUrl))
36  return b"".join(b)
37 
38  @staticmethod
39  def from_binary(data):
40  hello = Hello()
41  hello.ProtocolVersion = uabin.Primitives.UInt32.unpack(data)
42  hello.ReceiveBufferSize = uabin.Primitives.UInt32.unpack(data)
43  hello.SendBufferSize = uabin.Primitives.UInt32.unpack(data)
44  hello.MaxMessageSize = uabin.Primitives.UInt32.unpack(data)
45  hello.MaxChunkCount = uabin.Primitives.UInt32.unpack(data)
46  hello.EndpointUrl = uabin.Primitives.String.unpack(data)
47  return hello
48 
49 
50 class MessageType(object):
51  Invalid = b"INV" # FIXME: check value
52  Hello = b"HEL"
53  Acknowledge = b"ACK"
54  Error = b"ERR"
55  SecureOpen = b"OPN"
56  SecureClose = b"CLO"
57  SecureMessage = b"MSG"
58 
59 
60 class ChunkType(object):
61  Invalid = b"0" # FIXME check
62  Single = b"F"
63  Intermediate = b"C"
64  Abort = b"A" # when an error occurred and the Message is aborted (body is ErrorMessage)
65 
66 
67 class Header(uatypes.FrozenClass):
68 
69  def __init__(self, msgType=None, chunkType=None, channelid=0):
70  self.MessageType = msgType
71  self.ChunkType = chunkType
72  self.ChannelId = channelid
73  self.body_size = 0
74  self.packet_size = 0
75  self._freeze = True
76 
77  def add_size(self, size):
78  self.body_size += size
79 
80  def to_binary(self):
81  b = []
82  b.append(struct.pack("<3ss", self.MessageType, self.ChunkType))
83  size = self.body_size + 8
84  if self.MessageType in (MessageType.SecureOpen, MessageType.SecureClose, MessageType.SecureMessage):
85  size += 4
86  b.append(uabin.Primitives.UInt32.pack(size))
87  if self.MessageType in (MessageType.SecureOpen, MessageType.SecureClose, MessageType.SecureMessage):
88  b.append(uabin.Primitives.UInt32.pack(self.ChannelId))
89  return b"".join(b)
90 
91  @staticmethod
92  def from_string(data):
93  hdr = Header()
94  hdr.MessageType, hdr.ChunkType, hdr.packet_size = struct.unpack("<3scI", data.read(8))
95  hdr.body_size = hdr.packet_size - 8
96  if hdr.MessageType in (MessageType.SecureOpen, MessageType.SecureClose, MessageType.SecureMessage):
97  hdr.body_size -= 4
98  hdr.ChannelId = uabin.Primitives.UInt32.unpack(data)
99  return hdr
100 
101  @staticmethod
102  def max_size():
103  return struct.calcsize("<3scII")
104 
105  def __str__(self):
106  return "Header(type:{0}, chunk_type:{1}, body_size:{2}, channel:{3})".format(
107  self.MessageType, self.ChunkType, self.body_size, self.ChannelId)
108  __repr__ = __str__
109 
110 
111 class ErrorMessage(uatypes.FrozenClass):
112 
113  def __init__(self):
115  self.Reason = ""
116  self._freeze = True
117 
118  def to_binary(self):
119  b = []
120  b.append(self.Error.to_binary())
121  b.append(uabin.Primitives.String.pack(self.Reason))
122  return b"".join(b)
123 
124  @staticmethod
125  def from_binary(data):
126  ack = ErrorMessage()
127  ack.Error = uatypes.StatusCode.from_binary(data)
128  ack.Reason = uabin.Primitives.String.unpack(data)
129  return ack
130 
131  def __str__(self):
132  return "MessageAbort(error:{0}, reason:{1})".format(self.Error, self.Reason)
133  __repr__ = __str__
134 
135 
136 class Acknowledge(uatypes.FrozenClass):
137 
138  def __init__(self):
140  self.ReceiveBufferSize = 65536
141  self.SendBufferSize = 65536
142  self.MaxMessageSize = 0 # No limits
143  self.MaxChunkCount = 0 # No limits
144  self._freeze = True
145 
146  def to_binary(self):
147  return struct.pack(
148  "<5I",
149  self.ProtocolVersion,
150  self.ReceiveBufferSize,
151  self.SendBufferSize,
152  self.MaxMessageSize,
153  self.MaxChunkCount)
154 
155  @staticmethod
156  def from_binary(data):
157  ack = Acknowledge()
158  ack.ProtocolVersion, ack.ReceiveBufferSize, ack.SendBufferSize, ack.MaxMessageSize, ack.MaxChunkCount \
159  = struct.unpack("<5I", data.read(20))
160  return ack
161 
162 
163 class AsymmetricAlgorithmHeader(uatypes.FrozenClass):
164 
165  def __init__(self):
166  self.SecurityPolicyURI = "http://opcfoundation.org/UA/SecurityPolicy#None"
167  self.SenderCertificate = None
169  self._freeze = True
170 
171  def to_binary(self):
172  b = []
173  b.append(uabin.Primitives.String.pack(self.SecurityPolicyURI))
174  b.append(uabin.Primitives.String.pack(self.SenderCertificate))
175  b.append(uabin.Primitives.String.pack(self.ReceiverCertificateThumbPrint))
176  return b"".join(b)
177 
178  @staticmethod
179  def from_binary(data):
181  hdr.SecurityPolicyURI = uabin.Primitives.String.unpack(data)
182  hdr.SenderCertificate = uabin.Primitives.Bytes.unpack(data)
183  hdr.ReceiverCertificateThumbPrint = uabin.Primitives.Bytes.unpack(data)
184  return hdr
185 
186  def __str__(self):
187  return "{0}(SecurityPolicy:{1}, certificatesize:{2}, receiverCertificatesize:{3} )".format(
188  self.__class__.__name__, self.SecurityPolicyURI, len(self.SenderCertificate),
190  __repr__ = __str__
191 
192 
193 class SymmetricAlgorithmHeader(uatypes.FrozenClass):
194 
195  def __init__(self):
196  self.TokenId = 0
197  self._freeze = True
198 
199  @staticmethod
200  def from_binary(data):
202  obj.TokenId = uabin.Primitives.UInt32.unpack(data)
203  return obj
204 
205  def to_binary(self):
206  return uabin.Primitives.UInt32.pack(self.TokenId)
207 
208  @staticmethod
209  def max_size():
210  return struct.calcsize("<I")
211 
212  def __str__(self):
213  return "{0}(TokenId:{1} )".format(self.__class__.__name__, self.TokenId)
214  __repr__ = __str__
215 
216 
217 class SequenceHeader(uatypes.FrozenClass):
218 
219  def __init__(self):
220  self.SequenceNumber = None
221  self.RequestId = None
222  self._freeze = True
223 
224  @staticmethod
225  def from_binary(data):
226  obj = SequenceHeader()
227  obj.SequenceNumber = uabin.Primitives.UInt32.unpack(data)
228  obj.RequestId = uabin.Primitives.UInt32.unpack(data)
229  return obj
230 
231  def to_binary(self):
232  b = []
233  b.append(uabin.Primitives.UInt32.pack(self.SequenceNumber))
234  b.append(uabin.Primitives.UInt32.pack(self.RequestId))
235  return b"".join(b)
236 
237  @staticmethod
238  def max_size():
239  return struct.calcsize("<II")
240 
241  def __str__(self):
242  return "{0}(SequenceNumber:{1}, RequestId:{2} )".format(
243  self.__class__.__name__, self.SequenceNumber, self.RequestId)
244  __repr__ = __str__
245 
246 
248  """
249  Base class for symmetric/asymmetric cryprography
250  """
251 
252  def __init__(self):
253  pass
254 
255  def plain_block_size(self):
256  """
257  Size of plain text block for block cipher.
258  """
259  return 1
260 
262  """
263  Size of encrypted text block for block cipher.
264  """
265  return 1
266 
267  def padding(self, size):
268  """
269  Create padding for a block of given size.
270  plain_size = size + len(padding) + signature_size()
271  plain_size = N * plain_block_size()
272  """
273  return b''
274 
275  def min_padding_size(self):
276  return 0
277 
278  def signature_size(self):
279  return 0
280 
281  def signature(self, data):
282  return b''
283 
284  def encrypt(self, data):
285  return data
286 
287  def decrypt(self, data):
288  return data
289 
290  def vsignature_size(self):
291  return 0
292 
293  def verify(self, data, signature):
294  """
295  Verify signature and raise exception if signature is invalid
296  """
297  pass
298 
299  def remove_padding(self, data):
300  return data
301 
302 
303 class SecurityPolicy(object):
304  """
305  Base class for security policy
306  """
307  URI = "http://opcfoundation.org/UA/SecurityPolicy#None"
308  signature_key_size = 0
309  symmetric_key_size = 0
310 
311  def __init__(self):
314  self.Mode = auto.MessageSecurityMode.None_
315  self.server_certificate = None
316  self.client_certificate = None
317 
318  def make_symmetric_key(self, a, b):
319  pass
320 
321 
322 class SecurityPolicyFactory(object):
323  """
324  Helper class for creating server-side SecurityPolicy.
325  Server has one certificate and private key, but needs a separate
326  SecurityPolicy for every client and client's certificate
327  """
328 
329  def __init__(self, cls=SecurityPolicy, mode=auto.MessageSecurityMode.None_,
330  certificate=None, private_key=None):
331  self.cls = cls
332  self.mode = mode
333  self.certificate = certificate
334  self.private_key = private_key
335 
336  def matches(self, uri, mode=None):
337  return self.cls.URI == uri and (mode is None or self.mode == mode)
338 
339  def create(self, peer_certificate):
340  if self.cls is SecurityPolicy:
341  return self.cls()
342  else:
343  return self.cls(peer_certificate,
344  self.certificate, self.private_key,
345  self.mode)
346 
347 
348 class MessageChunk(uatypes.FrozenClass):
349  """
350  Message Chunk, as described in OPC UA specs Part 6, 6.7.2.
351  """
352 
353  def __init__(self, security_policy, body=b'', msg_type=MessageType.SecureMessage, chunk_type=ChunkType.Single):
354  self.MessageHeader = Header(msg_type, chunk_type)
355  if msg_type in (MessageType.SecureMessage, MessageType.SecureClose):
357  elif msg_type == MessageType.SecureOpen:
359  else:
360  raise UaError("Unsupported message type: {0}".format(msg_type))
362  self.Body = body
363  self._security_policy = security_policy
364 
365  @staticmethod
366  def from_binary(security_policy, data):
367  h = Header.from_string(data)
368  return MessageChunk.from_header_and_body(security_policy, h, data)
369 
370  @staticmethod
371  def from_header_and_body(security_policy, header, buf):
372  assert len(buf) >= header.body_size, 'Full body expected here'
373  data = buf.copy(header.body_size)
374  buf.skip(header.body_size)
375  if header.MessageType in (MessageType.SecureMessage, MessageType.SecureClose):
376  security_header = SymmetricAlgorithmHeader.from_binary(data)
377  crypto = security_policy.symmetric_cryptography
378  elif header.MessageType == MessageType.SecureOpen:
379  security_header = AsymmetricAlgorithmHeader.from_binary(data)
380  crypto = security_policy.asymmetric_cryptography
381  else:
382  raise UaError("Unsupported message type: {0}".format(header.MessageType))
383  obj = MessageChunk(crypto)
384  obj.MessageHeader = header
385  obj.SecurityHeader = security_header
386  decrypted = crypto.decrypt(data.read(len(data)))
387  signature_size = crypto.vsignature_size()
388  if signature_size > 0:
389  signature = decrypted[-signature_size:]
390  decrypted = decrypted[:-signature_size]
391  crypto.verify(obj.MessageHeader.to_binary() + obj.SecurityHeader.to_binary() + decrypted, signature)
392  data = utils.Buffer(crypto.remove_padding(decrypted))
393  obj.SequenceHeader = SequenceHeader.from_binary(data)
394  obj.Body = data.read(len(data))
395  return obj
396 
397  def encrypted_size(self, plain_size):
398  size = plain_size + self._security_policy.signature_size()
399  pbs = self._security_policy.plain_block_size()
400  assert(size % pbs == 0)
401  return size // pbs * self._security_policy.encrypted_block_size()
402 
403  def to_binary(self):
404  security = self.SecurityHeader.to_binary()
405  encrypted_part = self.SequenceHeader.to_binary() + self.Body
406  encrypted_part += self._security_policy.padding(len(encrypted_part))
407  self.MessageHeader.body_size = len(security) + self.encrypted_size(len(encrypted_part))
408  header = self.MessageHeader.to_binary()
409  encrypted_part += self._security_policy.signature(header + security + encrypted_part)
410  return header + security + self._security_policy.encrypt(encrypted_part)
411 
412  @staticmethod
413  def max_body_size(crypto, max_chunk_size):
414  max_encrypted_size = max_chunk_size - Header.max_size() - SymmetricAlgorithmHeader.max_size()
415  max_plain_size = (max_encrypted_size // crypto.encrypted_block_size()) * crypto.plain_block_size()
416  return max_plain_size - SequenceHeader.max_size() - crypto.signature_size() - crypto.min_padding_size()
417 
418  @staticmethod
419  def message_to_chunks(security_policy, body, max_chunk_size,
420  message_type=MessageType.SecureMessage, channel_id=1, request_id=1, token_id=1):
421  """
422  Pack message body (as binary string) into one or more chunks.
423  Size of each chunk will not exceed max_chunk_size.
424  Returns a list of MessageChunks. SequenceNumber is not initialized here,
425  it must be set by Secure Channel driver.
426  """
427  if message_type == MessageType.SecureOpen:
428  # SecureOpen message must be in a single chunk (specs, Part 6, 6.7.2)
429  chunk = MessageChunk(security_policy.asymmetric_cryptography, body, message_type, ChunkType.Single)
430  chunk.SecurityHeader.SecurityPolicyURI = security_policy.URI
431  if security_policy.client_certificate:
432  chunk.SecurityHeader.SenderCertificate = security_policy.client_certificate
433  if security_policy.server_certificate:
434  chunk.SecurityHeader.ReceiverCertificateThumbPrint =\
435  hashlib.sha1(security_policy.server_certificate).digest()
436  chunk.MessageHeader.ChannelId = channel_id
437  chunk.SequenceHeader.RequestId = request_id
438  return [chunk]
439 
440  crypto = security_policy.symmetric_cryptography
441  max_size = MessageChunk.max_body_size(crypto, max_chunk_size)
442 
443  chunks = []
444  for i in range(0, len(body), max_size):
445  part = body[i:i + max_size]
446  if i + max_size >= len(body):
447  chunk_type = ChunkType.Single
448  else:
449  chunk_type = ChunkType.Intermediate
450  chunk = MessageChunk(crypto, part, message_type, chunk_type)
451  chunk.SecurityHeader.TokenId = token_id
452  chunk.MessageHeader.ChannelId = channel_id
453  chunk.SequenceHeader.RequestId = request_id
454  chunks.append(chunk)
455  return chunks
456 
457  def __str__(self):
458  return "{0}({1}, {2}, {3}, {4} bytes)".format(self.__class__.__name__,
459  self.MessageHeader, self.SequenceHeader,
460  self.SecurityHeader, len(self.Body))
461  __repr__ = __str__
462 
463 
464 class Message(object):
465 
466  def __init__(self, chunks):
467  self._chunks = chunks
468 
469  def request_id(self):
470  return self._chunks[0].SequenceHeader.RequestId
471 
472  def SequenceHeader(self):
473  return self._chunks[0].SequenceHeader
474 
475  def SecurityHeader(self):
476  return self._chunks[0].SecurityHeader
477 
478  def body(self):
479  body = b"".join([c.Body for c in self._chunks])
480  return utils.Buffer(body)
481 
482 
483 class SecureConnection(object):
484  """
485  Common logic for client and server
486  """
487 
488  def __init__(self, security_policy):
491  self._incoming_parts = []
492  self._security_policy = security_policy
493  self._policies = []
494  self.channel = auto.OpenSecureChannelResult()
495  self._old_tokens = []
496  self._open = False
497  self._max_chunk_size = 65536
498 
499  def set_channel(self, channel):
500  """
501  Called on client side when getting secure channel data from server
502  """
503  self.channel = channel
504 
505  def open(self, params, server):
506  """
507  called on server side to open secure channel
508  """
509  if not self._open or params.RequestType == auto.SecurityTokenRequestType.Issue:
510  self._open = True
511  self.channel = auto.OpenSecureChannelResult()
512  self.channel.SecurityToken.TokenId = 13 # random value
513  self.channel.SecurityToken.ChannelId = server.get_new_channel_id()
514  self.channel.SecurityToken.RevisedLifetime = params.RequestedLifetime
515  else:
516  self._old_tokens.append(self.channel.SecurityToken.TokenId)
517  self.channel.SecurityToken.TokenId += 1
518  self.channel.SecurityToken.CreatedAt = datetime.utcnow()
519  self.channel.SecurityToken.RevisedLifetime = params.RequestedLifetime
520  self.channel.ServerNonce = utils.create_nonce(self._security_policy.symmetric_key_size)
521  self._security_policy.make_symmetric_key(self.channel.ServerNonce, params.ClientNonce)
522  return self.channel
523 
524  def close(self):
525  self._open = False
526 
527  def is_open(self):
528  return self._open
529 
530  def set_policy_factories(self, policies):
531  """
532  Set a list of available security policies.
533  Use this in servers with multiple endpoints with different security
534  """
535  self._policies = policies
536 
537  @staticmethod
538  def _policy_matches(policy, uri, mode=None):
539  return policy.URI == uri and (mode is None or policy.Mode == mode)
540 
541  def select_policy(self, uri, peer_certificate, mode=None):
542  for policy in self._policies:
543  if policy.matches(uri, mode):
544  self._security_policy = policy.create(peer_certificate)
545  return
546  if self._security_policy.URI != uri or (mode is not None and
547  self._security_policy.Mode != mode):
548  raise UaError("No matching policy: {0}, {1}".format(uri, mode))
549 
550  def tcp_to_binary(self, message_type, message):
551  """
552  Convert OPC UA TCP message (see OPC UA specs Part 6, 7.1) to binary.
553  The only supported types are Hello, Acknowledge and ErrorMessage
554  """
555  header = Header(message_type, ChunkType.Single)
556  binmsg = message.to_binary()
557  header.body_size = len(binmsg)
558  return header.to_binary() + binmsg
559 
560  def message_to_binary(self, message, message_type=MessageType.SecureMessage, request_id=0, algohdr=None):
561  """
562  Convert OPC UA secure message to binary.
563  The only supported types are SecureOpen, SecureMessage, SecureClose
564  if message_type is SecureMessage, the AlgoritmHeader should be passed as arg
565  """
566  if algohdr is None:
567  token_id = self.channel.SecurityToken.TokenId
568  else:
569  token_id = algohdr.TokenId
570  chunks = MessageChunk.message_to_chunks(
571  self._security_policy, message, self._max_chunk_size,
572  message_type=message_type,
573  channel_id=self.channel.SecurityToken.ChannelId,
574  request_id=request_id,
575  token_id=token_id)
576  for chunk in chunks:
577  self._sequence_number += 1
578  if self._sequence_number >= (1 << 32):
579  logger.debug("Wrapping sequence number: %d -> 1", self._sequence_number)
580  self._sequence_number = 1
581  chunk.SequenceHeader.SequenceNumber = self._sequence_number
582  return b"".join([chunk.to_binary() for chunk in chunks])
583 
584  def _check_incoming_chunk(self, chunk):
585  assert isinstance(chunk, MessageChunk), "Expected chunk, got: {0}".format(chunk)
586  if chunk.MessageHeader.MessageType != MessageType.SecureOpen:
587  if chunk.MessageHeader.ChannelId != self.channel.SecurityToken.ChannelId:
588  raise UaError("Wrong channel id {0}, expected {1}".format(
589  chunk.MessageHeader.ChannelId,
590  self.channel.SecurityToken.ChannelId))
591  if chunk.SecurityHeader.TokenId != self.channel.SecurityToken.TokenId:
592  if chunk.SecurityHeader.TokenId not in self._old_tokens:
593  logger.warning("Received a chunk with wrong token id %s, expected %s", chunk.SecurityHeader.TokenId, self.channel.SecurityToken.TokenId)
594 
595  #raise UaError("Wrong token id {}, expected {}, old tokens are {}".format(
596  #chunk.SecurityHeader.TokenId,
597  #self.channel.SecurityToken.TokenId,
598  #self._old_tokens))
599 
600  else:
601  # Do some cleanup, spec says we can remove old tokens when new one are used
602  idx = self._old_tokens.index(chunk.SecurityHeader.TokenId)
603  if idx != 0:
604  self._old_tokens = self._old_tokens[idx:]
605  if self._incoming_parts:
606  if self._incoming_parts[0].SequenceHeader.RequestId != chunk.SequenceHeader.RequestId:
607  raise UaError("Wrong request id {0}, expected {1}".format(
608  chunk.SequenceHeader.RequestId,
609  self._incoming_parts[0].SequenceHeader.RequestId))
610 
611  # sequence number must be incremented or wrapped
612  num = chunk.SequenceHeader.SequenceNumber
613  if self._peer_sequence_number is not None:
614  if num != self._peer_sequence_number + 1:
615  wrap = (1 << 32) - 1024
616  if num < 1024 and self._peer_sequence_number >= wrap:
617  # specs Part 6, 6.7.2
618  logger.debug("Sequence number wrapped: %d -> %d",
619  self._peer_sequence_number, num)
620  else:
621  raise UaError(
622  "Wrong sequence {0} -> {1} (server bug or replay attack)"
623  .format(self._peer_sequence_number, num))
624  self._peer_sequence_number = num
625 
626  def receive_from_header_and_body(self, header, body):
627  """
628  Convert MessageHeader and binary body to OPC UA TCP message (see OPC UA
629  specs Part 6, 7.1: Hello, Acknowledge or ErrorMessage), or a Message
630  object, or None (if intermediate chunk is received)
631  """
632  if header.MessageType == MessageType.SecureOpen:
633  data = body.copy(header.body_size)
634  security_header = AsymmetricAlgorithmHeader.from_binary(data)
635  self.select_policy(security_header.SecurityPolicyURI, security_header.SenderCertificate)
636 
637  if header.MessageType in (MessageType.SecureMessage,
638  MessageType.SecureOpen,
639  MessageType.SecureClose):
640  chunk = MessageChunk.from_header_and_body(self._security_policy,
641  header, body)
642  return self._receive(chunk)
643  elif header.MessageType == MessageType.Hello:
644  msg = Hello.from_binary(body)
645  self._max_chunk_size = msg.ReceiveBufferSize
646  return msg
647  elif header.MessageType == MessageType.Acknowledge:
648  msg = Acknowledge.from_binary(body)
649  self._max_chunk_size = msg.SendBufferSize
650  return msg
651  elif header.MessageType == MessageType.Error:
652  msg = ErrorMessage.from_binary(body)
653  logger.warning("Received an error: %s", msg)
654  return msg
655  else:
656  raise UaError("Unsupported message type {0}".format(header.MessageType))
657 
658  def receive_from_socket(self, socket):
659  """
660  Convert binary stream to OPC UA TCP message (see OPC UA
661  specs Part 6, 7.1: Hello, Acknowledge or ErrorMessage), or a Message
662  object, or None (if intermediate chunk is received)
663  """
664  logger.debug("Waiting for header")
665  header = Header.from_string(socket)
666  logger.info("received header: %s", header)
667  body = socket.read(header.body_size)
668  if len(body) != header.body_size:
669  raise UaError("{0} bytes expected, {1} available".format(header.body_size, len(body)))
670  return self.receive_from_header_and_body(header, utils.Buffer(body))
671 
672  def _receive(self, msg):
673  self._check_incoming_chunk(msg)
674  self._incoming_parts.append(msg)
675  if msg.MessageHeader.ChunkType == ChunkType.Intermediate:
676  return None
677  if msg.MessageHeader.ChunkType == ChunkType.Abort:
678  err = ErrorMessage.from_binary(utils.Buffer(msg.Body))
679  logger.warning("Message %s aborted: %s", msg, err)
680  # specs Part 6, 6.7.3 say that aborted message shall be ignored
681  # and SecureChannel should not be closed
682  self._incoming_parts = []
683  return None
684  elif msg.MessageHeader.ChunkType == ChunkType.Single:
685  message = Message(self._incoming_parts)
686  self._incoming_parts = []
687  return message
688  else:
689  raise UaError("Unsupported chunk type: {0}".format(msg))
690 
691 
692 # FIXES for missing switchfield in NodeAttributes classes
693 ana = auto.NodeAttributesMask
694 
695 
696 class ObjectAttributes(auto.ObjectAttributes):
697 
698  def __init__(self):
699  auto.ObjectAttributes.__init__(self)
700  self.SpecifiedAttributes = ana.DisplayName | ana.Description | ana.WriteMask | ana.UserWriteMask | ana.EventNotifier
701 
702 
703 class ObjectTypeAttributes(auto.ObjectTypeAttributes):
704 
705  def __init__(self):
706  auto.ObjectTypeAttributes.__init__(self)
707  self.SpecifiedAttributes = ana.DisplayName | ana.Description | ana.WriteMask | ana.UserWriteMask | ana.IsAbstract
708 
709 
710 class VariableAttributes(auto.VariableAttributes):
711 
712  def __init__(self):
713  auto.VariableAttributes.__init__(self)
714  self.SpecifiedAttributes = ana.DisplayName | ana.Description | ana.WriteMask | ana.UserWriteMask | ana.Value | ana.DataType | ana.ValueRank | ana.ArrayDimensions | ana.AccessLevel | ana.UserAccessLevel | ana.MinimumSamplingInterval | ana.Historizing
715  self.Historizing = False
716 
717 
718 class VariableTypeAttributes(auto.VariableTypeAttributes):
719 
720  def __init__(self):
721  auto.VariableTypeAttributes.__init__(self)
722  self.SpecifiedAttributes = ana.DisplayName | ana.Description | ana.WriteMask | ana.UserWriteMask | ana.Value | ana.DataType | ana.ValueRank | ana.ArrayDimensions | ana.IsAbstract
723 
724 
725 class MethodAttributes(auto.MethodAttributes):
726 
727  def __init__(self):
728  auto.MethodAttributes.__init__(self)
729  self.SpecifiedAttributes = ana.DisplayName | ana.Description | ana.WriteMask | ana.UserWriteMask | ana.Executable | ana.UserExecutable
730 
731 
732 class ReferenceTypeAttributes(auto.ReferenceTypeAttributes):
733 
734  def __init__(self):
735  auto.ReferenceTypeAttributes.__init__(self)
736  self.SpecifiedAttributes = ana.DisplayName | ana.Description | ana.WriteMask | ana.UserWriteMask | ana.IsAbstract | ana.Symmetric | ana.InverseName
737 
738 
739 class DataTypeAttributes(auto.DataTypeAttributes):
740 
741  def __init__(self):
742  auto.DataTypeAttributes.__init__(self)
743  self.SpecifiedAttributes = ana.DisplayName | ana.Description | ana.WriteMask | ana.UserWriteMask | ana.IsAbstract
744 
745 
746 class ViewAttributes(auto.ViewAttributes):
747 
748  def __init__(self):
749  auto.ViewAttributes.__init__(self)
750  self.SpecifiedAttributes = ana.DisplayName | ana.Description | ana.WriteMask | ana.UserWriteMask | ana.ContainsNoLoops | ana.EventNotifier
751 
752 
753 class Argument(auto.Argument):
754 
755  def __init__(self):
756  auto.Argument.__init__(self)
757  self.ValueRank = -2
758 
759 #AttributeIdsInv = {v: k for k, v in AttributeIds.__dict__.items()}
def tcp_to_binary(self, message_type, message)
def receive_from_header_and_body(self, header, body)
def max_body_size(crypto, max_chunk_size)
def select_policy(self, uri, peer_certificate, mode=None)
def __init__(self, cls=SecurityPolicy, mode=auto.MessageSecurityMode.None_, certificate=None, private_key=None)
def _policy_matches(policy, uri, mode=None)
def message_to_binary(self, message, message_type=MessageType.SecureMessage, request_id=0, algohdr=None)
def from_binary(security_policy, data)
def from_header_and_body(security_policy, header, buf)
def __init__(self, msgType=None, chunkType=None, channelid=0)
def __init__(self, security_policy, body=b'', msg_type=MessageType.SecureMessage, chunk_type=ChunkType.Single)
def message_to_chunks(security_policy, body, max_chunk_size, message_type=MessageType.SecureMessage, channel_id=1, request_id=1, token_id=1)


ros_opcua_impl_python_opcua
Author(s): Denis Štogl , Daniel Draper
autogenerated on Tue Jan 19 2021 03:12:44