NCBI C Toolkit Cross Reference

C/connect/ncbi_local.c


  1 /*  $Id: ncbi_local.c,v 1.15 2008/05/25 01:25:38 kazimird Exp $
  2  * ===========================================================================
  3  *
  4  *                            PUBLIC DOMAIN NOTICE
  5  *               National Center for Biotechnology Information
  6  *
  7  *  This software/database is a "United States Government Work" under the
  8  *  terms of the United States Copyright Act.  It was written as part of
  9  *  the author's official duties as a United States Government employee and
 10  *  thus cannot be copyrighted.  This software/database is freely available
 11  *  to the public for use. The National Library of Medicine and the U.S.
 12  *  Government have not placed any restriction on its use or reproduction.
 13  *
 14  *  Although all reasonable efforts have been taken to ensure the accuracy
 15  *  and reliability of the software and data, the NLM and the U.S.
 16  *  Government do not and cannot warrant the performance or results that
 17  *  may be obtained by using this software or data. The NLM and the U.S.
 18  *  Government disclaim all warranties, express or implied, including
 19  *  warranties of performance, merchantability or fitness for any particular
 20  *  purpose.
 21  *
 22  *  Please cite the author in any work or product based on this material.
 23  *
 24  * ===========================================================================
 25  *
 26  * Author:  Anton Lavrentiev
 27  *
 28  * File Description:
 29  *   Low-level API to resolve NCBI service name to the server meta-address
 30  *   with the use of local registry.
 31  *
 32  */
 33 
 34 #include "ncbi_ansi_ext.h"
 35 #include "ncbi_comm.h"
 36 #include "ncbi_lb.h"
 37 #include "ncbi_local.h"
 38 #include "ncbi_priv.h"
 39 #include <stdlib.h>
 40 
 41 
 42 #ifdef __cplusplus
 43 extern "C" {
 44 #endif /*__cplusplus*/
 45     static void        s_Reset      (SERV_ITER);
 46     static SSERV_Info* s_GetNextInfo(SERV_ITER, HOST_INFO*);
 47     static void        s_Close      (SERV_ITER);
 48 
 49     static const SSERV_VTable s_op = {
 50         s_Reset, s_GetNextInfo, 0/*Update*/, 0/*Penalize*/, s_Close, "LOCAL"
 51     };
 52 #ifdef __cplusplus
 53 } /* extern "C" */
 54 #endif /*__cplusplus*/
 55 
 56 
 57 struct SLOCAL_Data {
 58     SLB_Candidate* cand;
 59     size_t       i_cand;
 60     size_t       n_cand;
 61     size_t       a_cand;
 62     int/*bool*/  reset;
 63 };
 64 
 65 
 66 static int/*bool*/ s_AddService(const SSERV_Info* info,
 67                                 struct SLOCAL_Data* data)
 68 {
 69     if (data->a_cand <= data->n_cand) {
 70         size_t n = data->a_cand + 10;
 71         SLB_Candidate* temp =
 72             (SLB_Candidate*)(data->cand
 73                              ? realloc(data->cand, n * sizeof(*data->cand))
 74                              : malloc (            n * sizeof(*data->cand)));
 75         if (!temp)
 76             return 0/*false*/;
 77         data->a_cand = n;
 78         data->cand   = temp;
 79     }
 80 
 81     data->cand[data->n_cand++].info = info;
 82     return 1/*true*/;
 83 }
 84 
 85 
 86 static int/*bool*/ s_LoadSingleService(const char* name, SERV_ITER iter)
 87 {
 88     struct SLOCAL_Data* data = (struct SLOCAL_Data*) iter->data;
 89     const TSERV_Type type = iter->type & ~fSERV_Firewall;
 90     int/*bool*/ ok = 0/*failed*/;
 91     SSERV_Info* info;
 92     char* buf;
 93     int n;
 94 
 95     if (!(buf =
 96           (char*) malloc(strlen(name) + sizeof(REG_CONN_LOCAL_SERVER) + 80))) {
 97         return 0/*failed*/;
 98     }
 99 
100     info = 0;
101     for (n = 0;  n <= 100;  n++) {
102         char service[1024];
103         const char* c;
104 
105         if (info) {
106             free((void*) info);
107             info = 0;
108         }
109         sprintf(buf, "%s_" REG_CONN_LOCAL_SERVER "_%d", name, n);
110         if (!(c = getenv(buf))  &&  !(c = getenv(strupr(buf)))) {
111             char*  b = buf + strlen(name);
112             size_t len;
113             *b++ = '\0';
114             CORE_REG_GET(buf, b, service, sizeof(service) - 1, 0);
115             len = strlen(service);
116             if (len > 1  &&  (service[0] == '"'  ||  service[0] == '\'')
117                 &&  service[len - 1] == service[0]  &&  (len -= 2) > 0) {
118                 memmove(service, service + 1, len);
119                 service[len] = '\0';
120             }
121             if (!len)
122                 continue;
123             c = service;
124         }
125         if (!(info = SERV_ReadInfoEx
126               (c, iter->ismask  ||  iter->reverse_dns ? name : ""))) {
127             continue;
128         }
129         if (iter->external  &&  info->locl)
130             continue;  /* external mapping for local server not allowed */
131         if (!info->host  ||  (info->locl & 0xF0)) {
132             unsigned int localhost = SOCK_GetLocalHostAddress(eDefault);
133             if (!info->host)
134                 info->host = localhost;
135             if ((info->locl & 0xF0)  &&  info->host != localhost)
136                 continue;  /* private server */
137         }
138         if (!iter->reverse_dns  &&  info->type != fSERV_Dns) {
139             if (type != fSERV_Any  &&  !(type & info->type))
140                 continue;  /* type doesn't match */
141             if (type == fSERV_Any  &&  info->type == fSERV_Dns)
142                 continue;  /* DNS entries have to be req'd explicitly */
143             if (iter->stateless && info->sful && !(info->type & fSERV_Http))
144                 continue;  /* skip stateful only servers */
145         }
146         if (!info->rate)
147             info->rate = LBSM_DEFAULT_RATE;
148         if (!info->time)
149             info->time = LBSM_DEFAULT_TIME;
150 
151         if (!s_AddService(info, data))
152             break;
153 
154         info = 0;
155         ok = 1/*succeeded*/;
156     }
157     if (info)
158         free((void*) info);
159 
160     free(buf);
161     return ok/*whatever*/;
162 }
163 
164 
165 static int/*bool*/ s_LoadServices(SERV_ITER iter)
166 {
167     int/*bool*/ ok = 0/*false*/;
168     char services[1024];
169     const char* c;
170     char* s;
171 
172     if (!iter->ismask) {
173         ok = s_LoadSingleService(iter->name, iter);
174         if (!ok  ||  !iter->reverse_dns)
175             return ok;
176     }
177     if (!(c = ConnNetInfo_GetValue(0, REG_CONN_LOCAL_SERVICES,
178                                    services, sizeof(services), 0))  ||  !*c) {
179         return ok;
180     }
181 
182     s = services;
183     ok = 0/*false*/;
184     for (s += strspn(s, " \t");  *s;  s += strspn(s, " \t")) {
185         size_t len = strcspn(s, " \t");
186         assert(len);
187         if (s[len])
188             s[len++] = '\0';
189         if (!(c = SERV_ServiceName(s)))
190             break;
191         if ((iter->reverse_dns  ||  UTIL_MatchesMask(c, iter->name))  &&
192             s_LoadSingleService(c, iter)) {
193             ok = 1/*succeeded*/;
194         }
195         free((void*) c);
196         s += len;
197     }
198 
199     return ok/*whatever*/;
200 }
201 
202 
203 static int s_Sort(const void* p1, const void* p2)
204 {
205     const SLB_Candidate* c1 = (const SLB_Candidate*) p1;
206     const SLB_Candidate* c2 = (const SLB_Candidate*) p2;
207     if (c1->info->type == fSERV_Dns  ||  c2->info->type == fSERV_Dns) {
208         if (c1->info->type != fSERV_Dns)
209             return -1;
210         if (c2->info->type != fSERV_Dns)
211             return  1;
212     }
213     if ((int) c1->info->type < (int) c2->info->type)
214         return -1;
215     if ((int) c1->info->type > (int) c2->info->type)
216         return  1;
217     return 0;
218 }
219 
220 
221 static SLB_Candidate* s_GetCandidate(void* user_data, size_t i)
222 {
223     struct SLOCAL_Data* data = (struct SLOCAL_Data*) user_data;
224     return i < data->i_cand ? &data->cand[i] : 0;
225 }
226 
227 
228 static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info)
229 {
230     struct SLOCAL_Data* data = (struct SLOCAL_Data*) iter->data;
231     const TSERV_Type type = iter->type & ~fSERV_Firewall;
232     int/*bool*/ dns_info_seen = 0/*false*/;
233     SSERV_Info* info;
234     size_t i, n;
235 
236     assert(data);
237     if (data->reset) {
238         data->reset = 0/*false*/;
239         if (!s_LoadServices(iter))
240             return 0;
241         if (data->n_cand > 1)
242             qsort(data->cand, data->n_cand, sizeof(*data->cand), s_Sort);
243     }
244 
245     i = 0;
246     data->i_cand = 0;
247     while (i < data->n_cand) {
248         /* NB all servers have been loaded in accordance with iter->external */
249         info = (SSERV_Info*) data->cand[i].info;
250         if (info->rate > 0.0  ||  iter->ok_down) {
251             const char* c = SERV_NameOfInfo(info);
252             for (n = 0;  n < iter->n_skip;  n++) {
253                 const SSERV_Info* skip = iter->skip[n];
254                 const char* s = SERV_NameOfInfo(skip);
255                 if (*s) {
256                     assert(iter->ismask  ||  iter->reverse_dns);
257                     if (strcasecmp(s, c) == 0
258                         &&  ((skip->type == fSERV_Dns  &&  !skip->host)  ||
259                              SERV_EqualInfo(skip, info))) {
260                         break;
261                     }
262                 } else if (SERV_EqualInfo(skip, info))
263                     break;
264                 if (iter->reverse_dns  &&  skip->type == fSERV_Dns
265                     &&  skip->host == info->host
266                     &&  (!skip->port  ||  skip->port == info->port)) {
267                     break;
268                 }
269             }
270         } else
271             n = 0;
272         if (!iter->ismask) {
273             if (type == fSERV_Any) {
274                 if (iter->reverse_dns  &&  info->type != fSERV_Dns)
275                     dns_info_seen = 1/*true*/;
276             } else if ((type & info->type)  &&  info->type == fSERV_Dns)
277                 dns_info_seen = 1/*true*/;
278         }
279         if (n < iter->n_skip) {
280             if (i < --data->n_cand) {
281                 memmove(data->cand + i, data->cand + i + 1,
282                         (data->n_cand - i) * sizeof(*data->cand));
283             }
284             free(info);
285         } else {
286             if (type != fSERV_Any  &&  !(type & info->type))
287                 break;
288             if (type == fSERV_Any  &&  info->type == fSERV_Dns)
289                 break;
290             data->i_cand++;
291             data->cand[i].status = info->rate < 0.0 ? 0.0 : info->rate;
292             if (iter->ok_down)
293                 break;
294             i++;
295         }
296     }
297 
298     if (data->i_cand) {
299         n = LB_Select(iter, data, s_GetCandidate, 1.0);
300         info = (SSERV_Info*) data->cand[n].info;
301         if (iter->reverse_dns  &&  info->type != fSERV_Dns) {
302             dns_info_seen = 0/*false*/;
303             for (i = 0;  i < data->n_cand;  i++) {
304                 SSERV_Info* temp = (SSERV_Info*) data->cand[i].info;
305                 if (temp->type != fSERV_Dns   ||
306                     temp->host != info->host  ||  temp->port != info->port) {
307                     continue;
308                 }
309                 if (!iter->ismask)
310                     dns_info_seen = 1/*true*/;
311                 if (iter->external  &&  temp->locl)
312                     continue; /* external mapping req'd; local server */
313                 assert(!(temp->locl & 0xF0)); /* no private DNS */
314                 if (temp->rate > 0.0  ||  iter->ok_down) {
315                     data->cand[i].status = data->cand[n].status;
316                     info = temp;
317                     n = i;
318                     break;
319                 }
320             }
321             if (i >= data->n_cand  &&  dns_info_seen)
322                 info = 0;
323         }
324 
325         if (info) {
326             info->rate  = data->cand[n].status;
327             info->time += iter->time;
328             if (n < --data->n_cand) {
329                 memmove(data->cand + n, data->cand + n + 1,
330                         (data->n_cand - n) * sizeof(*data->cand));
331             }
332         }
333     } else if (iter->last  ||  iter->n_skip  ||  !dns_info_seen) {
334         info = 0;
335     } else if ((info = SERV_CreateDnsInfo(0)) != 0)
336         info->time = NCBI_TIME_INFINITE;
337 
338     if (info  &&  host_info)
339         *host_info = 0;
340     return info;
341 }
342 
343 
344 static void s_Reset(SERV_ITER iter)
345 {
346     struct SLOCAL_Data* data = (struct SLOCAL_Data*) iter->data;
347     if (data  &&  data->cand) {
348         size_t i;
349         assert(data->a_cand);
350         for (i = 0; i < data->n_cand; i++)
351             free((void*) data->cand[i].info);
352         data->n_cand = 0;
353     }
354     data->reset = 1/*true*/;
355 }
356 
357 
358 static void s_Close(SERV_ITER iter)
359 {
360     struct SLOCAL_Data* data = (struct SLOCAL_Data*) iter->data;
361     assert(!data->n_cand  &&  data->reset); /* s_Reset() has been called */
362     if (data->cand) {
363         assert(data->a_cand);
364         data->a_cand = 0;
365         free(data->cand);
366         data->cand = 0;
367     }
368     free(data);
369     iter->data = 0;
370 }
371 
372 
373 /***********************************************************************
374  *  EXTERNAL
375  ***********************************************************************/
376 
377 /*ARGSUSED*/
378 const SSERV_VTable* SERV_LOCAL_Open(SERV_ITER iter,
379                                     SSERV_Info** info, HOST_INFO* u/*unused*/)
380 {
381     struct SLOCAL_Data* data;
382 
383     if (!iter->ismask  &&  strpbrk(iter->name, "?*"))
384         return 0/*failed to start unallowed wildcard search*/;
385 
386     if (!(data = (struct SLOCAL_Data*) calloc(1, sizeof(*data))))
387         return 0;
388 
389     iter->data = data;
390 
391     if (g_NCBI_ConnectRandomSeed == 0) {
392         g_NCBI_ConnectRandomSeed = iter->time ^ NCBI_CONNECT_SRAND_ADDEND;
393         srand(g_NCBI_ConnectRandomSeed);
394     }
395 
396     if (!s_LoadServices(iter)) {
397         s_Reset(iter);
398         s_Close(iter);
399         return 0;
400     }
401     if (data->n_cand > 1)
402         qsort(data->cand, data->n_cand, sizeof(*data->cand), s_Sort);
403 
404     /* call GetNextInfo subsequently if info is actually needed */
405     if (info)
406         *info = 0;
407     return &s_op;
408 }
409 

source navigation ]   [ diff markup ]   [ identifier search ]   [ freetext search ]   [ file search ]  

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.