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

Go to the SVN repository for this file.

1 /* $Id: connect_misc.cpp 101249 2023-11-20 16:10:08Z sadyrovr $
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 #include <array>
33 
34 #include "connect_misc_impl.hpp"
35 
36 #include "ncbi_servicep.h"
37 
39 
41 #include <connect/ncbi_socket.hpp>
42 
43 #include <corelib/ncbi_system.hpp>
44 #include <corelib/ncbisys.hpp>
45 
46 #if defined(NCBI_OS_MSWIN)
47 # include <io.h>
48 #elif defined(NCBI_OS_UNIX)
49 # include <unistd.h>
50 #endif
51 
53 
54 // This class also initializes CONNECT library in its constructor (via CConnIniter base)
55 struct SSocketAddressImpl : protected CConnIniter
56 {
57  // Do not make static (see above)
58  unsigned GetHost(const string& name) const
59  {
60  return CSocketAPI::gethostbyname(name, eOn);
61  }
62 
63  const string& GetName(unsigned host)
64  {
65  auto& name = m_Data[host];
66 
67  // Name was not looked up yet or host changed
68  if (name.empty()) {
69  name = CSocketAPI::gethostbyaddr(host, eOn);
70 
71  if (name.empty()) {
72  name = CSocketAPI::ntoa(host);
73  }
74  }
75 
76  return name;
77  }
78 
80  {
81  thread_local static SSocketAddressImpl impl;
82  return impl;
83  }
84 
85 private:
87 };
88 
90  name(n == EName::eOriginal ? h : std::optional<string>()),
91  host(SSocketAddressImpl::GetInstance().GetHost(h))
92 {
93 }
94 
96 {
98 }
99 
101 {
102  string host, port;
103 
104  if (NStr::SplitInTwo(address, ":", host, port)) {
105  return { { host, name }, port };
106  }
107 
108  return { 0, 0 };
109 }
110 
111 bool operator==(const SSocketAddress& lhs, const SSocketAddress& rhs)
112 {
113  return lhs.host == rhs.host && lhs.port == rhs.port;
114 }
115 
116 bool operator< (const SSocketAddress& lhs, const SSocketAddress& rhs)
117 {
118  if (lhs.host != rhs.host) return lhs.host < rhs.host;
119 
120  return lhs.port < rhs.port;
121 }
122 
123 // This class also initializes CONNECT library in its constructor (via CConnIniter base)
125 {
126  // Do not make static (see above)
127  shared_ptr<void> GetSingleServer(const string& service_name, SSocketAddress::SHost::EName name) const
128  {
129  if (auto address = SSocketAddress::Parse(service_name, name)) {
130  CServiceDiscovery::TServer server(std::move(address), 1.0);
131  return make_shared<CServiceDiscovery::TServers>(1, std::move(server));
132  }
133 
134  return {};
135  }
136 };
137 
139  m_ServiceName(service_name),
140  m_Data(SServiceDiscoveryImpl().GetSingleServer(m_ServiceName, name)),
141  m_IsSingleServer(m_Data)
142 {
143 }
144 
146 {
147  // Single server "discovery"
148  if (m_IsSingleServer) {
149  _ASSERT(m_Data);
150  return *static_pointer_cast<TServers>(m_Data);
151  }
152 
154  return DiscoverImpl(m_ServiceName, types, m_Data, {}, 0, 0);
155 }
156 
158  shared_ptr<void>& net_info, pair<string, const char*> lbsm_affinity,
159  int try_count, unsigned long retry_delay)
160 {
161  TServers rv;
162 
163  // Query the Load Balancer.
164  for (;;) {
165  if (!net_info) {
166  net_info.reset(ConnNetInfo_Create(service_name.c_str()), ConnNetInfo_Destroy);
167  }
168 
169  if (auto it = make_c_unique(SERV_OpenP(service_name.c_str(), types, SERV_LOCALHOST, 0, 0.0,
170  static_cast<const SConnNetInfo*>(net_info.get()), NULL, 0, 0 /*false*/,
171  lbsm_affinity.first.c_str(), lbsm_affinity.second), SERV_Close)) {
172 
173  while (auto info = SERV_GetNextInfoEx(it.get(), 0)) {
174  if (info->time > 0 && info->time != NCBI_TIME_INFINITE && info->rate != 0.0) {
175  rv.emplace_back(SSocketAddress(info->host, info->port), info->rate);
176  }
177  }
178 
179  break;
180  }
181 
182  // FIXME Retry logic can be removed as soon as LBSMD with
183  // packet compression is installed universally.
184  if (--try_count < 0) {
185  break;
186  }
187 
188  ERR_POST("Could not find LB service name '" << service_name << "', will retry after delay");
189  SleepMilliSec(retry_delay);
190  }
191 
192  return rv;
193 }
194 
196 {
197  using namespace chrono;
198 
199  enum ESubExpression : size_t { eServer = 1, eTimestamp = 1 };
200  enum EMatchedPattern : size_t { fNothing = 0, fStart, fStop, eServerSide, eNumberOfPatterns, eBoth = fStart | fStop };
201  array<const char*, eNumberOfPatterns> prefixes{ " ", "Start -> ", "Stop -> ", "Server -> " };
202 
203  cmatch m;
204 
205  using TMatched = size_t;
206  using TTimePoints = array<system_clock::time_point, eBoth>;
207  using TServerData = tuple<TMatched, TTimePoints, TServerSide>;
208  unordered_map<string, TServerData> servers;
209  TServerData* current = nullptr;
210 
211  for (const auto& msg : data) {
212  const auto msg_start = msg.m_Buffer;
213  const auto msg_len = min((size_t)1024, msg.m_BufferLen);
214  const auto msg_end = msg_start + msg_len;
215  TMatched matched = fNothing;
216 
217  if (regex_match(msg_start, msg_end, m, m_Start)) {
218  matched = fStart;
219  current = &servers[m[eServer].str()];
220 
221  } else if (regex_match(msg_start, msg_end, m, m_Stop)) {
222  matched = fStop;
223 
224  // If there is a server specified
225  if (m.size() > eServer) {
226  current = &servers[m[eServer].str()];
227  }
228 
229  } else if (m_ServerSide && regex_match(msg_start, msg_end, m, *m_ServerSide)) {
230  matched = eServerSide;
231  }
232 
233  if (m_Debug) {
234  cerr << prefixes[matched];
235  msg.Write(cerr);
236  }
237 
238  if (matched) {
239  if (!current) {
240  cerr << "Cannot use matched data without a server\n";
241 
242  } else if (matched == eServerSide) {
243  get<TServerSide>(*current) = m[eTimestamp].str();
244 
245  } else {
246  auto t = msg.GetTime();
247  auto tp = system_clock::from_time_t(t.GetTimeT()) + microseconds(t.MicroSecond());
248  get<TMatched>(*current) |= matched;
249  get<TTimePoints>(*current)[matched] = tp;
250  }
251  }
252  }
253 
254  TResult latencies;
256  auto extremum_it = latencies.end();
257 
258  for (const auto& server : servers) {
259  const auto& server_name = server.first;
260  const auto& server_data = server.second;
261 
262  if (get<TMatched>(server_data) == eBoth) {
263  const auto& start = get<TTimePoints>(server_data)[fStart];
264  const auto& stop = get<TTimePoints>(server_data)[fStop];
265  const auto& server_side = get<TServerSide>(server_data);
266  auto result = latencies.try_emplace(server_name, duration_cast<microseconds>(stop - start), server_side);
267 
268  if (((m_Which == eLast) && (start > extremum)) || ((m_Which == eFirst) && (start < extremum))) {
269  extremum = start;
270  extremum_it = result.first;
271  }
272  }
273  }
274 
275  return extremum_it == latencies.end() ? latencies : TResult(extremum_it, next(extremum_it));
276 }
277 
279 {
280  // It has not been started, nothing to report
281  if (!m_Handler) {
282  return;
283  }
284 
285  try {
286  SetDiagHandler(nullptr);
287  const auto latencies = Parse(*m_Handler);
288 
289  for (const auto& server : latencies) {
290  const auto address = SSocketAddress::Parse(server.first);
291  const auto server_name = address ? address.AsString() : server.first;
292  const auto& server_side = get<TServerSide>(server.second);
293  ostringstream os;
294  os << "server=" << server_name << "&latency=" << get<TLatency>(server.second).count();
295  if (!server_side.empty()) os << "&server_side=" << server_side;
296  os << '\n';
297  cerr << os.str();
298  }
299  }
300  catch (exception& ex) {
301  cerr << "Exception on calculating latencies: " << ex.what();
302  }
303 }
304 
306 {
307  // If it has already been started
308  if (m_Handler) {
309  return;
310  }
311 
312  SetWhich(which);
313  m_Handler.reset(new SHandler);
315  SetDiagFilter(eDiagFilter_All, m_Filter.c_str());
316  SetDiagHandler(m_Handler.get(), false);
317 
318  // Swapping stdout and stderr, so latency is reported to stdout and output of measured code to stderr
319  auto saved_stderr = NcbiSys_dup(NcbiSys_fileno(stderr));
320  _ASSERT(saved_stderr >= 0);
321  _VERIFY(NcbiSys_dup2(NcbiSys_fileno(stdout), NcbiSys_fileno(stderr)) >= 0);
322  _VERIFY(NcbiSys_dup2(saved_stderr, NcbiSys_fileno(stdout)) >= 0);
323  _VERIFY(NcbiSys_close(saved_stderr) >= 0);
324 }
325 
358 
@ eBoth
Both preliminary and traceback stages.
Definition: blast_def.h:332
Helper hook-up class that installs default logging/registry/locking (but only if they have not yet be...
void SetWhich(EWhich which)
std::optional< regex > m_ServerSide
TResult Parse(const TData &data)
map< string, TServerResult > TResult
deque< SDiagMessage > TData
void Start(EWhich which)
static TServers DiscoverImpl(const string &, unsigned, shared_ptr< void > &, pair< string, const char * >, int, unsigned long)
pair< SSocketAddress, double > TServer
vector< TServer > TServers
shared_ptr< void > m_Data
CServiceDiscovery(const string &service_name, SSocketAddress::SHost::EName name=SSocketAddress::SHost::EName::eOriginal)
const bool m_IsSingleServer
TServers operator()()
const string m_ServiceName
const_iterator end() const
Definition: map.hpp:152
bool operator<(const SSocketAddress &lhs, const SSocketAddress &rhs)
bool operator==(const SSocketAddress &lhs, const SSocketAddress &rhs)
NCBI_EXPORT_FUNC_DEFINE(XCONNECT, mbedtls_ctr_drbg_free_ncbicxx_2_28_8)
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.
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.
static DLIST_TYPE *DLIST_NAME() next(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:56
static const struct type types[]
Definition: type.c:22
char data[12]
Definition: iconv.c:80
unique_ptr< T, TDeleter > make_c_unique(T *p, TDeleter d)
Eliminates the necessity for specifying types of both allocated resource and deallocating C function.
Definition: ncbimisc.hpp:1448
@ eOn
Definition: ncbi_types.h:111
string
Definition: cgiapp.hpp:687
#define NULL
Definition: ncbistd.hpp:225
#define _VERIFY(expr)
Definition: ncbidbg.hpp:161
void SetDiagFilter(EDiagFilter what, const char *filter_str)
Set diagnostic filter.
Definition: ncbidiag.cpp:7670
CDiagContext & GetDiagContext(void)
Get diag context instance.
Definition: logging.cpp:818
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
void SetDiagHandler(CDiagHandler *handler, bool can_delete=true)
Set the diagnostic handler using the specified diagnostic handler class.
Definition: ncbidiag.cpp:6288
static void SetOldPostFormat(bool value)
Set old/new format flag.
Definition: ncbidiag.cpp:3352
@ eDiagFilter_All
for all non-FATAL
Definition: ncbidiag.hpp:2531
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
void SERV_Close(SERV_ITER iter)
Deallocate the iterator.
Definition: ncbi_service.c:993
unsigned int TSERV_Type
Bitwise OR of ESERV_Type[Special].
Definition: ncbi_service.h:94
#define SERV_LOCALHOST
Special values for the "preferred_host" parameter.
Definition: ncbi_service.h:54
SSERV_InfoCPtr SERV_GetNextInfoEx(SERV_ITER iter, HOST_INFO *host_info)
Get the next server meta-address, optionally accompanied by the host parameters made available by the...
Definition: ncbi_service.c:928
@ fSERV_Standalone
@ fSERV_IncludeStandby
Definition: ncbi_service.h:87
static string ntoa(unsigned int host)
BSD-like API. NB: when int, "host" must be in network byte order.
static unsigned int gethostbyname(const string &host, ESwitch log=eOff)
Return 0 on error.
static string gethostbyaddr(unsigned int host, ESwitch log=eOff)
Return empty string on error.
static bool SplitInTwo(const CTempString str, const CTempString delim, string &str1, string &str2, TSplitFlags flags=0)
Split a string into two pieces using the specified delimiters.
Definition: ncbistr.cpp:3554
#define NCBI_TIME_INFINITE
Definition: ncbi_types.h:147
SConnNetInfo * ConnNetInfo_Create(const char *service)
void ConnNetInfo_Destroy(SConnNetInfo *net_info)
yy_size_t n
static MDB_envinfo info
Definition: mdb_load.c:37
Uint4 GetHost(TEndpointKey key)
EIPRangeType t
Definition: ncbi_localip.c:101
SERV_ITER SERV_OpenP(const char *service, TSERV_Type types, unsigned int preferred_host, unsigned short preferred_port, double preference, const SConnNetInfo *net_info, SSERV_InfoCPtr skip[], size_t n_skip, int external, const char *arg, const char *val)
Definition: ncbi_service.c:837
void SleepMilliSec(unsigned long ml_sec, EInterruptOnSignal onsignal=eRestartOnSignal)
#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 max(T x_, T y_)
T min(T x_, T y_)
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.
void mbedtls_strerror(int errnum, char *buffer, size_t buflen)
Translate an Mbed TLS error code into a string representation.
#define NcbiSys_dup2
Definition: ncbisys.hpp:42
#define NcbiSys_fileno
Definition: ncbisys.hpp:43
#define NcbiSys_dup
Definition: ncbisys.hpp:41
#define NcbiSys_close
Definition: ncbisys.hpp:40
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.
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.
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(...
int mbedtls_ssl_close_notify(mbedtls_ssl_context *ssl)
Notify the peer that the connection is being closed.
int mbedtls_ssl_setup(mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf)
Set up an SSL context for use.
shared_ptr< void > GetSingleServer(const string &service_name, SSocketAddress::SHost::EName name) const
unsigned GetHost(const string &name) const
map< unsigned, string > m_Data
const string & GetName(unsigned host)
static SSocketAddressImpl & GetInstance()
string GetHostName() const
std::optional< string > m_Name
unsigned short port
static SSocketAddress Parse(const string &address, SHost::EName name=SHost::EName::eResolved)
#define _ASSERT
else result
Definition: token2.c:20
Modified on Tue Apr 23 07:37:57 2024 by modify_doxy.py rev. 669887