/src/S2OPC/src/PubSub/subscriber/sopc_reader_layer.c
Line | Count | Source |
1 | | /* |
2 | | * Licensed to Systerel under one or more contributor license |
3 | | * agreements. See the NOTICE file distributed with this work |
4 | | * for additional information regarding copyright ownership. |
5 | | * Systerel licenses this file to you under the Apache |
6 | | * License, Version 2.0 (the "License"); you may not use this |
7 | | * file except in compliance with the License. You may obtain |
8 | | * a copy of the License at |
9 | | * |
10 | | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | | * |
12 | | * Unless required by applicable law or agreed to in writing, |
13 | | * software distributed under the License is distributed on an |
14 | | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
15 | | * KIND, either express or implied. See the License for the |
16 | | * specific language governing permissions and limitations |
17 | | * under the License. |
18 | | */ |
19 | | |
20 | | #include "sopc_reader_layer.h" |
21 | | |
22 | | #include "sopc_assert.h" |
23 | | #include "sopc_dataset_ll_layer.h" |
24 | | #include "sopc_logger.h" |
25 | | #include "sopc_macros.h" |
26 | | #include "sopc_network_layer.h" |
27 | | #include "sopc_pubsub_helpers.h" |
28 | | |
29 | | /** |
30 | | * Filter at NetworkMessage Level |
31 | | * |
32 | | */ |
33 | | static inline bool SOPC_Sub_Filter_Reader_PublisherId(const SOPC_Conf_PublisherId* conf_pubid, |
34 | | const SOPC_Dataset_LL_PublisherId* nm_pubid); |
35 | | |
36 | | static bool SOPC_Sub_Filter_Reader_FieldMetaData(const SOPC_DataSetReader* reader, |
37 | | const SOPC_Dataset_LL_DataSetMessage* dsm); |
38 | | /** \brief |
39 | | * Identify a reader in connection matching received parameters |
40 | | * \param connection The connection configuration |
41 | | * \param uadp_conf The received message configuration |
42 | | * \param pubid The Publisher Id received |
43 | | * \param groupVersion The GroupVersion received |
44 | | * \param groupId The GroupId received |
45 | | * \return the reader group, or NULL if no matching group found |
46 | | */ |
47 | | static const SOPC_ReaderGroup* SOPC_Sub_GetReaderGroup(const SOPC_PubSubConnection* connection, |
48 | | const SOPC_UADP_Configuration* uadp_conf, |
49 | | const SOPC_Dataset_LL_PublisherId* pubid, |
50 | | const uint32_t groupVersion, |
51 | | const uint32_t groupId); |
52 | | |
53 | | /** \brief |
54 | | * Identify a reader in a group matching received parameters in nm |
55 | | * \param group The group configuration |
56 | | * \param uadp_conf The received message configuration |
57 | | * \param writerId The received dataset writerId |
58 | | * |
59 | | * \return the dataset reader, or NULL if no matching reader found |
60 | | */ |
61 | | static const SOPC_DataSetReader* SOPC_Sub_GetReader(const SOPC_ReaderGroup* group, |
62 | | const SOPC_UADP_Configuration* uadp_conf, |
63 | | const uint16_t writerId); |
64 | | |
65 | | /** \brief |
66 | | * Received a DSM and applies changes to target variables. |
67 | | * \pre Groups & Writer Id must have been checked prior to call. |
68 | | * \param dsm The received DataSetMesasge |
69 | | * \param uadp_conf The received message configuration |
70 | | * \param reader DataSetReader associated to this dsm |
71 | | * \param targetVariable ::SOPC_TargetVariableCtx to provide to user |
72 | | * |
73 | | * \return ::SOPC_STATUS_OK if success, ::SOPC_STATUS_ENCODING otherwise |
74 | | */ |
75 | | static SOPC_ReturnStatus SOPC_Sub_ReceiveDsm(SOPC_Dataset_LL_DataSetMessage* dsm, |
76 | | SOPC_SubTargetVariableConfig* config, |
77 | | const SOPC_DataSetReader* reader, |
78 | | SOPC_TargetVariableCtx* targetVariable); |
79 | | |
80 | | const SOPC_UADP_NetworkMessage_Reader_Callbacks SOPC_Reader_NetworkMessage_Default_Readers = { |
81 | | .pGetGroup_Func = &SOPC_Sub_GetReaderGroup, |
82 | | .pGetReader_Func = &SOPC_Sub_GetReader, |
83 | | .pSetDsm_Func = &SOPC_Sub_ReceiveDsm}; |
84 | | |
85 | | SOPC_NetworkMessage_Error_Code SOPC_Reader_Read_UADP(const SOPC_PubSubConnection* connection, |
86 | | SOPC_Buffer* buffer, |
87 | | SOPC_SubTargetVariableConfig* config, |
88 | | SOPC_UADP_GetSecurity_Func securityCBck, |
89 | | SOPC_UADP_UpdateTimeout_Func updateTimeoutCBck, |
90 | | SOPC_UADP_GetTargetVariable_Func targetVariableCBck, |
91 | | SOPC_UADP_IsWriterSequenceNumberNewer_Func snCBck) |
92 | 0 | { |
93 | 0 | SOPC_NetworkMessage_Error_Code errorCode = SOPC_NetworkMessage_Error_Code_None; |
94 | 0 | const SOPC_UADP_NetworkMessage_Reader_Configuration readerConf = { |
95 | 0 | .pGetSecurity_Func = securityCBck, |
96 | 0 | .callbacks = SOPC_Reader_NetworkMessage_Default_Readers, |
97 | 0 | .updateTimeout_Func = updateTimeoutCBck, |
98 | 0 | .targetVariable_Func = targetVariableCBck, |
99 | 0 | .checkDataSetMessageSN_Func = snCBck, |
100 | 0 | .targetConfig = config}; |
101 | 0 | SOPC_UADP_NetworkMessage* uadp_nm = NULL; |
102 | 0 | errorCode = SOPC_UADP_NetworkMessage_Decode(buffer, &readerConf, connection, &uadp_nm); |
103 | |
|
104 | 0 | if (NULL == uadp_nm) |
105 | 0 | { |
106 | | /* TODO: have a more resilient behavior and avoid stopping the subscriber because of |
107 | | * random bytes found on the network */ |
108 | 0 | return errorCode; |
109 | 0 | } |
110 | | |
111 | 0 | SOPC_UADP_NetworkMessage_Delete(uadp_nm); |
112 | 0 | return errorCode; |
113 | 0 | } |
114 | | |
115 | | static const SOPC_ReaderGroup* SOPC_Sub_GetReaderGroup(const SOPC_PubSubConnection* connection, |
116 | | const SOPC_UADP_Configuration* uadp_conf, |
117 | | const SOPC_Dataset_LL_PublisherId* pubid, |
118 | | const uint32_t groupVersion, |
119 | | const uint32_t groupId) |
120 | 7.27k | { |
121 | 7.27k | SOPC_ASSERT(NULL != connection && uadp_conf != NULL); |
122 | | // Find a matching ReaderGroup in connection |
123 | 7.27k | const uint16_t nbReaderGroup = SOPC_PubSubConnection_Nb_ReaderGroup(connection); |
124 | | |
125 | 7.27k | SOPC_ReaderGroup* result = NULL; |
126 | | |
127 | 14.8k | for (uint16_t i = 0; i < nbReaderGroup && NULL == result; i++) |
128 | 7.60k | { |
129 | 7.60k | bool match = true; |
130 | 7.60k | SOPC_ReaderGroup* readerGroup = SOPC_PubSubConnection_Get_ReaderGroup_At(connection, i); |
131 | 7.60k | SOPC_ASSERT(NULL != readerGroup); |
132 | | |
133 | 7.60k | if (uadp_conf->GroupVersionFlag) |
134 | 77 | { |
135 | | // Check group version |
136 | 77 | const uint32_t confVersion = SOPC_ReaderGroup_Get_GroupVersion(readerGroup); |
137 | | |
138 | 77 | match &= (groupVersion == confVersion) || (0 == confVersion); |
139 | 77 | } |
140 | | |
141 | 7.60k | if (match && uadp_conf->GroupIdFlag) |
142 | 40 | { |
143 | | // Check group Id |
144 | 40 | const uint16_t confGroupId = SOPC_ReaderGroup_Get_GroupId(readerGroup); |
145 | | |
146 | 40 | match &= (confGroupId == groupId) || (0 == confGroupId); |
147 | 40 | } |
148 | | |
149 | 7.60k | if (match && uadp_conf->PublisherIdFlag) |
150 | 541 | { |
151 | | // Check PublisherIdFlag |
152 | 541 | const SOPC_Conf_PublisherId* expPubId = SOPC_ReaderGroup_Get_PublisherId(readerGroup); |
153 | 541 | match &= SOPC_Sub_Filter_Reader_PublisherId(expPubId, pubid); |
154 | 541 | } |
155 | 7.60k | if (match) |
156 | 7.21k | { |
157 | 7.21k | result = readerGroup; |
158 | 7.21k | } |
159 | 7.60k | } |
160 | 7.27k | return result; |
161 | 7.27k | } |
162 | | |
163 | | static const SOPC_DataSetReader* SOPC_Sub_GetReader(const SOPC_ReaderGroup* group, |
164 | | const SOPC_UADP_Configuration* uadp_conf, |
165 | | const uint16_t writerId) |
166 | 11.1k | { |
167 | 11.1k | SOPC_ASSERT(NULL != group && uadp_conf != NULL); |
168 | | // Find a matching reader in group |
169 | 11.1k | const SOPC_DataSetReader* result = NULL; |
170 | 11.1k | const uint16_t nbReaders = SOPC_ReaderGroup_Nb_DataSetReader(group); |
171 | | |
172 | 22.3k | for (uint8_t i = 0; i < nbReaders && NULL == result; i++) |
173 | 11.1k | { |
174 | | // Find matching WriterId |
175 | 11.1k | const SOPC_DataSetReader* reader = SOPC_ReaderGroup_Get_DataSetReader_At(group, i); |
176 | 11.1k | const uint16_t readerWriterId = SOPC_DataSetReader_Get_DataSetWriterId(reader); |
177 | | |
178 | 11.1k | if (writerId == readerWriterId && writerId != 0) |
179 | 7.43k | { |
180 | 7.43k | result = reader; |
181 | 7.43k | } |
182 | 11.1k | } |
183 | 11.1k | return result; |
184 | 11.1k | } |
185 | | |
186 | | static SOPC_ReturnStatus SOPC_Sub_ReceiveDsm(SOPC_Dataset_LL_DataSetMessage* dsm, |
187 | | SOPC_SubTargetVariableConfig* targetConfig, |
188 | | const SOPC_DataSetReader* reader, |
189 | | SOPC_TargetVariableCtx* targetVariable) |
190 | 379 | { |
191 | 379 | SOPC_ASSERT(NULL != dsm && NULL != reader); |
192 | 379 | SOPC_ReturnStatus result = SOPC_STATUS_ENCODING_ERROR; |
193 | 379 | const SOPC_DataSet_LL_UadpDataSetMessageContentMask* conf = SOPC_Dataset_LL_DataSetMsg_Get_ContentMask(dsm); |
194 | 379 | if (DataSet_LL_MessageType_KeepAlive == conf->dataSetMessageType) |
195 | 160 | { |
196 | | // In case of keep alive message, dataSetMessage is sent without payload so possibly-remaining payload won't be |
197 | | // parsed |
198 | 160 | result = SOPC_STATUS_OK; |
199 | 160 | } |
200 | 219 | else |
201 | 219 | { |
202 | 219 | if (SOPC_Sub_Filter_Reader_FieldMetaData(reader, dsm)) |
203 | 95 | { |
204 | 95 | bool write_succes = (targetConfig == NULL || |
205 | 0 | SOPC_SubTargetVariable_SetVariables(targetConfig, targetVariable, reader, dsm)); |
206 | 95 | if (write_succes) |
207 | 95 | { |
208 | 95 | result = SOPC_STATUS_OK; |
209 | 95 | } |
210 | 95 | } |
211 | 219 | } |
212 | 379 | return result; |
213 | 379 | } |
214 | | |
215 | | static bool SOPC_Sub_Filter_Reader_PublisherId(const SOPC_Conf_PublisherId* conf_pubid, |
216 | | const SOPC_Dataset_LL_PublisherId* nm_pubid) |
217 | 541 | { |
218 | 541 | SOPC_ASSERT(NULL != conf_pubid && NULL != nm_pubid); |
219 | 541 | int32_t match = -1; |
220 | 541 | switch (conf_pubid->type) |
221 | 541 | { |
222 | 0 | case SOPC_String_PublisherId: |
223 | | // First check if received pubId is also a string publisher Id |
224 | 0 | if (DataSet_LL_PubId_String_Id == nm_pubid->type) |
225 | 0 | { |
226 | 0 | SOPC_ReturnStatus status = |
227 | 0 | SOPC_String_Compare(&conf_pubid->data.string, &nm_pubid->data.string, false, &match); |
228 | 0 | SOPC_ASSERT(SOPC_STATUS_OK == status); |
229 | 0 | } |
230 | 0 | return 0 == match; |
231 | 271 | case SOPC_UInteger_PublisherId: |
232 | 271 | { |
233 | 271 | uint64_t nm_pubid64; |
234 | | |
235 | 271 | switch (nm_pubid->type) |
236 | 271 | { |
237 | 156 | case DataSet_LL_PubId_Byte_Id: |
238 | 156 | nm_pubid64 = nm_pubid->data.byte; |
239 | 156 | break; |
240 | 26 | case DataSet_LL_PubId_UInt16_Id: |
241 | 26 | nm_pubid64 = nm_pubid->data.uint16; |
242 | 26 | break; |
243 | 26 | case DataSet_LL_PubId_UInt32_Id: |
244 | 26 | nm_pubid64 = nm_pubid->data.uint32; |
245 | 26 | break; |
246 | 63 | case DataSet_LL_PubId_UInt64_Id: |
247 | 63 | nm_pubid64 = nm_pubid->data.uint64; |
248 | 63 | break; |
249 | 0 | default: |
250 | 0 | return false; |
251 | 271 | } |
252 | | |
253 | 271 | return conf_pubid->data.uint == nm_pubid64; |
254 | 271 | } |
255 | 270 | case SOPC_Null_PublisherId: |
256 | | // if there is no expected publisher id, this filter is passed |
257 | 270 | return true; |
258 | 0 | default: |
259 | 0 | return false; |
260 | 541 | } |
261 | 541 | } |
262 | | |
263 | | static bool SOPC_Sub_Filter_Reader_FieldMetaData(const SOPC_DataSetReader* reader, |
264 | | const SOPC_Dataset_LL_DataSetMessage* dsm) |
265 | 219 | { |
266 | 219 | uint16_t datasetFieldsNb = SOPC_Dataset_LL_DataSetMsg_Nb_DataSetField(dsm); |
267 | | |
268 | 219 | bool result = datasetFieldsNb == SOPC_DataSetReader_Nb_FieldMetaData(reader); |
269 | | |
270 | 718 | for (uint16_t i = 0; result && i < datasetFieldsNb; i++) |
271 | 499 | { |
272 | | // Get field config |
273 | 499 | SOPC_FieldMetaData* fmd = SOPC_DataSetReader_Get_FieldMetaData_At(reader, i); |
274 | | // Get field value in message |
275 | 499 | const SOPC_Variant* variant = SOPC_Dataset_LL_DataSetMsg_Get_ConstVariant_At(dsm, i); |
276 | | |
277 | 499 | result = SOPC_PubSubHelpers_IsCompatibleVariant(fmd, variant, NULL); |
278 | 499 | } |
279 | | |
280 | 219 | return result; |
281 | 219 | } |