| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent c63e873 commit 4018f3a
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -240,7 +240,7 @@ int SelectALPNCallback( | |||
| 240 | 240 | unsigned int inlen, | |
| 241 | 241 | void* arg) { | |
| 242 | 242 | TLSWrap* w = static_cast<TLSWrap*>(SSL_get_app_data(s)); | |
| 243 | - if (w->alpn_callback_enabled_) { | ||
| 243 | + if (w->get_alpn_callback_enabled()) { | ||
| 244 | 244 | Environment* env = w->env(); | |
| 245 | 245 | HandleScope handle_scope(env->isolate()); | |
| 246 | 246 | ||
@@ -275,7 +275,7 @@ int SelectALPNCallback( | |||
| 275 | 275 | return SSL_TLSEXT_ERR_OK; | |
| 276 | 276 | } | |
| 277 | 277 | ||
| 278 | - const std::vector<unsigned char>& alpn_protos = w->alpn_protos_; | ||
| 278 | + auto& alpn_protos = w->get_alpn_protos(); | ||
| 279 | 279 | ||
| 280 | 280 | if (alpn_protos.empty()) return SSL_TLSEXT_ERR_NOACK; | |
| 281 | 281 | ||
@@ -403,9 +403,9 @@ TLSWrap::TLSWrap(Environment* env, | |||
| 403 | 403 | StreamBase(env), | |
| 404 | 404 | env_(env), | |
| 405 | 405 | kind_(kind), | |
| 406 | - sc_(sc), | ||
| 407 | - has_active_write_issued_by_prev_listener_( | ||
| 408 | - under_stream_ws == UnderlyingStreamWriteStatus::kHasActive) { | ||
| 406 | + sc_(sc) { | ||
| 407 | + flags_.has_active_write_issued_by_prev_listener = | ||
| 408 | + under_stream_ws == UnderlyingStreamWriteStatus::kHasActive; | ||
| 409 | 409 | MakeWeak(); | |
| 410 | 410 | CHECK(sc_); | |
| 411 | 411 | ssl_ = sc_->CreateSSL(); | |
@@ -444,8 +444,7 @@ SSL_SESSION* TLSWrap::ReleaseSession() { | |||
| 444 | 444 | ||
| 445 | 445 | void TLSWrap::InvokeQueued(int status, const char* error_str) { | |
| 446 | 446 | Debug(this, "Invoking queued write callbacks (%d, %s)", status, error_str); | |
| 447 | - if (!write_callback_scheduled_) | ||
| 448 | - return; | ||
| 447 | + if (!flags_.write_callback_scheduled) return; | ||
| 449 | 448 | ||
| 450 | 449 | if (current_write_) { | |
| 451 | 450 | BaseObjectPtr<AsyncWrap> current_write = std::move(current_write_); | |
@@ -465,8 +464,8 @@ void TLSWrap::NewSessionDoneCb() { | |||
| 465 | 464 | bool TLSWrap::OnEarlyClientHello(const unsigned char* session_id, | |
| 466 | 465 | size_t session_id_len, | |
| 467 | 466 | bool has_ticket) { | |
| 468 | - if (!hello_emitted_) { | ||
| 469 | - hello_emitted_ = true; | ||
| 467 | + if (!flags_.hello_emitted) { | ||
| 468 | + flags_.hello_emitted = true; | ||
| 470 | 469 | Debug(this, "Scheduling onclienthello"); | |
| 471 | 470 | ||
| 472 | 471 | // The hello data is only valid inside the library callback, and JS must | |
@@ -480,7 +479,7 @@ bool TLSWrap::OnEarlyClientHello(const unsigned char* session_id, | |||
| 480 | 479 | if (ssl_) EmitClientHello(id, has_ticket); | |
| 481 | 480 | }); | |
| 482 | 481 | } | |
| 483 | - return hello_answered_; | ||
| 482 | + return flags_.hello_answered; | ||
| 484 | 483 | } | |
| 485 | 484 | ||
| 486 | 485 | void TLSWrap::EmitClientHello(const std::vector<unsigned char>& session_id, | |
@@ -658,8 +657,8 @@ void TLSWrap::Start(const FunctionCallbackInfo<Value>& args) { | |||
| 658 | 657 | TLSWrap* wrap; | |
| 659 | 658 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.This()); | |
| 660 | 659 | ||
| 661 | - CHECK(!wrap->started_); | ||
| 662 | - wrap->started_ = true; | ||
| 660 | + CHECK(!wrap->flags_.started); | ||
| 661 | + wrap->flags_.started = true; | ||
| 663 | 662 | ||
| 664 | 663 | // Send ClientHello handshake | |
| 665 | 664 | CHECK(wrap->is_client()); | |
@@ -703,7 +702,7 @@ void TLSWrap::SSLInfoCallback(const SSL* ssl_, int where, int ret) { | |||
| 703 | 702 | CHECK(!SSL_renegotiate_pending(ssl)); | |
| 704 | 703 | Local<Value> callback; | |
| 705 | 704 | ||
| 706 | - c->established_ = true; | ||
| 705 | + c->flags_.established = true; | ||
| 707 | 706 | ||
| 708 | 707 | if (object->Get(env->context(), env->onhandshakedone_string()) | |
| 709 | 708 | .ToLocal(&callback) && callback->IsFunction()) { | |
@@ -727,17 +726,17 @@ void TLSWrap::EncOut() { | |||
| 727 | 726 | return; | |
| 728 | 727 | } | |
| 729 | 728 | ||
| 730 | - if (has_active_write_issued_by_prev_listener_) [[unlikely]] { | ||
| 729 | + if (flags_.has_active_write_issued_by_prev_listener) [[unlikely]] { | ||
| 731 | 730 | Debug(this, | |
| 732 | 731 | "Returning from EncOut(), " | |
| 733 | 732 | "has_active_write_issued_by_prev_listener_ is true"); | |
| 734 | 733 | return; | |
| 735 | 734 | } | |
| 736 | 735 | ||
| 737 | 736 | // Split-off queue | |
| 738 | - if (established_ && current_write_) { | ||
| 737 | + if (flags_.established && current_write_) { | ||
| 739 | 738 | Debug(this, "EncOut() write is scheduled"); | |
| 740 | - write_callback_scheduled_ = true; | ||
| 739 | + flags_.write_callback_scheduled = true; | ||
| 741 | 740 | } | |
| 742 | 741 | ||
| 743 | 742 | if (ssl_ == nullptr) { | |
@@ -750,7 +749,7 @@ void TLSWrap::EncOut() { | |||
| 750 | 749 | Debug(this, "No pending encrypted output"); | |
| 751 | 750 | if (!pending_cleartext_input_ || | |
| 752 | 751 | pending_cleartext_input_->ByteLength() == 0) { | |
| 753 | - if (!in_dowrite_) { | ||
| 752 | + if (!flags_.in_dowrite) { | ||
| 754 | 753 | Debug(this, "No pending cleartext input, not inside DoWrite()"); | |
| 755 | 754 | InvokeQueued(0); | |
| 756 | 755 | } else { | |
@@ -805,7 +804,7 @@ void TLSWrap::EncOut() { | |||
| 805 | 804 | void TLSWrap::OnStreamAfterWrite(WriteWrap* req_wrap, int status) { | |
| 806 | 805 | Debug(this, "OnStreamAfterWrite(status = %d)", status); | |
| 807 | 806 | ||
| 808 | - if (has_active_write_issued_by_prev_listener_) [[unlikely]] { | ||
| 807 | + if (flags_.has_active_write_issued_by_prev_listener) [[unlikely]] { | ||
| 809 | 808 | Debug(this, "Notify write finish to the previous_listener_"); | |
| 810 | 809 | CHECK_EQ(write_size_, 0); // we must have restrained writes | |
| 811 | 810 | ||
@@ -830,7 +829,7 @@ void TLSWrap::OnStreamAfterWrite(WriteWrap* req_wrap, int status) { | |||
| 830 | 829 | ||
| 831 | 830 | // Handle error | |
| 832 | 831 | if (status) { | |
| 833 | - if (shutdown_) { | ||
| 832 | + if (flags_.shutdown) { | ||
| 834 | 833 | Debug(this, "Ignoring error after shutdown"); | |
| 835 | 834 | return; | |
| 836 | 835 | } | |
@@ -855,7 +854,7 @@ void TLSWrap::ClearOut() { | |||
| 855 | 854 | Debug(this, "Trying to read cleartext output"); | |
| 856 | 855 | ||
| 857 | 856 | // No reads after EOF | |
| 858 | - if (eof_) { | ||
| 857 | + if (flags_.eof) { | ||
| 859 | 858 | Debug(this, "Returning from ClearOut(), EOF reached"); | |
| 860 | 859 | return; | |
| 861 | 860 | } | |
@@ -911,8 +910,8 @@ void TLSWrap::ClearOut() { | |||
| 911 | 910 | int err = SSL_get_error(ssl_.get(), read); | |
| 912 | 911 | switch (err) { | |
| 913 | 912 | case SSL_ERROR_ZERO_RETURN: | |
| 914 | - if (!eof_) { | ||
| 915 | - eof_ = true; | ||
| 913 | + if (!flags_.eof) { | ||
| 914 | + flags_.eof = true; | ||
| 916 | 915 | EmitRead(UV_EOF); | |
| 917 | 916 | } | |
| 918 | 917 | return; | |
@@ -1005,7 +1004,7 @@ void TLSWrap::ClearIn() { | |||
| 1005 | 1004 | int err = SSL_get_error(ssl_.get(), written); | |
| 1006 | 1005 | if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL) { | |
| 1007 | 1006 | Debug(this, "Got SSL error (%d)", err); | |
| 1008 | - write_callback_scheduled_ = true; | ||
| 1007 | + flags_.write_callback_scheduled = true; | ||
| 1009 | 1008 | // TODO(@sam-github) Should forward an error object with | |
| 1010 | 1009 | // .code/.function/.etc, if possible. | |
| 1011 | 1010 | InvokeQueued(UV_EPROTO, GetBIOError().c_str()); | |
@@ -1049,7 +1048,7 @@ bool TLSWrap::IsClosing() { | |||
| 1049 | 1048 | ||
| 1050 | 1049 | int TLSWrap::ReadStart() { | |
| 1051 | 1050 | Debug(this, "ReadStart()"); | |
| 1052 | - if (underlying_stream() != nullptr && !eof_) | ||
| 1051 | + if (underlying_stream() != nullptr && !flags_.eof) | ||
| 1053 | 1052 | return underlying_stream()->ReadStart(); | |
| 1054 | 1053 | return 0; | |
| 1055 | 1054 | } | |
@@ -1197,9 +1196,9 @@ int TLSWrap::DoWrite(WriteWrap* w, | |||
| 1197 | 1196 | ||
| 1198 | 1197 | // Write any encrypted/handshake output that may be ready. | |
| 1199 | 1198 | // Guard against sync call of current_write_->Done(), its unsupported. | |
| 1200 | - in_dowrite_ = true; | ||
| 1199 | + flags_.in_dowrite = true; | ||
| 1201 | 1200 | EncOut(); | |
| 1202 | - in_dowrite_ = false; | ||
| 1201 | + flags_.in_dowrite = false; | ||
| 1203 | 1202 | ||
| 1204 | 1203 | return 0; | |
| 1205 | 1204 | } | |
@@ -1216,16 +1215,15 @@ void TLSWrap::OnStreamRead(ssize_t nread, const uv_buf_t& buf) { | |||
| 1216 | 1215 | Debug(this, "Read %zd bytes from underlying stream", nread); | |
| 1217 | 1216 | ||
| 1218 | 1217 | // Ignore everything after close_notify (rfc5246#section-7.2.1) | |
| 1219 | - if (eof_) | ||
| 1220 | - return; | ||
| 1218 | + if (flags_.eof) return; | ||
| 1221 | 1219 | ||
| 1222 | 1220 | if (nread < 0) { | |
| 1223 | 1221 | // Error should be emitted only after all data was read | |
| 1224 | 1222 | ClearOut(); | |
| 1225 | 1223 | ||
| 1226 | 1224 | if (nread == UV_EOF) { | |
| 1227 | 1225 | // underlying stream already should have also called ReadStop on itself | |
| 1228 | - eof_ = true; | ||
| 1226 | + flags_.eof = true; | ||
| 1229 | 1227 | } | |
| 1230 | 1228 | ||
| 1231 | 1229 | EmitRead(nread); | |
@@ -1256,7 +1254,7 @@ int TLSWrap::DoShutdown(ShutdownWrap* req_wrap) { | |||
| 1256 | 1254 | if (ssl_ && SSL_shutdown(ssl_.get()) == 0) | |
| 1257 | 1255 | SSL_shutdown(ssl_.get()); | |
| 1258 | 1256 | ||
| 1259 | - shutdown_ = true; | ||
| 1257 | + flags_.shutdown = true; | ||
| 1260 | 1258 | EncOut(); | |
| 1261 | 1259 | return underlying_stream()->DoShutdown(req_wrap); | |
| 1262 | 1260 | } | |
@@ -1352,7 +1350,7 @@ void TLSWrap::Destroy() { | |||
| 1352 | 1350 | return; | |
| 1353 | 1351 | ||
| 1354 | 1352 | // If there is a write happening, mark it as finished. | |
| 1355 | - write_callback_scheduled_ = true; | ||
| 1353 | + flags_.write_callback_scheduled = true; | ||
| 1356 | 1354 | ||
| 1357 | 1355 | // And destroy | |
| 1358 | 1356 | InvokeQueued(UV_ECANCELED, "Canceled because of SSL destruction"); | |
@@ -1389,7 +1387,7 @@ void TLSWrap::ResumeAfterCertCb(void* arg) { | |||
| 1389 | 1387 | void TLSWrap::EnableALPNCb(const FunctionCallbackInfo<Value>& args) { | |
| 1390 | 1388 | TLSWrap* wrap; | |
| 1391 | 1389 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.This()); | |
| 1392 | - wrap->alpn_callback_enabled_ = true; | ||
| 1390 | + wrap->flags_.alpn_callback_enabled = true; | ||
| 1393 | 1391 | ||
| 1394 | 1392 | SSL* ssl = wrap->ssl_.get(); | |
| 1395 | 1393 | SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(ssl); | |
@@ -1418,7 +1416,7 @@ void TLSWrap::SetServername(const FunctionCallbackInfo<Value>& args) { | |||
| 1418 | 1416 | ||
| 1419 | 1417 | CHECK_EQ(args.Length(), 1); | |
| 1420 | 1418 | CHECK(args[0]->IsString()); | |
| 1421 | - CHECK(!wrap->started_); | ||
| 1419 | + CHECK(!wrap->flags_.started); | ||
| 1422 | 1420 | CHECK(wrap->is_client()); | |
| 1423 | 1421 | ||
| 1424 | 1422 | CHECK(wrap->ssl_); | |
@@ -1633,7 +1631,7 @@ void TLSWrap::CertCbDone(const FunctionCallbackInfo<Value>& args) { | |||
| 1633 | 1631 | TLSWrap* w; | |
| 1634 | 1632 | ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); | |
| 1635 | 1633 | ||
| 1636 | - CHECK(w->is_waiting_cert_cb() && w->cert_cb_running_); | ||
| 1634 | + CHECK(w->is_waiting_cert_cb() && w->flags_.cert_cb_running); | ||
| 1637 | 1635 | ||
| 1638 | 1636 | Local<Object> object = w->object(); | |
| 1639 | 1637 | Local<Value> ctx = object->Get(env->context(), env->sni_context_string()) | |
@@ -1685,7 +1683,7 @@ void TLSWrap::CertCbDone(const FunctionCallbackInfo<Value>& args) { | |||
| 1685 | 1683 | cb = w->cert_cb_; | |
| 1686 | 1684 | arg = w->cert_cb_arg_; | |
| 1687 | 1685 | ||
| 1688 | - w->cert_cb_running_ = false; | ||
| 1686 | + w->flags_.cert_cb_running = false; | ||
| 1689 | 1687 | w->cert_cb_ = nullptr; | |
| 1690 | 1688 | w->cert_cb_arg_ = nullptr; | |
| 1691 | 1689 | ||
@@ -2072,7 +2070,7 @@ void TLSWrap::ExportKeyingMaterial(const FunctionCallbackInfo<Value>& args) { | |||
| 2072 | 2070 | void TLSWrap::ClientHelloDone(const FunctionCallbackInfo<Value>& args) { | |
| 2073 | 2071 | TLSWrap* w; | |
| 2074 | 2072 | ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); | |
| 2075 | - w->hello_answered_ = true; | ||
| 2073 | + w->flags_.hello_answered = true; | ||
| 2076 | 2074 | w->Cycle(); | |
| 2077 | 2075 | } | |
| 2078 | 2076 | ||
@@ -2107,7 +2105,7 @@ void TLSWrap::GetTLSTicket(const FunctionCallbackInfo<Value>& args) { | |||
| 2107 | 2105 | void TLSWrap::NewSessionDone(const FunctionCallbackInfo<Value>& args) { | |
| 2108 | 2106 | TLSWrap* w; | |
| 2109 | 2107 | ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); | |
| 2110 | - w->awaiting_new_session_ = false; | ||
| 2108 | + w->flags_.awaiting_new_session = false; | ||
| 2111 | 2109 | w->NewSessionDoneCb(); | |
| 2112 | 2110 | } | |
| 2113 | 2111 | ||
@@ -2188,7 +2186,7 @@ void TLSWrap::WritesIssuedByPrevListenerDone( | |||
| 2188 | 2186 | ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); | |
| 2189 | 2187 | ||
| 2190 | 2188 | Debug(w, "WritesIssuedByPrevListenerDone is called"); | |
| 2191 | - w->has_active_write_issued_by_prev_listener_ = false; | ||
| 2189 | + w->flags_.has_active_write_issued_by_prev_listener = false; | ||
| 2192 | 2190 | w->EncOut(); // resume all of our restrained writes | |
| 2193 | 2191 | } | |
| 2194 | 2192 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -62,22 +62,26 @@ class TLSWrap : public AsyncWrap, | |||
| 62 | 62 | ||
| 63 | 63 | ~TLSWrap() override; | |
| 64 | 64 | ||
| 65 | - inline bool is_cert_cb_running() const { return cert_cb_running_; } | ||
| 65 | + inline bool is_cert_cb_running() const { return flags_.cert_cb_running; } | ||
| 66 | 66 | inline bool is_waiting_cert_cb() const { return cert_cb_ != nullptr; } | |
| 67 | - inline bool has_session_callbacks() const { return session_callbacks_; } | ||
| 67 | + inline bool has_session_callbacks() const { return flags_.session_callbacks; } | ||
| 68 | 68 | // We need to suspend the ClientHello only for server session id | |
| 69 | 69 | // callbacks, and only on the first pass. | |
| 70 | 70 | inline bool should_suspend_for_client_hello() const { | |
| 71 | - return is_server() && session_callbacks_ && !hello_answered_; | ||
| 71 | + return is_server() && flags_.session_callbacks && !flags_.hello_answered; | ||
| 72 | + } | ||
| 73 | + inline void set_cert_cb_running(bool on = true) { | ||
| 74 | + flags_.cert_cb_running = on; | ||
| 72 | 75 | } | |
| 73 | - inline void set_cert_cb_running(bool on = true) { cert_cb_running_ = on; } | ||
| 74 | 76 | inline void set_awaiting_new_session(bool on = true) { | |
| 75 | - awaiting_new_session_ = on; | ||
| 77 | + flags_.awaiting_new_session = on; | ||
| 76 | 78 | } | |
| 77 | - inline void enable_session_callbacks() { session_callbacks_ = true; } | ||
| 79 | + inline void enable_session_callbacks() { flags_.session_callbacks = true; } | ||
| 78 | 80 | inline bool is_server() const { return kind_ == Kind::kServer; } | |
| 79 | 81 | inline bool is_client() const { return kind_ == Kind::kClient; } | |
| 80 | - inline bool is_awaiting_new_session() const { return awaiting_new_session_; } | ||
| 82 | + inline bool is_awaiting_new_session() const { | ||
| 83 | + return flags_.awaiting_new_session; | ||
| 84 | + } | ||
| 81 | 85 | ||
| 82 | 86 | // Implement StreamBase: | |
| 83 | 87 | bool IsAlive() override; | |
@@ -125,6 +129,14 @@ class TLSWrap : public AsyncWrap, | |||
| 125 | 129 | ||
| 126 | 130 | std::string diagnostic_name() const override; | |
| 127 | 131 | ||
| 132 | + bool get_alpn_callback_enabled() const { | ||
| 133 | + return flags_.alpn_callback_enabled; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + const std::vector<unsigned char>& get_alpn_protos() const { | ||
| 137 | + return alpn_protos_; | ||
| 138 | + } | ||
| 139 | + | ||
| 128 | 140 | private: | |
| 129 | 141 | // OpenSSL structures are opaque. Estimate SSL memory size for OpenSSL 1.1.1b: | |
| 130 | 142 | // SSL: 6224 | |
@@ -284,26 +296,30 @@ class TLSWrap : public AsyncWrap, | |||
| 284 | 296 | BaseObjectPtr<AsyncWrap> current_empty_write_; | |
| 285 | 297 | std::string error_; | |
| 286 | 298 | ||
| 287 | - bool session_callbacks_ = false; | ||
| 288 | - bool awaiting_new_session_ = false; | ||
| 289 | - // 'onclienthello' has been emitted for this connection. | ||
| 290 | - bool hello_emitted_ = false; | ||
| 291 | - // JS has answered it by calling clientHelloDone(). | ||
| 292 | - bool hello_answered_ = false; | ||
| 293 | - bool in_dowrite_ = false; | ||
| 294 | - bool started_ = false; | ||
| 295 | - bool shutdown_ = false; | ||
| 296 | - bool cert_cb_running_ = false; | ||
| 297 | - bool eof_ = false; | ||
| 298 | - | ||
| 299 | 299 | // TODO(@jasnell): These state flags should be revisited. | |
| 300 | 300 | // The established_ flag indicates that the handshake is | |
| 301 | 301 | // completed. The write_callback_scheduled_ flag is less | |
| 302 | 302 | // clear -- once it is set to true, it is never set to | |
| 303 | 303 | // false and it is only set to true after established_ | |
| 304 | 304 | // is set to true, so it's likely redundant. | |
| 305 | - bool established_ = false; | ||
| 306 | - bool write_callback_scheduled_ = false; | ||
| 305 | + struct Flags { | ||
| 306 | + bool session_callbacks : 1; | ||
| 307 | + bool awaiting_new_session : 1; | ||
| 308 | + // 'onclienthello' has been emitted for this connection. | ||
| 309 | + bool hello_emitted : 1; | ||
| 310 | + // JS has answered it by calling clientHelloDone(). | ||
| 311 | + bool hello_answered : 1; | ||
| 312 | + bool in_dowrite : 1; | ||
| 313 | + bool started : 1; | ||
| 314 | + bool shutdown : 1; | ||
| 315 | + bool cert_cb_running : 1; | ||
| 316 | + bool eof : 1; | ||
| 317 | + bool established : 1; | ||
| 318 | + bool write_callback_scheduled : 1; | ||
| 319 | + bool has_active_write_issued_by_prev_listener : 1; | ||
| 320 | + bool alpn_callback_enabled : 1; | ||
| 321 | + }; | ||
| 322 | + Flags flags_{}; | ||
| 307 | 323 | ||
| 308 | 324 | int cycle_depth_ = 0; | |
| 309 | 325 | ||
@@ -313,11 +329,7 @@ class TLSWrap : public AsyncWrap, | |||
| 313 | 329 | ||
| 314 | 330 | ncrypto::BIOPointer bio_trace_; | |
| 315 | 331 | ||
| 316 | - bool has_active_write_issued_by_prev_listener_ = false; | ||
| 317 | - | ||
| 318 | - public: | ||
| 319 | 332 | std::vector<unsigned char> alpn_protos_; // Accessed by SelectALPNCallback. | |
| 320 | - bool alpn_callback_enabled_ = false; // Accessed by SelectALPNCallback. | ||
| 321 | 333 | }; | |
| 322 | 334 | ||
| 323 | 335 | } // namespace crypto | |
| Back | FazBrowse Home | New Git URL |
0 commit comments