async_bio.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include "async_bio.h"
  10. #include <errno.h>
  11. #include <string.h>
  12. #include <openssl/bio.h>
  13. #include <openssl/crypto.h>
  14. namespace {
  15. struct AsyncBio {
  16. bool datagram;
  17. bool enforce_write_quota;
  18. size_t read_quota;
  19. size_t write_quota;
  20. };
  21. AsyncBio *GetData(BIO *bio) {
  22. return (AsyncBio *)BIO_get_data(bio);
  23. }
  24. static int AsyncWrite(BIO *bio, const char *in, int inl) {
  25. AsyncBio *a = GetData(bio);
  26. if (a == NULL || BIO_next(bio) == NULL) {
  27. return 0;
  28. }
  29. if (!a->enforce_write_quota) {
  30. return BIO_write(BIO_next(bio), in, inl);
  31. }
  32. BIO_clear_retry_flags(bio);
  33. if (a->write_quota == 0) {
  34. BIO_set_retry_write(bio);
  35. errno = EAGAIN;
  36. return -1;
  37. }
  38. if (!a->datagram && (size_t)inl > a->write_quota) {
  39. inl = a->write_quota;
  40. }
  41. int ret = BIO_write(BIO_next(bio), in, inl);
  42. if (ret <= 0) {
  43. BIO_copy_next_retry(bio);
  44. } else {
  45. a->write_quota -= (a->datagram ? 1 : ret);
  46. }
  47. return ret;
  48. }
  49. static int AsyncRead(BIO *bio, char *out, int outl) {
  50. AsyncBio *a = GetData(bio);
  51. if (a == NULL || BIO_next(bio) == NULL) {
  52. return 0;
  53. }
  54. BIO_clear_retry_flags(bio);
  55. if (a->read_quota == 0) {
  56. BIO_set_retry_read(bio);
  57. errno = EAGAIN;
  58. return -1;
  59. }
  60. if (!a->datagram && (size_t)outl > a->read_quota) {
  61. outl = a->read_quota;
  62. }
  63. int ret = BIO_read(BIO_next(bio), out, outl);
  64. if (ret <= 0) {
  65. BIO_copy_next_retry(bio);
  66. } else {
  67. a->read_quota -= (a->datagram ? 1 : ret);
  68. }
  69. return ret;
  70. }
  71. static long AsyncCtrl(BIO *bio, int cmd, long num, void *ptr) {
  72. if (BIO_next(bio) == NULL) {
  73. return 0;
  74. }
  75. BIO_clear_retry_flags(bio);
  76. int ret = BIO_ctrl(BIO_next(bio), cmd, num, ptr);
  77. BIO_copy_next_retry(bio);
  78. return ret;
  79. }
  80. static int AsyncNew(BIO *bio) {
  81. AsyncBio *a = (AsyncBio *)OPENSSL_malloc(sizeof(*a));
  82. if (a == NULL) {
  83. return 0;
  84. }
  85. memset(a, 0, sizeof(*a));
  86. a->enforce_write_quota = true;
  87. BIO_set_init(bio, 1);
  88. BIO_set_data(bio, a);
  89. return 1;
  90. }
  91. static int AsyncFree(BIO *bio) {
  92. if (bio == NULL) {
  93. return 0;
  94. }
  95. OPENSSL_free(BIO_get_data(bio));
  96. BIO_set_data(bio, NULL);
  97. BIO_set_init(bio, 0);
  98. return 1;
  99. }
  100. static long AsyncCallbackCtrl(BIO *bio, int cmd, BIO_info_cb fp)
  101. {
  102. if (BIO_next(bio) == NULL)
  103. return 0;
  104. return BIO_callback_ctrl(BIO_next(bio), cmd, fp);
  105. }
  106. static BIO_METHOD *g_async_bio_method = NULL;
  107. static const BIO_METHOD *AsyncMethod(void)
  108. {
  109. if (g_async_bio_method == NULL) {
  110. g_async_bio_method = BIO_meth_new(BIO_TYPE_FILTER, "async bio");
  111. if ( g_async_bio_method == NULL
  112. || !BIO_meth_set_write(g_async_bio_method, AsyncWrite)
  113. || !BIO_meth_set_read(g_async_bio_method, AsyncRead)
  114. || !BIO_meth_set_ctrl(g_async_bio_method, AsyncCtrl)
  115. || !BIO_meth_set_create(g_async_bio_method, AsyncNew)
  116. || !BIO_meth_set_destroy(g_async_bio_method, AsyncFree)
  117. || !BIO_meth_set_callback_ctrl(g_async_bio_method, AsyncCallbackCtrl))
  118. return NULL;
  119. }
  120. return g_async_bio_method;
  121. }
  122. } // namespace
  123. bssl::UniquePtr<BIO> AsyncBioCreate() {
  124. return bssl::UniquePtr<BIO>(BIO_new(AsyncMethod()));
  125. }
  126. bssl::UniquePtr<BIO> AsyncBioCreateDatagram() {
  127. bssl::UniquePtr<BIO> ret(BIO_new(AsyncMethod()));
  128. if (!ret) {
  129. return nullptr;
  130. }
  131. GetData(ret.get())->datagram = true;
  132. return ret;
  133. }
  134. void AsyncBioAllowRead(BIO *bio, size_t count) {
  135. AsyncBio *a = GetData(bio);
  136. if (a == NULL) {
  137. return;
  138. }
  139. a->read_quota += count;
  140. }
  141. void AsyncBioAllowWrite(BIO *bio, size_t count) {
  142. AsyncBio *a = GetData(bio);
  143. if (a == NULL) {
  144. return;
  145. }
  146. a->write_quota += count;
  147. }
  148. void AsyncBioEnforceWriteQuota(BIO *bio, bool enforce) {
  149. AsyncBio *a = GetData(bio);
  150. if (a == NULL) {
  151. return;
  152. }
  153. a->enforce_write_quota = enforce;
  154. }