Api.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/crt/Api.h>
  6. #include <aws/crt/StlAllocator.h>
  7. #include <aws/crt/external/cJSON.h>
  8. #include <aws/crt/io/TlsOptions.h>
  9. #include <aws/auth/auth.h>
  10. #include <aws/common/ref_count.h>
  11. #include <aws/event-stream/event_stream.h>
  12. #include <aws/http/http.h>
  13. #include <aws/mqtt/mqtt.h>
  14. #include <aws/s3/s3.h>
  15. #include <thread>
  16. namespace Aws
  17. {
  18. namespace Crt
  19. {
  20. static Crypto::CreateHashCallback s_BYOCryptoNewMD5Callback;
  21. static Crypto::CreateHashCallback s_BYOCryptoNewSHA256Callback;
  22. static Crypto::CreateHMACCallback s_BYOCryptoNewSHA256HMACCallback;
  23. static Io::NewClientTlsHandlerCallback s_BYOCryptoNewClientTlsHandlerCallback;
  24. static Io::NewTlsContextImplCallback s_BYOCryptoNewTlsContextImplCallback;
  25. static Io::DeleteTlsContextImplCallback s_BYOCryptoDeleteTlsContextImplCallback;
  26. static Io::IsTlsAlpnSupportedCallback s_BYOCryptoIsTlsAlpnSupportedCallback;
  27. Io::ClientBootstrap *ApiHandle::s_static_bootstrap = nullptr;
  28. Io::EventLoopGroup *ApiHandle::s_static_event_loop_group = nullptr;
  29. int ApiHandle::s_host_resolver_default_max_hosts = 8;
  30. Io::HostResolver *ApiHandle::s_static_default_host_resolver = nullptr;
  31. std::mutex ApiHandle::s_lock_client_bootstrap;
  32. std::mutex ApiHandle::s_lock_event_loop_group;
  33. std::mutex ApiHandle::s_lock_default_host_resolver;
  34. static void *s_cJSONAlloc(size_t sz) { return aws_mem_acquire(ApiAllocator(), sz); }
  35. static void s_cJSONFree(void *ptr) { return aws_mem_release(ApiAllocator(), ptr); }
  36. static void s_initApi(Allocator *allocator)
  37. {
  38. // sets up the StlAllocator for use.
  39. g_allocator = allocator;
  40. aws_mqtt_library_init(allocator);
  41. aws_s3_library_init(allocator);
  42. aws_event_stream_library_init(allocator);
  43. aws_sdkutils_library_init(allocator);
  44. cJSON_Hooks hooks;
  45. hooks.malloc_fn = s_cJSONAlloc;
  46. hooks.free_fn = s_cJSONFree;
  47. cJSON_InitHooks(&hooks);
  48. }
  49. ApiHandle::ApiHandle(Allocator *allocator) noexcept
  50. : m_logger(), m_shutdownBehavior(ApiHandleShutdownBehavior::Blocking)
  51. {
  52. s_initApi(allocator);
  53. }
  54. ApiHandle::ApiHandle() noexcept : m_logger(), m_shutdownBehavior(ApiHandleShutdownBehavior::Blocking)
  55. {
  56. s_initApi(DefaultAllocator());
  57. }
  58. ApiHandle::~ApiHandle()
  59. {
  60. ReleaseStaticDefaultClientBootstrap();
  61. ReleaseStaticDefaultEventLoopGroup();
  62. ReleaseStaticDefaultHostResolver();
  63. if (m_shutdownBehavior == ApiHandleShutdownBehavior::Blocking)
  64. {
  65. aws_thread_join_all_managed();
  66. }
  67. if (aws_logger_get() == &m_logger)
  68. {
  69. aws_logger_set(NULL);
  70. aws_logger_clean_up(&m_logger);
  71. }
  72. g_allocator = nullptr;
  73. aws_s3_library_clean_up();
  74. aws_mqtt_library_clean_up();
  75. aws_event_stream_library_clean_up();
  76. aws_sdkutils_library_clean_up();
  77. s_BYOCryptoNewMD5Callback = nullptr;
  78. s_BYOCryptoNewSHA256Callback = nullptr;
  79. s_BYOCryptoNewSHA256HMACCallback = nullptr;
  80. s_BYOCryptoNewClientTlsHandlerCallback = nullptr;
  81. s_BYOCryptoNewTlsContextImplCallback = nullptr;
  82. s_BYOCryptoDeleteTlsContextImplCallback = nullptr;
  83. s_BYOCryptoIsTlsAlpnSupportedCallback = nullptr;
  84. }
  85. void ApiHandle::InitializeLogging(Aws::Crt::LogLevel level, const char *filename)
  86. {
  87. struct aws_logger_standard_options options;
  88. AWS_ZERO_STRUCT(options);
  89. options.level = (enum aws_log_level)level;
  90. options.filename = filename;
  91. InitializeLoggingCommon(options);
  92. }
  93. void ApiHandle::InitializeLogging(Aws::Crt::LogLevel level, FILE *fp)
  94. {
  95. struct aws_logger_standard_options options;
  96. AWS_ZERO_STRUCT(options);
  97. options.level = (enum aws_log_level)level;
  98. options.file = fp;
  99. InitializeLoggingCommon(options);
  100. }
  101. void ApiHandle::InitializeLoggingCommon(struct aws_logger_standard_options &options)
  102. {
  103. if (aws_logger_get() == &m_logger)
  104. {
  105. aws_logger_set(NULL);
  106. aws_logger_clean_up(&m_logger);
  107. if (options.level == AWS_LL_NONE)
  108. {
  109. AWS_ZERO_STRUCT(m_logger);
  110. return;
  111. }
  112. }
  113. if (aws_logger_init_standard(&m_logger, ApiAllocator(), &options))
  114. {
  115. return;
  116. }
  117. aws_logger_set(&m_logger);
  118. }
  119. void ApiHandle::SetShutdownBehavior(ApiHandleShutdownBehavior behavior) { m_shutdownBehavior = behavior; }
  120. #if BYO_CRYPTO
  121. static struct aws_hash *s_MD5New(struct aws_allocator *allocator)
  122. {
  123. if (!s_BYOCryptoNewMD5Callback)
  124. {
  125. AWS_LOGF_ERROR(
  126. AWS_LS_IO_TLS, "Must call ApiHandle::SetBYOCryptoNewMD5Callback() before MD5 hash can be created");
  127. aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
  128. return nullptr;
  129. }
  130. auto hash = s_BYOCryptoNewMD5Callback(AWS_MD5_LEN, allocator);
  131. if (!hash)
  132. {
  133. return nullptr;
  134. }
  135. return hash->SeatForCInterop(hash);
  136. }
  137. void ApiHandle::SetBYOCryptoNewMD5Callback(Crypto::CreateHashCallback &&callback)
  138. {
  139. s_BYOCryptoNewMD5Callback = std::move(callback);
  140. aws_set_md5_new_fn(s_MD5New);
  141. }
  142. static struct aws_hash *s_Sha256New(struct aws_allocator *allocator)
  143. {
  144. if (!s_BYOCryptoNewSHA256Callback)
  145. {
  146. AWS_LOGF_ERROR(
  147. AWS_LS_IO_TLS,
  148. "Must call ApiHandle::SetBYOCryptoNewSHA256Callback() before SHA256 hash can be created");
  149. aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
  150. return nullptr;
  151. }
  152. auto hash = s_BYOCryptoNewSHA256Callback(AWS_SHA256_LEN, allocator);
  153. if (!hash)
  154. {
  155. return nullptr;
  156. }
  157. return hash->SeatForCInterop(hash);
  158. }
  159. void ApiHandle::SetBYOCryptoNewSHA256Callback(Crypto::CreateHashCallback &&callback)
  160. {
  161. s_BYOCryptoNewSHA256Callback = std::move(callback);
  162. aws_set_sha256_new_fn(s_Sha256New);
  163. }
  164. static struct aws_hmac *s_sha256HMACNew(struct aws_allocator *allocator, const struct aws_byte_cursor *secret)
  165. {
  166. if (!s_BYOCryptoNewSHA256HMACCallback)
  167. {
  168. AWS_LOGF_ERROR(
  169. AWS_LS_IO_TLS,
  170. "Must call ApiHandle::SetBYOCryptoNewSHA256HMACCallback() before SHA256 HMAC can be created");
  171. aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
  172. return nullptr;
  173. }
  174. auto hmac = s_BYOCryptoNewSHA256HMACCallback(AWS_SHA256_HMAC_LEN, *secret, allocator);
  175. if (!hmac)
  176. {
  177. return nullptr;
  178. }
  179. return hmac->SeatForCInterop(hmac);
  180. }
  181. void ApiHandle::SetBYOCryptoNewSHA256HMACCallback(Crypto::CreateHMACCallback &&callback)
  182. {
  183. s_BYOCryptoNewSHA256HMACCallback = std::move(callback);
  184. aws_set_sha256_hmac_new_fn(s_sha256HMACNew);
  185. }
  186. static struct aws_channel_handler *s_NewClientTlsHandler(
  187. struct aws_allocator *allocator,
  188. struct aws_tls_connection_options *options,
  189. struct aws_channel_slot *slot,
  190. void *)
  191. {
  192. if (!s_BYOCryptoNewClientTlsHandlerCallback)
  193. {
  194. AWS_LOGF_ERROR(
  195. AWS_LS_IO_TLS,
  196. "Must call ApiHandle::SetBYOCryptoClientTlsCallback() before client TLS handler can be created");
  197. aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
  198. return nullptr;
  199. }
  200. auto clientHandlerSelfReferencing = s_BYOCryptoNewClientTlsHandlerCallback(slot, *options, allocator);
  201. if (!clientHandlerSelfReferencing)
  202. {
  203. return nullptr;
  204. }
  205. return clientHandlerSelfReferencing->SeatForCInterop(clientHandlerSelfReferencing);
  206. }
  207. static int s_ClientTlsHandlerStartNegotiation(struct aws_channel_handler *handler, void *)
  208. {
  209. auto *clientHandler = reinterpret_cast<Io::ClientTlsChannelHandler *>(handler->impl);
  210. if (clientHandler->ChannelsThreadIsCallersThread())
  211. {
  212. clientHandler->StartNegotiation();
  213. }
  214. else
  215. {
  216. clientHandler->ScheduleTask([clientHandler](Io::TaskStatus) { clientHandler->StartNegotiation(); });
  217. }
  218. return AWS_OP_SUCCESS;
  219. }
  220. void ApiHandle::SetBYOCryptoClientTlsCallback(Io::NewClientTlsHandlerCallback &&callback)
  221. {
  222. s_BYOCryptoNewClientTlsHandlerCallback = std::move(callback);
  223. struct aws_tls_byo_crypto_setup_options setupOptions;
  224. setupOptions.new_handler_fn = s_NewClientTlsHandler;
  225. setupOptions.start_negotiation_fn = s_ClientTlsHandlerStartNegotiation;
  226. setupOptions.user_data = nullptr;
  227. aws_tls_byo_crypto_set_client_setup_options(&setupOptions);
  228. }
  229. void ApiHandle::SetBYOCryptoTlsContextCallbacks(
  230. Io::NewTlsContextImplCallback &&newCallback,
  231. Io::DeleteTlsContextImplCallback &&deleteCallback,
  232. Io::IsTlsAlpnSupportedCallback &&alpnCallback)
  233. {
  234. s_BYOCryptoNewTlsContextImplCallback = newCallback;
  235. s_BYOCryptoDeleteTlsContextImplCallback = deleteCallback;
  236. s_BYOCryptoIsTlsAlpnSupportedCallback = alpnCallback;
  237. }
  238. #else // BYO_CRYPTO
  239. void ApiHandle::SetBYOCryptoNewMD5Callback(Crypto::CreateHashCallback &&)
  240. {
  241. AWS_LOGF_WARN(AWS_LS_IO_TLS, "SetBYOCryptoNewMD5Callback() has no effect unless compiled with BYO_CRYPTO");
  242. }
  243. void ApiHandle::SetBYOCryptoNewSHA256Callback(Crypto::CreateHashCallback &&)
  244. {
  245. AWS_LOGF_WARN(
  246. AWS_LS_IO_TLS, "SetBYOCryptoNewSHA256Callback() has no effect unless compiled with BYO_CRYPTO");
  247. }
  248. void ApiHandle::SetBYOCryptoNewSHA256HMACCallback(Crypto::CreateHMACCallback &&)
  249. {
  250. AWS_LOGF_WARN(
  251. AWS_LS_IO_TLS, "SetBYOCryptoNewSHA256HMACCallback() has no effect unless compiled with BYO_CRYPTO");
  252. }
  253. void ApiHandle::SetBYOCryptoClientTlsCallback(Io::NewClientTlsHandlerCallback &&)
  254. {
  255. AWS_LOGF_WARN(
  256. AWS_LS_IO_TLS, "SetBYOCryptoClientTlsCallback() has no effect unless compiled with BYO_CRYPTO");
  257. }
  258. void ApiHandle::SetBYOCryptoTlsContextCallbacks(
  259. Io::NewTlsContextImplCallback &&,
  260. Io::DeleteTlsContextImplCallback &&,
  261. Io::IsTlsAlpnSupportedCallback &&)
  262. {
  263. AWS_LOGF_WARN(
  264. AWS_LS_IO_TLS, "SetBYOCryptoClientTlsCallback() has no effect unless compiled with BYO_CRYPTO");
  265. }
  266. #endif // BYO_CRYPTO
  267. Io::ClientBootstrap *ApiHandle::GetOrCreateStaticDefaultClientBootstrap()
  268. {
  269. std::lock_guard<std::mutex> lock(s_lock_client_bootstrap);
  270. if (s_static_bootstrap == nullptr)
  271. {
  272. s_static_bootstrap = Aws::Crt::New<Io::ClientBootstrap>(
  273. ApiAllocator(), *GetOrCreateStaticDefaultEventLoopGroup(), *GetOrCreateStaticDefaultHostResolver());
  274. }
  275. return s_static_bootstrap;
  276. }
  277. Io::EventLoopGroup *ApiHandle::GetOrCreateStaticDefaultEventLoopGroup()
  278. {
  279. std::lock_guard<std::mutex> lock(s_lock_event_loop_group);
  280. if (s_static_event_loop_group == nullptr)
  281. {
  282. s_static_event_loop_group = Aws::Crt::New<Io::EventLoopGroup>(ApiAllocator(), (uint16_t)0);
  283. }
  284. return s_static_event_loop_group;
  285. }
  286. Io::HostResolver *ApiHandle::GetOrCreateStaticDefaultHostResolver()
  287. {
  288. std::lock_guard<std::mutex> lock(s_lock_default_host_resolver);
  289. if (s_static_default_host_resolver == nullptr)
  290. {
  291. s_static_default_host_resolver = Aws::Crt::New<Io::DefaultHostResolver>(
  292. ApiAllocator(), *GetOrCreateStaticDefaultEventLoopGroup(), 1, s_host_resolver_default_max_hosts);
  293. }
  294. return s_static_default_host_resolver;
  295. }
  296. void ApiHandle::ReleaseStaticDefaultClientBootstrap()
  297. {
  298. std::lock_guard<std::mutex> lock(s_lock_client_bootstrap);
  299. if (s_static_bootstrap != nullptr)
  300. {
  301. Aws::Crt::Delete(s_static_bootstrap, ApiAllocator());
  302. s_static_bootstrap = nullptr;
  303. }
  304. }
  305. void ApiHandle::ReleaseStaticDefaultEventLoopGroup()
  306. {
  307. std::lock_guard<std::mutex> lock(s_lock_event_loop_group);
  308. if (s_static_event_loop_group != nullptr)
  309. {
  310. Aws::Crt::Delete(s_static_event_loop_group, ApiAllocator());
  311. s_static_event_loop_group = nullptr;
  312. }
  313. }
  314. void ApiHandle::ReleaseStaticDefaultHostResolver()
  315. {
  316. std::lock_guard<std::mutex> lock(s_lock_default_host_resolver);
  317. if (s_static_default_host_resolver != nullptr)
  318. {
  319. Aws::Crt::Delete(s_static_default_host_resolver, ApiAllocator());
  320. s_static_default_host_resolver = nullptr;
  321. }
  322. }
  323. const Io::NewTlsContextImplCallback &ApiHandle::GetBYOCryptoNewTlsContextImplCallback()
  324. {
  325. return s_BYOCryptoNewTlsContextImplCallback;
  326. }
  327. const Io::DeleteTlsContextImplCallback &ApiHandle::GetBYOCryptoDeleteTlsContextImplCallback()
  328. {
  329. return s_BYOCryptoDeleteTlsContextImplCallback;
  330. }
  331. const Io::IsTlsAlpnSupportedCallback &ApiHandle::GetBYOCryptoIsTlsAlpnSupportedCallback()
  332. {
  333. return s_BYOCryptoIsTlsAlpnSupportedCallback;
  334. }
  335. const char *ErrorDebugString(int error) noexcept { return aws_error_debug_str(error); }
  336. int LastError() noexcept { return aws_last_error(); }
  337. int LastErrorOrUnknown() noexcept
  338. {
  339. int last_error = aws_last_error();
  340. if (last_error == AWS_ERROR_SUCCESS)
  341. {
  342. last_error = AWS_ERROR_UNKNOWN;
  343. }
  344. return last_error;
  345. }
  346. } // namespace Crt
  347. } // namespace Aws