NCBI C++ ToolKit
ncbi_uv_nghttp2.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_uv_nghttp2.cpp 102329 2024-04-23 19:21:48Z ucko $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Rafael Sadyrov
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 
32 #define HAVE_LOCAL_NCBI_BUILD_VER_H 1
33 
34 #include "connect_misc_impl.hpp"
35 
37 #include <connect/ncbi_socket.hpp>
38 #include <connect/ncbi_tls.h>
39 
40 #include <corelib/ncbiapp.hpp>
41 #include <corelib/request_ctx.hpp>
42 
43 #include <psa/crypto.h>
44 
46 
47 #define NCBI_UV_WRITE_TRACE(message) _TRACE(message)
48 #define NCBI_UV_TCP_TRACE(message) _TRACE(message)
49 #define NCBI_NGHTTP2_SESSION_TRACE(message) _TRACE(message)
50 #define NCBI_UVNGHTTP2_TLS_TRACE(message) _TRACE(message)
51 #define NCBI_UVNGHTTP2_SESSION_TRACE(message) _TRACE(message)
52 
53 using namespace NCBI_XCONNECT;
54 
57 {
58  mbedtls_strerror(static_cast<int>(e), data(), size());
59  return data();
60 }
61 
62 SUv_Write::SUv_Write(void* user_data, size_t buf_size) :
63  m_UserData(user_data),
64  m_BufSize(buf_size)
65 {
66  NewBuffer();
67  NCBI_UV_WRITE_TRACE(this << " created");
68 }
69 
70 int SUv_Write::Write(uv_stream_t* handle, uv_write_cb cb)
71 {
73  auto& request = m_CurrentBuffer->request;
74  auto& data = m_CurrentBuffer->data;
75  auto& in_progress = m_CurrentBuffer->in_progress;
76 
77  _ASSERT(!in_progress);
78 
79  if (data.empty()) {
80  NCBI_UV_WRITE_TRACE(this << " empty write");
81  return 0;
82  }
83 
84  uv_buf_t buf;
85  buf.base = data.data();
86  buf.len = static_cast<decltype(buf.len)>(data.size());
87 
88  auto try_rv = uv_try_write(handle, &buf, 1);
89 
90  // If immediately sent everything
91  if (try_rv == static_cast<int>(data.size())) {
92  NCBI_UV_WRITE_TRACE(this << '/' << &request << " try-wrote: " << try_rv);
93  data.clear();
94  return 0;
95 
96  // If sent partially
97  } else if (try_rv > 0) {
98  NCBI_UV_WRITE_TRACE(this << '/' << &request << " try-wrote partially: " << try_rv);
99  _ASSERT(try_rv < static_cast<int>(data.size()));
100  buf.base += try_rv;
101  buf.len -= try_rv;
102 
103  // If unexpected error
104  } else if (try_rv != UV_EAGAIN) {
105  NCBI_UV_WRITE_TRACE(this << '/' << &request << " try-write failed: " << SUvNgHttp2_Error::LibuvStr(try_rv));
106  return try_rv;
107  }
108 
109  auto rv = uv_write(&request, handle, &buf, 1, cb);
110 
111  if (rv < 0) {
112  NCBI_UV_WRITE_TRACE(this << '/' << &request << " pre-write failed: " << SUvNgHttp2_Error::LibuvStr(rv));
113  return rv;
114  }
115 
116  NCBI_UV_WRITE_TRACE(this << '/' << &request << " writing: " << data.size());
117  in_progress = true;
118 
119  // Looking for unused buffer
120  for (auto& buffer : m_Buffers) {
121  if (!buffer.in_progress) {
122  _ASSERT(buffer.data.empty());
123 
124  NCBI_UV_WRITE_TRACE(this << '/' << &buffer.request << " switching to");
126  return 0;
127  }
128  }
129 
130  // Need more buffers
131  NewBuffer();
132  return 0;
133 }
134 
135 void SUv_Write::OnWrite(uv_write_t* req)
136 {
137  for (auto& buffer : m_Buffers) {
138  if (&buffer.request == req) {
139  _ASSERT(buffer.data.size());
140  _ASSERT(buffer.in_progress);
141 
142  NCBI_UV_WRITE_TRACE(this << '/' << req << " wrote");
143  buffer.data.clear();
144  buffer.in_progress = false;
145  return;
146  }
147  }
148 
149  _TROUBLE;
150 }
151 
153 {
154  NCBI_UV_WRITE_TRACE(this << " reset");
155 
156  for (auto& buffer : m_Buffers) {
157  buffer.data.clear();
158  buffer.in_progress = false;
159  }
160 }
161 
163 {
164  m_Buffers.emplace_front();
165  m_CurrentBuffer = &m_Buffers.front();
166 
167  NCBI_UV_WRITE_TRACE(this << '/' << &m_CurrentBuffer->request << " new buffer");
169  m_CurrentBuffer->data.reserve(m_BufSize);
170 }
171 
172 
173 SUv_Connect::SUv_Connect(void* user_data, const SSocketAddress& address)
174 {
175  m_Request.data = user_data;
176 
177  m_Address.sin_family = AF_INET;
178  m_Address.sin_addr.s_addr = address.host;
179  m_Address.sin_port = CSocketAPI::HostToNetShort(address.port);
180 #ifdef HAVE_SIN_LEN
181  m_Address.sin_len = sizeof(m_Address);
182 #endif
183 }
184 
185 int SUv_Connect::operator()(uv_tcp_t* handle, uv_connect_cb cb)
186 {
187  return uv_tcp_connect(&m_Request, handle, reinterpret_cast<sockaddr*>(&m_Address), cb);
188 }
189 
190 
191 SUv_Tcp::SUv_Tcp(uv_loop_t *l, const SSocketAddress& address, size_t rd_buf_size, size_t wr_buf_size,
192  TConnectCb connect_cb, TReadCb rcb, TWriteCb write_cb) :
193  SUv_Handle<uv_tcp_t>(s_OnClose),
194  m_Loop(l),
195  m_Connect(this, address),
196  m_Write(this, wr_buf_size),
197  m_ConnectCb(connect_cb),
198  m_ReadCb(rcb),
199  m_WriteCb(write_cb)
200 {
201  data = this;
202  m_ReadBuffer.reserve(rd_buf_size);
203 
204  _DEBUG_CODE(address.GetHostName();); // To avoid splitting the trace message below by gethostbyaddr
205  NCBI_UV_TCP_TRACE(this << '/' << address << " created");
206 }
207 
209 {
210  if (m_State == eClosing) {
212  }
213 
214  if (m_State == eClosed) {
215  auto rv = Connect();
216 
217  if (rv < 0) {
218  return rv;
219  }
220  }
221 
222  if (m_State == eConnected) {
223  auto rv = m_Write.Write((uv_stream_t*)this, s_OnWrite);
224 
225  if (rv < 0) {
226  NCBI_UV_TCP_TRACE(this << " pre-write failed: " << SUvNgHttp2_Error::LibuvStr(rv));
227  Close();
228  return rv;
229  }
230 
231  NCBI_UV_TCP_TRACE(this << " writing");
232  }
233 
234  return 0;
235 }
236 
237 // uv_tcp_close_reset was added in libuv v1.32.0
238 #if UV_VERSION_HEX < 0x12000
240 {
241  return false;
242 }
243 #else
244 bool SUv_Tcp::CloseReset(ECloseType close_type)
245 {
246  if (close_type == eNormalClose) {
247  return false;
248  }
249 
250  auto rv = uv_tcp_close_reset(this, s_OnClose);
251 
252  if (rv < 0) {
253  NCBI_UV_TCP_TRACE(this << " close reset failed: " << SUvNgHttp2_Error::LibuvStr(rv));
254  return false;
255  } else {
256  NCBI_UV_TCP_TRACE(this << " close resetting");
257  return true;
258  }
259 }
260 #endif
261 
262 void SUv_Tcp::Close(ECloseType close_type)
263 {
264  if (m_State == eConnected) {
265  auto rv = uv_read_stop(reinterpret_cast<uv_stream_t*>(this));
266 
267  if (rv < 0) {
268  NCBI_UV_TCP_TRACE(this << " read stop failed: " << SUvNgHttp2_Error::LibuvStr(rv));
269  } else {
270  NCBI_UV_TCP_TRACE(this << " read stopped");
271  }
272  }
273 
274  m_Write.Reset();
275 
276  if ((m_State == eClosing) || (m_State == eRestarting)) {
277  NCBI_UV_TCP_TRACE(this << " already closing");
278 
279  } else if (m_State == eClosed) {
280  NCBI_UV_TCP_TRACE(this << " already closed");
281 
282  } else {
283  m_State = eClosing;
284 
285  if (!CloseReset(close_type)) {
287  NCBI_UV_TCP_TRACE(this << " closing");
288  }
289  }
290 }
291 
293 {
294  auto rv = uv_tcp_init(m_Loop, this);
295 
296  if (rv < 0) {
297  NCBI_UV_TCP_TRACE(this << " init failed: " << SUvNgHttp2_Error::LibuvStr(rv));
298  return rv;
299  }
300 
301  rv = m_Connect(this, s_OnConnect);
302 
303  if (rv < 0) {
304  NCBI_UV_TCP_TRACE(this << " pre-connect failed: " << SUvNgHttp2_Error::LibuvStr(rv));
305  Close();
306  return rv;
307  }
308 
309  NCBI_UV_TCP_TRACE(this << " connecting");
311 
312  return 0;
313 }
314 
315 void SUv_Tcp::OnConnect(uv_connect_t*, int status)
316 {
317  if (status >= 0) {
318  status = uv_tcp_nodelay(this, 1);
319 
320  if (status >= 0) {
321  status = uv_read_start((uv_stream_t*)this, s_OnAlloc, s_OnRead);
322 
323  if (status >= 0) {
324  struct sockaddr_storage name;
325  auto namelen = static_cast<int>(sizeof(name));
326 
327  status = uv_tcp_getsockname(this, reinterpret_cast<sockaddr*>(&name), &namelen);
328 
329  if (status >= 0) {
330  if (name.ss_family == AF_INET) {
331  auto sin = reinterpret_cast<sockaddr_in*>(&name);
332  m_LocalPort = CSocketAPI::NetToHostShort(sin->sin_port);
333  }
334 
335  NCBI_UV_TCP_TRACE(this << " connected: " << m_LocalPort);
337  m_ConnectCb(status);
338  return;
339  } else {
340  NCBI_UV_TCP_TRACE(this << " getsockname failed: " << SUvNgHttp2_Error::LibuvStr(status));
341  }
342  } else {
343  NCBI_UV_TCP_TRACE(this << " read start failed: " << SUvNgHttp2_Error::LibuvStr(status));
344  }
345  } else {
346  NCBI_UV_TCP_TRACE(this << " nodelay failed: " << SUvNgHttp2_Error::LibuvStr(status));
347  }
348  } else {
349  NCBI_UV_TCP_TRACE(this << " connect failed: " << SUvNgHttp2_Error::LibuvStr(status));
350  }
351 
352  Close();
353  m_ConnectCb(status);
354 }
355 
356 void SUv_Tcp::OnAlloc(uv_handle_t*, size_t suggested_size, uv_buf_t* buf)
357 {
358  NCBI_UV_TCP_TRACE(this << " alloc: " << suggested_size);
359  m_ReadBuffer.resize(suggested_size);
360  buf->base = m_ReadBuffer.data();
361  buf->len = static_cast<decltype(buf->len)>(m_ReadBuffer.size());
362 }
363 
364 void SUv_Tcp::OnRead(uv_stream_t*, ssize_t nread, const uv_buf_t* buf)
365 {
366  if (nread < 0) {
367  NCBI_UV_TCP_TRACE(this << " read failed: " << SUvNgHttp2_Error::LibuvStr(nread));
368  Close();
369  } else {
370  NCBI_UV_TCP_TRACE(this << " read: " << nread);
371  }
372 
373  m_ReadCb(buf->base, nread);
374 }
375 
376 void SUv_Tcp::OnWrite(uv_write_t* req, int status)
377 {
378  if (status < 0) {
379  NCBI_UV_TCP_TRACE(this << '/' << req << " write failed: " << SUvNgHttp2_Error::LibuvStr(status));
380  Close();
381  } else {
382  NCBI_UV_TCP_TRACE(this << '/' << req << " wrote");
383  m_Write.OnWrite(req);
384  }
385 
386  m_WriteCb(status);
387 }
388 
389 void SUv_Tcp::OnClose(uv_handle_t*)
390 {
391  NCBI_UV_TCP_TRACE(this << " closed");
392 
393  if (exchange(m_State, eClosed) == eRestarting) {
394  Connect();
395  }
396 }
397 
399 {
401 };
402 
404 {
405  if (auto app = CNcbiApplication::InstanceGuard()) {
406  const auto& full_version = app->GetFullVersion();
407  const auto& app_version = full_version.GetVersionInfo();
408  const auto pkg_version = full_version.GetPackageVersion();
409 
410  assign(app->GetProgramDisplayName());
411  append(1, '/');
412 
413  if (app_version.IsAny() && !pkg_version.IsAny()) {
414  append(1, 'p');
415  append(pkg_version.Print());
416  } else {
417  append(app_version.Print());
418  }
419  } else {
420  assign("UNKNOWN/UNKNOWN");
421  }
422 
423  append(" NcbiCxxToolkit/"
424 #if defined(NCBI_PRODUCTION_VER)
425  "P" NCBI_AS_STRING(NCBI_PRODUCTION_VER)
426 #elif defined(NCBI_SUBVERSION_REVISION)
428 #if defined(NCBI_DEVELOPMENT_VER)
430 #elif defined(NCBI_SC_VERSION)
431  ".SC" NCBI_AS_STRING(NCBI_SC_VERSION)
432 #endif
433 #else
434  "UNKNOWN"
435 #endif
436  );
437 }
438 
440 {
441  return SUvNgHttp2_UserAgentImpl();
442 }
443 
444 SNgHttp2_Session::SNgHttp2_Session(void* user_data, uint32_t max_streams,
445  nghttp2_on_data_chunk_recv_callback on_data,
446  nghttp2_on_stream_close_callback on_stream_close,
447  nghttp2_on_header_callback on_header,
448  nghttp2_error_callback2 on_error,
449  nghttp2_on_frame_recv_callback on_frame_recv) :
450  m_UserData(user_data),
451  m_OnData(on_data),
452  m_OnStreamClose(on_stream_close),
453  m_OnHeader(on_header),
454  m_OnError(on_error),
455  m_OnFrameRecv(on_frame_recv),
456  m_MaxStreams(max_streams, max_streams)
457 {
458  NCBI_NGHTTP2_SESSION_TRACE(this << " created");
459 }
460 
462 {
463  if (m_Session) return 0;
464 
465  nghttp2_session_callbacks* callbacks;
466  nghttp2_session_callbacks_new(&callbacks);
467 
468  nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks, m_OnData);
469  nghttp2_session_callbacks_set_on_stream_close_callback( callbacks, m_OnStreamClose);
470  nghttp2_session_callbacks_set_on_header_callback( callbacks, m_OnHeader);
471  nghttp2_session_callbacks_set_error_callback2( callbacks, m_OnError);
472  if (m_OnFrameRecv) nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, m_OnFrameRecv);
473 
474  nghttp2_session_client_new(&m_Session, callbacks, m_UserData);
475  nghttp2_session_callbacks_del(callbacks);
476 
477  nghttp2_settings_entry iv[1] = {
478  {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, m_MaxStreams.second}
479  };
480 
481  /* client 24 bytes magic string will be sent by nghttp2 library */
482  if (auto rv = nghttp2_submit_settings(m_Session, NGHTTP2_FLAG_NONE, iv, sizeof(iv) / sizeof(iv[0]))) {
483  NCBI_NGHTTP2_SESSION_TRACE(this << " submit settings failed: " << SUvNgHttp2_Error::NgHttp2Str(rv));
484  return x_DelOnError(rv);
485  }
486 
487  auto max_streams = nghttp2_session_get_remote_settings(m_Session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
488  m_MaxStreams.first = min(max_streams, m_MaxStreams.second);
489  NCBI_NGHTTP2_SESSION_TRACE(this << " initialized: " << m_MaxStreams.first);
490  return 0;
491 }
492 
494 {
495  if (!m_Session) {
496  NCBI_NGHTTP2_SESSION_TRACE(this << " already terminated");
497  return;
498  }
499 
500  auto rv = nghttp2_session_terminate_session(m_Session, NGHTTP2_NO_ERROR);
501 
502  if (rv) {
503  NCBI_NGHTTP2_SESSION_TRACE(this << " terminate failed: " << SUvNgHttp2_Error::NgHttp2Str(rv));
504  } else {
505  NCBI_NGHTTP2_SESSION_TRACE(this << " terminated");
506  }
507 
508  x_DelOnError(-1);
509 }
510 
511 int32_t SNgHttp2_Session::Submit(const nghttp2_nv *nva, size_t nvlen, nghttp2_data_provider* data_prd)
512 {
513  if (auto rv = Init()) return rv;
514 
515  auto rv = nghttp2_submit_request(m_Session, nullptr, nva, nvlen, data_prd, nullptr);
516 
517  if (rv < 0) {
518  NCBI_NGHTTP2_SESSION_TRACE(this << " submit failed: " << SUvNgHttp2_Error::NgHttp2Str(rv));
519  } else {
520  NCBI_NGHTTP2_SESSION_TRACE(this << " submitted");
521  }
522 
523  return x_DelOnError(rv);
524 }
525 
527 {
528  if (auto rv = Init()) return rv;
529 
530  auto rv = nghttp2_session_resume_data(m_Session, stream_id);
531 
532  if (rv < 0) {
533  NCBI_NGHTTP2_SESSION_TRACE(this << " resume failed: " << SUvNgHttp2_Error::NgHttp2Str(rv));
534  } else {
535  NCBI_NGHTTP2_SESSION_TRACE(this << " resumed");
536  }
537 
538  return x_DelOnError(rv);
539 }
540 
542 {
543  if (auto rv = Init()) return rv;
544 
545  _DEBUG_ARG(ssize_t total = 0);
546 
547  while (nghttp2_session_want_write(m_Session)) {
548  const uint8_t* data;
549  auto rv = nghttp2_session_mem_send(m_Session, &data);
550 
551  if (rv > 0) {
552  buffer.insert(buffer.end(), data, data + rv);
553  _DEBUG_CODE(total += rv;);
554 
555  } else if (rv < 0) {
556  NCBI_NGHTTP2_SESSION_TRACE(this << " send failed: " << SUvNgHttp2_Error::NgHttp2Str(rv));
557  return x_DelOnError(rv);
558 
559  } else {
560  NCBI_NGHTTP2_SESSION_TRACE(this << " sent: " << total);
561  return eOkay;
562  }
563  }
564 
565  if (nghttp2_session_want_read(m_Session) == 0) {
566  NCBI_NGHTTP2_SESSION_TRACE(this << " does not want to write and read");
567  x_DelOnError(-1);
568  return eWantsClose;
569  }
570 
571  NCBI_NGHTTP2_SESSION_TRACE(this << " does not want to write");
572  return eOkay;
573 }
574 
576 {
577  if (auto rv = Init()) return rv;
578 
579  ssize_t total = 0;
580 
581  while (size > 0) {
582  auto rv = nghttp2_session_mem_recv(m_Session, buffer, size);
583 
584  if (rv > 0) {
585  buffer += rv;
586  size -= rv;
587  total += rv;
588 
589  } else {
590  NCBI_NGHTTP2_SESSION_TRACE(this << " receive failed: " << SUvNgHttp2_Error::NgHttp2Str(rv));
591  return x_DelOnError(rv);
592  }
593  }
594 
595  NCBI_NGHTTP2_SESSION_TRACE(this << " received: " << total);
596  return total;
597 }
598 
600 {
601  SUvNgHttp2_TlsNoOp(TGetWriteBuf get_write_buf) : m_GetWriteBuf(get_write_buf) {}
602 
603  int Read(const char*& buf, ssize_t& nread) override
604  {
605  m_IncomingData = exchange(buf, buf + nread);
606  return static_cast<int>(exchange(nread, 0));
607  }
608 
609  int Write() override { return 0; }
610  int Close() override { return 0; }
611 
612  const char* GetReadBuffer() override { return m_IncomingData; }
613  vector<char>& GetWriteBuffer() override { return m_GetWriteBuf(); }
614 
615 private:
616  const char* m_IncomingData = nullptr;
618 };
619 
621 {
622  SUvNgHttp2_TlsImpl(const TAddrNCred& addr_n_cred, size_t rd_buf_size, size_t wr_buf_size, TGetWriteBuf get_write_buf);
623  ~SUvNgHttp2_TlsImpl() override;
624 
625  int Read(const char*& buf, ssize_t& nread) override;
626  int Write() override;
627  int Close() override;
628 
629  const char* GetReadBuffer() override { return m_ReadBuffer.data(); }
630  vector<char>& GetWriteBuffer() override { return m_WriteBuffer; }
631 
632 private:
633  // Provides scope-restricted access to incoming TLS data
634  struct SIncomingData : pair<const char**, ssize_t*>
635  {
636  struct SReset { void operator()(first_type* p) const { *p = nullptr; } };
637  auto operator()(first_type b, second_type l) { first = b; second = l; return unique_ptr<first_type, SReset>(&first); }
638  };
639 
642 
645 
646  int Init();
647  int GetReady();
648 
649  int OnRecv(unsigned char* buf, size_t len);
650  int OnSend(const unsigned char* buf, size_t len);
651 
653  {
654  _ASSERT(ctx);
655  return static_cast<SUvNgHttp2_TlsImpl*>(ctx);
656  }
657 
658  static int s_OnRecv(void* ctx, unsigned char* buf, size_t len)
659  {
660  return GetThat(ctx)->OnRecv(buf, len);
661  }
662 
663  static int s_OnSend(void* ctx, const unsigned char* buf, size_t len)
664  {
665  return GetThat(ctx)->OnSend(buf, len);
666  }
667 
669 
670  vector<char> m_ReadBuffer;
671  vector<char> m_WriteBuffer;
674 
682 };
683 
684 bool s_WantReadOrWrite(int rv)
685 {
686  return (rv == MBEDTLS_ERR_SSL_WANT_READ) || (rv == MBEDTLS_ERR_SSL_WANT_WRITE);
687 }
688 
689 SUvNgHttp2_TlsImpl::SUvNgHttp2_TlsImpl(const TAddrNCred& addr_n_cred, size_t rd_buf_size, size_t wr_buf_size, TGetWriteBuf get_write_buf) :
690  m_ReadBuffer(rd_buf_size),
691  m_GetWriteBuf(get_write_buf),
692  m_Protocols({ "h2", nullptr })
693 {
694  NCBI_UVNGHTTP2_TLS_TRACE(this << " created");
695  m_WriteBuffer.reserve(wr_buf_size),
696 
697  mbedtls_ssl_config_init(&m_Conf);
698 
700 
701  if (c_rv) {
702  NCBI_UVNGHTTP2_TLS_TRACE(this << " mbedtls_ssl_config_defaults: " << SUvNgHttp2_Error::MbedTlsStr(c_rv));
703  return;
704  }
705 
707 #if MBEDTLS_VERSION_MAJOR >= 3
708  /* The above line can otherwise be ineffective. */
710 #endif
711  mbedtls_entropy_init(&m_Entropy);
712  mbedtls_ctr_drbg_init(&m_CtrDrbg);
713  mbedtls_x509_crt_init(&m_Cert);
714  mbedtls_pk_init(&m_Pkey);
715 
716  auto d_rv = mbedtls_ctr_drbg_seed(&m_CtrDrbg, mbedtls_entropy_func, &m_Entropy, nullptr, 0);
717 
718  if (d_rv) {
719  NCBI_UVNGHTTP2_TLS_TRACE(this << " mbedtls_ctr_drbg_seed: " << SUvNgHttp2_Error::MbedTlsStr(d_rv));
720  return;
721  }
722 
723  mbedtls_ssl_conf_rng(&m_Conf, mbedtls_ctr_drbg_random, &m_CtrDrbg);
724  auto p_rv = psa_crypto_init();
725 
726  if (p_rv != PSA_SUCCESS) {
727  NCBI_UVNGHTTP2_TLS_TRACE(this << " psa_crypto_init: error code"
728  << p_rv);
729  return;
730  }
731 
732  mbedtls_ssl_conf_alpn_protocols(&m_Conf, m_Protocols.data());
733  mbedtls_ssl_init(&m_Ssl);
734 
735  auto s_rv = mbedtls_ssl_setup(&m_Ssl, &m_Conf);
736 
737  if (s_rv) {
738  NCBI_UVNGHTTP2_TLS_TRACE(this << " mbedtls_ssl_setup: " << SUvNgHttp2_Error::MbedTlsStr(s_rv));
739  return;
740  }
741 
742  const auto host_name = addr_n_cred.first.GetHostName();
743  auto h_rv = mbedtls_ssl_set_hostname(&m_Ssl, host_name.c_str());
744 
745  if (h_rv) {
746  NCBI_UVNGHTTP2_TLS_TRACE(this << " mbedtls_ssl_set_hostname: " << SUvNgHttp2_Error::MbedTlsStr(h_rv));
747  return;
748  }
749 
750  mbedtls_ssl_set_bio(&m_Ssl, this, s_OnSend, s_OnRecv, nullptr);
751 
752  const auto& cert = addr_n_cred.second.first;
753  const auto& pkey = addr_n_cred.second.second;
754 
755  if (cert.empty() || pkey.empty()) {
756  return;
757  }
758 
759  auto cp_rv = mbedtls_x509_crt_parse(&m_Cert, reinterpret_cast<const unsigned char*>(cert.data()), cert.size() + 1);
760 
761  if (cp_rv) {
762  NCBI_UVNGHTTP2_TLS_TRACE(this << " mbedtls_x509_crt_parse: " << SUvNgHttp2_Error::MbedTlsStr(cp_rv));
763  return;
764  }
765 
766  auto pk_rv = mbedtls_pk_parse_key(
767  &m_Pkey, reinterpret_cast<const unsigned char*>(pkey.data()),
768  pkey.size() + 1, nullptr, 0
769 #if MBEDTLS_VERSION_MAJOR >= 3
770  , mbedtls_ctr_drbg_random, &m_CtrDrbg
771 #endif
772  );
773 
774  if (pk_rv) {
775  NCBI_UVNGHTTP2_TLS_TRACE(this << " mbedtls_pk_parse_key: " << SUvNgHttp2_Error::MbedTlsStr(pk_rv));
776  return;
777  }
778 
779  auto oc_rv = mbedtls_ssl_conf_own_cert(&m_Conf, &m_Cert, &m_Pkey);
780 
781  if (oc_rv) {
782  NCBI_UVNGHTTP2_TLS_TRACE(this << " mbedtls_ssl_conf_own_cert: " << SUvNgHttp2_Error::MbedTlsStr(oc_rv));
783  return;
784  }
785 }
786 
788 {
795 }
796 
798 {
799  switch (m_State)
800  {
801  case eInitialized:
802  return GetReady();
803 
804  case eReady:
805  return 0;
806 
807  case eClosed:
808  break;
809  }
810 
811  auto rv = mbedtls_ssl_session_reset(&m_Ssl);
812 
813  if (rv < 0) {
814  NCBI_UVNGHTTP2_TLS_TRACE(this << " reset: " << SUvNgHttp2_Error::MbedTlsStr(rv));
815  } else {
816  NCBI_UVNGHTTP2_TLS_TRACE(this << " reset: " << rv);
818  }
819 
820  return rv;
821 }
822 
824 {
825  auto hs_rv = mbedtls_ssl_handshake(&m_Ssl);
826 
827  if (hs_rv < 0) {
828  NCBI_UVNGHTTP2_TLS_TRACE(this << " handshake: " << SUvNgHttp2_Error::MbedTlsStr(hs_rv));
829  return hs_rv;
830  }
831 
832  NCBI_UVNGHTTP2_TLS_TRACE(this << " handshake: " << hs_rv);
833 
834  auto v_rv = mbedtls_ssl_get_verify_result(&m_Ssl);
835 
836  if (v_rv) {
837  NCBI_UVNGHTTP2_TLS_TRACE(this << " verify: " << v_rv);
838  } else {
839  NCBI_UVNGHTTP2_TLS_TRACE(this << " verified");
840  }
841 
842  m_State = eReady;
843  return 0;
844 }
845 
846 int SUvNgHttp2_TlsImpl::Read(const char*& buf, ssize_t& nread)
847 {
848  auto scope_guard = m_IncomingData(&buf, &nread);
849 
850  if (auto rv = Init()) return rv;
851 
852  auto rv = mbedtls_ssl_read(&m_Ssl, reinterpret_cast<unsigned char*>(m_ReadBuffer.data()), m_ReadBuffer.size());
853 
854  if (rv < 0) {
855  NCBI_UVNGHTTP2_TLS_TRACE(this << " read: " << SUvNgHttp2_Error::MbedTlsStr(rv));
856  } else {
857  NCBI_UVNGHTTP2_TLS_TRACE(this << " read: " << rv);
858  }
859 
860  return rv;
861 }
862 
864 {
865  if (auto rv = Init()) return rv;
866 
867  auto buf = m_WriteBuffer.data();
868  auto size = m_WriteBuffer.size();
869 
870  while (size > 0) {
871  auto rv = mbedtls_ssl_write(&m_Ssl, (unsigned char*)buf, size);
872 
873  if (rv > 0) {
874  buf += rv;
875  size -= rv;
876 
877  } else if (rv < 0) {
878  NCBI_UVNGHTTP2_TLS_TRACE(this << " write: " << SUvNgHttp2_Error::MbedTlsStr(rv));
879  return rv;
880  }
881  }
882 
883  auto written = m_WriteBuffer.size() - size;
884  m_WriteBuffer.erase(m_WriteBuffer.begin(), m_WriteBuffer.begin() + written);
885  NCBI_UVNGHTTP2_TLS_TRACE(this << " write: " << written);
886  return static_cast<int>(written);
887 }
888 
890 {
891  NCBI_UVNGHTTP2_TLS_TRACE(this << " close");
892 
893  switch (m_State)
894  {
895  case eInitialized:
896  case eClosed: return 0;
897  case eReady: break;
898  }
899 
900  m_WriteBuffer.clear();
901  m_State = eClosed;
903 }
904 
905 int SUvNgHttp2_TlsImpl::OnRecv(unsigned char* buf, size_t len)
906 {
907  if (m_IncomingData.first && m_IncomingData.second) {
908  auto copied = min(len, static_cast<size_t>(*m_IncomingData.second));
909  NCBI_UVNGHTTP2_TLS_TRACE(this << " on receiving: " << copied);
910 
911  if (copied) {
912  memcpy(buf, *m_IncomingData.first, copied);
913  *m_IncomingData.first += copied;
914  *m_IncomingData.second -= copied;
915  return static_cast<int>(copied);
916  }
917  } else {
918  NCBI_UVNGHTTP2_TLS_TRACE(this << " on receiving");
919  }
920 
922 }
923 
924 int SUvNgHttp2_TlsImpl::OnSend(const unsigned char* buf, size_t len)
925 {
926  NCBI_UVNGHTTP2_TLS_TRACE(this << " on sending: " << len);
927  auto& write_buf = m_GetWriteBuf();
928  write_buf.insert(write_buf.end(), buf, buf + len);
929  return static_cast<int>(len);
930 }
931 
932 SUvNgHttp2_Tls* SUvNgHttp2_Tls::Create(bool https, const TAddrNCred& addr_n_cred, size_t rd_buf_size, size_t wr_buf_size, TGetWriteBuf get_write_buf)
933 {
934  if (https) {
935  return new SUvNgHttp2_TlsImpl(addr_n_cred, rd_buf_size, wr_buf_size, get_write_buf);
936  }
937 
938  return new SUvNgHttp2_TlsNoOp(get_write_buf);
939 }
940 
942 {
943  auto send_rv = m_Session.Send(m_Tls->GetWriteBuffer());
944 
945  if (send_rv < 0) {
946  Reset(SUvNgHttp2_Error::FromNgHttp2(send_rv, "on send"));
947 
948  } else if (send_rv == SNgHttp2_Session::eWantsClose) {
949  Reset("nghttp2 asked to drop connection", SUv_Tcp::eNormalClose);
950 
951  } else {
952  auto tls_rv = m_Tls->Write();
953 
954  if ((tls_rv < 0) && !s_WantReadOrWrite(tls_rv)) {
955  Reset(SUvNgHttp2_Error::FromMbedTls(tls_rv, "on write"));
956 
957  } else if (auto tcp_rv = m_Tcp.Write()) {
958  Reset(SUvNgHttp2_Error::FromLibuv(tcp_rv, "on write"));
959 
960  } else {
961  return true;
962  }
963  }
964 
965  return false;
966 }
967 
968 int SUvNgHttp2_SessionBase::OnError(nghttp2_session*, int lib_error_code, const char* msg, size_t len)
969 {
970  NCBI_UVNGHTTP2_SESSION_TRACE(this << " error: " << SUvNgHttp2_Error::NgHttp2Str(lib_error_code) << ". " << CTempString(msg, len));
971  return 0;
972 }
973 
975 {
976  NCBI_UVNGHTTP2_SESSION_TRACE(this << " connected: " << status);
977 
978  if (status < 0) {
979  Reset(SUvNgHttp2_Error::FromLibuv(status, "on connecting"));
980  } else {
981  Send();
982  }
983 }
984 
986 {
987  NCBI_UVNGHTTP2_SESSION_TRACE(this << " wrote: " << status);
988 
989  if (status < 0) {
990  Reset(SUvNgHttp2_Error::FromLibuv(status, "on writing"));
991  }
992 }
993 
995 {
996  NCBI_UVNGHTTP2_SESSION_TRACE(this << " read: " << nread);
997 
998  if (nread < 0) {
999  Reset(SUvNgHttp2_Error::FromLibuv(nread, "on reading"));
1000  return;
1001  }
1002 
1003  while (nread > 0) {
1004  auto read_rv = m_Tls->Read(buf, nread);
1005 
1006  if (read_rv == 0) {
1007  m_Session.Del();
1008  m_Tls->Close();
1010 
1011  } else if (s_WantReadOrWrite(read_rv)) {
1012  if (nread == 0) break;
1013 
1014  Reset("Some encrypted data was ignored");
1015 
1016  } else if (read_rv < 0) {
1017  Reset(SUvNgHttp2_Error::FromMbedTls(read_rv, "on read"));
1018 
1019  } else {
1020  auto recv_rv = m_Session.Recv((const uint8_t*)m_Tls->GetReadBuffer(), (size_t)read_rv);
1021 
1022  if (recv_rv < 0) {
1023  Reset(SUvNgHttp2_Error::FromNgHttp2(recv_rv, "on receive"));
1024 
1025  } else if (recv_rv != read_rv) {
1026  Reset("Processed size does not equal to received");
1027 
1028  } else {
1029  continue;
1030  }
1031  }
1032 
1033  return;
1034  }
1035 
1036  Send();
1037 }
1038 
1040 {
1041  NCBI_UVNGHTTP2_SESSION_TRACE(this << " resetting with " << error);
1042  m_Session.Del();
1043  m_Tls->Close();
1044  m_Tcp.Close(close_type);
1045  OnReset(std::move(error));
1046 }
1047 
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
Platform Security Architecture cryptography module.
void mbedtls_ctr_drbg_free(mbedtls_ctr_drbg_context *ctx)
This function resets CTR_DRBG context to the state immediately after initial call of mbedtls_ctr_drbg...
void mbedtls_ctr_drbg_init(mbedtls_ctr_drbg_context *ctx)
This function initializes the CTR_DRBG context, and prepares it for mbedtls_ctr_drbg_seed() or mbedtl...
int mbedtls_ctr_drbg_seed(mbedtls_ctr_drbg_context *ctx, int(*f_entropy)(void *, unsigned char *, size_t), void *p_entropy, const unsigned char *custom, size_t len)
This function seeds and sets up the CTR_DRBG entropy source for future reseeds.
int mbedtls_ctr_drbg_random(void *p_rng, unsigned char *output, size_t output_len)
This function uses CTR_DRBG to generate random data.
#define T(s)
Definition: common.h:230
void mbedtls_entropy_free(mbedtls_entropy_context *ctx)
Free the data in the context.
int mbedtls_entropy_func(void *data, unsigned char *output, size_t len)
Retrieve entropy from the accumulator (Maximum length: MBEDTLS_ENTROPY_BLOCK_SIZE) (Thread-safe if MB...
void mbedtls_entropy_init(mbedtls_entropy_context *ctx)
Initialize the context.
CS_CONTEXT * ctx
Definition: t0006.c:12
static void DLIST_NAME() append(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:78
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:46
char data[12]
Definition: iconv.c:80
Int4 int32_t
unsigned char uint8_t
Uint4 uint32_t
static CNcbiApplicationGuard InstanceGuard(void)
Singleton method.
Definition: ncbiapp.cpp:133
string
Definition: cgiapp.hpp:687
#define _DEBUG_CODE(code)
Definition: ncbidbg.hpp:136
#define _DEBUG_ARG(arg)
Definition: ncbidbg.hpp:134
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define NCBI_AS_STRING(value)
Convert some value to string even if this value is macro itself.
Definition: ncbistl.hpp:146
static unsigned short HostToNetShort(unsigned short value)
static unsigned short NetToHostShort(unsigned short value)
#define PSA_SUCCESS
The action was completed successfully.
Definition: crypto_values.h:57
psa_status_t psa_crypto_init(void)
Library initialization.
#define NCBI_DEVELOPMENT_VER
char * buf
int len
#define MBEDTLS_VERSION_MAJOR
The version number x.y.z is split into three parts.
Definition: build_info.h:27
const struct ncbi::grid::netcache::search::fields::SIZE size
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
#define NCBI_SUBVERSION_REVISION
#define NCBI_UV_WRITE_TRACE(message)
#define NCBI_UVNGHTTP2_TLS_TRACE(message)
#define NCBI_UV_TCP_TRACE(message)
bool s_WantReadOrWrite(int rv)
#define NCBI_UVNGHTTP2_SESSION_TRACE(message)
#define NCBI_NGHTTP2_SESSION_TRACE(message)
Defines the CNcbiApplication and CAppException classes for creating NCBI applications.
int ssize_t
Definition: ncbiconf_msvc.h:93
#define mbedtls_ssl_conf_own_cert
#define mbedtls_pk_parse_key
#define mbedtls_ssl_set_hostname
#define mbedtls_x509_crt_init
#define mbedtls_x509_crt_free
#define mbedtls_x509_crt_parse
#define mbedtls_ssl_conf_alpn_protocols
T min(T x_, T y_)
static pcre_uint8 * buffer
Definition: pcretest.c:1051
void mbedtls_pk_init(mbedtls_pk_context *ctx)
Initialize a mbedtls_pk_context (as NONE).
void mbedtls_pk_free(mbedtls_pk_context *ctx)
Free the components of a mbedtls_pk_context.
Defines CRequestContext class for NCBI C++ diagnostic API.
void mbedtls_strerror(int errnum, char *buffer, size_t buflen)
Translate an Mbed TLS error code into a string representation.
#define MBEDTLS_SSL_VERIFY_NONE
Definition: ssl.h:299
#define MBEDTLS_SSL_IS_CLIENT
Definition: ssl.h:285
int mbedtls_ssl_session_reset(mbedtls_ssl_context *ssl)
Reset an already initialized SSL context for re-use while retaining application-set variables,...
void mbedtls_ssl_free(mbedtls_ssl_context *ssl)
Free referenced items in an SSL context and clear memory.
@ MBEDTLS_SSL_VERSION_TLS1_2
Definition: ssl.h:1216
void mbedtls_ssl_conf_rng(mbedtls_ssl_config *conf, int(*f_rng)(void *, unsigned char *, size_t), void *p_rng)
Set the random number generator callback.
int mbedtls_ssl_handshake(mbedtls_ssl_context *ssl)
Perform the SSL handshake.
uint32_t mbedtls_ssl_get_verify_result(const mbedtls_ssl_context *ssl)
Return the result of the certificate verification.
void mbedtls_ssl_conf_authmode(mbedtls_ssl_config *conf, int authmode)
Set the certificate verification mode Default: NONE on server, REQUIRED on client.
int mbedtls_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len)
Try to write exactly 'len' application data bytes.
#define MBEDTLS_ERR_SSL_WANT_WRITE
Connection requires a write call.
Definition: ssl.h:141
#define MBEDTLS_ERR_SSL_WANT_READ
No data of requested type currently available on underlying transport.
Definition: ssl.h:139
void mbedtls_ssl_config_free(mbedtls_ssl_config *conf)
Free an SSL configuration context.
void mbedtls_ssl_init(mbedtls_ssl_context *ssl)
Initialize an SSL context Just makes the context ready for mbedtls_ssl_setup() or mbedtls_ssl_free()
void mbedtls_ssl_set_bio(mbedtls_ssl_context *ssl, void *p_bio, mbedtls_ssl_send_t *f_send, mbedtls_ssl_recv_t *f_recv, mbedtls_ssl_recv_timeout_t *f_recv_timeout)
Set the underlying BIO callbacks for write, read and read-with-timeout.
int mbedtls_ssl_config_defaults(mbedtls_ssl_config *conf, int endpoint, int transport, int preset)
Load reasonable default SSL configuration values.
int mbedtls_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len)
Read at most 'len' application data bytes.
void mbedtls_ssl_config_init(mbedtls_ssl_config *conf)
Initialize an SSL configuration context Just makes the context ready for mbedtls_ssl_config_defaults(...
static void mbedtls_ssl_conf_max_tls_version(mbedtls_ssl_config *conf, mbedtls_ssl_protocol_version tls_version)
Set the maximum supported version sent from the client side and/or accepted at the server side.
Definition: ssl.h:4301
int mbedtls_ssl_close_notify(mbedtls_ssl_context *ssl)
Notify the peer that the connection is being closed.
#define MBEDTLS_SSL_TRANSPORT_STREAM
Definition: ssl.h:268
int mbedtls_ssl_setup(mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf)
Set up an SSL context for use.
#define MBEDTLS_SSL_PRESET_DEFAULT
Definition: ssl.h:327
SNgHttp2_Session(void *user_data, uint32_t max_streams, nghttp2_on_data_chunk_recv_callback on_data, nghttp2_on_stream_close_callback on_stream_close, nghttp2_on_header_callback on_header, nghttp2_error_callback2 on_error, nghttp2_on_frame_recv_callback on_frame_recv=nullptr)
TInt x_DelOnError(TInt rv)
nghttp2_on_frame_recv_callback m_OnFrameRecv
pair< uint32_t, const uint32_t > m_MaxStreams
int32_t Submit(const nghttp2_nv *nva, size_t nvlen, nghttp2_data_provider *data_prd=nullptr)
int Resume(int32_t stream_id)
nghttp2_on_stream_close_callback m_OnStreamClose
nghttp2_error_callback2 m_OnError
ssize_t Recv(const uint8_t *buffer, size_t size)
ssize_t Send(vector< char > &buffer)
nghttp2_session * m_Session
nghttp2_on_header_callback m_OnHeader
nghttp2_on_data_chunk_recv_callback m_OnData
string GetHostName() const
unsigned short port
static SUvNgHttp2_Error FromNgHttp2(T e, const char *w)
static const char * LibuvStr(T e)
static const char * NgHttp2Str(T e)
static SUvNgHttp2_Error FromMbedTls(T e, const char *w)
static SMbedTlsStr MbedTlsStr(T e)
static SUvNgHttp2_Error FromLibuv(T e, const char *w)
void Reset(SUvNgHttp2_Error error, SUv_Tcp::ECloseType close_type=SUv_Tcp::eCloseReset)
void OnRead(const char *buf, ssize_t nread)
void OnConnect(int status)
int OnError(nghttp2_session *session, int lib_error_code, const char *msg, size_t len)
virtual void OnReset(SUvNgHttp2_Error error)=0
void OnWrite(int status)
SNgHttp2_Session m_Session
unique_ptr< SUvNgHttp2_Tls > m_Tls
auto operator()(first_type b, second_type l)
mbedtls_x509_crt m_Cert
SUvNgHttp2_TlsImpl & operator=(SUvNgHttp2_TlsImpl &&)=delete
SIncomingData m_IncomingData
mbedtls_entropy_context m_Entropy
int OnRecv(unsigned char *buf, size_t len)
vector< char > m_WriteBuffer
static int s_OnSend(void *ctx, const unsigned char *buf, size_t len)
mbedtls_ctr_drbg_context m_CtrDrbg
SUvNgHttp2_TlsImpl(const TAddrNCred &addr_n_cred, size_t rd_buf_size, size_t wr_buf_size, TGetWriteBuf get_write_buf)
const char * GetReadBuffer() override
vector< char > m_ReadBuffer
mbedtls_ssl_config m_Conf
SUvNgHttp2_TlsImpl & operator=(const SUvNgHttp2_TlsImpl &)=delete
static SUvNgHttp2_TlsImpl * GetThat(void *ctx)
~SUvNgHttp2_TlsImpl() override
array< const char *, 2 > m_Protocols
mbedtls_pk_context m_Pkey
mbedtls_ssl_context m_Ssl
static int s_OnRecv(void *ctx, unsigned char *buf, size_t len)
int Read(const char *&buf, ssize_t &nread) override
vector< char > & GetWriteBuffer() override
SUvNgHttp2_TlsImpl(SUvNgHttp2_TlsImpl &&)=delete
TGetWriteBuf m_GetWriteBuf
int Write() override
enum SUvNgHttp2_TlsImpl::@981 m_State
int Close() override
SUvNgHttp2_TlsImpl(const SUvNgHttp2_TlsImpl &)=delete
int OnSend(const unsigned char *buf, size_t len)
const char * m_IncomingData
vector< char > & GetWriteBuffer() override
const char * GetReadBuffer() override
int Close() override
int Read(const char *&buf, ssize_t &nread) override
SUvNgHttp2_TlsNoOp(TGetWriteBuf get_write_buf)
int Write() override
TGetWriteBuf m_GetWriteBuf
function< vector< char > &()> TGetWriteBuf
pair< SSocketAddress, TCred > TAddrNCred
static SUvNgHttp2_Tls * Create(bool https, const TAddrNCred &addr_n_cred, size_t rd_buf_size, size_t wr_buf_size, TGetWriteBuf get_write_buf)
struct sockaddr_in m_Address
SUv_Connect(void *user_data, const SSocketAddress &address)
int operator()(uv_tcp_t *handle, uv_connect_cb cb)
uv_connect_t m_Request
SUv_Connect m_Connect
TWriteCb m_WriteCb
TConnectCb m_ConnectCb
TPort m_LocalPort
void OnWrite(uv_write_t *, int status)
EState m_State
function< void(int)> TConnectCb
static void s_OnAlloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
void OnClose(uv_handle_t *)
void OnAlloc(uv_handle_t *, size_t suggested_size, uv_buf_t *buf)
static void s_OnClose(uv_handle_t *handle)
void OnRead(uv_stream_t *, ssize_t nread, const uv_buf_t *buf)
static void s_OnWrite(uv_write_t *req, int status)
uv_loop_t * m_Loop
function< void(int)> TWriteCb
bool CloseReset(ECloseType close_type)
SUv_Tcp(uv_loop_t *loop, const SSocketAddress &address, size_t rd_buf_size, size_t wr_buf_size, TConnectCb connect_cb, TReadCb read_cb, TWriteCb write_cb)
function< void(const char *, ssize_t)> TReadCb
vector< char > m_ReadBuffer
SUv_Write m_Write
void Close(ECloseType close_type=eCloseReset)
static void s_OnRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
TReadCb m_ReadCb
void OnConnect(uv_connect_t *req, int status)
static void s_OnConnect(uv_connect_t *req, int status)
SBuffer * m_CurrentBuffer
void OnWrite(uv_write_t *req)
forward_list< SBuffer > m_Buffers
int Write(uv_stream_t *handle, uv_write_cb cb)
SUv_Write(void *user_data, size_t buf_size)
const size_t m_BufSize
void *const m_UserData
The CTR_DRBG context structure.
Definition: ctr_drbg.h:170
Entropy context structure.
Definition: entropy.h:105
Public key container.
Definition: pk.h:220
SSL/TLS configuration to be shared between mbedtls_ssl_context structures.
Definition: ssl.h:1411
Container for an X.509 certificate.
Definition: x509_crt.h:41
#define _TROUBLE
#define _ASSERT
Modified on Wed Jun 19 17:06:23 2024 by modify_doxy.py rev. 669887