communication.c
Go to the documentation of this file.
1 /*!**********************************************************************
2 *
3  * @copyright Copyright (C) 2016 Siemens Aktiengesellschaft.\n
4  * All rights reserved.
5  *
6  *************************************************************************
7  *
8  * @file communication.c
9  * @date Jul 15, 2016
10  * @brief Communication module implementation file.
11  *
12  ************************************************************************/
13 
14 #include "communication.h"
15 #include "memory.h"
16 #include "log_util.h"
17 #include "definitions.h"
18 #include "mcl/mcl_communication.h"
19 #include "event_list.h"
20 
21 #define USER_AGENT_HEADER_FORMAT "MCL/" MCL_VERSION_ " (%s)"
22 
23 // This function is used to log configuration which is used to initialize communication.
24 static void _log_configuration(mcl_configuration_t *configuration);
25 
27 {
28  DEBUG_ENTRY("mcl_configuration_t *configuration = <%p>, mcl_communication_t **communication = <%p>", configuration, communication)
29 
30  E_MCL_ERROR_CODE return_code;
31  mcl_size_t host_name_length = 0;
32  mcl_size_t proxy_host_length = 0;
33  mcl_size_t proxy_user_name_length = 0;
34  mcl_size_t proxy_password_length = 0;
35  mcl_size_t proxy_domain_length = 0;
36  mcl_size_t user_agent_length = 0;
37  mcl_size_t tenant_length = 0;
38  mcl_size_t initial_access_token_length = 0;
39  mcl_size_t store_path_length = 0;
40 
41  // Null check of configuration.
42  ASSERT_NOT_NULL(configuration);
43 
44  // Null check for input argument **communication.
45  ASSERT_NOT_NULL(communication);
46 
47  // Validate host name.
49  host_name_length = string_util_strnlen(configuration->mindsphere_hostname, MAXIMUM_HOST_NAME_LENGTH + 1);
50  ASSERT_CODE((0 < host_name_length) && (MAXIMUM_HOST_NAME_LENGTH >= host_name_length), MCL_INVALID_HOST_NAME);
51 
52  // Check if proxy is used but do not return error if not used.
53  if (MCL_NULL != configuration->proxy_hostname)
54  {
55  // Validate proxy host name.
56  proxy_host_length = string_util_strnlen(configuration->proxy_hostname, MAXIMUM_HOST_NAME_LENGTH + 1);
57  ASSERT_CODE((0 < proxy_host_length) && (MAXIMUM_HOST_NAME_LENGTH >= proxy_host_length), MCL_INVALID_PROXY_HOST_NAME);
58 
59  // Check if user name is provided but do not return error if not.
60  if (MCL_NULL != configuration->proxy_username)
61  {
62  // Validate proxy user name.
63  proxy_user_name_length = string_util_strnlen(configuration->proxy_username, MAXIMUM_PROXY_USER_NAME_LENGTH + 1);
64  ASSERT_CODE((0 < proxy_user_name_length) && (MAXIMUM_PROXY_USER_NAME_LENGTH >= proxy_user_name_length), MCL_INVALID_PROXY_USER_NAME);
65 
66  // Validate proxy password.
68  proxy_password_length = string_util_strnlen(configuration->proxy_password, MAXIMUM_PROXY_PASSWORD_LENGTH + 1);
69  ASSERT_CODE((0 < proxy_password_length) && (MAXIMUM_PROXY_PASSWORD_LENGTH >= proxy_password_length), MCL_INVALID_PROXY_PASSWORD);
70 
71  // Validate proxy domain.
72  if (MCL_NULL != configuration->proxy_domain)
73  {
74  proxy_domain_length = string_util_strnlen(configuration->proxy_domain, MAXIMUM_PROXY_DOMAIN_LENGTH + 1);
75  ASSERT_CODE((0 < proxy_domain_length) && (MAXIMUM_PROXY_DOMAIN_LENGTH >= proxy_domain_length), MCL_INVALID_PROXY_DOMAIN);
76  }
77  }
78  }
79 
80  // Validate security profile.
82 
83  // Validate User-Agent.
85  user_agent_length = string_util_strnlen(configuration->user_agent, MAXIMUM_USER_AGENT_LENGTH + 1);
86  ASSERT_CODE((0 < user_agent_length) && (MAXIMUM_USER_AGENT_LENGTH >= user_agent_length), MCL_INVALID_USER_AGENT);
87 
88  // Validate Tenant.
89  ASSERT_CODE(MCL_NULL != configuration->tenant, MCL_INVALID_TENANT);
90  tenant_length = string_util_strlen(configuration->tenant);
91 
92  // Validate max_http_payload_size.
93  ASSERT_CODE_MESSAGE(MIN_HTTP_PAYLOAD_SIZE <= configuration->max_http_payload_size && configuration->max_http_payload_size <= MCL_MAXIMUM_HTTP_PAYLOAD_SIZE,
94  MCL_INVALID_MAX_HTTP_PAYLOAD_SIZE, "max_http_payload_size is not in the range of %d - %d (Inclusive).", MIN_HTTP_PAYLOAD_SIZE, MCL_MAXIMUM_HTTP_PAYLOAD_SIZE);
95 
96  // Allocate memory for mcl handle.
97  MCL_NEW(*communication);
98  ASSERT_CODE_MESSAGE(MCL_NULL != *communication, MCL_OUT_OF_MEMORY, "Memory can not be allocated for communication object.");
99 
100  (*communication)->state.initialized = MCL_FALSE;
101  (*communication)->http_processor = MCL_NULL;
102  (*communication)->configuration.mindsphere_hostname = MCL_NULL;
103  (*communication)->configuration.mindsphere_port = 0;
104  (*communication)->configuration.mindsphere_certificate = MCL_NULL;
105  (*communication)->configuration.proxy_hostname = MCL_NULL;
106  (*communication)->configuration.proxy_port = 0;
107  (*communication)->configuration.proxy_type = MCL_PROXY_UNKNOWN;
108  (*communication)->configuration.proxy_username = MCL_NULL;
109  (*communication)->configuration.proxy_password = MCL_NULL;
110  (*communication)->configuration.proxy_domain = MCL_NULL;
111  (*communication)->configuration.security_profile = MCL_SECURITY_SHARED_SECRET;
112  (*communication)->configuration.initial_access_token = MCL_NULL;
113  (*communication)->configuration.tenant = MCL_NULL;
114  (*communication)->configuration.store_path = MCL_NULL;
115  (*communication)->configuration.load_function.rsa = MCL_NULL;
116  (*communication)->configuration.save_function.rsa = MCL_NULL;
117  (*communication)->configuration.access_token_endpoint = MCL_NULL;
118  (*communication)->configuration.exchange_endpoint = MCL_NULL;
119  (*communication)->configuration.registration_endpoint = MCL_NULL;
120  (*communication)->configuration.enter_critical_section = MCL_NULL;
121  (*communication)->configuration.leave_critical_section = MCL_NULL;
122 
123  // 16K performs a lot better and the practical minimum is about 400 bytes for libcurl.
124  (*communication)->configuration.max_http_payload_size = DEFAULT_HTTP_PAYLOAD_SIZE;
125  (*communication)->configuration.user_agent = MCL_NULL;
126 
127  // Create new string_t for the host name.
128  return_code = string_initialize_new(configuration->mindsphere_hostname, host_name_length, &((*communication)->configuration.mindsphere_hostname));
129  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code, "Memory can not be allocated for host name.");
130 
131  // Copy port number to mcl handle.
132  (*communication)->configuration.mindsphere_port = configuration->mindsphere_port;
133 
134  // Create new string_t for the certificate.
135  if (MCL_NULL != configuration->mindsphere_certificate)
136  {
137  return_code = string_initialize_new(configuration->mindsphere_certificate, 0, &((*communication)->configuration.mindsphere_certificate));
138  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code, "Memory can not be allocated for certificate.");
139  }
140 
141  // Copy security profile to mcl handle.
142  (*communication)->configuration.security_profile = configuration->security_profile;
143 
144  (*communication)->configuration.max_http_payload_size = configuration->max_http_payload_size;
145 
146  // Copy http_request_timeout to mcl_handle.
147  (*communication)->configuration.http_request_timeout = configuration->http_request_timeout;
148 
149  // Check if proxy is used but do not return error if not used.
150  if (MCL_NULL != configuration->proxy_hostname)
151  {
152  // Create new string_t for the proxy host name.
153  return_code = string_initialize_new(configuration->proxy_hostname, proxy_host_length, &((*communication)->configuration.proxy_hostname));
154  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code, "Memory can not be allocated for proxy host name.");
155 
156  // Copy proxy port to mcl handle.
157  (*communication)->configuration.proxy_port = configuration->proxy_port;
158 
159  // Copy proxy type to mcl handle.
160  (*communication)->configuration.proxy_type = configuration->proxy_type;
161 
162  // Check if user name is provided but do not return error if not.
163  if (MCL_NULL != configuration->proxy_username)
164  {
165  // Create new string_t for the proxy user name.
166  return_code = string_initialize_new(configuration->proxy_username, proxy_user_name_length, &((*communication)->configuration.proxy_username));
167  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code, "Memory can not be allocated for proxy user name.");
168 
169  // Create new string_t for the proxy password.
170  return_code = string_initialize_new(configuration->proxy_password, proxy_password_length, &((*communication)->configuration.proxy_password));
171  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code, "Memory can not be allocated for proxy password.");
172 
173  // Create new string_t for the proxy domain.
174  if (MCL_NULL != configuration->proxy_domain)
175  {
176  return_code = string_initialize_new(configuration->proxy_domain, proxy_domain_length, &((*communication)->configuration.proxy_domain));
177  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code, "Memory can not be allocated for proxy domain.");
178  }
179  }
180  }
181 
182  // Create new string_t for the user_agent.
183  // Construct user_agent header line once for all request send HTTP processor (the header line will not be changed until configuration has been changed)
184  // example MCL/0.9.0.0 (Custom Agent v1.0)
185  user_agent_length += 4 + MCL_VERSION_LENGTH_ + 3;
186 
187  return_code = string_initialize_new(MCL_NULL, user_agent_length, &((*communication)->configuration.user_agent));
188  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Memory can not be allocated for the <User-Agent> header line.");
189 
190  return_code = string_util_snprintf((*communication)->configuration.user_agent->buffer, user_agent_length + 1, USER_AGENT_HEADER_FORMAT, configuration->user_agent);
191  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code, "<User-Agent> header line can not be composed.");
192 
193  // Create string_t for initial access token if it is provided.
194  if ((MCL_NULL != configuration->initial_access_token))
195  {
196  initial_access_token_length = string_util_strlen(configuration->initial_access_token);
197  if (0 < initial_access_token_length)
198  {
199  return_code = string_initialize_new(configuration->initial_access_token, initial_access_token_length, &((*communication)->configuration.initial_access_token));
200  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code,
201  "Memory can not be allocated for initial access token.");
202  }
203  }
204 
205  return_code = string_initialize_new(configuration->tenant, tenant_length, &((*communication)->configuration.tenant));
206  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code, "Memory can not be allocated for tenant.");
207 
208  // Create new string_t for the storage path.
209  if (MCL_NULL != configuration->store_path)
210  {
211  store_path_length = string_util_strlen(configuration->store_path);
212  if (0 < store_path_length)
213  {
214  return_code = string_initialize_new(configuration->store_path, store_path_length, &((*communication)->configuration.store_path));
215  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code, "Memory can not be allocated for storage path.");
216  }
217  }
218 
219  // Copy custom load & save functions to mcl handle.
220  (*communication)->configuration.load_function = configuration->load_function;
221  (*communication)->configuration.save_function = configuration->save_function;
222 
223  // Set critical section functions.
224  (*communication)->configuration.enter_critical_section = configuration->enter_critical_section;
225  (*communication)->configuration.leave_critical_section = configuration->leave_critical_section;
226 
227  // Initialize http processor.
228  return_code = http_processor_initialize(&((*communication)->configuration), &((*communication)->http_processor));
229  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, mcl_communication_destroy(communication), return_code, "Http processor initialization failed.");
230 
231  // Set state of the mcl handle to "initialized".
232  (*communication)->state.initialized = MCL_TRUE;
233 
234  MCL_INFO("Communication structure is initialized.");
235  _log_configuration(configuration);
236 
237  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
238  return MCL_OK;
239 }
240 
242 {
243  DEBUG_ENTRY("mcl_communication_t **communication = <%p>", communication)
244 
245  // Make sure input argument is not NULL.
246  ASSERT_NOT_NULL(communication);
247 
248  if (MCL_NULL != *communication)
249  {
250  // Free configuration memory.
251  string_destroy(&((*communication)->configuration.mindsphere_hostname));
252  string_destroy(&((*communication)->configuration.mindsphere_certificate));
253  string_destroy(&((*communication)->configuration.proxy_hostname));
254  string_destroy(&((*communication)->configuration.proxy_username));
255  string_destroy(&((*communication)->configuration.proxy_password));
256  string_destroy(&((*communication)->configuration.proxy_domain));
257  string_destroy(&((*communication)->configuration.user_agent));
258  string_destroy(&((*communication)->configuration.initial_access_token));
259  string_destroy(&((*communication)->configuration.tenant));
260  string_destroy(&((*communication)->configuration.store_path));
261 
262  // Destroy Http processor.
263  http_processor_destroy(&((*communication)->http_processor));
264 
265  // Free MCL handle.
266  MCL_FREE(*communication);
267 
268  MCL_DEBUG("Communication handle is destroyed.");
269  }
270  else
271  {
272  MCL_DEBUG("Communication handle is already null.");
273  }
274 
275  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
276  return MCL_OK;
277 }
278 
280 {
281  DEBUG_ENTRY("mcl_communication_t *communication = <%p>", communication)
282 
283  E_MCL_ERROR_CODE result;
284  mcl_bool_t critical_section_callbacks_are_used;
285 
286  // Null check for the input arguments.
287  ASSERT_NOT_NULL(communication);
288 
289  critical_section_callbacks_are_used = MCL_NULL != communication->configuration.enter_critical_section && MCL_NULL != communication->configuration.leave_critical_section;
290  if(critical_section_callbacks_are_used)
291  {
292  result = communication->configuration.enter_critical_section();
293  ASSERT_CODE(MCL_OK == result, result);
294  }
295 
296  result = MCL_NOT_INITIALIZED;
297 
298  if (mcl_communication_is_initialized(communication))
299  {
300  if (!mcl_communication_is_onboarded(communication))
301  {
302  // Start the onboarding procedure.
303  result = http_processor_register(communication->http_processor);
304  if (MCL_OK == result)
305  {
306  MCL_INFO("Agent is successfully onboarded.");
307  }
308  else
309  {
310  MCL_ERROR("Onboarding of agent failed.");
311  }
312  }
313  else
314  {
315  MCL_INFO("Agent is already onboarded.");
316  result = MCL_ALREADY_ONBOARDED;
317  }
318 
319  if ((MCL_OK == result ) || (MCL_ALREADY_ONBOARDED == result))
320  {
321  if (MCL_OK == http_processor_get_access_token(communication->http_processor))
322  {
323  MCL_INFO("New access token is obtained.");
324  }
325  else
326  {
327  MCL_INFO("New access token can not be obtained.");
328  }
329  }
330  }
331 
332  if(critical_section_callbacks_are_used)
333  {
334  communication->configuration.leave_critical_section();
335  }
336 
337  DEBUG_LEAVE("retVal = <%d>", result);
338  return result;
339 }
340 
342 {
343  DEBUG_ENTRY("mcl_communication_t *communication = <%p>", communication)
344 
345  E_MCL_ERROR_CODE result;
346  mcl_bool_t critical_section_callbacks_are_used;
347 
348  // Null check for the input arguments.
349  ASSERT_NOT_NULL(communication);
350 
351  critical_section_callbacks_are_used = MCL_NULL != communication->configuration.enter_critical_section && MCL_NULL != communication->configuration.leave_critical_section;
352  if (critical_section_callbacks_are_used)
353  {
354  result = communication->configuration.enter_critical_section();
355  ASSERT_CODE(MCL_OK == result, result);
356  }
357 
358  result = MCL_NOT_INITIALIZED;
359 
360  // Check if MCL is initialized or not.
361  if (mcl_communication_is_initialized(communication))
362  {
363  // Check if the agent is onboarded or not.
364  if (mcl_communication_is_onboarded(communication))
365  {
366  // Perform key rotation.
367  MCL_INFO("Key rotation started.");
368  result = http_processor_register(communication->http_processor);
369  if (MCL_OK == result)
370  {
371  MCL_INFO("Key successfully rotated.");
372 
373  if (MCL_OK == http_processor_get_access_token(communication->http_processor))
374  {
375  MCL_INFO("New access token is obtained.");
376  }
377  else
378  {
379  MCL_INFO("New access token can not be obtained.");
380  }
381  }
382  else
383  {
384  MCL_ERROR("Key rotation failed.");
385  }
386  }
387  else
388  {
389  result = MCL_NOT_ONBOARDED;
390  }
391  }
392 
393  if(critical_section_callbacks_are_used)
394  {
395  communication->configuration.leave_critical_section();
396  }
397 
398  DEBUG_LEAVE("retVal = <%d>", result);
399  return result;
400 }
401 
403 {
404  DEBUG_ENTRY("mcl_communication_t *communication = <%p>", communication)
405 
406  E_MCL_ERROR_CODE result;
407  mcl_bool_t critical_section_callbacks_are_used;
408 
409  ASSERT_NOT_NULL(communication);
410 
411  critical_section_callbacks_are_used = MCL_NULL != communication->configuration.enter_critical_section && MCL_NULL != communication->configuration.leave_critical_section;
412  if (critical_section_callbacks_are_used)
413  {
414  result = communication->configuration.enter_critical_section();
415  ASSERT_CODE(MCL_OK == result, result);
416  }
417 
418  result = MCL_NOT_INITIALIZED;
419 
420  // Check if MCL is initialized or not.
421  if (mcl_communication_is_initialized(communication))
422  {
423  // Check if the agent is onboarded.
424  if (mcl_communication_is_onboarded(communication))
425  {
426  // Update security information.
427  result = http_processor_update_security_information(communication->http_processor);
428  }
429  else
430  {
431  result = MCL_NOT_ONBOARDED;
432  }
433  }
434 
435  if (MCL_OK == result)
436  {
437  if (MCL_OK == http_processor_get_access_token(communication->http_processor))
438  {
439  MCL_INFO("Security information is updated, new access token has been acquired.");
440  }
441  else
442  {
443  MCL_INFO("Security information is updated, new access token could not be acquired.");
444  }
445  }
446 
447  if(critical_section_callbacks_are_used)
448  {
449  communication->configuration.leave_critical_section();
450  }
451 
452  DEBUG_LEAVE("retVal = <%d>", result);
453  return result;
454 }
455 
457 {
458  DEBUG_ENTRY("mcl_communication_t *communication = <%p>", communication)
459 
460  E_MCL_ERROR_CODE result;
461 
462  ASSERT_NOT_NULL(communication);
463 
464  ASSERT_CODE_MESSAGE(MCL_TRUE == mcl_communication_is_initialized(communication), MCL_NOT_INITIALIZED, "Received communication handle is not initialized!");
465  ASSERT_CODE_MESSAGE(MCL_TRUE == mcl_communication_is_onboarded(communication), MCL_NOT_ONBOARDED, "Onboard operation is not performed yet on this mcl_communication handle!");
466 
467  result = http_processor_get_access_token(communication->http_processor);
468 
469  DEBUG_LEAVE("retVal = <%d>", result);
470  return result;
471 }
472 
474 {
475  DEBUG_ENTRY("mcl_communication_t *communication = <%p>, mcl_store_t *store = <%p>, void **reserved = <%p>", communication, store, reserved)
476 
477  E_MCL_ERROR_CODE result;
478 
479  // Unused parameter.
480  (void)reserved;
481 
482  // Initial checks :
483  ASSERT_NOT_NULL(communication);
484  ASSERT_NOT_NULL(store);
485 
486  ASSERT_CODE_MESSAGE(MCL_TRUE == mcl_communication_is_initialized(communication), MCL_NOT_INITIALIZED, "Received communication handle is not initialized!");
487  ASSERT_CODE_MESSAGE(MCL_TRUE == mcl_communication_is_onboarded(communication), MCL_NOT_ONBOARDED, "Onboard operation is not performed yet on this mcl_communication handle!");
488  ASSERT_CODE_MESSAGE(MCL_NULL != communication->http_processor->security_handler->access_token, MCL_NO_ACCESS_TOKEN_EXISTS, "No access token exists.");
489 
490  // Trigger http_processor to perform exchange based on store type :
491  if (MCL_TRUE == store->streamable)
492  {
493  result = http_processor_stream(communication->http_processor, store, NULL);
494  }
495  else
496  {
497  result = http_processor_exchange(communication->http_processor, store, NULL);
498  }
499 
500  DEBUG_LEAVE("retVal = <%d>", result);
501  return result;
502 }
503 
505 {
506  DEBUG_ENTRY("mcl_communication_t *communication = <%p>, mcl_store_t *store = <%p>, void **reserved = <%p>", communication, store, reserved)
507 
508  E_MCL_ERROR_CODE result;
509 
510  // Unused parameter.
511  (void)reserved;
512 
513  result = mcl_communication_exchange(communication, store, NULL);
514 
515  if (MCL_UNAUTHORIZED == result || MCL_NO_ACCESS_TOKEN_EXISTS == result)
516  {
517  MCL_INFO("Exchange has failed. Trying to get / renew access token.");
518  result = mcl_communication_get_access_token(communication);
519  if (MCL_OK == result)
520  {
521  MCL_INFO("Access token is obtained. Trying to exchange again.");
522  result = mcl_communication_exchange(communication, store, NULL);
523  if (MCL_OK == result)
524  {
525  MCL_INFO("Store is successfully exchanged.");
526  }
527  else
528  {
529  MCL_INFO("Exchange has failed.");
530  }
531  }
532  else if (MCL_BAD_REQUEST == result)
533  {
534  MCL_INFO("Access token can not be obtained. Trying to rotate key.");
535  result = mcl_communication_rotate_key(communication);
536  ASSERT_CODE_MESSAGE(MCL_OK == result, result, "Key rotation failed.");
537 
538  MCL_INFO("Key rotated. Trying to exchange again.");
539  result = mcl_communication_exchange(communication, store, NULL);
540  if (MCL_OK == result)
541  {
542  MCL_INFO("Store is successfully exchanged.");
543  }
544  else
545  {
546  MCL_INFO("Exchange has failed.");
547  }
548  }
549  else
550  {
551  MCL_INFO("Access token can not be obtained. Exchange is terminating.");
552  }
553 
554  }
555 
556  DEBUG_LEAVE("retVal = <%d>", result);
557  return result;
558 }
559 
560 #if MCL_FILE_DOWNLOAD_ENABLED
561 E_MCL_ERROR_CODE mcl_communication_download(mcl_communication_t *communication, mcl_uint8_t *buffer, mcl_size_t buffer_size, mcl_size_t start_byte, mcl_size_t end_byte,
562  char *file_id, mcl_file_t **file)
563 {
564  DEBUG_ENTRY("mcl_communication_t *communication = <%p>, mcl_uint8_t *buffer = <%p>, mcl_size_t buffer_size = <%u>, mcl_size_t start_byte = <%u>, mcl_size_t end_byte = <%u>, char *file_id = <%p>, mcl_file_t **file = <%p>",
565  communication, buffer, buffer_size, start_byte, end_byte, file_id, file)
566 
567  ASSERT_NOT_NULL(file);
568  *file = MCL_NULL;
569 
570  ASSERT_NOT_NULL(communication);
571  ASSERT_NOT_NULL(buffer);
572  ASSERT_NOT_NULL(file_id);
573 
574  ASSERT_CODE_MESSAGE(MCL_TRUE == mcl_communication_is_initialized(communication), MCL_NOT_INITIALIZED, "Received communication handle is not initialized!");
575  ASSERT_CODE_MESSAGE(MCL_TRUE == mcl_communication_is_onboarded(communication), MCL_NOT_ONBOARDED, "Onboard operation is not performed yet on this mcl_communication handle!");
576 
577  // If start and end bytes are given zero then whole file is going to be downloaded
578  mcl_bool_t with_range = !((0 == start_byte) && (0 == end_byte));
579 
580  // Check if range values are valid and buffer size is enough.
581  ASSERT_CODE_MESSAGE(!with_range || ((end_byte - start_byte <= buffer_size)), MCL_INVALID_PARAMETER, "start_byte: <%u> - end_byte: <%u> is not a valid range.", start_byte,
582  end_byte);
583 
584  string_t *file_id_string = MCL_NULL;
585 
586  E_MCL_ERROR_CODE result = string_initialize_new(file_id, 0, &file_id_string);
587  ASSERT_CODE_MESSAGE(MCL_OK == result, result, "Memory cannot be allocated for file_uri");
588 
589  result = http_processor_download(communication->http_processor, buffer, buffer_size, start_byte, end_byte, file_id_string, with_range, file);
590  string_destroy(&file_id_string);
591 
592  DEBUG_LEAVE("retVal = <%d>", result);
593  return result;
594 }
595 
596 #endif
597 
599 {
600  DEBUG_ENTRY("mcl_communication_t *communication = <%p>", communication)
601 
602  mcl_bool_t is_initialized;
603 
604  ASSERT_NOT_NULL(communication);
605 
606  is_initialized = communication->state.initialized;
607 
608  DEBUG_LEAVE("retVal = <%p>", &is_initialized);
609  return is_initialized;
610 }
611 
613 {
614  DEBUG_ENTRY("mcl_communication_t *communication = <%p>", communication)
615 
616  mcl_bool_t is_onboarded;
617 
618  ASSERT_NOT_NULL(communication);
619 
620  is_onboarded = (MCL_NULL == communication->http_processor->security_handler->registration_access_token) ? MCL_FALSE : MCL_TRUE;
621 
622  DEBUG_LEAVE("retVal = <%d>", is_onboarded);
623  return is_onboarded;
624 }
625 
627 {
628  DEBUG_ENTRY("mcl_communication_t *communication = <%p>, char **token = <%p>", communication, token)
629 
630  E_MCL_ERROR_CODE code;
631  mcl_size_t token_length;
632 
633  ASSERT_NOT_NULL(communication);
634  ASSERT_NOT_NULL(token);
635  ASSERT_CODE_MESSAGE(MCL_NULL != communication->http_processor->security_handler->access_token, MCL_NO_ACCESS_TOKEN_EXISTS, "No access token found.");
636 
637  token_length = communication->http_processor->security_handler->access_token->length + 1;
638  *token = MCL_CALLOC(token_length, 1);
639  ASSERT_CODE_MESSAGE(MCL_NULL != *token, MCL_OUT_OF_MEMORY, "Could not allocate memory for token.");
640 
641  code = string_util_snprintf(*token, token_length, "%s", communication->http_processor->security_handler->access_token->buffer);
642  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == code, MCL_FREE(*token), MCL_FAIL, "string_util_snprintf failed.");
643 
644  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
645  return MCL_OK;
646 }
647 
649 {
650  DEBUG_ENTRY("mcl_communication_t *communication = <%p>, char **token_time = <%p>", communication, token_time)
651 
652  E_MCL_ERROR_CODE code;
653  mcl_size_t token_time_length;
654 
655  ASSERT_NOT_NULL(token_time);
656  *token_time = MCL_NULL;
657 
658  ASSERT_NOT_NULL(communication);
659 
660  if(MCL_NULL == communication->http_processor->security_handler->last_token_time)
661  {
662  MCL_ERROR_RETURN(MCL_NO_SERVER_TIME, "Last token time is null.");
663  }
664 
665  token_time_length = communication->http_processor->security_handler->last_token_time->length + 1;
666  *token_time = MCL_CALLOC(token_time_length, 1);
667  ASSERT_CODE_MESSAGE(MCL_NULL != *token_time, MCL_OUT_OF_MEMORY, "Could not allocate memory for token_time.");
668 
669  code = string_util_snprintf(*token_time, token_time_length, "%s", communication->http_processor->security_handler->last_token_time->buffer);
670  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == code, MCL_FREE(*token_time), code, "string_util_snprintf failed.");
671 
672  DEBUG_LEAVE("retVal = <%d>", code);
673  return code;
674 }
675 
676 static void _log_configuration(mcl_configuration_t *configuration)
677 {
678  DEBUG_ENTRY("mcl_configuration_t *configuration = <%p>", configuration)
679 
680  // This function will be called in success case, no need to check mandatory fields.
681  MCL_INFO("Mindsphere Hostname: %s", configuration->mindsphere_hostname);
682  MCL_INFO("Mindsphere Port: %u", configuration->mindsphere_port);
683 
684  if (MCL_NULL != configuration->mindsphere_certificate)
685  {
686  MCL_INFO("Mindsphere Certificate: Provided");
687  }
688  else
689  {
690  MCL_INFO("Mindsphere Certificate: Not provided");
691  }
692 
693  if (MCL_NULL != configuration->proxy_hostname)
694  {
695  MCL_INFO("Proxy Hostname: %s", configuration->proxy_hostname);
696  MCL_INFO("Proxy Port: %u", configuration->proxy_port);
697 
698  switch (configuration->proxy_type)
699  {
700  case MCL_PROXY_HTTP:
701  MCL_INFO("Proxy Type: MCL_PROXY_HTTP");
702  break;
703 
704  case MCL_PROXY_HTTP_1_0:
705  MCL_INFO("Proxy Type: MCL_PROXY_HTTP_1_0");
706  break;
707 
708  case MCL_PROXY_SOCKS4:
709  MCL_INFO("Proxy Type: MCL_PROXY_SOCKS4");
710  break;
711 
712  case MCL_PROXY_SOCKS5:
713  MCL_INFO("Proxy Type: MCL_PROXY_SOCKS5");
714  break;
715 
716  case MCL_PROXY_SOCKS4A:
717  MCL_INFO("Proxy Type: MCL_PROXY_SOCKS4A");
718  break;
719 
721  MCL_INFO("Proxy Type: MCL_PROXY_SOCKS5_HOSTNAME");
722  break;
723 
724  default:
725  MCL_INFO("Proxy Type: MCL_PROXY_UNKNOWN");
726  break;
727  }
728 
729  if (MCL_NULL != configuration->proxy_username)
730  {
731  MCL_INFO("Proxy Username: %s", configuration->proxy_username);
732  MCL_INFO("Proxy Password: %s", configuration->proxy_password);
733 
734  if (MCL_NULL != configuration->proxy_domain)
735  {
736  MCL_INFO("Proxy Domain: %s", configuration->proxy_domain);
737  }
738  }
739  }
740  else
741  {
742  MCL_INFO("Proxy: Not used");
743  }
744 
745  if (MCL_SECURITY_SHARED_SECRET == configuration->security_profile)
746  {
747  MCL_INFO("Security Profile: MCL_SECURITY_SHARED_SECRET");
748  }
749  // Invalid parameter check is already done.
750  else
751  {
752  MCL_INFO("Security Profile: MCL_SECURITY_RSA_3072");
753  }
754 
755  MCL_INFO("Maximum HTTP Payload Size: %u bytes", configuration->max_http_payload_size);
756  MCL_INFO("HTTP Request Timeout: %u seconds", configuration->http_request_timeout);
757  MCL_INFO("User Agent: %s", configuration->user_agent);
758 
759  if (MCL_NULL != configuration->initial_access_token)
760  {
761  MCL_INFO("Initial Access Token: Provided");
762  }
763  else
764  {
765  MCL_INFO("Initial Access Token: Not provided");
766  }
767 
768  MCL_INFO("Tenant: %s", configuration->tenant);
769 
770  if (MCL_NULL != configuration->load_function.rsa && MCL_NULL != configuration->save_function.rsa)
771  {
772  MCL_INFO("Security Information: Callback functions will be used");
773  }
774  else if(MCL_NULL != configuration->store_path)
775  {
776  MCL_INFO("Security Information: File system will be used (not safe)");
777  MCL_INFO("Store Path: %s", configuration->store_path);
778  }
779  else
780  {
781  MCL_INFO("Security Information: Will not be saved");
782  }
783 
784  if (MCL_NULL != configuration->enter_critical_section && MCL_NULL != configuration->leave_critical_section)
785  {
786  MCL_INFO("Critical Section: Callback functions are provided");
787  }
788  else
789  {
790  MCL_INFO("Critical Section: Callback functions are not provided");
791  }
792 
793  DEBUG_LEAVE("retVal = void");
794 }
E_MCL_SECURITY_PROFILE security_profile
Security levels E_MCL_SECURITY_PROFILE.
char * user_agent
User agent.
mcl_uint16_t proxy_port
Proxy port no. Optional if proxy_hostname is not used.
E_MCL_ERROR_CODE mcl_communication_exchange(mcl_communication_t *communication, mcl_store_t *store, void **reserved)
mcl_load_rsa_callback_t rsa
Callback type to load RSA key.
Definition: mcl_common.h:297
Communication module header file.
void string_destroy(string_t **string)
Destroys the allocated resources of the string.
Definition: string_type.c:326
Agent is not onboarded to the server yet and does not possess an authentication key.
Definition: mcl_common.h:196
mcl_enter_critical_section_callback_t enter_critical_section
Custom function for entering critical section (Optional, default is NULL).
char * proxy_password
Proxy password. Optional if proxy_hostname and proxy_username are not used.
Internal failure in MCL.
Definition: mcl_common.h:141
mcl_size_t string_util_strnlen(const char *buffer, mcl_size_t maximum_length)
Standard library strnlen wrapper.
Definition: string_util.c:34
Memory module header file.
SOCKS5 proxy.
Definition: mcl_common.h:70
E_MCL_ERROR_CODE mcl_communication_onboard(mcl_communication_t *communication)
#define DEBUG_LEAVE(...)
Definition: log_util.h:81
SOCKS4a proxy.
Definition: mcl_common.h:71
#define DEFAULT_HTTP_PAYLOAD_SIZE
Definition: definitions.h:54
MindSphere proxy password given as a configuration parameter is either NULL or of inappropriate size...
Definition: mcl_common.h:162
#define DEBUG_ENTRY(...)
Definition: log_util.h:80
char * tenant
Tenant name which is used in self issued JWT.
#define MCL_NEW(p)
Definition: memory.h:121
E_MCL_ERROR_CODE string_initialize_new(const char *value, mcl_size_t value_length, string_t **string)
Initializes a new string_t object with the given value and length.
Definition: string_type.c:46
#define MCL_TRUE
Definition: mcl_common.h:54
Unknown proxy.
Definition: mcl_common.h:66
mcl_load_registration_information_callback_t load_function
Custom function for loading registration information; if both load_function and save_function are non...
E_MCL_ERROR_CODE mcl_communication_get_access_token(mcl_communication_t *communication)
Host name given as a configuration parameter is either NULL or of inappropriate size.
Definition: mcl_common.h:158
#define MCL_DEBUG(...)
Definition: log_util.h:70
#define ASSERT_NOT_NULL(argument)
Definition: definitions.h:129
#define MCL_FALSE
MCL bool type.
Definition: mcl_common.h:53
Http 1.0 proxy.
Definition: mcl_common.h:68
E_MCL_ERROR_CODE http_processor_register(http_processor_t *http_processor)
mcl_uint16_t mindsphere_port
Mindsphere port no.
#define USER_AGENT_HEADER_FORMAT
Definition: communication.c:21
Log utility module header file.
E_MCL_ERROR_CODE
MCL Error code definitions. Every function returning an error code uses this enum values...
Definition: mcl_common.h:137
E_MCL_ERROR_CODE string_util_snprintf(char *string, mcl_size_t length, const char *format,...)
Standard library snprintf wrapper.
Definition: string_util.c:95
Max HTTP payload size for every HTTP request given as configuration parameter is inappropriate size...
Definition: mcl_common.h:167
Security profile given as a configuration parameter is invalid. Please check the security profile opt...
Definition: mcl_common.h:164
mcl_leave_critical_section_callback_t leave_critical_section
Custom function for leaving critical section (Optional, default is NULL).
#define MCL_FREE(p)
Definition: memory.h:125
Tenant for JWT is NULL.
Definition: mcl_common.h:166
No access token exists in mcl_communication_t handle.
Definition: mcl_common.h:155
struct mcl_store_t mcl_store_t
Definition: mcl_store.h:34
#define ASSERT_STATEMENT_CODE_MESSAGE(condition, statement, return_code,...)
Definition: definitions.h:121
Http proxy.
Definition: mcl_common.h:67
char * proxy_hostname
Proxy hostname. Optional.
static void _log_configuration(mcl_configuration_t *configuration)
General invalid parameter fail.
Definition: mcl_common.h:144
uint8_t mcl_uint8_t
Definition: mcl_common.h:43
char * mindsphere_hostname
Mindsphere hostname.
#define MCL_CALLOC(count, bytes)
Definition: memory.h:122
SOCKS4 proxy.
Definition: mcl_common.h:69
#define ASSERT_CODE_MESSAGE(condition, return_code,...)
Definition: definitions.h:105
Definitions module header file.
User-Agent for every HTTP request given as configuration parameter is either NULL or longer than 32 c...
Definition: mcl_common.h:165
mcl_uint32_t http_request_timeout
Timeout value (in seconds) for HTTP requests. Default timeout is 300 seconds.
mcl_bool_t mcl_communication_is_onboarded(mcl_communication_t *communication)
Can be used to determine if communication handle is onboarded.
#define MAXIMUM_HOST_NAME_LENGTH
Definition: definitions.h:44
MindSphere proxy user name given as a configuration parameter is either NULL or of inappropriate size...
Definition: mcl_common.h:161
If the response of server is HTTP 400.
Definition: mcl_common.h:184
E_MCL_ERROR_CODE mcl_communication_destroy(mcl_communication_t **communication)
MindSphere proxy domain given as a configuration parameter is either NULL or of inappropriate size...
Definition: mcl_common.h:163
char * proxy_username
Proxy username. Optional if proxy_hostname is not used.
E_MCL_ERROR_CODE http_processor_update_security_information(http_processor_t *http_processor)
E_MCL_PROXY proxy_type
Proxy type E_MCL_PROXY. Optional if proxy_hostname is not used.
E_MCL_ERROR_CODE http_processor_initialize(configuration_t *configuration, http_processor_t **http_processor)
Http Processor Initialize function.
#define ASSERT_CODE(condition, return_code)
Definition: definitions.h:97
mcl_save_registration_information_callback_t save_function
Custom function for saving registration information; if both load_function and save_function are non-...
E_MCL_ERROR_CODE http_processor_stream(http_processor_t *http_processor, store_t *store, void **reserved)
Exchange operation logic with streaming.
E_MCL_ERROR_CODE mcl_communication_rotate_key(mcl_communication_t *communication)
E_MCL_ERROR_CODE http_processor_exchange(http_processor_t *http_processor, store_t *store, void **reserved)
Exchange operation logic.
size_t mcl_size_t
Definition: mcl_common.h:38
E_MCL_ERROR_CODE mcl_communication_process(mcl_communication_t *communication, mcl_store_t *store, void **reserved)
char * store_path
Path of the file the library uses to save registration artifacts such as registration access token...
#define MAXIMUM_PROXY_DOMAIN_LENGTH
Definition: definitions.h:47
mcl_uint8_t mcl_bool_t
Definition: mcl_common.h:47
Success.
Definition: mcl_common.h:140
SOCKS5 hostname proxy.
Definition: mcl_common.h:72
char * proxy_domain
Proxy domain. Optional if proxy_hostname and proxy_username are not used.
E_MCL_ERROR_CODE mcl_communication_initialize(mcl_configuration_t *configuration, mcl_communication_t **communication)
Definition: communication.c:26
E_MCL_ERROR_CODE mcl_communication_get_last_token_time(mcl_communication_t *communication, char **token_time)
Returns the time when lastly received oauth access token is received.
MCL is not initialized, mcl_communication_initialize() function must be called first.
Definition: mcl_common.h:195
#define MCL_ERROR(...)
Definition: log_util.h:97
#define MCL_INFO(...)
Definition: log_util.h:87
E_MCL_ERROR_CODE http_processor_get_access_token(http_processor_t *http_processor)
char * initial_access_token
Initial access token. Not used by the library if a registration access token is present in store_path...
#define MIN_HTTP_PAYLOAD_SIZE
Definition: definitions.h:51
#define MAXIMUM_PROXY_PASSWORD_LENGTH
Definition: definitions.h:46
mcl_bool_t mcl_communication_is_initialized(mcl_communication_t *communication)
Can be used to determine if communication handle is initialized.
E_MCL_ERROR_CODE mcl_communication_get_last_access_token(mcl_communication_t *communication, char **token)
Returns the lastly received oauth access token, NULL if server time is not received.
Communication module interface header file.
#define MCL_MAXIMUM_HTTP_PAYLOAD_SIZE
Http request payload size limit for MindSphere.
Definition: mcl_common.h:59
Agent is already onboarded to the server, hence the library did not try to onboard again...
Definition: mcl_common.h:197
Server time is not received from the server.
Definition: mcl_common.h:154
struct mcl_communication_t mcl_communication_t
Event list module header file.
Memory allocation fail.
Definition: mcl_common.h:143
struct mcl_file_t mcl_file_t
This struct is used for building the complete message of file.
Definition: mcl_store.h:39
#define MCL_NULL
Definition: definitions.h:24
MindSphere proxy host name given as a configuration parameter is either NULL or of inappropriate size...
Definition: mcl_common.h:160
#define MAXIMUM_USER_AGENT_LENGTH
Definition: definitions.h:48
#define MAXIMUM_PROXY_USER_NAME_LENGTH
Definition: definitions.h:45
mcl_size_t string_util_strlen(const char *buffer)
Standard library strlen wrapper.
Definition: string_util.c:24
If the response of server is HTTP 401.
Definition: mcl_common.h:185
mcl_size_t max_http_payload_size
Not valid for streamable request. Default value is 16K Bytes. Minimum value is 400 Bytes and maximum ...
void http_processor_destroy(http_processor_t **http_processor)
To destroy the HTTP Processor Handler.
E_MCL_ERROR_CODE mcl_communication_update_security_information(mcl_communication_t *communication)
mcl_save_rsa_callback_t rsa
Callback type to save RSA key.
Definition: mcl_common.h:306
char * mindsphere_certificate
Mindsphere certificate. Optional. If set to NULL, MCL will use default CA certificate store (if provi...
#define MCL_ERROR_RETURN(return_value,...)
Definition: definitions.h:69