A small memory footprint AMQP implimentation

Dependents:   iothub_client_sample_amqp remote_monitoring simplesample_amqp

Revision:
41:0e723f9cbd89
Parent:
38:7631b92cc772
Child:
43:4c1e4e94cdd3
--- a/connection.c	Mon Mar 05 17:41:28 2018 -0800
+++ b/connection.c	Tue Mar 20 10:29:38 2018 -0700
@@ -12,6 +12,7 @@
 
 #include "azure_uamqp_c/connection.h"
 #include "azure_uamqp_c/frame_codec.h"
+#include "azure_uamqp_c/amqpvalue.h"
 #include "azure_uamqp_c/amqp_frame_codec.h"
 #include "azure_uamqp_c/amqp_definitions.h"
 #include "azure_uamqp_c/amqpvalue_to_string.h"
@@ -73,6 +74,7 @@
     double idle_timeout_empty_frame_send_ratio;
     tickcounter_ms_t last_frame_received_time;
     tickcounter_ms_t last_frame_sent_time;
+    fields properties;
 
     unsigned int is_underlying_io_open : 1;
     unsigned int idle_timeout_specified : 1;
@@ -356,6 +358,22 @@
                 connection_set_state(connection, CONNECTION_STATE_END);
                 result = __FAILURE__;
             }
+            /* Codes_SRS_CONNECTION_01_243: [If no properties value has been specified, no value shall be stamped in the open frame (no call to open_set_properties shall be made).] */
+            else if ((connection->properties != NULL) &&
+                /* Codes_SRS_CONNECTION_01_244: [If properties has been specified by a call to connection_set_properties, then that value shall be stamped in the open frame.] */
+                (open_set_properties(open_performative, connection->properties) != 0))
+            {
+                LogError("Cannot set properties");
+
+                /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
+                if (xio_close(connection->io, NULL, NULL) != 0)
+                {
+                    LogError("xio_close failed");
+                }
+
+                connection_set_state(connection, CONNECTION_STATE_END);
+                result = __FAILURE__;
+            }
             else
             {
                 AMQP_VALUE open_performative_value = amqpvalue_create_open(open_performative);
@@ -1182,6 +1200,7 @@
                                 connection->endpoints = NULL;
                                 connection->header_bytes_received = 0;
                                 connection->is_remote_frame_received = 0;
+                                connection->properties = NULL;
 
                                 connection->is_underlying_io_open = 0;
                                 connection->remote_max_frame_size = 512;
@@ -1245,6 +1264,10 @@
         amqp_frame_codec_destroy(connection->amqp_frame_codec);
         frame_codec_destroy(connection->frame_codec);
         tickcounter_destroy(connection->tick_counter);
+        if (connection->properties != NULL)
+        {
+            amqpvalue_destroy(connection->properties);
+        }
 
         free(connection->host_name);
         free(connection->container_id);
@@ -1542,6 +1565,116 @@
     return result;
 }
 
+int connection_set_properties(CONNECTION_HANDLE connection, fields properties)
+{
+    int result;
+
+    /* Codes_SRS_CONNECTION_01_261: [If connection is NULL, connection_set_properties shall fail and return a non-zero value.] */
+    if (connection == NULL)
+    {
+        LogError("NULL connection");
+        result = __FAILURE__;
+    }
+    else
+    {
+        /* Codes_SRS_CONNECTION_01_262: [If connection_set_properties is called after the initial Open frame has been sent, it shall fail and return a non-zero value.] */
+        if (connection->connection_state != CONNECTION_STATE_START)
+        {
+            LogError("Connection already open");
+            result = __FAILURE__;
+        }
+        else
+        {
+            if (properties == NULL)
+            {
+                /* Codes_SRS_CONNECTION_01_263: [ If `properties` is NULL, the previously stored properties associated with `connection` shall be freed. ]*/
+                if (connection->properties != NULL)
+                {
+                    fields_destroy(connection->properties);
+                    connection->properties = NULL;
+                }
+
+                /* Codes_SRS_CONNECTION_01_264: [ On success it shall return 0. ]*/
+                result = 0;
+            }
+            else
+            {
+                fields new_properties;
+
+                /* Codes_SRS_CONNECTION_01_265: [ `connection_set_properties` shall copy the contents of `properties` as the properties contents for the connection instance identified by `connection`. ]*/
+                /* Codes_SRS_CONNECTION_01_266: [ Cloning the properties shall be done by calling `fields_clone`. ]*/
+                new_properties = fields_clone(properties);
+                if (new_properties == NULL)
+                {
+                    /* Codes_SRS_CONNECTION_01_267: [ If `fields_clone` fails, `connection_set_properties` shall fail and return a non-zero value. ]*/
+                    LogError("Cannot clone connection properties");
+                    result = __FAILURE__;
+                }
+                else
+                {
+                    /* Codes_SRS_CONNECTION_01_268: [ If setting the properties fails, the previous value shall be preserved. ]*/
+                    /* Only do the free of the previous value if we could clone the new one*/
+                    if (connection->properties != NULL)
+                    {
+                        fields_destroy(connection->properties);
+                    }
+
+                    connection->properties = new_properties;
+
+                    /* Codes_SRS_CONNECTION_01_264: [ On success it shall return 0. ]*/
+                    result = 0;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+int connection_get_properties(CONNECTION_HANDLE connection, fields* properties)
+{
+    int result;
+
+    /* Codes_SRS_CONNECTION_01_269: [If connection or properties is NULL, connection_get_properties shall fail and return a non-zero value.] */
+    if ((connection == NULL) ||
+        (properties == NULL))
+    {
+        LogError("Bad arguments: connection = %p, properties = %p",
+            connection, properties);
+        result = __FAILURE__;
+    }
+    else
+    {
+        if (connection->properties == NULL)
+        {
+            /* Codes_SRS_CONNECTION_01_270: [ If no properties have been set, `connection_get_properties` shall set `properties` to NULL. ]*/
+            *properties = NULL;
+
+            /* Codes_SRS_CONNECTION_01_271: [On success, connection_get_properties shall return 0.] */
+            result = 0;
+        }
+        else
+        {
+            /* Codes_SRS_CONNECTION_01_272: [connection_get_properties shall return in the properties argument the current properties setting.] */
+            /* Codes_SRS_CONNECTION_01_273: [ Cloning the properties shall be done by calling `fields_clone`. ]*/
+            *properties = fields_clone(connection->properties);
+            if (*properties == NULL)
+            {
+                /* Codes_SRS_CONNECTION_01_274: [ If `fields_clone` fails, `connection_get_properties` shall fail and return a non-zero value. ]*/
+                LogError("Cannot clone properties");
+                result = __FAILURE__;
+            }
+            else
+            {
+                /* Codes_SRS_CONNECTION_01_271: [On success, connection_get_properties shall return 0.] */
+                result = 0;
+            }
+        }
+    }
+
+    return result;
+}
+
 int connection_get_remote_max_frame_size(CONNECTION_HANDLE connection, uint32_t* remote_max_frame_size)
 {
     int result;