PageRenderTime 58ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/src/node_crypto_bio.cc

http://github.com/joyent/node
C++ | 400 lines | 276 code | 82 blank | 42 comment | 79 complexity | 4ce446d7ec86684854fa733b16d8606f MD5 | raw file
Possible License(s): 0BSD, BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0, ISC, Apache-2.0, MIT, AGPL-3.0
  1. // Copyright Joyent, Inc. and other Node contributors.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a
  4. // copy of this software and associated documentation files (the
  5. // "Software"), to deal in the Software without restriction, including
  6. // without limitation the rights to use, copy, modify, merge, publish,
  7. // distribute, sublicense, and/or sell copies of the Software, and to permit
  8. // persons to whom the Software is furnished to do so, subject to the
  9. // following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included
  12. // in all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  15. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  17. // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  18. // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  19. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  20. // USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #include "node_crypto_bio.h"
  22. #include "openssl/bio.h"
  23. #include <string.h>
  24. namespace node {
  25. const BIO_METHOD NodeBIO::method = {
  26. BIO_TYPE_MEM,
  27. "node.js SSL buffer",
  28. NodeBIO::Write,
  29. NodeBIO::Read,
  30. NodeBIO::Puts,
  31. NodeBIO::Gets,
  32. NodeBIO::Ctrl,
  33. NodeBIO::New,
  34. NodeBIO::Free,
  35. NULL
  36. };
  37. BIO* NodeBIO::New() {
  38. // The const_cast doesn't violate const correctness. OpenSSL's usage of
  39. // BIO_METHOD is effectively const but BIO_new() takes a non-const argument.
  40. return BIO_new(const_cast<BIO_METHOD*>(&method));
  41. }
  42. int NodeBIO::New(BIO* bio) {
  43. bio->ptr = new NodeBIO();
  44. // XXX Why am I doing it?!
  45. bio->shutdown = 1;
  46. bio->init = 1;
  47. bio->num = -1;
  48. return 1;
  49. }
  50. int NodeBIO::Free(BIO* bio) {
  51. if (bio == NULL) return 0;
  52. if (bio->shutdown) {
  53. if (bio->init && bio->ptr != NULL) {
  54. delete FromBIO(bio);
  55. bio->ptr = NULL;
  56. }
  57. }
  58. return 1;
  59. }
  60. int NodeBIO::Read(BIO* bio, char* out, int len) {
  61. int bytes;
  62. BIO_clear_retry_flags(bio);
  63. bytes = FromBIO(bio)->Read(out, len);
  64. if (bytes == 0) {
  65. bytes = bio->num;
  66. if (bytes != 0) {
  67. BIO_set_retry_read(bio);
  68. }
  69. }
  70. return bytes;
  71. }
  72. char* NodeBIO::Peek(size_t* size) {
  73. *size = read_head_->write_pos_ - read_head_->read_pos_;
  74. return read_head_->data_ + read_head_->read_pos_;
  75. }
  76. int NodeBIO::Write(BIO* bio, const char* data, int len) {
  77. BIO_clear_retry_flags(bio);
  78. FromBIO(bio)->Write(data, len);
  79. return len;
  80. }
  81. int NodeBIO::Puts(BIO* bio, const char* str) {
  82. return Write(bio, str, strlen(str));
  83. }
  84. int NodeBIO::Gets(BIO* bio, char* out, int size) {
  85. NodeBIO* nbio = FromBIO(bio);
  86. if (nbio->Length() == 0)
  87. return 0;
  88. int i = nbio->IndexOf('\n', size);
  89. // Include '\n'
  90. if (i < size) i++;
  91. // Shift `i` a bit to NULL-terminate string later
  92. if (size == i) i--;
  93. // Flush read data
  94. nbio->Read(out, i);
  95. out[i] = 0;
  96. return i;
  97. }
  98. long NodeBIO::Ctrl(BIO* bio, int cmd, long num, void* ptr) {
  99. NodeBIO* nbio;
  100. long ret;
  101. nbio = FromBIO(bio);
  102. ret = 1;
  103. switch (cmd) {
  104. case BIO_CTRL_RESET:
  105. nbio->Reset();
  106. break;
  107. case BIO_CTRL_EOF:
  108. ret = nbio->Length() == 0;
  109. break;
  110. case BIO_C_SET_BUF_MEM_EOF_RETURN:
  111. bio->num = num;
  112. break;
  113. case BIO_CTRL_INFO:
  114. ret = nbio->Length();
  115. if (ptr != NULL)
  116. *reinterpret_cast<void**>(ptr) = NULL;
  117. break;
  118. case BIO_C_SET_BUF_MEM:
  119. assert(0 && "Can't use SET_BUF_MEM_PTR with NodeBIO");
  120. abort();
  121. break;
  122. case BIO_C_GET_BUF_MEM_PTR:
  123. assert(0 && "Can't use GET_BUF_MEM_PTR with NodeBIO");
  124. ret = 0;
  125. break;
  126. case BIO_CTRL_GET_CLOSE:
  127. ret = bio->shutdown;
  128. break;
  129. case BIO_CTRL_SET_CLOSE:
  130. bio->shutdown = num;
  131. break;
  132. case BIO_CTRL_WPENDING:
  133. ret = 0;
  134. break;
  135. case BIO_CTRL_PENDING:
  136. ret = nbio->Length();
  137. break;
  138. case BIO_CTRL_DUP:
  139. case BIO_CTRL_FLUSH:
  140. ret = 1;
  141. break;
  142. case BIO_CTRL_PUSH:
  143. case BIO_CTRL_POP:
  144. default:
  145. ret = 0;
  146. break;
  147. }
  148. return ret;
  149. }
  150. size_t NodeBIO::Read(char* out, size_t size) {
  151. size_t bytes_read = 0;
  152. size_t expected = Length() > size ? size : Length();
  153. size_t offset = 0;
  154. size_t left = size;
  155. while (bytes_read < expected) {
  156. assert(read_head_->read_pos_ <= read_head_->write_pos_);
  157. size_t avail = read_head_->write_pos_ - read_head_->read_pos_;
  158. if (avail > left)
  159. avail = left;
  160. // Copy data
  161. if (out != NULL)
  162. memcpy(out + offset, read_head_->data_ + read_head_->read_pos_, avail);
  163. read_head_->read_pos_ += avail;
  164. // Move pointers
  165. bytes_read += avail;
  166. offset += avail;
  167. left -= avail;
  168. // Move to next buffer
  169. if (read_head_->read_pos_ == read_head_->write_pos_) {
  170. read_head_->read_pos_ = 0;
  171. read_head_->write_pos_ = 0;
  172. // But not get beyond write_head_
  173. if (length_ != bytes_read && read_head_ != write_head_) {
  174. read_head_ = read_head_->next_;
  175. }
  176. }
  177. }
  178. assert(expected == bytes_read);
  179. length_ -= bytes_read;
  180. // Free all empty buffers, but write_head's child
  181. FreeEmpty();
  182. return bytes_read;
  183. }
  184. void NodeBIO::FreeEmpty() {
  185. Buffer* child = write_head_->next_;
  186. if (child == write_head_ || child == read_head_)
  187. return;
  188. Buffer* cur = child->next_;
  189. if (cur == write_head_ || cur == read_head_)
  190. return;
  191. Buffer* prev = child;
  192. while (cur != read_head_) {
  193. // Skip embedded buffer, and continue deallocating again starting from it
  194. if (cur == &head_) {
  195. prev->next_ = cur;
  196. prev = cur;
  197. cur = head_.next_;
  198. continue;
  199. }
  200. assert(cur != write_head_);
  201. assert(cur->write_pos_ == cur->read_pos_);
  202. Buffer* next = cur->next_;
  203. delete cur;
  204. cur = next;
  205. }
  206. assert(prev == child || prev == &head_);
  207. prev->next_ = cur;
  208. }
  209. size_t NodeBIO::IndexOf(char delim, size_t limit) {
  210. size_t bytes_read = 0;
  211. size_t max = Length() > limit ? limit : Length();
  212. size_t left = limit;
  213. Buffer* current = read_head_;
  214. while (bytes_read < max) {
  215. assert(current->read_pos_ <= current->write_pos_);
  216. size_t avail = current->write_pos_ - current->read_pos_;
  217. if (avail > left)
  218. avail = left;
  219. // Walk through data
  220. char* tmp = current->data_ + current->read_pos_;
  221. size_t off = 0;
  222. while (off < avail && *tmp != delim) {
  223. off++;
  224. tmp++;
  225. }
  226. // Move pointers
  227. bytes_read += off;
  228. left -= off;
  229. // Found `delim`
  230. if (off != avail) {
  231. return bytes_read;
  232. }
  233. // Move to next buffer
  234. if (current->read_pos_ + avail == kBufferLength) {
  235. current = current->next_;
  236. }
  237. }
  238. assert(max == bytes_read);
  239. return max;
  240. }
  241. void NodeBIO::Write(const char* data, size_t size) {
  242. size_t offset = 0;
  243. size_t left = size;
  244. while (left > 0) {
  245. size_t to_write = left;
  246. assert(write_head_->write_pos_ <= kBufferLength);
  247. size_t avail = kBufferLength - write_head_->write_pos_;
  248. if (to_write > avail)
  249. to_write = avail;
  250. // Copy data
  251. memcpy(write_head_->data_ + write_head_->write_pos_,
  252. data + offset,
  253. to_write);
  254. // Move pointers
  255. left -= to_write;
  256. offset += to_write;
  257. length_ += to_write;
  258. write_head_->write_pos_ += to_write;
  259. assert(write_head_->write_pos_ <= kBufferLength);
  260. // Go to next buffer if there still are some bytes to write
  261. if (left != 0) {
  262. assert(write_head_->write_pos_ == kBufferLength);
  263. TryAllocateForWrite();
  264. write_head_ = write_head_->next_;
  265. }
  266. }
  267. assert(left == 0);
  268. }
  269. char* NodeBIO::PeekWritable(size_t* size) {
  270. size_t available = kBufferLength - write_head_->write_pos_;
  271. if (*size != 0 && available > *size)
  272. available = *size;
  273. else
  274. *size = available;
  275. return write_head_->data_ + write_head_->write_pos_;
  276. }
  277. void NodeBIO::Commit(size_t size) {
  278. write_head_->write_pos_ += size;
  279. length_ += size;
  280. assert(write_head_->write_pos_ <= kBufferLength);
  281. // Allocate new buffer if write head is full,
  282. // and there're no other place to go
  283. TryAllocateForWrite();
  284. if (write_head_->write_pos_ == kBufferLength)
  285. write_head_ = write_head_->next_;
  286. }
  287. void NodeBIO::TryAllocateForWrite() {
  288. // If write head is full, next buffer is either read head or not empty.
  289. if (write_head_->write_pos_ == kBufferLength &&
  290. (write_head_->next_ == read_head_ ||
  291. write_head_->next_->write_pos_ != 0)) {
  292. Buffer* next = new Buffer();
  293. next->next_ = write_head_->next_;
  294. write_head_->next_ = next;
  295. }
  296. }
  297. void NodeBIO::Reset() {
  298. while (read_head_->read_pos_ != read_head_->write_pos_) {
  299. assert(read_head_->write_pos_ > read_head_->read_pos_);
  300. length_ -= read_head_->write_pos_ - read_head_->read_pos_;
  301. read_head_->write_pos_ = 0;
  302. read_head_->read_pos_ = 0;
  303. read_head_ = read_head_->next_;
  304. }
  305. write_head_ = read_head_;
  306. assert(length_ == 0);
  307. }
  308. NodeBIO::~NodeBIO() {
  309. Buffer* current = head_.next_;
  310. while (current != &head_) {
  311. Buffer* next = current->next_;
  312. delete current;
  313. current = next;
  314. }
  315. read_head_ = NULL;
  316. write_head_ = NULL;
  317. }
  318. } // namespace node