1 /* $Id: test_ncbi_conn.cpp 594768 2019-10-09 14:57:02Z lavr $
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  *   Run NCBI connectivity test
30  *
31  */
32 
33 #include <ncbi_pch.hpp>
34 #include "../ncbi_ansi_ext.h"
35 #include "../ncbi_priv.h"
36 #include "../ncbi_version.h"
37 #include <corelib/ncbiapp.hpp>
38 #include <corelib/ncbifile.hpp>
39 #ifdef NCBI_OS_MSWIN
40 #  include <corelib/ncbi_system.hpp>
41 #endif // NCBI_OS_MSWIN
42 #include <corelib/rwstream.hpp>
43 #include <connect/ncbi_connutil.h>
44 #include <connect/ncbi_conn_test.hpp>
45 #include <connect/ncbi_socket.hpp>
46 #include <util/multi_writer.hpp>
47 #include <iomanip>
48 #if   defined(NCBI_OS_MSWIN)
49 #  include <conio.h>
50 #elif defined(NCBI_OS_UNIX)
51 #  include <signal.h>
52 #endif // NCBI_OS
53 
54 
55 #define PAGE_WIDTH  72
56 
57 
58 BEGIN_NCBI_SCOPE
59 
60 
61 static const char kLogfile[] = "test_ncbi_conn.log";
62 
63 
64 static bool s_Run = true;
65 
66 
67 static volatile bool s_Canceled = false;
68 
69 
70 class CCanceled : public CObject, public ICanceled
71 {
72 public:
IsCanceled(void) const73     virtual bool IsCanceled(void) const { return s_Canceled; }
74 };
75 
76 
77 ////////////////////////////////
78 // Test application
79 //
80 
81 class CTestApp : public CNcbiApplication
82 {
83 public:
84     CTestApp(CNcbiOstream& log);
85 
86     virtual void Init(void);
87     virtual int  Run (void);
88 
89 protected:
90     virtual bool LoadConfig(CNcbiRegistry& reg, const string* conf);
91     using CNcbiApplication::LoadConfig;
92 
93 private:
94     CWStream m_Tee;
95 };
96 
97 
98 #if   defined(NCBI_OS_MSWIN)
s_Interrupt(DWORD type)99 static BOOL WINAPI s_Interrupt(DWORD type)
100 {
101     switch (type) {
102     case CTRL_C_EVENT:
103     case CTRL_BREAK_EVENT:
104         s_Canceled = true;
105         return TRUE;  // handled
106     case CTRL_CLOSE_EVENT:
107     case CTRL_LOGOFF_EVENT:
108     case CTRL_SHUTDOWN_EVENT:
109     default:
110         break;
111     }
112     return FALSE;  // unhandled
113 }
114 #elif defined(NCBI_OS_UNIX)
115 extern "C" {
s_Interrupt(int)116 static void s_Interrupt(int /*signo*/)
117 {
118     s_Canceled = true;
119 }
120 }
121 #endif // NCBI_OS
122 
123 
s_MakeList(CNcbiOstream & os1,CNcbiOstream & os2)124 static list<CNcbiOstream*> s_MakeList(CNcbiOstream& os1,
125                                       CNcbiOstream& os2)
126 {
127     list<CNcbiOstream*> rv;
128     rv.push_front(&os1);
129     rv.push_back (&os2);
130     return rv;
131 }
132 
133 
CTestApp(CNcbiOstream & log)134 CTestApp::CTestApp(CNcbiOstream& log)
135     : m_Tee(new CMultiWriter(s_MakeList(NcbiCout, log)),
136             0, 0, CRWStreambuf::fOwnWriter)
137 {
138     HideStdArgs(-1/*everything*/);
139 }
140 
141 
LoadConfig(CNcbiRegistry & reg,const string * conf)142 bool CTestApp::LoadConfig(CNcbiRegistry& reg, const string* conf)
143 {
144     string dir;
145     const string& path = GetProgramExecutablePath();
146     CDirEntry::SplitPath(path, &dir, NULL, NULL);
147     CMetaRegistry::SetSearchPath().clear();
148     CMetaRegistry::SetSearchPath().push_back(dir);
149     return LoadConfig(reg, conf, 0);
150 }
151 
152 
Init(void)153 void CTestApp::Init(void)
154 {
155     // Show revision number in the name
156     string appname = GetProgramDisplayName() + '/';
157     appname += g_VersionStr("$Revision: 594768 $");
158     SetProgramDisplayName(appname);
159 
160     // Init the library explicitly (this sets up the registry)
161     {
162         class CInPlaceConnIniter : protected CConnIniter
163         {
164         } conn_initer;  /*NCBI_FAKE_WARNING*/
165     }
166 
167     auto_ptr<CArgDescriptions> args(new CArgDescriptions);
168     if (args->Exist ("h"))
169         args->Delete("h");
170     if (args->Exist ("xmlhelp"))
171         args->Delete("xmlhelp");
172     args->AddFlag("nopause",
173                   "Do not pause at the end"
174 #ifndef NCBI_OS_MSWIN
175                   " (MS-WIN only, no effect on this platform)"
176 #endif // !NCBI_OS_MSWIN
177                   );
178     args->AddExtra(0/*no mandatory*/, 1/*single timeout argument allowed*/,
179                    "Timeout", CArgDescriptions::eDouble);
180     args->SetUsageContext(GetArguments().GetProgramBasename(),
181                           "NCBI Connectivity Test Suite");
182     SetupArgDescriptions(args.release());
183 
184     s_Run = false;
185 }
186 
187 
Run(void)188 int CTestApp::Run(void)
189 {
190     s_Run = true;
191 
192     const CArgs& args = GetArgs();
193     double timeout;
194 
195     if (!args.GetNExtra()) {
196         char val[40], *e;
197         if (!ConnNetInfo_GetValue(0, REG_CONN_TIMEOUT, val, sizeof(val), 0)
198             ||  !*val  ||  (timeout = NCBI_simple_atof(val, &e)) < 0.0
199             ||  errno  ||  *e) {
200             timeout = DEF_CONN_TIMEOUT;
201         }
202     } else if ((timeout = args[1].AsDouble()) < 0.0)
203         timeout = DEF_CONN_TIMEOUT;
204 
205     m_Tee << NcbiEndl << "NCBI Connectivity Test Suite (Timeout = "
206           << setprecision(6) << timeout << "s, "
207           << (CConnTest::IsNcbiInhouseClient() ? "" : "non-")
208           << "local client)" << NcbiEndl;
209 
210     STimeout tmo;
211     tmo.sec  = (unsigned int)  timeout;
212     tmo.usec = (unsigned int)((timeout - tmo.sec) * 1000000.0);
213 
214     CCanceled canceled;
215     CConnTest test(&tmo, &m_Tee);
216     test.SetCanceledCallback(&canceled);
217     CSocketAPI::SetInterruptOnSignal(eOn);
218 
219     test.SetDebugPrintout(eDebugPrintout_Data);
220     CConnTest::EStage everything = CConnTest::eStatefulService;
221     EIO_Status status = test.Execute(everything);
222 
223     test.SetOutput(0);
224 
225     if (status != eIO_Success) {
226         list<string> msg;
227         NStr::Justify("Detailed transaction log has been saved in:",
228                       PAGE_WIDTH, msg);
229         msg.push_back('"' + CDirEntry::CreateAbsolutePath(kLogfile) + "\".");
230         msg.push_back(kEmptyStr);
231         NStr::Justify("Should you choose to make its contents available to"
232                       " NCBI, please keep in mind that the log can contain"
233                       " authorization credentials, which you may want to"
234                       " redact prior to actually submitting the file for"
235                       " review.", PAGE_WIDTH, msg, "      ", "NOTE: ");
236         ITERATE(list<string>, line, msg)
237             m_Tee << NcbiEndl << *line;
238     } else {
239         _ASSERT(everything == CConnTest::eStatefulService);
240         m_Tee << NcbiEndl << "NCBI Connectivity Test Suite PASSED!";
241     }
242     m_Tee << NcbiEndl << NcbiEndl << NcbiFlush;
243 
244     int retval = status == eIO_Success ? 0 : 1;
245 #ifdef NCBI_OS_MSWIN
246     if (args["nopause"].HasValue())
247         retval = ~retval;
248 #endif // NCBI_OS_MSWIN
249 
250     CORE_SetREG(0);
251     return retval;
252 }
253 
254 
255 END_NCBI_SCOPE
256 
257 
main(int argc,const char * argv[])258 int main(int argc, const char* argv[])
259 {
260     USING_NCBI_SCOPE;
261 
262     // Set error posting and tracing at what regular use would do.
263     // If traces are needed, they can be enabled from the environment.
264     //SetDiagTrace(eDT_Enable);
265     SetDiagPostLevel(eDiag_Info);
266     SetDiagPostAllFlags(SetDiagPostAllFlags(eDPF_Default)
267                         | eDPF_All | eDPF_OmitInfoSev);
268     UnsetDiagPostFlag(eDPF_Line);
269     UnsetDiagPostFlag(eDPF_File);
270     UnsetDiagPostFlag(eDPF_Location);
271     UnsetDiagPostFlag(eDPF_LongFilename);
272     SetDiagTraceAllFlags(SetDiagPostAllFlags(eDPF_Default));
273 
274 #if   defined(NCBI_OS_MSWIN)
275     SetConsoleCtrlHandler(s_Interrupt, TRUE);
276 #elif defined(NCBI_OS_UNIX)
277     signal(SIGINT,  s_Interrupt);
278     signal(SIGQUIT, s_Interrupt);
279 #endif // NCBI_OS
280 
281     int retval = 1/*failure*/;
282 
283     try {
284         // Going to leak because it is used in CNcbiDiag after main() returns
285         CNcbiOfstream* log = new CNcbiOfstream(kLogfile,
286                                                IOS_BASE::out |
287                                                IOS_BASE::trunc);
288         log->close();
289         log->open(kLogfile, IOS_BASE::out | IOS_BASE::app);
290         if (log->good()) {
291             SetDiagStream(log);
292 
293             // Execute main application function
294             int rv = CTestApp(*log).AppMain(argc, argv, 0, eDS_User);
295 
296             log->flush();
297             retval = rv;
298         } else {
299             int/*bool*/ dynamic = 0/*false*/;
300             const char* msg = NcbiMessagePlusError
301                 (&dynamic, ("Cannot open logfile " +
302                             CDirEntry::CreateAbsolutePath(kLogfile)).c_str(),
303                  errno, 0);
304             ERR_POST(Critical << msg);
305             if (dynamic)
306                 free((void*) msg);
307             delete log;
308         }
309     }
310     NCBI_CATCH_ALL("Test failed");
311 
312 #ifdef NCBI_OS_MSWIN
313     if (retval < 0)
314         retval = ~retval;
315     else if (s_Run) {
316         NcbiCout << "Hit any key or program will bail out in 1 minute..."
317                  << NcbiFlush;
318         for (int n = 0;  n < 120;  ++n) {
319             if (_kbhit()) {
320                 _getch();
321                 break;
322             }
323             SleepMilliSec(500);
324         }
325     }
326 #endif // NCBI_OS_MSWIN
327 
328     return retval;
329 }
330