1 /* $Id: ncbi_service.c,v 6.152 2016/12/27 19:44:11 fukanchi 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 * Top-level API to resolve NCBI service name to the server meta-address.
30 *
31 */
32
33 #include "ncbi_ansi_ext.h"
34 #include "ncbi_dispd.h"
35 #include "ncbi_lbsmd.h"
36 #include "ncbi_local.h"
37 #ifdef NCBI_CXX_TOOLKIT
38 # include "ncbi_lbosp.h"
39 #endif
40 #include "ncbi_priv.h"
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <time.h>
44
45 #define NCBI_USE_ERRCODE_X Connect_Service
46
47
48 /*
49 * FIXME FIXME FIXME FIXME FIXME ---->
50 *
51 * NOTE: For fSERV_ReverseDns lookups the following rules apply to "skip"
52 * contents: a service would not be selected if there is a same-named
53 * entry with matching host[:port] is found in the "skip" list, or
54 * there is a nameless...
55 * NOTE: Lookup by mask cancels fSERV_ReverseDns mode, if both are used.
56 */
57
58
59 #define CONN_SERVICE_NAME DEF_CONN_REG_SECTION "_" REG_CONN_SERVICE_NAME
60
61
62 static ESwitch s_Fast = eOff;
63
64
SERV_DoFastOpens(ESwitch on)65 ESwitch SERV_DoFastOpens(ESwitch on)
66 {
67 ESwitch retval = s_Fast;
68 if (on != eDefault)
69 s_Fast = on;
70 return retval;
71 }
72
73
x_ServiceName(const char * service,int ismask,unsigned int depth)74 static char* x_ServiceName(const char* service,
75 int/*bool*/ ismask, unsigned int depth)
76 {
77 char buf[128];
78 char srv[128];
79 size_t len;
80 char* s;
81
82 if (depth > 7) {
83 assert(service && *service);
84 CORE_LOGF_X(7, eLOG_Error,
85 ("[%s] Maximal service name recursion depth reached: %u",
86 service, depth));
87 return 0/*failure*/;
88 }
89 len = 0;
90 assert(sizeof(buf) > sizeof(CONN_SERVICE_NAME));
91 if (!service || (!ismask && (!*service || strpbrk(service, "?*")))
92 || (len = strlen(service)) >= sizeof(buf)-sizeof(CONN_SERVICE_NAME)) {
93 CORE_LOGF_X(8, eLOG_Error,
94 ("%s%s%s%s service name",
95 !service || !*service ? "" : "[",
96 !service ? "" : service,
97 !service || !*service ? "" : "] ",
98 !service ? "NULL" : !*service ? "Empty" :
99 len < sizeof(buf)-sizeof(CONN_SERVICE_NAME) ? "Invalid" :
100 "Too long"));
101 return 0/*failure*/;
102 }
103 if (!s_Fast && !ismask) {
104 s = (char*) memcpy(buf, service, len) + len;
105 *s++ = '_';
106 memcpy(s, CONN_SERVICE_NAME, sizeof(CONN_SERVICE_NAME));
107 /* Looking for "service_CONN_SERVICE_NAME" in the environment */
108 if (!(s = getenv(strupr(buf))) || !*s) {
109 /* Looking for "CONN_SERVICE_NAME" in registry section [service] */
110 buf[len++] = '\0';
111 CORE_REG_GET(buf, buf + len, srv, sizeof(srv), 0);
112 s = srv;
113 }
114 if (*s && strcasecmp(s, service) != 0)
115 return x_ServiceName(s, ismask, depth + 1);
116 }
117 return strdup(service);
118 }
119
120
s_ServiceName(const char * service,int ismask)121 static char* s_ServiceName(const char* service, int/*bool*/ ismask)
122 {
123 char* retval;
124 CORE_LOCK_READ;
125 retval = x_ServiceName(service, ismask, 0);
126 CORE_UNLOCK;
127 return retval;
128 }
129
130
SERV_ServiceName(const char * service)131 char* SERV_ServiceName(const char* service)
132 {
133 return s_ServiceName(service, 0);
134 }
135
136
s_AddSkipInfo(SERV_ITER iter,const char * name,SSERV_InfoCPtr info)137 static int/*bool*/ s_AddSkipInfo(SERV_ITER iter,
138 const char* name,
139 SSERV_InfoCPtr info)
140 {
141 size_t n;
142 assert(name);
143 for (n = 0; n < iter->n_skip; n++) {
144 if (strcasecmp(name, SERV_NameOfInfo(iter->skip[n])) == 0
145 && (SERV_EqualInfo(info, iter->skip[n]) ||
146 (iter->skip[n]->type == fSERV_Firewall &&
147 iter->skip[n]->u.firewall.type == info->u.firewall.type))) {
148 /* Replace older version */
149 if (iter->last == iter->skip[n])
150 iter->last = info;
151 free((void*) iter->skip[n]);
152 iter->skip[n] = info;
153 return 1;
154 }
155 }
156 if (iter->n_skip == iter->a_skip) {
157 SSERV_InfoCPtr* temp;
158 n = iter->a_skip + 10;
159 temp = (SSERV_InfoCPtr*)
160 (iter->skip
161 ? realloc((void*) iter->skip, n * sizeof(*temp))
162 : malloc ( n * sizeof(*temp)));
163 if (!temp)
164 return 0;
165 iter->skip = temp;
166 iter->a_skip = n;
167 }
168 iter->skip[iter->n_skip++] = info;
169 return 1;
170 }
171
172
173 #ifdef __GNUC__
174 inline
175 #endif /*__GNUC__*/
s_IsMapperConfigured(const char * service,const char * key)176 static int/*bool*/ s_IsMapperConfigured(const char* service, const char* key)
177 {
178 char val[32];
179 if (s_Fast)
180 return 0;
181 ConnNetInfo_GetValue(service, key, val, sizeof(val), 0);
182 return ConnNetInfo_Boolean(val);
183 }
184
185
x_Open(const char * service,unsigned ismask,TSERV_Type types,unsigned int preferred_host,unsigned short preferred_port,double preference,const SConnNetInfo * net_info,SSERV_InfoCPtr skip[],size_t n_skip,unsigned external,const char * arg,const char * val,SSERV_Info ** info,HOST_INFO * host_info)186 static SERV_ITER x_Open(const char* service,
187 unsigned/*bool*/ ismask,
188 TSERV_Type types,
189 unsigned int preferred_host,
190 unsigned short preferred_port,
191 double preference,
192 const SConnNetInfo* net_info,
193 SSERV_InfoCPtr skip[],
194 size_t n_skip,
195 unsigned/*bool*/ external,
196 const char* arg,
197 const char* val,
198 SSERV_Info** info,
199 HOST_INFO* host_info)
200 {
201 int/*bool*/
202 do_lbsmd = -1/*unassigned*/,
203 #ifdef NCBI_CXX_TOOLKIT
204 do_lbos = -1/*unassigned*/,
205 #endif /*NCBI_CXX_TOOLKIT*/
206 do_dispd = -1/*unassigned*/;
207 const SSERV_VTable* op;
208 SERV_ITER iter;
209 const char* s;
210
211 if (!(s = s_ServiceName(service, ismask)))
212 return 0;
213 if (!(iter = (SERV_ITER) calloc(1, sizeof(*iter)))) {
214 free((void*) s);
215 return 0;
216 }
217 assert(ismask || *s);
218
219 iter->name = s;
220 iter->host = (preferred_host == SERV_LOCALHOST
221 ? SOCK_GetLocalHostAddress(eDefault)
222 : preferred_host);
223 iter->port = preferred_port;
224 iter->pref = (preference < 0.0
225 ? -1.0
226 : 0.01 * (preference > 100.0
227 ? 100.0
228 : preference));
229 iter->types = types;
230 if (ismask)
231 iter->ismask = 1;
232 if (types & fSERV_IncludeDown)
233 iter->ok_down = 1;
234 if (types & fSERV_IncludeReserved)
235 iter->ok_reserved = 1;
236 if (types & fSERV_IncludeSuppressed)
237 iter->ok_suppressed = 1;
238 if (types & fSERV_ReverseDns)
239 iter->reverse_dns = 1;
240 if (types & fSERV_Stateless)
241 iter->stateless = 1;
242 iter->external = external ? 1 : 0;
243 if (arg && *arg) {
244 iter->arg = arg;
245 iter->arglen = strlen(arg);
246 if (val) {
247 iter->val = val;
248 iter->vallen = strlen(val);
249 }
250 }
251 iter->time = (TNCBI_Time) time(0);
252
253 if (n_skip) {
254 size_t i;
255 for (i = 0; i < n_skip; i++) {
256 const char* name = (iter->ismask || skip[i]->type == fSERV_Dns
257 ? SERV_NameOfInfo(skip[i]) : "");
258 SSERV_Info* temp = SERV_CopyInfoEx(skip[i],
259 !iter->reverse_dns || *name ?
260 name : s);
261 if (temp) {
262 temp->time = NCBI_TIME_INFINITE;
263 if (!s_AddSkipInfo(iter, name, temp)) {
264 free(temp);
265 temp = 0;
266 }
267 }
268 if (!temp) {
269 SERV_Close(iter);
270 return 0;
271 }
272 }
273 }
274 assert(n_skip == iter->n_skip);
275 iter->o_skip = iter->n_skip;
276
277 if (net_info) {
278 if (net_info->external)
279 iter->external = 1;
280 if (net_info->firewall)
281 iter->types |= fSERV_Firewall;
282 if (net_info->stateless)
283 iter->stateless = 1;
284 if (net_info->lb_disable)
285 do_lbsmd = 0/*false*/;
286 } else
287 do_dispd = 0/*false*/;
288 /* Ugly optimization not to access the registry more than necessary */
289 if ((!s_IsMapperConfigured(service, REG_CONN_LOCAL_ENABLE) ||
290 !(op = SERV_LOCAL_Open(iter, info, host_info)))
291
292 &&
293 (!do_lbsmd ||
294 !(do_lbsmd = !s_IsMapperConfigured
295 (service, REG_CONN_LBSMD_DISABLE)) ||
296 !(op = SERV_LBSMD_Open(iter, info, host_info,
297 (!do_dispd ||
298 !(do_dispd = !s_IsMapperConfigured
299 (service, REG_CONN_DISPD_DISABLE)))
300 #ifdef NCBI_CXX_TOOLKIT
301 &&
302 !(do_lbos = s_IsMapperConfigured
303 (service, REG_CONN_LBOS_ENABLE))
304 #endif /*NCBI_CXX_TOOLKIT*/
305 )))
306
307 #ifdef NCBI_CXX_TOOLKIT
308 &&
309 (!do_lbos ||
310 (do_lbos < 0 && !(do_lbos = s_IsMapperConfigured
311 (service, REG_CONN_LBOS_ENABLE))) ||
312 !(op = SERV_LBOS_Open(iter, net_info, info)))
313 #endif /*NCBI_CXX_TOOLKIT*/
314
315 &&
316 (!do_dispd ||
317 (do_dispd < 0 && !(do_dispd = !s_IsMapperConfigured
318 (service, REG_CONN_DISPD_DISABLE))) ||
319 !(op = SERV_DISPD_Open(iter, net_info, info, host_info)))) {
320 if (!do_lbsmd && !do_dispd) {
321 CORE_LOGF_X(1, eLOG_Error,
322 ("[%s] No service mappers available", service));
323 }
324 SERV_Close(iter);
325 return 0;
326 }
327
328 assert(op != 0);
329 iter->op = op;
330 return iter;
331 }
332
333
s_SkipSkip(SERV_ITER iter)334 static void s_SkipSkip(SERV_ITER iter)
335 {
336 size_t n;
337 if (iter->time && (iter->ismask | iter->ok_down | iter->ok_suppressed))
338 return;
339 n = 0;
340 while (n < iter->n_skip) {
341 SSERV_InfoCPtr temp = iter->skip[n];
342 if (temp->time != NCBI_TIME_INFINITE
343 && (!iter->time/*iterator reset*/
344 || ((temp->type != fSERV_Dns || temp->host)
345 && temp->time < iter->time))) {
346 if (--iter->n_skip > n) {
347 SSERV_InfoCPtr* ptr = iter->skip + n;
348 memmove((void*) ptr, (void*)(ptr + 1),
349 (iter->n_skip - n) * sizeof(*ptr));
350 }
351 if (iter->last == temp)
352 iter->last = 0;
353 free((void*) temp);
354 } else
355 n++;
356 }
357 }
358
359
s_GetNextInfo(SERV_ITER iter,HOST_INFO * host_info,int internal)360 static SSERV_Info* s_GetNextInfo(SERV_ITER iter,
361 HOST_INFO* host_info,
362 int/*bool*/ internal)
363 {
364 SSERV_Info* info = 0;
365 assert(iter && iter->op);
366 if (iter->op->GetNextInfo) {
367 if (!internal) {
368 iter->time = (TNCBI_Time) time(0);
369 s_SkipSkip(iter);
370 }
371 /* Obtain a fresh entry from the actual mapper */
372 while ((info = iter->op->GetNextInfo(iter, host_info)) != 0) {
373 /* This should never actually be used for LBSMD dispatcher,
374 * as all exclusion logic is already done in it internally. */
375 int/*bool*/ go =
376 !info->host || iter->pref >= 0.0 ||
377 !iter->host || (iter->host == info->host &&
378 (!iter->port || iter->port == info->port));
379 if (go && internal)
380 break;
381 if (!s_AddSkipInfo(iter, SERV_NameOfInfo(info), info)) {
382 free(info);
383 info = 0;
384 }
385 if (go || !info)
386 break;
387 }
388 }
389 if (!internal)
390 iter->last = info;
391 return info;
392 }
393
394
s_Open(const char * service,unsigned ismask,TSERV_Type types,unsigned int preferred_host,unsigned short preferred_port,double preference,const SConnNetInfo * net_info,SSERV_InfoCPtr skip[],size_t n_skip,int external,const char * arg,const char * val,SSERV_Info ** info,HOST_INFO * host_info)395 static SERV_ITER s_Open(const char* service,
396 unsigned/*bool*/ ismask,
397 TSERV_Type types,
398 unsigned int preferred_host,
399 unsigned short preferred_port,
400 double preference,
401 const SConnNetInfo* net_info,
402 SSERV_InfoCPtr skip[],
403 size_t n_skip,
404 int /*bool*/ external,
405 const char* arg,
406 const char* val,
407 SSERV_Info** info,
408 HOST_INFO* host_info)
409 {
410 SSERV_Info* x_info;
411 SERV_ITER iter = x_Open(service, ismask, types,
412 preferred_host, preferred_port, preference,
413 net_info, skip, n_skip,
414 external, arg, val,
415 &x_info, host_info);
416 assert(!iter || iter->op);
417 if (!iter)
418 x_info = 0;
419 else if (!x_info)
420 x_info = info ? s_GetNextInfo(iter, host_info, 1/*internal*/) : 0;
421 else if (x_info == (SSERV_Info*)(-1L)) {
422 SERV_Close(iter);
423 x_info = 0;
424 iter = 0;
425 }
426 if (info)
427 *info = x_info;
428 else if (x_info)
429 free(x_info);
430 return iter;
431 }
432
433
SERV_OpenSimple(const char * service)434 extern SERV_ITER SERV_OpenSimple(const char* service)
435 {
436 SConnNetInfo* net_info = ConnNetInfo_Create(service);
437 SERV_ITER iter = s_Open(service, 0/*not mask*/, fSERV_Any,
438 SERV_ANYHOST,
439 0/*preferred_port*/, 0.0/*preference*/,
440 net_info, 0/*skip*/, 0/*n_skip*/,
441 0/*not external*/, 0/*arg*/, 0/*val*/,
442 0/*info*/, 0/*host_info*/);
443 ConnNetInfo_Destroy(net_info);
444 return iter;
445 }
446
447
SERV_Open(const char * service,TSERV_Type types,unsigned int preferred_host,const SConnNetInfo * net_info)448 extern SERV_ITER SERV_Open(const char* service,
449 TSERV_Type types,
450 unsigned int preferred_host,
451 const SConnNetInfo* net_info)
452 {
453 return s_Open(service, 0/*not mask*/, types,
454 preferred_host, 0/*preferred_port*/, 0.0/*preference*/,
455 net_info, 0/*skip*/, 0/*n_skip*/,
456 0/*not external*/, 0/*arg*/, 0/*val*/,
457 0/*info*/, 0/*host_info*/);
458 }
459
460
SERV_OpenEx(const char * service,TSERV_Type types,unsigned int preferred_host,const SConnNetInfo * net_info,SSERV_InfoCPtr skip[],size_t n_skip)461 extern SERV_ITER SERV_OpenEx(const char* service,
462 TSERV_Type types,
463 unsigned int preferred_host,
464 const SConnNetInfo* net_info,
465 SSERV_InfoCPtr skip[],
466 size_t n_skip)
467 {
468 return s_Open(service, 0/*not mask*/, types,
469 preferred_host, 0/*preferred_port*/, 0.0/*preference*/,
470 net_info, skip, n_skip,
471 0/*not external*/, 0/*arg*/, 0/*val*/,
472 0/*info*/, 0/*host_info*/);
473 }
474
475
SERV_OpenP(const char * service,TSERV_Type types,unsigned int preferred_host,unsigned short preferred_port,double preference,const SConnNetInfo * net_info,SSERV_InfoCPtr skip[],size_t n_skip,int external,const char * arg,const char * val)476 SERV_ITER SERV_OpenP(const char* service,
477 TSERV_Type types,
478 unsigned int preferred_host,
479 unsigned short preferred_port,
480 double preference,
481 const SConnNetInfo* net_info,
482 SSERV_InfoCPtr skip[],
483 size_t n_skip,
484 int/*bool*/ external,
485 const char* arg,
486 const char* val)
487 {
488 return s_Open(service,
489 service && (!*service || strpbrk(service, "?*")), types,
490 preferred_host, preferred_port, preference,
491 net_info, skip, n_skip,
492 external, arg, val,
493 0/*info*/, 0/*host_info*/);
494 }
495
496
SERV_GetInfoSimple(const char * service)497 extern SSERV_Info* SERV_GetInfoSimple(const char* service)
498 {
499 SConnNetInfo* net_info = ConnNetInfo_Create(service);
500 SSERV_Info* info = SERV_GetInfoP(service, fSERV_Any,
501 SERV_ANYHOST/*preferred_host*/,
502 0/*preferred_port*/, 0.0/*preference*/,
503 net_info, 0/*skip*/, 0/*n_skip*/,
504 0/*not external*/, 0/*arg*/, 0/*val*/,
505 0/*host_info*/);
506 ConnNetInfo_Destroy(net_info);
507 return info;
508 }
509
510
SERV_GetInfo(const char * service,TSERV_Type types,unsigned int preferred_host,const SConnNetInfo * net_info)511 extern SSERV_Info* SERV_GetInfo(const char* service,
512 TSERV_Type types,
513 unsigned int preferred_host,
514 const SConnNetInfo* net_info)
515 {
516 return SERV_GetInfoP(service, types,
517 preferred_host,
518 0/*preferred_port*/, 0.0/*preference*/,
519 net_info, 0/*skip*/, 0/*n_skip*/,
520 0/*not external*/, 0/*arg*/, 0/*val*/,
521 0/*host_info*/);
522 }
523
524
SERV_GetInfoEx(const char * service,TSERV_Type types,unsigned int preferred_host,const SConnNetInfo * net_info,SSERV_InfoCPtr skip[],size_t n_skip,HOST_INFO * host_info)525 extern SSERV_Info* SERV_GetInfoEx(const char* service,
526 TSERV_Type types,
527 unsigned int preferred_host,
528 const SConnNetInfo* net_info,
529 SSERV_InfoCPtr skip[],
530 size_t n_skip,
531 HOST_INFO* host_info)
532 {
533 return SERV_GetInfoP(service, types,
534 preferred_host,
535 0/*preferred_port*/, 0.0/*preference*/,
536 net_info, skip, n_skip,
537 0/*not external*/, 0/*arg*/, 0/*val*/,
538 host_info);
539 }
540
541
SERV_GetInfoP(const char * service,TSERV_Type types,unsigned int preferred_host,unsigned short preferred_port,double preference,const SConnNetInfo * net_info,SSERV_InfoCPtr skip[],size_t n_skip,int external,const char * arg,const char * val,HOST_INFO * host_info)542 SSERV_Info* SERV_GetInfoP(const char* service,
543 TSERV_Type types,
544 unsigned int preferred_host,
545 unsigned short preferred_port,
546 double preference,
547 const SConnNetInfo* net_info,
548 SSERV_InfoCPtr skip[],
549 size_t n_skip,
550 int/*bool*/ external,
551 const char* arg,
552 const char* val,
553 HOST_INFO* host_info)
554 {
555 SSERV_Info* info;
556 SERV_ITER iter = s_Open(service, 0/*not mask*/, types,
557 preferred_host, preferred_port, preference,
558 net_info, skip, n_skip,
559 external, arg, val,
560 &info, host_info);
561 assert(!info || iter);
562 SERV_Close(iter);
563 return info;
564 }
565
566
SERV_GetNextInfoEx(SERV_ITER iter,HOST_INFO * host_info)567 extern SSERV_InfoCPtr SERV_GetNextInfoEx(SERV_ITER iter,
568 HOST_INFO* host_info)
569 {
570 assert(!iter || iter->op);
571 return iter ? s_GetNextInfo(iter, host_info, 0) : 0;
572 }
573
574
SERV_GetNextInfo(SERV_ITER iter)575 extern SSERV_InfoCPtr SERV_GetNextInfo(SERV_ITER iter)
576 {
577 assert(!iter || iter->op);
578 return iter ? s_GetNextInfo(iter, 0, 0) : 0;
579 }
580
581
SERV_MapperName(SERV_ITER iter)582 const char* SERV_MapperName(SERV_ITER iter)
583 {
584 assert(!iter || iter->op);
585 return iter ? iter->op->mapper : 0;
586 }
587
588
SERV_CurrentName(SERV_ITER iter)589 const char* SERV_CurrentName(SERV_ITER iter)
590 {
591 const char* name = SERV_NameOfInfo(iter->last);
592 return name && *name ? name : iter->name;
593 }
594
595
SERV_PenalizeEx(SERV_ITER iter,double fine,TNCBI_Time time)596 int/*bool*/ SERV_PenalizeEx(SERV_ITER iter, double fine, TNCBI_Time time)
597 {
598 assert(!iter || iter->op);
599 if (!iter || !iter->op->Feedback || !iter->last)
600 return 0/*false*/;
601 return iter->op->Feedback(iter, fine, time ? time : 1/*NB: always != 0*/);
602 }
603
604
SERV_Penalize(SERV_ITER iter,double fine)605 extern int/*bool*/ SERV_Penalize(SERV_ITER iter, double fine)
606 {
607 return SERV_PenalizeEx(iter, fine, 0);
608 }
609
610
SERV_Rerate(SERV_ITER iter,double rate)611 extern int/*bool*/ SERV_Rerate(SERV_ITER iter, double rate)
612 {
613 assert(!iter || iter->op);
614 if (!iter || !iter->op->Feedback || !iter->last)
615 return 0/*false*/;
616 return iter->op->Feedback(iter, rate, 0/*i.e.rate*/);
617 }
618
619
SERV_Reset(SERV_ITER iter)620 extern void SERV_Reset(SERV_ITER iter)
621 {
622 if (!iter)
623 return;
624 iter->last = 0;
625 iter->time = 0;
626 s_SkipSkip(iter);
627 if (iter->op && iter->op->Reset)
628 iter->op->Reset(iter);
629 }
630
631
SERV_Close(SERV_ITER iter)632 extern void SERV_Close(SERV_ITER iter)
633 {
634 size_t i;
635 if (!iter)
636 return;
637 SERV_Reset(iter);
638 for (i = 0; i < iter->n_skip; i++)
639 free((void*) iter->skip[i]);
640 iter->n_skip = 0;
641 if (iter->op) {
642 if (iter->op->Close)
643 iter->op->Close(iter);
644 iter->op = 0;
645 }
646 if (iter->skip)
647 free((void*) iter->skip);
648 free((void*) iter->name);
649 free(iter);
650 }
651
652
SERV_Update(SERV_ITER iter,const char * text,int code)653 int/*bool*/ SERV_Update(SERV_ITER iter, const char* text, int code)
654 {
655 static const char used_server_info[] = "Used-Server-Info-";
656 int retval = 0/*not updated yet*/;
657
658 assert(!iter || iter->op);
659 if (iter && text) {
660 const char *c, *b;
661 iter->time = (TNCBI_Time) time(0);
662 for (b = text; (c = strchr(b, '\n')) != 0; b = c + 1) {
663 size_t len = (size_t)(c - b);
664 SSERV_Info* info;
665 unsigned int d1;
666 char* p, *t;
667 int d2;
668
669 if (!(t = (char*) malloc(len + 1)))
670 continue;
671 memcpy(t, b, len);
672 if (t[len - 1] == '\r')
673 t[len - 1] = '\0';
674 else
675 t[len ] = '\0';
676 p = t;
677 if (iter->op->Update && iter->op->Update(iter, p, code))
678 retval = 1/*updated*/;
679 if (!strncasecmp(p, used_server_info, sizeof(used_server_info) - 1)
680 && isdigit((unsigned char) p[sizeof(used_server_info) - 1])) {
681 p += sizeof(used_server_info) - 1;
682 if (sscanf(p, "%u: %n", &d1, &d2) >= 1
683 && (info = SERV_ReadInfoEx(p + d2, "", 0)) != 0) {
684 if (!s_AddSkipInfo(iter, "", info))
685 free(info);
686 else
687 retval = 1/*updated*/;
688 }
689 }
690 free(t);
691 }
692 }
693 return retval;
694 }
695
696
s_SetDefaultReferer(SConnNetInfo * net_info,SERV_ITER iter)697 static void s_SetDefaultReferer(SConnNetInfo* net_info, SERV_ITER iter)
698 {
699 char* str, *referer = 0;
700
701 if (strcasecmp(iter->op->mapper, "DISPD") == 0)
702 referer = ConnNetInfo_URL(net_info);
703 else if ((str = strdup(iter->op->mapper)) != 0) {
704 const char* host = net_info->client_host;
705 const char* args = net_info->args;
706 const char* name = iter->name;
707
708 if (!*net_info->client_host
709 && !SOCK_gethostbyaddr(0, net_info->client_host,
710 sizeof(net_info->client_host))) {
711 SOCK_gethostname(net_info->client_host,
712 sizeof(net_info->client_host));
713 }
714 if (!(referer = (char*) malloc(3 + 1 + 1 + 1 + 2*strlen(strlwr(str)) +
715 strlen(host) + (args[0]
716 ? strlen(args)
717 : 8 + strlen(name))))) {
718 return;
719 }
720 strcat(strcat(strcat(strcat(strcpy
721 (referer, str), "://"), host), "/"), str);
722 if (args[0])
723 strcat(strcat(referer, "?"), args);
724 else
725 strcat(strcat(referer, "?service="), name);
726 free(str);
727 }
728 assert(!net_info->http_referer);
729 net_info->http_referer = referer;
730 }
731
732
SERV_Print(SERV_ITER iter,SConnNetInfo * net_info,int but_last)733 char* SERV_Print(SERV_ITER iter, SConnNetInfo* net_info, int/*bool*/ but_last)
734 {
735 static const char kAcceptedServerTypes[] = "Accepted-Server-Types:";
736 static const char kClientRevision[] = "Client-Revision: %u.%u\r\n";
737 static const char kUsedServerInfo[] = "Used-Server-Info: ";
738 static const char kNcbiExternal[] = NCBI_EXTERNAL ": Y\r\n";
739 static const char kNcbiFWPorts[] = "NCBI-Firewall-Ports: ";
740 static const char kPreference[] = "Preference: ";
741 static const char kSkipInfo[] = "Skip-Info-%u: ";
742 static const char kAffinity[] = "Affinity: ";
743 char buffer[128], *str;
744 TBSERV_TypeOnly t;
745 size_t buflen, i;
746 BUF buf = 0;
747
748 /* Put client version number */
749 buflen = sprintf(buffer, kClientRevision,
750 SERV_CLIENT_REVISION_MAJOR, SERV_CLIENT_REVISION_MINOR);
751 assert(buflen < sizeof(buffer));
752 if (!BUF_Write(&buf, buffer, buflen)) {
753 BUF_Destroy(buf);
754 return 0;
755 }
756 if (iter) {
757 assert(iter->op);
758 if (net_info && !net_info->http_referer && iter->op->mapper)
759 s_SetDefaultReferer(net_info, iter);
760 /* Accepted server types */
761 buflen = sizeof(kAcceptedServerTypes) - 1;
762 memcpy(buffer, kAcceptedServerTypes, buflen);
763 for (t = 1; t; t <<= 1) {
764 if (iter->types & t) {
765 const char* name = SERV_TypeStr((ESERV_Type) t);
766 size_t namelen = strlen(name);
767 if (!namelen || buflen + 1 + namelen + 2 >= sizeof(buffer))
768 break;
769 buffer[buflen++] = ' ';
770 memcpy(buffer + buflen, name, namelen);
771 buflen += namelen;
772 } else if (iter->types < t)
773 break;
774 }
775 if (buffer[buflen - 1] != ':') {
776 strcpy(&buffer[buflen], "\r\n");
777 assert(strlen(buffer) == buflen+2 && buflen+2 < sizeof(buffer));
778 if (!BUF_Write(&buf, buffer, buflen + 2)) {
779 BUF_Destroy(buf);
780 return 0;
781 }
782 }
783 if (iter->external) {
784 /* External */
785 if (!BUF_Write(&buf, kNcbiExternal, sizeof(kNcbiExternal)-1)) {
786 BUF_Destroy(buf);
787 return 0;
788 }
789 }
790 if (iter->types & fSERV_Firewall) {
791 /* Firewall */
792 EFWMode mode
793 = net_info ? (EFWMode) net_info->firewall : eFWMode_Legacy;
794 SERV_PrintFirewallPorts(buffer, sizeof(buffer), mode);
795 if (*buffer
796 && (!BUF_Write(&buf, kNcbiFWPorts, sizeof(kNcbiFWPorts)-1) ||
797 !BUF_Write(&buf, buffer, strlen(buffer)) ||
798 !BUF_Write(&buf, "\r\n", 2))) {
799 BUF_Destroy(buf);
800 return 0;
801 }
802 }
803 if (iter->pref && (iter->host | iter->port)) {
804 /* Preference */
805 buflen = SOCK_HostPortToString(iter->host, iter->port,
806 buffer, sizeof(buffer));
807 buffer[buflen++] = ' ';
808 buflen = (size_t)(strcpy(NCBI_simple_ftoa(buffer + buflen,
809 iter->pref * 100.0, 2),
810 "\r\n") - buffer) + 2/*"\r\n"*/;
811 if (!BUF_Write(&buf, kPreference, sizeof(kPreference) - 1) ||
812 !BUF_Write(&buf, buffer, buflen)) {
813 BUF_Destroy(buf);
814 return 0;
815 }
816 }
817 if (iter->arglen) {
818 /* Affinity */
819 if (!BUF_Write(&buf, kAffinity, sizeof(kAffinity) - 1) ||
820 !BUF_Write(&buf, iter->arg, iter->arglen) ||
821 (iter->val && (!BUF_Write(&buf, "=", 1) ||
822 !BUF_Write(&buf, iter->val, iter->vallen))) ||
823 !BUF_Write(&buf, "\r\n", 2)) {
824 BUF_Destroy(buf);
825 return 0;
826 }
827 }
828 /* Drop any outdated skip entries */
829 iter->time = (TNCBI_Time) time(0);
830 s_SkipSkip(iter);
831 /* Put all the rest into rejection list */
832 for (i = 0; i < iter->n_skip; ++i) {
833 /* NB: all skip infos are now kept with names (perhaps, empty) */
834 const char* name = SERV_NameOfInfo(iter->skip[i]);
835 size_t namelen = name && *name ? strlen(name) : 0;
836 if (!(str = SERV_WriteInfo(iter->skip[i])))
837 break;
838 if (but_last && iter->last == iter->skip[i]) {
839 buflen = sizeof(kUsedServerInfo) - 1;
840 memcpy(buffer, kUsedServerInfo, buflen);
841 } else
842 buflen = sprintf(buffer, kSkipInfo, (unsigned) i + 1);
843 assert(buflen < sizeof(buffer) - 1);
844 if (!BUF_Write(&buf, buffer, buflen) ||
845 (namelen && !BUF_Write(&buf, name, namelen)) ||
846 (namelen && !BUF_Write(&buf, " ", 1)) ||
847 !BUF_Write(&buf, str, strlen(str)) ||
848 !BUF_Write(&buf, "\r\n", 2)) {
849 free(str);
850 break;
851 }
852 free(str);
853 }
854 if (i < iter->n_skip) {
855 BUF_Destroy(buf);
856 return 0;
857 }
858 }
859 /* Ok then, we have filled the entire header, <CR><LF> terminated */
860 if ((buflen = BUF_Size(buf)) != 0) {
861 if ((str = (char*) malloc(buflen + 1)) != 0) {
862 if (BUF_Read(buf, str, buflen) != buflen) {
863 free(str);
864 str = 0;
865 } else
866 str[buflen] = '\0';
867 }
868 } else
869 str = 0;
870 BUF_Destroy(buf);
871 return str;
872 }
873
874
SERV_ServerPort(const char * name,unsigned int host)875 extern unsigned short SERV_ServerPort(const char* name,
876 unsigned int host)
877 {
878 SSERV_Info* info;
879 unsigned short port;
880
881 /* FIXME: SERV_LOCALHOST may not need to be resolved here,
882 * but taken from LBSMD table (or resolved later in DISPD/LOCAL
883 * if needed).
884 */
885 if (!host || host == SERV_LOCALHOST)
886 host = SOCK_GetLocalHostAddress(eDefault);
887 if (!(info = SERV_GetInfoP(name, fSERV_Standalone | fSERV_Promiscuous,
888 host, 0/*pref. port*/, -1.0/*latch host*/,
889 0/*net_info*/, 0/*skip*/, 0/*n_skip*/,
890 0/*not external*/, 0/*arg*/, 0/*val*/,
891 0/*host_info*/))) {
892 return 0;
893 }
894 assert(info->host == host);
895 port = info->port;
896 free((void*) info);
897 assert(port);
898 return port;
899 }
900
901
902 #if 0
903 int/*bool*/ SERV_MatchesHost(const SSERV_Info* info, unsigned int host)
904 {
905 if (host == SERV_ANYHOST)
906 return 1/*true*/;
907 if (host != SERV_LOCALHOST)
908 return info->host == host ? 1/*true*/ : 0/*false*/;
909 if (!info->host || info->host == SOCK_GetLocalHostAddress(eDefault))
910 return 1/*true*/;
911 return 0/*false*/;
912 }
913 #endif
914