1 #ifndef CONNECT___NCBI_LBOSP__H
2 #define CONNECT___NCBI_LBOSP__H
3 /*
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  * Authors:  Dmitriy Elisov
29  * Credits:  Denis Vakatov
30  * @file
31  * File Description:
32  *   This header was made only because of unit testing application. Please,
33  *   include only ncbi_lbos.h.
34  *   This file contains only those elements that are absolutely unneeded
35  *   if you do not want to dive into internal LBOS client implementation.
36 */
37 #include "ncbi_servicep.h"
38 #include <connect/ncbi_http_connector.h>
39 #include "ncbi_lbos.h"
40 
41 
42 #ifdef __cplusplus
43 extern "C" {
44 #endif /*__cplusplus*/
45 
46 #ifndef LBOS_METADATA
47 #define LBOS_METADATA
48 #endif
49 
50 /*
51  * Additional HTTP codes:
52  *  450 - LBOS not found
53  *  451 - DNS resolve failed for healthcheck URL
54  *  452 - Invalid arguments provided, request was not sent to LBOS
55  *  453 - Memory allocation error encountered
56  *  454 - LBOS output could not be parsed
57  *  550 - LBOS client is OFF in the current process
58  */
59 enum ELBOSStatusCodes {
60     eLBOS_Success         = 200, /**< HTTP 200 OK */
61     eLBOS_BadRequest      = 400, /**< HTTP 400 Bad Request */
62     eLBOS_NotFound        = 404, /**< HTTP 404 Not Found */
63     eLBOS_LbosNotFound    = 450, /**< Not a HTTP code. LBOS was not found */
64     eLBOS_DNSResolve      = 451, /**< Not a HTTP code. Could not find IP of
65                                       localhost */
66     eLBOS_InvalidArgs     = 452, /**< Not a HTTP code. Some arguments were
67                                       invalid */
68     eLBOS_MemAlloc        = 453, /**< Not a HTTP code. Some memory could not be
69                                       allocated */
70     eLBOS_Protocol        = 454, /**< Not a HTTP code. LBOS response could not
71                                       be parsed */
72     eLBOS_Server          = 500, /**< HTTP 500 Internal Server Error */
73     eLBOS_Disabled        = 550  /**< Not a HTTP code. LBOS Client functionality
74                                       is disabled in registry or during
75                                       initialization (LBOS Client could not
76                                       establish connection with LBOS) */
77 };
78 
79 ///////////////////////////////////////////////////////////////////////////////
80 //                             DATA TYPES                                    //
81 ///////////////////////////////////////////////////////////////////////////////
82 /** @brief Possible values to set primary address where to search for LBOS.
83  *
84  * LBOS can be located in different places, such as:
85  *   - localhost,
86  *   - home zone server (i.e. LBOS.dev.be-md.ncbi.nlm.nih.gov, if you
87  *     are be-md domain on dev machine),
88  *   - somewhere else (set in registry with [CONN]LBOS)
89  * You can set priority for the first place to try. If LBOS is not found in
90  * this primary location, then it will be searched for in other places
91  * following default algorithm of going through places (maybe even through
92  * the same place again).                                                    */
93 typedef enum {
94     eLBOSFindMethod_None,           /**< do not search. Used to skip
95                                          "custom host" method                */
96     eLBOS_FindMethod_CustomHost,     /**< Use custom address provided by
97                                          s_SetLBOSaddress()                  */
98     eLBOS_FindMethod_Registry,       /**< Use value from registry (default)   */
99     eLBOS_FindMethod_Lbosresolve,    /**< Use value from /etc/ncbi/lbosresolve*/
100 } ELBOSFindMethod;
101 
102 
103 /** Very simple internal structure which stores information about found
104  * servers.                                                                  */
105 typedef struct {
106     SSERV_Info*         info;        /**< Stores only IP and port for now    */
107 } SLBOS_Candidate;
108 
109 
110 /** All the data required to store state of one request to LBOS between
111  * calls to SERV_GetNextInfo.                                                */
112 typedef struct {
113     SConnNetInfo*       net_info;    /**< Connection point                   */
114     const char*         lbos_addr;   /**< LBOS host:port or IP:port. Used if
115                                           find_method ==
116                                           eLBOS_FindMethod_CustomHost        */
117     SLBOS_Candidate*    cand;        /**< Array of found server to iterate   */
118     size_t              pos_cand;    /**< Current candidate                  */
119     size_t              n_cand;      /**< Used space for candidates          */
120     size_t              a_cand;      /**< Allocated space for candidates     */
121     ELBOSFindMethod     find_method; /**< How we find LBOS. Mainly for
122                                           testing                            */
123 } SLBOS_Data;
124 
125 
126 /** Data structure to use as user_data in HTTP Connector (header is used
127  *  only for unit testing)                                                   */
128 typedef struct {
129     int http_response_code;
130     char* http_status_mesage;
131     const char* header;
132     size_t content_length; /**< Value of "Content-length" HTTP header tag.
133                                 -1 (max value) as no limit */
134 } SLBOS_UserData;
135 
136 
137 /** Used for internal storage, so that DeannounceAll() could deannounce
138  *  everything that was announced earlier.
139  * @see
140  *  DeannounceAll()
141  */
142 struct SLBOS_AnnounceHandle_Tag
143 {
144     char*            service;       /**< service name of announced server    */
145     char*            version;       /**< service version of announced server */
146     char*            host;          /**< host of announced server            */
147     unsigned short   port;          /**< port of announced server            */
148 };
149 
150 
151 /** Possible values of parameter for g_LBOS_CheckIterator(),
152  *  this enum is used only in assertions
153  * @see
154  *  g_LBOS_CheckIterator()                                                   */
155 typedef enum {
156     ELBOSIteratorCheckType_MustHaveData,   /**< Iterator MUST have 'data'
157                                                 filled or error will be
158                                                 returned                     */
159     ELBOSIteratorCheckType_DataMustBeNULL, /**< Iterator MUST have 'data'
160                                                 NULL or error will be
161                                                 returned                     */
162     ELBOSIteratorCheckType_NoCheck         /**< No check of 'data'           */
163 } ELBOSIteratorCheckType;
164 
165 ///////////////////////////////////////////////////////////////////////////////
166 //                        MOCK FUNCTION TYPEDEFS                             //
167 ///////////////////////////////////////////////////////////////////////////////
168 /** Send REST API request to LBOS, read answer and return filled array of
169  * SSERV_INFO, containing info about all found servers.
170  * @param lbos_address[in]
171  *  IP:port or host:port where to send request.
172  * @param serviceName[in]
173  *  Name of service to ask for.
174  * @param net_info[in]
175  *  Connection point.
176  * @return
177  *  Array of pointers to SSERV_Info structs, containing all found servers.
178  */
179 typedef
180 SSERV_Info** FLBOS_ResolveIPPortMethod(const char*     lbos_address,
181                                        const char*     serviceName,
182                                        SConnNetInfo*   net_info);
183 
184 
185 /** Read from connection. Handles buffer itself.
186  * @param conn[in]
187  *  Connection handle.
188  * @param buf[in]
189  *  Memory buffer to read to.
190  * @param size[in]
191  *  Max. # of bytes to read.
192  * @param n_read[out]
193  *  Non-NULL, # of actually read bytes.
194  * @param how[in]
195  *  Peek/read/persist.
196  * @return
197  *  Success or some error code.                                              */
198 typedef
199 EIO_Status FLBOS_ConnReadMethod(CONN           conn,
200                                 void*          buf,
201                                 size_t         size,
202                                 size_t*        n_read,
203                                 EIO_ReadMethod how);
204 
205 
206 /**  Given just empty data structure and name of service, do all necessary
207  *  operations to fill the structure with servers.
208  *  @param data[out]
209  *   This structure will be filled.
210  *  @param service[in]
211  *   Name of the service of which we search servers.                         */
212 typedef
213 void FLBOS_FillCandidatesMethod(SLBOS_Data* data,
214                                 const char* service);
215 
216 
217 /**  Destroy data (simulation of destructor as if SLBOS_Data were a class.
218  *  Please note that it will be free()'d and no following access is possible,
219  *  so setting data to NULL after this method is recommended for avoiding
220  *  confusion.
221  *  @param data[in]
222  *   Structure to be destroyed.
223  *  @note
224  *   It presumes that s_LBOS_Reset was called previously.
225  *  @see
226  *   S_LBOS_Reset(), SLBOS_Data                                              */
227 typedef
228 void FLBOS_DestroyDataMethod(SLBOS_Data* data);
229 
230 
231 /** Called under the hood of SERV_GetNextInfo and is responsible for
232  *  LBOS client.
233  *  @param iter[in]
234  *   Iterator used to iterate through servers.
235  *  @param host_info[out]
236  *   Supposed to be set to pointer to info about host on which returned
237  *   server resides, but due to limitations of AWS cloud, it is always NULL.
238  *  @return
239  *   Next server.                                                            */
240 typedef
241 SSERV_Info* FLBOS_GetNextInfoMethod(SERV_ITER  iter,
242                                     HOST_INFO* host_info);
243 
244 
245 /** For announcement we search for a LBOS which can handle our request.
246  * Search starts with default order of LBOS.
247  * @param service[in]
248  *  Name of service as it will appear in ZK. For services this means that
249  *  name should start with '/'.
250  * @param version[in]
251  *  Any non-NULL valid C-string.
252 * @param [in] host
253 *  Optional parameter (NULL to ignore). If provided, tells on which host
254 *  the server resides. Can be different from healthcheck host. If set to
255 *  NULL, host is taken from healthcheck.
256  * @param port[in]
257  *  Port for service. Can differ from healthcheck port.
258  * @param healthcheck_url[in]
259  *  Full absolute URL starting with "http://" or "https://". Should include
260  *  hostname or IP and port, if necessary.
261  * @param metadata[in]
262  *  URL-ready link with additional meta parameters
263  * @param LBOS_answer[out]
264  *  This variable will be assigned a pointer to char* with exact answer of
265  *  LBOS, or NULL. If it is not NULL, must be free()'d by the caller. If
266  *  eLBOS_Success is returned, LBOS answer contains "host:port"
267  *  of LBOS that was used for announce. If something else is returned, LBOS
268  *  answer contains human-readable error message.
269  * @return
270  *  Code of success or some error.
271  * @see
272  *  ELBOS_Result                                                             */
273 typedef
274 unsigned short FLBOS_AnnounceMethod(const char*     service,
275                                     const char*     version,
276                                     const char*     host,
277                                     unsigned short  port,
278                                     const char*     healthcheck_url,
279 #ifdef LBOS_METADATA
280                                     const char*     metadata,
281 #endif /* LBOS_METADATA */
282                                     char**          LBOS_answer,
283                                     char**          http_status_message);
284 
285 
286 /** Deannounce previously announced service.
287  * @param lbos_hostport[in]
288  *  Address of the same LBOS that was used for announcement of the service
289  *  now being de-announced.
290  * @param service[in]
291  *  Name of service to be de-announced.
292  * @param version[in]
293  *  Version of service to be de-announced.
294  * @param port[in]
295  *  Port of service to be de-announced.
296  * @param[in]
297  *  IP or hostname of service to be de-announced.
298  * @return
299  *  false - any error, no deannounce was made;
300  *  true - success, deannounce was made.                                     */
301 typedef
302 int/*bool*/ FLBOS_DeannounceMethod(const char*       lbos_hostport,
303                                    const char*       service,
304                                    const char*       version,
305                                    const char*       host,
306                                    unsigned short    port,
307                                    char**            lbos_answer,
308                                    int*              http_status_code,
309                                    char**            http_status_message);
310 
311 
312 /** This function test existence of the application that should always be
313  * found - LBOS itself. If it is not found, we turn client off.              */
314 typedef
315 void FLBOS_InitializeMethod(void);
316 
317 
318 typedef char* FLBOS_UrlReadAllMethod(SConnNetInfo* net_info,
319                                      const char*   url,
320                                      int*          status_code,
321                                      char**        status_message);
322 
323 
324 /** Standard parse header function. The only thing considered is that
325    standard "void* data" field is used as int code of HTTP response          */
326 typedef EHTTP_HeaderParse FLBOS_ParseHeader(const char*      header,
327                                              void* /* int* */response_code,
328                                              int             server_error);
329 
330 /** Get (and cache for faster follow-up retrievals) the address of
331  * local host.                                                               */
332 typedef unsigned int FLBOS_SOCKGetLocalHostAddressMethod(ESwitch reget);
333 
334 ///////////////////////////////////////////////////////////////////////////////
335 //                       VIRTUAL FUNCTIONS TABLE                             //
336 ///////////////////////////////////////////////////////////////////////////////
337 typedef struct {
338     FLBOS_ResolveIPPortMethod*              ResolveIPPort;
339     FLBOS_ConnReadMethod*                   Read;
340     FLBOS_FillCandidatesMethod*             FillCandidates;
341     FLBOS_DestroyDataMethod*                DestroyData;
342     FLBOS_GetNextInfoMethod*                GetNextInfo;
343     FLBOS_InitializeMethod*                 Initialize;
344     FLBOS_UrlReadAllMethod*                 UrlReadAll;
345     FLBOS_ParseHeader*                      ParseHeader;
346     FLBOS_SOCKGetLocalHostAddressMethod*    LocalHostAddr;
347     FLBOS_AnnounceMethod*                   AnnounceEx;
348 } SLBOS_Functions;
349 
350 
351 ///////////////////////////////////////////////////////////////////////////////
352 //                             GLOBAL FUNCTIONS                              //
353 ///////////////////////////////////////////////////////////////////////////////
354 /** Get the best possible LBOS address for this platform.
355  * @return
356  *  LBOS address that needs to be free()'d by the caller.
357  * @see
358  *  g_LBOS_GetLBOSAddressEx()                                              */
359 NCBI_XCONNECT_EXPORT
360 char* g_LBOS_GetLBOSAddress(void);
361 
362 
363 /** Get the best possible LBOS addresses for this platform, extended version -
364  * first tries the method of caller's choice.
365  * @param[in]   priority_find_method
366  *  First method to try.
367  * @param[in]   lbos_addr
368  *  String with "%hostname%:%port%" or "%IP%:%port%". If priority_find_method
369  *  is set to eLBOS_FindMethod_CustomHost, lbos_addr should be non-NULL
370  *  (or else the method will be ignored)
371  * @return
372  *  LBOS address that needs to be free()'d by the caller.
373  * @see
374  *  g_LBOS_GetLBOSAddress()                                                */
375 NCBI_XCONNECT_EXPORT
376 char* g_LBOS_GetLBOSAddressEx(ELBOSFindMethod priority_find_method,
377                               const char*     lbos_addr);
378 
379 /** Creates iterator and fills it with found servers.
380  * @param[in,out] iter
381  *  Pointer to iterator. It is read and rewritten. If nothing found, it is
382  *  free()'d and points to unallocated area.
383  * @param[in] net_info
384  *  Connection point.
385  * @param[out] info
386  *  Always assigned NULL, as not used in this client.
387  * @return
388  *  Table of methods if found servers, NULL if not found.
389  * @see
390  *  s_Open(), SERV_LOCAL_Open(), SERV_LBSMD_Open(), SERV_DISPD_Open()        */
391 NCBI_XCONNECT_EXPORT
392 const SSERV_VTable*  SERV_LBOS_Open(SERV_ITER           iter,
393                                     const SConnNetInfo* net_info,
394                                     SSERV_Info**        info);
395 
396 
397 /** Checks C-string if it is NULL or is of zero length.
398  * @param[in]   str
399  *  String to check.
400  * @return
401  *  true - string is NULL or empty;
402  *  false - string exists and contains elements.                             */
403 NCBI_XCONNECT_EXPORT
404 int/*bool*/ g_LBOS_StringIsNullOrEmpty(const char* str);
405 
406 
407 /** Compose LBOS address from /etc/ncbi/{role, domain}.
408  *  @return
409  *   LBOS address. Must be free()'d by the caller.                           */
410 NCBI_XCONNECT_EXPORT
411 char* g_LBOS_ComposeLBOSAddress(void);
412 
413 
414 /** Set primary method how to find LBOS. Default is eLBOS_FindMethod_Registry.
415  *  @param[in]  iter
416  *   Iterator that represents current request to LBOS.
417  *  @param[in]  method
418  *   One of methods.
419  *  @return             f
420  *   false - something went wrong, primary method was not changed;
421  *   true  - success.                                                        */
422 NCBI_XCONNECT_EXPORT
423 int/*bool*/ g_LBOS_UnitTesting_SetLBOSFindMethod(SERV_ITER        iter,
424                                                  ELBOSFindMethod  method);
425 
426 
427 /**  Set custom host for LBOS. It will be used when method
428  *  eLBOS_FindMethod_CustomHost is used.
429  *  @param[in]  iter
430  *   Iterator that represents current request to LBOS.
431  *  @param[in]  address
432  *   IP:port  or host:port to use.
433  *  @return
434  *   false - something went wrong, LBOS address was not changed.
435  *   true  - success.                                                        */
436 NCBI_XCONNECT_EXPORT
437 int/*bool*/ g_LBOS_UnitTesting_SetLBOSaddress(SERV_ITER  iter,
438                                               char*      address);
439 
440 
441 /**  Set custom files to load role and domain from, respectively.
442  *  @param lbosresolverFile[in]
443  *   To change lbosresolver file path, pass it here. To use current
444  *   lbosresolver file path, pass NULL.
445  *  @return
446  *   false - values not changed;
447  *   true  - success.                                                        */
448 NCBI_XCONNECT_EXPORT int/*bool*/
449 g_LBOS_UnitTesting_SetLBOSResolverFile(const char* lbosresolverFile);
450 
451 
452 /**  Checks iterator, fact that iterator belongs to this client, iterator data.
453  * Only debug function.
454  * @param iter[in]
455  *  Iterator to check. Not modified in any way.
456  * @param should_have_data[in]
457  *  How to check 'data' field of iterator.
458  * @see
459  *  ELBOSIteratorCheckType
460  * @return
461  *  true  - iterator is valid;
462  *  false - iterator is invalid.
463  */
464 NCBI_XCONNECT_EXPORT
465 int/*bool*/  g_LBOS_CheckIterator(SERV_ITER               iter,
466                                   ELBOSIteratorCheckType  should_have_data);
467 
468 /** Find server among announced and return its position. If not found,
469  * return -1.
470  */
471 NCBI_XCONNECT_EXPORT
472 int  g_LBOS_UnitTesting_FindAnnouncedServer(const char*          service,
473                                              const char*          version,
474                                              unsigned short       port,
475                                              const char*          host);
476 
477 /** Get LBOS-specific announcement variable from registry
478  */
479 NCBI_XCONNECT_EXPORT char* g_LBOS_RegGet(const char* section,
480                                           const char* name,
481                                           const char* def_value);
482 
483 
484 
485 /** This service can be used to remove service from configuration. Current
486  * version will be empty. Previous version shows deleted version.
487  */
488 NCBI_XCONNECT_EXPORT
489 unsigned short LBOS_ServiceVersionDelete(const char*   service,
490                                                char**  lbos_answer,
491                                                char**  http_status_message);
492 
493 
494 /** This request can be used to set new version for a service. Current and
495  * previous versions show currently set and previously used service versions.
496  * @param[in] service
497  *  Name of service for which the version is going to be changed
498  * @param new_version[out]
499  *  Version that will be used by default for specefied service
500  * @param lbos_answer[out]
501  *  Variable to be assigned pointer to C-string with LBOS answer
502  * @param http_status_message[out]
503  *  Variable to be assigned pointer to C-string with status message from LBOS
504  */
505 NCBI_XCONNECT_EXPORT
506 unsigned short LBOS_ServiceVersionSet(const char*   service,
507                                       const char*   new_version,
508                                             char**  lbos_answer,
509                                             char**  http_status_message);
510 
511 
512 /** This request will show currently used version for a requested service.
513 * Current and previous version will be the same.
514 * @param service[in]
515 *  Name of service for which to ask default version
516 * @param lbos_answer[out]
517 *  Variable to be assigned pointer to C-string with LBOS answer
518 * @param http_status_message[out]
519 *  Variable to be assigned pointer to C-string with status message from LBOS
520 * @return
521 *  Status code returned by LBOS
522 */
523 NCBI_XCONNECT_EXPORT
524 unsigned short LBOS_ServiceVersionGet(const char*  service,
525                                             char** lbos_answer,
526                                             char** http_status_message);
527 
528 ///////////////////////////////////////////////////////////////////////////////
529 //                      GLOBAL VARIABLES FOR UNIT TESTS                      //
530 ///////////////////////////////////////////////////////////////////////////////
531 
532 /** Table of all functions to mock, used solely for unit testing purposes.
533  * @see
534  *  SLBOS_Functions                                                          */
535 NCBI_XCONNECT_EXPORT
536 SLBOS_Functions* g_LBOS_UnitTesting_GetLBOSFuncs(void);
537 
538 
539 /** Check whether LBOS client is turned ON or OFF.
540  * @return
541  *  address of static variable s_LBOS_TurnedOn.
542  * @see
543  *  SERV_LBOS_Open()                                                         */
544 NCBI_XCONNECT_EXPORT
545 int* g_LBOS_UnitTesting_PowerStatus(void);
546 
547 
548 /** Check whether LBOS client is turned ON or OFF.
549  * @return
550  *  address of static variable s_LBOS_TurnedOn.
551  * @see
552  *  SERV_LBOS_Open()                                                         */
553 NCBI_XCONNECT_EXPORT
554 int* g_LBOS_UnitTesting_InitStatus(void);
555 
556 
557 /** List of addresses of LBOS that is maintained in actual state.
558  * @return
559  *  address of static variable s_LBOS_InstancesList.
560  * @see
561  *  SERV_LBOS_Open(), s_LBOS_FillCandidates()                                */
562 NCBI_XCONNECT_EXPORT
563 char** g_LBOS_UnitTesting_Instance(void);
564 
565 
566 /** List of announced servers that is stored statically
567  * @return
568  *  address of static variable s_LBOS_AnnouncedServers                       */
569 NCBI_XCONNECT_EXPORT
570 struct SLBOS_AnnounceHandle_Tag** g_LBOS_UnitTesting_GetAnnouncedServers(void);
571 
572 
573 /** Number of announced servers stored
574  * @return
575  *  pointer to s_LBOS_AnnouncedServersNum                                    */
576 NCBI_XCONNECT_EXPORT
577 int g_LBOS_UnitTesting_GetAnnouncedServersNum(void);
578 
579 
580 /**  Pointer to s_LBOS_Lbosresolver
581  *  @return
582  *   address of static variable s_LBOS_Lbosresolver.
583  *  @see                                                                     */
584 NCBI_XCONNECT_EXPORT
585 char** g_LBOS_UnitTesting_Lbosresolver(void);
586 
587 
588 #ifdef __cplusplus
589 } /* extern "C" */
590 #endif /*__cplusplus*/
591 
592 #endif /* CONNECT___NCBI_LBOSP__H */
593