00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "ncbi_ansi_ext.h"
00034 #include "ncbi_dispd.h"
00035 #include "ncbi_lbsmd.h"
00036 #include "ncbi_local.h"
00037 #include "ncbi_priv.h"
00038 #include <ctype.h>
00039 #include <stdlib.h>
00040 #include <time.h>
00041
00042 #define NCBI_USE_ERRCODE_X Connect_Service
00043
00044 #define CONN_SERVICE_NAME DEF_CONN_REG_SECTION "_" REG_CONN_SERVICE_NAME
00045
00046
00047 static ESwitch s_Fast = eOff;
00048
00049
00050 ESwitch SERV_DoFastOpens(ESwitch on)
00051 {
00052 ESwitch retval = s_Fast;
00053 if (on != eDefault)
00054 s_Fast = on;
00055 return retval;
00056 }
00057
00058
00059 static char* s_ServiceName(const char* service, size_t depth)
00060 {
00061 char buf[128];
00062 char srv[128];
00063 size_t len;
00064 char* s;
00065
00066 if (depth > 7) {
00067 CORE_LOGF_X(7, eLOG_Error,
00068 ("[%s] Maximal service name recursion depth reached: %lu",
00069 service, (unsigned long) depth));
00070 return 0;
00071 }
00072 if (!service || !*service ||
00073 (len = strlen(service)) + sizeof(CONN_SERVICE_NAME) >= sizeof(buf)) {
00074 CORE_LOGF_X(8, eLOG_Error,
00075 ("[%s] %s service name",
00076 !service ? "<NULL>" : service,
00077 !service ? "NULL" : *service ? "Too long" : "Empty"));
00078 return 0;
00079 }
00080 s = (char*) memcpy(buf, service, len) + len;
00081 *s++ = '_';
00082 memcpy(s, CONN_SERVICE_NAME, sizeof(CONN_SERVICE_NAME));
00083
00084 if (!(s = getenv(strupr(buf))) || !*s) {
00085
00086 buf[len++] = '\0';
00087 CORE_REG_GET(buf, buf + len, srv, sizeof(srv), 0);
00088 s = srv;
00089 }
00090 if (!*s || strcasecmp(s, service) == 0)
00091 return strdup(service);
00092 return s_ServiceName(s, ++depth);
00093 }
00094
00095
00096 char* SERV_ServiceName(const char* service)
00097 {
00098 return s_ServiceName(service, 0);
00099 }
00100
00101
00102 static int s_AddSkipInfo(SERV_ITER iter,
00103 const char* name,
00104 SSERV_Info* info)
00105 {
00106 size_t n;
00107 assert(name);
00108 for (n = 0; n < iter->n_skip; n++) {
00109 if (strcasecmp(name, SERV_NameOfInfo(iter->skip[n])) == 0 &&
00110 (SERV_EqualInfo(info, iter->skip[n]) ||
00111 (iter->skip[n]->type == fSERV_Firewall &&
00112 iter->skip[n]->u.firewall.type == info->u.firewall.type))) {
00113
00114 if (iter->last == iter->skip[n])
00115 iter->last = info;
00116 free(iter->skip[n]);
00117 iter->skip[n] = info;
00118 return 1;
00119 }
00120 }
00121 if (iter->n_skip == iter->a_skip) {
00122 SSERV_Info** temp;
00123 n = iter->a_skip + 10;
00124 temp = (SSERV_Info**)
00125 (iter->skip
00126 ? realloc(iter->skip, n * sizeof(*temp))
00127 : malloc ( n * sizeof(*temp)));
00128 if (!temp)
00129 return 0;
00130 iter->skip = temp;
00131 iter->a_skip = n;
00132 }
00133 iter->skip[iter->n_skip++] = info;
00134 return 1;
00135 }
00136
00137
00138 #ifdef __GNUC__
00139 inline
00140 #endif
00141 static int s_IsMapperConfigured(const char* service, const char* key)
00142 {
00143 char val[80];
00144 if (s_Fast)
00145 return 0;
00146 ConnNetInfo_GetValue(service, key, val, sizeof(val), 0);
00147 return *val && (strcmp (val, "1") == 0 ||
00148 strcasecmp(val, "on") == 0 ||
00149 strcasecmp(val, "yes") == 0 ||
00150 strcasecmp(val, "true") == 0);
00151 }
00152
00153
00154 static SERV_ITER s_Open(const char* service,
00155 unsigned ismask,
00156 TSERV_Type types,
00157 unsigned int preferred_host,
00158 unsigned short preferred_port,
00159 double preference,
00160 const SConnNetInfo* net_info,
00161 const SSERV_InfoCPtr skip[],
00162 size_t n_skip,
00163 unsigned external,
00164 const char* arg,
00165 const char* val,
00166 SSERV_Info** info,
00167 HOST_INFO* host_info)
00168 {
00169 int do_lbsmd = -1, do_dispd = -1;
00170 const SSERV_VTable* op;
00171 SERV_ITER iter;
00172 const char* s;
00173
00174 if (!service || !*service)
00175 return 0;
00176 if (!(s = ismask || s_Fast ? strdup(service) : s_ServiceName(service, 0)))
00177 return 0;
00178 if (!*s || !(iter = (SERV_ITER) calloc(1, sizeof(*iter)))) {
00179 free((void*) s);
00180 return 0;
00181 }
00182
00183 iter->name = s;
00184 iter->type = types & fSERV_All;
00185 iter->host = (preferred_host == SERV_LOCALHOST
00186 ? SOCK_GetLocalHostAddress(eDefault)
00187 : preferred_host);
00188 iter->port = preferred_port;
00189 iter->pref = (preference < 0.0
00190 ? -1.0
00191 : 0.01 * (preference > 100.0
00192 ? 100.0
00193 : preference));
00194 if (ismask)
00195 iter->ismask = 1;
00196 if (types & fSERV_IncludeDown)
00197 iter->ok_down = 1;
00198 if (types & fSERV_IncludeSuppressed)
00199 iter->ok_suppressed = 1;
00200 if (types & fSERV_ReverseDns)
00201 iter->reverse_dns = 1;
00202 if (types & fSERV_Stateless)
00203 iter->stateless = 1;
00204 iter->external = external;
00205 if (arg && *arg) {
00206 iter->arg = arg;
00207 iter->arglen = strlen(arg);
00208 if (val) {
00209 iter->val = val;
00210 iter->vallen = strlen(val);
00211 }
00212 }
00213 iter->time = (TNCBI_Time) time(0);
00214
00215 if (n_skip) {
00216 size_t i;
00217 for (i = 0; i < n_skip; i++) {
00218 const char* name = (iter->ismask || skip[i]->type == fSERV_Dns
00219 ? SERV_NameOfInfo(skip[i]) : "");
00220 SSERV_Info* temp = SERV_CopyInfoEx(skip[i],
00221 !iter->reverse_dns || *name ?
00222 name : s);
00223 if (temp) {
00224 temp->time = NCBI_TIME_INFINITE;
00225 if (!s_AddSkipInfo(iter, name, temp)) {
00226 free(temp);
00227 temp = 0;
00228 }
00229 }
00230 if (!temp) {
00231 SERV_Close(iter);
00232 return 0;
00233 }
00234 }
00235 }
00236 assert(n_skip == iter->n_skip);
00237
00238 if (net_info) {
00239 if (net_info->firewall)
00240 iter->type |= fSERV_Firewall;
00241 if (net_info->stateless)
00242 iter->stateless = 1;
00243 if (net_info->lb_disable)
00244 do_lbsmd = 0;
00245 } else
00246 do_dispd = 0;
00247
00248 if ((!s_IsMapperConfigured(service, REG_CONN_LOCAL_ENABLE) ||
00249 !(op = SERV_LOCAL_Open(iter, info, host_info))) &&
00250 (!do_lbsmd ||
00251 !(do_lbsmd= !s_IsMapperConfigured(service, REG_CONN_LBSMD_DISABLE)) ||
00252 !(op = SERV_LBSMD_Open(iter, info, host_info,
00253 !do_dispd ||
00254 !(do_dispd = !s_IsMapperConfigured
00255 (service, REG_CONN_DISPD_DISABLE))))) &&
00256 (!do_dispd ||
00257 !(do_dispd= !s_IsMapperConfigured(service, REG_CONN_DISPD_DISABLE)) ||
00258 !(op = SERV_DISPD_Open(iter, net_info, info, host_info)))) {
00259 if (!do_lbsmd && !do_dispd) {
00260 CORE_LOGF_X(1, eLOG_Error,
00261 ("[%s] No service mappers available", service));
00262 }
00263 SERV_Close(iter);
00264 return 0;
00265 }
00266
00267 assert(op != 0);
00268 iter->op = op;
00269 return iter;
00270 }
00271
00272
00273 SERV_ITER SERV_OpenSimple(const char* service)
00274 {
00275 SConnNetInfo* net_info = ConnNetInfo_Create(service);
00276 SERV_ITER iter = SERV_Open(service, fSERV_Any, 0, net_info);
00277 ConnNetInfo_Destroy(net_info);
00278 return iter;
00279 }
00280
00281
00282 SERV_ITER SERV_Open(const char* service,
00283 TSERV_Type types,
00284 unsigned int preferred_host,
00285 const SConnNetInfo* net_info)
00286 {
00287 return s_Open(service, 0, types,
00288 preferred_host, 0, 0.0,
00289 net_info, 0, 0,
00290 0, 0, 0,
00291 0, 0);
00292 }
00293
00294
00295 SERV_ITER SERV_OpenEx(const char* service,
00296 TSERV_Type types,
00297 unsigned int preferred_host,
00298 const SConnNetInfo* net_info,
00299 const SSERV_InfoCPtr skip[],
00300 size_t n_skip)
00301 {
00302 return s_Open(service, 0, types,
00303 preferred_host, 0, 0.0,
00304 net_info, skip, n_skip,
00305 0, 0, 0,
00306 0, 0);
00307 }
00308
00309
00310 SERV_ITER SERV_OpenP(const char* service,
00311 TSERV_Type types,
00312 unsigned int preferred_host,
00313 unsigned short preferred_port,
00314 double preference,
00315 const SConnNetInfo* net_info,
00316 const SSERV_InfoCPtr skip[],
00317 size_t n_skip,
00318 int external,
00319 const char* arg,
00320 const char* val)
00321 {
00322 return s_Open(service, strpbrk(service, "?*") != 0, types,
00323 preferred_host, preferred_port, preference,
00324 net_info, skip, n_skip,
00325 external, arg, val,
00326 0, 0);
00327 }
00328
00329
00330 static void s_SkipSkip(SERV_ITER iter)
00331 {
00332 size_t n;
00333 if (iter->time && (iter->ismask || (iter->type & fSERV_Promiscuous)))
00334 return;
00335 n = 0;
00336 while (n < iter->n_skip) {
00337 SSERV_Info* temp = iter->skip[n];
00338 if (temp->time != NCBI_TIME_INFINITE
00339 && (!iter->time
00340 || ((temp->type != fSERV_Dns || temp->host)
00341 && temp->time < iter->time))) {
00342 if (n < --iter->n_skip) {
00343 memmove(iter->skip + n, iter->skip + n + 1,
00344 sizeof(*iter->skip)*(iter->n_skip - n));
00345 }
00346 if (iter->last == temp)
00347 iter->last = 0;
00348 free(temp);
00349 } else
00350 n++;
00351 }
00352 }
00353
00354
00355 static SSERV_Info* s_GetNextInfo(SERV_ITER iter,
00356 HOST_INFO* host_info,
00357 int internal)
00358 {
00359 SSERV_Info* info = 0;
00360 assert(iter && iter->op);
00361 if (iter->op->GetNextInfo) {
00362 if (!internal) {
00363 iter->time = (TNCBI_Time) time(0);
00364 s_SkipSkip(iter);
00365 }
00366
00367 while ((info = (*iter->op->GetNextInfo)(iter, host_info)) != 0) {
00368
00369
00370 int go =
00371 !info->host || iter->pref >= 0.0 ||
00372 !iter->host || (iter->host == info->host &&
00373 (!iter->port || iter->port == info->port));
00374 if (go && internal)
00375 break;
00376 if (!s_AddSkipInfo(iter, SERV_NameOfInfo(info), info)) {
00377 free(info);
00378 info = 0;
00379 }
00380 if (go || !info)
00381 break;
00382 }
00383 }
00384 if (!internal)
00385 iter->last = info;
00386 return info;
00387 }
00388
00389
00390 static SSERV_Info* s_GetInfo(const char* service,
00391 TSERV_Type types,
00392 unsigned int preferred_host,
00393 unsigned short preferred_port,
00394 double preference,
00395 const SConnNetInfo* net_info,
00396 const SSERV_InfoCPtr skip[],
00397 size_t n_skip,
00398 int external,
00399 const char* arg,
00400 const char* val,
00401 HOST_INFO* host_info)
00402 {
00403 SSERV_Info* info = 0;
00404 SERV_ITER iter = s_Open(service, 0, types,
00405 preferred_host, preferred_port, preference,
00406 net_info, skip, n_skip,
00407 external, arg, val,
00408 &info, host_info);
00409 if (iter && iter->op && !info) {
00410
00411 info = s_GetNextInfo(iter, host_info, 1);
00412 }
00413 SERV_Close(iter);
00414 return info;
00415 }
00416
00417
00418 SSERV_Info* SERV_GetInfo(const char* service,
00419 TSERV_Type types,
00420 unsigned int preferred_host,
00421 const SConnNetInfo* net_info)
00422 {
00423 return s_GetInfo(service, types,
00424 preferred_host, 0, 0.0,
00425 net_info, 0, 0,
00426 0, 0, 0,
00427 0);
00428 }
00429
00430
00431 SSERV_Info* SERV_GetInfoEx(const char* service,
00432 TSERV_Type types,
00433 unsigned int preferred_host,
00434 const SConnNetInfo* net_info,
00435 const SSERV_InfoCPtr skip[],
00436 size_t n_skip,
00437 HOST_INFO* host_info)
00438 {
00439 return s_GetInfo(service, types,
00440 preferred_host, 0, 0.0,
00441 net_info, skip, n_skip,
00442 0, 0, 0,
00443 host_info);
00444 }
00445
00446
00447 SSERV_Info* SERV_GetInfoP(const char* service,
00448 TSERV_Type types,
00449 unsigned int preferred_host,
00450 unsigned short preferred_port,
00451 double preference,
00452 const SConnNetInfo* net_info,
00453 const SSERV_InfoCPtr skip[],
00454 size_t n_skip,
00455 int external,
00456 const char* arg,
00457 const char* val,
00458 HOST_INFO* host_info)
00459 {
00460 return s_GetInfo(service, types,
00461 preferred_host, preferred_port, preference,
00462 net_info, skip, n_skip,
00463 external, arg, val,
00464 host_info);
00465 }
00466
00467
00468 const SSERV_Info* SERV_GetNextInfoEx(SERV_ITER iter,
00469 HOST_INFO* host_info)
00470 {
00471 return iter && iter->op ? s_GetNextInfo(iter, host_info, 0) : 0;
00472 }
00473
00474
00475 const SSERV_Info* SERV_GetNextInfo(SERV_ITER iter)
00476 {
00477 return iter && iter->op ? s_GetNextInfo(iter, 0, 0) : 0;
00478 }
00479
00480
00481 const char* SERV_MapperName(SERV_ITER iter)
00482 {
00483 return iter && iter->op ? iter->op->name : 0;
00484 }
00485
00486
00487 const char* SERV_CurrentName(SERV_ITER iter)
00488 {
00489 const char* name = SERV_NameOfInfo(iter->last);
00490 return name && *name ? name : iter->name;
00491 }
00492
00493
00494 int SERV_Penalize(SERV_ITER iter, double fine)
00495 {
00496 if (!iter || !iter->op || !iter->op->Feedback || !iter->last)
00497 return 0;
00498 return (*iter->op->Feedback)(iter, fine, 1);
00499 }
00500
00501
00502 int SERV_Rerate(SERV_ITER iter, double rate)
00503 {
00504 if (!iter || !iter->op || !iter->op->Feedback || !iter->last)
00505 return 0;
00506 return (*iter->op->Feedback)(iter, rate, 0);
00507 }
00508
00509
00510 void SERV_Reset(SERV_ITER iter)
00511 {
00512 if (!iter)
00513 return;
00514 iter->last = 0;
00515 iter->time = 0;
00516 s_SkipSkip(iter);
00517 if (iter->op && iter->op->Reset)
00518 (*iter->op->Reset)(iter);
00519 }
00520
00521
00522 void SERV_Close(SERV_ITER iter)
00523 {
00524 size_t i;
00525 if (!iter)
00526 return;
00527 SERV_Reset(iter);
00528 for (i = 0; i < iter->n_skip; i++)
00529 free(iter->skip[i]);
00530 iter->n_skip = 0;
00531 if (iter->op) {
00532 if (iter->op->Close)
00533 (*iter->op->Close)(iter);
00534 iter->op = 0;
00535 }
00536 if (iter->skip)
00537 free(iter->skip);
00538 if (iter->name)
00539 free((void*) iter->name);
00540 free(iter);
00541 }
00542
00543
00544 int SERV_Update(SERV_ITER iter, const char* text, int code)
00545 {
00546 static const char used_server_info[] = "Used-Server-Info-";
00547 int retval = 0;
00548
00549 if (iter && iter->op && text) {
00550 const char *c, *b;
00551 iter->time = (TNCBI_Time) time(0);
00552 for (b = text; (c = strchr(b, '\n')) != 0; b = c + 1) {
00553 size_t len = (size_t)(c - b);
00554 SSERV_Info* info;
00555 unsigned int d1;
00556 char* p, *t;
00557 int d2;
00558
00559 if (!(t = (char*) malloc(len + 1)))
00560 continue;
00561 memcpy(t, b, len);
00562 if (t[len - 1] == '\r')
00563 t[len - 1] = '\0';
00564 else
00565 t[len] = '\0';
00566 p = t;
00567 if (iter->op->Update && (*iter->op->Update)(iter, p, code))
00568 retval = 1;
00569 if (!strncasecmp(p, used_server_info, sizeof(used_server_info) - 1)
00570 && isdigit((unsigned char) p[sizeof(used_server_info) - 1])) {
00571 p += sizeof(used_server_info) - 1;
00572 if (sscanf(p, "%u: %n", &d1, &d2) >= 1 &&
00573 (info = SERV_ReadInfoEx(p + d2, "")) != 0) {
00574 if (!s_AddSkipInfo(iter, "", info))
00575 free(info);
00576 else
00577 retval = 1;
00578 }
00579 }
00580 free(t);
00581 }
00582 }
00583 return retval;
00584 }
00585
00586
00587 static void s_SetDefaultReferer(SERV_ITER iter, SConnNetInfo* net_info)
00588 {
00589 char* str, *referer = 0;
00590
00591 if (strcasecmp(iter->op->name, "DISPD") == 0)
00592 referer = ConnNetInfo_URL(net_info);
00593 else if ((str = strdup(iter->op->name)) != 0) {
00594 const char* host = net_info->client_host;
00595 const char* args = net_info->args;
00596 const char* name = iter->name;
00597
00598 if (!*net_info->client_host
00599 && !SOCK_gethostbyaddr(0, net_info->client_host,
00600 sizeof(net_info->client_host))) {
00601 SOCK_gethostname(net_info->client_host,
00602 sizeof(net_info->client_host));
00603 }
00604 if (!(referer = (char*) malloc(3 + 1 + 1 + 1 + 2*strlen(strlwr(str)) +
00605 strlen(host) + (args[0]
00606 ? strlen(args)
00607 : 8 + strlen(name))))) {
00608 return;
00609 }
00610 strcat(strcat(strcat(strcat(strcpy
00611 (referer, str), "://"), host), "/"), str);
00612 if (args[0])
00613 strcat(strcat(referer, "?"), args);
00614 else
00615 strcat(strcat(referer, "?service="), name);
00616 free(str);
00617 }
00618 assert(!net_info->http_referer);
00619 net_info->http_referer = referer;
00620 }
00621
00622
00623 char* SERV_Print(SERV_ITER iter, SConnNetInfo* net_info, int but_last)
00624 {
00625 static const char kClientRevision[] = "Client-Revision: %hu.%hu\r\n";
00626 static const char kAcceptedServerTypes[] = "Accepted-Server-Types:";
00627 static const char kUsedServerInfo[] = "Used-Server-Info: ";
00628 static const char kServerCount[] = "Server-Count: ";
00629 static const char kSkipInfo[] = "Skip-Info-%u: ";
00630 static const char kAffinity[] = "Affinity: ";
00631 char buffer[128], *str;
00632 size_t buflen, i;
00633 TSERV_Type t;
00634 BUF buf = 0;
00635
00636
00637 buflen = sprintf(buffer, kClientRevision,
00638 SERV_CLIENT_REVISION_MAJOR, SERV_CLIENT_REVISION_MINOR);
00639 assert(buflen < sizeof(buffer));
00640 if (!BUF_Write(&buf, buffer, buflen)) {
00641 BUF_Destroy(buf);
00642 return 0;
00643 }
00644 if (iter) {
00645 if (net_info && !net_info->http_referer && iter->op && iter->op->name)
00646 s_SetDefaultReferer(iter, net_info);
00647
00648 buflen = sizeof(kAcceptedServerTypes) - 1;
00649 memcpy(buffer, kAcceptedServerTypes, buflen);
00650 for (t = 1; t; t <<= 1) {
00651 if (iter->type & t) {
00652 const char* name = SERV_TypeStr((ESERV_Type) t);
00653 size_t namelen = strlen(name);
00654 if (!namelen || buflen + 1 + namelen + 2 >= sizeof(buffer))
00655 break;
00656 buffer[buflen++] = ' ';
00657 memcpy(buffer + buflen, name, namelen);
00658 buflen += namelen;
00659 }
00660 }
00661 if (buffer[buflen - 1] != ':') {
00662 strcpy(&buffer[buflen], "\r\n");
00663 assert(strlen(buffer) == buflen+2 && buflen+2 < sizeof(buffer));
00664 if (!BUF_Write(&buf, buffer, buflen + 2)) {
00665 BUF_Destroy(buf);
00666 return 0;
00667 }
00668 }
00669 if (iter->ismask || (iter->pref && iter->host)) {
00670
00671 if (!BUF_Write(&buf, kServerCount, sizeof(kServerCount) - 1) ||
00672 !BUF_Write(&buf,
00673 iter->ismask ? "10" : "ALL",
00674 iter->ismask ? 2 : 3) ||
00675 !BUF_Write(&buf, "\r\n", 2)) {
00676 BUF_Destroy(buf);
00677 return 0;
00678 }
00679 }
00680 if (iter->arglen) {
00681
00682 if (!BUF_Write(&buf, kAffinity, sizeof(kAffinity) - 1) ||
00683 !BUF_Write(&buf, iter->arg, iter->arglen) ||
00684 (iter->val && (!BUF_Write(&buf, "=", 1) ||
00685 !BUF_Write(&buf, iter->val, iter->vallen))) ||
00686 !BUF_Write(&buf, "\r\n", 2)) {
00687 BUF_Destroy(buf);
00688 return 0;
00689 }
00690 }
00691
00692 iter->time = (TNCBI_Time) time(0);
00693 s_SkipSkip(iter);
00694
00695 for (i = 0; i < iter->n_skip; i++) {
00696
00697 const char* name = SERV_NameOfInfo(iter->skip[i]);
00698 if (!(str = SERV_WriteInfo(iter->skip[i])))
00699 break;
00700 if (but_last && iter->last == iter->skip[i]) {
00701 buflen = sizeof(kUsedServerInfo) - 1;
00702 memcpy(buffer, kUsedServerInfo, buflen);
00703 } else
00704 buflen = sprintf(buffer, kSkipInfo, (unsigned) i + 1);
00705 assert(buflen < sizeof(buffer) - 1);
00706 if (!BUF_Write(&buf, buffer, buflen) ||
00707 (name && !BUF_Write(&buf, name, strlen(name))) ||
00708 (name && *name && !BUF_Write(&buf, " ", 1)) ||
00709 !BUF_Write(&buf, str, strlen(str)) ||
00710 !BUF_Write(&buf, "\r\n", 2)) {
00711 free(str);
00712 break;
00713 }
00714 free(str);
00715 }
00716 if (i < iter->n_skip) {
00717 BUF_Destroy(buf);
00718 return 0;
00719 }
00720 }
00721
00722 if ((buflen = BUF_Size(buf)) != 0) {
00723 if ((str = (char*) malloc(buflen + 1)) != 0) {
00724 if (BUF_Read(buf, str, buflen) != buflen) {
00725 free(str);
00726 str = 0;
00727 } else
00728 str[buflen] = '\0';
00729 }
00730 } else
00731 str = 0;
00732 BUF_Destroy(buf);
00733 return str;
00734 }
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 double SERV_Preference(double pref, double gap, size_t n)
00745 {
00746 double spread;
00747 assert(0.0 <= pref && pref <= 1.0);
00748 assert(0.0 < gap && gap <= 1.0);
00749 assert(n >= 2);
00750 if (gap >= pref)
00751 return gap;
00752 spread = 14.0/(n + 12.0);
00753 if (gap >= spread/((double) n))
00754 return pref;
00755 else
00756 return 2.0/spread*gap*pref;
00757 }
00758
00759
00760 unsigned short SERV_ServerPort(const char* name,
00761 unsigned int host)
00762 {
00763 SSERV_Info* info;
00764 unsigned short port;
00765
00766
00767
00768
00769
00770 if (!host || host == SERV_LOCALHOST)
00771 host = SOCK_GetLocalHostAddress(eDefault);
00772 if (!(info = s_GetInfo(name, fSERV_Standalone | fSERV_Promiscuous,
00773 host, 0, -1.0,
00774 0, 0, 0,
00775 0, 0, 0,
00776 0))) {
00777 return 0;
00778 }
00779 assert(info->host == host);
00780 port = info->port;
00781 free((void*) info);
00782 assert(port);
00783 return port;
00784 }
00785
00786