~ubuntu-branches/ubuntu/precise/ncbi-tools6/precise

« back to all changes in this revision

Viewing changes to connect/ncbi_service.c

  • Committer: Bazaar Package Importer
  • Author(s): Aaron M. Ucko
  • Date: 2005-03-27 12:00:15 UTC
  • mfrom: (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050327120015-embhesp32nj73p9r
Tags: 6.1.20041020-3
* Fix FTBFS under GCC 4.0 caused by inconsistent use of "static" on
  functions.  (Closes: #295110.)
* Add a watch file, now that we can.  (Upstream's layout needs version=3.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  $Id: ncbi_service.c,v 6.32 2001/11/09 20:03:14 lavr Exp $
 
1
/*  $Id: ncbi_service.c,v 6.55 2004/08/19 15:48:35 lavr Exp $
2
2
 * ===========================================================================
3
3
 *
4
4
 *                            PUBLIC DOMAIN NOTICE
28
28
 * File Description:
29
29
 *   Top-level API to resolve NCBI service name to the server meta-address.
30
30
 *
31
 
 * --------------------------------------------------------------------------
32
 
 * $Log: ncbi_service.c,v $
33
 
 * Revision 6.32  2001/11/09 20:03:14  lavr
34
 
 * Minor fix to remove a trailing space in client version tag
35
 
 *
36
 
 * Revision 6.31  2001/10/01 19:52:38  lavr
37
 
 * Call update directly; do not remove time from server specs in SERV_Print()
38
 
 *
39
 
 * Revision 6.30  2001/09/29 19:33:04  lavr
40
 
 * BUGFIX: SERV_Update() requires VT bound (was not the case in constructor)
41
 
 *
42
 
 * Revision 6.29  2001/09/28 22:03:12  vakatov
43
 
 * Included missing <connect/ncbi_ansi_ext.h>
44
 
 *
45
 
 * Revision 6.28  2001/09/28 20:50:16  lavr
46
 
 * SERV_Update() modified to capture Used-Server-Info tags;
47
 
 * Update VT method changed - now called on per-line basis;
48
 
 * Few bugfixes related to keeping last info correct
49
 
 *
50
 
 * Revision 6.27  2001/09/24 20:28:48  lavr
51
 
 * +SERV_Reset(); SERV_Close() changed to utilize SERV_Reset()
52
 
 *
53
 
 * Revision 6.26  2001/09/10 21:19:48  lavr
54
 
 * SERV_Print():  Client version tag added
55
 
 * SERV_OpenEx(): Firewall type handling
56
 
 *
57
 
 * Revision 6.25  2001/08/20 21:58:19  lavr
58
 
 * Parameter change for clarity: info -> net_info if type is SConnNetInfo
59
 
 *
60
 
 * Revision 6.24  2001/06/25 15:35:54  lavr
61
 
 * Added function: SERV_GetNextInfoEx
62
 
 *
63
 
 * Revision 6.23  2001/06/20 17:27:49  kans
64
 
 * include <time.h> for Mac compiler
65
 
 *
66
 
 * Revision 6.22  2001/06/19 19:12:01  lavr
67
 
 * Type change: size_t -> TNCBI_Size; time_t -> TNCBI_Time
68
 
 *
69
 
 * Revision 6.21  2001/05/24 21:28:12  lavr
70
 
 * Timeout for skip servers increased to 1 year period
71
 
 *
72
 
 * Revision 6.20  2001/05/17 15:02:51  lavr
73
 
 * Typos corrected
74
 
 *
75
 
 * Revision 6.19  2001/04/24 21:37:26  lavr
76
 
 * New code for: SERV_MapperName() and SERV_Penalize().
77
 
 *
78
 
 * Revision 6.18  2001/03/21 21:23:30  lavr
79
 
 * Explicit type conversion size_t -> unsigned in printf
80
 
 *
81
 
 * Revision 6.17  2001/03/20 22:03:32  lavr
82
 
 * BUGFIX in SERV_Print (miscalculation of buflen for accepted server types)
83
 
 *
84
 
 * Revision 6.16  2001/03/06 23:55:25  lavr
85
 
 * SOCK_gethostaddr -> SOCK_gethostbyname
86
 
 *
87
 
 * Revision 6.15  2001/03/05 23:10:29  lavr
88
 
 * SERV_WriteInfo takes only one argument now
89
 
 *
90
 
 * Revision 6.14  2001/03/02 20:09:51  lavr
91
 
 * Support added for SERV_LOCALHOST as preferred_host.
92
 
 *
93
 
 * Revision 6.13  2001/03/01 00:31:23  lavr
94
 
 * SERV_OpenSimple now builds SConnNetInfo to use both LBSMD and DISPD.CGI
95
 
 *
96
 
 * Revision 6.12  2001/02/09 17:33:06  lavr
97
 
 * Modified: fSERV_StatelessOnly overrides info->stateless
98
 
 *
99
 
 * Revision 6.11  2001/01/25 17:05:32  lavr
100
 
 * Bugfix in SERV_OpenEx: op was not inited to 0
101
 
 *
102
 
 * Revision 6.10  2001/01/08 23:47:29  lavr
103
 
 * (unsigned char) conversion in isspace
104
 
 *
105
 
 * Revision 6.9  2001/01/08 22:38:34  lavr
106
 
 * Numerous patches to code after debugging
107
 
 *
108
 
 * Revision 6.8  2000/12/29 18:01:27  lavr
109
 
 * SERV_Print introduced; pool of skipped services now follows
110
 
 * expiration times of services and is updated on that basis.
111
 
 *
112
 
 * Revision 6.7  2000/12/06 22:20:30  lavr
113
 
 * Skip info list is not maintained forever; instead the entries get
114
 
 * deleted in accordance with their expiration period
115
 
 *
116
 
 * Revision 6.6  2000/10/20 17:19:04  lavr
117
 
 * SConnNetInfo made 'const' as a parameter to 'SERV_Open*'
118
 
 * 'SERV_Update' added as a private interface
119
 
 *
120
 
 * Revision 6.5  2000/10/05 22:36:21  lavr
121
 
 * Additional parameters in call to DISPD mapper
122
 
 *
123
 
 * Revision 6.4  2000/05/31 23:12:23  lavr
124
 
 * First try to assemble things together to get working service mapper
125
 
 *
126
 
 * Revision 6.3  2000/05/22 16:53:11  lavr
127
 
 * Rename service_info -> server_info everywhere (including
128
 
 * file names) as the latter name is more relevant
129
 
 *
130
 
 * Revision 6.2  2000/05/12 21:42:59  lavr
131
 
 * Cleaned up for the C++ compilation, etc.
132
 
 *
133
 
 * Revision 6.1  2000/05/12 18:50:20  lavr
134
 
 * First working revision
135
 
 *
136
 
 * ==========================================================================
137
31
 */
138
32
 
139
 
#include "ncbi_servicep.h"
140
 
#include "ncbi_servicep_lbsmd.h"
141
 
#include "ncbi_servicep_dispd.h"
142
 
#include <connect/ncbi_ansi_ext.h>
143
 
#include <assert.h>
 
33
#include "ncbi_ansi_ext.h"
 
34
#include "ncbi_dispd.h"
 
35
#include "ncbi_lbsmd.h"
 
36
#include "ncbi_priv.h"
144
37
#include <ctype.h>
145
38
#include <stdlib.h>
146
 
#include <string.h>
147
39
#include <time.h>
148
40
 
 
41
#define SERV_SERVICE_NAME "SERVICE_NAME"
 
42
 
 
43
 
 
44
static char* s_ServiceName(const char* service, size_t depth)
 
45
{
 
46
    char *s, *p;
 
47
    char key[128];
 
48
    char srv[128];
 
49
 
 
50
    if (++depth > 8 || !service || !*service ||
 
51
        sizeof(DEF_CONN_REG_SECTION) + sizeof(SERV_SERVICE_NAME) +
 
52
        strlen(service) >= sizeof(key))
 
53
        return 0/*failure*/;
 
54
    s = key;
 
55
    strcpy(s, DEF_CONN_REG_SECTION);
 
56
    s += sizeof(DEF_CONN_REG_SECTION) - 1;
 
57
    *s++ = '_';
 
58
    strcpy(s, SERV_SERVICE_NAME);
 
59
    s += sizeof(SERV_SERVICE_NAME) - 1;
 
60
    *s++ = '_';
 
61
    strcpy(s, service);
 
62
    strupr(key);
 
63
    /* Looking for "CONN_SERVICE_NAME_service" in environment */
 
64
    if (!(p = getenv(key))) {
 
65
        *--s = '\0';
 
66
        /* Looking for "CONN_SERVICE_NAME" in registry's section [service] */
 
67
        CORE_REG_GET(service, key, srv, sizeof(srv), 0);
 
68
        if (!*srv)
 
69
            return strdup(service);
 
70
    } else
 
71
        strncpy0(srv, p, sizeof(srv) - 1);
 
72
 
 
73
    /* No cycle detection in service name redefinition */
 
74
    return s_ServiceName(srv, depth);
 
75
}
 
76
 
 
77
 
 
78
char* SERV_ServiceName(const char* service)
 
79
{
 
80
    return s_ServiceName(service, 0);
 
81
}
 
82
 
149
83
 
150
84
SERV_ITER SERV_OpenSimple(const char* service)
151
85
{
158
92
 
159
93
static int/*bool*/ s_AddSkipInfo(SERV_ITER iter, SSERV_Info* info)
160
94
{
 
95
    if (info->type == fSERV_Firewall) {
 
96
        size_t n;
 
97
        for (n = 0; n < iter->n_skip; n++) {
 
98
            SSERV_Info* temp = iter->skip[n];
 
99
            if (temp->type == fSERV_Firewall &&
 
100
                temp->u.firewall.type == info->u.firewall.type) {
 
101
                if (n < --iter->n_skip) {
 
102
                    memmove(iter->skip + n, iter->skip + n + 1,
 
103
                            sizeof(*iter->skip)*(iter->n_skip - n));
 
104
                }
 
105
                if (iter->last == temp)
 
106
                    iter->last = 0;
 
107
                free(temp);
 
108
                break;
 
109
            }
 
110
        }
 
111
    }
161
112
    if (iter->n_skip == iter->n_max_skip) {
162
113
        SSERV_Info** temp;
163
114
        size_t n = iter->n_max_skip + 10;
172
123
        iter->skip = temp;
173
124
        iter->n_max_skip = n;
174
125
    }
175
 
 
176
126
    iter->skip[iter->n_skip++] = info;
177
127
    return 1;
178
128
}
179
129
 
180
130
 
181
 
SERV_ITER SERV_OpenEx(const char* service,
182
 
                      TSERV_Type type, unsigned int preferred_host,
183
 
                      const SConnNetInfo* net_info,
184
 
                      const SSERV_Info* const skip[], size_t n_skip)
 
131
static SERV_ITER s_Open(const char* service, TSERV_Type types,
 
132
                        unsigned int preferred_host, double preference,
 
133
                        const SConnNetInfo* net_info,
 
134
                        const SSERV_Info* const skip[], size_t n_skip,
 
135
                        SSERV_Info** info, HOST_INFO* host_info, int external)
185
136
{
 
137
    const char* s = s_ServiceName(service, 0);
186
138
    const SSERV_VTable* op;
187
139
    SERV_ITER iter;
188
 
    TNCBI_Time t;
189
 
    size_t i;
190
 
 
191
 
    if (!service || !*service ||
192
 
        !(iter = (SERV_ITER) malloc(sizeof(*iter) + strlen(service)+1)))
 
140
    
 
141
    if (!s || !*s || !(iter = (SERV_ITER) malloc(sizeof(*iter))))
193
142
        return 0;
194
143
 
195
 
    iter->service = (char*) iter + sizeof(*iter);
196
 
    strcpy((char*) iter->service, service);
197
 
    iter->type = type;
198
 
    iter->preferred_host =
199
 
        preferred_host == SERV_LOCALHOST
 
144
    iter->service        = s;
 
145
    iter->types          = types;
 
146
    iter->preferred_host = preferred_host == SERV_LOCALHOST
200
147
        ? SOCK_gethostbyname(0) : preferred_host;
201
 
    iter->n_skip = iter->n_max_skip = 0;
202
 
    iter->skip = 0;
203
 
    iter->last = 0;
204
 
    iter->op = 0;
205
 
    iter->data = 0;
 
148
    iter->preference = 0.01*(preference < 0.0   ? 0.0   :
 
149
                             preference > 100.0 ? 100.0 : preference);
 
150
    iter->n_skip         = iter->n_max_skip = 0;
 
151
    iter->skip           = 0;
 
152
    iter->last           = 0;
 
153
    iter->op             = 0;
 
154
    iter->data           = 0;
 
155
    iter->external       = external;
206
156
 
207
 
    t = (TNCBI_Time) time(0);
208
 
    for (i = 0; i < n_skip; i++) {
209
 
        size_t infolen = SERV_SizeOfInfo(skip[i]);
210
 
        SSERV_Info* info = (SSERV_Info*) malloc(infolen);
211
 
        if (!info) {
212
 
            SERV_Close(iter);
213
 
            return 0;
214
 
        }
215
 
        memcpy(info, skip[i], infolen);
216
 
        info->time = t + 3600/*hour*/*24/*day*/*365/*year - long enough :-) */;
217
 
        if (!s_AddSkipInfo(iter, info)) {
218
 
            free(info);
219
 
            SERV_Close(iter);
 
157
    if (n_skip) {
 
158
        size_t i;
 
159
        for (i = 0; i < n_skip; i++) {
 
160
            size_t   skipinfolen = SERV_SizeOfInfo(skip[i]);
 
161
            SSERV_Info* skipinfo = (SSERV_Info*) malloc(skipinfolen);
 
162
            if (!skipinfo) {
 
163
                SERV_Close(iter);
 
164
                return 0;
 
165
            }
 
166
            memcpy(skipinfo, skip[i], skipinfolen);
 
167
            skipinfo->time = (TNCBI_Time)(-1);
 
168
            if (!s_AddSkipInfo(iter, skipinfo)) {
 
169
                free(skipinfo);
 
170
                SERV_Close(iter);
 
171
            }
220
172
        }
221
173
    }
222
174
    assert(n_skip == iter->n_skip);
223
175
 
224
176
    if (!net_info) {
225
 
        if (!(op = SERV_LBSMD_Open(iter))) {
 
177
        if (!(op = SERV_LBSMD_Open(iter, info, host_info))) {
226
178
            /* LBSMD failed in non-DISPD mapping */
227
179
            SERV_Close(iter);
228
180
            return 0;
229
181
        }
230
182
    } else {
231
183
        if (net_info->stateless)
232
 
            iter->type |= fSERV_StatelessOnly;
 
184
            iter->types |= fSERV_StatelessOnly;
233
185
        if (net_info->firewall)
234
 
            iter->type |= fSERV_Firewall;
235
 
        if ((net_info->lb_disable || !(op = SERV_LBSMD_Open(iter))) &&
236
 
            !(op = SERV_DISPD_Open(iter, net_info))) {
 
186
            iter->types |= fSERV_Firewall;
 
187
        if ((net_info->lb_disable ||
 
188
             !(op = SERV_LBSMD_Open(iter, info, host_info))) &&
 
189
            !(op = SERV_DISPD_Open(iter, net_info, info, host_info))) {
237
190
            SERV_Close(iter);
238
191
            return 0;
239
192
        }
245
198
}
246
199
 
247
200
 
 
201
SERV_ITER SERV_OpenEx(const char* service,
 
202
                      TSERV_Type types, unsigned int preferred_host,
 
203
                      const SConnNetInfo* net_info,
 
204
                      const SSERV_Info* const skip[], size_t n_skip)
 
205
{
 
206
    return s_Open(service, types, preferred_host, 0.0,
 
207
                  net_info, skip, n_skip, 0, 0, 0/*not external*/);
 
208
}
 
209
 
 
210
 
 
211
SERV_ITER SERV_OpenP(const char* service, TSERV_Type types,
 
212
                     unsigned int preferred_host, double preference,
 
213
                     int/*bool*/ external)
 
214
{
 
215
    return s_Open(service, types, preferred_host, preference,
 
216
                  0, 0, 0, 0, 0, external);
 
217
}
 
218
 
 
219
 
 
220
static SSERV_Info* s_GetInfo(const char* service, TSERV_Type types,
 
221
                             unsigned int preferred_host, double preference,
 
222
                             const SConnNetInfo* net_info,
 
223
                             const SSERV_Info* const skip[], size_t n_skip,
 
224
                             HOST_INFO* host_info, int/*bool*/ external)
 
225
{
 
226
    SSERV_Info* info = 0;
 
227
    SERV_ITER iter= s_Open(service, types, preferred_host, preference,
 
228
                           net_info, skip, n_skip, &info, host_info, external);
 
229
    if (iter && !info && iter->op && iter->op->GetNextInfo)
 
230
        info = (*iter->op->GetNextInfo)(iter, host_info);
 
231
    SERV_Close(iter);
 
232
    return info;
 
233
}
 
234
 
 
235
 
 
236
SSERV_Info* SERV_GetInfoEx(const char* service, TSERV_Type types,
 
237
                           unsigned int preferred_host,
 
238
                           const SConnNetInfo* net_info,
 
239
                           const SSERV_Info* const skip[], size_t n_skip,
 
240
                           HOST_INFO* host_info)
 
241
{
 
242
    return s_GetInfo(service, types, preferred_host, 0.0,
 
243
                     net_info, skip, n_skip, host_info, 0/*not external*/);
 
244
}
 
245
 
 
246
 
 
247
SSERV_Info* SERV_GetInfoP(const char* service, TSERV_Type types,
 
248
                          unsigned int preferred_host, double preference,
 
249
                          int/*bool*/ external)
 
250
{
 
251
    return s_GetInfo(service, types, preferred_host, preference,
 
252
                     0, 0, 0, 0, external);
 
253
}
 
254
 
 
255
 
248
256
static void s_SkipSkip(SERV_ITER iter)
249
257
{
250
 
    TNCBI_Time t = (TNCBI_Time) time(0);
251
 
    size_t i;
 
258
    if (iter->n_skip) {
 
259
        TNCBI_Time t = (TNCBI_Time) time(0);
 
260
        size_t n = 0;
252
261
 
253
 
    i = 0;
254
 
    while (i < iter->n_skip) {
255
 
        SSERV_Info* info = iter->skip[i];
256
 
        if (info->time < t) {
257
 
            if (i < --iter->n_skip)
258
 
                memmove(iter->skip + i, iter->skip + i + 1,
259
 
                        sizeof(*iter->skip)*(iter->n_skip - i));
260
 
            if (info == iter->last)
261
 
                iter->last = 0;
262
 
            free(info);
263
 
        } else
264
 
            i++;
 
262
        while (n < iter->n_skip) {
 
263
            SSERV_Info* temp = iter->skip[n];
 
264
            if (temp->time < t) {
 
265
                if (n < --iter->n_skip) {
 
266
                    memmove(iter->skip + n, iter->skip + n + 1,
 
267
                            sizeof(*iter->skip)*(iter->n_skip - n));
 
268
                }
 
269
                if (iter->last == temp)
 
270
                    iter->last = 0;
 
271
                free(temp);
 
272
            } else
 
273
                n++;
 
274
        }
265
275
    }
266
276
}
267
277
 
268
278
 
269
 
const SSERV_Info* SERV_GetNextInfoEx(SERV_ITER iter, char** env)
 
279
const SSERV_Info* SERV_GetNextInfoEx(SERV_ITER iter, HOST_INFO* host_info)
270
280
{
271
281
    SSERV_Info* info = 0;
272
282
 
275
285
        s_SkipSkip(iter);
276
286
        /* Next, obtain a fresh entry from the actual mapper */
277
287
        if (iter->op->GetNextInfo &&
278
 
            (info = (*iter->op->GetNextInfo)(iter, env)) != 0 &&
 
288
            (info = (*iter->op->GetNextInfo)(iter, host_info)) != 0 &&
279
289
            !s_AddSkipInfo(iter, info)) {
280
290
            free(info);
281
291
            info = 0;
300
310
}
301
311
 
302
312
 
 
313
char* SERV_GetConfig(void)
 
314
{
 
315
    return SERV_LBSMD_GetConfig();
 
316
}
 
317
 
 
318
 
303
319
void SERV_Reset(SERV_ITER iter)
304
320
{
305
321
    size_t i;
321
337
    SERV_Reset(iter);
322
338
    if (iter->op && iter->op->Close)
323
339
        (*iter->op->Close)(iter);
324
 
    iter->op = 0;
325
 
    if (iter->skip) {
 
340
    if (iter->skip)
326
341
        free(iter->skip);
327
 
        iter->skip = 0;
328
 
    }
 
342
    if (iter->service)
 
343
        free((void*) iter->service);
329
344
    free(iter);
330
345
}
331
346
 
373
388
}
374
389
 
375
390
 
376
 
char* SERV_Print(SERV_ITER iter)
 
391
char* SERV_PrintEx(SERV_ITER iter, const SConnNetInfo* referrer)
377
392
{
378
 
    static const char revision[] = "$Revision: 6.32 $";
379
 
    static const char client_version[] = "Client-Version:";
 
393
    static const char referrer_header[] = "Referer: "/*standard misspelling*/;
 
394
    static const char client_revision[] = "Client-Revision: %hu.%hu\r\n";
380
395
    static const char accepted_types[] = "Accepted-Server-Types:";
381
 
    TSERV_Type type = (TSERV_Type) (iter->type & ~fSERV_StatelessOnly);
382
396
    char buffer[128], *str;
 
397
    TSERV_Type types, t;
383
398
    size_t buflen, i;
384
 
    TSERV_Type t;
385
399
    BUF buf = 0;
386
400
 
387
401
    /* Put client version number */
388
 
    buflen = sizeof(client_version) - 1;
389
 
    memcpy(buffer, client_version, buflen);
390
 
    for (i = 0; revision[i]; i++)
391
 
        if (isspace((unsigned char) revision[i]))
392
 
            break;
393
 
    while (revision[i] && buflen + 2 < sizeof(buffer)) {
394
 
        if (revision[i] == '$') {
395
 
            if (isspace((unsigned char) revision[i - 1]))
396
 
                --buflen;
397
 
            break;
398
 
        } else
399
 
            buffer[buflen++] = revision[i++];
400
 
    }
401
 
    strcpy(&buffer[buflen], "\r\n");
402
 
    assert(strlen(buffer) == buflen + 2 && buflen + 2 < sizeof(buffer));
403
 
    if (!BUF_Write(&buf, buffer, buflen + 2)) {
 
402
    buflen = sprintf(buffer, client_revision,
 
403
                     SERV_CLIENT_REVISION_MAJOR, SERV_CLIENT_REVISION_MINOR);
 
404
    assert(buflen < sizeof(buffer));
 
405
    if (!BUF_Write(&buf, buffer, buflen)) {
404
406
        BUF_Destroy(buf);
405
407
        return 0;
406
408
    }
407
 
    /* Form accepted server types */
408
 
    buflen = sizeof(accepted_types) - 1;
409
 
    memcpy(buffer, accepted_types, buflen);
410
 
    for (t = 1; t; t <<= 1) {
411
 
        if (type & t) {
412
 
            const char* name = SERV_TypeStr((ESERV_Type) t);
413
 
            size_t namelen = strlen(name);
414
 
            if (!namelen || buflen + 1 + namelen + 2 >= sizeof(buffer))
415
 
                break;
416
 
            buffer[buflen++] = ' ';
417
 
            strcpy(&buffer[buflen], name);
418
 
            buflen += namelen;
419
 
        }
420
 
    }
421
 
    if (buffer[buflen - 1] != ':') {
422
 
        strcpy(&buffer[buflen], "\r\n");
423
 
        assert(strlen(buffer) == buflen + 2 && buflen + 2 < sizeof(buffer));
424
 
        if (!BUF_Write(&buf, buffer, buflen + 2)) {
 
409
    if (iter) {
 
410
        int/*bool*/ refer = referrer && iter->op && iter->op->name;
 
411
        if (refer && strcasecmp(iter->op->name, "DISPD") == 0) {
 
412
            const char* host = referrer->host;
 
413
            const char* path = referrer->path;
 
414
            const char* args = referrer->args;
 
415
            const char* service = iter->service;
 
416
            char port[8];
 
417
            if (referrer->port && referrer->port != DEF_CONN_PORT)
 
418
                sprintf(port, ":%hu", referrer->port);
 
419
            else
 
420
                port[0] = '\0';
 
421
            if (!BUF_Write(&buf, referrer_header, sizeof(referrer_header)-1) ||
 
422
                !BUF_Write(&buf, "http://", 7)                               ||
 
423
                !BUF_Write(&buf, host, strlen(host))                         ||
 
424
                !BUF_Write(&buf, port, strlen(port))                         ||
 
425
                !BUF_Write(&buf, path, strlen(path))                         ||
 
426
                !BUF_Write(&buf, "?service=", 9)                             ||
 
427
                !BUF_Write(&buf, service, strlen(service))                   ||
 
428
                (args[0] && (!BUF_Write(&buf, "&", 1)                        ||
 
429
                             !BUF_Write(&buf, args, strlen(args))))          ||
 
430
                !BUF_Write(&buf, "\r\n", 2)) {
 
431
                BUF_Destroy(buf);
 
432
                return 0;
 
433
            }
 
434
        } else if (refer && strcasecmp(iter->op->name, "LBSMD") == 0) {
 
435
            const char* host = referrer->client_host;
 
436
            const char* service = iter->service;
 
437
            if (!BUF_Write(&buf, referrer_header, sizeof(referrer_header)-1) ||
 
438
                !BUF_Write(&buf, "lbsm://", 7)                               ||
 
439
                !BUF_Write(&buf, host, strlen(host))                         ||
 
440
                !BUF_Write(&buf, "/dispatch?service=", 18)                   ||
 
441
                !BUF_Write(&buf, service, strlen(service))                   ||
 
442
                !BUF_Write(&buf, "\r\n", 2)) {
 
443
                BUF_Destroy(buf);
 
444
                return 0;
 
445
            }
 
446
        }
 
447
        /* Form accepted server types */
 
448
        buflen = sizeof(accepted_types) - 1;
 
449
        memcpy(buffer, accepted_types, buflen);
 
450
        types = (TSERV_Type) (iter->types & ~fSERV_StatelessOnly);
 
451
        for (t = 1; t; t <<= 1) {
 
452
            if (types & t) {
 
453
                const char* name = SERV_TypeStr((ESERV_Type) t);
 
454
                size_t namelen = strlen(name);
 
455
                if (!namelen || buflen + 1 + namelen + 2 >= sizeof(buffer))
 
456
                    break;
 
457
                buffer[buflen++] = ' ';
 
458
                strcpy(&buffer[buflen], name);
 
459
                buflen += namelen;
 
460
            }
 
461
        }
 
462
        if (buffer[buflen - 1] != ':') {
 
463
            strcpy(&buffer[buflen], "\r\n");
 
464
            assert(strlen(buffer) == buflen+2  &&  buflen+2 < sizeof(buffer));
 
465
            if (!BUF_Write(&buf, buffer, buflen + 2)) {
 
466
                BUF_Destroy(buf);
 
467
                return 0;
 
468
            }
 
469
        }
 
470
        /* Drop any outdated skip entries */
 
471
        s_SkipSkip(iter);
 
472
        /* Put all the rest into rejection list */
 
473
        for (i = 0; i < iter->n_skip; i++) {
 
474
            if (!(str = SERV_WriteInfo(iter->skip[i])))
 
475
                break;
 
476
            buflen = sprintf(buffer, "Skip-Info-%u: ", (unsigned) i + 1); 
 
477
            assert(buflen < sizeof(buffer)-1);
 
478
            if (!BUF_Write(&buf, buffer, buflen) ||
 
479
                !BUF_Write(&buf, str, strlen(str)) ||
 
480
                !BUF_Write(&buf, "\r\n", 2)) {
 
481
                free(str);
 
482
                break;
 
483
            }
 
484
            free(str);
 
485
        }
 
486
        if (i < iter->n_skip) {
425
487
            BUF_Destroy(buf);
426
488
            return 0;
427
489
        }
428
490
    }
429
 
    /* Drop any outdated skip entries */
430
 
    s_SkipSkip(iter);
431
 
    /* Put all the rest into rejection list */
432
 
    for (i = 0; i < iter->n_skip; i++) {
433
 
        if (!(str = SERV_WriteInfo(iter->skip[i])))
434
 
            break;
435
 
        buflen = sprintf(buffer, "Skip-Info-%u: ", (unsigned) i + 1); 
436
 
        assert(buflen < sizeof(buffer)-1);
437
 
        if (!BUF_Write(&buf, buffer, buflen) ||
438
 
            !BUF_Write(&buf, str, strlen(str)) ||
439
 
            !BUF_Write(&buf, "\r\n", 2)) {
440
 
            free(str);
441
 
            break;
 
491
    /* Ok then, we have filled the entire header, <CR><LF> terminated */
 
492
    if ((buflen = BUF_Size(buf)) != 0) {
 
493
        if ((str = (char*) malloc(buflen + 1)) != 0) {
 
494
            if (BUF_Read(buf, str, buflen) != buflen) {
 
495
                free(str);
 
496
                str = 0;
 
497
            } else
 
498
                str[buflen] = '\0';
442
499
        }
443
 
        free(str);
444
 
    }
445
 
    if (i >= iter->n_skip) {
446
 
        /* Ok then, we have filled the entire header, <CR><LF> terminated */
447
 
        if ((buflen = BUF_Size(buf)) != 0) {
448
 
            if ((str = (char*) malloc(buflen + 1)) != 0) {
449
 
                if (BUF_Read(buf, str, buflen) != buflen) {
450
 
                    free(str);
451
 
                    str = 0;
452
 
                } else
453
 
                    str[buflen] = '\0';
454
 
            }
455
 
        } else
456
 
            str = 0;
457
500
    } else
458
501
        str = 0;
459
502
    BUF_Destroy(buf);
460
503
    return str;
461
504
}
 
505
 
 
506
 
 
507
#ifdef SERV_Print
 
508
#  undef SERV_Print
 
509
#endif
 
510
char* SERV_Print(SERV_ITER iter)
 
511
{
 
512
    return SERV_PrintEx(iter, 0);
 
513
}
 
514
 
 
515
 
 
516
/*
 
517
 * Note parameters' ranges here:
 
518
 * 0.0 <= pref <= 1.0
 
519
 * 0.0 <  gap  <= 1.0
 
520
 * n >= 2
 
521
 * Hence, the formula below always yields a value in the range [0.0 .. 1.0].
 
522
 */
 
523
double SERV_Preference(double pref, double gap, unsigned int n)
 
524
{
 
525
    assert(0.0 <= pref && pref <= 1.0);
 
526
    assert(0.0 <  gap  && gap  <= 1.0);
 
527
    assert(n >= 2);
 
528
    if (gap >= pref)
 
529
        return gap;
 
530
    else if (gap >= 0.75*(1.0/(double) n))
 
531
        return pref;
 
532
    else
 
533
        return 2.5*gap*pref;
 
534
}
 
535
 
 
536
 
 
537
/*
 
538
 * --------------------------------------------------------------------------
 
539
 * $Log: ncbi_service.c,v $
 
540
 * Revision 6.55  2004/08/19 15:48:35  lavr
 
541
 * SERV_ITER::type renamed into SERV_ITER::types to reflect its bitmask nature
 
542
 *
 
543
 * Revision 6.54  2004/07/01 16:28:19  lavr
 
544
 * +SERV_PrintEx(): "Referer:" tag impelemented
 
545
 *
 
546
 * Revision 6.53  2004/06/14 16:37:09  lavr
 
547
 * Allow no more than one firewall server info in the skip list
 
548
 *
 
549
 * Revision 6.52  2004/05/17 18:19:43  lavr
 
550
 * Mark skip infos with maximal time instead of calculating 1 year from now
 
551
 *
 
552
 * Revision 6.51  2004/03/23 02:28:21  lavr
 
553
 * Limit service name resolution recursion by 8
 
554
 *
 
555
 * Revision 6.50  2004/01/30 14:37:26  lavr
 
556
 * Client revision made independent of CVS revisions
 
557
 *
 
558
 * Revision 6.49  2003/09/02 21:17:15  lavr
 
559
 * Clean up included headers
 
560
 *
 
561
 * Revision 6.48  2003/06/26 15:20:46  lavr
 
562
 * Additional parameter "external" in implementation of generic methods
 
563
 *
 
564
 * Revision 6.47  2003/06/09 19:53:01  lavr
 
565
 * +SERV_OpenP()
 
566
 *
 
567
 * Revision 6.46  2003/04/30 17:00:47  lavr
 
568
 * Name collision resolved
 
569
 *
 
570
 * Revision 6.45  2003/02/28 14:49:04  lavr
 
571
 * SERV_Preference(): redeclare last argument 'unsigned'
 
572
 *
 
573
 * Revision 6.44  2003/02/13 22:04:16  lavr
 
574
 * Document SERV_Preference() domain, change last argument, tweak formula
 
575
 *
 
576
 * Revision 6.43  2003/01/31 21:19:30  lavr
 
577
 * +SERV_GetInfoP(), preference measure for preferred host, SERV_Preference()
 
578
 *
 
579
 * Revision 6.42  2002/11/12 05:53:01  lavr
 
580
 * Fit a long line within 80 chars
 
581
 *
 
582
 * Revision 6.41  2002/10/28 20:16:00  lavr
 
583
 * Take advantage of host info API
 
584
 *
 
585
 * Revision 6.40  2002/10/28 15:43:49  lavr
 
586
 * Use "ncbi_ansi_ext.h" privately and use strncpy0()
 
587
 *
 
588
 * Revision 6.39  2002/10/11 19:48:10  lavr
 
589
 * +SERV_GetConfig()
 
590
 * const dropped in return value of SERV_ServiceName()
 
591
 *
 
592
 * Revision 6.38  2002/09/04 15:11:41  lavr
 
593
 * Log moved to end
 
594
 *
 
595
 * Revision 6.37  2002/05/06 19:16:50  lavr
 
596
 * +#include <stdio.h>, +SERV_ServiceName() - translation of service name
 
597
 *
 
598
 * Revision 6.36  2002/04/15 20:07:09  lavr
 
599
 * Use size_t for iterating over skip_info's
 
600
 *
 
601
 * Revision 6.35  2002/04/13 06:35:11  lavr
 
602
 * Fast track routine SERV_GetInfoEx(), many syscalls optimizations
 
603
 *
 
604
 * Revision 6.34  2002/03/22 19:51:28  lavr
 
605
 * Do not explicitly include <assert.h>: included from ncbi_core.h
 
606
 *
 
607
 * Revision 6.33  2002/03/11 21:59:32  lavr
 
608
 * 'Client version' changed into 'Client revision'
 
609
 *
 
610
 * Revision 6.32  2001/11/09 20:03:14  lavr
 
611
 * Minor fix to remove a trailing space in client version tag
 
612
 *
 
613
 * Revision 6.31  2001/10/01 19:52:38  lavr
 
614
 * Call update directly; do not remove time from server specs in SERV_Print()
 
615
 *
 
616
 * Revision 6.30  2001/09/29 19:33:04  lavr
 
617
 * BUGFIX: SERV_Update() requires VT bound (was not the case in constructor)
 
618
 *
 
619
 * Revision 6.29  2001/09/28 22:03:12  vakatov
 
620
 * Included missing <connect/ncbi_ansi_ext.h>
 
621
 *
 
622
 * Revision 6.28  2001/09/28 20:50:16  lavr
 
623
 * SERV_Update() modified to capture Used-Server-Info tags;
 
624
 * Update VT method changed - now called on per-line basis;
 
625
 * Few bugfixes related to keeping last info correct
 
626
 *
 
627
 * Revision 6.27  2001/09/24 20:28:48  lavr
 
628
 * +SERV_Reset(); SERV_Close() changed to utilize SERV_Reset()
 
629
 *
 
630
 * Revision 6.26  2001/09/10 21:19:48  lavr
 
631
 * SERV_Print():  Client version tag added
 
632
 * SERV_OpenEx(): Firewall type handling
 
633
 *
 
634
 * Revision 6.25  2001/08/20 21:58:19  lavr
 
635
 * Parameter change for clarity: info -> net_info if type is SConnNetInfo
 
636
 *
 
637
 * Revision 6.24  2001/06/25 15:35:54  lavr
 
638
 * Added function: SERV_GetNextInfoEx
 
639
 *
 
640
 * Revision 6.23  2001/06/20 17:27:49  kans
 
641
 * include <time.h> for Mac compiler
 
642
 *
 
643
 * Revision 6.22  2001/06/19 19:12:01  lavr
 
644
 * Type change: size_t -> TNCBI_Size; time_t -> TNCBI_Time
 
645
 *
 
646
 * Revision 6.21  2001/05/24 21:28:12  lavr
 
647
 * Timeout for skip servers increased to 1 year period
 
648
 *
 
649
 * Revision 6.20  2001/05/17 15:02:51  lavr
 
650
 * Typos corrected
 
651
 *
 
652
 * Revision 6.19  2001/04/24 21:37:26  lavr
 
653
 * New code for: SERV_MapperName() and SERV_Penalize().
 
654
 *
 
655
 * Revision 6.18  2001/03/21 21:23:30  lavr
 
656
 * Explicit type conversion size_t -> unsigned in printf
 
657
 *
 
658
 * Revision 6.17  2001/03/20 22:03:32  lavr
 
659
 * BUGFIX in SERV_Print (miscalculation of buflen for accepted server types)
 
660
 *
 
661
 * Revision 6.16  2001/03/06 23:55:25  lavr
 
662
 * SOCK_gethostaddr -> SOCK_gethostbyname
 
663
 *
 
664
 * Revision 6.15  2001/03/05 23:10:29  lavr
 
665
 * SERV_WriteInfo takes only one argument now
 
666
 *
 
667
 * Revision 6.14  2001/03/02 20:09:51  lavr
 
668
 * Support added for SERV_LOCALHOST as preferred_host.
 
669
 *
 
670
 * Revision 6.13  2001/03/01 00:31:23  lavr
 
671
 * SERV_OpenSimple now builds SConnNetInfo to use both LBSMD and DISPD.CGI
 
672
 *
 
673
 * Revision 6.12  2001/02/09 17:33:06  lavr
 
674
 * Modified: fSERV_StatelessOnly overrides info->stateless
 
675
 *
 
676
 * Revision 6.11  2001/01/25 17:05:32  lavr
 
677
 * Bugfix in SERV_OpenEx: op was not inited to 0
 
678
 *
 
679
 * Revision 6.10  2001/01/08 23:47:29  lavr
 
680
 * (unsigned char) conversion in isspace
 
681
 *
 
682
 * Revision 6.9  2001/01/08 22:38:34  lavr
 
683
 * Numerous patches to code after debugging
 
684
 *
 
685
 * Revision 6.8  2000/12/29 18:01:27  lavr
 
686
 * SERV_Print introduced; pool of skipped services now follows
 
687
 * expiration times of services and is updated on that basis.
 
688
 *
 
689
 * Revision 6.7  2000/12/06 22:20:30  lavr
 
690
 * Skip info list is not maintained forever; instead the entries get
 
691
 * deleted in accordance with their expiration period
 
692
 *
 
693
 * Revision 6.6  2000/10/20 17:19:04  lavr
 
694
 * SConnNetInfo made 'const' as a parameter to 'SERV_Open*'
 
695
 * 'SERV_Update' added as a private interface
 
696
 *
 
697
 * Revision 6.5  2000/10/05 22:36:21  lavr
 
698
 * Additional parameters in call to DISPD mapper
 
699
 *
 
700
 * Revision 6.4  2000/05/31 23:12:23  lavr
 
701
 * First try to assemble things together to get working service mapper
 
702
 *
 
703
 * Revision 6.3  2000/05/22 16:53:11  lavr
 
704
 * Rename service_info -> server_info everywhere (including
 
705
 * file names) as the latter name is more relevant
 
706
 *
 
707
 * Revision 6.2  2000/05/12 21:42:59  lavr
 
708
 * Cleaned up for the C++ compilation, etc.
 
709
 *
 
710
 * Revision 6.1  2000/05/12 18:50:20  lavr
 
711
 * First working revision
 
712
 *
 
713
 * ==========================================================================
 
714
 */