1 /*===========================================================================
2  *
3  *                            PUBLIC DOMAIN NOTICE
4  *               National Center for Biotechnology Information
5  *
6  *  This software/database is a "United States Government Work" under the
7  *  terms of the United States Copyright Act.  It was written as part of
8  *  the author's official duties as a United States Government employee and
9  *  thus cannot be copyrighted.  This software/database is freely available
10  *  to the public for use. The National Library of Medicine and the U.S.
11  *  Government have not placed any restriction on its use or reproduction.
12  *
13  *  Although all reasonable efforts have been taken to ensure the accuracy
14  *  and reliability of the software and data, the NLM and the U.S.
15  *  Government do not and cannot warrant the performance or results that
16  *  may be obtained by using this software or data. The NLM and the U.S.
17  *  Government disclaim all warranties, express or implied, including
18  *  warranties of performance, merchantability or fitness for any particular
19  *  purpose.
20  *
21  *  Please cite the author in any work or product based on this material.
22  *
23  * ===========================================================================
24  *
25  */
26 
27 #include <kns/extern.h>
28 
29 #include <kfg/config.h>
30 #include <kfg/properties.h>
31 
32 #include <klib/base64.h>
33 #include <klib/data-buffer.h>
34 #include <klib/printf.h>
35 #include <klib/rc.h>
36 #include <klib/strings.h>
37 #include <klib/writer.h>
38 
39 #include <kproc/lock.h>
40 #include <kproc/timeout.h>
41 
42 #include <kns/http.h>
43 #include <kns/manager.h>
44 #include <kns/socket.h>
45 
46 #include <cloud/manager.h>
47 
48 #include <atomic.h> /* atomic_ptr_t */
49 #include <ctype.h>
50 #include <strtol.h> /* strtou64 */
51 #include <sysalloc.h>
52 
53 #include <assert.h>
54 
55 #if LINUX
56 #include <gnu/libc-version.h>
57 #include <arpa/inet.h>
58 #include <netinet/in.h>
59 #endif
60 
61 #include <stdio.h> /* fprintf */
62 
63 #include "../klib/release-vers.h"
64 #include "http-priv.h"
65 #include "kns_manager-singleton.h" /* USE_SINGLETON */
66 #include "mgr-priv.h"
67 #include "stream-priv.h"
68 #include "sysmgr.h"
69 
70 #ifndef MAX_CONN_LIMIT
71 #define MAX_CONN_LIMIT ( 60 * 1000 )
72 #endif
73 
74 #ifndef MAX_CONN_READ_LIMIT
75 #define MAX_CONN_READ_LIMIT ( 10 * 60 * 1000 )
76 #endif
77 
78 #ifndef MAX_CONN_WRITE_LIMIT
79 #define MAX_CONN_WRITE_LIMIT ( 10 * 60 * 1000 )
80 #endif
81 
82 static KLock *kns_manager_lock = NULL; /* Protects below */
83 static KDataBuffer kns_manager_user_agent;
84 
85 static KDataBuffer kns_manager_guid;
86 
87 /* thread-local values */
88 _Thread_local char kns_manager_user_agent_append [ 4096 ] = { 0 };
89 _Thread_local char kns_manager_clientip  [ KNSMANAGER_STRING_MAX ] = { 0 };
90 _Thread_local char kns_manager_sessionid [ KNSMANAGER_STRING_MAX ] = { 0 };
91 _Thread_local char kns_manager_pagehitid [ KNSMANAGER_STRING_MAX ] = { 0 };
92 _Thread_local char kns_manager_ua_suffix [ KNSMANAGER_STRING_MAX ] = { 0 };
93 
94 quitting_t quitting;
95 
96 #if USE_SINGLETON
97 static atomic_ptr_t kns_singleton;
98 #endif
99 
100 /*
101 #define RELEASE( type, obj ) do { rc_t rc2 = type##Release ( obj ); \
102     if (rc2 != 0 && rc == 0) { rc = rc2; } obj = NULL; } while ( false )
103 */
104 
KNSManagerHttpProxyOnly(const KNSManager * self)105 bool KNSManagerHttpProxyOnly ( const KNSManager *self )
106 {
107     if ( self == NULL ) { return false; }
108 
109     return KNSProxiesHttpProxyOnly ( self->proxies );
110 }
111 
KNSManagerGetProxies(const KNSManager * self,size_t * cnt)112 struct KNSProxies *KNSManagerGetProxies ( const KNSManager *self, size_t *cnt )
113 {
114     if ( self == NULL ) { return NULL; }
115     size_t dummy;
116     if ( cnt == NULL ) { cnt = &dummy; }
117     return KNSProxiesGetHttpProxy ( self->proxies, cnt );
118 }
119 
120 
KNSManagerWhack(KNSManager * self)121 static rc_t KNSManagerWhack ( KNSManager *self )
122 {
123     rc_t rc;
124 
125 #if USE_SINGLETON
126     KNSManager *our_mgr
127         = atomic_test_and_set_ptr ( &kns_singleton, NULL, NULL );
128     if ( self == our_mgr ) {
129         if ( !self->notSingleton ) { return 0; }
130         atomic_test_and_set_ptr ( &kns_singleton, NULL, self );
131     }
132 #endif
133 
134     KNSProxiesWhack ( self->proxies );
135     CloudMgrRelease ( self->cloud );
136 
137     rc = HttpRetrySpecsDestroy ( &self->retry_specs );
138 
139     KTLSGlobalsWhack ( &self->tlsg );
140 
141     free ( self );
142 
143     KNSManagerCleanup ();
144     if ( kns_manager_lock ) {
145         KLockRelease ( kns_manager_lock );
146         kns_manager_lock = NULL;
147     }
148     if ( !rc ) rc = KDataBufferWhack ( &kns_manager_user_agent );
149 
150     return rc;
151 }
152 
KNSManagerAddRef(const KNSManager * self)153 LIB_EXPORT rc_t CC KNSManagerAddRef ( const KNSManager *self )
154 {
155     if ( self != NULL ) {
156         switch ( KRefcountAdd ( &self->refcount, "KNSManager" ) ) {
157         case krefLimit:
158             return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcExcessive );
159         case krefNegative:
160             return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
161         }
162     }
163     return 0;
164 }
165 
166 
KNSManagerRelease(const KNSManager * self)167 LIB_EXPORT rc_t CC KNSManagerRelease ( const KNSManager *self )
168 {
169     if ( self != NULL ) {
170         switch ( KRefcountDrop ( &self->refcount, "KNSManager" ) ) {
171         case krefWhack: return KNSManagerWhack ( (KNSManager *)self );
172         case krefNegative:
173             return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
174         }
175     }
176     else
177          return KDataBufferWhack(&kns_manager_user_agent);
178     return 0;
179 }
180 
181 static rc_t CC KNSManagerMakeConfigImpl ( KNSManager **mgrp, KConfig *kfg );
182 
183 
KNSManagerMakeSingleton(KNSManager ** mgrp,KConfig * aKfg,bool local)184 static rc_t CC KNSManagerMakeSingleton (
185     KNSManager **mgrp, KConfig *aKfg, bool local )
186 {
187     rc_t rc = 0;
188 
189     if ( mgrp == NULL ) {
190         rc = RC ( rcNS, rcMgr, rcAllocating, rcParam, rcNull );
191     } else {
192         KConfig *kfg = aKfg;
193         KNSManager *our_mgr = NULL;
194 
195         *mgrp = NULL;
196 
197 #if USE_SINGLETON
198         if ( !local ) {
199             /* grab single-shot singleton */
200             our_mgr = atomic_test_and_set_ptr ( &kns_singleton, NULL, NULL );
201             if ( our_mgr != NULL ) {
202                 /* add a new reference and return */
203                 rc = KNSManagerAddRef ( our_mgr );
204                 if ( rc == 0 ) { *mgrp = our_mgr; }
205                 return rc;
206             }
207         }
208 #endif
209 
210         /* singleton was NULL. Make from scratch. */
211         if ( kfg == NULL ) { rc = KConfigMake ( &kfg, NULL ); }
212 
213         if ( rc == 0 ) {
214             if ( !kns_manager_lock ) {
215                 rc = KLockMake ( &kns_manager_lock );
216                 if ( rc ) { return rc; }
217             }
218 
219             if (kns_manager_user_agent.base == NULL) {
220                 rc = KDataBufferMakeBytes ( &kns_manager_user_agent, 0 );
221                 if ( rc ) { return rc; }
222                 rc = KDataBufferPrintf ( &kns_manager_user_agent, "%s", "" );
223                 if ( rc ) { return rc; }
224             }
225 
226             if (kns_manager_guid.base == NULL) {
227                 rc = KDataBufferMakeBytes ( &kns_manager_guid, 0 );
228                 if ( rc ) { return rc; }
229                 rc = KDataBufferPrintf ( &kns_manager_guid, "%s", "" );
230                 if ( rc ) { return rc; }
231             }
232 
233             rc = KNSManagerMakeConfigImpl ( &our_mgr, kfg );
234 
235             if ( aKfg == NULL ) { KConfigRelease ( kfg ); }
236 
237             if ( rc == 0 ) {
238 #if USE_SINGLETON
239                 if ( !local ) {
240                     /* try to set single-shot ( set once, never reset ) */
241                     KNSManager *new_mgr = atomic_test_and_set_ptr (
242                         &kns_singleton, our_mgr, NULL );
243                     if ( new_mgr != NULL ) {
244                         /* somebody else got here first - drop our version */
245                         assert ( our_mgr != new_mgr );
246                         KNSManagerRelease ( our_mgr );
247 
248                         /* use the new manager,
249                            just add a reference and return */
250                         rc = KNSManagerAddRef ( new_mgr );
251                         if ( rc == 0 ) { *mgrp = new_mgr; }
252                         return rc;
253                     }
254                 }
255 #endif
256                 /* return parameter */
257                 *mgrp = our_mgr;
258             }
259         }
260     }
261 
262     return rc;
263 }
264 
KNSManagerMake(KNSManager ** mgrp)265 LIB_EXPORT rc_t CC KNSManagerMake ( KNSManager **mgrp )
266 {
267     return KNSManagerMakeSingleton ( mgrp, NULL, false );
268 }
269 
KNSManagerSetVerbose(KNSManager * self,bool verbosity)270 LIB_EXPORT void KNSManagerSetVerbose ( KNSManager *self, bool verbosity )
271 {
272     if ( self != NULL ) { self->verbose = verbosity; }
273 }
274 
275 
KNSManagerIsVerbose(const KNSManager * self)276 LIB_EXPORT bool KNSManagerIsVerbose ( const KNSManager *self )
277 {
278     return ( self != NULL ) ? self->verbose : false;
279 }
280 
281 
282 /* MakeConnection
283  *  create a connection-oriented stream
284  *
285  *  "conn" [ OUT ] - a stream for communication with the server
286  *
287  *  "from" [ IN ] - client endpoint
288  *
289  *  "to" [ IN ] - server endpoint
290  *
291  *  both endpoints have to be of type epIP; creates a TCP connection
292  */
KNSManagerMakeConnection(const KNSManager * self,struct KSocket ** conn,struct KEndPoint const * from,struct KEndPoint const * to)293 LIB_EXPORT rc_t CC KNSManagerMakeConnection ( const KNSManager *self,
294     struct KSocket **conn, struct KEndPoint const *from,
295     struct KEndPoint const *to )
296 {
297     timeout_t tm;
298     timeout_t * ptm = NULL;
299 
300     if ( self == NULL ) {
301         if ( conn == NULL ) {
302             return RC ( rcNS, rcStream, rcConstructing, rcParam, rcNull );
303         }
304 
305         *conn = NULL;
306 
307         return RC ( rcNS, rcStream, rcConstructing, rcSelf, rcNull );
308     }
309 
310     if (self->conn_timeout >= 0) {
311         TimeoutInit ( &tm, self->conn_timeout );
312         ptm = &tm;
313     }
314 
315     return KNSManagerMakeRetryTimedConnection ( self, conn, ptm,
316         self->conn_read_timeout, self->conn_write_timeout, from, to );
317 }
318 /* MakeTimedConnection
319  *  create a connection-oriented stream
320  *
321  *  "conn" [ OUT ] - a stream for communication with the server
322  *
323  *  "retryTimeout" [ IN ] - if connection is refused, retry with 1ms intervals:
324  * when negative, retry infinitely, when 0, do not retry, positive gives maximum
325  * wait time in seconds
326  *
327  *  "readMillis" [ IN ] and "writeMillis" - when negative, infinite timeout
328  *   when 0, return immediately, positive gives maximum wait time in mS
329  *   for reads and writes respectively.
330  *
331  *  "from" [ IN ] - client endpoint
332  *
333  *  "to" [ IN ] - server endpoint
334  *
335  *  both endpoints have to be of type epIP; creates a TCP connection
336  */
KNSManagerMakeTimedConnection(struct KNSManager const * self,struct KSocket ** conn,int32_t readMillis,int32_t writeMillis,struct KEndPoint const * from,struct KEndPoint const * to)337 LIB_EXPORT rc_t CC KNSManagerMakeTimedConnection (
338     struct KNSManager const *self, struct KSocket **conn, int32_t readMillis,
339     int32_t writeMillis, struct KEndPoint const *from,
340     struct KEndPoint const *to )
341 {
342     timeout_t tm;
343     timeout_t * ptm = NULL;
344 
345     if ( self == NULL ) {
346         if ( conn == NULL ) {
347             return RC ( rcNS, rcStream, rcConstructing, rcParam, rcNull );
348         }
349 
350         *conn = NULL;
351 
352         return RC ( rcNS, rcStream, rcConstructing, rcSelf, rcNull );
353     }
354 
355     if (self->conn_timeout >=0 ) {
356         TimeoutInit ( &tm, self->conn_timeout );
357         ptm = &tm;
358     }
359 
360     return KNSManagerMakeRetryTimedConnection (
361         self, conn, ptm, readMillis, writeMillis, from, to );
362 }
363 
364 /* MakeRetryConnection
365  *  create a connection-oriented stream
366  *
367  *  "conn" [ OUT ] - a stream for communication with the server
368  *
369  *  "retryTimeout" [ IN ] - if connection is refused, retry with 1ms intervals:
370  * when negative, retry infinitely, when 0, do not retry, positive gives maximum
371  * wait time in seconds
372  *
373  *  "from" [ IN ] - client endpoint
374  *
375  *  "to" [ IN ] - server endpoint
376  *
377  *  both endpoints have to be of type epIP; creates a TCP connection
378  */
KNSManagerMakeRetryConnection(struct KNSManager const * self,struct KSocket ** conn,timeout_t * retryTimeout,struct KEndPoint const * from,struct KEndPoint const * to)379 LIB_EXPORT rc_t CC KNSManagerMakeRetryConnection (
380     struct KNSManager const *self, struct KSocket **conn,
381     timeout_t *retryTimeout, struct KEndPoint const *from,
382     struct KEndPoint const *to )
383 {
384     if ( self == NULL ) {
385         if ( conn == NULL ) {
386             return RC ( rcNS, rcStream, rcConstructing, rcParam, rcNull );
387         }
388 
389         *conn = NULL;
390 
391         return RC ( rcNS, rcStream, rcConstructing, rcSelf, rcNull );
392     }
393 
394     return KNSManagerMakeRetryTimedConnection ( self, conn, retryTimeout,
395         self->conn_read_timeout, self->conn_write_timeout, from, to );
396 }
397 
398 /* SetConnectionTimeouts
399  *  sets default connect/read/write timeouts to supply to sockets
400  *
401  *  "connectMillis", "readMillis", "writeMillis" [ IN ] - when negative,
402  * infinite timeout when 0, return immediately, positive gives maximum wait time
403  * in sec/mS for connects, reads and writes respectively.
404  */
KNSManagerSetConnectionTimeouts(KNSManager * self,int32_t connectMillis,int32_t readMillis,int32_t writeMillis)405 LIB_EXPORT rc_t CC KNSManagerSetConnectionTimeouts ( KNSManager *self,
406     int32_t connectMillis, int32_t readMillis, int32_t writeMillis )
407 {
408     if ( self == NULL ) {
409         return RC ( rcNS, rcMgr, rcUpdating, rcSelf, rcNull );
410     }
411 
412     /* limit values */
413     if ( connectMillis > MAX_CONN_LIMIT ) {
414         connectMillis = MAX_CONN_LIMIT;
415     }
416 
417     if ( readMillis > MAX_CONN_READ_LIMIT ) {
418         readMillis = MAX_CONN_READ_LIMIT;
419     }
420 
421     if ( writeMillis > MAX_CONN_WRITE_LIMIT ) {
422         writeMillis = MAX_CONN_WRITE_LIMIT;
423     }
424 
425     self->conn_timeout = connectMillis;
426     self->conn_read_timeout = readMillis;
427     self->conn_write_timeout = writeMillis;
428 
429     return 0;
430 }
431 
432 
433 /* SetHTTPTimeouts
434  *  sets default read/write timeouts to supply to HTTP connections
435  *
436  *  "readMillis" [ IN ] and "writeMillis" - when negative, infinite timeout
437  *  when 0, return immediately, positive gives maximum wait time in mS
438  *  for reads and writes respectively.
439  */
KNSManagerSetHTTPTimeouts(KNSManager * self,int32_t readMillis,int32_t writeMillis)440 LIB_EXPORT rc_t CC KNSManagerSetHTTPTimeouts (
441     KNSManager *self, int32_t readMillis, int32_t writeMillis )
442 {
443     if ( self == NULL ) {
444         return RC ( rcNS, rcMgr, rcUpdating, rcSelf, rcNull );
445     }
446 
447     /* limit values */
448     if ( readMillis < 0 || readMillis > MAX_HTTP_READ_LIMIT ) {
449         readMillis = MAX_HTTP_READ_LIMIT;
450     }
451 
452     if ( writeMillis < 0 || writeMillis > MAX_HTTP_WRITE_LIMIT ) {
453         writeMillis = MAX_HTTP_WRITE_LIMIT;
454     }
455 
456     self->http_read_timeout = readMillis;
457     self->http_write_timeout = writeMillis;
458 
459     return 0;
460 }
461 
462 /* GetHTTPProxyPath
463  * DEPRECATED
464  *  returns path to HTTP proxy server ( if set ) or NULL.
465  *  return status is 0 if the path is valid, non-zero otherwise
466  */
KNSManagerGetHTTPProxyPath(const KNSManager * self,const String ** proxy)467 LIB_EXPORT rc_t CC KNSManagerGetHTTPProxyPath (
468     const KNSManager *self, const String **proxy )
469 {
470     fprintf ( stderr,
471         "WARNING : KNSManagerGetHTTPProxyPath IS DEPRECATED AND SHOULD NOT BE "
472         "USED\n" );
473     return KNSProxiesGetHttpProxyPath ( self->proxies, proxy );
474 }
475 
476 
477 /* SetHTTPProxyPath
478  *  sets a path to HTTP proxy server.
479  *  a NULL path value removes all proxy settings.
480  *
481  *  the VPath passed in must still be released using VPathRelease,
482  *  because KNSManager will attach a new reference to it.
483  */
KNSManagerSetHTTPProxyPath(KNSManager * self,const char * fmt,...)484 LIB_EXPORT rc_t CC KNSManagerSetHTTPProxyPath (
485     KNSManager *self, const char *fmt, ... )
486 {
487     rc_t rc;
488 
489     va_list args;
490     va_start ( args, fmt );
491     rc = KNSManagerVSetHTTPProxyPath ( self, fmt, args );
492     va_end ( args );
493 
494     return rc;
495 }
496 
KNSManagerVSetHTTPProxyPath(KNSManager * self,const char * fmt,va_list args)497 LIB_EXPORT rc_t CC KNSManagerVSetHTTPProxyPath (
498     KNSManager *self, const char *fmt, va_list args )
499 {
500     if ( self == NULL ) {
501         return RC ( rcNS, rcMgr, rcUpdating, rcSelf, rcNull );
502     }
503 
504     return KNSProxiesVSetHTTPProxyPath ( self->proxies, fmt, args, true );
505 }
506 
KNSManagerHttpProxyInit(KNSManager * self,const KConfig * kfg)507 static rc_t KNSManagerHttpProxyInit ( KNSManager *self, const KConfig *kfg )
508 {
509     assert ( self );
510     self->proxies = KNSManagerKNSProxiesMake ( self, kfg );
511     if ( self->proxies == NULL ) {
512         return RC ( rcNS, rcMgr, rcAllocating, rcMemory, rcExhausted );
513     }
514 
515     return 0;
516 }
517 
518 /* GetHTTPProxyEnabled
519  *  returns true if a non-NULL proxy path exists and user wants to use it
520  *  users indicate desire to use proxy through configuration
521  *  or SetHTTPProxyEnabled
522  */
KNSManagerGetHTTPProxyEnabled(const KNSManager * self)523 LIB_EXPORT bool CC KNSManagerGetHTTPProxyEnabled ( const KNSManager *self )
524 {
525     if ( self != NULL ) {
526         return KNSProxiesGetHTTPProxyEnabled ( self->proxies );
527     }
528 
529     return false;
530 }
531 
532 /* SetHTTPProxyEnabled
533  *  sets http-proxy enabled state to supplied value
534  *  returns the prior value as a convenience
535  */
KNSManagerSetHTTPProxyEnabled(KNSManager * self,bool enabled)536 LIB_EXPORT bool CC KNSManagerSetHTTPProxyEnabled (
537     KNSManager *self, bool enabled )
538 {
539     bool prior = false;
540     if ( self != NULL ) {
541         prior = KNSProxiesSetHTTPProxyEnabled ( self->proxies, enabled );
542     }
543     return prior;
544 }
545 
546 
KNSManagerSetNCBI_VDB_NET(KNSManager * self,const KConfig * kfg)547 static void KNSManagerSetNCBI_VDB_NET ( KNSManager *self, const KConfig *kfg )
548 {
549     rc_t rc = 0;
550 
551     const KConfigNode *node = NULL;
552 
553     if ( self == NULL || kfg == NULL ) { return; }
554 
555     rc = KConfigOpenNodeRead ( kfg, &node, "/libs/kns/NCBI_VDB_NET" );
556     if ( rc != 0 ) {
557         self->NCBI_VDB_NETkfgValueSet = self->NCBI_VDB_NETkfgValue = false;
558         return;
559     }
560 
561     char buffer[1] = "";
562     size_t num_read = 0;
563     self->NCBI_VDB_NETkfgValueSet = true;
564     KConfigNodeRead ( node, 0, buffer, sizeof buffer, &num_read, 0 );
565     if ( num_read == 0 ) {
566         self->NCBI_VDB_NETkfgValue = false;
567     } else {
568         switch ( buffer[0] ) {
569         case '0':
570         case 'f': /* false */ self->NCBI_VDB_NETkfgValue = false; break;
571         default: self->NCBI_VDB_NETkfgValue = true; break;
572         }
573     }
574 
575 
576     KConfigNodeRelease ( node );
577     node = NULL;
578 }
579 
580 
581 /* VDB-DESIREMENTS:
582 1. to call *[s]/kfg/properties* to read configuration
583 2. to create a header file to keep constants (node names) */
KNSManagerLoadConnTimeout(KConfig * kfg)584 static int32_t KNSManagerLoadConnTimeout ( KConfig *kfg )
585 {
586     int64_t result = 0;
587 
588     rc_t rc = KConfigReadI64 ( kfg, "/libs/kns/connect/timeout", &result );
589     if ( rc != 0 )
590         result = MAX_CONN_LIMIT;
591 
592     return result;
593 }
KNSManagerLoadConnReadTimeout(KConfig * kfg)594 static int32_t KNSManagerLoadConnReadTimeout ( KConfig *kfg )
595 {
596     int64_t result = 0;
597 
598     rc_t rc = KConfigReadI64 ( kfg, "/libs/kns/connect/timeout/read", &result );
599     if ( rc != 0 )
600         result = MAX_CONN_READ_LIMIT;
601 
602     return result;
603 }
KNSManagerLoadConnWriteTimeout(KConfig * kfg)604 static int32_t KNSManagerLoadConnWriteTimeout ( KConfig *kfg )
605 {
606     int64_t result = 0;
607 
608     rc_t rc
609         = KConfigReadI64 ( kfg, "/libs/kns/connect/timeout/write", &result );
610     if ( rc != 0 )
611         result = MAX_CONN_WRITE_LIMIT;
612 
613     return result;
614 }
615 
KNSManagerLoadHttpReadTimeout(KConfig * kfg)616 static int32_t KNSManagerLoadHttpReadTimeout ( KConfig *kfg )
617 {
618     int64_t result = 0; /* when negative - infinite timeout */
619 
620     rc_t rc = KConfigReadI64 ( kfg, "/http/timeout/read", &result );
621     if ( rc != 0 )
622         result = MAX_HTTP_READ_LIMIT;
623 
624     return result;
625 }
KNSManagerLoadHttpWriteTimeout(KConfig * kfg)626 static int32_t KNSManagerLoadHttpWriteTimeout ( KConfig *kfg )
627 {
628     int64_t result = 0; /* when negative - infinite timeout */
629 
630     rc_t rc = KConfigReadI64 ( kfg, "/http/timeout/write", &result );
631     if ( rc != 0 )
632         result = MAX_HTTP_WRITE_LIMIT;
633 
634     return result;
635 }
636 
637 static
KNSManagerLoadTotalWaitForReliableURLs(const KConfig * kfg)638 int32_t KNSManagerLoadTotalWaitForReliableURLs(const KConfig *kfg)
639 {
640     rc_t rc = 0;
641 
642     int64_t result = 0;
643 
644     const char * str = getenv("NCBI_VDB_RELIABLE_WAIT");
645     if (str != NULL) {
646         char *end = NULL;
647         result = strtou64(str, &end, 0);
648         if (end[0] == 0)
649             return result;
650     }
651 
652     rc = KConfigReadI64(kfg, "/http/reliable/wait", &result);
653     if (rc != 0
654         || result < 0)  /* no support for infinite wait in HTTP retry loop in */
655     {     /* StableHttpFile: it might lead to infinite loop of reading errors */
656         result = MAX_HTTP_TOTAL_READ_LIMIT;
657     }
658 
659     return result;
660 }
661 
KNSManagerLoadTotalConnectWaitForReliableURLs(const KConfig * kfg)662 static int32_t KNSManagerLoadTotalConnectWaitForReliableURLs(
663     const KConfig *kfg)
664 {
665     rc_t rc = 0;
666 
667     int64_t result = 0;
668 
669     const char * str = getenv("NCBI_VDB_RELIABLE_CONNECT_WAIT");
670     if (str != NULL) {
671         char *end = NULL;
672         result = strtou64(str, &end, 0);
673         if (end[0] == 0)
674             return result;
675     }
676 
677     rc = KConfigReadI64(kfg, "/http/reliable/connect/wait", &result);
678     if (rc != 0)
679         result = MAX_HTTP_TOTAL_CONNECT_LIMIT;
680 
681     return result;
682 }
683 
KNSManagerLoadRetryFirstRead(const KConfig * kfg)684 static bool KNSManagerLoadRetryFirstRead(const KConfig *kfg) {
685     rc_t rc = 0;
686 
687     bool result = 0;
688 
689     const char * str = getenv("NCBI_VDB_RELIABLE_RETRY_FIRST_READ");
690     if (str != NULL && str[0] != '\0') {
691         switch (str[0]) {
692         case 'f':
693             return false;
694         case 't':
695             return true;
696         default:
697             break;
698         }
699     }
700 
701     rc = KConfigReadBool(kfg, "/http/reliable/retryFirstRead", &result);
702     if (rc != 0)
703         result = false;
704 
705     return result;
706 }
707 
KNSManagerLoadRetryFile(const KConfig * kfg)708 static bool KNSManagerLoadRetryFile(const KConfig *kfg) {
709     rc_t rc = 0;
710 
711     bool result = 0;
712 
713     const char * str = getenv("NCBI_VDB_RELIABLE_RETRY_FILE");
714     if (str != NULL && str[0] != '\0') {
715         switch (str[0]) {
716         case 'f':
717             return false;
718         case 't':
719             return true;
720         default:
721             break;
722         }
723     }
724 
725     rc = KConfigReadBool(kfg, "/http/reliable/retryFile", &result);
726     if (rc != 0)
727         result = true;
728 
729     return result;
730 }
731 
KNSManagerLoadMaxNumberOfRetriesOnFailureForReliableURLs(const KConfig * kfg)732 static uint8_t KNSManagerLoadMaxNumberOfRetriesOnFailureForReliableURLs
733 (const KConfig *kfg)
734 {
735     int64_t result = 0;
736     rc_t rc = KConfigReadI64(kfg, "/http/reliable/retries", &result);
737     if (rc != 0 || result < 0)
738         result = 10;
739 
740     return result;
741 }
742 
743 #if 0
744 static bool KNSManagerLoadLogTlsErrors(KConfig* kfg) {
745     const char * e = getenv("NCBI_VDB_TLS_LOG_ERR");
746     if (e != NULL)
747         if (e[0] == '\0')
748             return true;
749         else {
750             if (e[0] == '0' ||
751                 e[0] == 'f') /* false */
752             {
753                 return false;
754             }
755             else
756                 return true;
757         }
758     else {
759         bool log = false;
760         rc_t rc = KConfigReadBool(kfg, "/tls/NCBI_VDB_TLS_LOG_ERR", &log);
761         if (rc != 0)
762             return false;
763         else
764             return log;
765     }
766 }
767 
768 static int KNSManagerLoadEmulateTldReadErrors(KConfig* kfg) {
769     const char * e = getenv("NCBI_VDB_ERR_MBEDTLS_READ");
770     if (e != NULL)
771         return atoi(e);
772     else {
773         int64_t emult = 0;
774         rc_t rc = KConfigReadI64(kfg, "/tls/NCBI_VDB_ERR_MBEDTLS_READ", &emult);
775         if (rc != 0)
776             return 0;
777         else
778             return emult;
779     }
780 }
781 #endif
782 
KNSManagerLoadResolveToCache(KConfig * kfg)783 static bool KNSManagerLoadResolveToCache ( KConfig *kfg )
784 {
785     /* VResolverCache resolve to user's cache vs. cwd/AD */
786     bool reslt = true;
787 
788     /* TODO: call ncbi-vdb/interfaces/kfg/properties.h for exact key name */
789     rc_t rc
790         = KConfigReadBool ( kfg, "/tools/prefetch/download_to_cache", &reslt );
791     if ( rc == 0 ) { return reslt; }
792 
793     return true;
794 }
795 
KNSManagerLoadAcceptAwsCharges(KConfig * kfg)796 static bool KNSManagerLoadAcceptAwsCharges ( KConfig *kfg )
797 {
798     bool reslt = false;
799 
800     /* TODO: call ncbi-vdb/interfaces/kfg/properties.h for exact key name */
801     rc_t rc = KConfigReadBool ( kfg, "/libs/cloud/accept_aws_charges", &reslt );
802     if ( rc == 0 ) { return reslt; }
803 
804     return false;
805 }
806 
KNSManagerLoadAcceptGcpCharges(KConfig * kfg)807 static bool KNSManagerLoadAcceptGcpCharges ( KConfig *kfg )
808 {
809     bool reslt = false;
810 
811     /* TODO: call ncbi-vdb/interfaces/kfg/properties.h for exact key name */
812     rc_t rc = KConfigReadBool ( kfg, "/libs/cloud/accept_gcp_charges", &reslt );
813     if ( rc == 0 ) { return reslt; }
814 
815     return false;
816 }
817 
KNSManagerMakeConfigImpl(KNSManager ** mgrp,KConfig * kfg)818 static rc_t CC KNSManagerMakeConfigImpl ( KNSManager **mgrp, KConfig *kfg )
819 {
820     rc_t rc;
821 
822     if ( mgrp == NULL || kfg == NULL ) {
823         rc = RC ( rcNS, rcMgr, rcAllocating, rcParam, rcNull );
824     } else {
825         KNSManager *mgr = calloc ( 1, sizeof *mgr );
826         if ( mgr == NULL ) {
827             rc = RC ( rcNS, rcMgr, rcAllocating, rcMemory, rcExhausted );
828         } else {
829             KRefcountInit ( &mgr->refcount, 1, "KNSManager", "init", "kns" );
830 
831             mgr->conn_timeout = KNSManagerLoadConnTimeout ( kfg );
832             mgr->conn_read_timeout = KNSManagerLoadConnReadTimeout ( kfg );
833             mgr->conn_write_timeout = KNSManagerLoadConnWriteTimeout ( kfg );
834             mgr->http_read_timeout = KNSManagerLoadHttpReadTimeout ( kfg );
835             mgr->http_write_timeout = KNSManagerLoadHttpWriteTimeout ( kfg );
836 
837             mgr->maxTotalWaitForReliableURLs_ms =
838                 KNSManagerLoadTotalWaitForReliableURLs ( kfg );
839 
840             mgr->maxTotalConnectWaitForReliableURLs_ms =
841                 KNSManagerLoadTotalConnectWaitForReliableURLs ( kfg );
842 
843             mgr->maxNumberOfRetriesOnFailureForReliableURLs =
844                 KNSManagerLoadMaxNumberOfRetriesOnFailureForReliableURLs( kfg );
845 
846             mgr->retryFirstRead = KNSManagerLoadRetryFirstRead(kfg);
847             mgr->retryFile = KNSManagerLoadRetryFile ( kfg );
848             mgr->max_http_read_timeout = 60 * 1000; /* 1 minute */
849             /*          mgr->logTlsErrors = KNSManagerLoadLogTlsErrors(kfg);
850                         mgr->emulateTlsReadErrors
851                             = KNSManagerLoadEmulateTldReadErrors(kfg); */
852 
853             mgr->resolveToCache = KNSManagerLoadResolveToCache ( kfg );
854 
855             mgr->accept_aws_charges = KNSManagerLoadAcceptAwsCharges ( kfg );
856             mgr->accept_gcp_charges = KNSManagerLoadAcceptGcpCharges ( kfg );
857 
858             if ( strlen ( kns_manager_guid.base ) == 0 ) {
859                 rc = KDataBufferResize ( &kns_manager_guid, 37 );
860                 size_t written = 0;
861                 KConfig_Get_GUID ( kfg, kns_manager_guid.base,
862                     KDataBufferBytes ( &kns_manager_guid ), &written );
863                 assert ( written <= 37 );
864             }
865 
866             rc = KNSManagerInit (); /* platform specific init in sysmgr.c ( in
867                                        unix|win etc. subdir ) */
868             if ( rc == 0 ) {
869                 /* the manager is not a proper singleton */
870                 if ( strlen ( kns_manager_user_agent.base ) == 0 ) {
871                     ver_t version = RELEASE_VERS;
872                     KNSManagerSetUserAgent (
873                         mgr, PKGNAMESTR " ncbi-vdb.%V", version );
874                 }
875 
876                 rc = HttpRetrySpecsInit ( &mgr->retry_specs, kfg );
877                 if ( rc == 0 ) {
878                     rc = KTLSGlobalsInit ( &mgr->tlsg, kfg );
879 
880                     if ( rc == 0 ) {
881                         rc = KNSManagerHttpProxyInit ( mgr, kfg );
882                     }
883 
884                     if ( rc == 0 ) {
885                         KNSManagerSetNCBI_VDB_NET ( mgr, kfg );
886 
887                         *mgrp = mgr;
888 
889                         /*
890                         printf("KNSManager.conn_timeout(%d) = %d\n",
891                         MAX_CONN_LIMIT, mgr->conn_timeout);
892                         printf("KNSManager.conn_read_timeout(%d) = %d\n",
893                         MAX_CONN_READ_LIMIT, mgr->conn_read_timeout);
894                         printf("KNSManager.conn_write_timeout(%d) = %d\n",
895                         MAX_CONN_WRITE_LIMIT, mgr->conn_write_timeout);
896                         printf("KNSManager.http_read_timeout(%d) = %d\n",
897                         MAX_HTTP_READ_LIMIT, mgr->http_read_timeout);
898                         printf("KNSManager.http_write_timeout(%d) = %d\n",
899                         MAX_HTTP_WRITE_LIMIT, mgr->http_write_timeout);
900                         */
901 
902                         return 0;
903                     }
904                 }
905             }
906 
907             free ( mgr );
908         }
909 
910         *mgrp = NULL;
911     }
912 
913     return rc;
914 }
915 
KNSManagerMakeWithConfig(KNSManager ** mgrp,KConfig * kfg)916 LIB_EXPORT rc_t CC KNSManagerMakeWithConfig ( KNSManager **mgrp, KConfig *kfg )
917 {
918     return KNSManagerMakeSingleton ( mgrp, kfg, false );
919 }
920 
KNSManagerMakeLocal(KNSManager ** mgrp,KConfig * kfg)921 LIB_EXPORT rc_t CC KNSManagerMakeLocal ( KNSManager **mgrp, KConfig *kfg )
922 {
923     return KNSManagerMakeSingleton ( mgrp, kfg, true );
924 }
925 
KNSManagerMakeConfig(KNSManager ** mgrp,KConfig * kfg)926 LIB_EXPORT rc_t CC KNSManagerMakeConfig ( KNSManager **mgrp, KConfig *kfg )
927 {
928     return KNSManagerMakeLocal ( mgrp, kfg );
929 }
930 
KNSManagerSetUserAgent(KNSManager * self,const char * fmt,...)931 LIB_EXPORT rc_t CC KNSManagerSetUserAgent (
932     KNSManager *self, const char *fmt, ... )
933 {
934     /* 6/18/14 - don't check "self", since the current implementation
935        is actually static. Later implementations will not be...
936        Cast silences warning
937        */
938     (void)( self );
939 
940     rc_t rc = 0;
941     if ( fmt == NULL ) {
942         rc = RC ( rcNS, rcMgr, rcUpdating, rcParam, rcNull );
943         return rc;
944     }
945 
946     KDataBufferResize ( &kns_manager_user_agent, 0 );
947     va_list args;
948     va_start ( args, fmt );
949     rc = KDataBufferVPrintf ( &kns_manager_user_agent, fmt, args );
950     va_end ( args );
951 
952     return rc;
953 }
954 
KNSManagerGetUserAgent(const char ** user_agent)955 LIB_EXPORT rc_t CC KNSManagerGetUserAgent ( const char **user_agent )
956 {
957     rc_t rc = 0;
958     if ( user_agent == NULL ) {
959         rc = RC ( rcNS, rcMgr, rcAccessing, rcParam, rcNull );
960         return rc;
961     }
962 
963     char cloudtrunc[64];
964     const char *cloudid = getenv ( ENV_MAGIC_CE_TOKEN );
965     if ( cloudid && strlen ( cloudid ) > 8 ) {
966         /* AWS access keys should always begin with AKIA,
967          * suffixes seems non-random */
968         strncpy ( cloudtrunc, cloudid + 4, sizeof cloudtrunc );
969         cloudtrunc[3] = '\0';
970         assert ( strlen ( cloudtrunc ) < ( sizeof cloudtrunc - 1 ) );
971     } else {
972         strcpy ( cloudtrunc, "noc" );
973     }
974 
975     const char *sessid = getenv ( ENV_VAR_SESSION_ID );
976     if ( sessid == NULL ) { sessid = "nos"; }
977 
978     const char *libc_version = "";
979 #if LINUX
980     libc_version = gnu_get_libc_version ();
981 #endif
982 
983     /* Sometimes called before KNSManagerMake */
984     const char *guid = "nog";
985 
986     if ( ( KDataBufferBytes ( &kns_manager_guid ) == 0 )
987         || ( strlen ( kns_manager_guid.base ) == 0 ) ) {
988         KConfig *kfg = NULL;
989         KConfigMake ( &kfg, NULL );
990         size_t written = 0;
991 
992         rc = KDataBufferResize ( &kns_manager_guid, 37 );
993         if ( rc ) {
994             /* Some tests whack guid */
995             rc = KDataBufferMakeBytes ( &kns_manager_guid, 37 );
996             if ( rc ) { return rc; }
997         }
998 
999         KConfig_Get_GUID ( kfg, kns_manager_guid.base,
1000             KDataBufferBytes ( &kns_manager_guid ), &written );
1001         assert ( written <= 37 );
1002 
1003         if ( kfg ) KConfigRelease ( kfg );
1004     }
1005 
1006     if ( strlen ( kns_manager_guid.base ) ) guid = kns_manager_guid.base;
1007 
1008     KDataBuffer phid;
1009     KDataBufferMakeBytes ( &phid, 0 );
1010     rc = KDataBufferPrintf (
1011         &phid, "%.3s%.4s%.3s,libc=%s", cloudtrunc, guid, sessid, libc_version );
1012     if ( rc ) { return rc; }
1013 
1014     if ( kns_manager_lock ) {
1015         rc_t rc = KLockAcquire ( kns_manager_lock );
1016         if ( rc ) { return rc; }
1017     }
1018 
1019     /* Some tests call before these are initialized */
1020     if ( KDataBufferBytes ( &kns_manager_user_agent ) == 0 )
1021         KDataBufferPrintf ( &kns_manager_user_agent, "%s", "" );
1022 
1023     if ( kns_manager_lock ) { KLockUnlock ( kns_manager_lock ); }
1024 
1025     KDataBuffer sessids;
1026     KDataBufferMakeBytes ( &sessids, 0 );
1027 
1028     /* If any are populated, emit all */
1029     if ( strlen ( kns_manager_clientip )
1030         || strlen ( kns_manager_sessionid )
1031         || strlen ( kns_manager_pagehitid ) ) {
1032         rc = KDataBufferPrintf ( &sessids, "cip=%s,sid=%s,pagehit=%s",
1033             kns_manager_clientip, kns_manager_sessionid,
1034             kns_manager_pagehitid );
1035     }
1036 
1037     if ( rc ) { return rc; }
1038 
1039     if ( sessids.base && strlen ( sessids.base ) ) {
1040         const String *b64;
1041         encodeBase64 ( &b64, sessids.base, strlen ( sessids.base ) );
1042         rc = string_printf ( kns_manager_user_agent_append, sizeof kns_manager_user_agent_append, NULL,
1043             "%s%s (phid=%s,%s)", kns_manager_user_agent.base,
1044             kns_manager_ua_suffix, phid.base, b64->addr );
1045         StringWhack ( b64 );
1046     } else {
1047         rc = string_printf ( kns_manager_user_agent_append, sizeof kns_manager_user_agent_append, NULL,
1048             "%s%s (phid=%s)", kns_manager_user_agent.base, kns_manager_ua_suffix, phid.base );
1049     }
1050 
1051     KDataBufferWhack ( &phid );
1052     KDataBufferWhack ( &sessids );
1053 
1054     ( *user_agent ) = kns_manager_user_agent_append;
1055     return rc;
1056 }
1057 
1058 
1059 /******************************************************************************/
1060 
1061 #define NCBI_VDB_NET                                                           \
1062     1 /* VDB-3399 : temporarily enable for internal testing                    \
1063        */
1064 
KNSManagerSetLogNcbiVdbNetError(KNSManager * self,bool set)1065 void KNSManagerSetLogNcbiVdbNetError ( KNSManager *self, bool set )
1066 {
1067     if ( self ) { self->NCBI_VDB_NETnoLogError = !set; }
1068 }
1069 
KNSManagerLogNcbiVdbNetError(const KNSManager * self)1070 bool KNSManagerLogNcbiVdbNetError ( const KNSManager *self )
1071 {
1072     if ( self == NULL ) {
1073 #ifdef NCBI_VDB_NET
1074         return true;
1075 #else
1076         return false;
1077 #endif
1078     }
1079     if ( !self->logTlsErrors ) { return false; }
1080 
1081     if ( self->NCBI_VDB_NETnoLogError ) { return false; }
1082     const char *e = getenv ( "NCBI_VDB_NET" );
1083     if ( e != NULL ) {
1084         if ( e[0] == '0' || e[0] == 'f' ) /* false */
1085         {
1086             return false;
1087         }
1088 
1089         return true;
1090     }
1091     if ( self->NCBI_VDB_NETkfgValueSet ) { return self->NCBI_VDB_NETkfgValue; }
1092 
1093 
1094 #ifdef NCBI_VDB_NET
1095     return true;
1096 #else
1097     return false;
1098 #endif
1099 }
1100 
KNSManagerSetAdCaching(struct KNSManager * self,bool enabled)1101 LIB_EXPORT rc_t CC KNSManagerSetAdCaching (
1102     struct KNSManager *self, bool enabled )
1103 {
1104     if ( self != NULL )
1105         self->enabledResolveToAd = enabled;
1106     return 0;
1107 }
1108 
KNSManagerGetAdCaching(const KNSManager * self,bool * enabled)1109 LIB_EXPORT rc_t CC KNSManagerGetAdCaching(
1110     const KNSManager* self, bool * enabled)
1111 {
1112     assert(self && enabled);
1113     *enabled = self->enabledResolveToAd;
1114     return 0;
1115 }
1116 
KNSManagerGetResolveToCache(const KNSManager * self,bool * resolveToCache)1117 LIB_EXPORT rc_t CC KNSManagerGetResolveToCache(
1118     const KNSManager* self, bool * resolveToCache)
1119 {
1120     assert(self && resolveToCache);
1121     *resolveToCache = self->resolveToCache;
1122     return 0;
1123 }
1124 
1125 /*
1126 LIB_EXPORT rc_t CC KNSManagerSetClientIPv4 (
1127     KNSManager *self, uint32_t client_ipv4_addr)
1128 {
1129     if ( self == NULL )
1130         return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
1131     }
1132 
1133     char str[INET6_ADDRSTRLEN];
1134     struct in_addr ina;
1135 
1136     ina.s_addr=client_ipv4_addr;
1137 
1138     if (inet_ntop(AF_INET, &ina, str, sizeof str)==NULL)
1139         return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
1140 
1141     if ( kns_manager_lock ) {
1142         rc_t rc = KLockAcquire ( kns_manager_lock );
1143         if ( rc ) { return rc; }
1144     }
1145     string_copy ( kns_manager_clientip, sizeof kns_manager_clientip, ipv4,
1146         strlen ( ipv4 ) );
1147 
1148     if ( kns_manager_lock ) { KLockUnlock ( kns_manager_lock ); }
1149     return 0;
1150 }
1151 
1152 LIB_EXPORT rc_t CC KNSManagerSetClientIPv6 (
1153     KNSManager *self, uint16_t client_ipv6_addr[])
1154 {
1155     if ( self == NULL )
1156         return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
1157     }
1158 
1159     char str[INET6_ADDSTRLEN];
1160     struct in6_addr ina;
1161 
1162     memcpy(&ina.s6_addr,client_ipv6_addr, 16);
1163     ina.s_addr=client_ipv6_addr;
1164 
1165     if (inet_ntop(AF_INET6, &ina, str, sizeof str)==NULL)
1166         return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
1167 
1168     if ( kns_manager_lock ) {
1169         rc_t rc = KLockAcquire ( kns_manager_lock );
1170         if ( rc ) { return rc; }
1171     }
1172     string_copy ( kns_manager_clientip, sizeof kns_manager_clientip, ipv4,
1173         strlen ( ipv4 ) );
1174 
1175     if ( kns_manager_lock ) { KLockUnlock ( kns_manager_lock ); }
1176     return 0;
1177 }
1178 */
KNSManagerSetUserAgentSuffix(const char * suffix)1179 LIB_EXPORT rc_t CC KNSManagerSetUserAgentSuffix ( const char *suffix )
1180 {
1181     if ( suffix == NULL ) {
1182         return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
1183     }
1184     size_t len = strlen( suffix );
1185     if ( len >= KNSMANAGER_STRING_MAX )
1186     {
1187         return RC ( rcNS, rcMgr, rcAttaching, rcParam, rcTooLong );
1188     }
1189 
1190     string_copy ( kns_manager_ua_suffix, sizeof kns_manager_ua_suffix, suffix, len );
1191     return 0;
1192 }
1193 
KNSManagerGetUserAgentSuffix(const char ** suffix)1194 LIB_EXPORT rc_t CC KNSManagerGetUserAgentSuffix ( const char ** suffix )
1195 {
1196     if ( suffix == NULL ) {
1197         return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
1198     }
1199     *suffix = kns_manager_ua_suffix;
1200     return 0;
1201 }
1202 
KNSManagerSetClientIP(KNSManager * self,const char * clientip)1203 LIB_EXPORT rc_t CC KNSManagerSetClientIP (
1204     KNSManager *self, const char *clientip )
1205 {
1206     if ( self == NULL || clientip == NULL ) {
1207         return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
1208     }
1209     size_t len = strlen( clientip );
1210     if ( len >= KNSMANAGER_STRING_MAX )
1211     {
1212         return RC ( rcNS, rcMgr, rcAttaching, rcParam, rcTooLong );
1213     }
1214 
1215     string_copy ( kns_manager_clientip, sizeof kns_manager_clientip, clientip, len );
1216     return 0;
1217 }
1218 
KNSManagerSetSessionID(KNSManager * self,const char * sessionid)1219 LIB_EXPORT rc_t CC KNSManagerSetSessionID (
1220     KNSManager *self, const char *sessionid )
1221 {
1222     if ( self == NULL || sessionid == NULL ) {
1223         return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
1224     }
1225     size_t len = strlen( sessionid );
1226     if ( len >= KNSMANAGER_STRING_MAX )
1227     {
1228         return RC ( rcNS, rcMgr, rcAttaching, rcParam, rcTooLong );
1229     }
1230 
1231     string_copy ( kns_manager_sessionid, sizeof kns_manager_sessionid, sessionid, len );
1232     return 0;
1233 }
1234 
1235 
KNSManagerSetPageHitID(KNSManager * self,const char * pagehitid)1236 LIB_EXPORT rc_t CC KNSManagerSetPageHitID (
1237     KNSManager *self, const char *pagehitid )
1238 {
1239     if ( self == NULL || pagehitid == NULL ) {
1240         return RC ( rcNS, rcMgr, rcAttaching, rcRefcount, rcInvalid );
1241     }
1242     size_t len = strlen( pagehitid );
1243     if ( len >= KNSMANAGER_STRING_MAX )
1244     {
1245         return RC ( rcNS, rcMgr, rcAttaching, rcParam, rcTooLong );
1246     }
1247 
1248     string_copy ( kns_manager_pagehitid, sizeof kns_manager_pagehitid, pagehitid, len );
1249     return 0;
1250 }
1251 
1252 
1253 LIB_EXPORT
KNSManagerSetQuitting(KNSManager * self,quitting_t aQuitting)1254 rc_t CC KNSManagerSetQuitting(KNSManager *self, quitting_t aQuitting)
1255 {
1256     quitting = aQuitting;
1257     return 0;
1258 }
1259 
1260 LIB_EXPORT
KNSManagerGetQuitting(const KNSManager * self)1261 quitting_t CC KNSManagerGetQuitting(const KNSManager *self)
1262 {
1263     return quitting;
1264 }
1265 
1266 /******************************************************************************/
1267 /**************** API to manage HTTP File read retry behavior *****************/
1268 /******************************************************************************/
1269 
1270 /* SetRetryFailedReads
1271  *  manages retry layer on HttpFileRead
1272  *
1273  *  "retry" [ IN ] - true : turn on retry layer,
1274  *                   false: don't create retry layer.
1275  */
KNSManagerSetRetryFailedReads(KNSManager * self,bool retry)1276 KNS_EXTERN rc_t CC KNSManagerSetRetryFailedReads(KNSManager *self,
1277     bool retry)
1278 {
1279     if (self == NULL)
1280         return RC(rcNS, rcMgr, rcUpdating, rcSelf, rcNull);
1281     else {
1282         self->retryFile = retry;
1283         return 0;
1284     }
1285 }
1286 
1287 /* GetRetryFailedReads
1288  *  returns whether or not retry layer on HttpFileRead is turned on
1289  */
KNSManagerGetRetryFailedReads(const KNSManager * self,bool * retry)1290 LIB_EXPORT rc_t CC KNSManagerGetRetryFailedReads(const KNSManager *self,
1291     bool *retry)
1292 {
1293     if (self == NULL)
1294         return RC(rcNS, rcMgr, rcAccessing, rcSelf, rcNull);
1295     else if (retry == NULL)
1296         return RC(rcNS, rcMgr, rcAccessing, rcParam, rcNull);
1297     else {
1298         *retry = self->retryFile;
1299         return 0;
1300     }
1301 }
1302 
1303 /* SetMaxConnectRetryTime
1304  *  sets maximum time when opening HttpFile
1305  *
1306  *  "millis" - when negative, infinite timeout
1307  */
KNSManagerSetMaxConnectRetryTime(KNSManager * self,int32_t millis)1308 LIB_EXPORT rc_t CC KNSManagerSetMaxConnectRetryTime(KNSManager *self,
1309     int32_t millis)
1310 {
1311     if (self == NULL)
1312         return RC(rcNS, rcMgr, rcUpdating, rcSelf, rcNull);
1313     else {
1314         if (millis < 0)
1315             self->maxTotalConnectWaitForReliableURLs_ms = ~0;
1316         else
1317             self->maxTotalConnectWaitForReliableURLs_ms = millis;
1318 
1319         return 0;
1320     }
1321 }
1322 
1323 /* SetMaxReadRetryTime
1324  *  sets maximum time in HttpFileRead retry loop
1325  *
1326  *  "millis" - when negative, infinite timeout
1327  */
KNSManagerSetMaxReadRetryTime(KNSManager * self,int32_t millis)1328 LIB_EXPORT rc_t CC KNSManagerSetMaxReadRetryTime(KNSManager *self,
1329     int32_t millis)
1330 {
1331     if (self == NULL)
1332         return RC(rcNS, rcMgr, rcUpdating, rcSelf, rcNull);
1333     else {
1334         if (millis < 0)
1335             self->maxTotalWaitForReliableURLs_ms = ~0;
1336         else
1337             self->maxTotalWaitForReliableURLs_ms = millis;
1338 
1339         return 0;
1340     }
1341 }
1342 
1343 /* GetMaxReadRetryTime
1344  *  returns maximum time in HttpFileRead retry loop
1345  */
KNSManagerGetMaxReadRetryTime(const KNSManager * self,int32_t * millis)1346 LIB_EXPORT rc_t CC KNSManagerGetMaxReadRetryTime(const KNSManager *self,
1347     int32_t *millis)
1348 {
1349     if (self == NULL)
1350         return RC(rcNS, rcMgr, rcAccessing, rcSelf, rcNull);
1351     else if (millis == NULL)
1352         return RC(rcNS, rcMgr, rcAccessing, rcParam, rcNull);
1353     else {
1354         if (self->maxTotalWaitForReliableURLs_ms == ~0)
1355             *millis = -1;
1356         else
1357             *millis = self->maxTotalWaitForReliableURLs_ms;
1358 
1359         return 0;
1360     }
1361 }
1362 
1363 
1364 /* GetMaxConnectRetryTime
1365  *  returns maximum time when opening HttpFile
1366  */
KNSManagerGetMaxConnectRetryTime(const KNSManager * self,int32_t * millis)1367 LIB_EXPORT rc_t CC KNSManagerGetMaxConnectRetryTime(const KNSManager *self,
1368     int32_t *millis)
1369 {
1370     if (self == NULL)
1371         return RC(rcNS, rcMgr, rcAccessing, rcSelf, rcNull);
1372     else if (millis == NULL)
1373         return RC(rcNS, rcMgr, rcAccessing, rcParam, rcNull);
1374     else {
1375         if (self->maxTotalConnectWaitForReliableURLs_ms == ~0)
1376             *millis = -1;
1377         else
1378             *millis = self->maxTotalConnectWaitForReliableURLs_ms;
1379 
1380         return 0;
1381     }
1382 }
1383 
1384 
1385 /* SetRetryFirstReads
1386  *  manages retry on the first HttpFileRead
1387  */
KNSManagerSetRetryFirstReads(KNSManager * self,bool retry)1388 LIB_EXPORT rc_t CC KNSManagerSetRetryFirstReads(KNSManager *self,
1389     bool retry)
1390 {
1391     if (self == NULL)
1392         return RC(rcNS, rcMgr, rcUpdating, rcSelf, rcNull);
1393     else {
1394         self->retryFirstRead = retry;
1395         return 0;
1396     }
1397 }
1398 
1399 /* GetRetryFirstReads
1400  *  returns whether or not retry on the first HttpFileRead is turned on
1401  */
KNSManagerGetRetryFirstReads(const KNSManager * self,bool * retry)1402 LIB_EXPORT rc_t CC KNSManagerGetRetryFirstReads(const KNSManager *self,
1403     bool *retry)
1404 {
1405     if (self == NULL)
1406         return RC(rcNS, rcMgr, rcAccessing, rcSelf, rcNull);
1407     else if (retry == NULL)
1408         return RC(rcNS, rcMgr, rcAccessing, rcParam, rcNull);
1409     else {
1410         *retry = self->retryFirstRead;
1411         return 0;
1412     }
1413 }
1414 
1415 /******************************************************************************/
1416