選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

192 行
4.9 KiB

  1. /* Copyright (c) 2014, Google Inc.
  2. *
  3. * Permission to use, copy, modify, and/or distribute this software for any
  4. * purpose with or without fee is hereby granted, provided that the above
  5. * copyright notice and this permission notice appear in all copies.
  6. *
  7. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  14. #include "packeted_bio.h"
  15. #include <assert.h>
  16. #include <errno.h>
  17. #include <string.h>
  18. #include <openssl/mem.h>
  19. namespace {
  20. extern const BIO_METHOD packeted_bio_method;
  21. const uint8_t kOpcodePacket = 'P';
  22. const uint8_t kOpcodeTimeout = 'T';
  23. const uint8_t kOpcodeTimeoutAck = 't';
  24. static int packeted_write(BIO *bio, const char *in, int inl) {
  25. if (bio->next_bio == NULL) {
  26. return 0;
  27. }
  28. BIO_clear_retry_flags(bio);
  29. // Write the header.
  30. uint8_t header[5];
  31. header[0] = kOpcodePacket;
  32. header[1] = (inl >> 24) & 0xff;
  33. header[2] = (inl >> 16) & 0xff;
  34. header[3] = (inl >> 8) & 0xff;
  35. header[4] = inl & 0xff;
  36. int ret = BIO_write(bio->next_bio, header, sizeof(header));
  37. if (ret <= 0) {
  38. BIO_copy_next_retry(bio);
  39. return ret;
  40. }
  41. // Write the buffer. BIOs for which this operation fails are not supported.
  42. ret = BIO_write(bio->next_bio, in, inl);
  43. assert(ret == inl);
  44. return ret;
  45. }
  46. static int packeted_read(BIO *bio, char *out, int outl) {
  47. if (bio->next_bio == NULL) {
  48. return 0;
  49. }
  50. BIO_clear_retry_flags(bio);
  51. // Read the opcode.
  52. uint8_t opcode;
  53. int ret = BIO_read(bio->next_bio, &opcode, sizeof(opcode));
  54. if (ret <= 0) {
  55. BIO_copy_next_retry(bio);
  56. return ret;
  57. }
  58. assert(static_cast<size_t>(ret) == sizeof(opcode));
  59. if (opcode == kOpcodeTimeout) {
  60. // Process the timeout.
  61. uint8_t buf[8];
  62. ret = BIO_read(bio->next_bio, &buf, sizeof(buf));
  63. if (ret <= 0) {
  64. BIO_copy_next_retry(bio);
  65. return ret;
  66. }
  67. assert(static_cast<size_t>(ret) == sizeof(buf));
  68. uint64_t timeout = (static_cast<uint64_t>(buf[0]) << 56) |
  69. (static_cast<uint64_t>(buf[1]) << 48) |
  70. (static_cast<uint64_t>(buf[2]) << 40) |
  71. (static_cast<uint64_t>(buf[3]) << 32) |
  72. (static_cast<uint64_t>(buf[4]) << 24) |
  73. (static_cast<uint64_t>(buf[5]) << 16) |
  74. (static_cast<uint64_t>(buf[6]) << 8) |
  75. static_cast<uint64_t>(buf[7]);
  76. timeout /= 1000; // Convert nanoseconds to microseconds.
  77. OPENSSL_timeval *out_timeout =
  78. reinterpret_cast<OPENSSL_timeval *>(bio->ptr);
  79. assert(out_timeout->tv_usec == 0);
  80. assert(out_timeout->tv_sec == 0);
  81. out_timeout->tv_usec = timeout % 1000000;
  82. out_timeout->tv_sec = timeout / 1000000;
  83. // Send an ACK to the peer.
  84. ret = BIO_write(bio->next_bio, &kOpcodeTimeoutAck, 1);
  85. assert(ret == 1);
  86. // Signal to the caller to retry the read, after processing the
  87. // new clock.
  88. BIO_set_retry_read(bio);
  89. return -1;
  90. }
  91. if (opcode != kOpcodePacket) {
  92. fprintf(stderr, "Unknown opcode, %u\n", opcode);
  93. return -1;
  94. }
  95. // Read the length prefix.
  96. uint8_t len_bytes[4];
  97. ret = BIO_read(bio->next_bio, &len_bytes, sizeof(len_bytes));
  98. if (ret <= 0) {
  99. BIO_copy_next_retry(bio);
  100. return ret;
  101. }
  102. // BIOs for which a partial length comes back are not supported.
  103. assert(static_cast<size_t>(ret) == sizeof(len_bytes));
  104. uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
  105. (len_bytes[2] << 8) | len_bytes[3];
  106. char *buf = (char *)OPENSSL_malloc(len);
  107. if (buf == NULL) {
  108. return -1;
  109. }
  110. ret = BIO_read(bio->next_bio, buf, len);
  111. assert(ret == (int)len);
  112. if (outl > (int)len) {
  113. outl = len;
  114. }
  115. memcpy(out, buf, outl);
  116. OPENSSL_free(buf);
  117. return outl;
  118. }
  119. static long packeted_ctrl(BIO *bio, int cmd, long num, void *ptr) {
  120. if (bio->next_bio == NULL) {
  121. return 0;
  122. }
  123. BIO_clear_retry_flags(bio);
  124. int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
  125. BIO_copy_next_retry(bio);
  126. return ret;
  127. }
  128. static int packeted_new(BIO *bio) {
  129. bio->init = 1;
  130. return 1;
  131. }
  132. static int packeted_free(BIO *bio) {
  133. if (bio == NULL) {
  134. return 0;
  135. }
  136. bio->init = 0;
  137. return 1;
  138. }
  139. static long packeted_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
  140. if (bio->next_bio == NULL) {
  141. return 0;
  142. }
  143. return BIO_callback_ctrl(bio->next_bio, cmd, fp);
  144. }
  145. const BIO_METHOD packeted_bio_method = {
  146. BIO_TYPE_FILTER,
  147. "packeted bio",
  148. packeted_write,
  149. packeted_read,
  150. NULL /* puts */,
  151. NULL /* gets */,
  152. packeted_ctrl,
  153. packeted_new,
  154. packeted_free,
  155. packeted_callback_ctrl,
  156. };
  157. } // namespace
  158. BIO *packeted_bio_create(OPENSSL_timeval *out_timeout) {
  159. BIO *bio = BIO_new(&packeted_bio_method);
  160. bio->ptr = out_timeout;
  161. return bio;
  162. }