1 #ifndef WINDOWS
2 //#define DEPURAR 1
3 #endif
4 /*==============================================================================
5 *
6 *                            PUBLIC DOMAIN NOTICE
7 *               National Center for Biotechnology Information
8 *
9 *  This software/database is a "United States Government Work" under the
10 *  terms of the United States Copyright Act.  It was written as part of
11 *  the author's official duties as a United States Government employee and
12 *  thus cannot be copyrighted.  This software/database is freely available
13 *  to the public for use. The National Library of Medicine and the U.S.
14 *  Government have not placed any restriction on its use or reproduction.
15 *
16 *  Although all reasonable efforts have been taken to ensure the accuracy
17 *  and reliability of the software and data, the NLM and the U.S.
18 *  Government do not and cannot warrant the performance or results that
19 *  may be obtained by using this software or data. The NLM and the U.S.
20 *  Government disclaim all warranties, express or implied, including
21 *  warranties of performance, merchantability or fitness for any particular
22 *  purpose.
23 *
24 *  Please cite the author in any work or product based on this material.
25 *
26 * ==============================================================================
27 *
28 */
29 
30 #include "diagnose/diagnose.h" /* KDiagnoseAdvanced */
31 #include "diagnose.h" /* endpoint_to_string */
32 
33 #include <kfg/config.h> /* KConfigReadString */
34 
35 #include <kfs/directory.h> /* KDirectoryRelease */
36 #include <kfs/file.h> /* KFile */
37 
38 #include <klib/data-buffer.h> /* KDataBuffer */
39 #include <klib/out.h> /* KOutMsg */
40 #include <klib/printf.h> /* string_vprintf */
41 #include <klib/rc.h>
42 #include <klib/text.h> /* String */
43 #include <klib/vector.h> /* Vector */
44 
45 #include <kns/ascp.h> /* aspera_get */
46 #include <kns/endpoint.h> /* KNSManagerInitDNSEndpoint */
47 #include <kns/http.h> /* KHttpRequest */
48 #include <kns/manager.h> /* KNSManager */
49 #include <kns/kns-mgr-priv.h> /* KNSManagerMakeReliableHttpFile */
50 #include <kns/stream.h> /* KStream */
51 
52 #include <kproc/cond.h> /* KConditionRelease */
53 #include <kproc/lock.h> /* KLockRelease */
54 
55 #include <vfs/manager.h> /* VFSManagerOpenDirectoryRead */
56 #include <vfs/path.h> /* VFSManagerMakePath */
57 #include <vfs/resolver.h> /* VResolverRelease */
58 
59 #include <strtol.h> /* strtoi64 */
60 
61 #include <ctype.h> /* isprint */
62 #include <limits.h> /* PATH_MAX */
63 
64 #ifndef PATH_MAX
65 #define PATH_MAX 4096
66 #endif
67 
68 #define RELEASE(type, obj) do { rc_t rc2 = type##Release(obj); \
69     if (rc2 != 0 && rc == 0) { rc = rc2; } obj = NULL; } while (false)
70 
OutMsg(int level,unsigned type,const char * fmt,va_list args)71 static rc_t CC OutMsg ( int level, unsigned type,
72                         const char * fmt, va_list args )
73 {
74     return KOutVMsg ( fmt, args );
75 }
76 
77 static rc_t ( CC * LOGGER )
78     ( int level, unsigned type, const char * fmt, va_list args );
79 
KDiagnoseLogHandlerSet(KDiagnose * self,rc_t (CC * logger)(int level,unsigned type,const char * fmt,va_list args))80 LIB_EXPORT rc_t CC KDiagnoseLogHandlerSet ( KDiagnose * self,
81         rc_t ( CC * logger ) ( int level, unsigned type,
82                                const char * fmt, va_list args )
83     )
84 {
85     LOGGER = logger;
86     return 0;
87 }
88 
89 LIB_EXPORT
KDiagnoseLogHandlerSetKOutMsg(KDiagnose * self)90 rc_t CC KDiagnoseLogHandlerSetKOutMsg ( KDiagnose * self )
91 {
92     return KDiagnoseLogHandlerSet ( self, OutMsg );
93 }
94 
LogOut(int level,unsigned type,const char * fmt,...)95 static rc_t LogOut ( int level, unsigned type, const char * fmt, ... )
96 {
97     rc_t rc = 0;
98 
99     va_list args;
100     va_start ( args, fmt );
101 
102     if ( LOGGER != NULL )
103         rc = LOGGER ( level, type, fmt, args );
104 
105     va_end ( args );
106 
107     return rc;
108 }
109 
110 typedef struct { const char * begin; char * end; } Block;
111 
112 typedef struct {
113     KDataBuffer response; /* cgi response */
114     uint32_t code;        /* cgi response status code */
115     char * location;      /* cgi response redirect location */
116     KDataBuffer redirect; /* redirect response */
117 
118     Block p;
119     Block mailto;
120 
121     String ip;
122     String date;
123     char * server;
124 } Abuse;
125 
AbuseFini(Abuse * self)126 static rc_t AbuseFini ( Abuse * self ) {
127     rc_t rc = 0, r2 = 0;
128 
129     assert ( self );
130 
131     free ( self -> location );
132     free ( self -> server );
133 
134     rc = KDataBufferWhack ( & self -> response );
135 
136     r2 = KDataBufferWhack ( & self -> redirect );
137     if ( r2 != 0 && rc == 0 )
138         rc = r2;
139 
140     memset ( self, 0, sizeof * self );
141 
142     return rc;
143 }
144 
AbuseInit(Abuse * self)145 static void AbuseInit ( Abuse * self ) {
146     assert ( self );
147 
148     memset ( self, 0, sizeof * self );
149 
150     self -> response . elem_bits = self -> redirect . elem_bits = 8;
151 }
152 
AbuseSetStatus(Abuse * self,uint32_t code)153 static void AbuseSetStatus ( Abuse * self, uint32_t code ) {
154     assert ( self );
155 
156     self -> code = code;
157 }
158 
159 static
AbuseSetLocation(Abuse * self,const char * str,size_t size)160 rc_t AbuseSetLocation ( Abuse * self, const char * str, size_t size )
161 {
162     assert ( self );
163 
164     self -> location = string_dup ( str, size );
165     return self -> location != NULL
166         ? 0 : RC ( rcRuntime, rcString, rcCopying, rcMemory, rcExhausted );
167 }
168 
169 static
AbuseSetCgi(Abuse * self,const String * cgi)170 rc_t AbuseSetCgi ( Abuse * self, const String * cgi ) {
171     const char * s = NULL, * e = NULL;
172 
173     size_t i = 0;
174 
175     assert ( self && cgi );
176 
177     s = cgi -> addr;
178     if ( s == NULL )
179         return 0;
180 
181     for ( i = 0; i < cgi -> size ; ++ i ) {
182         switch ( * s ) {
183          case '\0':
184           return 0;
185 
186          case ':' :
187           if ( * ++ s != '/' )
188             return 0;
189           if ( * ++ s != '/' )
190             return 0;
191           if ( i >= cgi -> size )
192             return 0;
193 
194           e = string_chr ( ++ s, cgi -> size - i, '/' );
195           if ( e == NULL )
196             return 0;
197 
198           self -> server = string_dup ( s, e - s );
199           if ( self -> server == NULL )
200             return RC ( rcRuntime, rcString, rcCopying, rcMemory, rcExhausted );
201           else
202             return 0;
203 
204          default:
205           ++ s;
206         }
207     }
208 
209     return 0;
210 }
211 
AbuseAdd(Abuse * self,const char * txt,int sz)212 static rc_t AbuseAdd ( Abuse * self, const char * txt, int sz ) {
213     rc_t rc = 0;
214 
215     assert ( self );
216 
217     if ( rc == 0 )
218         return KDataBufferPrintf ( & self -> response,  "%s", txt );
219     else
220         return KDataBufferPrintf ( & self -> response,  "%.*s", sz, txt );
221 }
222 
find(const char * haystack,uint64_t n,const String * needle)223 static char * find ( const char * haystack, uint64_t n,
224                      const String * needle )
225 {
226     uint64_t i = 0;
227 
228     assert ( needle && needle -> addr );
229 
230     for ( i = 0; ; ++ i ) {
231         char * c = NULL;
232         uint64_t size = n - i;
233 
234         assert ( n >= i );
235 
236         c = string_chr ( haystack + i, size, * needle -> addr );
237         if ( c == NULL )
238             return NULL;
239 
240         i = c - haystack;
241         if ( i < needle -> size && i > 0)
242             return NULL;
243 
244         if ( string_cmp ( c, needle -> size, needle -> addr, needle -> size,
245                              ( uint32_t ) needle -> size) == 0)
246         {
247             return c;
248         }
249     }
250 }
251 
252 typedef struct {
253     bool incompleteGapKfg;
254     bool firewall;
255     bool blocked;
256 
257     Abuse abuse;
258 } Report;
259 
260 struct KDiagnose {
261     atomic32_t refcount;
262 
263     KConfig    * kfg;
264     KNSManager * kmgr;
265     VFSManager * vmgr;
266     rc_t       (CC * quitting) (void);
267 
268     int verbosity;
269 
270     Vector tests;
271     Vector errors;
272 
273     KDiagnoseTestDesc * desc;
274 
275     enum EState {
276         eRunning,
277         ePaused,
278         eCanceled,
279     } state;
280     KLock * lock;
281     KCondition * condition;
282 
283     Report report;
284 };
285 
286 struct KDiagnoseTest {
287     struct KDiagnoseTest * parent;
288     const struct KDiagnoseTest * next;
289     const struct KDiagnoseTest * nextChild;
290     const struct KDiagnoseTest * firstChild;
291     struct KDiagnoseTest * crntChild;
292     char * name;
293     uint64_t code;
294     uint32_t level;
295     char * message;
296     EKDiagTestState state;
297 
298     char * number;
299     char * numberNode;
300 };
301 
KDiagnoseTestWhack(KDiagnoseTest * self)302 static void KDiagnoseTestWhack ( KDiagnoseTest * self ) {
303     assert ( self );
304     free ( self -> name );
305     free ( self -> message );
306     free ( self -> number );
307     free ( self -> numberNode );
308     memset ( self, 0, sizeof * self );
309     free ( self );
310 }
311 
312 
KDiagnoseGetTests(const KDiagnose * self,const KDiagnoseTest ** test)313 LIB_EXPORT rc_t CC KDiagnoseGetTests ( const KDiagnose * self,
314                                        const KDiagnoseTest ** test )
315 {
316     if ( test == NULL )
317         return RC ( rcRuntime, rcData, rcAccessing, rcParam, rcNull );
318 
319     * test = NULL;
320 
321     if ( self == NULL )
322         return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );
323 
324     * test = VectorGet ( & self -> tests, 0 );
325     return 0;
326 }
327 
KDiagnoseTestNext(const KDiagnoseTest * self,const KDiagnoseTest ** test)328 LIB_EXPORT rc_t CC KDiagnoseTestNext ( const KDiagnoseTest * self,
329                                        const KDiagnoseTest ** test )
330 {
331     if ( test == NULL )
332         return RC ( rcRuntime, rcData, rcAccessing, rcParam, rcNull );
333 
334     * test = NULL;
335 
336     if ( self == NULL )
337         return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );
338 
339     * test = self -> next;
340     return 0;
341 }
342 
KDiagnoseTestChild(const KDiagnoseTest * self,uint32_t idx,const KDiagnoseTest ** test)343 LIB_EXPORT rc_t CC KDiagnoseTestChild ( const KDiagnoseTest * self,
344                           uint32_t idx, const KDiagnoseTest ** test )
345 {
346     const KDiagnoseTest * t = NULL;
347     uint32_t i;
348 
349     if ( test == NULL )
350         return RC ( rcRuntime, rcData, rcAccessing, rcParam, rcNull );
351 
352     * test = NULL;
353 
354     if ( self == NULL )
355         return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );
356 
357     for ( i = 0, t = self -> firstChild; i < idx && t != NULL;
358           ++ i, t = t->nextChild );
359 
360     * test = t;
361     return 0;
362 }
363 
364 #define TEST_GET_INT( PROPERTY )       \
365     do {                               \
366         if ( PROPERTY == NULL )        \
367             return RC ( rcRuntime, rcData, rcAccessing, rcParam, rcNull ); \
368         * PROPERTY = 0;             \
369         if ( self == NULL )            \
370             return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );  \
371         * PROPERTY = self -> PROPERTY; \
372         return 0;                      \
373     } while ( 0 )
374 
375 #define TEST_GET( PROPERTY )       \
376     do {                               \
377         if ( PROPERTY == NULL )        \
378             return RC ( rcRuntime, rcData, rcAccessing, rcParam, rcNull ); \
379         * PROPERTY = NULL;             \
380         if ( self == NULL )            \
381             return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );  \
382         * PROPERTY = self -> PROPERTY; \
383         return 0;                      \
384     } while ( 0 )
385 
KDiagnoseTestName(const KDiagnoseTest * self,const char ** name)386 LIB_EXPORT rc_t CC KDiagnoseTestName ( const KDiagnoseTest * self,
387                                        const char ** name )
388 {   TEST_GET ( name ); }
389 
KDiagnoseTestCode(const KDiagnoseTest * self,uint64_t * code)390 LIB_EXPORT rc_t CC KDiagnoseTestCode ( const KDiagnoseTest * self,
391                                        uint64_t * code )
392 {   TEST_GET_INT ( code ); }
393 
KDiagnoseTestLevel(const KDiagnoseTest * self,uint32_t * level)394 LIB_EXPORT rc_t CC KDiagnoseTestLevel ( const KDiagnoseTest * self,
395                                         uint32_t * level )
396 {   TEST_GET_INT ( level ); }
397 
KDiagnoseTestNumber(const KDiagnoseTest * self,const char ** number)398 LIB_EXPORT rc_t CC KDiagnoseTestNumber ( const KDiagnoseTest * self,
399                                          const char ** number )
400 {   TEST_GET ( number ); }
401 
KDiagnoseTestMessage(const KDiagnoseTest * self,const char ** message)402 LIB_EXPORT rc_t CC KDiagnoseTestMessage ( const KDiagnoseTest * self,
403                                           const char ** message )
404 {   TEST_GET ( message ); }
405 
KDiagnoseTestState(const KDiagnoseTest * self,EKDiagTestState * state)406 LIB_EXPORT rc_t CC KDiagnoseTestState ( const KDiagnoseTest * self,
407                                         EKDiagTestState * state )
408 {   TEST_GET_INT ( state ); }
409 
410 
411 struct KDiagnoseError {
412     atomic32_t refcount;
413 
414     char * message;
415 };
416 
417 static const char DIAGNOSERROR_CLSNAME [] = "KDiagnoseError";
418 
419 LIB_EXPORT
KDiagnoseErrorAddRef(const KDiagnoseError * self)420 rc_t CC KDiagnoseErrorAddRef ( const KDiagnoseError * self )
421 {
422     if ( self != NULL )
423         switch ( KRefcountAdd ( & self -> refcount, DIAGNOSERROR_CLSNAME ) ) {
424             case krefLimit:
425                 return RC ( rcRuntime,
426                             rcData, rcAttaching, rcRange, rcExcessive );
427         }
428 
429     return 0;
430 }
431 
KDiagnoseErrorWhack(KDiagnoseError * self)432 static void KDiagnoseErrorWhack ( KDiagnoseError * self ) {
433     assert ( self );
434     free ( self -> message );
435     memset ( self, 0, sizeof * self );
436     free ( self );
437 }
438 
439 LIB_EXPORT
KDiagnoseErrorRelease(const KDiagnoseError * cself)440 rc_t CC KDiagnoseErrorRelease ( const KDiagnoseError * cself )
441 {
442     rc_t rc = 0;
443 
444     KDiagnoseError * self = ( KDiagnoseError * ) cself;
445 
446     if ( self != NULL )
447         switch ( KRefcountDrop ( & self -> refcount,
448                                  DIAGNOSERROR_CLSNAME ) )
449         {
450             case krefWhack:
451                 KDiagnoseErrorWhack ( self );
452                 break;
453             case krefNegative:
454                 return RC ( rcRuntime,
455                             rcData, rcReleasing, rcRange, rcExcessive );
456         }
457 
458     return rc;
459 }
460 
KDiagnoseErrorGetMsg(const KDiagnoseError * self,const char ** message)461 LIB_EXPORT rc_t CC KDiagnoseErrorGetMsg ( const KDiagnoseError * self,
462                                           const char ** message )
463 {
464     if ( message == NULL )
465         return RC ( rcRuntime, rcData, rcAccessing, rcParam, rcNull );
466 
467     * message = NULL;
468 
469     if ( self == NULL )
470         return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );
471 
472     * message = self -> message;
473     return 0;
474 }
475 
KDiagnoseErrorMake(const KDiagnoseError ** self,const char * message)476 static rc_t KDiagnoseErrorMake ( const KDiagnoseError ** self,
477                                  const char * message )
478 {
479     KDiagnoseError * p = NULL;
480 
481     assert ( self );
482 
483     * self = NULL;
484 
485     p = calloc ( 1, sizeof * p );
486     if ( p == NULL )
487         return RC ( rcRuntime, rcData, rcAllocating, rcMemory, rcExhausted );
488 
489     p -> message = string_dup_measure ( message, NULL );
490     if ( p == NULL ) {
491         KDiagnoseErrorWhack ( p );
492         return RC ( rcRuntime, rcData, rcAllocating, rcMemory, rcExhausted );
493     }
494 
495     KRefcountInit ( & p -> refcount, 1, DIAGNOSERROR_CLSNAME, "init", "" );
496 
497     * self = p;
498 
499     return 0;
500 }
501 
502 static void ( CC * CALL_BACK )
503     ( EKDiagTestState state, const KDiagnoseTest * test, void * data );
504 static void * CALL_BACK_DATA;
505 
KDiagnoseTestHandlerSet(KDiagnose * self,void (CC * callback)(EKDiagTestState state,const KDiagnoseTest * test,void * data),void * data)506 LIB_EXPORT rc_t CC KDiagnoseTestHandlerSet ( KDiagnose * self,
507     void ( CC * callback )
508         ( EKDiagTestState state, const KDiagnoseTest * test, void * data ),
509     void * data
510 )
511 {
512     CALL_BACK = callback;
513     CALL_BACK_DATA = data;
514     return 0;
515 }
516 
517 LIB_EXPORT
KDiagnoseSetVerbosity(KDiagnose * self,int verbosity)518 rc_t CC KDiagnoseSetVerbosity ( KDiagnose * self, int verbosity )
519 {
520     if ( self == NULL )
521         return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );
522 
523     self -> verbosity = verbosity - 1;
524 
525     return 0;
526 }
527 
KDiagnoseGetErrorCount(const KDiagnose * self,uint32_t * count)528 LIB_EXPORT rc_t CC KDiagnoseGetErrorCount ( const KDiagnose * self,
529                                             uint32_t * count )
530 {
531     if ( count == NULL )
532         return RC ( rcRuntime, rcData, rcAccessing, rcParam, rcNull );
533 
534     * count = 0;
535 
536     if ( self == NULL )
537         return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );
538 
539     * count = VectorLength ( & self -> errors );
540     return 0;
541 }
542 
KDiagnoseGetError(const KDiagnose * self,uint32_t idx,const KDiagnoseError ** error)543 LIB_EXPORT rc_t CC KDiagnoseGetError ( const KDiagnose * self, uint32_t idx,
544                                        const KDiagnoseError ** error )
545 {
546     rc_t rc = 0;
547 
548     const KDiagnoseError * e = NULL;
549 
550     if ( error == NULL )
551         return RC ( rcRuntime, rcData, rcAccessing, rcParam, rcNull );
552 
553     * error = NULL;
554 
555     if ( self == NULL )
556         return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );
557 
558     if ( idx >= VectorLength ( & self -> errors ) )
559         return RC ( rcRuntime, rcData, rcAccessing, rcParam, rcInvalid );
560 
561     e = VectorGet ( & self -> errors, idx );
562 
563     rc = KDiagnoseErrorAddRef ( e );
564     if ( rc == 0 )
565         * error = e;
566 
567     return rc;
568 }
569 
570 typedef struct {
571     int n [ 7 ];
572     int level;
573     bool ended;
574     bool started;           /*  TestStart did not terminale string by EOL */
575     bool failedWhileSilent;
576 
577     int verbosity; /* -3    none  ( KVERBOSITY_NONE  )
578                       -2    error ( KVERBOSITY_ERROR )
579                       -1    info  ( KVERBOSITY_INFO  )
580                        0... last printed index of n [] */
581 
582     int total;
583     int failures;
584     int warnings;
585     KDiagnoseTest * crnt;
586     KDiagnoseTest * root;
587     Vector * tests;
588     Vector * errors;
589 
590     KDataBuffer msg;
591 
592     const KConfig * kfg;
593     const KNSManager * kmgr;
594     const VFSManager * vmgr;
595     VResolver * resolver;
596     VResolverEnableState cacheState;
597     KDirectory * dir;
598 
599     bool ascpChecked;
600     const char * ascp;
601     const char * asperaKey;
602 
603     KDiagnose * dad;
604 } STest;
605 
STestInit(STest * self,KDiagnose * test)606 static void STestInit ( STest * self, KDiagnose * test )
607 {
608     rc_t rc = 0;
609 
610     assert ( self && test );
611 
612     memset ( self, 0, sizeof * self );
613 
614     self -> dad = test;
615 
616     self -> level = -1;
617 
618     self -> kfg = test -> kfg;
619     self -> kmgr = test -> kmgr;
620     self -> vmgr = test -> vmgr;
621     self -> errors = & test -> errors;
622     self -> tests = & test -> tests;
623 
624     self -> verbosity = test -> verbosity;
625     if ( self -> verbosity > 0 )
626         -- self -> verbosity;
627     else if ( self -> verbosity == 0 ) /* max */
628         self -> verbosity = sizeof self -> n / sizeof self -> n [ 0 ] - 1;
629 
630     rc = KDirectoryNativeDir ( & self -> dir );
631     if ( rc != 0 )
632         LogOut ( KVERBOSITY_ERROR, 0, "CANNOT KDirectoryNativeDir: %R\n", rc );
633 
634     rc = VFSManagerGetResolver ( self -> vmgr, & self -> resolver);
635     if ( rc != 0 )
636         LogOut ( KVERBOSITY_ERROR, 0, "CANNOT GetResolver: %R\n", rc );
637     else
638         self -> cacheState = VResolverCacheEnable ( self -> resolver,
639                                                     vrAlwaysEnable );
640 }
641 
STestReport(const STest * self)642 static void STestReport ( const STest * self ) {
643     assert ( self && self -> dad );
644 
645     if ( self -> level < KVERBOSITY_INFO )
646         return;
647 
648     if ( self -> n [ 0 ] == 0 || self -> n [ 1 ] != 0 ||
649             self -> level != 0 )
650     {   LogOut ( KVERBOSITY_INFO, 0, "= TEST WAS NOT COMPLETED\n" ); }
651 
652     LogOut ( KVERBOSITY_INFO, 0, "= %d (%d) tests performed, %d failed\n",
653                 self -> n [ 0 ], self -> total, self -> failures );
654 
655     if ( self -> failures > 0 ) {
656         uint32_t i = 0;
657         LogOut ( KVERBOSITY_INFO, 0, "Errors:\n" );
658         for ( i = 0; i < VectorLength ( self -> errors ); ++ i ) {
659             const KDiagnoseError * e = VectorGet ( self -> errors, i );
660             assert ( e );
661             LogOut ( KVERBOSITY_INFO, 0, " %d: %s\n", i + 1, e -> message );
662         }
663     }
664 
665     LogOut ( KVERBOSITY_INFO, 0, "\n\nANALYSIS:\n\n" );
666 
667     if ( self -> failures == 0 )
668         LogOut ( KVERBOSITY_INFO, 0, "No errors detected.\n" );
669     else {
670         const Report * report = & self -> dad -> report;
671 
672         if ( report -> firewall )
673             LogOut ( KVERBOSITY_INFO, 0,
674  "Most likely access to NCBI is blocked by your firewall.\n"
675  "Please look over the information about firewalls at\n"
676  "https://github.com/ncbi/sra-tools/wiki/Firewall-and-Routing-Information\n"
677  "and make sure that your IT people are aware of the requirements\n"
678  "for accessing SRA data at NCBI.\n\n" );
679 
680         if ( report -> blocked ) {
681             const Abuse * test = & report -> abuse;
682             LogOut ( KVERBOSITY_INFO, 0,
683        "Your access to the NCBI website at %s has been\n"
684        "temporarily blocked due to a possible misuse/abuse situation\n"
685        "involving your site. This is not an indication of a security issue\n"
686        "such as a virus or attack.\n"
687        "To restore access and understand how to better interact with our site\n"
688        "to avoid this in the future, please have your system administrator\n"
689        "send an email with subject \"NCBI Web site BLOCKED: %S\"\n"
690        "to info@ncbi.nlm.nih.gov with the following information:\n"
691        "Error=blocked for possible abuse\n"
692        "Server=%s\n"
693        "Client=%S\n"
694        "Time=%S\n\n"
695                 , test -> server
696                 , & test -> ip
697                 , test -> server
698                 , & test -> ip
699                 , & test -> date );
700         }
701     }
702 
703     LogOut ( KVERBOSITY_INFO, 0,
704         "For more infotrmation mail the complete output\n"
705         "and your questions to sra-tools@ncbi.nlm.nih.gov .\n" );
706 }
707 
STestFini(STest * self)708 static void STestFini ( STest * self ) {
709     rc_t rc = 0;
710 
711     assert ( self );
712 
713     if ( self -> level >= KVERBOSITY_INFO )
714         STestReport ( self );
715 
716     VResolverCacheEnable ( self -> resolver, self -> cacheState );
717 
718     RELEASE ( KDirectory, self -> dir );
719     RELEASE ( VResolver, self -> resolver );
720 
721     KDataBufferWhack ( & self -> msg );
722 
723     free ( ( void * ) self -> ascp );
724     free ( ( void * ) self -> asperaKey );
725 
726     memset ( self, 0, sizeof * self );
727 }
728 
KDiagnoseCheckState(KDiagnose * self)729 static rc_t KDiagnoseCheckState(KDiagnose * self) {
730     rc_t rc = 0;
731 
732     assert ( self );
733 
734     if ( self -> quitting && ( rc = self -> quitting () ) != 0 )
735         if ( rc == SILENT_RC ( rcExe,
736                                rcProcess, rcExecuting, rcProcess, rcCanceled ) )
737         {
738             LogOut ( KVERBOSITY_INFO, 0,
739                      "= Signal caught: CANCELED DIAGNOSTICS\n" );
740             self -> state = eCanceled;
741             if ( CALL_BACK )
742                 CALL_BACK ( eKDTS_Canceled, NULL, CALL_BACK_DATA );
743         }
744 
745     while ( self -> state != eRunning ) {
746         rc_t r2;
747 
748         rc = KLockAcquire ( self -> lock );
749         if ( rc == 0 )
750             switch ( self -> state ) {
751                 case eRunning:
752                     break;
753 
754                 case ePaused:
755                     LogOut ( KVERBOSITY_INFO, 0, "= PAUSED DIAGNOSTICS\n" );
756                     if ( CALL_BACK )
757                         CALL_BACK ( eKDTS_Paused, NULL, CALL_BACK_DATA );
758 
759                     rc = KConditionWait ( self -> condition, self -> lock );
760                     if ( rc != 0 )
761                         LogOut ( KVERBOSITY_INFO, 0,
762                                  "= FAILURE DURING PAUSE: %R\n" );
763                     else if ( self -> state == eRunning ) {
764                         LogOut ( KVERBOSITY_INFO, 0,
765                                  "= RESUMED DIAGNOSTICS\n" );
766                         if ( CALL_BACK )
767                             CALL_BACK ( eKDTS_Resumed, NULL, CALL_BACK_DATA );
768                     }
769 
770                     break;
771 
772                 case eCanceled:
773                     LogOut ( KVERBOSITY_INFO, 0, "= CANCELED DIAGNOSTICS\n" );
774                     if ( rc == 0 )
775                         rc = RC ( rcRuntime, rcProcess, rcExecuting,
776                                   rcProcess, rcCanceled );
777                     if ( CALL_BACK )
778                         CALL_BACK ( eKDTS_Canceled, NULL, CALL_BACK_DATA );
779 
780                     break;
781             }
782 
783         r2 = KLockUnlock ( self -> lock );
784         if ( rc == 0 && r2 != 0 )
785             rc = r2;
786 
787         if ( self -> state == eCanceled )
788             break;
789     }
790 
791     return rc;
792 }
793 
STestVStart(STest * self,bool checking,uint64_t code,const char * fmt,va_list args)794 static rc_t STestVStart ( STest * self, bool checking, uint64_t code,
795     const char * fmt, va_list args  )
796 {
797     KDiagnoseTest * test = NULL;
798     rc_t rc = 0;
799     int i = 0;
800     char b [ 512 ] = "";
801     bool next = false;
802     KDataBuffer bf;
803 
804     memset ( & bf, 0, sizeof bf );
805     rc = string_vprintf ( b, sizeof b, NULL, fmt, args );
806     if ( rc != 0 ) {
807         LogOut ( KVERBOSITY_ERROR, 0, "CANNOT PRINT: %R\n", rc );
808         return rc;
809     }
810 
811     assert ( self );
812 
813     test = calloc ( 1, sizeof * test );
814     if ( test == NULL )
815         return RC ( rcRuntime, rcData, rcAllocating, rcMemory, rcExhausted );
816     test -> code = code;
817     test -> name = strdup (b); /*TODO*/
818     if ( test -> name == NULL ) {
819         free ( test );
820         return RC ( rcRuntime, rcData, rcAllocating, rcMemory, rcExhausted );
821     }
822 
823     if ( self -> ended ) {
824         next = true;
825         self -> ended = false;
826     }
827     else
828         ++ self -> level;
829 
830     test -> level = self -> level;
831     test -> state = eKDTS_Started;
832 
833     if ( self -> crnt != NULL ) {
834         if ( next ) {
835             self -> crnt -> next = test;
836             test -> parent = self -> crnt -> parent;
837         }
838         else {
839             if ( self -> crnt -> firstChild == NULL )
840                 self -> crnt -> firstChild = test;
841             else {
842                 KDiagnoseTest * child = self -> crnt -> crntChild;
843                 assert ( child );
844                 child -> nextChild = test;
845             }
846             self -> crnt -> crntChild = test;
847             test -> parent = self -> crnt;
848         }
849     }
850     else
851         self -> root = test;
852     self -> crnt = test;
853     rc = VectorAppend ( self -> tests, NULL, test );
854     if ( rc != 0 )
855         return rc;
856 
857     assert ( self -> level >= 0 );
858     assert ( self -> level < sizeof self -> n / sizeof self -> n [ 0 ] );
859 
860     ++ self -> n [ self -> level ];
861 
862     if ( self -> msg . elem_count > 0 ) {
863         assert ( self -> msg . base );
864         ( ( char * ) self -> msg . base)  [ 0 ] = '\0';
865         self -> msg . elem_count = 0;
866     }
867     rc = KDataBufferPrintf ( & self -> msg,  "< %d", self -> n [ 0 ] );
868 #ifdef DEPURAR
869 const char*c=self->msg.base;
870 #endif
871     if ( rc != 0 )
872         LogOut ( KVERBOSITY_ERROR, 0, "CANNOT PRINT: %R\n", rc );
873     else {
874         size_t size = 0;
875         for ( i = 1; rc == 0 && i <= self -> level; ++ i ) {
876             rc = KDataBufferPrintf ( & self -> msg, ".%d", self -> n [ i ] );
877             if ( rc != 0 )
878                 LogOut ( KVERBOSITY_ERROR, 0, "CANNOT PRINT: %R\n", rc );
879         }
880         assert ( self -> msg . base && self -> msg . elem_count > 2 );
881         test -> number = string_dup_measure ( ( char * ) self -> msg . base + 2,
882                                               NULL );
883         if ( test -> number == NULL )
884             return RC ( rcRuntime,
885                         rcData, rcAllocating, rcMemory, rcExhausted );
886 
887         test -> numberNode = string_dup_measure ( test -> number, & size );
888         if ( test -> numberNode == NULL )
889             return RC ( rcRuntime,
890                         rcData, rcAllocating, rcMemory, rcExhausted );
891         else {
892             while ( true ) {
893                 char * c = string_chr ( test -> numberNode, size, '.' );
894                 if ( c == NULL )
895                     break;
896                 else
897                     * c = '/';
898             }
899         }
900 
901     }
902     if ( rc == 0 )
903     {
904         rc = KDataBufferPrintf ( & self -> msg, " %s ", b );
905         if ( rc != 0 )
906             LogOut ( KVERBOSITY_ERROR, 0, "CANNOT PRINT: %R\n", rc );
907     }
908 
909     if ( self -> level <= self -> verbosity ) {
910         rc = LogOut ( self -> level, 0, "> %d", self -> n [ 0 ] );
911         for ( i = 1; i <= self -> level; ++ i )
912             rc = LogOut ( self -> level, 0, ".%d", self -> n [ i ] );
913 
914         rc = LogOut ( self -> level, 0, " %s%s%s",
915                       checking ? "Checking " : "", b, checking ? "..." : " " );
916         if ( checking ) {
917             if ( self -> level < self -> verbosity ) {
918                 rc = LogOut ( self -> level, 0, "\n" );
919                 self -> started = false;
920             }
921             else {
922                 rc = LogOut ( self -> level, 0, " " );
923                 self -> started = true;
924             }
925         }
926     }
927 
928     if ( CALL_BACK )
929          CALL_BACK ( eKDTS_Started, test, CALL_BACK_DATA );
930 
931     return rc;
932 }
933 
934 typedef enum {
935     eFAIL,
936     eOK,
937     eMSG,
938     eEndFAIL,
939     eEndOK,
940     eDONE, /* never used */
941     eCANCELED,
942     eWarning
943 } EOK;
944 
STestVEnd(STest * self,EOK ok,const char * fmt,va_list args)945 static rc_t STestVEnd ( STest * self, EOK ok,
946                         const char * fmt, va_list args )
947 {
948     rc_t rc = 0;
949 #ifdef DEPURAR
950 switch(ok){
951 case eFAIL:
952 rc=0;
953 break;
954 case eOK:
955 rc=1;
956 break;
957 case eMSG:
958 rc=2;
959 break;
960 case eEndFAIL:
961 rc=3;
962 break;
963 case eEndOK:
964 rc=4;
965 break;
966 case eDONE:
967 rc=5; /* never used */
968 break;
969 }
970 rc=0;
971 #endif
972     bool failedWhileSilent = self -> failedWhileSilent;
973     bool print = false;
974     char b [ 1024 ] = "";
975     size_t num_writ = 0;
976     size_t num_warn = 0;
977 
978     assert ( self );
979 
980     if ( ok != eMSG ) {
981         if ( self -> ended ) {
982             self -> crnt = self -> crnt -> parent;
983             self -> n [ self -> level -- ] = 0;
984         }
985         else {
986             self -> ended = true;
987             ++ self -> total;
988             if ( ok == eFAIL || ok == eEndFAIL )
989                 ++ self -> failures;
990             else if ( ok == eWarning )
991                 ++ self -> warnings;
992         }
993     }
994 
995     assert ( self -> level >= 0 );
996 #ifdef DEPURAR
997 const char*c=self->msg.base;
998 #endif
999     if ( ok == eWarning )
1000         rc = string_printf ( b, sizeof b, & num_warn, "WARNING: " );
1001     else if ( ok == eEndFAIL )
1002         rc = string_printf ( b, sizeof b, & num_warn, "FAILURE: " );
1003     rc = string_vprintf ( b + num_warn, sizeof b - num_warn,
1004                           & num_writ, fmt, args );
1005     num_writ += num_warn;
1006     if ( rc != 0 ) {
1007         LogOut ( KVERBOSITY_ERROR, 0, "CANNOT PRINT: %R", rc );
1008         return rc;
1009     }
1010 
1011     if ( self -> crnt -> message == NULL )
1012         self -> crnt -> message = string_dup_measure ( b, NULL );
1013     else {
1014         size_t m = string_measure ( self -> crnt -> message, NULL);
1015         size_t s = m + num_writ + 1;
1016         char * tmp = realloc ( self -> crnt -> message, s );
1017         if ( tmp == NULL )
1018             return RC ( rcRuntime,
1019                         rcData, rcAllocating, rcMemory, rcExhausted );
1020         self -> crnt -> message = tmp;
1021         rc = string_printf ( self -> crnt -> message + m, s, NULL, b );
1022         assert ( rc == 0 );
1023     }
1024     if ( ok == eOK ) {
1025         free ( self -> crnt -> message );
1026         self -> crnt -> message = string_dup_measure ( "OK", NULL );
1027     }
1028 
1029     if ( ok == eEndFAIL || ok == eMSG ) {
1030         rc = KDataBufferPrintf ( & self -> msg, b );
1031         if ( rc != 0 )
1032             LogOut ( KVERBOSITY_ERROR, 0, "CANNOT PRINT: %R", rc );
1033         else if ( ok == eEndFAIL ) {
1034             const KDiagnoseError * e = NULL;
1035             rc = KDiagnoseErrorMake ( & e, self -> msg . base );
1036             if ( rc != 0 )
1037                 return rc;
1038             rc = VectorAppend ( self -> errors, NULL, e );
1039             if ( rc != 0 ) {
1040                 LogOut ( KVERBOSITY_ERROR, 0, "CANNOT rcRuntime: %R", rc );
1041                 return rc;
1042             }
1043         }
1044     }
1045 
1046     if ( self -> level > self -> verbosity ) {
1047         if ( ok == eEndFAIL || ok == eMSG ) {
1048             if ( ok == eEndFAIL ) {
1049                 rc = KDataBufferPrintf ( & self -> msg, "\n" );
1050                 if ( self -> started ) {
1051                     LogOut ( KVERBOSITY_ERROR, 0,  "\n" );
1052                     self -> failedWhileSilent = true;
1053                     self -> started = false;
1054                 }
1055                 if ( self -> level >= KVERBOSITY_ERROR )
1056                     LogOut ( KVERBOSITY_ERROR, 0, self -> msg . base );
1057                 assert ( self -> msg . base );
1058                 ( ( char * ) self -> msg . base)  [ 0 ] = '\0';
1059                 self -> msg . elem_count = 0;
1060             }
1061         }
1062     }
1063     else {
1064         print = self -> level < self -> verbosity || failedWhileSilent;
1065         if ( ok == eFAIL || ok == eOK || ok == eDONE || ok == eCANCELED) {
1066             if ( print ) {
1067                 int i = 0;
1068                 rc = LogOut ( self -> level, 0, "< %d", self -> n [ 0 ] );
1069                 for ( i = 1; i <= self -> level; ++ i )
1070                     rc = LogOut ( self -> level, 0, ".%d", self -> n [ i ] );
1071                 rc = LogOut ( self -> level, 0, " " );
1072             }
1073         }
1074         if ( print ||
1075                 ( self -> level == self -> verbosity &&
1076                   ok != eFAIL && ok != eOK ) )
1077         {
1078             rc = LogOut ( self -> level, 0, b );
1079         }
1080 
1081         if ( print )
1082             switch ( ok ) {
1083                 case eFAIL: rc = LogOut ( self -> level, 0, ": FAILURE\n" );
1084                             break;
1085                 case eOK  : rc = LogOut ( self -> level, 0, ": OK\n"      );
1086                             break;
1087                 case eCANCELED:
1088                 case eEndFAIL:
1089                 case eEndOK :
1090                 case eWarning:
1091                 case eDONE: rc = LogOut ( self -> level, 0, "\n"      );
1092                             break;
1093                 default   : break;
1094             }
1095         else if ( self -> level == self -> verbosity )
1096             switch ( ok ) {
1097                 case eFAIL: rc = LogOut ( self -> level, 0, "FAILURE\n" );
1098                             break;
1099                 case eOK  : rc = LogOut ( self -> level, 0, "OK\n"      );
1100                             break;
1101                 case eEndFAIL:
1102                 case eEndOK :
1103                 case eWarning:
1104                 case eDONE: rc = LogOut ( self -> level, 0, "\n"      );
1105                             break;
1106                 default   : break;
1107             }
1108 
1109         self -> failedWhileSilent = false;
1110     }
1111 
1112     if (  ok != eMSG ) {
1113         EKDiagTestState state = eKDTS_Succeed;
1114         switch ( ok ) {
1115             case eEndOK   : state = eKDTS_Succeed ; break;
1116             case eOK      : state = eKDTS_Succeed ; break;
1117             case eFAIL    : state = eKDTS_Failed  ; break;
1118             case eCANCELED: state = eKDTS_Canceled; break;
1119             case eWarning : state = eKDTS_Warning ; break;
1120             default       : state = eKDTS_Failed  ; break;
1121         }
1122         self -> crnt -> state = state;
1123         if ( CALL_BACK )
1124             CALL_BACK ( state, self -> crnt, CALL_BACK_DATA );
1125     }
1126 
1127     if ( rc == 0 ) {
1128         assert ( self -> dad );
1129         rc = KDiagnoseCheckState ( self -> dad );
1130     }
1131 
1132     return rc;
1133 }
1134 
_RcCanceled(rc_t rc)1135 static bool _RcCanceled ( rc_t rc ) {
1136     return rc == SILENT_RC ( rcExe,
1137                              rcProcess, rcExecuting, rcProcess, rcCanceled )
1138         || rc == SILENT_RC ( rcRuntime,
1139                              rcProcess, rcExecuting, rcProcess, rcCanceled );
1140 }
STestCanceled(const STest * self,rc_t rc)1141 static bool STestCanceled ( const STest * self, rc_t rc ) {
1142     assert ( self && self -> dad );
1143     return _RcCanceled ( rc ) && self -> dad -> state == eCanceled;
1144 }
1145 
STestFailure(const STest * self)1146 static rc_t STestFailure ( const STest * self ) {
1147     rc_t failure = 0;
1148 
1149     rc_t rc = RC ( rcRuntime, rcProcess, rcExecuting, rcProcess, rcCanceled );
1150     const KConfigNode * node = NULL;
1151 
1152     assert ( self && self -> crnt && self -> crnt -> numberNode );
1153 
1154     rc = KConfigOpenNodeRead ( self -> kfg, & node,
1155         "tools/test-sra/diagnose/%s", self -> crnt -> numberNode );
1156     if ( rc == 0 ) {
1157         uint64_t result = 0;
1158         rc = KConfigNodeReadU64 ( node, & result );
1159         if ( rc == 0 ) {
1160             failure = ( rc_t ) result;
1161 // if ( _RcCanceled ( failure ) && CALL_BACK ) CALL_BACK ( eKDTS_Canceled,NULL);
1162         }
1163 
1164         KConfigNodeRelease ( node );
1165         node = NULL;
1166     }
1167 
1168     return failure;
1169 }
1170 
STestEndOr(STest * self,rc_t * failure,EOK ok,const char * fmt,...)1171 static rc_t STestEndOr ( STest * self, rc_t * failure,
1172                          EOK ok, const char * fmt, ...  )
1173 {
1174     rc_t rc = 0;
1175     bool canceled = false;
1176 
1177     va_list args;
1178     va_start ( args, fmt );
1179 
1180     assert ( failure );
1181     * failure = 0;
1182 
1183     rc = STestVEnd ( self, ok, fmt, args );
1184     canceled = STestCanceled ( self, rc );
1185 
1186     va_end ( args );
1187 
1188     if ( LOGGER == OutMsg ) {
1189         assert ( rc == 0 || canceled );
1190     }
1191 
1192     if ( canceled )
1193         * failure = rc;
1194     else if ( rc == 0 )
1195         * failure = STestFailure ( self );
1196 
1197     return rc;
1198 }
1199 
STestEnd(STest * self,EOK ok,const char * fmt,...)1200 static rc_t STestEnd ( STest * self, EOK ok, const char * fmt, ...  ) {
1201     rc_t rc = 0;
1202 
1203     va_list args;
1204     va_start ( args, fmt );
1205 
1206     rc = STestVEnd ( self, ok, fmt, args );
1207 
1208     va_end ( args );
1209 
1210     if ( LOGGER == OutMsg ) {
1211         assert ( rc == 0 || STestCanceled ( self, rc ) );
1212     }
1213 
1214     return rc;
1215 }
1216 
STestStart(STest * self,bool checking,uint64_t code,const char * fmt,...)1217 static rc_t STestStart ( STest * self, bool checking, uint64_t code,
1218                          const char * fmt, ...  )
1219 {
1220     rc_t rc = 0;
1221 
1222     va_list args;
1223     va_start ( args, fmt );
1224 
1225     rc = STestVStart ( self, checking, code, fmt, args );
1226 
1227     va_end ( args );
1228 
1229     if ( LOGGER == OutMsg ) {
1230         assert ( rc == 0 );
1231     }
1232 
1233     return rc;
1234 }
1235 
STestFail(STest * self,rc_t failure,uint64_t code,const char * start,...)1236 static rc_t STestFail ( STest * self, rc_t failure, uint64_t code,
1237                         const char * start,  ...  )
1238 {
1239     va_list args;
1240 
1241     rc_t rc = 0;
1242 
1243     rc_t r2 = 0;
1244 
1245     va_start ( args, start );
1246 
1247     rc = STestVStart ( self, false, code, start, args );
1248 
1249     r2 = STestEnd ( self, eEndFAIL, "%R", failure );
1250     if ( rc == 0 && r2 != 0 )
1251         rc = r2;
1252 
1253     va_end ( args );
1254 
1255     return rc;
1256 }
1257 
1258 typedef struct {
1259     VPath * vpath;
1260     const String * acc;
1261 } Data;
1262 
DataInit(Data * self,const VFSManager * mgr,const char * path)1263 static rc_t DataInit ( Data * self, const VFSManager * mgr,
1264                        const char * path )
1265 {
1266     rc_t rc = 0;
1267 
1268     assert ( self );
1269 
1270     memset ( self, 0, sizeof * self );
1271 
1272     rc = VFSManagerMakePath ( mgr, & self -> vpath, path );
1273     if ( rc != 0 )
1274         LogOut ( KVERBOSITY_ERROR, 0,
1275                  "VFSManagerMakePath(%s) = %R\n", path, rc );
1276     else {
1277         VPath * vacc = NULL;
1278         rc = VFSManagerExtractAccessionOrOID ( mgr, & vacc, self -> vpath );
1279         if ( rc != 0 )
1280             rc = 0;
1281         else {
1282             String acc;
1283             rc = VPathGetPath ( vacc, & acc );
1284             if ( rc == 0 )
1285                 StringCopy ( & self -> acc, & acc );
1286             else
1287                 LogOut ( KVERBOSITY_ERROR, 0, "Cannot VPathGetPath"
1288                            "(VFSManagerExtractAccessionOrOID(%R))\n", rc );
1289             RELEASE ( VPath, vacc );
1290         }
1291     }
1292 
1293     return rc;
1294 }
1295 
DataFini(Data * self)1296 static rc_t DataFini ( Data * self ) {
1297     rc_t rc = 0;
1298 
1299     assert ( self );
1300 
1301     free ( ( void * ) self -> acc );
1302 
1303     rc = VPathRelease ( self -> vpath );
1304 
1305     memset ( self, 0, sizeof * self );
1306 
1307     return rc;
1308 }
1309 
1310 static const ver_t HTTP_VERSION = 0x01010000;
1311 
STestCheckFile(STest * self,const String * path,uint64_t * sz,rc_t * rc_read)1312 static rc_t STestCheckFile ( STest * self, const String * path,
1313                              uint64_t * sz, rc_t * rc_read )
1314 {
1315     rc_t rc = 0;
1316 
1317     const KFile * file = NULL;
1318 
1319     assert ( self && sz && rc_read );
1320 
1321     STestStart ( self, false, 0,
1322                  "KFile = KNSManagerMakeReliableHttpFile(%S):", path );
1323 
1324     rc = KNSManagerMakeReliableHttpFile ( self -> kmgr, & file, NULL,
1325                                           HTTP_VERSION, true, false, false, "%S", path );
1326     if ( rc != 0 )
1327         STestEnd ( self, eEndFAIL, "%R", rc );
1328     else {
1329         if ( rc == 0 )
1330             STestEndOr ( self, & rc, eEndOK, "OK" );
1331         if ( rc != 0 ) {
1332             if ( _RcCanceled ( rc ) )
1333                 STestEnd ( self, eCANCELED, "CANCELED" );
1334             else
1335                 STestEnd ( self, eEndFAIL, "%R", rc );
1336         }
1337         else {
1338             STestStart ( self, false, 0, "KFileSize(KFile(%S)) =", path );
1339             rc = KFileSize ( file, sz );
1340             if ( rc == 0 )
1341                 STestEndOr ( self, & rc, eEndOK, "%lu: OK", * sz );
1342             if ( rc != 0 ) {
1343                 if ( _RcCanceled ( rc ) )
1344                     STestEnd ( self, eCANCELED, "CANCELED" );
1345                 else
1346                     STestEnd ( self, eEndFAIL, "%R", rc );
1347             }
1348         }
1349     }
1350 
1351     if ( rc == 0 ) {
1352         char buffer [ 304 ] = "";
1353         uint64_t pos = 0;
1354         size_t bsize = sizeof buffer;
1355         size_t num_read = 0;
1356         if ( * sz < 256 ) {
1357             pos = 0;
1358             bsize = ( size_t ) * sz;
1359         }
1360         else
1361             pos = ( * sz - sizeof buffer ) / 2;
1362         STestStart ( self, false, 0,
1363                     "KFileRead(%S,%lu,%zu):", path, pos, bsize );
1364         * rc_read = KFileRead ( file, pos, buffer, bsize, & num_read );
1365         if ( * rc_read == 0 )
1366             STestEndOr ( self, rc_read, eEndOK, "OK" );
1367         if ( * rc_read != 0 ) {
1368             if ( _RcCanceled ( * rc_read ) )
1369                 STestEnd ( self, eCANCELED, "CANCELED" );
1370             else
1371                 STestEnd ( self, eEndFAIL, "%R", * rc_read );
1372         }
1373     }
1374 
1375     KFileRelease ( file );
1376     file = NULL;
1377 
1378     return rc;
1379 }
1380 
1381 static
STestCheckRanges(STest * self,const Data * data,uint64_t sz)1382 rc_t STestCheckRanges ( STest * self, const Data * data, uint64_t sz )
1383 {
1384     rc_t rc = 0;
1385     uint64_t pos = 0;
1386     size_t bytes = 4096;
1387     uint64_t ebytes = bytes;
1388     bool https = false;
1389     char buffer [ 2048 ] = "";
1390     size_t num_read = 0;
1391     KClientHttp * http = NULL;
1392     KHttpRequest * req = NULL;
1393     KHttpResult * rslt = NULL;
1394     String host;
1395     String scheme;
1396     assert ( self && data );
1397     STestStart ( self, true, 0, "Support of Range requests" );
1398     rc = VPathGetHost ( data -> vpath, & host );
1399     if ( rc != 0 )
1400         STestFail ( self, rc, 0, "VPathGetHost" );
1401     if ( rc == 0 )
1402         rc = VPathGetScheme ( data -> vpath, & scheme );
1403     if ( rc != 0 )
1404         STestFail ( self, rc, 0, "VPathGetScheme" );
1405     if ( rc == 0 ) {
1406         String sHttps;
1407         String sHttp;
1408         CONST_STRING ( & sHttp, "http" );
1409         CONST_STRING ( & sHttps, "https" );
1410         if ( StringEqual ( & scheme, & sHttps ) )
1411             https = true;
1412         else if ( StringEqual ( & scheme, & sHttp ) )
1413             https = false;
1414         else {
1415             LogOut ( KVERBOSITY_ERROR, 0,
1416                      "Unexpected scheme '(%S)'\n", & scheme );
1417             return 0;
1418         }
1419     }
1420     if ( rc == 0 ) {
1421         if ( https ) {
1422             STestStart ( self, false, 0, "KClientHttp = "
1423                          "KNSManagerMakeClientHttps(%S):", & host );
1424             rc = KNSManagerMakeClientHttps ( self -> kmgr, & http, NULL,
1425                                              HTTP_VERSION, & host, 0 );
1426         }
1427         else {
1428             STestStart ( self, false, 0, "KClientHttp = "
1429                          "KNSManagerMakeClientHttp(%S):", & host );
1430             rc = KNSManagerMakeClientHttp ( self -> kmgr, & http, NULL,
1431                                             HTTP_VERSION, & host, 0 );
1432         }
1433         if ( rc == 0 )
1434             STestEndOr ( self, & rc, eEndOK, "OK" );
1435         if ( rc != 0 ) {
1436             if ( _RcCanceled ( rc ) )
1437                 STestEnd ( self, eCANCELED, "CANCELED" );
1438             else
1439                 STestEnd ( self, eEndFAIL, "%R", rc );
1440         }
1441     }
1442     if ( rc == 0 ) {
1443         String path;
1444         rc = VPathGetPath ( data -> vpath, & path );
1445         if ( rc != 0 )
1446             STestFail ( self, rc, 0, "VPathGetPath" );
1447         else {
1448             rc = KHttpMakeRequest ( http, & req, "%S", & path );
1449             if ( rc != 0 ) {
1450                 self -> dad -> report . firewall = true;
1451                 STestFail ( self, rc, 0, "KHttpMakeRequest(%S)", & path );
1452             }
1453         }
1454     }
1455     if ( rc == 0 ) {
1456         STestStart ( self, false, 0, "KHttpResult = "
1457             "KHttpRequestHEAD(KHttpMakeRequest(KClientHttp)):" );
1458         rc = KHttpRequestHEAD ( req, & rslt );
1459         if ( rc == 0 )
1460             STestEndOr ( self, & rc, eEndOK, "OK" );
1461         if ( rc != 0 ) {
1462             if ( _RcCanceled ( rc ) )
1463                 STestEnd ( self, eCANCELED, "CANCELED" );
1464             else
1465                 STestEnd ( self, eEndFAIL, "%R", rc );
1466         }
1467     }
1468     if ( rc == 0 ) {
1469         STestStart ( self, false, 0,
1470                      "KHttpResultGetHeader(KHttpResult, Accept-Ranges) =" );
1471         rc = KHttpResultGetHeader ( rslt, "Accept-Ranges",
1472                                     buffer, sizeof buffer, & num_read );
1473         if ( rc == 0 ) {
1474             const char bytes [] = "bytes";
1475             if ( string_cmp ( buffer, num_read, bytes, sizeof bytes - 1,
1476                               sizeof bytes - 1 ) == 0 )
1477             {
1478                 rc = STestEnd ( self, eEndOK, "'%.*s': OK",
1479                                         ( int ) num_read, buffer );
1480             }
1481             else {
1482                 STestEnd ( self, eEndFAIL, "'%.*s'", ( int ) num_read, buffer );
1483                 rc = RC ( rcRuntime,
1484                           rcFile, rcOpening, rcFunction, rcUnsupported );
1485             }
1486         }
1487         else
1488             STestEnd ( self, eEndFAIL, "%R", rc );
1489     }
1490     KHttpResultRelease ( rslt );
1491     rslt = NULL;
1492     if ( sz < ebytes )
1493         ebytes = sz;
1494     if ( sz > bytes * 2 )
1495         pos = sz / 2;
1496     if ( rc == 0 ) {
1497         STestStart ( self, false, 0, "KHttpResult = KHttpRequestByteRange"
1498                         "(KHttpMakeRequest, %lu, %zu):", pos, bytes );
1499         rc = KHttpRequestByteRange ( req, pos, bytes );
1500         if ( rc == 0 )
1501             STestEndOr ( self, & rc, eEndOK, "OK" );
1502         if ( rc != 0 ) {
1503             if ( _RcCanceled ( rc ) )
1504                 STestEnd ( self, eCANCELED, "CANCELED" );
1505             else
1506                 STestEnd ( self, eEndFAIL, "%R", rc );
1507         }
1508     }
1509     if ( rc == 0 ) {
1510         STestStart ( self, false, 0,
1511             "KHttpResult = KHttpRequestGET(KHttpMakeRequest(KClientHttp)):" );
1512         rc = KHttpRequestGET ( req, & rslt );
1513         if ( rc == 0 )
1514             STestEndOr ( self, & rc, eEndOK, "OK" );
1515         if ( rc != 0 ) {
1516             if ( _RcCanceled ( rc ) )
1517                 STestEnd ( self, eCANCELED, "CANCELED" );
1518             else
1519                 STestEnd ( self, eEndFAIL, "%R", rc );
1520         }
1521     }
1522     if ( rc == 0 ) {
1523         uint64_t po = 0;
1524         size_t byte = 0;
1525         rc = KClientHttpResultRange ( rslt, & po, & byte );
1526         if ( rc == 0 ) {
1527             if ( po != pos || ( ebytes > 0 && byte != ebytes ) ) {
1528                 rc = RC ( rcRuntime, rcFile, rcReading, rcRange, rcOutofrange );
1529                 STestFail ( self, rc, 0,
1530                     "KClientHttpResultRange(KHttpResult,&p,&b): "
1531                     "got:{%lu,%zu}", pos, ebytes, po, byte );
1532 /*              STestStart ( self, false,
1533                              "KClientHttpResultRange(KHttpResult,&p,&b):" );
1534                 STestEnd ( self, eEndFAIL, "FAILURE: expected:{%lu,%zu}, "
1535                             "got:{%lu,%zu}", pos, ebytes, po, byte );*/
1536             }
1537         }
1538         else {
1539             STestFail ( self, rc, 0, "KClientHttpResultRange(KHttpResult)" );
1540 /*          STestStart ( self, false, "KClientHttpResultRange(KHttpResult):" );
1541             STestEnd ( self, eEndFAIL, "FAILURE: %R", rc );*/
1542         }
1543     }
1544     if ( rc == 0 ) {
1545         STestStart ( self, false, 0,
1546                      "KHttpResultGetHeader(KHttpResult, Content-Range) =" );
1547         rc = KHttpResultGetHeader ( rslt, "Content-Range",
1548                                     buffer, sizeof buffer, & num_read );
1549         if ( rc == 0 )
1550             STestEndOr ( self, & rc, eEndOK, "'%.*s': OK",
1551                                     ( int ) num_read, buffer );
1552         if ( rc != 0 ) {
1553             if ( _RcCanceled ( rc ) )
1554                 STestEnd ( self, eCANCELED, "CANCELED" );
1555             else
1556                 STestEnd ( self, eEndFAIL, "%R", rc );
1557         }
1558     }
1559     KHttpResultRelease ( rslt );
1560     rslt = NULL;
1561     KHttpRequestRelease ( req );
1562     req = NULL;
1563     KHttpRelease ( http );
1564     http = NULL;
1565 
1566     if ( rc == 0 ) {
1567         rc_t r2 = STestEnd ( self, eOK, "Support of Range requests" );
1568         if ( r2 != 0 && rc == 0 )
1569             rc = r2;
1570     }
1571     else if ( _RcCanceled ( rc ) )
1572         STestEnd ( self, eCANCELED, "Support of Range requests: CANCELED" );
1573     else
1574         STestEnd ( self, eFAIL, "Support of Range requests" );
1575 
1576     return rc;
1577 }
1578 
STestRemoveCache(STest * self,const char * cache)1579 static KPathType STestRemoveCache ( STest * self, const char * cache ) {
1580     KPathType type = kptNotFound;
1581 
1582     assert ( self );
1583 
1584     type = KDirectoryPathType ( self -> dir, cache );
1585 
1586     if ( type != kptNotFound ) {
1587         if ( ( type & ~ kptAlias ) == kptFile ) {
1588             rc_t rc = KDirectoryRemove ( self -> dir, false, cache );
1589             if ( rc != 0 )
1590                 STestFail ( self, rc, 0, "KDirectoryRemove(%s)", cache );
1591             else
1592                 type = kptNotFound;
1593         }
1594         else
1595             LogOut ( KVERBOSITY_ERROR, 0,
1596                      "UNEXPECTED FILE TYPE OF '%s': %d\n", cache, type );
1597     }
1598 
1599     return type;
1600 }
1601 
STestCheckStreamRead(STest * self,const KStream * stream,const char * cache,uint64_t * cacheSize,uint64_t sz,bool print,const char ** exp,size_t esz,bool * tooBig)1602 static rc_t STestCheckStreamRead ( STest * self, const KStream * stream,
1603     const char * cache, uint64_t * cacheSize, uint64_t sz, bool print,
1604     const char ** exp, size_t esz, bool * tooBig )
1605 {
1606     rc_t rc = 0;
1607     size_t total = 0;
1608     char buffer [ 1024 ] = "";
1609     KFile * out = NULL;
1610     rc_t rw = 0;
1611     uint64_t pos = 0;
1612     assert ( cache && cacheSize && tooBig );
1613     if ( cache [ 0 ] != '\0' ) {
1614         if ( STestRemoveCache ( self, cache ) == kptNotFound ) {
1615             rw = KDirectoryCreateFile ( self -> dir, & out, false,  0664,
1616                                         kcmCreate | kcmParents, cache );
1617             if ( rw != 0 )
1618                 LogOut ( KVERBOSITY_ERROR, 0,
1619                          "CANNOT CreateFile '%s': %R\n", cache, rw );
1620         }
1621     }
1622     STestStart ( self, false, 0, "KStreamRead(KHttpResult):" );
1623     while ( rc == 0 ) {
1624         size_t num_read = 0;
1625         rc = KStreamRead ( stream, buffer, sizeof buffer, & num_read );
1626         if ( rc != 0 )
1627             STestEnd ( self, eEndFAIL, "%R", rc );
1628         else if ( num_read != 0 ) {
1629             if ( rw == 0 && out != NULL ) {
1630                 size_t num_writ = 0;
1631                 rw = KFileWriteAll ( out, pos, buffer, num_read, & num_writ );
1632                 if ( rw == 0 ) {
1633                     assert ( num_writ == num_read );
1634                     pos += num_writ;
1635                 }
1636                 else
1637                     LogOut ( KVERBOSITY_ERROR, 0,
1638                              "CANNOT WRITE TO '%s': %R\n", cache, rw );
1639             }
1640             if ( total == 0 && esz > 0 ) {
1641                 int i = 0;
1642                 size_t s = esz;
1643                 if ( num_read < esz )
1644                     s = num_read;
1645                 rc = STestEnd ( self, eMSG, "'" );
1646                 if ( rc != 0 ) {
1647                     if ( STestCanceled ( self, rc ) )
1648                         STestEnd ( self, eCANCELED, "CANCELED" );
1649                     else
1650                         STestEnd ( self, eEndFAIL, "%R", rc );
1651                     break;
1652                 }
1653                 for ( i = 0; i < s && rc == 0; ++ i ) {
1654                     if ( isprint ( ( unsigned char ) buffer [ i ] ) )
1655                         rc = STestEnd ( self, eMSG, "%c", buffer [ i ] );
1656                     else if ( buffer [ i ] == 0 )
1657                         rc = STestEnd ( self, eMSG, "\\0" );
1658                     else
1659                         rc = STestEnd ( self, eMSG, "\\%03o",
1660                                                ( unsigned char ) buffer [ i ] );
1661                 }
1662                 if ( rc == 0 )
1663                     rc = STestEnd ( self, eMSG, "': " );
1664                 if ( rc != 0 ) {
1665                     if ( STestCanceled ( self, rc ) )
1666                         STestEnd ( self, eCANCELED, "CANCELED" );
1667                     else
1668                         STestEnd ( self, eEndFAIL, "%R", rc );
1669                     break;
1670                 }
1671                 for ( i = 0; i < 2; ++ i ) {
1672                     if ( string_cmp ( buffer, num_read, exp [ i ], esz,
1673                                       (uint32_t) esz ) == 0 )
1674                     {   break; }
1675                     else if ( i == 1 ) {
1676                         STestEnd ( self, eEndFAIL, "bad content" );
1677                         rc = RC ( rcRuntime,
1678                                   rcFile, rcReading, rcString, rcUnequal );
1679                     }
1680                 }
1681             }
1682             total += num_read;
1683             if ( total > 1000000 /* 1mb */ ) {
1684                 * tooBig = true;
1685                 rc = STestEnd ( self, eEndOK,
1686                                 "Interrupted (file is too big): OK" );
1687                 assert ( total < sz );
1688                 break;
1689             }
1690         }
1691         else {
1692             assert ( num_read == 0 );
1693             if ( total == sz ) {
1694                 if ( print ) {
1695                     if ( total >= sizeof buffer )
1696                         buffer [ sizeof buffer - 1 ] = '\0';
1697                     else {
1698                         buffer [ total ] = '\0';
1699                         while ( total > 0 ) {
1700                             -- total;
1701                             if ( buffer [ total ] == '\n' )
1702                                 buffer [ total ] = '\0';
1703                             else
1704                                 break;
1705                         }
1706                     }
1707                     rc = STestEnd ( self, eMSG, "%s: ", buffer );
1708                 }
1709                 if ( rc == 0 )
1710                     rc = STestEnd ( self, eEndOK, "OK" );
1711                 if ( rc != 0 ) {
1712                     if ( STestCanceled ( self, rc ) )
1713                         STestEnd ( self, eCANCELED, "CANCELED" );
1714                     else
1715                         STestEnd ( self, eEndFAIL, "%R", rc );
1716                 }
1717             }
1718             else
1719                 STestEnd ( self, eEndFAIL, "%s: SIZE DO NOT MATCH (%zu)\n",
1720                                            total );
1721             break;
1722         }
1723     }
1724     {
1725         rc_t r2 = KFileRelease ( out );
1726         if ( rw == 0 )
1727             rw = r2;
1728     }
1729     if ( rw == 0 )
1730         * cacheSize = pos;
1731     return rc;
1732 }
1733 
STestCheckHttpUrl(STest * self,uint64_t tests,uint64_t atest,const Data * data,const char * cache,uint64_t * cacheSize,bool print,const char ** exp,size_t esz,bool * tooBig)1734 static rc_t STestCheckHttpUrl ( STest * self, uint64_t tests, uint64_t atest,
1735     const Data * data, const char * cache, uint64_t * cacheSize,
1736     bool print, const char ** exp, size_t esz, bool * tooBig )
1737 {
1738     rc_t rc = 0;
1739     rc_t rc_read = 0;
1740     rc_t r2 = 0;
1741     KHttpRequest * req = NULL;
1742     KHttpResult * rslt = NULL;
1743     const String * full = NULL;
1744     uint64_t sz = 0;
1745     assert ( self && data );
1746     rc = VPathMakeString ( data -> vpath, & full );
1747     if ( rc != 0 )
1748         STestFail ( self, rc, 0, "VPathMakeString" );
1749     if ( rc == 0 )
1750         STestStart ( self, true, atest, "Access to '%S'", full );
1751     if ( rc == 0 )
1752         rc = STestCheckFile ( self, full, & sz, & rc_read );
1753     r2 = STestCheckRanges ( self, data, sz );
1754     if ( rc == 0 ) {
1755         STestStart ( self, false, 0,
1756                      "KHttpRequest = KNSManagerMakeRequest(%S):", full );
1757         rc = KNSManagerMakeRequest ( self -> kmgr, & req,
1758                                      HTTP_VERSION, NULL, "%S", full );
1759         if ( rc == 0 )
1760             STestEndOr ( self, & rc, eEndOK, "OK"  );
1761         if ( rc != 0 ) {
1762             if ( _RcCanceled ( rc ) )
1763                 STestEnd ( self, eCANCELED, "CANCELED" );
1764             else {
1765                 self -> dad -> report . firewall = true;
1766                 STestEnd ( self, eEndFAIL, "%R", rc );
1767             }
1768         }
1769     }
1770     if ( rc == 0 ) {
1771         STestStart ( self, false, 0,
1772                      "KHttpResult = KHttpRequestGET(KHttpRequest):" );
1773         rc = KHttpRequestGET ( req, & rslt );
1774         if ( rc == 0 )
1775             STestEndOr ( self, & rc, eEndOK, "OK" );
1776         if ( rc != 0 ) {
1777             if ( _RcCanceled ( rc ) )
1778                 STestEnd ( self, eCANCELED, "CANCELED" );
1779             else
1780                 STestEnd ( self, eEndFAIL, "%R", rc );
1781         }
1782     }
1783     if ( rc == 0 ) {
1784         uint32_t code = 0;
1785         STestStart ( self, false, 0, "KHttpResultStatus(KHttpResult) =" );
1786         rc = KHttpResultStatus ( rslt, & code, NULL, 0, NULL );
1787         if ( rc != 0 )
1788             STestEnd ( self, eEndFAIL, "%R", rc );
1789         else {
1790             rc = STestEnd ( self, eMSG, "%u: ", code );
1791             if ( rc == 0 )
1792                 if ( code == 200 )
1793                     STestEnd ( self, eEndOK, "OK" );
1794                 else {
1795                     STestEnd ( self, eEndFAIL, "bad status" );
1796                     rc = RC ( rcRuntime, rcFile, rcReading, rcFile, rcInvalid );
1797                 }
1798             else  if ( STestCanceled ( self, rc ) )
1799                 STestEnd ( self, eCANCELED, "CANCELED" );
1800             else
1801                 STestEnd ( self, eEndFAIL, "%R", rc );
1802         }
1803     }
1804     if ( rc == 0 && tests & KDIAGN_DOWNLOAD_HTTP ) {
1805         KStream * stream = NULL;
1806         rc = KHttpResultGetInputStream ( rslt, & stream );
1807         if ( rc != 0 )
1808             STestFail ( self, rc, KDIAGN_DOWNLOAD_HTTP,
1809                         "KHttpResultGetInputStream(KHttpResult)" );
1810         else
1811             rc = STestCheckStreamRead ( self, stream, cache, cacheSize,
1812                                         sz, print, exp, esz, tooBig );
1813         KStreamRelease ( stream );
1814         stream = NULL;
1815     }
1816     if ( rc == 0 && r2 != 0 )
1817         rc = r2;
1818     if ( rc == 0 && rc_read != 0 )
1819         rc = rc_read;
1820     KHttpRequestRelease ( req );
1821     req = NULL;
1822     KHttpResultRelease ( rslt );
1823     rslt = NULL;
1824 
1825     if ( rc == 0 )
1826         STestEnd ( self, eOK, "Access to '%S'", full );
1827     else if ( _RcCanceled ( rc ) )
1828         STestEnd ( self, eCANCELED, "Access to '%S': CANCELED", full );
1829     else
1830         STestEnd ( self, eFAIL, "Access to '%S'", full );
1831 
1832     free ( ( void * ) full );
1833     full = NULL;
1834     return rc;
1835 }
1836 
DataIsAccession(const Data * self)1837 static bool DataIsAccession ( const Data * self ) {
1838     assert ( self );
1839 
1840     if ( self -> acc == NULL )
1841         return false;
1842     else
1843         return self -> acc -> size != 0;
1844 }
1845 
STestCheckVfsUrl(STest * self,uint64_t atest,const Data * data,bool warn)1846 static rc_t STestCheckVfsUrl ( STest * self, uint64_t atest, const Data * data,
1847                                bool warn )
1848 {
1849     rc_t rc = 0;
1850 
1851     const KDirectory * d = NULL;
1852 
1853     String path;
1854 
1855     assert ( self && data );
1856 
1857     if ( ! DataIsAccession ( data ) )
1858         return 0;
1859 
1860     rc = VPathGetPath ( data -> vpath, & path );
1861     if ( rc != 0 ) {
1862         STestFail ( self, rc, 0, "VPathGetPath" );
1863         return rc;
1864     }
1865 
1866     STestStart ( self, false, atest, "VFSManagerOpenDirectoryReadDecrypt(%S):",
1867                                                                   & path );
1868     rc = VFSManagerOpenDirectoryReadDecrypt ( self -> vmgr, & d,
1869                                               data -> vpath );
1870     if ( rc == 0 )
1871         STestEndOr ( self, & rc, eEndOK, "OK"  );
1872     if ( rc != 0 ) {
1873         if ( _RcCanceled ( rc ) )
1874             STestEnd ( self, eCANCELED, "CANCELED" );
1875         else
1876             STestEnd ( self, eEndFAIL, "%R", rc );
1877     }
1878 
1879     RELEASE ( KDirectory, d );
1880 
1881     return rc;
1882 }
1883 
STestCheckUrlImpl(STest * self,uint64_t tests,uint64_t htest,uint64_t vtest,const Data * data,const char * cache,uint64_t * cacheSize,bool print,const char ** exp,size_t esz,bool * tooBig)1884 static rc_t STestCheckUrlImpl ( STest * self, uint64_t tests, uint64_t htest,
1885     uint64_t vtest,  const Data * data, const char * cache,
1886     uint64_t * cacheSize, bool print, const char ** exp, size_t esz,
1887     bool * tooBig )
1888 {
1889     rc_t rc = 0;
1890     rc_t r2 = 0;
1891     if ( tests & htest )
1892         rc = STestCheckHttpUrl ( self, tests, htest, data,
1893                                  cache, cacheSize, print, exp, esz, tooBig );
1894     if ( tests & vtest )
1895         r2 = STestCheckVfsUrl  ( self, vtest, data, cacheSize == 0 );
1896     return rc != 0 ? rc : r2;
1897 }
1898 
STestCheckUrl(STest * self,uint64_t tests,uint64_t htest,uint64_t vtest,const Data * data,const char * cache,uint64_t * cacheSize,bool print,const char ** exp,size_t esz,bool * tooBig)1899 static rc_t STestCheckUrl ( STest * self, uint64_t tests, uint64_t htest,
1900     uint64_t vtest, const Data * data, const char * cache, uint64_t * cacheSize,
1901     bool print, const char ** exp, size_t esz, bool * tooBig )
1902 {
1903     rc_t rc = 0;
1904 
1905     String path;
1906 
1907     bool dummy;
1908     if ( tooBig == NULL )
1909         tooBig = & dummy;
1910 
1911     assert ( data );
1912 
1913     rc = VPathGetPath ( data -> vpath, & path );
1914     if ( rc != 0 ) {
1915         STestFail ( self, rc, 0, "VPathGetPath" );
1916         return rc;
1917     }
1918 
1919     if ( path . size == 0 ) /* does not exist */
1920         return 0;
1921 
1922     return STestCheckUrlImpl ( self, tests, htest, vtest, data,
1923                                cache, cacheSize, print, exp, esz, tooBig );
1924 }
1925 
KConfig_Resolver(const KConfig * self)1926 static String * KConfig_Resolver ( const KConfig * self ) {
1927     String * s = NULL;
1928 
1929     rc_t rc = KConfigReadString ( self,
1930                                   "tools/test-sra/diagnose/resolver-cgi", & s );
1931     if ( rc != 0 ) {
1932         String str;
1933         CONST_STRING ( & str,
1934                        "https://trace.ncbi.nlm.nih.gov/Traces/names/names.fcgi" );
1935         rc = StringCopy ( ( const String ** ) & s, & str );
1936         assert ( rc == 0 );
1937     }
1938 
1939     assert ( s );
1940     return s;
1941 }
1942 
KConfig_Verbosity(const KConfig * self)1943 static int KConfig_Verbosity ( const KConfig * self ) {
1944     int64_t v = -1;
1945 
1946     String * s = NULL;
1947     rc_t rc = KConfigReadString ( self,
1948                                   "tools/test-sra/diagnose/verbosity", & s );
1949     if ( rc != 0 )
1950         return 0;
1951 
1952     assert ( s );
1953 
1954     if ( s -> size > 0 )
1955         if ( isdigit ( s -> addr [ 0 ] ) )
1956             v = strtoi64 ( s -> addr, NULL, 0 );
1957 
1958     free ( s );
1959     s = NULL;
1960 
1961     return ( int ) v;
1962 }
1963 
STestAbuseRedirect(const STest * self,Abuse * test,bool * abuse)1964 static rc_t STestAbuseRedirect ( const STest * self,
1965                                  Abuse * test, bool * abuse )
1966 {
1967     rc_t rc = 0;
1968 
1969     KHttpRequest * req = NULL;
1970     KHttpResult * rslt = NULL;
1971     KStream * stream = NULL;
1972 
1973     size_t i = 0;
1974     size_t total = 0;
1975     char * base = NULL;
1976     const char * c = NULL;
1977 
1978     Block * p = NULL;
1979     KDataBuffer * buffer = NULL;
1980 
1981     String open, close, needle;
1982     CONST_STRING ( & open,   "<p>" );
1983     CONST_STRING ( & close, "</p>" );
1984 
1985     assert ( self && test && abuse );
1986 
1987     buffer = & test -> redirect;
1988     p = & test -> p;
1989 
1990     if ( rc == 0 )
1991         rc = KNSManagerMakeRequest ( self -> kmgr, & req, HTTP_VERSION,
1992                                      NULL, test -> location );
1993     if ( rc == 0 )
1994         rc = KHttpRequestGET ( req, & rslt );
1995 
1996     if ( rc == 0 )
1997         rc = KHttpResultGetInputStream ( rslt, & stream );
1998 
1999 #if 0
2000 if(false){
2001 char*c="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> \n<html>\n<head>\n<title>NCBI - WWW Error Blocked Diagnostic</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n<meta http-equiv=\"pragma\" content=\"no-cache\" />\n<meta http-equiv=\"cache-control\" content=\"no-cache\" />\n<meta name=\"robots\" content=\"noarchive,none\" />\n\n<style type=\"text/css\">\nbody {\nmin-width: 950px;\n_width: 950px;\n}\nh1.error {color: red; font-size: 40pt}\n\n#mainContent {\npadding: 1em 2em;\n}\n\ndl#diags {\npadding: 0.5em 0.5em 1.5em 0.5em;\npadding-left: 2em;\nborder: solid 1px #888;\nborder-left: none;\nborder-right: none;\nmargin-bottom:0;\nbackground-color:#eeeeee;\ncolor:#666;\nfont-size: 80%;\n_font-size: 70%;\nfont-family: Verdana, sans-serif;\n}\n\ndl#diags dt {\nfloat: left;\nfont-weight: bold;\nwidth: auto;\n}\n\ndl#diags dd {\nmargin-left:1em;\nfloat: left;\nmargin-right: 2em;\n}\n\n#footer span {\nfloat: left;\ncolor: #888;\nfont-size: 80%;\n}\n\n#footer {\ntext-align: right;\npadding: 0 0.5em;\nclear: left;\n}\n\n#footer img {\nborder: none;\n}\n\n.ncbi {\nmargin: 0;\npadding:0;\nfont-size:240%;\nfont-weight: bold;\nfont-family: Times, serif;\ncolor: #336699;\nfloat: left;\ndisplay: inline;\n}\n\n.ncbi a {\ntext-decoration: none;\ncolor: #336699;\n}\n\n.ncbi a:visited {\ntext-decoration: none;\ncolor: #336699;\n}\n\n.ncbi a:hover {\ntext-decoration: underline;\n}\n\n.message {\nfont-family: Verdana, sans-serif;\nbackground-color: #336699;\ncolor: white;\npadding: .35em;\nmargin-left: 7em;\nmargin-top: .67em;\n_margin-top: 0.5em;\nfont-weight: bold;\nfont-size: 100%;\nmargin-bottom: 0;\n}\n\nh1 {\nclear: left;\nfont-size: 110%;\nfont-family: Verdana, sans-serif;\n}\n\n\nbody.denied {\nbackground-color: black;\ncolor: white;\n}\n\nbody.denied h1 {\ncolor: red;\n}\n\nbody.denied a {\ncolor: green;\n}\n\nbody.denied #footer, body.denied #diags {\ncolor: black;\n}\n\n#searchme:focus {\nbackground-color: #ffa;\n}\n\n.errurl {\nletter-spacing: 0;\nmargin: 0 1em;\npadding: 0.25em;\nbackground-color: #fff0f0;\ncolor: #c00;\nfont-family: \"Courier New\", Courier, monospace;\nfont-size: 90%;\n_font-size: 80%;\n}\n\nbody.denied .errurl {\nbackground-color: black;\ncolor: yellow;\n}\n\nspan.x {\ndisplay: none;\n}\n\n</style>\n\n</head>\n<body class='denied'>\n\n\n\n\n\n\n<div id='header'>\n<a href=\"#mainContent\" title=\"Skip to main content\" />\n<p class=\"ncbi\"><a href=\"http://www.ncbi.nlm.nih.gov\">NCBI</a></p>\n<p class=\"message\">Error</p>\n</div>\n\n<div id='mainContent'>\n\n\n<h1 class=\"error\">Access Denied</h1>\n\n\n<p>\nYour access to the NCBI website at <b>www.ncbi.nlm.nih.gov</b> has been\ntemporarily blocked due to a possible misuse/abuse situation\ninvolving your site. This is not an indication of a security issue\nsuch as a virus or attack. It could be something as simple as a run\naway script or learning how to better use E-utilities,\n<a href=\"http://www.ncbi.nlm.nih.gov/books/NBK25497/\">http://www.ncbi.nlm.nih.gov/books/NBK25497/</a>,\nfor more efficient work such that your work does not impact the ability of other researchers\nto also use our site.\nTo restore access and understand how to better interact with our site\nto avoid this in the future, please have your system administrator\ncontact \n<a href=\"mailto:info@ncbi.nlm.nih.gov?subject=NCBI Web site BLOCKED: 12.34.567.890&amp;body=%3E%20Error%3Dblocked for possible abuse%0D%3E%20Server%3Dmisuse.ncbi.nlm.nih.gov%0D%3E%20Client%3D12.34.567.890%0D%3E%20Time%3DTuesday, 03-Apr-2018 13:30:17 EDT  %0D%0DPlease%20enter%20comments%20below:%0D%0D\">info@ncbi.nlm.nih.gov</a>.\n</p>\n\n</div>\n\n<dl id='diags'>\n\n<dt>Error</dt><dd>blocked for possible abuse </dd>\n<dt>Server</dt><dd>misuse.ncbi.nlm.nih.gov</dd>\n<dt>Client</dt><dd>12.34.567.890</dd>\n<dt>Time</dt><dd>Tuesday, 03-Apr-2018 13:30:17 EDT</dd>\n\n</dl>\n \n\n<p id='footer'>\n<span id='rev'>Rev. 05/18/15</span>\n</p>\n\n</body>\n</html>\n\n";
2002 size_t s = string_size ( c );KDataBufferMakeBytes ( buffer, s + 9 );
2003 memmove(buffer->base,c,s);base = buffer -> base;
2004 buffer->elem_count=s;
2005 }
2006 else
2007 #endif
2008     while ( rc == 0 )
2009     {
2010         size_t num_read = 0;
2011 
2012         uint64_t avail = buffer -> elem_count - total;
2013         if ( avail == 0 ) {
2014             rc = KDataBufferResize ( buffer, buffer -> elem_count + 1024 );
2015             if ( rc != 0 )
2016                 break;
2017         }
2018 
2019         base = buffer -> base;
2020         rc = KStreamRead ( stream, & base [ total ],
2021             ( size_t ) buffer -> elem_count - total, & num_read );
2022         if ( num_read == 0 ) {
2023             buffer -> elem_count = total;
2024             break;
2025         }
2026         if ( rc != 0 ) /* TBD - look more closely at rc */
2027             rc = 0;
2028 
2029         total += num_read;
2030     }
2031 
2032     if ( rc == 0 ) {
2033         p -> begin = find ( base + i, buffer -> elem_count - i, & open );
2034         if ( p -> begin != NULL ) {
2035             i = p -> begin - base;
2036             p -> end = find ( base + i, buffer -> elem_count - i, & close );
2037             if ( p -> end != NULL )
2038                 * ( p -> end ) = '\0';
2039         }
2040     }
2041 
2042     if ( p -> end != NULL ) {
2043         CONST_STRING ( & needle, "<a href=\"mailto:" );
2044         test -> mailto . begin = find ( p -> begin, p -> end - p -> begin,
2045                                         & needle );
2046         if ( test -> mailto . begin != NULL ) {
2047             CONST_STRING ( & needle, "</a>" );
2048             test -> mailto . end = find ( test -> mailto . begin,
2049                 p -> end - test -> mailto . begin, & needle );
2050         }
2051     }
2052 
2053     if ( test -> mailto . end != NULL ) {
2054         CONST_STRING ( & needle, "Client%3D" );
2055         test -> ip . addr = find ( test -> mailto . begin,
2056             test -> mailto . end - test -> mailto . begin, & needle );
2057         if ( test -> ip . addr == NULL )
2058             test -> ip . addr = "";
2059         else {
2060             test -> ip . addr += needle . size;
2061             c = string_chr ( test -> ip . addr,
2062                              test -> mailto . end - test -> ip . addr, '%' );
2063             if ( c != NULL )
2064                 test -> ip . len = test -> ip . size = c - test -> ip . addr;
2065         }
2066     }
2067 
2068     if ( test -> mailto . end != NULL ) {
2069         CONST_STRING ( & needle, "Time%3D" );
2070         test -> date . addr = find ( test -> mailto . begin,
2071             test -> mailto . end - test -> mailto . begin, & needle );
2072         if ( test -> date . addr == NULL )
2073             test -> date . addr = "";
2074         else {
2075             test -> date . addr += needle . size;
2076             c = string_chr ( test -> date . addr,
2077                              test -> mailto . end - test -> date . addr, '%' );
2078             if ( c != NULL )
2079                 test -> date . len = test -> date . size
2080                                    = c - test -> date . addr;
2081         }
2082     }
2083 
2084     * abuse = true;
2085 
2086     RELEASE ( KStream, stream );
2087     RELEASE ( KHttpResult, rslt );
2088     RELEASE ( KHttpRequest, req );
2089 
2090     return rc;
2091 }
2092 
STestAbuse(STest * self,Abuse * test,bool * ok,bool * abuse)2093 static rc_t STestAbuse ( STest * self, Abuse * test,
2094                          bool * ok, bool * abuse )
2095 {
2096     size_t i = 0;
2097     const char * s = NULL;
2098     const char * h;
2099 
2100     String misuse;
2101     CONST_STRING ( & misuse,
2102         "https://misuse.ncbi.nlm.nih.gov/error/abuse.shtml" );
2103 
2104     assert ( test && ok && abuse );
2105 
2106     * ok = * abuse = false;
2107 
2108     if ( test -> code == 200 ) {
2109         * ok = true;
2110         return 0;
2111     }
2112 
2113     if ( test -> code != 302 )
2114         return 0;
2115 
2116     if ( test -> location != NULL )
2117         return STestAbuseRedirect ( self, test, abuse );
2118 
2119     s = test -> response . base;
2120     h = find ( s + i, test -> response . elem_count - i,
2121                             & misuse );
2122     if ( h != NULL ) {
2123         rc_t rc = AbuseSetLocation ( test, misuse . addr, misuse . size );
2124         return rc == 0 ? STestAbuseRedirect ( self, test, abuse ) : rc;
2125     }
2126 
2127     return 0;
2128 }
2129 
processResponse(char * response,size_t size)2130 static char * processResponse ( char * response, size_t size ) {
2131     int n = 0;
2132 
2133     size_t i = 0;
2134     for ( i = 0; i < size; ++ n ) {
2135         const char * p = string_chr ( response + i, size - i, '|' );
2136         if ( p == NULL )
2137             return NULL;
2138 
2139         i = p - response + 1;
2140 
2141         if ( n == 5 ) {
2142             for ( ; response [ i ] != '|' && i < size; ++i )
2143                 response [ i ] = 'x';
2144 
2145             return response [ i ] == '|' ? response + i + 1 : NULL;
2146         }
2147     }
2148 
2149     return NULL;
2150 }
2151 
STestCallCgi(STest * self,uint64_t atest,const String * acc,char * response,size_t response_sz,size_t * resp_read,const char ** url,bool http)2152 static rc_t STestCallCgi ( STest * self, uint64_t atest, const String * acc,
2153     char * response, size_t response_sz, size_t * resp_read,
2154     const char ** url, bool http )
2155 {
2156     rc_t rc = 0;
2157 
2158     rc_t rs = 0;
2159     KHttpRequest * req = NULL;
2160     const String * cgi = NULL;
2161     KHttpResult * rslt = NULL;
2162     KStream * stream = NULL;
2163     Abuse * test = NULL;
2164 
2165     assert ( url && self && self -> dad );
2166 
2167     test = & self -> dad -> report . abuse;
2168 
2169     STestStart ( self, true, atest,
2170                  "Resolving of %s path to '%S'", http ? "HTTPS": "FASP", acc );
2171 
2172     * url = NULL;
2173 
2174     cgi = KConfig_Resolver ( self -> kfg );
2175     AbuseSetCgi ( test, cgi );
2176     STestStart ( self, false, 0,
2177         "KHttpRequest = KNSManagerMakeReliableClientRequest(%S):", cgi );
2178     rc = KNSManagerMakeReliableClientRequest ( self -> kmgr, & req,
2179         HTTP_VERSION, NULL, "%S", cgi);
2180     if ( rc == 0 )
2181         STestEndOr ( self, & rc, eEndOK, "OK"  );
2182     if ( rc != 0 ) {
2183         if ( _RcCanceled ( rc ) )
2184             STestEnd ( self, eCANCELED, "CANCELED" );
2185         else {
2186             self -> dad -> report . firewall = true;
2187             STestEnd ( self, eEndFAIL, "%R", rc );
2188         }
2189     }
2190     if ( rc == 0 ) {
2191         const char param [] = "accept-proto";
2192         const char * v = "http,fasp";
2193         if ( http )
2194             v = "http,https";
2195         rc = KHttpRequestAddPostParam ( req, "%s=%s", param, v );
2196         if ( rc != 0 )
2197             STestFail ( self, rc, 0,
2198                 "KHttpRequestAddPostParam(%s=%s)", param, v );
2199     }
2200     if ( rc == 0 ) {
2201         const char param [] = "object";
2202         rc = KHttpRequestAddPostParam ( req, "%s=0||%S", param, acc );
2203         if ( rc != 0 )
2204             STestFail ( self, rc, 0,
2205                         "KHttpRequestAddPostParam(%s=0||%S)", param, acc );
2206     }
2207     if ( rc == 0 ) {
2208         const char param [] = "version";
2209         rc = KHttpRequestAddPostParam ( req, "%s=3.0", param );
2210         if ( rc != 0 )
2211             STestFail ( self, rc, 0,
2212                         "KHttpRequestAddPostParam(%s=3.0)", param );
2213     }
2214     if ( rc == 0 ) {
2215         rc_t r1 = 0;
2216         const KConfigNode * nProtected = NULL;
2217         KNamelist * names = NULL;
2218         uint32_t count = 0;
2219         const char path [] = "/repository/user/protected";
2220         if ( KConfigOpenNodeRead ( self -> kfg, & nProtected, path ) != 0 )
2221             return 0;
2222         r1 = KConfigNodeListChildren ( nProtected, & names );
2223         if ( r1 == 0 )
2224             r1 = KNamelistCount ( names, & count );
2225         if ( r1 == 0 ) {
2226             uint32_t i = 0;
2227             for ( i = 0; i < count; ++ i ) {
2228                 const KConfigNode * node = NULL;
2229                 String * tic = NULL;
2230                 const char * name = NULL;
2231                 r1 = KNamelistGet ( names, i, & name );
2232                 if ( r1 != 0 )
2233                     continue;
2234                 r1 = KConfigNodeOpenNodeRead ( nProtected, & node,
2235                                                "%s/download-ticket", name );
2236                 if ( r1 != 0 )
2237                     continue;
2238                 r1 = KConfigNodeReadString ( node, & tic );
2239                 if ( r1 == 0 ) {
2240                     const char param[] = "tic";
2241                     rc = KHttpRequestAddPostParam ( req, "%s=%S", param, tic );
2242                     if ( rc != 0 )
2243                         STestFail ( self, rc, 0,
2244                             "KHttpRequestAddPostParam(%s)", param );
2245                     free ( tic );
2246                     tic = NULL;
2247                 }
2248                 RELEASE ( KConfigNode, node  );
2249             }
2250         }
2251         RELEASE ( KConfigNode, nProtected  );
2252     }
2253     if ( rc == 0 ) {
2254         STestStart ( self, false, 0,
2255                      "KHttpRequestPOST(KHttpRequest(%S)):", cgi );
2256         rc = KHttpRequestPOST ( req, & rslt );
2257         if ( rc == 0 )
2258             STestEndOr ( self, & rc, eEndOK, "OK"  );
2259         if ( rc != 0 ) {
2260             if ( _RcCanceled ( rc ) )
2261                 STestEnd ( self, eCANCELED, "CANCELED" );
2262             else
2263                 STestEnd ( self, eEndFAIL, "%R", rc );
2264         }
2265     }
2266     if ( rc == 0 ) {
2267         uint32_t code = 0;
2268         STestStart ( self, false, 0,
2269                      "KHttpResultStatus(KHttpResult(%S)) =", cgi );
2270         rc = KHttpResultStatus ( rslt, & code, NULL, 0, NULL );
2271         if ( rc != 0 )
2272             STestEnd ( self, eEndFAIL, "%R", rc );
2273         else {
2274             rc = STestEnd ( self, eMSG, "%u: ", code );
2275             if ( rc == 0 ) {
2276                 if ( code == 200 )
2277                     STestEnd ( self, eEndOK, "OK" );
2278                 else {
2279                     STestEnd ( self, eEndFAIL, "bad status" );
2280                     rs = RC ( rcRuntime, rcFile, rcReading, rcFile, rcInvalid );
2281                 }
2282                 AbuseSetStatus ( test, code );
2283             }
2284             else  if ( STestCanceled ( self, rc ) )
2285                 STestEnd ( self, eCANCELED, "CANCELED" );
2286             else
2287                 STestEnd ( self, eEndFAIL, "%R", rc );
2288         }
2289     }
2290     if ( rc == 0 ) {
2291         const char name [] = "Location";
2292         rc_t r2 = 0;
2293         char buffer [ PATH_MAX ] = "";
2294         size_t num_read = 0;
2295         STestStart ( self, false, 0, "KClientHttpResultGetHeader(%s)", name );
2296         r2 = KClientHttpResultGetHeader ( rslt, name,
2297                                           buffer, sizeof buffer, & num_read );
2298         if ( r2 != 0 ) {
2299             if ( r2 == SILENT_RC ( rcNS,rcTree,rcSearching,rcName,rcNotFound ) )
2300                 rc = STestEnd ( self, eEndOK, ": not found: OK" );
2301             else
2302                 STestEnd ( self, eEndFAIL, "%R", r2 );
2303         }
2304         else {
2305             STestEnd ( self, eEndFAIL, "'%.*s'", ( int ) num_read, buffer );
2306             r2 = AbuseSetLocation ( test, buffer, num_read );
2307             if ( r2 != 0 && rc == 0)
2308                 rc = r2;
2309         }
2310     }
2311     if ( rc == 0 ) {
2312         rc = KHttpResultGetInputStream ( rslt, & stream );
2313         if ( rc != 0 )
2314             STestFail ( self, rc, 0, "KHttpResultGetInputStream" );
2315     }
2316     if ( rc == 0 ) {
2317         assert ( resp_read );
2318         STestStart ( self, false, 0, "KStreamRead(KHttpResult(%S)) =", cgi );
2319         rc = KStreamRead ( stream, response, response_sz, resp_read );
2320         if ( rc != 0 )
2321             STestEnd ( self, eEndFAIL, "%R", rc );
2322         else {
2323             if ( * resp_read > response_sz - 4 ) {
2324                 response [ response_sz - 4 ] = '.';
2325                 response [ response_sz - 3 ] = '.';
2326                 response [ response_sz - 2 ] = '.';
2327                 response [ response_sz - 1 ] = '\0';
2328             }
2329             else {
2330                 response [ * resp_read + 1 ] = '\0';
2331                 for ( ; * resp_read > 0 && ( response [ * resp_read ] == '\n' ||
2332                                              response [ * resp_read ] == '\0' );
2333                       --  ( * resp_read ) )
2334                 {
2335                     response [ * resp_read ] = '\0';
2336                 }
2337             }
2338             * url = processResponse ( response, * resp_read );
2339             if ( rs != 0 )
2340                 * url = NULL;
2341             rc = STestEnd ( self, eEndOK, "'%s': OK", response );
2342             if ( true )
2343                 AbuseAdd ( test, response, * resp_read );
2344 else      AbuseAdd(test,"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
2345 "<html><head>\n"
2346 "<title>302 Found</title>\n"
2347 "</head><body>\n"
2348 "<h1>Found</h1>\n"
2349 "<p>The document has moved <a href=\"https://misuse.ncbi.nlm.nih.gov/error/abuse.shtml\">here</a>.</p>\n"
2350 "</body></html>",0);
2351         }
2352     }
2353     {
2354         bool ok = false;
2355         bool abuse = true;
2356         STestAbuse ( self, test, & ok, & abuse );
2357         if ( abuse )
2358             self -> dad -> report . blocked = true;
2359     }
2360     KStreamRelease ( stream );
2361     stream = NULL;
2362     KHttpResultRelease ( rslt );
2363     rslt = NULL;
2364     KHttpRequestRelease ( req );
2365     req = NULL;
2366     free ( ( void * ) cgi );
2367     cgi = NULL;
2368 /*AbuseAdd(test,"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
2369 "<html><head>\n"
2370 "<title>302 Found</title>\n"
2371 "</head><body>\n"
2372 "<h1>Found</h1>\n"
2373 "<p>The document has moved <a href=\"https://misuse.ncbi.nlm.nih.gov/error/abuse.shtml\">here</a>.</p>\n"
2374 "</body></html>",0);*/
2375     if ( rc == 0 ) {
2376         const char * server = test -> server;
2377         if ( server == NULL )
2378             server = "www.ncbi.nlm.nih.gov ";
2379         if ( rs == 0 )
2380             rc = STestEnd ( self, eOK,  "Resolving of %s path to '%S'",
2381                                         http ? "HTTPS": "FASP", acc );
2382         else {
2383             rc = rs;
2384             STestEnd ( self, eFAIL, "Resolving of %s path to '%S'",
2385                                     http ? "HTTPS": "FASP", acc );
2386         }
2387     }
2388     else if ( _RcCanceled ( rc ) )
2389         STestEnd ( self, eCANCELED, "Resolving of %s path to '%S': CANCELED",
2390                                     http ? "HTTPS": "FASP", acc );
2391     else
2392         STestEnd ( self, eFAIL,     "Resolving of %s path to '%S'",
2393                                     http ? "HTTPS": "FASP", acc );
2394     return rc;
2395 }
2396 
STestCheckFaspDownload(STest * self,const char * url,const char * cache,uint64_t * cacheSz)2397 static rc_t STestCheckFaspDownload ( STest * self, const char * url,
2398                              const char * cache, uint64_t * cacheSz )
2399 {
2400     rc_t rc = 0;
2401 
2402     uint32_t m = 0;
2403     String fasp;
2404     String schema;
2405 
2406     assert ( self );
2407 
2408     if ( ! self -> ascpChecked ) {
2409         ascp_locate ( & self -> ascp, & self -> asperaKey, true, true);
2410         self -> ascpChecked = true;
2411 
2412         if ( self -> ascp == NULL ) {
2413             STestStart ( self, false, 0, "ascp download test:" );
2414             rc = STestEnd ( self, eEndOK, "skipped: ascp not found" );
2415         }
2416     }
2417 
2418     if ( self -> ascp == NULL )
2419         return rc;
2420 
2421     STestStart ( self, false, KDIAGN_ASCP_DOWNLOAD, "ascp download test:" );
2422 
2423     CONST_STRING ( & fasp, "fasp://" );
2424 
2425     m = string_measure ( url, NULL );
2426     if ( m < fasp . size ) {
2427         LogOut ( KVERBOSITY_ERROR, 0, "UNEXPECTED SCHEMA IN '%s'", url );
2428         return 0;
2429     }
2430 
2431     StringInit( & schema, url, fasp . size, fasp . len );
2432     if ( ! StringEqual ( & schema, & fasp ) ) {
2433         LogOut ( KVERBOSITY_ERROR, 0, "UNEXPECTED SCHEMA IN '%s'", url );
2434         return 0;
2435     }
2436 
2437     if ( rc == 0 ) {
2438         STestRemoveCache ( self, cache );
2439         rc = aspera_get ( self -> ascp, self -> asperaKey,
2440                           url + fasp . size, cache, 0 );
2441     }
2442 
2443     if ( rc == 0 )
2444         rc = KDirectoryFileSize ( self -> dir, cacheSz, cache );
2445     if ( rc == 0 )
2446         STestEndOr ( self, & rc, eEndOK, "OK" );
2447     if ( rc != 0 ) {
2448         if ( _RcCanceled ( rc ) )
2449             STestEnd ( self, eCANCELED, "CANCELED" );
2450         else
2451             STestEnd ( self, eEndFAIL, "%R", rc );
2452     }
2453 
2454     return rc;
2455 }
2456 
2457 /******************************************************************************/
2458 
2459 /*
2460 static rc_t _STestCheckAcc ( STest * self, const Data * data, bool print,
2461                             const char * exp, size_t esz )
2462 {
2463     rc_t rc = 0;
2464     char response [ 4096 ] = "";
2465     size_t resp_len = 0;
2466     const char * url = NULL;
2467     String acc;
2468     bool checked = false;
2469 
2470     const VPath * vcache = NULL;
2471     char faspCache [ PATH_MAX ] = "";
2472     uint64_t faspCacheSize = 0;
2473     char httpCache [ PATH_MAX ] = "";
2474     uint64_t httpCacheSize = 0;
2475 
2476     assert ( self && data );
2477 
2478     memset ( & acc, 0, sizeof acc );
2479     if ( DataIsAccession ( data ) ) {
2480         Abuse test;
2481         AbuseInit ( & test );
2482         acc = * data -> acc;
2483         rc = STestCallCgi ( self, & acc, response, sizeof response,
2484                             & resp_len, & url, & test, true | false );
2485         AbuseFini ( & test );
2486     }
2487     if ( acc . size != 0 ) {
2488         String cache;
2489         VPath * path = NULL;
2490         rc_t r2 = VFSManagerMakePath ( self -> vmgr, & path,
2491                                        "%S", data -> acc );
2492         if ( r2 == 0 )
2493             r2 = VResolverQuery ( self -> resolver, eProtocolFasp,
2494                                   path, NULL, NULL, & vcache);
2495 // TODO: find another cache location if r2 != 0
2496         if ( r2 == 0 )
2497             r2 = VPathGetPath ( vcache, & cache );
2498         if ( r2 == 0 ) {
2499             rc_t r1 = string_printf ( faspCache, sizeof faspCache, NULL,
2500                                       "%S.fasp", & cache );
2501             r2      = string_printf ( httpCache, sizeof httpCache, NULL,
2502                                       "%S.http", & cache );
2503             if ( r2 == 0 )
2504                 r2 = r1;
2505         }
2506         RELEASE ( VPath, path );
2507         if ( rc == 0 && r2 != 0 )
2508             rc = r2;
2509     }
2510     if ( url != NULL ) {
2511         char * p = string_chr ( url, resp_len - ( url - response ), '|' );
2512         if ( p == NULL ) {
2513             rc = RC ( rcRuntime, rcString ,rcParsing, rcString, rcIncorrect );
2514             STestFail ( self, rc, "UNEXPECTED RESOLVER RESPONSE" );
2515         }
2516         else {
2517             const String * full = NULL;
2518             rc_t r2 = VPathMakeString ( data -> vpath, & full );
2519             char * d = NULL;
2520             if ( r2 != 0 )
2521                 LogOut ( KVERBOSITY_ERROR, 0,
2522                          "CANNOT VPathMakeString: %R\n", r2 );
2523             d = string_chr ( url, resp_len - ( url - response ), '$' );
2524             if ( d == NULL )
2525                 d = p;
2526             while ( d != NULL && d <= p ) {
2527                 if ( ! checked && full != NULL && string_cmp ( full -> addr,
2528                         full -> size, url, d - url, d - url ) == 0 )
2529                 {
2530                     checked = true;
2531                 }
2532                 * d = '\0';
2533                 switch ( * url ) {
2534                     case 'h': {
2535                         Data dt;
2536                         if ( rc == 0 )
2537                             rc = DataInit ( & dt, self -> vmgr, url );
2538                         if ( rc == 0 ) {
2539                             rc_t r1 = STestCheckUrl ( self, & dt,
2540                                 httpCache, & httpCacheSize, print, exp, esz );
2541                             if ( rc == 0 && r1 != 0 )
2542                                 rc = r1;
2543                         }
2544                         DataFini ( & dt );
2545                         break;
2546                     }
2547                     case 'f': {
2548                         rc_t r1 = STestCheckFaspDownload ( self, url,
2549                                                    faspCache, & faspCacheSize );
2550                         if ( rc == 0 && r1 != 0 )
2551                             rc = r1;
2552                         break;
2553                     }
2554                     default:
2555                         break;
2556                 }
2557                 if ( d == p )
2558                     break;
2559                 url = d + 1;
2560                 d = string_chr ( d, resp_len - ( d - response ), '$' );
2561                 if ( d > p )
2562                     d = p;
2563             }
2564             free ( ( void * ) full );
2565             full = NULL;
2566         }
2567     }
2568     if ( ! checked ) {
2569         rc_t r1 = STestCheckUrl ( self, data, httpCache, & httpCacheSize,
2570                                   print, exp, esz );
2571         if ( rc == 0 && r1 != 0 )
2572             rc = r1;
2573     }
2574     if ( faspCacheSize != 0 && httpCacheSize != 0 ) {
2575         uint64_t pos = 0;
2576         rc_t r1 = 0;
2577         STestStart ( self, false, "HTTP vs ASCP download:" );
2578         if ( faspCacheSize != httpCacheSize ) {
2579             r1 = RC ( rcRuntime, rcFile, rcComparing, rcSize, rcUnequal );
2580             STestEnd ( self, eEndFAIL, "FAILURE: size does not match: "
2581                        "ascp(%lu)/http(%lu)", faspCacheSize, httpCacheSize );
2582         }
2583         else {
2584             const KFile * ascp = NULL;
2585             const KFile * http = NULL;
2586             rc_t r1 = KDirectoryOpenFileRead ( self -> dir, & ascp, faspCache );
2587             if ( r1 != 0 )
2588                 LogOut ( KVERBOSITY_ERROR, 0,
2589                          "KDirectoryOpenFileRead(%s)=%R\n", faspCache, r1 );
2590             else {
2591                 r1 = KDirectoryOpenFileRead ( self -> dir, & http, httpCache );
2592                 if ( r1 != 0 )
2593                     LogOut ( KVERBOSITY_ERROR, 0,
2594                              "KDirectoryOpenFileRead(%s)=%R\n", httpCache, r1 );
2595             }
2596             if ( r1 == 0 ) {
2597                 char bAscp [ 1024 ] = "";
2598                 char bHttp [ 1024 ] = "";
2599                 size_t ascp_read = 0;
2600                 size_t http_read = 0;
2601                 while ( r1 == 0 ) {
2602                     r1 = KFileReadAll ( ascp, pos, bAscp, sizeof bAscp,
2603                                         & ascp_read );
2604                     if ( r1 != 0 ) {
2605                         STestEnd ( self, eEndFAIL, "FAILURE to read '%s': %R",
2606                                                    faspCache, r1 );
2607                         break;
2608                     }
2609                     r1 = KFileReadAll ( http, pos, bHttp, sizeof bHttp,
2610                                         & http_read );
2611                     if ( r1 != 0 ) {
2612                         STestEnd ( self, eEndFAIL, "FAILURE to read '%s': %R",
2613                                                    httpCache, r1 );
2614                         break;
2615                     }
2616                     else if ( ascp_read != http_read ) {
2617                         r1 = RC (
2618                             rcRuntime, rcFile, rcComparing, rcSize, rcUnequal );
2619                         STestEnd ( self, eEndFAIL,
2620                             "FAILURE to read the same amount from files" );
2621                         break;
2622                     }
2623                     else if ( ascp_read == 0 )
2624                         break;
2625                     else {
2626                         pos += ascp_read;
2627                         if ( string_cmp ( bAscp, ascp_read,
2628                                           bHttp, http_read, ascp_read ) != 0 )
2629                         {
2630                             r1 = RC ( rcRuntime,
2631                                       rcFile, rcComparing, rcData, rcUnequal );
2632                             STestEnd ( self, eEndFAIL,
2633                                        "FAILURE: files are different" );
2634                             break;
2635                         }
2636                     }
2637                 }
2638             }
2639             RELEASE ( KFile, ascp );
2640             RELEASE ( KFile, http );
2641         }
2642         if ( r1 == 0 ) {
2643             rc_t r2 = 0;
2644             r1 = KDirectoryRemove ( self -> dir, false, faspCache );
2645             if ( r1 != 0 )
2646                 STestEnd ( self, eEndFAIL, "FAILURE: cannot remove '%s': %R",
2647                                            faspCache, r1 );
2648             r2 = KDirectoryRemove ( self -> dir, false, httpCache );
2649             if ( r2 != 0 ) {
2650                 if ( r1 == 0 ) {
2651                     r1 = r2;
2652                     STestEnd ( self, eEndFAIL,
2653                         "FAILURE: cannot remove '%s': %R", httpCache, r1 );
2654                 }
2655                 else
2656                     LogOut ( KVERBOSITY_ERROR, 0,
2657                              "Cannot remove '%s': %R\n", httpCache, r2 );
2658             }
2659             if ( r1 == 0 )
2660                 rc = STestEnd ( self, eEndOK, "%lu bytes compared: OK", pos );
2661             else if ( rc == 0 )
2662                 rc = r1;
2663         }
2664     }
2665 
2666     if ( acc . size != 0 ) {
2667         if ( rc == 0 )
2668             rc = STestEnd ( self, eOK, "Access to '%S'", & acc );
2669         else if ( _RcCanceled ( rc ) )
2670             STestEnd ( self, eCANCELED, "Access to '%S': CANCELED", & acc );
2671         else
2672             STestEnd ( self, eFAIL, "Access to '%S'", & acc );
2673     }
2674 
2675     RELEASE ( VPath, vcache );
2676     return rc;
2677 }
2678 */
2679 # if 0
2680 static rc_t _STestCheckNetwork ( STest * self, const Data * data,
2681     const char * exp, size_t esz, const Data * data2,
2682     const char * fmt, ... )
2683 {
2684     rc_t rc = 0;
2685     KEndPoint ep;
2686     char b [ 512 ] = "";
2687     String host;
2688 
2689     va_list args;
2690     va_start ( args, fmt );
2691     rc = string_vprintf ( b, sizeof b, NULL, fmt, args );
2692     if ( rc != 0 )
2693         STestFail ( self, rc, "CANNOT PREPARE MESSAGE" );
2694     va_end ( args );
2695 
2696     assert ( self && data );
2697 
2698     STestStart ( self, true, b );
2699     rc = VPathGetHost ( data -> vpath, & host );
2700     if ( rc != 0 )
2701         STestFail ( self, rc, "VPathGetHost" );
2702     else {
2703         rc_t r1 = 0;
2704         uint16_t port = 443;
2705         STestStart ( self, false, "KNSManagerInitDNSEndpoint(%S:%hu)",
2706                                   & host, port );
2707         rc = KNSManagerInitDNSEndpoint ( self -> kmgr, & ep, & host, port );
2708         if ( rc != 0 )
2709             STestEnd ( self, eEndFAIL, ": FAILURE: %R", rc );
2710         else {
2711             char endpoint [ 1024 ] = "";
2712             rc_t rx = endpoint_to_string ( endpoint, sizeof endpoint, & ep );
2713             if ( rx == 0 )
2714                 STestEndOr ( self, & rx, eEndOK, "= '%s': OK", endpoint );
2715             if ( rx != 0 ) {
2716                 if ( _RcCanceled ( rx ) )
2717                     STestEnd ( self, eCANCELED, "CANCELED" );
2718                 else
2719                     STestEnd ( self, eEndFAIL,
2720                                "CANNOT CONVERT TO STRING: %R", rx );
2721             }
2722         }
2723         port = 80;
2724         STestStart ( self, false, "KNSManagerInitDNSEndpoint(%S:%hu)",
2725                                   & host, port );
2726         r1 = KNSManagerInitDNSEndpoint ( self -> kmgr, & ep,
2727                                               & host, port );
2728         if ( r1 != 0 )
2729             STestEnd ( self, eEndFAIL, "FAILURE: %R", r1 );
2730         else {
2731             char endpoint [ 1024 ] = "";
2732             rc_t rx = endpoint_to_string ( endpoint, sizeof endpoint, & ep );
2733             if ( rx == 0 )
2734                 STestEndOr ( self, & rx, eEndOK, "= '%s': OK", endpoint );
2735             if ( rx != 0 ) {
2736                 if ( _RcCanceled ( rx ) )
2737                     STestEnd ( self, eCANCELED, "CANCELED" );
2738                 else
2739                     STestEnd ( self, eEndFAIL,
2740                                "CANNOT CONVERT TO STRING: %R", rx );
2741             }
2742         }
2743         rc = KNSManagerInitDNSEndpoint ( self -> kmgr, & ep, & host, port );
2744         if ( rc == 0 ) {
2745             rc = _STestCheckAcc ( self, data, false, exp, esz );
2746             if ( data2 != NULL ) {
2747                 rc_t r2 = _STestCheckAcc ( self, data2, true, 0, 0 );
2748                 if ( rc == 0 && r2 != 0 )
2749                     rc = r2;
2750             }
2751         }
2752         if ( rc == 0 && r1 != 0 )
2753             rc = r1;
2754     }
2755 
2756     if ( rc == 0 )
2757         rc = STestEnd ( self, eOK, b );
2758     else  if ( _RcCanceled ( rc ) )
2759         STestEnd ( self, eCANCELED, "%s: CANCELED", b );
2760     else
2761         STestEnd ( self, eFAIL, b );
2762     return rc;
2763 }
2764 #endif
2765 
2766 struct KDiagnoseTestDesc {
2767     const char * name;
2768     const char * desc;
2769     uint64_t code;
2770     uint32_t level;
2771     KDiagnoseTestDesc * next;
2772     KDiagnoseTestDesc * child;
2773     const KDiagnoseTestDesc * depends;
2774 };
2775 
KDiagnoseTestDescRelease(KDiagnoseTestDesc * self)2776 static rc_t KDiagnoseTestDescRelease ( KDiagnoseTestDesc * self ) {
2777     if ( self != NULL ) {
2778         if ( self -> child )
2779             KDiagnoseTestDescRelease ( self -> child );
2780 
2781         if ( self -> next )
2782             KDiagnoseTestDescRelease ( self -> next );
2783 
2784         memset ( self, 0, sizeof * self );
2785 
2786         free ( self );
2787     }
2788 
2789     return 0;
2790 }
2791 
KDiagnoseTestDescMake(KDiagnoseTestDesc ** self,uint32_t level,const char * name,uint64_t code)2792 static rc_t KDiagnoseTestDescMake ( KDiagnoseTestDesc ** self,
2793     uint32_t level, const char * name, uint64_t code )
2794 {
2795     assert ( self );
2796 
2797     * self = calloc ( 1, sizeof ** self );
2798 
2799     if ( * self == NULL )
2800         return RC ( rcRuntime, rcData, rcAllocating, rcMemory, rcExhausted );
2801     else {
2802         ( * self ) -> name  = name;
2803         ( * self ) -> desc  = "";
2804         ( * self ) -> code  = code;
2805         ( * self ) -> level = level;
2806 
2807         return 0;
2808     }
2809 }
2810 
KDiagnoseMakeDesc(KDiagnose * self)2811 static rc_t KDiagnoseMakeDesc ( KDiagnose * self ) {
2812   rc_t rc = 0;
2813 
2814   KDiagnoseTestDesc * root = NULL;
2815   KDiagnoseTestDesc * kfg = NULL;
2816 
2817   KDiagnoseTestDesc * net = NULL;
2818   KDiagnoseTestDesc * netNcbi = NULL;
2819   KDiagnoseTestDesc * netHttp = NULL;
2820   KDiagnoseTestDesc * netAscp = NULL;
2821   KDiagnoseTestDesc * netHttpVsAscp = NULL;
2822 
2823   assert ( self );
2824 
2825   if ( rc == 0 )
2826     rc = KDiagnoseTestDescMake ( & root, 0, "System", KDIAGN_ALL );
2827   {
2828     KDiagnoseTestDesc * kfgRemote = NULL;
2829     KDiagnoseTestDesc * kfgSite = NULL;
2830     KDiagnoseTestDesc * kfgUser = NULL;
2831     KDiagnoseTestDesc * kfgAscp = NULL;
2832     KDiagnoseTestDesc * kfgGap = NULL;
2833 
2834     if ( rc == 0 ) {
2835         rc = KDiagnoseTestDescMake ( & kfg, 1, "Configuration", KDIAGN_CONFIG );
2836         if ( rc == 0 )
2837             root -> child = kfg;
2838     }
2839     if ( rc == 0 ) {
2840         rc = KDiagnoseTestDescMake ( & kfgRemote, 2, "Remote repository",
2841                                      KDIAGN_REPO_REMOTE );
2842         if ( rc == 0 )
2843             kfg -> child = kfgRemote;
2844     }
2845     if ( rc == 0 ) {
2846         rc = KDiagnoseTestDescMake ( & kfgSite, 2, "Site repository",
2847                                      KDIAGN_REPO_SITE );
2848         if ( rc == 0 )
2849             kfgRemote -> next = kfgSite;
2850     }
2851     if ( rc == 0 ) {
2852         rc = KDiagnoseTestDescMake ( & kfgUser, 2, "Public user repository",
2853                                      KDIAGN_REPO_USER_PUBLIC );
2854         if ( rc == 0 )
2855             kfgSite -> next = kfgUser;
2856     }
2857     if ( rc == 0 ) {
2858         rc = KDiagnoseTestDescMake ( & kfgAscp, 2, "ascp transfer rate",
2859                                      KDIAGN_KFG_ASCP );
2860         if ( rc == 0 )
2861             kfgUser -> next = kfgAscp;
2862     }
2863     if ( rc == 0 ) {
2864         rc = KDiagnoseTestDescMake ( & kfgGap, 2, "DbGaP configuration",
2865                                      KDIAGN_REPO_GAP );
2866         if ( rc == 0 )
2867             kfgAscp -> next = kfgGap;
2868     }
2869   }
2870 
2871   if ( rc == 0 ) {
2872     rc = KDiagnoseTestDescMake ( & net, 1, "Network", KDIAGN_NETWORK );
2873     if ( rc == 0 )
2874         kfg -> next = net;
2875   }
2876 
2877   {
2878     KDiagnoseTestDesc * netNcbiHttp = NULL;
2879     KDiagnoseTestDesc * netNcbiHttps = NULL;
2880     KDiagnoseTestDesc * netNcbiFtp = NULL;
2881     KDiagnoseTestDesc * netNcbiVers = NULL;
2882     if ( rc == 0 ) {
2883         rc = KDiagnoseTestDescMake ( & netNcbi, 2, "Access to NCBI",
2884                                      KDIAGN_ACCESS_NCBI );
2885         if ( rc == 0 ) {
2886             net -> child = netNcbi;
2887             //netNcbi -> depends = kfgCommon;
2888         }
2889     }
2890     if ( rc == 0 ) {
2891         rc = KDiagnoseTestDescMake ( & netNcbiHttp, 3,
2892             "KNSManagerInitDNSEndpoint(www.ncbi.nlm.nih.gov:80)",
2893             KDIAGN_ACCESS_NCBI_HTTP );
2894         if ( rc == 0 ) {
2895             netNcbi -> child = netNcbiHttp;
2896         }
2897     }
2898     if ( rc == 0 ) {
2899         rc = KDiagnoseTestDescMake ( & netNcbiHttps, 3,
2900             "KNSManagerInitDNSEndpoint(www.ncbi.nlm.nih.gov:443)",
2901             KDIAGN_ACCESS_NCBI_HTTPS );
2902         if ( rc == 0 ) {
2903             netNcbiHttp -> next = netNcbiHttps;
2904         }
2905     }
2906 #define FTP "ftp-trace.ncbi.nlm.nih.gov"
2907     if ( rc == 0 ) {
2908         rc = KDiagnoseTestDescMake ( & netNcbiFtp, 3,
2909             "KNSManagerInitDNSEndpoint(" FTP ":443)", KDIAGN_ACCESS_NCBI_FTP );
2910         if ( rc == 0 ) {
2911             netNcbiHttps -> next = netNcbiFtp;
2912         }
2913     }
2914     if ( rc == 0 ) {
2915         rc = KDiagnoseTestDescMake ( & netNcbiVers, 3, "Access to "
2916             "'https://" FTP "/sra/sdk/current/sratoolkit.current.version'",
2917             KDIAGN_ACCESS_NCBI_VERSION );
2918         if ( rc == 0 ) {
2919             netNcbiFtp -> next = netNcbiVers;
2920         }
2921     }
2922   }
2923 
2924   if ( rc == 0 ) {
2925     rc = KDiagnoseTestDescMake ( & netHttp, 2, "HTTPS download",
2926                                      KDIAGN_HTTP );
2927     if ( rc == 0 ) {
2928         netNcbi -> next = netHttp;
2929 //      netHttp -> depends = netNcbi;
2930     }
2931   }
2932   {
2933     KDiagnoseTestDesc * netHttpRun = NULL;
2934     KDiagnoseTestDesc * netHttpCgi = NULL;
2935     KDiagnoseTestDesc * netHttpSmall = NULL;
2936     KDiagnoseTestDesc * netVfsSmall = NULL;
2937     if ( rc == 0 ) {
2938         rc = KDiagnoseTestDescMake ( & netHttpRun, 3, "HTTPS access to a run",
2939                                      KDIAGN_HTTP_RUN );
2940         if ( rc == 0 ) {
2941             netHttp -> child = netHttpRun;
2942         }
2943     }
2944     if ( rc == 0 ) {
2945         rc = KDiagnoseTestDescMake ( & netHttpCgi, 4, "Resolving of HTTPS path",
2946                                      KDIAGN_HTTP_CGI );
2947         if ( rc == 0 ) {
2948             netHttpRun -> child = netHttpCgi;
2949         }
2950     }
2951     if ( rc == 0 ) {
2952         rc = KDiagnoseTestDescMake ( & netHttpSmall, 4, "Access to a small run",
2953                                      KDIAGN_HTTP_SMALL_ACCESS );
2954         if ( rc == 0 ) {
2955             netHttpCgi -> next = netHttpSmall;
2956 //          netAscp -> depends = netNcbi;
2957         }
2958     }
2959     if ( rc == 0 ) {
2960         rc = KDiagnoseTestDescMake ( & netVfsSmall, 4,
2961             "VFSManagerOpenDirectoryRead(a small run)", KDIAGN_HTTP_SMALL_VFS );
2962         if ( rc == 0 ) {
2963             netHttpSmall -> next = netVfsSmall;
2964 //          netAscp -> depends = netNcbi;
2965         }
2966     }
2967   }
2968   if ( rc == 0 ) {
2969     rc = KDiagnoseTestDescMake ( & netAscp, 2, "Aspera download",
2970                                      KDIAGN_ASCP );
2971     if ( rc == 0 ) {
2972         netHttp -> next = netAscp;
2973 //      netAscp -> depends = netNcbi;
2974     }
2975   }
2976   {
2977     KDiagnoseTestDesc * netRun = NULL;
2978     KDiagnoseTestDesc * netCgi = NULL;
2979     KDiagnoseTestDesc * download = NULL;
2980 
2981     if ( rc == 0 ) {
2982         rc = KDiagnoseTestDescMake ( & netRun, 3, "Aspera access to a run",
2983                                      KDIAGN_ASCP_RUN );
2984         if ( rc == 0 ) {
2985             netAscp -> child = netRun;
2986         }
2987     }
2988     if ( rc == 0 ) {
2989         rc = KDiagnoseTestDescMake ( & netCgi, 4, "Resolving of FASP path",
2990                                      KDIAGN_ASCP_CGI );
2991         if ( rc == 0 ) {
2992             netRun -> child = netCgi;
2993         }
2994     }
2995     if ( rc == 0 ) {
2996         rc = KDiagnoseTestDescMake ( & download, 4, "ascp download test",
2997                                      KDIAGN_ASCP_DOWNLOAD );
2998         if ( rc == 0 ) {
2999             netCgi -> next = download;
3000         }
3001     }
3002   }
3003 
3004   if ( rc == 0 ) {
3005     rc = KDiagnoseTestDescMake ( & netHttpVsAscp, 2,
3006         "HTTP vs ASCP download", KDIAGN_HTTP_VS_ASCP );
3007     if ( rc == 0 ) {
3008         netAscp -> next = netHttpVsAscp;
3009     }
3010   }
3011 
3012   if ( rc != 0 )
3013     KDiagnoseTestDescRelease ( root );
3014   else
3015     self -> desc = root;
3016 
3017   return rc;
3018 }
3019 
3020 static const char DIAGNOSE_CLSNAME [] = "KDiagnose";
3021 
KDiagnoseMakeExt(KDiagnose ** test,KConfig * kfg,KNSManager * kmgr,VFSManager * vmgr,rc_t (CC * quitting)(void))3022 LIB_EXPORT rc_t CC KDiagnoseMakeExt ( KDiagnose ** test, KConfig * kfg,
3023     KNSManager * kmgr, VFSManager * vmgr, rc_t (CC *quitting)(void) )
3024 {
3025     rc_t rc = 0;
3026 
3027     KDiagnose * p = NULL;
3028 
3029     if ( test == NULL )
3030         return  RC ( rcRuntime, rcData, rcCreating, rcParam, rcNull );
3031 
3032     p = calloc ( 1, sizeof * p );
3033     if ( p == NULL )
3034         return RC ( rcRuntime, rcData, rcAllocating, rcMemory, rcExhausted );
3035 
3036     if ( kfg == NULL ) {
3037         rc_t r2 = KConfigMake ( & p -> kfg, NULL );
3038         if ( rc == 0 && r2 != 0 )
3039             rc = r2;
3040     }
3041     else {
3042         rc_t r2 = KConfigAddRef ( kfg );
3043         if ( r2 == 0 )
3044             p -> kfg = kfg;
3045         else if ( rc == 0 )
3046             rc = r2;
3047     }
3048 
3049     if ( kmgr == NULL ) {
3050         rc_t r2 = KNSManagerMake ( & p -> kmgr );
3051         if ( rc == 0 && r2 != 0 )
3052             rc = r2;
3053     }
3054     else {
3055         rc_t r2 = KNSManagerAddRef ( kmgr );
3056         if ( r2 == 0 )
3057             p -> kmgr = kmgr;
3058         else if ( rc == 0 )
3059             rc = r2;
3060     }
3061 
3062     if ( vmgr == NULL ) {
3063         rc_t r2 = VFSManagerMake ( & p -> vmgr );
3064         if ( rc == 0 && r2 != 0 )
3065             rc = r2;
3066     }
3067     else {
3068         rc_t r2 = VFSManagerAddRef ( vmgr );
3069         if ( r2 == 0 )
3070             p -> vmgr = vmgr;
3071         else if ( rc == 0 )
3072             rc = r2;
3073     }
3074 
3075     if ( rc == 0 )
3076         rc = KLockMake ( & p -> lock );
3077     if ( rc == 0 )
3078         rc = KConditionMake ( & p -> condition );
3079 
3080     if ( rc == 0 )
3081         rc = KDiagnoseMakeDesc ( p );
3082 
3083     if ( rc == 0 ) {
3084         p -> verbosity = KConfig_Verbosity ( p -> kfg );
3085         KRefcountInit ( & p -> refcount, 1, DIAGNOSE_CLSNAME, "init", "" );
3086         p -> quitting = quitting;
3087         AbuseInit ( & p -> report . abuse );
3088         * test = p;
3089     }
3090     else
3091         KDiagnoseRelease ( p );
3092 
3093     return rc;
3094 }
3095 
KDiagnoseAddRef(const KDiagnose * self)3096 LIB_EXPORT rc_t CC KDiagnoseAddRef ( const KDiagnose * self ) {
3097     if ( self != NULL )
3098         switch ( KRefcountAdd ( & self -> refcount, DIAGNOSE_CLSNAME ) ) {
3099             case krefLimit:
3100                 return RC ( rcRuntime,
3101                             rcData, rcAttaching, rcRange, rcExcessive );
3102         }
3103 
3104     return 0;
3105 }
3106 
errorWhack(void * item,void * data)3107 static void CC errorWhack ( void * item, void * data )
3108 {   KDiagnoseErrorWhack ( item ); }
testsWhack(void * item,void * data)3109 static void CC testsWhack ( void * item, void * data )
3110 {   KDiagnoseTestWhack ( item ); }
3111 
KDiagnoseRelease(const KDiagnose * cself)3112 LIB_EXPORT rc_t CC KDiagnoseRelease ( const KDiagnose * cself ) {
3113     rc_t rc = 0;
3114 
3115     KDiagnose * self = ( KDiagnose * ) cself;
3116 
3117     if ( self != NULL )
3118         switch ( KRefcountDrop ( & self -> refcount, DIAGNOSE_CLSNAME ) ) {
3119             case krefWhack:
3120                 RELEASE ( KConfig   , self -> kfg );
3121                 RELEASE ( KNSManager, self -> kmgr );
3122                 RELEASE ( VFSManager, self -> vmgr );
3123                 RELEASE ( KLock     , self -> lock );
3124                 RELEASE ( KCondition, self -> condition );
3125                 VectorWhack ( & self -> tests , & testsWhack, NULL );
3126                 VectorWhack ( & self -> errors, & errorWhack, NULL );
3127 
3128                 RELEASE ( KDiagnoseTestDesc, self -> desc  );
3129 
3130                 AbuseFini ( & self -> report . abuse );
3131 
3132                 free ( self );
3133                 break;
3134             case krefNegative:
3135                 return RC ( rcRuntime,
3136                             rcData, rcReleasing, rcRange, rcExcessive );
3137         }
3138 
3139     return rc;
3140 }
3141 
_KDiagnoseSetState(KDiagnose * self,enum EState state)3142 static rc_t _KDiagnoseSetState ( KDiagnose * self, enum EState state ) {
3143     rc_t rc = 0;
3144     rc_t r2 = 0;
3145 
3146     if ( self == NULL )
3147         return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );
3148 
3149     rc = KLockAcquire ( self -> lock );
3150 
3151     if ( rc == 0 ) {
3152         self -> state = state;
3153 
3154         rc = KConditionSignal ( self -> condition );
3155     }
3156 
3157     r2 = KLockUnlock ( self -> lock );
3158     if ( rc == 0 && r2 != 0 )
3159         rc = r2;
3160 
3161     return rc;
3162 }
3163 
KDiagnosePause(KDiagnose * self)3164 LIB_EXPORT rc_t CC KDiagnosePause  ( KDiagnose * self ) {
3165     return _KDiagnoseSetState ( self, ePaused );
3166 }
3167 
KDiagnoseResume(KDiagnose * self)3168 LIB_EXPORT rc_t CC KDiagnoseResume ( KDiagnose * self ) {
3169     return _KDiagnoseSetState ( self, eRunning );
3170 }
3171 
KDiagnoseCancel(KDiagnose * self)3172 LIB_EXPORT rc_t CC KDiagnoseCancel ( KDiagnose * self ) {
3173     return _KDiagnoseSetState ( self, eCanceled );
3174 }
3175 
KDiagnoseGetDesc(const KDiagnose * self,const KDiagnoseTestDesc ** desc)3176 LIB_EXPORT rc_t CC KDiagnoseGetDesc ( const KDiagnose * self,
3177     const KDiagnoseTestDesc ** desc )
3178 {
3179     if ( desc == NULL )
3180         return RC ( rcRuntime, rcData, rcAccessing, rcParam, rcNull );
3181 
3182     * desc = NULL;
3183 
3184     if ( self == NULL )
3185         return RC ( rcRuntime, rcData, rcAccessing, rcSelf, rcNull );
3186 
3187     * desc = self -> desc;
3188 
3189     return 0;
3190 }
3191 
STestKNSManagerInitDNSEndpoint(STest * self,uint64_t tests,const String * host,uint16_t port,bool warn)3192 static rc_t STestKNSManagerInitDNSEndpoint ( STest * self, uint64_t tests,
3193     const String * host, uint16_t port, bool warn )
3194 {
3195     rc_t rc = 0;
3196 
3197     KEndPoint ep;
3198 
3199     assert ( self && self -> dad );
3200 
3201     STestStart ( self, false, tests, "KNSManagerInitDNSEndpoint(%S:%hu)",
3202                                                           host, port );
3203     rc = KNSManagerInitDNSEndpoint ( self -> kmgr, & ep, host, port );
3204     if ( rc != 0 ) {
3205         self -> dad -> report . firewall = true;
3206         STestEnd ( self, warn ? eWarning : eEndFAIL, "%R", rc );
3207     }
3208     else {
3209         char endpoint [ 1024 ] = "";
3210         rc_t rx = endpoint_to_string ( endpoint, sizeof endpoint, & ep );
3211         if ( rx == 0 )
3212             STestEndOr ( self, & rx, eEndOK, "= '%s': OK", endpoint );
3213         if ( rx != 0 ) {
3214             if ( _RcCanceled ( rx ) )
3215                 STestEnd ( self, eCANCELED, "CANCELED" );
3216             else
3217                 STestEnd ( self, eEndFAIL, "CANNOT CONVERT TO STRING: %R", rx );
3218         }
3219     }
3220 
3221     return rc;
3222 }
3223 
STestCheckNcbiAccess(STest * self,uint64_t tests)3224 static rc_t STestCheckNcbiAccess ( STest * self, uint64_t tests ) {
3225     rc_t rc = 0;
3226 
3227     String www;
3228     CONST_STRING ( & www, "www.ncbi.nlm.nih.gov" );
3229 
3230     if ( tests & KDIAGN_ACCESS_NCBI_HTTP ) {
3231         rc_t r1 = STestKNSManagerInitDNSEndpoint ( self,
3232             KDIAGN_ACCESS_NCBI_HTTP, & www, 80, false );
3233         if ( rc == 0 && r1 != 0 )
3234             rc = r1;
3235     }
3236 
3237     if ( tests & KDIAGN_ACCESS_NCBI_HTTPS ) {
3238         rc_t r1 = STestKNSManagerInitDNSEndpoint ( self,
3239             KDIAGN_ACCESS_NCBI_HTTPS, & www, 443, false );
3240         if ( rc == 0 && r1 != 0 )
3241             rc = r1;
3242     }
3243 
3244     if ( tests & KDIAGN_ACCESS_NCBI_FTP ) {
3245         rc_t r1 = 0;
3246         String ftp;
3247 #define FTP "ftp-trace.ncbi.nlm.nih.gov"
3248         CONST_STRING ( & ftp, FTP );
3249         r1 = STestKNSManagerInitDNSEndpoint ( self,
3250             KDIAGN_ACCESS_NCBI_FTP, & ftp, 443, true );
3251         if ( r1 == 0 ) {
3252             Data v;
3253             r1 = DataInit ( & v, self -> vmgr, "https://" FTP
3254                             "/sra/sdk/current/sratoolkit.current.version" );
3255             if ( r1 == 0 ) {
3256                 uint64_t s = 0;
3257                 r1 = STestCheckUrl ( self, tests, KDIAGN_ACCESS_NCBI_VERSION,
3258                                      0, & v, "", & s, true, 0, 0, NULL );
3259             }
3260             DataFini ( & v );
3261         }
3262         /* ignore result: failure to access current.version is not an error */
3263     }
3264 
3265     return rc;
3266 }
3267 
STestWritableImpl(const STest * self,const char * path,bool dir)3268 static bool STestWritableImpl ( const STest * self,
3269                                 const char * path, bool dir )
3270 {
3271     char tmp [ PATH_MAX ] = "";
3272 
3273     int i = 0;
3274 
3275     if ( path == NULL )
3276         return false;
3277 
3278     assert ( self );
3279 
3280     if ( ! dir ) {
3281         rc_t rc = 0;
3282         KFile * f = NULL;
3283 
3284         if ( KDirectoryPathType ( self -> dir, path ) != kptNotFound ) {
3285             rc = KDirectoryRemove ( self -> dir, false, path );
3286             if ( rc != 0 )
3287                 return false;
3288         }
3289 
3290         rc = KDirectoryCreateFile ( self -> dir, & f, false,
3291                                     0775, kcmCreate | kcmParents, path);
3292         if ( rc != 0 )
3293             return false;
3294 
3295         RELEASE ( KFile, f );
3296 
3297         rc = KDirectoryRemove ( self -> dir, false, path );
3298         return rc == 0;
3299     }
3300 
3301     for ( i = 0; i <= 0; ++i ) {
3302         rc_t rc = string_printf ( tmp, sizeof tmp, NULL, "%s/tmp-ncbi-vdb%d",
3303                                                          path, i );
3304         if ( rc != 0 )
3305             return false;
3306 
3307         if ( KDirectoryPathType ( self -> dir, tmp ) != kptNotFound )
3308             continue;
3309 
3310         rc = KDirectoryCreateDir ( self -> dir,
3311                                    0775, kcmCreate | kcmParents, tmp );
3312         if ( rc == 0 ) {
3313             rc = KDirectoryRemove ( self -> dir, false, tmp );
3314             return rc == 0;
3315         }
3316         else
3317             return false;
3318     }
3319 
3320     return false;
3321 }
3322 
STestWritable(const STest * self,const char * path)3323 static bool STestWritable ( const STest * self, const char * path )
3324 {   return STestWritableImpl ( self, path, true ); }
3325 
STestCanCreate(const STest * self,const char * path)3326 static bool STestCanCreate ( const STest * self, const char * path )
3327 {   return STestWritableImpl ( self, path, false ); }
3328 
STestCache(const STest * self,const String * acc,char * cache,size_t sCache,const char * suffix)3329 static rc_t STestCache ( const STest * self, const String * acc,
3330     char * cache, size_t sCache, const char * suffix )
3331 {
3332     String rCache;
3333     VPath * path = NULL;
3334     rc_t rc = VFSManagerMakePath ( self -> vmgr, & path, "%S", acc );
3335 
3336     const VPath * vcache = NULL;
3337     if ( rc == 0 )
3338         rc = VResolverQuery ( self -> resolver, eProtocolHttps, path,
3339                               NULL, NULL, & vcache );
3340     if ( rc == 0 )
3341         rc = VPathGetPath ( vcache, & rCache );
3342     if ( rc == 0 ) {
3343         rc = string_printf ( cache, sCache, NULL, "%S.%s", & rCache, suffix );
3344         RELEASE ( VPath, vcache );
3345         if ( rc != 0 || ! STestCanCreate ( self, cache ) )
3346             cache [ 0 ] = '\0';
3347     }
3348     RELEASE ( VPath, path );
3349 
3350     if ( cache [ 0 ] == '\0' ) {
3351         const char * p = getenv ( "TMPDIR" );
3352         while ( cache [ 0 ] == '\0' ) {
3353             if ( STestWritable ( self, p ) )
3354                 break;
3355             p          = getenv ( "TEMP" );
3356             if ( STestWritable ( self, p ) )
3357                 break;
3358             p          = getenv ( "TMP" );
3359             if ( STestWritable ( self, p ) )
3360                 break;
3361             p          = getenv ( "TEMPDIR" );
3362             if ( STestWritable ( self, p ) )
3363                 break;
3364             p = NULL;
3365             break;
3366         }
3367         if ( p != NULL ) {
3368             rc = string_printf ( cache, sCache, NULL, "%s/%S.%s",
3369                                                       p, acc, suffix );
3370             if ( rc != 0 )
3371                 cache [ 0 ] = '\0';
3372         }
3373     }
3374 
3375     if ( cache [ 0 ] == '\0' ) {
3376         String * p = NULL;
3377         rc = KConfigReadString ( self -> kfg,
3378                                  "/repository/user/default-path", & p );
3379         if ( rc == 0 && STestWritable ( self, p -> addr ) ) {
3380             rc = string_printf ( cache, sCache, NULL, "%S/%S.%s",
3381                                                       p, acc, suffix );
3382             free ( p );
3383         }
3384         if ( rc != 0 )
3385             cache [ 0 ] = '\0';
3386     }
3387 
3388     if ( cache [ 0 ] == '\0' ) {
3389         String * p = NULL;
3390         rc = KConfigReadString ( self -> kfg, "NCBI_HOME", & p );
3391         if ( rc == 0 && STestWritable ( self, p -> addr ) ) {
3392             rc = string_printf ( cache, sCache, NULL, "%S/%S.%s",
3393                                                       p, acc, suffix );
3394             free ( p );
3395         }
3396         if ( rc != 0 )
3397             cache [ 0 ] = '\0';
3398     }
3399 
3400     if ( cache [ 0 ] == '\0' ) {
3401         String * p = NULL;
3402         rc = KConfigReadString ( self -> kfg, "HOME", & p );
3403         if ( rc == 0 && STestWritable ( self, p -> addr ) ) {
3404             rc = string_printf ( cache, sCache, NULL, "%S/%S.%s",
3405                                                       p, acc, suffix );
3406             free ( p );
3407         }
3408         if ( rc != 0 )
3409             cache [ 0 ] = '\0';
3410     }
3411 
3412     if ( cache [ 0 ] == '\0' ) {
3413         rc = string_printf ( cache, sCache, NULL, "%S/%s", acc, suffix );
3414         if ( rc != 0 )
3415             cache [ 0 ] = '\0';
3416         else if ( ! STestWritable ( self, "." ) ) {
3417             cache [ 0 ] = '\0';
3418             rc = RC ( rcRuntime,
3419                       rcDirectory, rcAccessing, rcDirectory, rcUnauthorized );
3420         }
3421     }
3422 
3423     return rc;
3424 }
3425 
STestCheckHttp(STest * self,uint64_t tests,const String * acc,bool print,char * downloaded,size_t sDownloaded,uint64_t * downloadedSize,const char ** exp,size_t esz,bool * tooBig)3426 static rc_t STestCheckHttp ( STest * self, uint64_t tests, const String * acc,
3427     bool print,
3428     char * downloaded, size_t sDownloaded, uint64_t * downloadedSize,
3429     const char ** exp, size_t esz, bool * tooBig )
3430 {
3431     rc_t rc = 0;
3432     char response [ 4096 ] = "";
3433     size_t resp_len = 0;
3434     const char * url = NULL;
3435     bool failed = false;
3436     uint64_t atest = KDIAGN_HTTP_RUN;
3437     STestStart ( self, true, atest,
3438                  "HTTPS access to '%S'", acc );
3439     if ( tests & KDIAGN_HTTP_CGI )
3440         rc = STestCallCgi ( self, KDIAGN_HTTP_CGI, acc,
3441             response, sizeof response, & resp_len, & url, true );
3442 
3443     if ( rc == 0 ) {
3444         rc = STestCache ( self, acc, downloaded, sDownloaded, "http" );
3445         if ( rc != 0 )
3446             STestFail ( self, rc, 0, "Cannot find cache location" );
3447     }
3448     if ( rc == 0 && url != NULL ) {
3449         char * p = string_chr ( url, resp_len - ( url - response ), '|' );
3450         if ( p == NULL ) {
3451             rc = RC ( rcRuntime,
3452                         rcString ,rcParsing, rcString, rcIncorrect );
3453             STestFail ( self, rc, 0, "UNEXPECTED RESOLVER RESPONSE" );
3454             failed = true;
3455         }
3456         else {
3457             Data dt;
3458             * p = '\0';
3459             rc = DataInit ( & dt, self -> vmgr, url );
3460             if ( rc == 0 ) {
3461                 rc_t r1 = STestCheckUrl ( self,
3462                     tests, KDIAGN_HTTP_SMALL_ACCESS, KDIAGN_HTTP_SMALL_VFS,
3463                     & dt, downloaded, downloadedSize, print, exp, esz, tooBig );
3464                 if ( rc == 0 && r1 != 0 ) {
3465                     assert ( downloaded );
3466                     * downloaded = '\0';
3467                     rc = r1;
3468                 }
3469             }
3470             DataFini ( & dt );
3471         }
3472     }
3473 
3474     if ( ! failed ) {
3475         if ( rc == 0 )
3476             rc = STestEnd ( self, eOK,  "HTTPS access to '%S'", acc );
3477         else if ( _RcCanceled ( rc ) )
3478             STestEnd ( self, eCANCELED, "HTTPS access to '%S': CANCELED", acc );
3479         else
3480             STestEnd ( self, eFAIL,     "HTTPS access to '%S'", acc );
3481     }
3482     return rc;
3483 }
3484 
STestCheckFasp(STest * self,uint64_t tests,const String * acc,bool print,char * downloaded,size_t sDownloaded,uint64_t * downloadedSize)3485 static rc_t STestCheckFasp ( STest * self, uint64_t tests, const String * acc,
3486     bool print, char * downloaded, size_t sDownloaded,
3487     uint64_t * downloadedSize )
3488 {
3489     rc_t rc = 0;
3490     char response [ 4096 ] = "";
3491     size_t resp_len = 0;
3492     const char * url = NULL;
3493     bool failed = false;
3494     uint64_t atest = KDIAGN_ASCP_RUN;
3495     STestStart ( self, true, atest, "Aspera access to '%S'", acc );
3496     if ( tests & KDIAGN_ASCP_CGI )
3497         rc = STestCallCgi ( self, KDIAGN_ASCP_CGI, acc,
3498             response, sizeof response, & resp_len, & url, false );
3499 
3500     if ( tests & KDIAGN_DOWNLOAD_ASCP ) {
3501         if ( rc == 0 ) {
3502             rc = STestCache ( self, acc, downloaded, sDownloaded, "fasp" );
3503             if ( rc != 0 )
3504                 STestFail ( self, rc, 0, "Cannot find cache location" );
3505         }
3506         if ( rc == 0 && url != NULL ) {
3507             char * p = string_chr ( url, resp_len - ( url - response ), '|' );
3508             if ( p == NULL ) {
3509                 rc = RC ( rcRuntime,
3510                           rcString ,rcParsing, rcString, rcIncorrect );
3511                 STestFail ( self, rc, 0, "UNEXPECTED RESOLVER RESPONSE" );
3512                 failed = true;
3513             }
3514             else {
3515                 Data dt;
3516                 * p = '\0';
3517                 rc = DataInit ( & dt, self -> vmgr, url );
3518                 if ( rc == 0 ) {
3519                     rc_t r1 = STestCheckFaspDownload ( self, url, downloaded,
3520                                                        downloadedSize );
3521                     if ( rc == 0 && r1 != 0 ) {
3522                         assert ( downloaded );
3523                         * downloaded = '\0';
3524                         rc = r1;
3525                     }
3526                 }
3527                 DataFini ( & dt );
3528             }
3529         }
3530     }
3531 
3532     if ( ! failed ) {
3533         if ( rc == 0 )
3534             rc = STestEnd ( self, eOK,  "Aspera access to '%S'", acc );
3535         else if ( _RcCanceled ( rc ) )
3536             STestEnd ( self, eCANCELED, "Aspera access to '%S': CANCELED",
3537                                         acc );
3538         else
3539             STestEnd ( self, eFAIL,     "Aspera access to '%S'", acc );
3540     }
3541     return rc;
3542 }
3543 
3544 static
STestHttpVsFasp(STest * self,const char * http,uint64_t httpSize,const char * fasp,uint64_t faspSize)3545 rc_t STestHttpVsFasp ( STest * self, const char * http, uint64_t httpSize,
3546                        const char * fasp, uint64_t faspSize )
3547 {
3548     rc_t rc = 0;
3549     uint64_t pos = 0;
3550     const KFile * ascpF = NULL;
3551     const KFile * httpF = NULL;
3552     STestStart ( self, false, KDIAGN_HTTP_VS_ASCP, "HTTP vs ASCP download:" );
3553     if ( httpSize != faspSize ) {
3554         rc = RC ( rcRuntime, rcFile, rcComparing, rcSize, rcUnequal );
3555         STestEnd ( self, eEndFAIL, "size does not match: "
3556                    "http(%lu)/ascp(%lu)", httpSize, faspSize );
3557     }
3558     else {
3559         rc = KDirectoryOpenFileRead ( self -> dir, & httpF, http );
3560         if ( rc != 0 )
3561             STestEnd ( self, eEndFAIL, "cannot open '%s'; %R", http, rc );
3562         else {
3563             rc = KDirectoryOpenFileRead ( self -> dir, & ascpF, fasp );
3564             if ( rc != 0 )
3565                 STestEnd ( self, eEndFAIL, "cannot open '%s'; %R", fasp, rc );
3566         }
3567     }
3568     if ( rc == 0 ) {
3569         char bAscp [ 1024 ] = "";
3570         char bHttp [ 1024 ] = "";
3571         size_t ascp_read = 0;
3572         size_t http_read = 0;
3573         while ( rc == 0 ) {
3574             rc = KFileReadAll ( ascpF, pos, bAscp, sizeof bAscp, & ascp_read );
3575             if ( rc != 0 ) {
3576                 STestEnd ( self, eEndFAIL, "cannot read '%s': %R",
3577                                           fasp, rc );
3578                 break;
3579             }
3580             rc = KFileReadAll ( httpF, pos, bHttp, sizeof bHttp, & http_read );
3581             if ( rc != 0 ) {
3582                 STestEnd ( self, eEndFAIL, "cannot read '%s': %R",
3583                                           http, rc );
3584                 break;
3585             }
3586             else if ( ascp_read != http_read ) {
3587                 rc = RC ( rcRuntime, rcFile, rcComparing, rcSize, rcUnequal );
3588                 STestEnd ( self, eEndFAIL,
3589                            "cannot read the same amount from files" );
3590                 break;
3591             }
3592             else if ( ascp_read == 0 )
3593                 break;
3594             else {
3595                 pos += ascp_read;
3596                 if ( string_cmp ( bAscp, ascp_read,
3597                                   bHttp, http_read, (uint32_t)ascp_read ) != 0 )
3598                 {
3599                     rc = RC ( rcRuntime,
3600                               rcFile, rcComparing, rcData, rcUnequal );
3601                     STestEnd ( self, eEndFAIL, "files are different" );
3602                     break;
3603                 }
3604             }
3605         }
3606     }
3607     RELEASE ( KFile, ascpF );
3608     RELEASE ( KFile, httpF );
3609     if ( rc == 0 )
3610         rc = STestEnd ( self, eEndOK, "%lu bytes compared: OK", pos );
3611     return rc;
3612 }
3613 
StringRelease(String * self)3614 static rc_t StringRelease ( String * self ) {
3615     if ( self != NULL )
3616         free ( self );
3617     return 0;
3618 }
3619 
3620 /*static rc_t STestWarning ( STest * self,
3621                            const char * msg, const char * fmt, ... )
3622 {
3623     rc_t rc = 0;
3624 
3625     va_list args;
3626     va_start ( args, fmt );
3627 
3628     rc = STestVStart ( self, false, fmt, args );
3629     STestEnd ( self, eMSG, "WARNING: %s", msg );
3630     if ( CALL_BACK )
3631         CALL_BACK ( eKDTS_Warning, self -> crnt );
3632     rc = STestEnd ( self, eWarning, "" );
3633 
3634     va_end ( args );
3635 
3636     return rc;
3637 }*/
3638 
STestCheckNodeExists(STest * self,uint64_t code,const char * path,const char * msg,const char * fmt,String ** value)3639 static rc_t STestCheckNodeExists ( STest * self, uint64_t code,
3640     const char * path, const char * msg, const char * fmt, String ** value )
3641 {
3642     String * p = NULL;
3643     rc_t rc = KConfigReadString ( self -> kfg, path, & p );
3644 
3645     STestStart ( self, false, code, fmt );
3646 
3647     if ( rc != 0 ) {
3648         if ( rc != SILENT_RC ( rcKFG, rcNode, rcOpening, rcPath, rcNotFound ) )
3649             STestEnd ( self, eEndFAIL, "cannot read '%s': %R", path, rc );
3650         else {
3651             STestEnd ( self, eWarning, msg );
3652             rc = 0;
3653         }
3654 
3655         p = NULL;
3656     }
3657 
3658     if ( value != NULL )
3659         * value = p;
3660     else {
3661         STestEnd ( self, eEndOK, "'%S': OK", p );
3662         RELEASE ( String, p );
3663     }
3664 
3665     return rc;
3666 }
3667 
STestCheckRemoteRepoKfg(STest * self,bool * exists)3668 static rc_t STestCheckRemoteRepoKfg ( STest * self, bool * exists ) {
3669     rc_t rc = 0;
3670     rc_t r1 = 0;
3671     String * p = NULL;
3672     assert ( exists );
3673     * exists = false;
3674     STestStart ( self, true, KDIAGN_REPO_REMOTE, "Remote repository" );
3675     {
3676         bool printed = false;
3677         const char * path = "/repository/remote/disabled";
3678         rc_t r1 = KConfigReadString ( self -> kfg, path, & p );
3679         STestStart ( self, false, 0, "Remote repository disabled:" );
3680         if ( r1 != 0 ) {
3681             if ( r1 !=
3682                  SILENT_RC ( rcKFG, rcNode, rcOpening, rcPath, rcNotFound ) )
3683             {
3684                 STestEnd ( self, eEndFAIL, "cannot read '%s': %R", path, r1 );
3685                 printed = true;
3686                 if ( rc == 0 )
3687                     rc = r1;
3688             }
3689         }
3690         else {
3691             String sTrue;
3692             CONST_STRING ( & sTrue, "true" );
3693             if ( StringEqual ( p, & sTrue ) ) {
3694                 STestEnd ( self, eWarning, "Remote repository is disabled" );
3695                 printed = true;
3696             }
3697             RELEASE ( String, p );
3698         }
3699         if ( ! printed )
3700             STestEnd ( self, eEndOK, "false: OK" );
3701     }
3702     {
3703         bool printed = false;
3704         const char * path = "/repository/remote/main/CGI/resolver-cgi";
3705         rc_t r1 = KConfigReadString ( self -> kfg, path, & p );
3706         STestStart ( self, false, 0, "Main resolver-cgi:" );
3707         if ( r1 != 0 ) {
3708             if ( r1 !=
3709                  SILENT_RC ( rcKFG, rcNode, rcOpening, rcPath, rcNotFound ) )
3710             {
3711                 STestEnd ( self, eEndFAIL, "cannot read '%s': %R", path, r1 );
3712                 printed = true;
3713                 if ( rc == 0 )
3714                     rc = r1;
3715             }
3716             else {
3717                 STestEnd ( self, eWarning, "Main resolver-cgi is not set" );
3718                 printed = true;
3719             }
3720         }
3721         else {
3722             String c, f, t;
3723             CONST_STRING ( & c,
3724                 "https://www.ncbi.nlm.nih.gov/Traces/names/names.cgi" );
3725             CONST_STRING ( & f,
3726                 "https://www.ncbi.nlm.nih.gov/Traces/names/names.fcgi" );
3727             CONST_STRING ( & t,
3728                 "https://trace.ncbi.nlm.nih.gov/Traces/names/names.fcgi" );
3729             if ( ! StringEqual ( p, & f ) && ! StringEqual ( p, & c ) &&
3730                  ! StringEqual ( p, & t ))
3731             {
3732                 STestEnd ( self, eWarning,
3733                     "Main resolver-cgi is not standard: '%S'", p );
3734                 printed = true;
3735             }
3736             RELEASE ( String, p );
3737 
3738             * exists = true;
3739         }
3740         if ( ! printed )
3741             STestEnd ( self, eEndOK, "OK" );
3742     }
3743     r1 = STestEnd ( self, rc == 0 ? eOK : eFAIL, "Remote repository" );
3744     if ( rc == 0 && r1 != 0 )
3745         rc = r1;
3746     return rc;
3747 }
3748 
STestCheckSiteRepoKfg(STest * self,bool * exists)3749 static rc_t STestCheckSiteRepoKfg ( STest * self, bool * exists ) {
3750     bool printed = false;
3751     bool hasNode = true;
3752 #define SITE "/repository/site"
3753     const char * path = SITE;
3754     const KConfigNode * node = NULL;
3755     String * p = NULL;
3756     rc_t rc = KConfigOpenNodeRead ( self -> kfg, & node, path );
3757     assert ( exists );
3758     * exists = false;
3759     STestStart ( self, false, KDIAGN_REPO_SITE, "Site repository:" );
3760     if ( rc != 0 ) {
3761         if ( rc != SILENT_RC ( rcKFG, rcNode, rcOpening,
3762                                 rcPath, rcNotFound ) )
3763         {
3764             STestEnd ( self, eEndFAIL, "cannot read '%s': %R", path, rc );
3765             printed = true;
3766         }
3767         else {
3768             hasNode = false;
3769             rc = 0;
3770             STestEnd ( self, eEndOK, "not found: OK" );
3771             printed = true;
3772         }
3773     }
3774     if ( hasNode ) {
3775         KNamelist * names = NULL;
3776         uint32_t count = 0;
3777         if ( rc == 0 ) {
3778             rc = KConfigNodeListChildren ( node, & names );
3779             if ( rc != 0 ) {
3780                 STestEnd ( self, eEndFAIL,
3781                            "cannot list children of '%s': %R", path, rc );
3782                 printed = true;
3783             }
3784         }
3785         if ( rc == 0 ) {
3786             rc = KNamelistCount ( names, & count );
3787             if ( rc != 0 ) {
3788                 STestEnd ( self, eEndFAIL,
3789                            "cannot count children of '%s': %R", path, rc );
3790                 printed = true;
3791             }
3792             else if ( count > 0 )
3793                 * exists = true;
3794         }
3795         if ( rc == 0 ) {
3796             const char * path = SITE "/disabled";
3797             rc = KConfigReadString ( self -> kfg, path, & p );
3798             if ( rc != 0 ) {
3799                 if ( rc != SILENT_RC ( rcKFG, rcNode, rcOpening,
3800                                        rcPath, rcNotFound ) )
3801                 {
3802                     STestEnd ( self, eEndFAIL, "cannot read '%s': %R",
3803                                                             path, rc );
3804                     printed = true;
3805                 }
3806                 else
3807                     rc = 0;
3808             }
3809             else {
3810                 String sTrue;
3811                 CONST_STRING ( & sTrue, "true" );
3812                 if ( StringEqual ( p, & sTrue ) ) {
3813                     * exists = false;
3814                     if ( count > 1 ) {
3815                         STestEnd ( self, eWarning,
3816                                    "Site repository is disabled" );
3817                         printed = true;
3818                     }
3819                 }
3820                 RELEASE ( String, p );
3821             }
3822         }
3823         RELEASE ( KNamelist, names );
3824     }
3825     RELEASE ( KConfigNode, node );
3826     if ( ! printed )
3827         STestEnd ( self, eEndOK, "OK" );
3828     return rc;
3829 }
3830 
STestCheckUserRepoKfg(STest * self,bool * exists)3831 static rc_t STestCheckUserRepoKfg ( STest * self, bool * exists ) {
3832     rc_t rc = 0;
3833     rc_t r1 = 0;
3834     String * p = NULL;
3835     assert ( exists );
3836     * exists = false;
3837     STestStart ( self, true, KDIAGN_REPO_USER_PUBLIC,
3838                  "Public user repository" );
3839     {
3840         bool printed = false;
3841         const char * path = "/repository/user/cache-disabled";
3842         rc_t r1 = KConfigReadString ( self -> kfg, path, & p );
3843         STestStart ( self, false, 0, "User repository caching:" );
3844         if ( r1 != 0 ) {
3845             if ( r1 !=
3846                  SILENT_RC ( rcKFG, rcNode, rcOpening, rcPath, rcNotFound ) )
3847             {
3848                 STestEnd ( self, eEndFAIL, "cannot  read '%s': %R", path, r1 );
3849                 printed = true;
3850                 if ( rc == 0 )
3851                     rc = r1;
3852             }
3853         }
3854         else {
3855             String sTrue;
3856             CONST_STRING ( & sTrue, "true" );
3857             if ( StringEqual ( p, & sTrue ) ) {
3858                 STestEnd ( self, eWarning,
3859                            "User repository caching is disabled" );
3860                 printed = true;
3861             }
3862             RELEASE ( String, p );
3863         }
3864         if ( ! printed )
3865             STestEnd ( self, eEndOK, "enabled: OK" );
3866     }
3867     {
3868         const char * path = "/repository/user/main/public";
3869         const KConfigNode * node = NULL;
3870         rc_t r1 = KConfigOpenNodeRead ( self -> kfg, & node, path );
3871         if ( r1 == 0 )
3872             * exists = true;
3873         else if ( r1 != SILENT_RC
3874                         ( rcKFG, rcNode, rcOpening, rcPath, rcNotFound ) )
3875         {
3876             STestFail ( self, r1, 0, "Failed to read '%s'", path );
3877             if ( rc == 0 )
3878                 rc = r1;
3879         }
3880         RELEASE ( KConfigNode, node );
3881     }
3882     r1 = STestCheckNodeExists ( self, 0,
3883         "/repository/user/main/public/apps/file/volumes/flat",
3884         "User repository is incomplete", "User repository file app:", NULL );
3885     if ( r1 != 0 && rc == 0 )
3886         rc = r1;
3887 
3888     r1 = STestCheckNodeExists ( self, 0,
3889         "/repository/user/main/public/apps/nakmer/volumes/nakmerFlat",
3890         "User repository is incomplete", "User repository nakmer app:", NULL );
3891     if ( r1 != 0 && rc == 0 )
3892         rc = r1;
3893 
3894     r1 = STestCheckNodeExists ( self, 0,
3895         "/repository/user/main/public/apps/nannot/volumes/nannotFlat",
3896         "User repository is incomplete", "User repository nannot app:", NULL );
3897     if ( r1 != 0 && rc == 0 )
3898         rc = r1;
3899 
3900     {
3901         r1 = STestCheckNodeExists ( self, 0,
3902             "/repository/user/main/public/apps/refseq/volumes/refseq",
3903             "User repository is incomplete", "User repository refseq app:",
3904             & p );
3905         if ( r1 != 0 ) {
3906             if ( rc == 0 )
3907                 rc = r1;
3908         }
3909         else if ( p == NULL )
3910             * exists = false;
3911         else
3912             STestEnd ( self, eEndOK, "'%S': OK", p );
3913         RELEASE ( String, p );
3914     }
3915     {
3916         r1 = STestCheckNodeExists ( self, 0,
3917             "/repository/user/main/public/apps/sra/volumes/sraFlat",
3918             "User repository is incomplete", "User repository sra app:", & p );
3919         if ( r1 != 0 ) {
3920             if ( rc == 0 )
3921                 rc = r1;
3922         }
3923         else if ( p == NULL )
3924             * exists = false;
3925         else
3926             STestEnd ( self, eEndOK, "'%S': OK", p );
3927         RELEASE ( String, p );
3928     }
3929 
3930     r1 = STestCheckNodeExists ( self, 0,
3931         "/repository/user/main/public/apps/wgs/volumes/wgsFlat",
3932         "User repository is incomplete", "User repository wgs app:", NULL );
3933     if ( r1 != 0 && rc == 0 )
3934         rc = r1;
3935 
3936     {
3937         bool user = false;
3938         r1 = STestCheckNodeExists ( self, 0,
3939             "/repository/user/main/public/root",
3940             "User repository's root path is not set",
3941             "User repository root path:",
3942             & p );
3943         if ( r1 != 0 ) {
3944             if ( rc == 0 )
3945                 rc = r1;
3946         }
3947         else if ( p != NULL ) {
3948             if ( p -> size == 0 )
3949                 STestEnd ( self, eWarning,
3950                            "User repository's root path is empty" );
3951             else {
3952                 KPathType type = kptFirstDefined;
3953                 type = KDirectoryPathType ( self -> dir, p -> addr )
3954                         & ~ kptAlias;
3955                 if ( type == kptNotFound )
3956                     STestEnd ( self, eWarning,
3957                         "User repository's root path does not exist: '%S'", p );
3958                 else if ( type != kptDir )
3959                     STestEnd ( self, eWarning,
3960                         "User repository's root path is not a directory: '%S'",
3961                         p );
3962                 else {
3963                     STestEnd ( self, eEndOK, "'%S': OK", p );
3964                     user = true;
3965                 }
3966             }
3967             RELEASE ( String, p );
3968         }
3969         if ( ! user )
3970             * exists  = false;
3971     }
3972     r1 = STestEnd ( self, rc == 0 ? eOK : eFAIL, "Public user repository" );
3973     if ( rc == 0 && r1 != 0 )
3974         rc = r1;
3975     return rc;
3976 }
3977 
STestCheckNoGapKfg(STest * self,uint64_t tests)3978 static rc_t STestCheckNoGapKfg ( STest * self, uint64_t tests ) {
3979     rc_t rc = 0;
3980     rc_t r1 = 0;
3981     bool rRemote = false;
3982     bool rSite  = false;
3983     bool rUser  = false;
3984     if ( tests & KDIAGN_REPO_REMOTE ) {
3985         rc_t r1 = STestCheckRemoteRepoKfg ( self, & rRemote );
3986         if ( rc == 0 && r1 != 0 )
3987             rc = r1;
3988     }
3989     if ( tests & KDIAGN_REPO_SITE ) {
3990         rc_t r1 = STestCheckSiteRepoKfg ( self, & rSite );
3991         if ( rc == 0 && r1 != 0 )
3992             rc = r1;
3993     }
3994     if ( tests & KDIAGN_REPO_USER_PUBLIC ) {
3995         rc_t r1 = STestCheckUserRepoKfg ( self, & rUser );
3996         if ( rc == 0 && r1 != 0 )
3997             rc = r1;
3998     }
3999     if ( tests & KDIAGN_KFG_ASCP ) {
4000         r1 = STestCheckNodeExists ( self, KDIAGN_KFG_ASCP,
4001             "/tools/ascp/max_rate",
4002             "ascp max transfer rate is not set", "ascp transfer rate:", NULL );
4003         if ( r1 != 0 && rc == 0 )
4004             rc = r1;
4005     }
4006 
4007     if ( ! rRemote && ! rSite && ! rUser ) {
4008         if ( rc == 0 )
4009             rc = RC ( rcRuntime, rcNode, rcValidating, rcNode, rcInsufficient );
4010         STestFail ( self, rc, 0, "No repositories in configuration: " );
4011     }
4012 
4013     return rc;
4014 }
4015 
STestCheckGapKfg(STest * self,uint64_t tests)4016 static rc_t STestCheckGapKfg ( STest * self, uint64_t tests ) {
4017     rc_t rc = 0;
4018     String * p = NULL;
4019     {
4020         bool printed = false;
4021         const char * path = "/repository/remote/protected/CGI/resolver-cgi";
4022         rc_t r1 = KConfigReadString ( self -> kfg, path, & p );
4023         STestStart ( self, false, 0, "Protected resolver-cgi:" );
4024         if ( r1 != 0 ) {
4025             if ( r1 !=
4026                  SILENT_RC ( rcKFG, rcNode, rcOpening, rcPath, rcNotFound ) )
4027             {
4028                 STestEnd ( self, eEndFAIL, "cannot  read '%s': %R", path, r1 );
4029                 printed = true;
4030                 if ( rc == 0 )
4031                     rc = r1;
4032             }
4033             else {
4034                 STestEnd ( self, eEndOK, "not set: OK" );
4035                 printed = true;
4036             }
4037         }
4038         else {
4039             String c, f, t;
4040             CONST_STRING ( & c,
4041                 "https://www.ncbi.nlm.nih.gov/Traces/names/names.cgi" );
4042             CONST_STRING ( & f,
4043                 "https://www.ncbi.nlm.nih.gov/Traces/names/names.fcgi" );
4044             CONST_STRING ( & t,
4045                 "https://trace.ncbi.nlm.nih.gov/Traces/names/names.fcgi" );
4046             if ( ! StringEqual ( p, & f ) && ! StringEqual ( p, & c ) &&
4047                  ! StringEqual ( p, & t ))
4048             {
4049                 STestEnd ( self, eWarning,
4050                            "Protected resolver-cgi is not standard: '%S'", p );
4051                 printed = true;
4052             }
4053             RELEASE ( String, p );
4054         }
4055         if ( ! printed )
4056             STestEnd ( self, eEndOK, "OK" );
4057     }
4058     {
4059         const char * path = "/repository/user/protected";
4060         const KConfigNode * nProtected = NULL;
4061         rc_t r1 = KConfigOpenNodeRead ( self -> kfg, & nProtected, path );
4062         if ( r1 != 0 ) {
4063             if ( r1 != SILENT_RC ( rcKFG, rcNode, rcOpening,
4064                                    rcPath, rcNotFound ) )
4065             {
4066                 STestFail ( self, r1, 0,
4067                     "Protected repositories: failed to read '%s'", path );
4068                 if ( rc == 0 )
4069                     rc = r1;
4070             }
4071             else {
4072                 STestStart ( self, false, 0, "Protected repositories:" );
4073                 STestEnd ( self, eEndOK, "not found: OK" );
4074             }
4075         }
4076         else {
4077             bool printed = false;
4078             rc_t r1 = 0;
4079             KNamelist * names = NULL;
4080             uint32_t count = 0;
4081             STestStart ( self, true, 0, "Protected repositories" );
4082             if ( r1 == 0 ) {
4083                 r1 = KConfigNodeListChildren ( nProtected, & names );
4084                 if ( r1 != 0 ) {
4085                     STestEnd ( self, eEndFAIL,
4086                         "cannot list children of '%s': %R", path, r1 );
4087                     printed = true;
4088                 }
4089             }
4090             if ( r1 == 0 ) {
4091                 r1 = KNamelistCount ( names, & count );
4092                 if ( r1 != 0 ) {
4093                     STestEnd ( self, eEndFAIL,
4094                         "cannot count children of '%s': %R", path, r1 );
4095                     printed = true;
4096                 }
4097             }
4098             if ( r1 == 0 ) {
4099                 uint32_t i = 0;
4100                 for ( i = 0; i < count; ++ i ) {
4101                     const KConfigNode * node = NULL;
4102                     const char * name = NULL;
4103                     r1 = KNamelistGet ( names, i, & name );
4104                     if ( r1 != 0 ) {
4105                         STestEnd ( self, eEndFAIL,
4106                             "cannot get child of '%s': %R", path, r1 );
4107                         printed = true;
4108                         break;
4109                     }
4110                     STestStart ( self, true, 0, name );
4111                     {
4112                         rc_t r2 = KConfigOpenNodeRead ( self -> kfg, & node,
4113                             "%s/%s/apps/file/volumes/flat", path, name );
4114                         STestStart ( self, false, 0, "%s file app:", name );
4115                         if ( r2 != 0 ) {
4116                             if ( r2 != SILENT_RC ( rcKFG, rcNode, rcOpening,
4117                                                    rcPath, rcNotFound ) )
4118                                 STestEnd ( self, eEndFAIL, "cannot read "
4119                                     "'%s/%s/apps/file/volumes/flat': %R",
4120                                     path, name, r2 );
4121                             else {
4122                                 self -> dad -> report . incompleteGapKfg = true;
4123                                 STestEnd ( self, tests & KDIAGN_TRY_TO_WARN
4124                                                     ? eWarning : eEndFAIL,
4125                                            "not found" );
4126                             }
4127                         }
4128                         else
4129                             STestEnd ( self, eEndOK, "OK" );
4130                         RELEASE ( KConfigNode, node );
4131                         if ( r2 != 0 && r1 == 0 )
4132                             r1 = r2;
4133                     }
4134                     {
4135                         rc_t r2 = KConfigOpenNodeRead ( self -> kfg, & node,
4136                             "%s/%s/apps/sra/volumes/sraFlat", path, name );
4137                         STestStart ( self, false, 0, "%s sra app:", name );
4138                         if ( r2 != 0 ) {
4139                             if ( r2 != SILENT_RC ( rcKFG, rcNode, rcOpening,
4140                                                    rcPath, rcNotFound ) )
4141                                 STestEnd ( self, eEndFAIL, "cannot read "
4142                                     "'%s/%s/apps/sra/volumes/sraFlat': %R",
4143                                     path, name, r2 );
4144                             else {
4145                                 self -> dad -> report . incompleteGapKfg = true;
4146                                 STestEnd ( self, tests & KDIAGN_TRY_TO_WARN
4147                                                     ? eWarning : eEndFAIL,
4148                                            "not found" );
4149                             }
4150                         }
4151                         else
4152                             STestEnd ( self, eEndOK, "OK" );
4153                         RELEASE ( KConfigNode, node );
4154                         if ( r2 != 0 && r1 == 0 )
4155                             r1 = r2;
4156                     }
4157                     {
4158                         rc_t r2 = KConfigOpenNodeRead ( self -> kfg, & node,
4159                             "%s/%s/cache-enabled", path, name );
4160                         STestStart ( self, false, 0, "%s caching:", name );
4161                         if ( r2 != 0 ) {
4162                             if ( r2 != SILENT_RC ( rcKFG, rcNode, rcOpening,
4163                                                    rcPath, rcNotFound ) )
4164                                 STestEnd ( self, eEndFAIL, "cannot open "
4165                                     "'%s/%s/cache-enabled': %R",
4166                                     path, name, r2 );
4167                             else {
4168                                 STestEnd ( self, eEndOK, "not found: OK" );
4169                                 r2 = 0;
4170                             }
4171                         }
4172                         else {
4173                             String sFalse;
4174                             CONST_STRING ( & sFalse, "false" );
4175                             r2 = KConfigNodeReadString ( node, & p );
4176                             if ( r2 != 0 )
4177                                 STestEnd ( self, eEndFAIL, "cannot read "
4178                                     "'%s/%s/cache-enabled': %R",
4179                                     path, name, r2 );
4180                             else if ( StringEqual ( p, & sFalse ) )
4181                                 STestEnd ( self, eWarning,
4182                                     "caching is disabled" );
4183                             else
4184                                 STestEnd ( self, eEndOK, "OK" );
4185                             RELEASE ( String, p );
4186                         }
4187                         RELEASE ( KConfigNode, node );
4188                         if ( r2 != 0 && r1 == 0 )
4189                             r1 = r2;
4190                     }
4191                     {
4192                         rc_t r2 = KConfigOpenNodeRead ( self -> kfg, & node,
4193                             "%s/%s/download-ticket", path, name );
4194                         STestStart ( self, false, 0,
4195                                      "%s download-ticket:", name );
4196                         if ( r2 != 0 ) {
4197                             if ( r2 != SILENT_RC ( rcKFG, rcNode, rcOpening,
4198                                                    rcPath, rcNotFound ) )
4199                                 STestEnd ( self, eEndFAIL, "cannot read "
4200                                     "'%s/%s/download-ticket': %R",
4201                                     path, name, r2 );
4202                             else {
4203                                 self -> dad -> report . incompleteGapKfg = true;
4204                                 STestEnd ( self, tests & KDIAGN_TRY_TO_WARN
4205                                                     ? eWarning : eEndFAIL,
4206                                            "not found" );
4207                             }
4208                         }
4209                         else
4210                             STestEnd ( self, eEndOK, "OK" );
4211                         RELEASE ( KConfigNode, node );
4212                         if ( r2 != 0 && r1 == 0 )
4213                             r1 = r2;
4214                     }
4215                     {
4216                         rc_t r2 = KConfigOpenNodeRead ( self -> kfg, & node,
4217                             "%s/%s/encryption-key", path, name );
4218                         STestStart ( self, false, 0,
4219                                      "%s encryption-key:", name );
4220                         if ( r2 != 0 ) {
4221                             if ( r2 != SILENT_RC ( rcKFG, rcNode, rcOpening,
4222                                                    rcPath, rcNotFound ) )
4223                                 STestEnd ( self, eEndFAIL, "cannot read "
4224                                     "'%s/%s/encryption-key': %R",
4225                                     path, name, r2 );
4226                             else {
4227                                 r2 = KConfigOpenNodeRead ( self -> kfg, & node,
4228                                     "%s/%s/encryption-key-path", path, name );
4229                                 if ( r2 != 0 ) {
4230                                     if ( r2 != SILENT_RC ( rcKFG, rcNode,
4231                                         rcOpening, rcPath, rcNotFound ) )
4232                                     {
4233                                         STestEnd ( self, eEndFAIL,
4234                                             "cannot read "
4235                                             "'%s/%s/encryption-key-path': %R",
4236                                             path, name, r2 );
4237                                     }
4238                                     else {
4239                                         self -> dad -> report . incompleteGapKfg
4240                                             = true;
4241                                         STestEnd ( self,
4242                                             tests & KDIAGN_TRY_TO_WARN
4243                                                 ? eWarning : eEndFAIL,
4244                                             "not found" );
4245                                     }
4246                                 }
4247                             }
4248                         }
4249                         if ( r2 == 0 )
4250                             STestEnd ( self, eEndOK, "OK" );
4251                         RELEASE ( KConfigNode, node );
4252                         if ( r2 != 0 && r1 == 0 )
4253                             r1 = r2;
4254                     }
4255                     {
4256                         rc_t r2 = KConfigOpenNodeRead ( self -> kfg, & node,
4257                             "%s/%s/root", path, name );
4258                         STestStart ( self, false, 0, "%s root:", name );
4259                         if ( r2 != 0 ) {
4260                             if ( r2 != SILENT_RC ( rcKFG, rcNode, rcOpening,
4261                                                    rcPath, rcNotFound ) )
4262                                 STestEnd ( self, eEndFAIL,
4263                                            "cannot open '%s/%s/root': %R",
4264                                            path, name, r2 );
4265                             else
4266                                 STestEnd ( self, tests & KDIAGN_TRY_TO_WARN
4267                                                     ? eWarning : eEndFAIL,
4268                                            "not found" );
4269                         }
4270                         else {
4271                             r2 = KConfigNodeReadString ( node, & p );
4272                             if ( r2 != 0 )
4273                                 STestEnd ( self, eEndFAIL,
4274                                            "cannot read '%s/%s/root': %R",
4275                                            path, name, r2 );
4276                             else if ( p -> size == 0 )
4277                                 STestEnd ( self, tests & KDIAGN_TRY_TO_WARN
4278                                                     ? eWarning : eEndFAIL,
4279                                     "'%s' root path is empty", name );
4280                             else {
4281                                 KPathType type = kptFirstDefined;
4282                                 type = KDirectoryPathType
4283                                     ( self -> dir, p -> addr ) & ~ kptAlias;
4284                                 if ( type == kptNotFound )
4285                                     STestEnd ( self, eWarning, "'%s' root path "
4286                                         "does not exist: '%S'", name, p );
4287                                 else if ( type != kptDir )
4288                                     STestEnd ( self,
4289                                         tests & KDIAGN_TRY_TO_WARN
4290                                             ? eWarning : eEndFAIL,
4291                                         "'%s' root path "
4292                                         "is not a directory: '%S'", name, p );
4293                                 else
4294                                     STestEnd ( self, eEndOK, "'%S': OK", p );
4295                             }
4296                             RELEASE ( String, p );
4297                             RELEASE ( KConfigNode, node );
4298                         }
4299                         if ( r2 != 0 && r1 == 0 )
4300                             r1 = r2;
4301                     }
4302                     if ( r1 == 0 ) {
4303                         rc_t r2 = STestEnd ( self, eOK, name );
4304                         if ( r2 != 0 && r1 == 0 )
4305                             r1 = r2;
4306                     }
4307                     else if ( _RcCanceled ( r1 ) )
4308                         STestEnd ( self, eCANCELED, name );
4309                     else {
4310                         self -> dad -> report . incompleteGapKfg = true;
4311                         STestEnd ( self, eFAIL, name );
4312                     }
4313                 }
4314             }
4315             RELEASE ( KNamelist, names  );
4316             RELEASE ( KConfigNode, nProtected  );
4317             if ( ! printed ) {
4318                 printed = true;
4319                 if ( r1 == 0 ) {
4320                     rc_t r2 = STestEnd ( self, eOK, "Protected repositories" );
4321                     if ( r2 != 0 && r1 == 0 )
4322                         r1 = r2;
4323                 }
4324                 else if ( _RcCanceled ( r1 ) )
4325                     STestEnd ( self, eCANCELED,
4326                                          "Protected repositories: CANCELED" );
4327                 else
4328                     STestEnd ( self, eFAIL, "Protected repositories" );
4329             }
4330             if ( r1 != 0 && rc == 0 )
4331                 rc = r1;
4332         }
4333     }
4334     return rc;
4335 }
4336 
STestRun(STest * self,uint64_t tests,const KFile * kart,uint32_t numberOfKartItemsToCheck,bool checkHttp,bool checkAspera,bool checkDownload,const char * acc,uint32_t projectId,va_list args)4337 static rc_t CC STestRun ( STest * self, uint64_t tests,
4338     const KFile * kart, uint32_t numberOfKartItemsToCheck,
4339     bool checkHttp, bool checkAspera, bool checkDownload, const char * acc,
4340     uint32_t projectId, va_list args )
4341 {
4342     rc_t rc = 0;
4343 
4344     assert ( self );
4345 
4346     if ( tests & KDIAGN_CONFIG ) {
4347         rc_t r1 = 0;
4348         STestStart ( self, true, KDIAGN_CONFIG, "Configuration" );
4349         if ( tests & KDIAGN_KFG_NO_GAP && ! _RcCanceled ( r1 ) ) {
4350             rc_t r2 = STestCheckNoGapKfg ( self, tests );
4351             if ( r1 == 0 && r2 != 0 )
4352                 r1 = r2;
4353         }
4354         if ( tests & KDIAGN_REPO_GAP && ! _RcCanceled ( r1 ) ) {
4355             rc_t r2 = 0;
4356             STestStart ( self, true, KDIAGN_REPO_GAP, "DbGaP configuration" );
4357             r2 = STestCheckGapKfg ( self, tests );
4358             if ( r2 == 0 )
4359                 r2 = STestEnd ( self, eOK,  "DbGaP configuration" );
4360             else {
4361                 if ( _RcCanceled ( r2 ) )
4362                     STestEnd ( self, eCANCELED,
4363                                             "DbGaP configuration: CANCELED" );
4364                 else
4365                     STestEnd ( self, eFAIL, "DbGaP configuration" );
4366             }
4367             if ( r1 == 0 && r2 != 0 )
4368                 r1 = r2;
4369         }
4370         if ( r1 == 0 )
4371             r1 = STestEnd ( self, eOK,      "Configuration" );
4372         else {
4373             if ( _RcCanceled ( r1 ) )
4374                 STestEnd ( self, eCANCELED, "Configuration: CANCELED" );
4375             else
4376                 STestEnd ( self, eFAIL,     "Configuration" );
4377         }
4378         if ( rc == 0 && r1 != 0 )
4379             rc = r1;
4380     }
4381 
4382     if ( tests & KDIAGN_NETWORK && ! _RcCanceled ( rc ) ) {
4383         rc_t r1 = 0;
4384         bool tooBig = false;
4385         String run;
4386         char http [ PATH_MAX ] = "";
4387         uint64_t httpSize = 0;
4388         if ( acc != NULL )
4389             StringInitCString ( & run, acc );
4390         else
4391             CONST_STRING ( & run, "SRR029074" );
4392         STestStart ( self, true, KDIAGN_NETWORK, "Network" );
4393         if ( tests & KDIAGN_ACCESS_NCBI && ! _RcCanceled ( r1 ) ) {
4394             rc_t r2 = 0;
4395             STestStart ( self, true, KDIAGN_ACCESS_NCBI, "Access to NCBI" );
4396             r2 = STestCheckNcbiAccess ( self, tests );
4397             if ( r2 == 0 )
4398                 r2 = STestEnd ( self, eOK,      "Access to NCBI" );
4399             else {
4400                 if ( _RcCanceled ( r2 ) )
4401                     STestEnd ( self, eCANCELED, "Access to NCBI: CANCELED" );
4402                 else {
4403                     STestEnd ( self, eFAIL,     "Access to NCBI" );
4404                     self -> dad -> report . firewall = true;
4405                 }
4406             }
4407             if ( r1 == 0 && r2 != 0 )
4408                 r1 = r2;
4409         }
4410         if ( tests & KDIAGN_HTTP && ! _RcCanceled ( r1 ) ) {
4411             rc_t r2 = 0;
4412             STestStart ( self, true, KDIAGN_HTTP, "HTTPS download" );
4413             if ( tests & KDIAGN_HTTP_RUN ) {
4414                 const char sra  [] = "NCBI.sra\210\031\003\005\001\0\0\0";
4415                 const char nenc [] = "NCBInenc\210\031\003\005\002\0\0\0";
4416                 const char * exp [] = { sra, nenc };
4417                 size_t s = sizeof sra - 1;
4418                 r2 = STestCheckHttp ( self, tests, & run, false,
4419                     http, sizeof http, & httpSize, exp, s, & tooBig );
4420             }
4421             if ( r2 == 0 )
4422                 r2 = STestEnd ( self, eOK,      "HTTPS download" );
4423             else {
4424                 if ( _RcCanceled ( r2 ) )
4425                     STestEnd ( self, eCANCELED, "HTTPS download: CANCELED" );
4426                 else
4427                     STestEnd ( self, eFAIL,     "HTTPS download" );
4428             }
4429             if ( r1 == 0 && r2 != 0 )
4430                 r1 = r2;
4431         }
4432         if ( tests & KDIAGN_ASCP && ! _RcCanceled ( r1 ) ) {
4433             rc_t r2 = 0;
4434             char fasp [ PATH_MAX ] = "";
4435             uint64_t faspSize = 0;
4436             String smallrun;
4437             const String * frun = & run;
4438             STestStart ( self, true, KDIAGN_ASCP, "Aspera download" );
4439             if ( tooBig ) {
4440                 CONST_STRING ( & smallrun, "SRR029074" );
4441                 frun = & smallrun;
4442             }
4443 
4444             if ( tests & KDIAGN_ASCP_RUN )
4445                 r2 = STestCheckFasp ( self, tests,
4446                     frun, false, fasp, sizeof fasp, & faspSize );
4447             if ( r2 == 0 )
4448                 r2 = STestEnd ( self, eOK,      "Aspera download" );
4449             else {
4450                 if ( _RcCanceled ( r2 ) )
4451                     STestEnd ( self, eCANCELED, "Aspera download: CANCELED" );
4452                 else
4453                     STestEnd ( self, eFAIL,     "Aspera download" );
4454             }
4455             if ( r1 == 0 && r2 != 0 )
4456                 r1 = r2;
4457             if ( tests & KDIAGN_HTTP_VS_ASCP && ! tooBig &&
4458                  r2 == 0 && httpSize != 0 && faspSize != 0 )
4459             {
4460                 r2 = STestHttpVsFasp ( self, http, httpSize, fasp, faspSize );
4461                 if ( r1 == 0 && r2 != 0 )
4462                     r1 = r2;
4463             }
4464             if ( * fasp != '\0' ) {
4465                 rc_t r2 = KDirectoryRemove ( self-> dir, false, fasp );
4466                 if ( r2 != 0 ) {
4467                     STestFail ( self, r2, 0, "FAILURE: cannot remove '%s': %R",
4468                                           fasp, r2 );
4469                     if ( r1 == 0 && r2 != 0 )
4470                         r1 = r2;
4471                 }
4472                 else
4473                     * fasp = '\0';
4474             }
4475         }
4476         if ( * http != '\0' ) {
4477             rc_t r2 = KDirectoryRemove ( self-> dir, false, http );
4478             if ( r2 != 0 ) {
4479                 STestFail ( self, r2, 0, "FAILURE: cannot remove '%s': %R",
4480                                       http, r2 );
4481                 if ( r1 == 0 && r2 != 0 )
4482                     r1 = r2;
4483             }
4484             else
4485                 * http = '\0';
4486         }
4487         if ( r1 == 0)
4488             r1 = STestEnd ( self, eOK,  "Network" );
4489         else  if ( _RcCanceled ( r1 ) )
4490             STestEnd ( self, eCANCELED, "Network: CANCELED" );
4491         else
4492             STestEnd ( self, eFAIL,     "Network" );
4493         if ( rc == 0 && r1 != 0 )
4494             rc = r1;
4495     }
4496 
4497     if ( rc == 0 && tests & KDIAGN_FAIL )
4498       rc = 1;
4499 
4500   /*if ( rc == 0)
4501         STestEnd ( & t, eOK,       "System" );
4502     else  if ( _RcCanceled ( rc ) )
4503         STestEnd ( & t, eCANCELED, "System: CANCELED" );
4504     else
4505         STestEnd ( & t, eFAIL,     "System" );
4506 
4507     STestFini ( & t );
4508     KDiagnoseRelease ( self );*/
4509     return rc;
4510 }
4511 
KDiagnoseRunImpl(KDiagnose * self,const char * name,uint64_t tests,const KFile * kart,uint32_t numberOfKartItemsToCheck,bool checkHttp,bool checkAspera,bool checkDownload,const char * acc,uint32_t projectId,...)4512 static rc_t CC KDiagnoseRunImpl ( KDiagnose * self, const char * name,
4513     uint64_t tests, const KFile * kart, uint32_t numberOfKartItemsToCheck,
4514     bool checkHttp, bool checkAspera, bool checkDownload,
4515     const char * acc, uint32_t projectId, ... )
4516 {
4517     rc_t rc = 0;
4518     STest t;
4519     va_list args;
4520     va_start ( args, projectId );
4521     if ( self == NULL )
4522         rc = KDiagnoseMakeExt ( & self, NULL, NULL, NULL, NULL );
4523     else
4524         rc = KDiagnoseAddRef ( self );
4525     if ( rc != 0 )
4526         return rc;
4527 
4528     assert ( self );
4529 
4530     STestInit ( & t, self );
4531 
4532     STestStart ( & t, true, KDIAGN_ALL, name );
4533 
4534     rc = STestRun ( & t, tests, kart, numberOfKartItemsToCheck,
4535         checkHttp, checkAspera, checkDownload, acc, projectId, args );
4536     va_end ( args );
4537     if ( rc == 0 && tests & KDIAGN_FAIL )
4538       rc = 1;
4539 
4540     if ( rc == 0)
4541         STestEnd ( & t, eOK,       name );
4542     else  if ( _RcCanceled ( rc ) )
4543         STestEnd ( & t, eCANCELED, "%s: CANCELED", name );
4544     else
4545         STestEnd ( & t, eFAIL,     "%s", name );
4546 
4547     STestFini ( & t );
4548     KDiagnoseRelease ( self );
4549     return rc;
4550 }
4551 
KDiagnoseAll(KDiagnose * self,uint64_t tests)4552 LIB_EXPORT rc_t CC KDiagnoseAll ( KDiagnose * self, uint64_t tests ) {
4553     return KDiagnoseRunImpl ( self, "System", KDIAGN_ALL, NULL, 0,
4554                               true, true, true, NULL, 0 );
4555 }
4556 
4557 LIB_EXPORT
KDiagnoseAdvanced(KDiagnose * self,uint64_t tests)4558 rc_t CC KDiagnoseAdvanced ( KDiagnose * self, uint64_t tests )
4559 {
4560     return KDiagnoseRunImpl ( self, "System", tests, NULL, 0,
4561                               true, true, true, NULL, 0 );
4562 }
4563 
KDiagnoseAcc(KDiagnose * self,const char * acc,uint32_t projectId,bool checkHttp,bool checkAspera,bool checkDownload,uint64_t tests)4564 LIB_EXPORT rc_t CC KDiagnoseAcc ( KDiagnose * self,  const char * acc,
4565     uint32_t projectId, bool checkHttp, bool checkAspera, bool checkDownload,
4566     uint64_t tests )
4567 {
4568     return KDiagnoseRunImpl ( self, "System", tests, NULL, 0,
4569                               checkHttp, checkAspera, checkDownload, acc, 0 );
4570 }
4571 
4572 /*DIAGNOSE_EXTERN rc_t CC KDiagnoseDbGap ( KDiagnose * self, uint64_t tests,
4573     uint32_t projectId, ... )
4574 {
4575     rc_t rc = 0;
4576     va_list args;
4577     va_start ( args, projectId );
4578     rc = KDiagnoseRunImpl ( self, tests, NULL, 0, NULL, projectId, args );
4579     va_end ( args );
4580     return rc;
4581 }*/
4582 
KDiagnoseKart(KDiagnose * self,const struct KFile * kart,uint32_t numberOfKartItemsToCheck,bool checkHttp,bool checkAspera,uint64_t tests)4583 DIAGNOSE_EXTERN rc_t CC KDiagnoseKart ( KDiagnose * self,
4584     const struct KFile * kart, uint32_t numberOfKartItemsToCheck,
4585     bool checkHttp, bool checkAspera, uint64_t tests )
4586 {
4587     return KDiagnoseRunImpl ( self, "Kart file", KDIAGN_ALL, kart,
4588         numberOfKartItemsToCheck, checkHttp, checkAspera, true, NULL, 0 );
4589 }
4590