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