Quellcode durchsuchen

make de/encoding reentrant; improve docs

Julius Pfrommer vor 7 Jahren
Ursprung
Commit
b3c82e8fd1
2 geänderte Dateien mit 85 neuen und 38 gelöschten Zeilen
  1. 41 22
      src/ua_types_encoding_binary.c
  2. 44 16
      src/ua_types_encoding_binary.h

+ 41 - 22
src/ua_types_encoding_binary.c

@@ -98,17 +98,8 @@ static status
 exchangeBuffer(void) {
     if(!g_exchangeBufferCallback)
         return UA_STATUSCODE_BADENCODINGERROR;
-
-    /* Store context variables since exchangeBuffer might call UA_encode itself */
-    UA_exchangeEncodeBuffer store_exchangeBufferCallback = g_exchangeBufferCallback;
-    void *store_exchangeBufferCallbackHandle = g_exchangeBufferCallbackHandle;
-
-    status ret = g_exchangeBufferCallback(g_exchangeBufferCallbackHandle, &g_pos, &g_end);
-
-    /* Restore context variables */
-    g_exchangeBufferCallback = store_exchangeBufferCallback;
-    g_exchangeBufferCallbackHandle = store_exchangeBufferCallbackHandle;
-    return ret;
+    return g_exchangeBufferCallback(g_exchangeBufferCallbackHandle,
+                                    &g_pos, &g_end);
 }
 
 /*****************/
@@ -1432,17 +1423,31 @@ status
 UA_encodeBinary(const void *src, const UA_DataType *type,
                 u8 **bufPos, const u8 **bufEnd,
                 UA_exchangeEncodeBuffer exchangeCallback, void *exchangeHandle) {
+    /* Save global (thread-local) values to make UA_encodeBinary reentrant */
+    u8 *save_pos = g_pos;
+    const u8 *save_end = g_end;
+    UA_exchangeEncodeBuffer save_exchangeBufferCallback = g_exchangeBufferCallback;
+    void *save_exchangeBufferCallbackHandle = g_exchangeBufferCallbackHandle;
+
     /* Set the (thread-local) pointers to save function arguments */
     g_pos = *bufPos;
     g_end = *bufEnd;
     g_exchangeBufferCallback = exchangeCallback;
     g_exchangeBufferCallbackHandle = exchangeHandle;
+
+    /* Encode */
     status ret = UA_encodeBinaryInternal(src, type);
 
-    /* Set the current buffer position. Beware that the buffer might have been
-     * exchanged internally. */
+    /* Set the new buffer position for the output. Beware that the buffer might
+     * have been exchanged internally. */
     *bufPos = g_pos;
     *bufEnd = g_end;
+
+    /* Restore global (thread-local) values */
+    g_pos = save_pos;
+    g_end = save_end;
+    g_exchangeBufferCallback = save_exchangeBufferCallback;
+    g_exchangeBufferCallbackHandle = save_exchangeBufferCallbackHandle;
     return ret;
 }
 
@@ -1505,27 +1510,41 @@ status
 UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst,
                 const UA_DataType *type, size_t customTypesSize,
                 const UA_DataType *customTypes) {
-    /* Initialize the destination */
-    memset(dst, 0, type->memSize);
+    /* Save global (thread-local) values to make UA_decodeBinary reentrant */
+    size_t save_customTypesArraySize = g_customTypesArraySize;
+    const UA_DataType * save_customTypesArray = g_customTypesArray;
+    u8 *save_pos = g_pos;
+    const u8 *save_end = g_end;
 
-    /* Store the pointers to the custom datatypes. They might be needed during
-     * decoding of variants. */
+    /* Global pointers to the custom datatypes. */
     g_customTypesArraySize = customTypesSize;
     g_customTypesArray = customTypes;
 
-    /* Set the (thread-local) position and end pointers to save function
-     * arguments */
+    /* Global position pointers */
     g_pos = &src->data[*offset];
     g_end = &src->data[src->length];
 
+    /* Initialize the value */
+    memset(dst, 0, type->memSize);
+
     /* Decode */
     status ret = UA_decodeBinaryInternal(dst, type);
 
-    /* Clean up */
-    if(ret == UA_STATUSCODE_GOOD)
+    if(ret == UA_STATUSCODE_GOOD) {
+        /* Set the new offset */
         *offset = (size_t)(g_pos - src->data) / sizeof(u8);
-    else
+    } else {
+        /* Clean up */
         UA_deleteMembers(dst, type);
+        memset(dst, 0, type->memSize);
+    }
+
+    /* Restore global (thread-local) values */
+    g_customTypesArraySize = save_customTypesArraySize;
+    g_customTypesArray = save_customTypesArray;
+    g_pos = save_pos;
+    g_end = save_end;
+
     return ret;
 }
 

+ 44 - 16
src/ua_types_encoding_binary.h

@@ -11,35 +11,63 @@ extern "C" {
 
 #include "ua_types.h"
 
-typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_Byte **bufPos, const UA_Byte **bufEnd);
+typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_Byte **bufPos,
+                                                 const UA_Byte **bufEnd);
 
-/* Encode the data scalar (or structure) described by type in the binary
- * encoding.
+/* Encodes the scalar value described by type in the binary encoding. Encoding
+ * is thread-safe if thread-local variables are enabled. Encoding is also
+ * reentrant and can be safely called from signal handlers or interrupts.
  *
- * @param data Points to the data.
- * @param type Points to the type description.
- * @param buf_pos Points to a pointer to the current position in the encoding buffer.
- *        Must not be NULL. The pointer is advanced by the number of encoded bytes, or,
- *        if the buffer is exchanged, to the position in the new buffer.
- * @param buf_end Points to a pointer to the end of the encoding buffer (encoding always stops
- *        before *buf_end). Must not be NULL. The pointer is changed when the buffer is exchanged.
- * @param exchangeCallback Function that is called when the end of the encoding
- *        buffer is reached.
- * @param exchangeHandle Custom data passed intp the exchangeCallback.
+ * @param src The value. Must not be NULL.
+ * @param type The value type. Must not be NULL.
+ * @param bufPos Points to a pointer to the current position in the encoding
+ *        buffer. Must not be NULL. The pointer is advanced by the number of
+ *        encoded bytes, or, if the buffer is exchanged, to the position in the
+ *        new buffer.
+ * @param bufEnd Points to a pointer to the end of the encoding buffer (encoding
+ *        always stops before *buf_end). Must not be NULL. The pointer is
+ *        changed when the buffer is exchanged.
+ * @param exchangeCallback Called when the end of the buffer is reached. This is
+          used to send out a message chunk before continuing with the encoding.
+          Is ignored if NULL.
+ * @param exchangeHandle Custom data passed into the exchangeCallback.
  * @return Returns a statuscode whether encoding succeeded. */
 UA_StatusCode
 UA_encodeBinary(const void *src, const UA_DataType *type,
                 UA_Byte **bufPos, const UA_Byte **bufEnd,
-                UA_exchangeEncodeBuffer exchangeCallback, void *exchangeHandle) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+                UA_exchangeEncodeBuffer exchangeCallback,
+                void *exchangeHandle) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
 
+/* Decodes a scalar value described by type from binary encoding. Decoding
+ * is thread-safe if thread-local variables are enabled. Decoding is also
+ * reentrant and can be safely called from signal handlers or interrupts.
+ *
+ * @param src The buffer with the binary encoded value. Must not be NULL.
+ * @param offset The current position in the buffer. Must not be NULL. The value
+ *        is advanced as decoding progresses.
+ * @param dst The target value. Must not be NULL. The target is assumed to have
+ *        size type->memSize. The value is reset to zero before decoding. If
+ *        decoding fails, members are deleted and the value is reset (zeroed)
+ *        again.
+ * @param type The value type. Must not be NULL.
+ * @param customTypesSize The number of non-standard datatypes contained in the
+ *        customTypes array.
+ * @param customTypes An array of non-standard datatypes (not included in
+ *        UA_TYPES). Can be NULL if customTypesSize is zero.
+ * @return Returns a statuscode whether decoding succeeded. */
 UA_StatusCode
 UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst,
                 const UA_DataType *type, size_t customTypesSize,
                 const UA_DataType *customTypes) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
 
-size_t UA_calcSizeBinary(void *p, const UA_DataType *type);
+/* Returns the number of bytes the value p takes in binary encoding. Returns
+ * zero if an error occurs. UA_calcSizeBinary is thread-safe and reentrant since
+ * it does not access global (thread-local) variables. */
+size_t
+UA_calcSizeBinary(void *p, const UA_DataType *type);
 
-const UA_DataType *UA_findDataTypeByBinary(const UA_NodeId *typeId);
+const UA_DataType *
+UA_findDataTypeByBinary(const UA_NodeId *typeId);
 
 #ifdef __cplusplus
 }