1 | // Copyright (c) Microsoft. All rights reserved.
|
---|
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
---|
3 |
|
---|
4 | #include <stdlib.h>
|
---|
5 | #include <inttypes.h>
|
---|
6 | #include <math.h>
|
---|
7 | #include "azure_c_shared_utility/optimize_size.h"
|
---|
8 | #include "azure_c_shared_utility/gballoc.h"
|
---|
9 | #include "azure_c_shared_utility/xlogging.h"
|
---|
10 | #include "azure_c_shared_utility/agenttime.h"
|
---|
11 | #include "azure_c_shared_utility/buffer_.h"
|
---|
12 |
|
---|
13 | #include "internal/iothub_client_diagnostic.h"
|
---|
14 |
|
---|
15 | #define TIME_STRING_BUFFER_LEN 30
|
---|
16 |
|
---|
17 | static const int BASE_36 = 36;
|
---|
18 |
|
---|
19 | #define INDEFINITE_TIME ((time_t)-1)
|
---|
20 |
|
---|
21 | static char* get_epoch_time(char* timeBuffer)
|
---|
22 | {
|
---|
23 | char* result;
|
---|
24 | time_t epochTime;
|
---|
25 | int timeLen = sizeof(time_t);
|
---|
26 |
|
---|
27 | if ((epochTime = get_time(NULL)) == INDEFINITE_TIME)
|
---|
28 | {
|
---|
29 | LogError("Failed getting current time");
|
---|
30 | result = NULL;
|
---|
31 | }
|
---|
32 | else if (timeLen == sizeof(int64_t))
|
---|
33 | {
|
---|
34 | if (sprintf(timeBuffer, "%"PRIu64, (int64_t)epochTime) < 0)
|
---|
35 | {
|
---|
36 | LogError("Failed sprintf to timeBuffer with 8 bytes of time_t");
|
---|
37 | result = NULL;
|
---|
38 | }
|
---|
39 | else
|
---|
40 | {
|
---|
41 | result = timeBuffer;
|
---|
42 | }
|
---|
43 | }
|
---|
44 | else if (timeLen == sizeof(int32_t))
|
---|
45 | {
|
---|
46 | if (sprintf(timeBuffer, "%"PRIu32, (int32_t)epochTime) < 0)
|
---|
47 | {
|
---|
48 | LogError("Failed sprintf to timeBuffer with 4 bytes of time_t");
|
---|
49 | result = NULL;
|
---|
50 | }
|
---|
51 | else
|
---|
52 | {
|
---|
53 | result = timeBuffer;
|
---|
54 | }
|
---|
55 | }
|
---|
56 | else
|
---|
57 | {
|
---|
58 | LogError("Unknown size of time_t");
|
---|
59 | result = NULL;
|
---|
60 | }
|
---|
61 |
|
---|
62 | return result;
|
---|
63 | }
|
---|
64 |
|
---|
65 | static char get_base36_char(unsigned char value)
|
---|
66 | {
|
---|
67 | return value <= 9 ? '0' + value : 'a' + value - 10;
|
---|
68 | }
|
---|
69 |
|
---|
70 | static char* generate_eight_random_characters(char *randomString)
|
---|
71 | {
|
---|
72 | int i;
|
---|
73 | char* randomStringPos = randomString;
|
---|
74 | for (i = 0; i < 4; ++i)
|
---|
75 | {
|
---|
76 | int rawRandom = rand();
|
---|
77 | int first = rawRandom % BASE_36;
|
---|
78 | int second = rawRandom / BASE_36 % BASE_36;
|
---|
79 | *randomStringPos++ = get_base36_char((unsigned char)first);
|
---|
80 | *randomStringPos++ = get_base36_char((unsigned char)second);
|
---|
81 | }
|
---|
82 | *randomStringPos = 0;
|
---|
83 |
|
---|
84 | return randomString;
|
---|
85 | }
|
---|
86 |
|
---|
87 | static bool should_add_diagnostic_info(IOTHUB_DIAGNOSTIC_SETTING_DATA* diagSetting)
|
---|
88 | {
|
---|
89 | bool result = false;
|
---|
90 | if (diagSetting->diagSamplingPercentage > 0)
|
---|
91 | {
|
---|
92 | double number;
|
---|
93 | double percentage;
|
---|
94 |
|
---|
95 | if (diagSetting->currentMessageNumber == UINT32_MAX)
|
---|
96 | {
|
---|
97 | diagSetting->currentMessageNumber %= diagSetting->diagSamplingPercentage * 100;
|
---|
98 | }
|
---|
99 | ++diagSetting->currentMessageNumber;
|
---|
100 |
|
---|
101 | number = diagSetting->currentMessageNumber;
|
---|
102 | percentage = diagSetting->diagSamplingPercentage;
|
---|
103 | result = (floor((number - 2) * percentage / 100.0) < floor((number - 1) * percentage / 100.0));
|
---|
104 | }
|
---|
105 | return result;
|
---|
106 | }
|
---|
107 |
|
---|
108 | static IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* prepare_message_diagnostic_data()
|
---|
109 | {
|
---|
110 | IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* result = (IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA*)malloc(sizeof(IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA));
|
---|
111 | if (result == NULL)
|
---|
112 | {
|
---|
113 | LogError("malloc for DiagnosticData failed");
|
---|
114 | }
|
---|
115 | else
|
---|
116 | {
|
---|
117 | char* diagId = (char*)malloc(9);
|
---|
118 | if (diagId == NULL)
|
---|
119 | {
|
---|
120 | LogError("malloc for diagId failed");
|
---|
121 | free(result);
|
---|
122 | result = NULL;
|
---|
123 | }
|
---|
124 | else
|
---|
125 | {
|
---|
126 | char* timeBuffer;
|
---|
127 |
|
---|
128 | (void)generate_eight_random_characters(diagId);
|
---|
129 | result->diagnosticId = diagId;
|
---|
130 |
|
---|
131 | timeBuffer = (char*)malloc(TIME_STRING_BUFFER_LEN);
|
---|
132 | if (timeBuffer == NULL)
|
---|
133 | {
|
---|
134 | LogError("malloc for timeBuffer failed");
|
---|
135 | free(result->diagnosticId);
|
---|
136 | free(result);
|
---|
137 | result = NULL;
|
---|
138 | }
|
---|
139 | else if (get_epoch_time(timeBuffer) == NULL)
|
---|
140 | {
|
---|
141 | LogError("Failed getting current time");
|
---|
142 | free(result->diagnosticId);
|
---|
143 | free(result);
|
---|
144 | free(timeBuffer);
|
---|
145 | result = NULL;
|
---|
146 | }
|
---|
147 | else
|
---|
148 | {
|
---|
149 | result->diagnosticCreationTimeUtc = timeBuffer;
|
---|
150 | }
|
---|
151 | }
|
---|
152 | }
|
---|
153 | return result;
|
---|
154 | }
|
---|
155 |
|
---|
156 | int IoTHubClient_Diagnostic_AddIfNecessary(IOTHUB_DIAGNOSTIC_SETTING_DATA* diagSetting, IOTHUB_MESSAGE_HANDLE messageHandle)
|
---|
157 | {
|
---|
158 | int result;
|
---|
159 | /* Codes_SRS_IOTHUB_DIAGNOSTIC_13_001: [ IoTHubClient_Diagnostic_AddIfNecessary should return nonezero if diagSetting or messageHandle is NULL. ]*/
|
---|
160 | if (diagSetting == NULL || messageHandle == NULL)
|
---|
161 | {
|
---|
162 | result = MU_FAILURE;
|
---|
163 | }
|
---|
164 | /* Codes_SRS_IOTHUB_DIAGNOSTIC_13_003: [ If diagSamplingPercentage is equal to 0, message number should not be increased and no diagnostic properties added ]*/
|
---|
165 | else if (should_add_diagnostic_info(diagSetting))
|
---|
166 | {
|
---|
167 | /* Codes_SRS_IOTHUB_DIAGNOSTIC_13_004: [ If diagSamplingPercentage is equal to 100, diagnostic properties should be added to all messages]*/
|
---|
168 | /* Codes_SRS_IOTHUB_DIAGNOSTIC_13_005: [ If diagSamplingPercentage is between(0, 100), diagnostic properties should be added based on percentage]*/
|
---|
169 |
|
---|
170 | IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* diagnosticData;
|
---|
171 | if ((diagnosticData = prepare_message_diagnostic_data()) == NULL)
|
---|
172 | {
|
---|
173 | result = MU_FAILURE;
|
---|
174 | }
|
---|
175 | else
|
---|
176 | {
|
---|
177 | if (IoTHubMessage_SetDiagnosticPropertyData(messageHandle, diagnosticData) != IOTHUB_MESSAGE_OK)
|
---|
178 | {
|
---|
179 | /* Codes_SRS_IOTHUB_DIAGNOSTIC_13_002: [ IoTHubClient_Diagnostic_AddIfNecessary should return nonezero if failing to add diagnostic property. ]*/
|
---|
180 | result = MU_FAILURE;
|
---|
181 | }
|
---|
182 | else
|
---|
183 | {
|
---|
184 | result = 0;
|
---|
185 | }
|
---|
186 |
|
---|
187 | free(diagnosticData->diagnosticCreationTimeUtc);
|
---|
188 | free(diagnosticData->diagnosticId);
|
---|
189 | free(diagnosticData);
|
---|
190 | diagnosticData = NULL;
|
---|
191 | }
|
---|
192 | }
|
---|
193 | else
|
---|
194 | {
|
---|
195 | result = 0;
|
---|
196 | }
|
---|
197 |
|
---|
198 | return result;
|
---|
199 | }
|
---|