Модулі "OPC-UA", підсистем "Збір даних" та "Транспортні протоколи"
Параметр
Модуль 1
Модуль 2
Бібліотека
ID:
OPC_UA
OPC_UA
libOPC_UA
Ім'я:
Клієнт OPC-UA
Сервер OPC-UA
Бібліотека реалізації OPC-UA у OpenSCADA
Тип:
Збір Даних
Протокол
Бібліотека
Джерело:
daq_OPC_UA.so
daq_OPC_UA.so
libOPC_UA.{h,cpp}
Версія:
1.6.2
1.6.6
1.0.1
Автор:
Роман Савоченко
Опис:
Надає реалізацію OPC-UA клієнтського сервісу.
Надає реалізацію OPC-UA сервісу серверу.
Надає реалізацію протоколу OPC-UA в частині клієнта та серверу, у вигляді окремої бібліотеки.
Ліцензія:
GPL2
GPL2
LGPL3
Вступ
OPC (OLE for Process Control) — це сімейство протоколів та технологій, які надають єдиний інтерфейс для управління об'єктами автоматизації та технологічними процесами. Створення та підтримку специфікацій OPC координує міжнародна некомерційна організація OPC Foundation, яку створено у 1994 році провідними виробниками засобів промислової автоматизації.
У зв'язку з тим, що значний вплив у організації OPC Foundation має корпорація Microsoft, протоколи OPC до останнього часу були одноплатформними та закритими, з причини прив'язки до закритих технологій MS Windows. Однак, із недавніх пір, організацією OPC Foundation були створені такі багатоплатформні рішення, як OPC XML-DA та OPC-UA. Найбільший інтерес із них представляє OPC-UA, як уніфікуючий всі протоколи ранніх версій у межах відкритих та багатоплатформних технологій.
Цей модуль реалізує підтримку інтерфейсу та протоколу OPC-UA як у вигляді клієнтського сервісу, так і у вигляді серверу OPC-UA. Клієнтський сервіс OPC-UA реалізується однойменним модулем підсистеми "Збір даних", а сервер реалізується модулем підсистеми "Протоколи". Весь код реалізації цим модулем специфіки протоколу OPC-UA було винесено, за проханням користувачів, у окрему бібліотеку, яка розповсюджується під ліцензією LGPL3.
У поточній версії цих модулів та бібліотеки реалізуються бінарна частина протоколу та базові сервіси у небезпечному режимі та безпечних режимах політик "Base128Rsa15" та "Base256". Надалі планується розширення модуля для роботи через HTTP/SOAP та реалізації решти сервісів OPC-UA, за потребою.
Хоча протокол OPC-UA і є багатоплатформним, його специфікація та SDK не є вільно-доступними, а надаються тільки членам організації OPC Foundation. З цієї причини реалізація даних модулів зіткнулася зі значними перепонами та проблемами.
По перше, протокол OPC-UA складний та реалізація його взагалі без специфікації дуже працемістке. З цієї причини роботи над даними модулями тривалий час не починалися, та тільки завдяки спонсорської допомоги однієї із організацій-члену OPC Foundation проект OpenSCADA отримав документацію специфікації. При цьому SDK та вихідні тексти ANSIС-API протоколу OPC-UA отримано не було з причини несумісності їх ліцензії із GPL та, як наслідок, потенційної загрози порушення ліцензії при роботі із вихідними текстами, що могло призвести до подальших юридичних проблем при вільному розповсюджені цих модулів.
По друге, навіть наявність специфікації не дозволяє вирішити низку технічних питань без прикладів реалізації та можливості перевірки на робочому прототипі клієнта та сервера OPC-UA. Наприклад, саме технічні особливості реалізації алгоритмів симетричного шифрування та отримання ключів для них не дозволили реалізувати підтримку політик безпеки одразу.
Для налагодження функціювання модулів використовувалося демонстраційне ПО фірми Unified Automation, у складі OPC-UA клієнту — UAExpert та серверу — "OPC-UA Demo Server", із пакету SDK. У зв'язку із постійним розвитком самого клієнту "UAExpert", у плані інтерпретації специфікації OPC-UA, нові його версії часто мають проблеми при роботі із сервером OPC-UA від OpenSCADA. В цілому результати сумісності роботи із клієнтами та серверами різних виробників можна отримати у додатку.
1. Протокол OPC-UA
OPC-UA — це платформо-незалежний стандарт, за допомогою якого системи та пристрої різного типу можуть взаємодіяти шляхом відправки повідомлень між клієнтом та сервером через різноманітні типи мереж. Протокол підтримує безпечну взаємодію шляхом валідації клієнтів та серверів, а також протидії атакам. OPC-UA визначає поняття Сервіси, які сервери можуть надавати, а також сервіси, які сервер підтримує для клієнту. Інформація передається у вигляді типів даних, визначених OPC-UA та виробником, крім того сервера визначають об'єктну модель, для якої клієнти можуть здійснювати динамічний огляд.
OPC-UA надає поєднання інтегрованого адресного простору та сервісної моделі. Це дозволяє серверу інтегрувати дані, порушення (Alarms), повідомлень (Events) та історію у цьому адресному просторі, а також надавати доступ до них за посередництвом інтегрованих сервісів. Сервіси також надають інтегровану модель безпеки.
OPC-UA дозволяє серверам надавати для клієнтів визначення типів, для доступу до об'єктів із адресного простору. OPC-UA допускає надання даних у різних форматах, включаючи бінарні структури та XML-документи. Через адресний простір клієнти можуть запитати у сервера метадані, які описують формат даних.
OPC-UA додає підтримку множинної зв'язності між вузлами замість простого обмеження ієрархічністю. Така гнучкість у комбінації із визначенням типів дозволяє застосовувати OPC-UA для вирішення задач у широкій проблемній області.
OPC-UA спроектовано для забезпечення надійної видачі даних. Основна особливість всіх OPC серверів — спроможність видавати данні та повідомлення.
OPC-UA спроектовано для підтримки широкого діапазону серверів, від простіших ПЛК до промислових серверів. Ці сервери характеризуються широким спектром розмірів, продуктивності, платформ виконання та функційної ємкості. Відтак, OPC-UA визначає вичерпну множину можливостей, та сервер може імплементувати підмножини цих можливостей. Для забезпечення сумісності OPC-UA визначає підмножини, іменовані Профілями, які сервери можуть вказувати для погодження. Клієнти можуть згодом виконувати огляд профілів серверу та прокидати взаємодію із сервером, основаним на профілях.
OPC-UA специфікація спроектована як ядро у шарі, ізольованому від підлеглих комп'ютерних технологій та мережевих транспортів. Це дозволяє OPC-UA при потребі розширятися на майбутні технології без відторгнення основи дизайну. На цей час специфікацією визначено два способи кодування даних: XML/text та UA Binary. Додатково, визначено два типи транспортного шару: TCP та HTTP/SOAP.
OPC-UA спроектовано як рішення для міграції із OPC клієнтів та серверів, які основані на Microsoft COM технологіях. OPC COM сервери (DA, HDA та A&E) можуть бути легко віддзеркалені у OPС-UA. Виробники можуть самостійно здійснювати таку міграцію або ж рекомендувати користувачам використовувати обгортки та конвертори між цими протоколами. OPC-UA уніфікує попередні моделі у єдиному адресному просторі з єдиною множиною сервісів.
2. Модуль реалізації серверу
Модуль серверу містить код реалізації серверної частини OPC-UA — серверних сервісів, у частині специфічній для OpenSCADA, та використовуючи бібліотеку для OPC-UA специфічної частини. Для побудови OPC-UA серверу достатньо створити вхідний транспорт, за звичай це TCP-транспорт модуля Sockets, та обрати в ньому модуль даного протоколу, а також сконфігурувати хоча б один кінцевий вузол модуля протоколу, про що нижче.
2.1. Обслуговування запитів по протоколу OPC-UA
Вхідні запити до модуля-протоколу обробляються модулем у відповідності зі сконфігурованими кінцевими вузлами OPC-UA (EndPoints) (рис.1).
Рис.1. Кінцеві вузли протоколу.
Кінцевий вузол протоколу OPC-UA це фактично об'єкт серверу OPC-UA. Кінцеві вузли у OPC-UA можуть бути як локальними, так і віддаленими. Локальний кінцевий вузол призначено для надання ресурсів станції OpenSCADA за протоколом OPC-UA, в той-же час віддалені кінцеві вузли слугують для виконання як сервісу огляду доступних OPC-UA вузлів, так і для шлюзування запитів до віддалених станцій. У цій версії модуля підтримується тільки конфігурація локальних кінцевих вузлів.
Загальна конфігурація кінцевого вузла здійснюється на головній вкладці сторінки кінцевого вузла (рис.2) параметрами:
Стан вузла, а саме: статус, "Включено" та ім'я БД, яка містить конфігурацію.
Ідентифікатор, Ім'я та опис вузла.
Стан, у який переводити вузол при завантажені: "Включено".
Тип кодування протоколу. На цей час це тільки "Бінарний".
URL кінцевої точки.
Сертифікат серверу у форматі PEM.
Приватний ключ у форматі PEM.
Політики безпеки серверу.
Рис.2. Головна вкладка сторінки кінцевого вузла.
3. Модуль збору даних
Модуль збору даних надає можливість опитування та запису атрибутів значення(13) вузлів типу "Змінна".
3.1. Об'єкт контролеру даних
Для додання джерела даних OPC-UA створюється та конфігурується об'єкт контролеру у системі OpenSCADA. Приклад вкладки конфігурації об'єкту контролеру даного типу зображено на рисунку 3.
Рис.3. Вкладка конфігурації об'єкту контролера.
За допомогою цієї вкладки можна встановити:
Стан контролеру, а сам: Статус, "Включено", Запущено" та ім'я БД, яка містить конфігурацію.
Ідентифікатор, ім'я та опис контролеру.
Стан, в який переводити контролер при завантажені: "Включено" та "Запущено".
Ім'я таблиці для збереження конфігурації параметрів контролеру.
Політика планування та пріоритет задачі збору даних.
Період синхронізації конфігурації атрибутів параметрів з віддаленою станцією, а також час повтору спроб відновлення підключення.
URL кінцевого вузла віддаленої станції — сервера OPC-UA. На початку цю адресу можна вказати у вигляді "opc.tcp://{IP|name}:{port}", після чого, у випадку включення об'єкту контролера та наявності вказаного OPC-UA вузла, з'явиться можливість обрати уточнену адресу.
Часто зустрічається ситуація, коли уточнена адреса є символьною, який у цій мережі не резолвиться, через некоректне налаштування серверу. У таких випадках потрібно залишити початкову IP-адресу або ім'я яке резолвиться у IP правильно.
Політика безпеки та режим безпеки повідомлення.
Сертифікат клієнту та приватний ключ у форматі PEM.
Користувач та пароль для аутентифікації на сервері. Порожнє значення включає анонімний доступ.
Обмеження кількості атрибутів у параметрі.
З метою полегшення ідентифікації вузлів на віддаленій станції, а також вибору їх для вставки у об'єкті параметру контролеру, в самому об'єкту контролеру передбачено вкладку навігації за вузлам віддаленої станції "Огляд вузлів серверу", де можна пройтися за деревом об'єктів та ознайомитися з їх атрибутами (рис.4).
Модуль збору даних надає лише один тип параметрів — "Стандарт". Додатковим конфігураційним полем параметру даного модуля (рис.5) є перелік вузлів OPC-UA та поле навігації за вузлами OPC-UA у один рядок, для вставки обраних вузлів типу "Змінна" до визначеного переліку. Атрибут у цьому переліку записується наступним чином: {ns}:{id}.
Де:
ns — простір імен, числом; нульове значення може бути опущено; id — ідентифікатор вузла, числом, рядком, рядком байт або GUID.
Приклади:
84 — кореневий вузол; 3:"BasicDevices2" — вузол базових пристроїв у просторі імен 3 та у вигляді рядка; 4:"61626364" — вузол у просторі імен 4 та у вигляді рядка байт; 4:{40d95ab0-50d6-46d3-bffd-f55639b853d4} — вузол у просторі імен 4 і у вигляді GUID.
Рис.5. Вкладка конфігурації об'єкту параметра.
Вузли типу "Змінна" зі значенням у вигляді структури прочитати цілком зазвичай не можна тому потрібно її елементи вставляти до переліку вузлів читання окремо.
У відповідності із вказаним переліком вузлів виконується опитування та створення атрибутів параметру (рис.6).
Рис.6. Вкладка атрибутів параметру.
4. Бібліотека libOPC_UA
Ґрунтуючись на напрацюваннях цього модуля протокольний код OPC-UA було винесено до окремої бібліотеки та опубліковано під ліцензією LGPLv3. Такі дії виконано з метою надати можливість простого додання підтримки протоколу OPC-UA стороннім проектам. Бібліотека представлена двома файлами libOPC_UA.h, libOPC_UA.cpp; підтримується та міститься у складі цього модуля, тобто останню версію Ви можете завантажити тут: http://oscada.org/svn/trunk/OpenSCADA/src/moduls/daq/OPC_UA/libOPC_UA.
Бібліотеку, як і цей модуль, написано на мові програмування C++. Статичну діаграму класів, яка відображає архітектуру бібліотеки, приведена на рисунку 7. Згідно діаграмі класів бібліотеку виконано у просторі імен "OPC", а архітектурно її можна поділити на клієнтську "Client" та серверну "Server" частини, які успадковані від загального класу протоколу "UA". Крім безпосередньо класів протоколу "OPC-UA" бібліотека включає в себе набір функцій та класів для обробки або збереження даних протоколу, окремо з яких треба відзначити клас вузла мови XML "XML_N", використаний для уніфікації звернень до API бібліотеки.
Рис.7. Статична діаграма класів бібліотеки libOPC_UA.
Використання бібліотеки, в цілому, полягає у спадкуванні класу "Client" та/або "Server", згідно із функціями кінцевої програми, та наступної реалізації віртуальних функцій властивостей клієнта/сервера, у контексті протоколу OPC-UA, а також транспортної частини комунікації, тобто підключення/відкриття до TCP-сокету та передачу/читання неструктурованого потоку даних. Наступні запити та обробка запитів даних (для серверу) здійснюється через виклик функції reqService(), запит до сервісу, та/або обробки віртуальної функції reqData() запиту до даних, тобто фактично інтеграція у модель даних додатку.
Розташувати тут посилання на API класів, на первинній мові — Англійській
4.1. Служебные объекты, функции и класс UA
Данные
Типы реализаций (enum — SerializerType):
ST_Binary = 0 — бинарный.
Тип запроса открытия канала безопасности (enum — SC_ReqTP):
SC_ISSUE = 0 — исходный;
SC_RENEW = 1 — обновляющий.
Режим безопасности сообщения (enum — MessageSecurityMode):
MS_None = 1 — без безопасности;
MS_Sign = 2 — подпись;
MS_SignAndEncrypt = 3 — подпись и шифрование;
Тип аутентификации (enum — AuthTp):
A_Anon = 0 — анонимно;
A_UserNm = 1 — Пользователь+пароль;
A_Cert = 2 — Сертификат.
Классы узлов (enum — NodeClasses):
NC_Object = 1 — объект;
NC_Variable = 2 — переменная;
NC_Method = 4 — метод;
NC_ObjectType = 8 — тип объекта;
NC_VariableType = 16 — тип переменной;
NC_ReferenceType = 32 — тип ссылки;
NC_DataType = 64 — тип данных;
NC_View = 128 — вид.
Направление обзора (enum — BrowseDirection):
BD_FORWARD = 0 — вперёд;
BD_INVERSE = 1 — назад;
BD_BOTH = 2 — вперёд и назад.
Возвратная метка времени (enum — TimestampsToReturn):
TS_SOURCE = 0 — источника;
TS_SERVER = 1 — сервера;
TS_BOTH = 2 — источника и сервера;
TS_NEITHER = 3 — отсутствует.
Доступ (enum — Access):
ACS_Read = 0x01 — чтение;
ACS_Write = 0x02 — запись;
ACS_HistRead = 0x04 — чтение истории;
ACS_HistWrite = 0x08 — запись истории;
ACS_SemChange = 0x10 — ?.
Элементы маски описания обзорного запроса (enum — RefDscrResMask):
RdRm_RefType = 0x01 — тип ссылки;
RdRm_IsForward = 0x02 — направление;
RdRm_NodeClass = 0x04 — класс узла;
RdRm_BrowseName = 0x08 — имя обзора;
RdRm_DisplayName = 0x10 — имя отображения;
RdRm_TypeDef = 0x20 — тип определения.
Атрибуты узла (enum — AttrIds):
Aid_Error = 0 — ошибка;
AId_NodeId = 1 — идентификатор узла;
AId_NodeClass = 2 — класс узла;
AId_BrowseName = 3 — имя обзора;
AId_DisplayName = 4 — имя отображения;
AId_Descr = 5 — описание;
AId_WriteMask = 6 — маска записи;
AId_UserWriteMask = 7 — маска записи пользователя;
AId_IsAbstract = 8 — абстрактность;
AId_Symmetric = 9 — симметричность;
AId_InverseName = 10 — инверсное имя;
AId_ContainsNoLoops = 11 — несодержание петлей;
AId_EventNotifier = 12 — уведомление событий;
AId_Value = 13 — значение;
AId_DataType = 14 — тип данных;
AId_ValueRank = 15 — ранг значения;
AId_ArrayDimensions = 16 — размерность массива;
AId_AccessLevel = 17 — уровень доступа;
AId_UserAccessLevel = 18 — уровень доступа пользователя;
В библиотеку включен ряд внешних функция объекта TSYS? ядра OpenSCADA, для упрощения и унификации ряда внутренних операций:
int64_t curTime( ); — Текущее время в микросекундах с начала эпохи (01.01.1970).
string int2str( int val ); — Преобразование целого знакового в строку, в десятичном представлении.
string uint2str( unsigned val ); — Преобразования целого беззнакового в строку, в десятичном представлении.
string ll2str( int64_t val ); — Преобразования длинного целого (64бит) в строку, в десятичном представлении.
string real2str( double val, int prec = 15, char tp = 'g' ); — Преобразования вещественного с точностью prec знаков и типом tp в строку.
string strParse( const string &path, int level, const string &sep, int *off = NULL, bool mergeSepSymb = false ); — Разбор строки path на составляющие, отделённые разделителем sep, объединяя односимвольные mergeSepSymb, начиная со смещения off и контролируя смещение конца элемента в нём же.
string strMess( const char *fmt, ... ); — Формирование стоки по шаблону fmt и аргументам. Реализован на основе "printf".
Ошибка OPC (OPCError)
Объект ошибки "OPCError" является урезанной копией объекта "TError" ядра OpenSCADA.
XML_N* childGet( const string &name, const int numb = 0, bool noex = false ) const; — Получение вложенного numb порядкового тега по имени тега name. noex указывает на запрет генерации исключения в случае отсутствия тега.
XML_N* childGet( const string &attr, const string &name, bool noex = false ) const; — Получение вложенного numb порядкового тега по значению name атрибута attr. noex указывает на запрет генерации исключения в случае отсутствия тега.
XML_N* getElementBy( const string &attr, const string &val ); — Поиск вложенного узла по значению val атрибута attr.
XML_N* parent( ); — Родительский тег данного тега.
NodeId( uint32_t in, uint16_t ins = 0 ); — Численный инициирующий конструктор, для числа in в области имён ins.
NodeId( const string &istr, uint16_t ins = 0, Type tp = String ); — Строковый инициирующий конструктор, для строки istr в области имён ins, со строковым типом tp.
static string iErr( const string &buf, int &off ); — чтение ошибки из потока buf по смещению off.
static const char *iVal( const string &buf, int &off, char vSz ); — чтение значения размером vSz, как участок данных, из потока buf по смещению off.
static int64_t iN( const string &rb, int &off, char vSz ); — чтение знакового целого размером vSz (1, 2, 4, 8) из потока rb по смещению off.
static uint64_t iNu( const string &rb, int &off, char vSz ); — чтение беззнакового целого размером vSz (1, 2, 4, 8) из потока rb по смещению off.
static double iR( const string &rb, int &off, char vSz = 4 ); — чтение вещественного размером vSz (4, 8) из потока rb по смещению off.
static string iS( const string &buf, int &off ); — чтение строки из потока buf по смещению off.
static string iSl( const string &buf, int &off, string *locale = NULL ); — чтение локализованной locale строки из потока buf по смещению off.
static string iSqlf( const string &buf, int &off, uint16_t *nsIdx = NULL ); — чтение строки с квалификатором nsIdx из потока buf по смещению off.
static int64_t iTm( const string &buf, int &off ); — чтение времени, с преобразованием в эпоху UNIX, из потока buf по смещению off.
static NodeId iNodeId( const string &buf, int &off ); — чтение идентификатора узла из потока buf по смещению off.
static void iDataValue( const string &buf, int &off, XML_N &nVal ); — чтение комплексного значения (структура DataValue) в nVal из потока buf по смещению off.
static void oN( string &buf, int64_t val, char sz, int off = -1 ); — запись знакового целого val размером sz (1, 2, 4, 8) в поток buf по смещению off.
static void oNu( string &buf, uint64_t val, char sz, int off = -1 ); — запись беззнакового целого val размером sz (1, 2, 4, 8) в поток buf по смещению off.
static void oR( string &buf, double val, char sz = 4 ); — запись вещественного val размером sz (1, 2, 4, 8) в поток buf по смещению off.
static void oS( string &buf, const string &val, int off = -1 ); — запись строки val в поток buf по смещению off.
static void oSl( string &buf, const string &val, const string &locale = "" ); — запись локализованной locale строки val в поток buf по смещению off.
static void oSqlf( string &buf, const string &val, uint16_t nsIdx = 0 ); — запись строки val с квалификатором nsIdx в поток buf по смещению off.
static void oTm( string &buf, int64_t val ); — запись времени val, в эпохе UNIX, в поток buf по смещению off.
static void oNodeId( string &buf, const NodeId &val ); — запись идентификатора узла val в поток buf по смещению off.
static void oRef( string &buf, uint32_t resMask, const NodeId &nodeId, const NodeId &refTypeId, bool isForward, const string &name, uint32_t nodeClass, const NodeId &typeDef ); — запись в поток buf описателя обзора (структура ReferenceDescription) для маски resMask, узла nodeId, типа ссылки refTypeId, направления isForward, имени name, класса узла nodeClass, типа определения typeDef.
void oDataValue( string &buf, uint8_t eMsk, const string &vl, uint8_t vEMsk = 0, int64_t srcTmStmp = 0 ); — запись комплексного значения (структура DataValue) в поток buf для маски кодирования eMsk, значения vl, маски значения vEMsk, времени источника srcTmStmp.
static string randBytes( int num ); — генерация потока случайных данных в количестве num.
static string certPEM2DER( const string &certPem ); — преобразование сертификата из формата PEM certPem в формат DER.
static string certDER2PEM( const string &certDer ); — преобразование сертификата из формата DER certDer в формат PER.
int chnlSet( int cid, const string &iEp, int32_t lifeTm = 0, const string& iClCert = "", const string &iSecPolicy = "None", char iSecMessMode = 1, const string &iclAddr = "", uint32_t iseqN = 1 ); — установка канала безопасности с идентификатором cid (ненулевое значение для обновления) для конечной точки iEp, времени жизни lifeTm, клиентского сертификата iClCert, политики безопасности iSecPolicy, режима безопасности сообщения iSecMessMode, адреса клиента iclAddr, номера последовательности пакета iseqN.
void chnlClose( int cid ); — закрытие канала безопасности cid.
SecCnl chnlGet( int cid ); SecCnl &chnlGet_( int cid ); — получение копии и доступа к объекту канала безопасности cid.
void chnlSecSet( int cid, const string &servKey, const string &clKey ); — установка для канала безопасности cid серверного servKey и клиентского clKey ключа.
static string mkError( uint32_t errId, const string &err = "" ); — формирование ошибки с идентификатором errId и сообщением err.
virtual EP *epEnAt( const string &ep ) = 0; — обработчик запроса объекта конечной точки.
Включенный объект канала безопасности (SecCnl)
Публичные методы:
SecCnl( const string &iEp, uint32_t iTokenId, int32_t iLifeTm, const string &iClCert, const string &iSecPolicy, char iSecMessMode, const string &iclAddr, uint32_t isecN ); — конструктор объекта канала безопасности для: конечной точки iEp, талона безопасности iTokenId, времени жизни iLifeTm, клиентского сертификата iClCert, политики безопасности iSecPolicy, режима безопасности сообщения iSecMessMode, адреса клиента iclAddr, номера последовательности создания канала безопасности isecN.
Публичные атрибуты:
string endPoint; — конечная точка;
string secPolicy; — политика безопасности;
char secMessMode; — режим безопасности сообщения;
int64_t tCreate; — время создание;
int32_t tLife; — время жизни;
uint32_t TokenId, TokenIdPrev; — текущий и предыдущий идентификаторы талона;
string clCert, clAddr; — сертификат и адрес клиента;
string servKey, clKey; — ключ сервера и клиента;
uint32_t seqN, startSeqN; — текущий и стартовый номер последовательности пакета создания канала.
Включенный объект сеанса (Sess)
Публичные методы:
Sess( const string &iName, double iTInact ); — конструктор объекта для имени iName и таймаута неактивности iTInact.
Публичные атрибуты:
string name, inPrtId, idPolicyId, user; — имя, идентификатор входящего протокола, идентификатор политики безопасности, и пользователь;
Включенный объект точки продолжения обзора (ContPoint)
Публичные методы:
ContPoint( const string &i_brNode, const string &i_lstNode, uint32_t i_brDir, uint32_t i_refPerN, const string &i_refTypeId, uint32_t i_nClassMask, uint32_t i_resMask ) — конструктор объекта для узла ветви i_brNode, узла списка i_lstNode, направления обзора i_brDir, числа ссылок на узел i_refPerN, идентификатора ссылки i_refTypeId, маски класса узла i_nClassMask и маски результата i_resMask.
bool empty( ) const; — точка продолжения пуста.
Публичные атрибуты:
uint32_t brDir, refPerN, nClassMask, resMask; — направление обзора, число ссылок на узел, маска класса узла, маска результата;
string brNode, lstNode, refTypeId; — ветвь узлов, список узла и идентификатор типа ссылки.
Включенный объект подписки (Subscr)
Публичные методы:
Subscr copy( bool noWorkData = true ); — копия объекта подписки, без рабочих данных noWorkData.
SubScrSt setState( SubScrSt st = SS_CUR ); — установка состояния в st.
Публичные атрибуты:
SubScrSt st; — статус подписки;
int sess; — сеанс подписки;
bool en; — статус "Включен";
double publInterv; — интервал публикации (мс);
uint32_t seqN; — номер последовательности для ответов, заворачивается через 1, не инкрементируется на KeepAlive сообщениях;
uint32_t cntrLifeTime, wLT; — счётчик, по исчерпанию которого в течении отсутствия уведомления от клиента необходимо удалять данный объект;
uint32_t cntrKeepAlive, wKA; — счётчик, по исчерпанию которого нужно отправлять пустой ответ публикации и устанавливать StatusChangeNotification в Bad_Timeout;
uint32_t maxNotPerPubl; — максимальное количество уведомлений на один ответ публикации;
uint8_t pr; — приоритет;
vector<MonitItem> mItems; — перечень элементов мониторинга;
deque<string> retrQueue; — очередь перепосылки; используется запросом перепосылки (Republish); очищается на глубину согласно KeepAlive или прямым запросом в наборе подтверждения.
Включенный объект элемента мониторинга (MonitItem)
Публичные атрибуты:
MonitoringMode md; — режим мониторинга;
NodeId nd; — целевой узел;
uint32_t aid; — идентификатор атрибута узла;
TimestampsToReturn tmToRet; — метка времени для возврата;
double smplItv; — интервал измерений;
uint32_t qSz; — размер очереди;
bool dO; — отбрасывать старые;
uint32_t cH; — указатель клиента;
int vTp; — тип значений;
int64_t dtTm; — время последнего значения;
deque<Val> vQueue; — очередь значений.
Включенный объект элемента значения (Val)
Публичные методы:
Val( const string &ivl, int64_t itm ) — конструктор объекта значения ivl на время tm.
Публичные атрибуты:
string vl; — значение;
int64_t tm; — время значения.
Включенный объект конечной точки (EP)
Публичные методы:
EP( Server *serv ); — конструктор объекта, привязанного к серверу serv.
virtual double subscrProcPer( ) = 0; — общий минимальный период цикла публикации и обработки его данных;
virtual uint32_t limSubScr( ); — ограничение на количество подписок;
virtual uint32_t limMonitItms( ); — ограничение количества элементов мониторинга;
virtual uint32_t limRetrQueueTm( ); — ограничение времени на глубину очереди повторной передачи;
bool enableStat( ); — состояние "Включено";
virtual void setEnable( bool vl ); — установить во "Включено";
void subScrCycle( unsigned cntr ); — функция вызова цикла обработки подписок;
int secSize( ); — количество политик безопасности;
string secPolicy( int isec ); — получение описания политики безопасности isec;
MessageSecurityMode secMessageMode( int isec ); — режим безопасности сообщения политики безопасности isec;
int sessCreate( const string &iName, double iTInact ); — создание сеанса с именем iName и таймаутом неактивности iTInact, возвращает идентификатор сеанса;
void sessServNonceSet( int sid, const string &servNonce ); — установка последовательности безопасности сеанса sid сервера в servNonce;
virtual uint32_t sessActivate( int sid, uint32_t secCnl, bool check = false, const string &inPrtId = "", const XML_N &identTkn = XML_N() ); — активация сеанса sid для связывания с каналом безопасности secCnl, c проверкой check на возможность-необходимость переназначения, после разрыва предыдущего канала безопасности, возвращает ошибку (0 - ошибки нет);
void sessClose( int sid ); — закрытие сеанса sid;
Sess sessGet( int sid ); — получение экземпляра объекта сеанса для sid;
Sess::ContPoint sessCpGet( int sid, const string &cpId ); — получение точки продолжения браузинга cpId сеанса sid;
void sessCpSet( int sid, const string &cpId, const Sess::ContPoint &cp = Sess::ContPoint() ); — установка точки продолжения браузинга cp для сеанса sid и идентификатора cpId;
uint32_t subscrSet( uint32_t ssId, SubScrSt st, bool en = false, int sess = -1, double publInterv = 0, uint32_t cntrLifeTime = 0, uint32_t cntrKeepAlive = 0, uint32_t maxNotePerPubl = OpcUa_NPosID, int pr = -1 ); — установка-создание подписки ssId для: состояния st, включения en, сеанса sess, интервала публикации publInterv, счётчика времени жизни cntrLifeTime, счётчика сохранения "живым" cntrKeepAlive, максимального количества уведомлений в публикации maxNotePerPubl, приоритета pr;
Subscr subscrGet( uint32_t ssId, bool noWorkData = true ); — получение экземпляра подписки ssId, без рабочих данных noWorkData;
virtual uint32_t reqData( int reqTp, XML_N &req ); — обработчик запрос данных, запрос к дереву узлов сервера.
Защищённые методы:
XML_N *nodeReg( const NodeId &parent, const NodeId &ndId, const string &name, int ndClass, const NodeId &refTypeId, const NodeId &typeDef = 0 ); — регистрация узла ndId в дереве узлов сервера для: родителя parent, класса узла ndClass, идентификатора типа ссылки refTypeId и типа определения typeDef;
Sess *sessGet_( int sid ); — получение ссылки на объект сеанса, доступ не защищён захватом ресурса.
Защищённые атрибуты:
char mEn; — состояние "Включен";
uint64_t cntReq; — счётчик запросов;
vector<SecuritySetting> mSec; — перечень политик безопасности конечного узла;
vector<Sess> mSess; — перечень открытых сеансов;
vector<Subscr> mSubScr; — перечень подписок;
XML_N objTree; — дерево узлов сервера;
map<string, XML_N*> ndMap; — карта ссылок на узлы дерева;
pthread_mutex_t> mtxData; — мютекс для блокирования многопоточного доступа;
Server *serv; — ссылка на сервер, контейнер объекта конечной точки.
5. Приватні ключі та сертифікати
Для роботи клієнтської та протокольної частини OPC-UA потрібно створення та розташування приватного ключа та сертифікату у конфігурації об'єкту клієнта та сервера. У загальному випадку достатньо створення звичайного самопідписаного сертифікату та приватного ключа без пароля, однак для виключення попереджувальних повідомлень потрібно додати низку службових полів до сертифікату. Це можна зробити взявши файл конфігурації створення сертифікату та виконати наступну процедуру:
6. Зауваження
У процесі реалізації модулів підтримки OPC-UA було виявлено низку невідповідностей офіційного SDK зі специфікацією OPC-UA:
OPC-UA Part 6 на сторінці 27 містить зображення процесу рукостискання для встановлення безпечного каналу. Пакет створення сесії, виходячи із цього процесу, підписується клієнтським симетричним ключем, а кодування серверним. На справді і підпис і шифрування здійснюється серверним ключем.
OPC-UA Part 4 на сторінці 141 містить опис структури даних підпису, де перший йдуть дані підпису, а потім рядок алгоритму. На справді реалізовано зворотня послідовність.
7. Додаток: Таблиця сумісності із реалізаціями OPC-UA інших виробників
Розташувати тут посилання на таблицю, на первинній мові — Англійській
Name and version
Tested compatibility
Notes
UAExpert 1.4 (client)
Browse, Read, Write, Publish
Stopped for publish about 20 seconds by wrong process an event filter rejecting of OpenSCADA, mostly for Status. Needs to implement into OpenSCADA the event's filters support.
kepware
Browse, Read, Publish
Specific value types OpcUa_IntAuto and OpcUa_UIntAuto for adaptive integer type selection, mostly for provide integer not fixed as int64.
B&R Embedded OPC-UA Server
Browse, Read
Fix the authenticate process by the server provides self specific identifiers to its. Fix the string of bytes wrong interpretation.
Wonderware System Platform (client)
Browse, Read, Publish
Strange error by the client "Incorrect information" for OpenSCADA "Variable" type nodes browse try. Not resolved yet.