~ubuntu-branches/ubuntu/edgy/ncbi-tools6/edgy

« back to all changes in this revision

Viewing changes to connect/ncbi_dispd.c

  • Committer: Bazaar Package Importer
  • Author(s): Barry deFreese
  • Date: 2006-07-19 23:28:07 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20060719232807-et3cdmcjgmnyleyx
Tags: 6.1.20060507-3ubuntu1
Re-merge with Debian

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  $Id: ncbi_dispd.c,v 6.68 2005/07/11 18:23:14 lavr Exp $
 
1
/*  $Id: ncbi_dispd.c,v 6.79 2006/04/05 14:59:32 lavr Exp $
2
2
 * ===========================================================================
3
3
 *
4
4
 *                            PUBLIC DOMAIN NOTICE
34
34
#include "ncbi_ansi_ext.h"
35
35
#include "ncbi_comm.h"
36
36
#include "ncbi_dispd.h"
 
37
#include "ncbi_lb.h"
37
38
#include "ncbi_priv.h"
38
39
#include <connect/ncbi_connection.h>
39
40
#include <connect/ncbi_http_connector.h>
40
 
#include <connect/ncbi_service_misc.h>
41
41
#include <ctype.h>
42
42
#include <stdio.h>
43
43
#include <stdlib.h>
44
 
#include <time.h>
45
 
 
46
 
#if 0/*defined(_DEBUG) && !defined(NDEBUG)*/
47
 
#  define SERV_DISPD_DEBUG 1
48
 
#endif /*_DEBUG && !NDEBUG*/
49
44
 
50
45
/* Lower bound of up-to-date/out-of-date ratio */
51
46
#define SERV_DISPD_STALE_RATIO_OK  0.8
52
 
/* Default rate increase if svc runs locally */
 
47
/* Default rate increase 20% if svc runs locally */
53
48
#define SERV_DISPD_LOCAL_SVC_BONUS 1.2
54
49
 
55
50
 
56
 
/* Dispatcher messaging support */
57
 
static int               s_MessageIssued = 0;
58
 
static FDISP_MessageHook s_MessageHook = 0;
59
 
 
60
 
 
61
51
#ifdef __cplusplus
62
52
extern "C" {
63
53
#endif /*__cplusplus*/
64
54
    static void        s_Reset      (SERV_ITER);
65
55
    static SSERV_Info* s_GetNextInfo(SERV_ITER, HOST_INFO*);
66
 
    static int/*bool*/ s_Update     (SERV_ITER, TNCBI_Time, const char*);
 
56
    static int/*bool*/ s_Update     (SERV_ITER, const char*, int);
67
57
    static void        s_Close      (SERV_ITER);
68
58
 
69
59
    static const SSERV_VTable s_op = {
74
64
#endif /*__cplusplus*/
75
65
 
76
66
 
77
 
int g_NCBIConnectRandomSeed = 0;
78
 
 
79
 
 
80
 
typedef struct {
81
 
    SSERV_Info*   info;
82
 
    double        status;
83
 
} SDISPD_Node;
84
 
 
85
 
 
86
 
typedef struct {
87
 
    int/*bool*/   disp_fail;
88
 
    SConnNetInfo* net_info;
89
 
    SDISPD_Node*  s_node;
90
 
    size_t        n_node;
91
 
    size_t        a_node;
92
 
    const char*   name;
93
 
} SDISPD_Data;
94
 
 
95
 
 
96
 
static int/*bool*/ s_AddServerInfo(SDISPD_Data* data, SSERV_Info* info)
 
67
struct SDISPD_Data {
 
68
    int/*bool*/    disp_fail;
 
69
    SConnNetInfo*  net_info;
 
70
    SLB_Candidate* cand;
 
71
    size_t         n_cand;
 
72
    size_t         a_cand;
 
73
};
 
74
 
 
75
 
 
76
static int/*bool*/ s_AddServerInfo(struct SDISPD_Data* data, SSERV_Info* info)
97
77
{
98
78
    size_t i;
99
 
 
 
79
    const char* name = SERV_NameOfInfo(info);
100
80
    /* First check that the new server info updates an existing one */
101
 
    for (i = 0; i < data->n_node; i++) {
102
 
        if (SERV_EqualInfo(data->s_node[i].info, info)) {
 
81
    for (i = 0; i < data->n_cand; i++) {
 
82
        if (strcasecmp(name, SERV_NameOfInfo(data->cand[i].info))
 
83
            &&  SERV_EqualInfo(info, data->cand[i].info)) {
103
84
            /* Replace older version */
104
 
            free(data->s_node[i].info);
105
 
            data->s_node[i].info = info;
 
85
            free((void*) data->cand[i].info);
 
86
            data->cand[i].info = info;
106
87
            return 1;
107
88
        }
108
89
    }
109
 
 
110
90
    /* Next, add new service to the list */
111
 
    if (data->n_node == data->a_node) {
112
 
        size_t n = data->a_node + 10;
113
 
        SDISPD_Node* temp;
114
 
 
115
 
        if (data->s_node)
116
 
            temp = (SDISPD_Node*) realloc(data->s_node, sizeof(*temp) * n);
117
 
        else
118
 
            temp = (SDISPD_Node*) malloc(sizeof(*temp) * n);
 
91
    if (data->n_cand == data->a_cand) {
 
92
        size_t n = data->a_cand + 10;
 
93
        SLB_Candidate* temp = (SLB_Candidate*)
 
94
            (data->cand
 
95
             ? realloc(data->cand, n * sizeof(*temp))
 
96
             : malloc (            n * sizeof(*temp)));
119
97
        if (!temp)
120
98
            return 0;
121
 
 
122
 
        data->s_node = temp;
123
 
        data->a_node = n;
 
99
        data->cand = temp;
 
100
        data->a_cand = n;
124
101
    }
125
 
 
126
 
    data->s_node[data->n_node++].info = info;
 
102
    data->cand[data->n_cand++].info = info;
127
103
    return 1;
128
104
}
129
105
 
134
110
}
135
111
#endif /* __cplusplus */
136
112
 
137
 
/*ARGSUSED*/
138
 
static int/*bool*/ s_ParseHeader(const char* header, void *iter,
139
 
                                 int/*ignored*/ server_error)
 
113
static int/*bool*/ s_ParseHeader(const char* header,
 
114
                                 void*       iter,
 
115
                                 int         server_error)
140
116
{
141
 
    SERV_Update((SERV_ITER) iter, header);
 
117
    SERV_Update((SERV_ITER) iter, header, server_error);
142
118
    return 1/*header parsed okay*/;
143
119
}
144
120
 
155
131
                            void*         iter,
156
132
                            unsigned int  n)
157
133
{
158
 
    SDISPD_Data* data = (SDISPD_Data*)((SERV_ITER) iter)->data;
 
134
    struct SDISPD_Data* data = (struct SDISPD_Data*)((SERV_ITER) iter)->data;
159
135
    return data->disp_fail ? 0/*failed*/ : 1/*try again*/;
160
136
}
161
137
 
162
138
 
163
139
static int/*bool*/ s_Resolve(SERV_ITER iter)
164
140
{
165
 
    static const char service[]  = "service";
166
 
    static const char address[]  = "address";
167
 
    static const char platform[] = "platform";
168
 
    SDISPD_Data* data = (SDISPD_Data*) iter->data;
169
 
    SConnNetInfo *net_info = data->net_info;
 
141
    struct SDISPD_Data* data = (struct SDISPD_Data*) iter->data;
 
142
    SConnNetInfo* net_info = data->net_info;
170
143
    CONNECTOR conn = 0;
171
 
    const char *arch;
172
 
    unsigned int ip;
173
 
    char addr[64];
174
144
    char* s;
175
145
    CONN c;
176
146
 
177
 
    /* Dispatcher CGI arguments (sacrifice some if they all do not fit) */
178
 
    if ((arch = CORE_GetPlatform()) != 0 && *arch)
179
 
        ConnNetInfo_PreOverrideArg(net_info, platform, arch);
180
 
    if (*net_info->client_host && !strchr(net_info->client_host, '.') &&
181
 
        (ip = SOCK_gethostbyname(net_info->client_host)) != 0 &&
182
 
        SOCK_ntoa(ip, addr, sizeof(addr)) == 0) {
183
 
        if ((s = (char*) malloc(strlen(net_info->client_host) +
184
 
                                strlen(addr) + 3)) != 0) {
185
 
            sprintf(s, "%s(%s)", net_info->client_host, addr);
186
 
        } else
187
 
            s = net_info->client_host;
188
 
    } else
189
 
        s = net_info->client_host;
190
 
    if (s && *s)
191
 
        ConnNetInfo_PreOverrideArg(net_info, address, s);
192
 
    if (s != net_info->client_host)
193
 
        free(s);
194
 
    if (!ConnNetInfo_PreOverrideArg(net_info, service, iter->name)) {
195
 
        ConnNetInfo_DeleteArg(net_info, platform);
196
 
        if (!ConnNetInfo_PreOverrideArg(net_info, service, iter->name)) {
197
 
            ConnNetInfo_DeleteArg(net_info, address);
198
 
            if (!ConnNetInfo_PreOverrideArg(net_info, service, iter->name))
199
 
                return 0/*failed*/;
200
 
        }
201
 
    }
202
 
    /* Reset request method to be GET ('cause no HTTP body will follow) */
203
 
    net_info->req_method = eReqMethod_Get;
 
147
    assert(!!net_info->stateless == !!iter->stateless);
204
148
    /* Obtain additional header information */
205
149
    if ((!(s = SERV_Print(iter, 0))
206
 
         || ConnNetInfo_OverrideUserHeader(net_info, s))                     &&
207
 
        ConnNetInfo_OverrideUserHeader(net_info, net_info->stateless
208
 
                                       ?"Client-Mode: STATELESS_ONLY\r\n"
209
 
                                       :"Client-Mode: STATEFUL_CAPABLE\r\n") &&
210
 
        ConnNetInfo_OverrideUserHeader(net_info,
211
 
                                       "Dispatch-Mode: INFORMATION_ONLY\r\n")){
212
 
        ConnNetInfo_OverrideUserHeader
213
 
            (net_info, "User-Agent: NCBIServiceDispatcher/"
214
 
             DISP_PROTOCOL_VERSION
215
 
#ifdef NCBI_CXX_TOOLKIT
216
 
             " (C++ Toolkit)"
217
 
#else
218
 
             " (C Toolkit)"
219
 
#endif /*NCBI_CXX_TOOLKIT*/
220
 
             "\r\n");
 
150
         || ConnNetInfo_OverrideUserHeader(net_info, s))                    &&
 
151
        ConnNetInfo_OverrideUserHeader(net_info, !iter->promiscuous
 
152
                                       ? "Dispatch-Mode: INFORMATION_ONLY\r\n"
 
153
                                       : "Dispatch-Mode: PROMISCUOUS\r\n")  &&
 
154
        ConnNetInfo_OverrideUserHeader(net_info, iter->reverse_dns
 
155
                                       ? "Client-Mode: REVERSE_DNS\r\n"
 
156
                                       : !net_info->stateless
 
157
                                       ? "Client-Mode: STATEFUL_CAPABLE\r\n"
 
158
                                       : "Client-Mode: STATELESS_ONLY\r\n")) {
 
159
        /* all the rest in the net_info structure should be already fine */
221
160
        data->disp_fail = 0;
222
 
        /* All the rest in the net_info structure is fine with us */
223
161
        conn = HTTP_CreateConnectorEx(net_info, fHCC_SureFlush, s_ParseHeader,
224
162
                                      s_Adjust, iter/*data*/, 0/*cleanup*/);
225
163
    }
236
174
    /* This will also send all the HTTP data, and trigger header callback */
237
175
    CONN_Flush(c);
238
176
    CONN_Close(c);
239
 
    return ((SDISPD_Data*) iter->data)->n_node != 0;
 
177
    return data->n_cand != 0  ||
 
178
        (!data->disp_fail  &&  net_info->stateless  &&  net_info->firewall);
240
179
}
241
180
 
242
181
 
243
 
static int/*bool*/ s_Update(SERV_ITER iter, TNCBI_Time now, const char* text)
 
182
static int/*bool*/ s_Update(SERV_ITER iter, const char* text, int code)
244
183
{
245
 
    static const char service_name[] = "Service: ";
246
184
    static const char server_info[] = "Server-Info-";
247
 
    SDISPD_Data* data = (SDISPD_Data*) iter->data;
248
 
    size_t len = strlen(text);
 
185
    struct SDISPD_Data* data = (struct SDISPD_Data*) iter->data;
 
186
    int/*bool*/ failure;
249
187
 
250
 
    if (len >= sizeof(service_name)  &&
251
 
        strncasecmp(text, service_name, sizeof(service_name) - 1) == 0) {
252
 
        if (iter->mask) {
253
 
            if (data->name)
254
 
                free((void*) data->name);
255
 
            text += sizeof(service_name) - 1;
256
 
            while (*text  &&  isspace((unsigned char)(*text)))
257
 
                text++;
258
 
            data->name = strdup(text);
259
 
        }
260
 
    } else if (len >= sizeof(server_info) &&
261
 
        strncasecmp(text, server_info, sizeof(server_info) - 1) == 0) {
262
 
        const char* name = data->name ? data->name : "";
 
188
    if (code == 400)
 
189
        data->disp_fail = 1;
 
190
    if (strncasecmp(text, server_info, sizeof(server_info) - 1) == 0) {
 
191
        const char* name;
263
192
        SSERV_Info* info;
264
193
        unsigned int d1;
 
194
        char* s;
265
195
        int d2;
266
196
 
267
197
        text += sizeof(server_info) - 1;
268
 
        if (sscanf(text, "%u: %n", &d1, &d2) < 1)
 
198
        if (sscanf(text, "%u: %n", &d1, &d2) < 1  ||  d1 < 1)
269
199
            return 0/*not updated*/;
270
 
        info = SERV_ReadInfoEx(text + d2, strlen(name) + 1);
 
200
        if (iter->ismask  ||  iter->reverse_dns) {
 
201
            char* c;
 
202
            if (!(s = strdup(text + d2)))
 
203
                return 0/*not updated*/;
 
204
            name = s;
 
205
            while (*name  &&  isspace((unsigned char)(*name)))
 
206
                name++;
 
207
            if (!*name) {
 
208
                free(s);
 
209
                return 0/*not updated*/;
 
210
            }
 
211
            for (c = s + (name - s);  *c;  c++) {
 
212
                if (isspace((unsigned char)(*c)))
 
213
                    break;
 
214
            }
 
215
            *c++ = '\0';
 
216
            d2 += (int)(c - s);
 
217
        } else {
 
218
            s = 0;
 
219
            name = "";
 
220
        }
 
221
        info = SERV_ReadInfoEx(text + d2, name);
 
222
        if (s)
 
223
            free(s);
271
224
        if (info) {
272
 
            assert(info->rate != 0.0);
273
 
            info->time += now; /* expiration time now */
274
 
            strcpy((char*) info + SERV_SizeOfInfo(info), name);
 
225
            if (info->time != NCBI_TIME_INFINITE)
 
226
                info->time += iter->time; /* expiration time now */
275
227
            if (s_AddServerInfo(data, info))
276
228
                return 1/*updated*/;
277
229
            free(info);
278
230
        }
279
 
    } else if (len >= sizeof(HTTP_DISP_FAILURES) &&
280
 
               strncasecmp(text, HTTP_DISP_FAILURES,
281
 
                           sizeof(HTTP_DISP_FAILURES) - 1) == 0) {
 
231
    } else if (((failure = strncasecmp(text, HTTP_DISP_FAILURES,
 
232
                                       sizeof(HTTP_DISP_FAILURES) - 1) == 0)
 
233
                ||  strncasecmp(text, HTTP_DISP_MESSAGES,
 
234
                                sizeof(HTTP_DISP_MESSAGES) - 1) == 0)) {
 
235
        assert(sizeof(HTTP_DISP_FAILURES) == sizeof(HTTP_DISP_MESSAGES));
282
236
#if defined(_DEBUG) && !defined(NDEBUG)
283
 
        text += sizeof(HTTP_DISP_FAILURES) - 1;
284
 
        while (*text  &&  isspace((unsigned char)(*text)))
285
 
            text++;
286
 
        if (data->net_info->debug_printout)
287
 
            CORE_LOGF(eLOG_Warning, ("[DISPATCHER]  %s", text));
 
237
        if (data->net_info->debug_printout) {
 
238
            text += sizeof(HTTP_DISP_FAILURES) - 1;
 
239
            while (*text  &&  isspace((unsigned char)(*text)))
 
240
                text++;
 
241
            CORE_LOGF(eLOG_Warning, ("[DISPATCHER %s]  %s",
 
242
                                     failure ? "FAILURE" : "MESSAGE", text));
 
243
        }
288
244
#endif /*_DEBUG && !NDEBUG*/
289
 
        data->disp_fail = 1;
 
245
        if (failure)
 
246
            data->disp_fail = 1;
290
247
        return 1/*updated*/;
291
 
    } else if (len >= sizeof(HTTP_DISP_MESSAGE) &&
292
 
               strncasecmp(text, HTTP_DISP_MESSAGE,
293
 
                           sizeof(HTTP_DISP_MESSAGE) - 1) == 0) {
294
 
        text += sizeof(HTTP_DISP_MESSAGE) - 1;
295
 
        while (*text  &&  isspace((unsigned char)(*text)))
296
 
            text++;
297
 
        if (s_MessageHook) {
298
 
            if (s_MessageIssued <= 0) {
299
 
                s_MessageIssued = 1;
300
 
                s_MessageHook(text);
301
 
            }
302
 
        } else {
303
 
            s_MessageIssued = -1;
304
 
            CORE_LOGF(eLOG_Warning, ("[DISPATCHER]  %s", text));
305
 
        }
306
248
    }
307
249
 
308
250
    return 0/*not updated*/;
309
251
}
310
252
 
311
253
 
312
 
static int/*bool*/ s_IsUpdateNeeded(SDISPD_Data *data)
 
254
static int/*bool*/ s_IsUpdateNeeded(TNCBI_Time now, struct SDISPD_Data *data)
313
255
{
314
256
    double status = 0.0, total = 0.0;
315
257
 
316
 
    if (data->n_node) {
317
 
        TNCBI_Time t = (TNCBI_Time) time(0);
 
258
    if (data->n_cand) {
318
259
        size_t i = 0;
319
 
        while (i < data->n_node) {
320
 
            SSERV_Info* info = data->s_node[i].info;
 
260
        while (i < data->n_cand) {
 
261
            const SSERV_Info* info = data->cand[i].info;
321
262
 
322
263
            total += info->rate;
323
 
            if (info->time < t) {
324
 
                if (i < --data->n_node)
325
 
                    memmove(data->s_node + i, data->s_node + i + 1,
326
 
                            (data->n_node - i)*sizeof(*data->s_node));
327
 
                free(info);
 
264
            if (info->time < now) {
 
265
                if (i < --data->n_cand) {
 
266
                    memmove(data->cand + i, data->cand + i + 1,
 
267
                            sizeof(*data->cand)*(data->n_cand - i));
 
268
                }
 
269
                free((void*) info);
328
270
            } else {
329
271
                status += info->rate;
330
272
                i++;
332
274
        }
333
275
    }
334
276
 
335
 
    return total == 0.0 ? 1 : (status/total < SERV_DISPD_STALE_RATIO_OK);
 
277
    return total == 0.0 ? 1 : status/total < SERV_DISPD_STALE_RATIO_OK;
 
278
}
 
279
 
 
280
 
 
281
static SLB_Candidate* s_GetCandidate(void* user_data, size_t n)
 
282
{
 
283
    struct SDISPD_Data* data = (struct SDISPD_Data*) user_data;
 
284
    return n < data->n_cand ? &data->cand[n] : 0;
336
285
}
337
286
 
338
287
 
339
288
static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info)
340
289
{
341
 
    double total = 0.0, point = 0.0, access = 0.0, p = 0.0, status;
342
 
    SDISPD_Data* data = (SDISPD_Data*) iter->data;
 
290
    struct SDISPD_Data* data = (struct SDISPD_Data*) iter->data;
343
291
    SSERV_Info* info;
344
 
    size_t i;
345
 
 
346
 
    if (!data)
347
 
        return 0;
348
 
 
349
 
    if (s_IsUpdateNeeded(data) && !s_Resolve(iter))
350
 
        return 0;
351
 
    assert(data->n_node != 0);
352
 
 
353
 
    for (i = 0; i < data->n_node; i++) {
354
 
        info = data->s_node[i].info;
355
 
        status = info->rate;
356
 
        assert(status != 0.0);
357
 
 
358
 
        if (iter->host == info->host  ||
359
 
            (!iter->host  &&
360
 
             info->locl  &&  info->coef < 0.0)) {
361
 
            if (iter->pref  ||  info->coef <= 0.0) {
362
 
                status *= SERV_DISPD_LOCAL_SVC_BONUS;
363
 
                if (access < status &&
364
 
                    (iter->pref  ||  info->coef < 0.0)) {
365
 
                    access =  status;
366
 
                    point  =  total + status; /* Latch this local server */
367
 
                    p      = -info->coef;
368
 
                    assert(point > 0.0);
369
 
                }
370
 
            } else
371
 
                status *= info->coef;
372
 
        }
373
 
        total                 += status;
374
 
        data->s_node[i].status = total;
375
 
    }
376
 
 
377
 
    if (point > 0.0  &&  iter->pref) {
378
 
        if (total != access) {
379
 
            p = SERV_Preference(iter->pref, access/total, data->n_node);
380
 
#ifdef SERV_DISPD_DEBUG
381
 
            CORE_LOGF(eLOG_Note, ("(P = %lf, A = %lf, T = %lf, N = %d)"
382
 
                                  " -> Pref = %lf", iter->pref,
383
 
                                  access, total, (int) data->n_node, p));
384
 
#endif /*SERV_DISPD_DEBUG*/
385
 
            status = total*p;
386
 
            p = total*(1.0 - p)/(total - access);
387
 
            for (i = 0; i < data->n_node; i++) {
388
 
                data->s_node[i].status *= p;
389
 
                if (p*point <= data->s_node[i].status) 
390
 
                    data->s_node[i].status += status - p*access;
391
 
            }
392
 
#ifdef SERV_DISPD_DEBUG
393
 
            for (i = 0; i < data->n_node; i++) {
394
 
                char addr[16];
395
 
                SOCK_ntoa(data->s_node[i].info->host, addr, sizeof(addr));
396
 
                status = data->s_node[i].status -
397
 
                    (i ? data->s_node[i-1].status : 0.0);
398
 
                CORE_LOGF(eLOG_Note, ("%s %lf %.2lf%%", addr,
399
 
                                      status, status/total*100.0));
400
 
            }
401
 
#endif /*SERV_DISPD_DEBUG*/
402
 
        }
403
 
        point = -1.0;
404
 
    }
405
 
 
406
 
    /* We take pre-chosen local server only if its status is not less than
407
 
       p% of the average remaining status; otherwise, we ignore the server,
408
 
       and apply the generic procedure by seeding a random point. */
409
 
    if (point <= 0.0 || access*(data->n_node - 1) < p*0.01*(total - access))
410
 
        point = (total * rand()) / (double) RAND_MAX;
411
 
    for (i = 0; i < data->n_node; i++) {
412
 
        if (point <= data->s_node[i].status)
413
 
            break;
414
 
    }
415
 
    assert(i < data->n_node);
416
 
 
417
 
    info = data->s_node[i].info;
418
 
    info->rate = data->s_node[i].status - (i ? data->s_node[i-1].status : 0.0);
419
 
    if (i < --data->n_node) {
420
 
        memmove(data->s_node + i, data->s_node + i + 1,
421
 
                (data->n_node - i)*sizeof(*data->s_node));
422
 
    }
 
292
    size_t n;
 
293
 
 
294
    assert(data);
 
295
    if (s_IsUpdateNeeded(iter->time, data)  &&
 
296
        (!s_Resolve(iter)  ||  !data->n_cand)) {
 
297
        return 0;
 
298
    }
 
299
 
 
300
    for (n = 0; n < data->n_cand; n++)
 
301
        data->cand[n].status = data->cand[n].info->rate;
 
302
    n = LB_Select(iter, data, s_GetCandidate, SERV_DISPD_LOCAL_SVC_BONUS);
 
303
    info = (SSERV_Info*) data->cand[n].info;
 
304
    info->rate = data->cand[n].status;
 
305
    if (n < --data->n_cand) {
 
306
        memmove(data->cand + n, data->cand + n + 1,
 
307
                (data->n_cand - n) * sizeof(*data->cand));
 
308
    }
 
309
 
423
310
    if (host_info)
424
311
        *host_info = 0;
425
312
 
429
316
 
430
317
static void s_Reset(SERV_ITER iter)
431
318
{
432
 
    SDISPD_Data* data = (SDISPD_Data*) iter->data;
433
 
    if (data && data->s_node) {
 
319
    struct SDISPD_Data* data = (struct SDISPD_Data*) iter->data;
 
320
    if (data  &&  data->cand) {
434
321
        size_t i;
435
 
        assert(data->a_node);
436
 
        for (i = 0; i < data->n_node; i++)
437
 
            free(data->s_node[i].info);
438
 
        data->n_node = 0;
439
 
        if (data->name) {
440
 
            free((void*) data->name);
441
 
            data->name = 0;
442
 
        }
 
322
        assert(data->a_cand);
 
323
        for (i = 0; i < data->n_cand; i++)
 
324
            free((void*) data->cand[i].info);
 
325
        data->n_cand = 0;
443
326
    }
444
327
}
445
328
 
446
329
 
447
330
static void s_Close(SERV_ITER iter)
448
331
{
449
 
    SDISPD_Data* data = (SDISPD_Data*) iter->data;
450
 
    assert(!data->n_node && !data->name);/*s_Reset() had to be called before */
451
 
    if (data->s_node)
452
 
        free(data->s_node);
 
332
    struct SDISPD_Data* data = (struct SDISPD_Data*) iter->data;
 
333
    assert(!data->n_cand); /* s_Reset() had to be called before */
 
334
    if (data->cand)
 
335
        free(data->cand);
453
336
    ConnNetInfo_Destroy(data->net_info);
454
337
    free(data);
455
338
    iter->data = 0;
465
348
                                    const SConnNetInfo* net_info,
466
349
                                    SSERV_Info** info, HOST_INFO* u/*unused*/)
467
350
{
468
 
    SDISPD_Data* data;
469
 
 
470
 
    if (!(data = (SDISPD_Data*) calloc(1, sizeof(*data))))
471
 
        return 0;
472
 
    if (g_NCBI_ConnectRandomSeed == 0) {
473
 
        g_NCBI_ConnectRandomSeed = (int) time(0) ^ NCBI_CONNECT_SRAND_ADDEND;
474
 
        srand(g_NCBI_ConnectRandomSeed);
 
351
    struct SDISPD_Data* data;
 
352
 
 
353
    if (!iter->ismask  &&  strpbrk(iter->name, "?*"))
 
354
        return 0/*failed to start unallowed wildcard search*/;
 
355
 
 
356
    if (!(data = (struct SDISPD_Data*) calloc(1, sizeof(*data))))
 
357
        return 0;
 
358
 
 
359
    assert(net_info); /*must called with non-NULL*/
 
360
    if ((data->net_info = ConnNetInfo_Clone(net_info)) != 0)
 
361
        data->net_info->service = iter->name; /* SetupStandardArgs() expects */
 
362
    if (!ConnNetInfo_SetupStandardArgs(data->net_info)) {
 
363
        ConnNetInfo_Destroy(data->net_info);
 
364
        free(data);
 
365
        return 0;
475
366
    }
476
 
    data->net_info = ConnNetInfo_Clone(net_info); /*called with non-NULL*/
477
 
    if (iter->type & fSERV_StatelessOnly)
 
367
    /* Reset request method to be GET ('cause no HTTP body is ever used) */
 
368
    data->net_info->req_method = eReqMethod_Get;
 
369
    if (iter->stateless)
478
370
        data->net_info->stateless = 1/*true*/;
479
371
    if (iter->type & fSERV_Firewall)
480
372
        data->net_info->firewall = 1/*true*/;
 
373
    ConnNetInfo_ExtendUserHeader(data->net_info,
 
374
                                 "User-Agent: NCBIServiceDispatcher/"
 
375
                                 DISP_PROTOCOL_VERSION
 
376
#ifdef NCBI_CXX_TOOLKIT
 
377
                                 " (C++ Toolkit)"
 
378
#else
 
379
                                 " (C Toolkit)"
 
380
#endif /*NCBI_CXX_TOOLKIT*/
 
381
                                 "\r\n");
481
382
    iter->data = data;
482
 
 
483
383
    iter->op = &s_op; /* SERV_Update() - from HTTP callback - expects this */
 
384
 
 
385
    if (g_NCBI_ConnectRandomSeed == 0) {
 
386
        g_NCBI_ConnectRandomSeed = iter->time ^ NCBI_CONNECT_SRAND_ADDEND;
 
387
        srand(g_NCBI_ConnectRandomSeed);
 
388
    }
 
389
 
484
390
    if (!s_Resolve(iter)) {
485
391
        iter->op = 0;
486
392
        s_Reset(iter);
488
394
        return 0;
489
395
    }
490
396
 
491
 
    /* call GetNextInfo if info is needed */
 
397
    /* call GetNextInfo subsequently if info is actually needed */
492
398
    if (info)
493
399
        *info = 0;
494
400
    return &s_op;
495
401
}
496
402
 
497
403
 
498
 
extern void DISP_SetMessageHook(FDISP_MessageHook hook)
499
 
{
500
 
    if (hook) {
501
 
        if (hook != s_MessageHook)
502
 
            s_MessageIssued = s_MessageIssued ? -1 : -2;
503
 
    } else if (s_MessageIssued < -1)
504
 
        s_MessageIssued = 0;
505
 
    s_MessageHook = hook;
506
 
}
507
 
 
508
 
 
509
404
/*
510
405
 * --------------------------------------------------------------------------
511
406
 * $Log: ncbi_dispd.c,v $
 
407
 * Revision 6.79  2006/04/05 14:59:32  lavr
 
408
 * Small fixup
 
409
 *
 
410
 * Revision 6.78  2006/03/05 17:38:12  lavr
 
411
 * Adjust for SERV_ITER to now carry time (s_Update)
 
412
 *
 
413
 * Revision 6.77  2006/02/21 14:57:59  lavr
 
414
 * Dispatcher to not require server-infos for stateless firewalled client
 
415
 *
 
416
 * Revision 6.76  2006/02/01 17:13:30  lavr
 
417
 * Remove spurious definition of g_NCBI_ConnectRandomSeed (ncbi_priv.c has it)
 
418
 *
 
419
 * Revision 6.75  2006/01/17 20:25:32  lavr
 
420
 * Handling of NCBI messages moved to HTTP connector
 
421
 * Dispatcher messages handled separately (FAILURES vs MESSAGES)
 
422
 *
 
423
 * Revision 6.74  2006/01/11 20:26:29  lavr
 
424
 * Take advantage of ConnNetInfo_SetupStandardArgs(); other related changes
 
425
 *
 
426
 * Revision 6.73  2006/01/11 16:29:17  lavr
 
427
 * Take advantage of UTIL_ClientAddress(), some other minor improvements
 
428
 *
 
429
 * Revision 6.72  2005/12/23 18:18:17  lavr
 
430
 * Rework to use newer dispatcher protocol to closely match the functionality
 
431
 * of local (LBSM shmem based) service locator.  Factoring out invariant
 
432
 * initializations/tuneups; better detection of sufficiency of client addr.
 
433
 *
 
434
 * Revision 6.71  2005/12/16 16:00:16  lavr
 
435
 * Take advantage of new generic LB API
 
436
 *
 
437
 * Revision 6.70  2005/12/14 21:33:15  lavr
 
438
 * Use new SERV_ReadInfoEx() prototype
 
439
 *
 
440
 * Revision 6.69  2005/12/08 03:52:28  lavr
 
441
 * Do not override User-Agent but extend it
 
442
 *
512
443
 * Revision 6.68  2005/07/11 18:23:14  lavr
513
444
 * Break grounds for receiving wildcard matches via HTTP header tags
514
445
 *