1 /* $Id: ncbi_core_cxx.cpp 624723 2021-02-03 18:51:43Z ivanov $
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  * Author:  Anton Lavrentiev
27  *
28  * File Description:
29  *   C++->C conversion tools for basic CORE connect stuff:
30  *     Registry
31  *     Logging
32  *     Locking
33  *
34  */
35 
36 #include <ncbi_pch.hpp>
37 #include "ncbi_ansi_ext.h"
38 #include "ncbi_priv.h"
39 #include "ncbi_socketp.h"
40 #include <corelib/ncbiapp.hpp>
41 #include <corelib/ncbidbg.hpp>
42 #include <corelib/ncbi_param.hpp>
43 #include <corelib/request_ctx.hpp>
44 #include <connect/error_codes.hpp>
45 #include <connect/ncbi_core_cxx.hpp>
46 #include <connect/ncbi_monkey.hpp>
47 #include <common/ncbi_sanitizers.h>
48 
49 #define NCBI_USE_ERRCODE_X   Connect_Core
50 
51 
52 BEGIN_NCBI_SCOPE
53 
54 
55 NCBI_PARAM_DECL  (bool, CONN, TRACE_REG);
56 NCBI_PARAM_DEF_EX(bool, CONN, TRACE_REG,
57                   false, eParam_Default, CONN_TRACE_REG);
58 static NCBI_PARAM_TYPE (CONN, TRACE_REG) s_TraceReg;
59 
60 NCBI_PARAM_DECL  (bool, CONN, TRACE_LOG);
61 NCBI_PARAM_DEF_EX(bool, CONN, TRACE_LOG,
62                   false, eParam_Default, CONN_TRACE_LOG);
63 static NCBI_PARAM_TYPE (CONN, TRACE_LOG) s_TraceLog;
64 
65 NCBI_PARAM_DECL  (bool, CONN, TRACE_LOCK);
66 NCBI_PARAM_DEF_EX(bool, CONN, TRACE_LOCK,
67                   false, eParam_Default, CONN_TRACE_LOCK);
68 static NCBI_PARAM_TYPE (CONN, TRACE_LOCK) s_TraceLock;
69 
70 
71 static TCORE_Set s_CORE_Set = 0;
72 
73 
74 /***********************************************************************
75  *                              Registry                               *
76  ***********************************************************************/
77 
78 
x_Reg(const char * section,const char * name,const char * value=0,EREG_Storage storage=eREG_Transient)79 static string x_Reg(const char* section, const char* name,
80                     const char* value = 0,
81                     EREG_Storage storage = eREG_Transient)
82 {
83     string x_section;
84     if (section)
85         x_section = '[' + string(section) + ']';
86     else
87         x_section = "<NULL>";
88     string x_name;
89     if (name)
90         x_name = '"' + string(name) + '"';
91     else
92         x_name = "<NULL>";
93     string x_value;
94     if (value)
95         x_value = "=\"" + string(value) + '"';
96     string x_storage;
97     if (value) {
98         switch (int(storage)) {
99         case eREG_Transient:
100             x_storage = ", <Transient>";
101             break;
102         case eREG_Persistent:
103             x_storage = ", <Persistent>";
104             break;
105         default:
106             x_storage = ", <" + NStr::IntToString(int(storage)) + '>';
107             break;
108         }
109     }
110     return x_section + x_name + x_value + x_storage;
111 }
112 
113 
114 extern "C" {
s_REG_Get(void * user_data,const char * section,const char * name,char * value,size_t value_size)115 static int s_REG_Get(void* user_data,
116                       const char* section, const char* name,
117                       char* value, size_t value_size) THROWS_NONE
118 {
119     if (s_TraceReg.Get()) {
120         _TRACE("s_REG_Get(" + NStr::PtrToString(user_data) + ", "
121                + x_Reg(section, name) + ')');
122     }
123     int result = 0/*assume error, including truncation*/;
124     try {
125         string item
126             = static_cast<const IRegistry*> (user_data)->Get(section, name);
127         if (!item.empty()) {
128             size_t len = item.size();
129             if (len >= value_size)
130                 len  = value_size - 1;
131             else
132                 result = 1/*success*/;
133             strncpy0(value, item.data(), len);
134 
135             if (s_TraceReg.Get()) {
136                 _TRACE("s_REG_Get(" + NStr::PtrToString(user_data) + ", "
137                        + x_Reg(section, name) + ") = \"" + string(value)
138                        + (result ? "\"" : "\" <Truncated>"));
139             }
140         } else
141             result = -1/*unmodified*/;
142     }
143     NCBI_CATCH_ALL_X(1, "s_REG_Get(" + NStr::PtrToString(user_data) + ", "
144                      + x_Reg(section, name)
145                      + ") failed");
146     return result;
147 }
148 }
149 
150 
151 extern "C" {
s_REG_Set(void * user_data,const char * section,const char * name,const char * value,EREG_Storage storage)152 static int s_REG_Set(void* user_data,
153                      const char* section, const char* name,
154                      const char* value, EREG_Storage storage) THROWS_NONE
155 {
156     if (s_TraceReg.Get()) {
157         _TRACE("s_REG_" + string(value ? "Set" : "Unset") + '('
158                + NStr::PtrToString(user_data) + ", "
159                + x_Reg(section, name, value ? value : "", storage) + ')');
160     }
161     int result = 0;
162     try {
163         IRWRegistry* reg = static_cast<IRWRegistry*> (user_data);
164         result = value
165             ? reg->Set  (section, name, value,
166                          (storage == eREG_Persistent
167                           ? CNcbiRegistry::fPersistent
168                           | CNcbiRegistry::fTruncate
169                           : CNcbiRegistry::fTruncate))
170             : reg->Unset(section, name,
171                          (storage == eREG_Persistent
172                           ? CNcbiRegistry::fPersistent
173                           : CNcbiRegistry::fTransient));
174     }
175     NCBI_CATCH_ALL_X(2, "s_REG_" + string(value ? "Set" : "Unset") + '('
176                      + NStr::PtrToString(user_data) + ", "
177                      + x_Reg(section, name, value ? value : "", storage)
178                      + ") failed");
179     return result;
180 }
181 }
182 
183 
184 extern "C" {
s_REG_Cleanup(void * user_data)185 static void s_REG_Cleanup(void* user_data) THROWS_NONE
186 {
187 
188     if (s_TraceReg.Get())
189         _TRACE("s_REG_Cleanup(" + NStr::PtrToString(user_data) + ')');
190     try {
191         static_cast<const IRegistry*> (user_data)->RemoveReference();
192     }
193     NCBI_CATCH_ALL_X(3, "s_REG_Cleanup("
194                      + NStr::PtrToString(user_data) + ") failed");
195 }
196 }
197 
198 
REG_cxx2c(IRWRegistry * reg,bool pass_ownership)199 extern REG REG_cxx2c(IRWRegistry* reg, bool pass_ownership)
200 {
201     if (s_TraceReg.Get())
202         _TRACE("REG_cxx2c(" + NStr::PtrToString(reg) + ')');
203     if (!reg)
204         return 0;
205     if (pass_ownership)
206         reg->AddReference();
207     return REG_Create(reg,
208                       s_REG_Get, s_REG_Set,
209                       pass_ownership ? s_REG_Cleanup : 0, 0);
210 }
211 
212 
REG_cxx2c(const IRWRegistry * reg,bool pass_ownership)213 extern REG REG_cxx2c(const IRWRegistry* reg, bool pass_ownership)
214 {
215     if (s_TraceReg.Get())
216         _TRACE("REG_cxx2c(const " + NStr::PtrToString(reg) + ')');
217     if (!reg)
218         return 0;
219     if (pass_ownership)
220         reg->AddReference();
221     return REG_Create(const_cast<IRWRegistry*> (reg),
222                       s_REG_Get, 0/*no setter*/,
223                       pass_ownership ? s_REG_Cleanup : 0, 0);
224 }
225 
226 
227 /***********************************************************************
228  *                                Logger                               *
229  ***********************************************************************/
230 
231 
x_Log(ELOG_Level level)232 static string x_Log(ELOG_Level level)
233 {
234     string x_level;
235     switch (int(level)) {
236         case eLOG_Trace:
237             x_level = "Trace";
238             break;
239         case eLOG_Note:
240             x_level = "Note";
241             break;
242         case eLOG_Warning:
243             x_level = "Warning";
244             break;
245         case eLOG_Error:
246             x_level = "Error";
247             break;
248         case eLOG_Critical:
249             x_level = "Critical";
250             break;
251         case eLOG_Fatal:
252             x_level = "Fatal";
253             break;
254         default:
255             x_level = NStr::IntToString(int(level));
256             break;
257     }
258     return x_level;
259 }
260 
261 
262 extern "C" {
s_LOG_Handler(void *,const SLOG_Message * mess)263 static void s_LOG_Handler(void*             /*data*/,
264                           const SLOG_Message* mess) THROWS_NONE
265 {
266     if (s_TraceLog.Get())
267         _TRACE("s_LOG_Handler(" + x_Log(mess->level) + ')');
268     try {
269         EDiagSev level;
270         switch (int(mess->level)) {
271         case eLOG_Trace:
272             level = eDiag_Trace;
273             break;
274         case eLOG_Note:
275             level = eDiag_Info;
276             break;
277         case eLOG_Warning:
278             level = eDiag_Warning;
279             break;
280         case eLOG_Error:
281             level = eDiag_Error;
282             break;
283         case eLOG_Critical:
284             level = eDiag_Critical;
285             break;
286         case eLOG_Fatal:
287             /*FALLTHRU*/
288         default:
289             level = eDiag_Fatal;
290             break;
291         }
292         if (!IsVisibleDiagPostLevel(level))
293             return;
294 
295         CDiagCompileInfo info(mess->file,
296                               mess->line,
297                               mess->func,
298                               mess->module);
299         CNcbiDiag diag(info, level);
300         diag.SetErrorCode(mess->err_code, mess->err_subcode);
301         diag << mess->message;
302         if (mess->raw_size) {
303             diag <<
304                 "\n#################### [BEGIN] Raw Data (" <<
305                 mess->raw_size <<
306                 " byte" << (mess->raw_size != 1 ? "s" : "") << ")\n" <<
307                 NStr::PrintableString
308                 (CTempString(static_cast<const char*>(mess->raw_data),
309                              mess->raw_size),
310                  NStr::fNewLine_Passthru | NStr::fNonAscii_Quote) <<
311                 "\n#################### [END] Raw Data";
312         }
313     }
314     NCBI_CATCH_ALL_X(4, "s_LOG_Handler(" + x_Log(mess->level) + ") failed");
315 }
316 }
317 
318 
LOG_cxx2c(void)319 extern LOG LOG_cxx2c(void)
320 {
321     if (s_TraceLog.Get())
322         _TRACE("LOG_cxx2c()");
323     return LOG_Create(0, s_LOG_Handler, 0, 0);
324 }
325 
326 
327 /***********************************************************************
328  *                               MT-Lock                               *
329  ***********************************************************************/
330 
331 
x_Lock(EMT_Lock how)332 static string x_Lock(EMT_Lock how)
333 {
334     string x_how;
335     switch (int(how)) {
336     case eMT_Lock:
337         x_how = "Lock";
338         break;
339     case eMT_LockRead:
340         x_how = "ReadLock";
341         break;
342     case eMT_Unlock:
343         x_how = "Unlock";
344         break;
345     case eMT_TryLock:
346         x_how = "TryLock";
347         break;
348     case eMT_TryLockRead:
349         x_how = "TryLockRead";
350         break;
351     default:
352         x_how = NStr::IntToString(int(how));
353         break;
354     }
355     return x_how;
356 }
357 
358 
359 extern "C" {
s_LOCK_Handler(void * user_data,EMT_Lock how)360 static int/*bool*/ s_LOCK_Handler(void* user_data, EMT_Lock how) THROWS_NONE
361 {
362     if (s_TraceLock.Get()) {
363         _TRACE("s_LOCK_Handler(" + NStr::PtrToString(user_data) + ", "
364                + x_Lock(how) + ')');
365     }
366     try {
367         CRWLock* lock = static_cast<CRWLock*> (user_data);
368         switch (int(how)) {
369         case eMT_Lock:
370             lock->WriteLock();
371             break;
372         case eMT_LockRead:
373             lock->ReadLock();
374             break;
375         case eMT_Unlock:
376             lock->Unlock();
377             break;
378         case eMT_TryLock:
379             if (!lock->TryWriteLock())
380                 return 0/*false*/;
381             break;
382         case eMT_TryLockRead:
383             if (!lock->TryReadLock())
384                 return 0/*false*/;
385             break;
386         default:
387             NCBI_THROW(CCoreException, eCore, "Lock used with unknown op #" +
388                        NStr::UIntToString((unsigned int) how));
389         }
390         return 1/*true*/;
391     }
392     NCBI_CATCH_ALL_X(5, "s_LOCK_Handler(" + NStr::PtrToString(user_data) + ", "
393                      + x_Lock(how) + ") failed");
394     return 0/*false*/;
395 }
396 }
397 
398 
399 extern "C" {
s_LOCK_Cleanup(void * user_data)400 static void s_LOCK_Cleanup(void* user_data) THROWS_NONE
401 {
402     if (s_TraceLock.Get())
403         _TRACE("s_LOCK_Cleanup(" + NStr::PtrToString(user_data) + ')');
404     try {
405         delete static_cast<CRWLock*> (user_data);
406     }
407     NCBI_CATCH_ALL_X(6, "s_LOCK_Cleanup("
408                      + NStr::PtrToString(user_data) + ") failed");
409 }
410 }
411 
412 
MT_LOCK_cxx2c(CRWLock * lock,bool pass_ownership)413 extern MT_LOCK MT_LOCK_cxx2c(CRWLock* lock, bool pass_ownership)
414 {
415     if (s_TraceLock.Get())
416         _TRACE("MT_LOCK_cxx2c(" + NStr::PtrToString(lock) + ')');
417     return MT_LOCK_Create(static_cast<void*> (lock ? lock : new CRWLock),
418                           s_LOCK_Handler,
419                           !lock  ||  pass_ownership ? s_LOCK_Cleanup : 0);
420 }
421 
422 
423 /***********************************************************************
424  *                               App Name                              *
425  ***********************************************************************/
426 
427 
428 extern "C" {
s_GetAppName(void)429 static const char* s_GetAppName(void)
430 {
431     CNcbiApplicationGuard app = CNcbiApplication::InstanceGuard();
432     return app ? app->GetProgramDisplayName().c_str() : 0;
433 }
434 }
435 
436 
437 /***********************************************************************
438  *                           NCBI Request ID                           *
439  ***********************************************************************/
440 
441 
442 extern "C" {
s_GetRequestID(ENcbiRequestID reqid)443 static char* s_GetRequestID(ENcbiRequestID reqid)
444 {
445     string id;
446     switch (reqid) {
447     case eNcbiRequestID_SID:
448         if (!CDiagContext::GetRequestContext().IsSetSessionID())
449             CDiagContext::GetRequestContext().SetSessionID();
450         CDiagContext::GetRequestContext().GetSessionID().swap(id);
451         break;
452     case eNcbiRequestID_HitID:
453         id = CDiagContext::GetRequestContext().GetNextSubHitID();
454         break;
455     default:
456         return 0;
457     }
458     return id.empty() ? 0 : strdup(id.c_str());
459 }
460 }
461 
462 
463 /***********************************************************************
464  *                          NCBI Request DTab                          *
465  ***********************************************************************/
466 
467 
468 extern "C" {
s_GetRequestDTab(void)469 static const char* s_GetRequestDTab(void)
470 {
471     if (!CDiagContext::GetRequestContext().IsSetDtab())
472         CDiagContext::GetRequestContext().SetDtab("");
473     return CDiagContext::GetRequestContext().GetDtab().c_str();
474 }
475 }
476 
477 
478 /***********************************************************************
479  *                         CRAZY MONKEY CALLS                          *
480  ***********************************************************************/
481 
482 
483 #ifdef NCBI_MONKEY
484 extern "C" {
485     static MONKEY_RETTYPE
s_MonkeySend(MONKEY_SOCKTYPE sock,const MONKEY_DATATYPE data,MONKEY_LENTYPE size,int flags,void * sock_ptr)486         MONKEY_STDCALL s_MonkeySend(MONKEY_SOCKTYPE        sock,
487                                     const MONKEY_DATATYPE  data,
488                                     MONKEY_LENTYPE         size,
489                                     int                    flags,
490                                     void* /* SOCK* */      sock_ptr)
491     {
492         return CMonkey::Instance()->Send(sock, data, size, flags,
493                                          (SOCK*)sock_ptr);
494     }
495 
496     static MONKEY_RETTYPE
s_MonkeyRecv(MONKEY_SOCKTYPE sock,MONKEY_DATATYPE buf,MONKEY_LENTYPE size,int flags,void * sock_ptr)497         MONKEY_STDCALL s_MonkeyRecv(MONKEY_SOCKTYPE   sock,
498                                     MONKEY_DATATYPE   buf,
499                                     MONKEY_LENTYPE    size,
500                                     int               flags,
501                                     void* /* SOCK* */ sock_ptr)
502     {
503         return CMonkey::Instance()->Recv(sock, buf, size, flags,
504                                          (SOCK*) sock_ptr);
505     }
506 
507 
s_MonkeyConnect(MONKEY_SOCKTYPE sock,const struct sockaddr * name,MONKEY_SOCKLENTYPE namelen)508     static int MONKEY_STDCALL s_MonkeyConnect(MONKEY_SOCKTYPE        sock,
509                                               const struct sockaddr* name,
510                                               MONKEY_SOCKLENTYPE     namelen)
511     {
512         return CMonkey::Instance()->Connect(sock, name, namelen);
513     }
514 
515 
s_MonkeyPoll(size_t * n,void * polls,EIO_Status * return_status)516     static int /*bool*/ s_MonkeyPoll(size_t*                  n,
517                                      void* /* SSOCK_Poll** */ polls,
518                                      EIO_Status*              return_status)
519     {
520         return CMonkey::Instance()->
521             Poll(n, (SSOCK_Poll**) polls, return_status) ? 1 : 0;
522     }
523 
524 
s_MonkeyClose(SOCKET sock)525     static void s_MonkeyClose(SOCKET  sock)
526     {
527         CMonkey::Instance()->Close(sock);
528     }
529 
530 
s_MonkeySockHasSocket(void * sock,MONKEY_SOCKTYPE socket)531     static void s_MonkeySockHasSocket(void* /* SOCK* */ sock,
532                                       MONKEY_SOCKTYPE socket)
533     {
534         CMonkey::Instance()->SockHasSocket((SOCK)sock, socket);
535     }
536 }
537 
538 
s_MONKEY_Poll_dummy(size_t * n,void * polls,EIO_Status * return_status)539 static int s_MONKEY_Poll_dummy(size_t*     n,
540                                void*       polls,
541                                EIO_Status* return_status)
542 {
543     return 0; /* call was not intercepted by Monkey*/
544 }
545 
546 
s_MONKEY_Close_dummy(SOCKET sock)547 static void s_MONKEY_Close_dummy(SOCKET sock)
548 {
549     return; /* call was not intercepted by Monkey*/
550 }
551 
552 
553 /* Chaos Monkey hooks for Connect library*/
s_SetMonkeyHooks(EMonkeyHookSwitch hook_switch)554 static void s_SetMonkeyHooks(EMonkeyHookSwitch hook_switch)
555 {
556     switch (hook_switch)
557     {
558     case eMonkeyHookSwitch_Disabled:
559         g_MONKEY_Send          = 0;
560         g_MONKEY_Recv          = 0;
561         g_MONKEY_Connect       = 0;
562         g_MONKEY_Poll          = 0;
563         g_MONKEY_Close         = 0;
564         g_MONKEY_SockHasSocket = 0;
565         break;
566     case eMonkeyHookSwitch_Enabled:
567         g_MONKEY_Send          = s_MonkeySend;
568         g_MONKEY_Recv          = s_MonkeyRecv;
569         g_MONKEY_Connect       = s_MonkeyConnect;
570         g_MONKEY_Poll          = s_MonkeyPoll;
571         g_MONKEY_Close         = s_MonkeyClose;
572         g_MONKEY_SockHasSocket = s_MonkeySockHasSocket;
573         break;
574     default:
575         break;
576     }
577 }
578 #endif //NCBI_MONKEY
579 
580 
581 static volatile enum EConnectInit {
582     eConnectInit_Weak     = -1,  ///< CConn_Initer
583     eConnectInit_Intact   =  0,  ///< Not yet visited
584     eConnectInit_Strong   =  1,  ///< User init detected
585     eConnectInit_Explicit =  2   ///< CONNECT_Init() called
586 } s_ConnectInit = eConnectInit_Intact;
587 
588 
589 /***********************************************************************
590  *                                 Fini                                *
591  ***********************************************************************/
592 
593 
594 extern "C" {
s_Fini(void)595 static void s_Fini(void) THROWS_NONE
596 {
597     _TRACE("CONNECT::s_Fini()");
598     s_CORE_Set &= ~g_CORE_Set;
599     if (s_CORE_Set & eCORE_SetSSL)
600         SOCK_SetupSSL(0);
601     if (s_CORE_Set & eCORE_SetREG)
602         CORE_SetREG(0);
603     if (s_CORE_Set & eCORE_SetLOG)
604         CORE_SetLOG(0);
605     if (s_CORE_Set & eCORE_SetLOCK)
606         CORE_SetLOCK(&g_CORE_MT_Lock_default);
607     g_CORE_Set &= ~s_CORE_Set;
608     s_CORE_Set  =  0;
609 }
610 }
611 
612 
613 /***********************************************************************
614  *                                 Init                                *
615  ***********************************************************************/
616 
617 
618 DEFINE_STATIC_FAST_MUTEX(s_ConnectInitMutex);
619 
620 /* NB: gets called under a lock */
s_Init(const IRWRegistry * reg=0,FSSLSetup ssl=0,CRWLock * lock=0,TConnectInitFlags flag=0,EConnectInit how=eConnectInit_Weak)621 static void s_Init(const IRWRegistry* reg  = 0,
622                    FSSLSetup          ssl  = 0,
623                    CRWLock*           lock = 0,
624                    TConnectInitFlags  flag = 0,
625                    EConnectInit       how  = eConnectInit_Weak)
626 {
627     _TRACE("CONNECT::s_Init("
628            + NStr::PtrToString(reg)                         + ", "
629            + NStr::PtrToString((void*) ssl)                 + "(), "
630            + NStr::PtrToString(lock)                        + ", 0x"
631            + NStr::UIntToString((unsigned int) flag, 0, 16) + ", "
632            + NStr::IntToString(int(how))                    + ')');
633     _ASSERT(how != eConnectInit_Intact);
634 
635     TCORE_Set set = 0;
636     if (!(g_CORE_Set & eCORE_SetLOCK)) {
637         NCBI_LSAN_DISABLE_GUARD;
638         CORE_SetLOCK(MT_LOCK_cxx2c(lock, !!(flag & eConnectInit_OwnLock)));
639         set |= eCORE_SetLOCK;
640     }
641     if (!(g_CORE_Set & eCORE_SetLOG)) {
642         CORE_SetLOG(LOG_cxx2c());
643         set |= eCORE_SetLOG;
644     }
645     if (!(g_CORE_Set & eCORE_SetREG)) {
646         CORE_SetREG(REG_cxx2c(reg, !!(flag & eConnectInit_OwnRegistry)));
647         set |= eCORE_SetREG;
648     }
649     if (!(g_CORE_Set & eCORE_SetSSL)) {
650         SOCK_SetupSSLInternal(ssl, 1/*init*/);
651         set |= ssl ? eCORE_SetSSL : 0;
652     }
653     g_CORE_Set &= ~set;
654     s_CORE_Set |=  set;
655 
656     if (s_ConnectInit == eConnectInit_Intact) {
657         g_NCBI_ConnectRandomSeed
658             = (unsigned int) time(0) ^ NCBI_CONNECT_SRAND_ADDEND;
659         srand(g_NCBI_ConnectRandomSeed);
660         atexit(s_Fini);
661     }
662 
663     g_CORE_GetAppName     = s_GetAppName;
664     g_CORE_GetRequestID   = s_GetRequestID;
665     g_CORE_GetRequestDtab = s_GetRequestDTab;
666 
667 #ifdef NCBI_MONKEY
668     /* Allow CMonkey to switch hooks to Connect library */
669     CMonkey::MonkeyHookSwitchSet(s_SetMonkeyHooks);
670     /* Create CMonkey instance. It loads config and sets hooks */
671     CMonkey::Instance();
672 #endif //NCBI_MONKEY
673 
674     s_ConnectInit = g_CORE_Set ? eConnectInit_Strong : how;
675 }
676 
677 
678 /* PUBLIC */
CONNECT_Init(const IRWRegistry * reg,CRWLock * lock,TConnectInitFlags flag,FSSLSetup ssl)679 extern void CONNECT_Init(const IRWRegistry* reg,
680                          CRWLock*           lock,
681                          TConnectInitFlags  flag,
682                          FSSLSetup          ssl)
683 {
684     CFastMutexGuard guard(s_ConnectInitMutex);
685     _TRACE("CONNECT_Init("
686            + NStr::PtrToString(reg)                         + ", "
687            + NStr::PtrToString(lock)                        + ", 0x"
688            + NStr::UIntToString((unsigned int) flag, 0, 16) + ", "
689            + NStr::PtrToString((void*) ssl)                 + "())");
690     try {
691         g_CORE_Set = 0;
692         s_Init(reg, flag & eConnectInit_NoSSL ? 0 :
693                ssl ? ssl : NcbiSetupTls,
694                lock, flag, eConnectInit_Explicit);
695     }
696     NCBI_CATCH_ALL_X(8, "CONNECT_Init() failed");
697 }
698 
699 
CConnIniter(void)700 CConnIniter::CConnIniter(void)
701 {
702     if (s_ConnectInit != eConnectInit_Intact)
703         return;
704     CFastMutexGuard guard(s_ConnectInitMutex);
705     try {
706         if (s_ConnectInit == eConnectInit_Intact) {
707             CNcbiApplicationGuard app = CNcbiApplication::InstanceGuard();
708             s_Init(app ? &app->GetConfig() : 0, NcbiSetupTls);
709         }
710     }
711     NCBI_CATCH_ALL_X(7, "CConn_Initer::CConn_Initer() failed");
712 }
713 
714 
715 END_NCBI_SCOPE
716