/[hyperestraier]/trunk/estnode.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/estnode.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Fri Jul 29 21:57:20 2005 UTC (18 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 46153 byte(s)
make working copy from version 0.5.1

1 /*************************************************************************************************
2 * Implementation of the node API
3 * Copyright (C) 2004-2005 Mikio Hirabayashi
4 * This file is part of Hyper Estraier.
5 * Hyper Estraier is free software; you can redistribute it and/or modify it under the terms of
6 * the GNU Lesser General Public License as published by the Free Software Foundation; either
7 * version 2.1 of the License or any later version. Hyper Estraier is distributed in the hope
8 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10 * License for more details.
11 * You should have received a copy of the GNU Lesser General Public License along with Hyper
12 * Estraier; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13 * Boston, MA 02111-1307 USA.
14 *************************************************************************************************/
15
16
17 #include "estraier.h"
18 #include "estmtdb.h"
19 #include "estnode.h"
20 #include "myconf.h"
21
22 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
23 #define socklen_t int
24 #define in_addr_t int
25 #elif defined(_SYS_MACOSX_)
26 #define socklen_t int
27 #endif
28
29 #define ESTNUMBUFSIZ 32 /* size of a buffer for a number */
30 #define ESTPATHBUFSIZ 4096 /* size of a buffer for a path */
31 #define ESTIOBUFSIZ 8192 /* size of a buffer for I/O */
32 #define ESTMINIBNUM 31 /* bucket number of map for attributes */
33 #define ESTLISTUNIT 64 /* allocation unit number of a list */
34 #define ESTDNHOLDSEC 300 /* holding time of domain names */
35 #define ESTDNHOLDNUM 4096 /* holding number of domain names */
36
37 typedef struct { /* type of structure for interaction of a URL */
38 int alive; /* whether to be alive */
39 pthread_cond_t *cond; /* condition variable */
40 const char *url; /* URL */
41 const char *pxhost; /* host name of proxy */
42 int pxport; /* port number of proxy */
43 const char *auth; /* authority */
44 const CBLIST *reqheads; /* request headers */
45 const char *reqbody; /* request body */
46 int rbsiz; /* size of the request body */
47 int *rescodep; /* pointer to a variable for status code */
48 CBMAP *resheads; /* response headers */
49 CBDATUM *resbody; /* response body */
50 } TARGSHUTTLE;
51
52
53 /* private function prototypes */
54 static int est_sock_close(int sock);
55 static int est_inet_aton(const char *cp, struct in_addr *inp);
56 static void *est_url_shuttle_impl(void *targ);
57 static void est_sockpt_down(void *sp);
58 static int est_node_set_inform(ESTNODE *node);
59 static void est_parse_search_header(ESTNODERES *nres, const char *str);
60 static void est_parse_search_body(ESTNODERES *nres, char *str);
61
62
63
64 /*************************************************************************************************
65 * API for the network environment
66 *************************************************************************************************/
67
68
69 /* Cache of host addresses */
70 CBMAP *est_host_addrs = NULL;
71
72
73 /* Initialize the networking environment. */
74 int est_init_net_env(void){
75 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
76 WSADATA wsaData;
77 if(est_host_addrs) return TRUE;
78 est_host_addrs = cbmapopenex(ESTDNHOLDNUM + 1);
79 return WSAStartup(MAKEWORD(2,0), &wsaData) == 0;
80 #else
81 if(est_host_addrs) return TRUE;
82 est_host_addrs = cbmapopenex(ESTDNHOLDNUM + 1);
83 return TRUE;
84 #endif
85 }
86
87
88 /* Free the networking environment. */
89 void est_free_net_env(void){
90 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
91 if(!est_host_addrs) return;
92 cbmapclose(est_host_addrs);
93 WSACleanup();
94 #else
95 if(!est_host_addrs) return;
96 cbmapclose(est_host_addrs);
97 #endif
98 }
99
100
101
102 /*************************************************************************************************
103 * API for search result of node
104 *************************************************************************************************/
105
106
107 /* Delete a node result object. */
108 void est_noderes_delete(ESTNODERES *nres){
109 int i;
110 assert(nres);
111 cbmapclose(nres->hints);
112 for(i = nres->top; i < nres->top + nres->dnum; i++){
113 free(nres->docs[i].snippet);
114 cbmapclose(nres->docs[i].attrs);
115 }
116 free(nres->docs);
117 free(nres);
118 }
119
120
121 /* Get a map object for hints of a node result object. */
122 CBMAP *est_noderes_hints(ESTNODERES *nres){
123 assert(nres);
124 return nres->hints;
125 }
126
127
128 /* Get the number of documents in a node result object. */
129 int est_noderes_doc_num(ESTNODERES *nres){
130 assert(nres);
131 return nres->dnum;
132 }
133
134
135 /* Refer a result document object in a node result object. */
136 ESTRESDOC *est_noderes_get_doc(ESTNODERES *nres, int index){
137 assert(nres && index >= 0);
138 if(index >= nres->dnum) return NULL;
139 return nres->docs + (nres->top + index);
140 }
141
142
143 /* Get the URI of a result document object. */
144 const char *est_resdoc_uri(ESTRESDOC *rdoc){
145 assert(rdoc);
146 return rdoc->uri;
147 }
148
149
150 /* Get a list of attribute names of a result document object. */
151 CBLIST *est_resdoc_attr_names(ESTRESDOC *rdoc){
152 CBLIST *names;
153 assert(rdoc);
154 names = cbmapkeys(rdoc->attrs);
155 cblistsort(names);
156 return names;
157 }
158
159
160 /* Get the value of an attribute of a result document object. */
161 const char *est_resdoc_attr(ESTRESDOC *rdoc, const char *name){
162 assert(rdoc && name);
163 return cbmapget(rdoc->attrs, name, -1, NULL);
164 }
165
166
167 /* Get the value of an attribute of a result document object. */
168 const char *est_resdoc_snippet(ESTRESDOC *rdoc){
169 assert(rdoc);
170 return rdoc->snippet;
171 }
172
173
174
175 /*************************************************************************************************
176 * API for node
177 *************************************************************************************************/
178
179
180 /* Create a node connection object. */
181 ESTNODE *est_node_new(const char *url){
182 ESTNODE *node;
183 node = cbmalloc(sizeof(ESTNODE));
184 node->url = cbmemdup(url, -1);
185 node->pxhost = NULL;
186 node->pxport = 0;
187 node->timeout = -1;
188 node->auth = NULL;
189 node->name = NULL;
190 node->label = NULL;
191 node->dnum = -1;
192 node->wnum = -1;
193 node->size = -1.0;
194 node->status = 0;
195 node->heads = cbmapopenex(ESTMINIBNUM);
196 return node;
197 }
198
199
200 /* Destroy a node connection object. */
201 void est_node_delete(ESTNODE *node){
202 assert(node);
203 cbmapclose(node->heads);
204 free(node->label);
205 free(node->name);
206 free(node->auth);
207 free(node->pxhost);
208 free(node->url);
209 free(node);
210 }
211
212
213 /* Get the status code of the last request of a node. */
214 int est_node_status(ESTNODE *node){
215 assert(node);
216 return node->status;
217 }
218
219
220 /* Set the proxy information of a node connection object. */
221 void est_node_set_proxy(ESTNODE *node, const char *host, int port){
222 assert(node && host && port >= 0);
223 free(node->pxhost);
224 node->pxhost = cbmemdup(host, -1);
225 node->pxport = port;
226 }
227
228
229 /* Set timeout of a connection. */
230 void est_node_set_timeout(ESTNODE *node, int sec){
231 assert(node && sec >= 0);
232 node->timeout = sec;
233 }
234
235
236 /* Set the authoririty information of a node connection object. */
237 void est_node_set_auth(ESTNODE *node, const char *name, const char *passwd){
238 assert(node && name && passwd);
239 free(node->auth);
240 node->auth = cbsprintf("%s:%s", name, passwd);
241 }
242
243
244 /* Add a document to a node. */
245 int est_node_put_doc(ESTNODE *node, ESTDOC *doc){
246 CBLIST *reqheads;
247 const char *kbuf;
248 char url[ESTPATHBUFSIZ], *vbuf, *reqbody;
249 int rescode, err, ksiz;
250 assert(node && doc);
251 err = FALSE;
252 sprintf(url, "%s/put_doc", node->url);
253 reqheads = cblistopen();
254 if(cbmaprnum(node->heads) > 0){
255 cbmapiterinit(node->heads);
256 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
257 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
258 cblistpush(reqheads, vbuf, -1);
259 free(vbuf);
260 }
261 }
262 cblistpush(reqheads, "Content-Type: " ESTDRAFTTYPE, -1);
263 reqbody = est_doc_dump_draft(doc);
264 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
265 reqbody, strlen(reqbody), &rescode, NULL, NULL)){
266 node->status = -1;
267 err = TRUE;
268 }
269 if(!err){
270 node->status = rescode;
271 if(rescode != 200) err = TRUE;
272 }
273 free(reqbody);
274 cblistclose(reqheads);
275 return err ? FALSE : TRUE;
276 }
277
278
279 /* Remove a document from a node. */
280 int est_node_out_doc(ESTNODE *node, int id){
281 CBLIST *reqheads;
282 CBDATUM *reqbody;
283 const char *kbuf;
284 char url[ESTPATHBUFSIZ], *vbuf;
285 int rescode, err, ksiz;
286 assert(node && id > 0);
287 err = FALSE;
288 sprintf(url, "%s/out_doc", node->url);
289 reqheads = cblistopen();
290 if(cbmaprnum(node->heads) > 0){
291 cbmapiterinit(node->heads);
292 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
293 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
294 cblistpush(reqheads, vbuf, -1);
295 free(vbuf);
296 }
297 }
298 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
299 reqbody = cbdatumopen("", 0);
300 est_datum_printf(reqbody, "id=%d", id);
301 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
302 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, NULL)){
303 node->status = -1;
304 err = TRUE;
305 }
306 if(!err){
307 node->status = rescode;
308 if(rescode != 200) err = TRUE;
309 }
310 cbdatumclose(reqbody);
311 cblistclose(reqheads);
312 return err ? FALSE : TRUE;
313 }
314
315
316 /* Remove a document specified by URI from a node. */
317 int est_node_out_doc_by_uri(ESTNODE *node, const char *uri){
318 CBLIST *reqheads;
319 CBDATUM *reqbody;
320 const char *kbuf;
321 char url[ESTPATHBUFSIZ], *vbuf;
322 int rescode, err, ksiz;
323 assert(node && uri);
324 err = FALSE;
325 sprintf(url, "%s/out_doc", node->url);
326 reqheads = cblistopen();
327 if(cbmaprnum(node->heads) > 0){
328 cbmapiterinit(node->heads);
329 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
330 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
331 cblistpush(reqheads, vbuf, -1);
332 free(vbuf);
333 }
334 }
335 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
336 reqbody = cbdatumopen("", 0);
337 est_datum_printf(reqbody, "uri=%?", uri);
338 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
339 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, NULL)){
340 node->status = -1;
341 err = TRUE;
342 }
343 if(!err){
344 node->status = rescode;
345 if(rescode != 200) err = TRUE;
346 }
347 cbdatumclose(reqbody);
348 cblistclose(reqheads);
349 return err ? FALSE : TRUE;
350 }
351
352
353 /* Retrieve a document in a node. */
354 ESTDOC *est_node_get_doc(ESTNODE *node, int id){
355 ESTDOC *doc;
356 CBLIST *reqheads;
357 CBDATUM *reqbody, *resbody;
358 const char *kbuf;
359 char url[ESTPATHBUFSIZ], *vbuf;
360 int rescode, err, ksiz;
361 assert(node && id > 0);
362 err = FALSE;
363 sprintf(url, "%s/get_doc", node->url);
364 reqheads = cblistopen();
365 if(cbmaprnum(node->heads) > 0){
366 cbmapiterinit(node->heads);
367 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
368 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
369 cblistpush(reqheads, vbuf, -1);
370 free(vbuf);
371 }
372 }
373 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
374 reqbody = cbdatumopen("", 0);
375 est_datum_printf(reqbody, "id=%d", id);
376 resbody = cbdatumopen("", 0);
377 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
378 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
379 node->status = -1;
380 err = TRUE;
381 }
382 if(!err){
383 node->status = rescode;
384 if(rescode != 200) err = TRUE;
385 }
386 doc = err ? NULL : est_doc_new_from_draft(cbdatumptr(resbody));
387 cbdatumclose(resbody);
388 cbdatumclose(reqbody);
389 cblistclose(reqheads);
390 return doc;
391 }
392
393
394 /* Retrieve a document specified by URI in a node. */
395 ESTDOC *est_node_get_doc_by_uri(ESTNODE *node, const char *uri){
396 ESTDOC *doc;
397 CBLIST *reqheads;
398 CBDATUM *reqbody, *resbody;
399 const char *kbuf;
400 char url[ESTPATHBUFSIZ], *vbuf;
401 int rescode, err, ksiz;
402 assert(node && uri);
403 err = FALSE;
404 sprintf(url, "%s/get_doc", node->url);
405 reqheads = cblistopen();
406 if(cbmaprnum(node->heads) > 0){
407 cbmapiterinit(node->heads);
408 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
409 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
410 cblistpush(reqheads, vbuf, -1);
411 free(vbuf);
412 }
413 }
414 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
415 reqbody = cbdatumopen("", 0);
416 est_datum_printf(reqbody, "uri=%?", uri);
417 resbody = cbdatumopen("", 0);
418 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
419 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
420 node->status = -1;
421 err = TRUE;
422 }
423 if(!err){
424 node->status = rescode;
425 if(rescode != 200) err = TRUE;
426 }
427 doc = err ? NULL : est_doc_new_from_draft(cbdatumptr(resbody));
428 cbdatumclose(resbody);
429 cbdatumclose(reqbody);
430 cblistclose(reqheads);
431 return doc;
432 }
433
434
435 /* Retrieve the value of an attribute of a document in a node. */
436 char *est_node_get_doc_attr(ESTNODE *node, int id, const char *name){
437 CBLIST *reqheads;
438 CBDATUM *reqbody, *resbody;
439 const char *kbuf;
440 char url[ESTPATHBUFSIZ], *vbuf;
441 int rescode, err, ksiz;
442 assert(node && id > 0);
443 err = FALSE;
444 sprintf(url, "%s/get_doc_attr", node->url);
445 reqheads = cblistopen();
446 if(cbmaprnum(node->heads) > 0){
447 cbmapiterinit(node->heads);
448 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
449 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
450 cblistpush(reqheads, vbuf, -1);
451 free(vbuf);
452 }
453 }
454 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
455 reqbody = cbdatumopen("", 0);
456 est_datum_printf(reqbody, "id=%d&attr=%?", id, name);
457 resbody = cbdatumopen("", 0);
458 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
459 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
460 node->status = -1;
461 err = TRUE;
462 }
463 if(!err){
464 node->status = rescode;
465 if(rescode != 200) err = TRUE;
466 }
467 if(err){
468 cbdatumclose(resbody);
469 vbuf = NULL;
470 } else {
471 vbuf = cbdatumtomalloc(resbody, NULL);
472 cbstrtrim(vbuf);
473 }
474 cbdatumclose(reqbody);
475 cblistclose(reqheads);
476 return vbuf;
477 }
478
479
480 /* Retrieve the value of an attribute of a document specified by URI in a node. */
481 char *est_node_get_doc_attr_by_uri(ESTNODE *node, const char *uri, const char *name){
482 CBLIST *reqheads;
483 CBDATUM *reqbody, *resbody;
484 const char *kbuf;
485 char url[ESTPATHBUFSIZ], *vbuf;
486 int rescode, err, ksiz;
487 assert(node && uri);
488 err = FALSE;
489 sprintf(url, "%s/get_doc_attr", node->url);
490 reqheads = cblistopen();
491 if(cbmaprnum(node->heads) > 0){
492 cbmapiterinit(node->heads);
493 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
494 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
495 cblistpush(reqheads, vbuf, -1);
496 free(vbuf);
497 }
498 }
499 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
500 reqbody = cbdatumopen("", 0);
501 est_datum_printf(reqbody, "uri=%?&attr=%?", uri, name);
502 resbody = cbdatumopen("", 0);
503 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
504 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
505 node->status = -1;
506 err = TRUE;
507 }
508 if(!err){
509 node->status = rescode;
510 if(rescode != 200) err = TRUE;
511 }
512 if(err){
513 cbdatumclose(resbody);
514 vbuf = NULL;
515 } else {
516 vbuf = cbdatumtomalloc(resbody, NULL);
517 cbstrtrim(vbuf);
518 }
519 cbdatumclose(reqbody);
520 cblistclose(reqheads);
521 return vbuf;
522 }
523
524
525 /* Get the ID of a document spacified by URI. */
526 int est_node_uri_to_id(ESTNODE *node, const char *uri){
527 CBLIST *reqheads;
528 CBDATUM *reqbody, *resbody;
529 const char *kbuf;
530 char url[ESTPATHBUFSIZ], *vbuf;
531 int rescode, err, ksiz, id;
532 assert(node && uri);
533 err = FALSE;
534 sprintf(url, "%s/uri_to_id", node->url);
535 reqheads = cblistopen();
536 if(cbmaprnum(node->heads) > 0){
537 cbmapiterinit(node->heads);
538 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
539 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
540 cblistpush(reqheads, vbuf, -1);
541 free(vbuf);
542 }
543 }
544 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
545 reqbody = cbdatumopen("", 0);
546 est_datum_printf(reqbody, "uri=%?", uri);
547 resbody = cbdatumopen("", 0);
548 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
549 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
550 node->status = -1;
551 err = TRUE;
552 }
553 if(!err){
554 node->status = rescode;
555 if(rescode != 200) err = TRUE;
556 }
557 id = err ? -1 : atoi(cbdatumptr(resbody));
558 cbdatumclose(resbody);
559 cbdatumclose(reqbody);
560 cblistclose(reqheads);
561 return id;
562 }
563
564
565 /* Get the name of a node. */
566 const char *est_node_name(ESTNODE *node){
567 assert(node);
568 if(node->name) return node->name;
569 est_node_set_inform(node);
570 return node->name;
571 }
572
573
574 /* Get the label of a node. */
575 const char *est_node_label(ESTNODE *node){
576 assert(node);
577 if(node->label) return node->label;
578 est_node_set_inform(node);
579 return node->label;
580 }
581
582
583 /* Get the number of documents in a node. */
584 int est_node_doc_num(ESTNODE *node){
585 assert(node);
586 if(node->dnum >= 0) return node->dnum;
587 est_node_set_inform(node);
588 return node->dnum;
589 }
590
591
592 /* Get the number of words in a node. */
593 int est_node_word_num(ESTNODE *node){
594 assert(node);
595 if(node->wnum >= 0) return node->wnum;
596 est_node_set_inform(node);
597 return node->wnum;
598 }
599
600
601 /* Get the size of the datbase of a node. */
602 double est_node_size(ESTNODE *node){
603 assert(node);
604 if(node->size >= 0.0) return node->size;
605 est_node_set_inform(node);
606 return node->size;
607 }
608
609
610 /* Search documents corresponding a condition for a node. */
611 ESTNODERES *est_node_search(ESTNODE *node, ESTCOND *cond, int depth){
612 ESTNODERES *nres;
613 const CBLIST *attrs;
614 CBLIST *reqheads;
615 CBDATUM *reqbody, *resbody;
616 const char *kbuf, *phrase, *order;
617 char buf[ESTPATHBUFSIZ], *vbuf, *ptr, *pv, *ep;
618 int i, rescode, err, ksiz, max, plen, part, end;
619 assert(node && cond && depth >= 0);
620 err = FALSE;
621 sprintf(buf, "%s/search", node->url);
622 reqheads = cblistopen();
623 if(cbmaprnum(node->heads) > 0){
624 cbmapiterinit(node->heads);
625 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
626 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
627 cblistpush(reqheads, vbuf, -1);
628 free(vbuf);
629 }
630 }
631 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
632 reqbody = cbdatumopen("", 0);
633 if((phrase = est_cond_phrase(cond)) != NULL) est_datum_printf(reqbody, "phrase=%?", phrase);
634 if((attrs = est_cond_attrs(cond)) != NULL){
635 for(i = 0; i < cblistnum(attrs); i++){
636 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
637 est_datum_printf(reqbody, "attr%d=%?", i + 1, cblistval(attrs, i, NULL));
638 }
639 }
640 if((max = est_cond_max(cond)) >= 0){
641 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
642 est_datum_printf(reqbody, "max=%d", max);
643 } else {
644 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
645 est_datum_printf(reqbody, "max=%d", INT_MAX / 2);
646 }
647 if((order = est_cond_order(cond)) != NULL){
648 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
649 est_datum_printf(reqbody, "order=%?", order);
650 }
651 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
652 est_datum_printf(reqbody, "depth=%d", depth);
653 resbody = cbdatumopen("", 0);
654 if(!est_url_shuttle(buf, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
655 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
656 node->status = -1;
657 err = TRUE;
658 }
659 if(!err){
660 node->status = rescode;
661 if(rescode != 200) err = TRUE;
662 }
663 if(err){
664 cbdatumclose(resbody);
665 cbdatumclose(reqbody);
666 cblistclose(reqheads);
667 return NULL;
668 }
669 ptr = cbdatumtomalloc(resbody, NULL);
670 if(!(pv = strchr(ptr, '\n')) || pv <= ptr + 3){
671 free(ptr);
672 cbdatumclose(reqbody);
673 cblistclose(reqheads);
674 return NULL;
675 }
676 *pv = '\0';
677 if(pv[-1] == '\r') pv[-1] = '\0';
678 plen = strlen(ptr);
679 pv++;
680 ep = pv;
681 nres = est_noderes_new();
682 part = 0;
683 end = FALSE;
684 while(*ep != '\0'){
685 if(*ep == *ptr && cbstrfwmatch(ep, ptr) && ep[-1] == '\n' &&
686 (ep[plen] == '\r' || ep[plen] == '\n' || ep[plen] == ':')){
687 *ep = '\0';
688 if(part == 0){
689 est_parse_search_header(nres, pv);
690 } else {
691 est_parse_search_body(nres, pv);
692 }
693 ep += plen;
694 if(cbstrfwmatch(ep, ":END")){
695 end = TRUE;
696 break;
697 }
698 if(*ep == '\r') ep++;
699 if(*ep == '\n') ep++;
700 pv = ep;
701 part++;
702 } else {
703 ep++;
704 }
705 }
706 free(ptr);
707 cbdatumclose(reqbody);
708 cblistclose(reqheads);
709 if(!end){
710 est_noderes_delete(nres);
711 return NULL;
712 }
713 return nres;
714 }
715
716
717 /* Manage a user account of a node. */
718 int est_node_set_user(ESTNODE *node, const char *name, int mode){
719 CBLIST *reqheads;
720 CBDATUM *reqbody, *resbody;
721 const char *kbuf;
722 char url[ESTPATHBUFSIZ], *vbuf;
723 int rescode, err, ksiz;
724 assert(node && name);
725 err = FALSE;
726 sprintf(url, "%s/_set_user", node->url);
727 reqheads = cblistopen();
728 if(cbmaprnum(node->heads) > 0){
729 cbmapiterinit(node->heads);
730 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
731 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
732 cblistpush(reqheads, vbuf, -1);
733 free(vbuf);
734 }
735 }
736 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
737 reqbody = cbdatumopen("", 0);
738 est_datum_printf(reqbody, "name=%?&mode=%d", name, mode);
739 resbody = cbdatumopen("", 0);
740 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
741 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
742 node->status = -1;
743 err = TRUE;
744 }
745 if(!err){
746 node->status = rescode;
747 if(rescode != 200) err = TRUE;
748 }
749 cbdatumclose(resbody);
750 cbdatumclose(reqbody);
751 cblistclose(reqheads);
752 return err ? FALSE : TRUE;
753 }
754
755
756 /* Manage a link of a node. */
757 int est_node_set_link(ESTNODE *node, const char *url, const char *label, int credit){
758 CBLIST *reqheads;
759 CBDATUM *reqbody, *resbody;
760 const char *kbuf;
761 char myurl[ESTPATHBUFSIZ], *vbuf;
762 int rescode, err, ksiz;
763 assert(node && url && label);
764 err = FALSE;
765 sprintf(myurl, "%s/_set_link", node->url);
766 reqheads = cblistopen();
767 if(cbmaprnum(node->heads) > 0){
768 cbmapiterinit(node->heads);
769 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
770 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
771 cblistpush(reqheads, vbuf, -1);
772 free(vbuf);
773 }
774 }
775 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
776 reqbody = cbdatumopen("", 0);
777 if(credit >= 0){
778 est_datum_printf(reqbody, "url=%?&label=%?&credit=%d", url, label, credit);
779 } else {
780 est_datum_printf(reqbody, "url=%?&label=%?", url, label);
781 }
782 resbody = cbdatumopen("", 0);
783 if(!est_url_shuttle(myurl, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
784 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
785 node->status = -1;
786 err = TRUE;
787 }
788 if(!err){
789 node->status = rescode;
790 if(rescode != 200) err = TRUE;
791 }
792 cbdatumclose(resbody);
793 cbdatumclose(reqbody);
794 cblistclose(reqheads);
795 return err ? FALSE : TRUE;
796 }
797
798
799
800 /*************************************************************************************************
801 * features for experts
802 *************************************************************************************************/
803
804
805 /* Get the name of this host. */
806 const char *est_get_host_name(void){
807 static char host[ESTPATHBUFSIZ];
808 static int first = TRUE;
809 if(!est_host_addrs) return "127.0.0.1";
810 if(first){
811 first = FALSE;
812 if(gethostname(host, ESTPATHBUFSIZ - 1) == -1) return "127.0.0.1";
813 return host;
814 }
815 return host;
816 }
817
818
819 /* Get the address of a host. */
820 char *est_get_host_addr(const char *name){
821 static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
822 struct hostent *info;
823 const char *addr;
824 char *buf, *pv, vbuf[64];
825 int i, ost, nsiz, asiz, vsiz;
826 assert(name);
827 if(!est_host_addrs) return NULL;
828 if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ost) != 0) return NULL;
829 if(pthread_mutex_lock(&mymutex) != 0){
830 pthread_setcancelstate(ost, NULL);
831 return NULL;
832 }
833 nsiz = strlen(name);
834 buf = NULL;
835 if((addr = cbmapget(est_host_addrs, name, nsiz, &asiz)) != NULL){
836 buf = cbmemdup(addr, asiz);
837 if((pv = strchr(buf, '\t')) != NULL){
838 *pv = '\0';
839 if((int)time(NULL) - atoi(pv + 1) > ESTDNHOLDSEC){
840 free(buf);
841 buf = NULL;
842 }
843 }
844 cbmapmove(est_host_addrs, name, nsiz, FALSE);
845 }
846 pthread_mutex_unlock(&mymutex);
847 pthread_setcancelstate(ost, NULL);
848 if(buf){
849 if(buf[0] != '\0') return buf;
850 free(buf);
851 return NULL;
852 }
853 if((info = gethostbyname(name)) != NULL && info->h_addr_list[0]){
854 addr = inet_ntoa(*(struct in_addr *)info->h_addr_list[0]);
855 } else {
856 addr = NULL;
857 }
858 buf = addr ? cbmemdup(addr, -1) : NULL;
859 if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ost) == 0){
860 if(pthread_mutex_lock(&mymutex) == 0){
861 vsiz = sprintf(vbuf, "%s\t%d", addr ? addr : "", (int)time(NULL));
862 cbmapput(est_host_addrs, name, nsiz, vbuf, vsiz, TRUE);
863 if(cbmaprnum(est_host_addrs) > ESTDNHOLDNUM){
864 cbmapiterinit(est_host_addrs);
865 for(i = 0; i < ESTDNHOLDNUM / 4 &&
866 (addr = cbmapiternext(est_host_addrs, &asiz)) != NULL; i++){
867 cbmapout(est_host_addrs, addr, asiz);
868 }
869 }
870 pthread_mutex_unlock(&mymutex);
871 }
872 pthread_setcancelstate(ost, NULL);
873 }
874 return buf;
875 }
876
877
878 /* Get a server socket of an address and a port. */
879 int est_get_server_sock(const char *addr, int port){
880 struct sockaddr_in address;
881 struct linger li;
882 int ost, sock, optone;
883 assert(port > 0);
884 if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ost) != 0) return -1;
885 memset(&address, 0, sizeof(address));
886 address.sin_family = AF_INET;
887 if(!est_inet_aton(addr ? addr : "0.0.0.0", &address.sin_addr)){
888 pthread_setcancelstate(ost, NULL);
889 return -1;
890 }
891 address.sin_port = htons(port);
892 if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){
893 pthread_setcancelstate(ost, NULL);
894 return -1;
895 }
896 li.l_onoff = 1;
897 li.l_linger = 100;
898 optone = 1;
899 if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&li, sizeof(li)) == -1 ||
900 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&optone, sizeof(optone)) == -1){
901 est_sock_close(sock);
902 pthread_setcancelstate(ost, NULL);
903 return -1;
904 }
905 if(bind(sock, (struct sockaddr *)&address, sizeof(address)) == -1 ||
906 listen(sock, SOMAXCONN) == -1){
907 est_sock_close(sock);
908 pthread_setcancelstate(ost, NULL);
909 return -1;
910 }
911 pthread_setcancelstate(ost, NULL);
912 return sock;
913 }
914
915
916 /* Accept a connection from a client. */
917 int est_accept_conn(int sock, char *abuf, int *pp){
918 struct sockaddr_in address;
919 socklen_t socklen;
920 int clsock;
921 assert(sock >= 0);
922 socklen = sizeof(address);
923 if((clsock = accept(sock, (struct sockaddr *)&address, &socklen)) >= 0){
924 if(abuf) sprintf(abuf, "%s", inet_ntoa(address.sin_addr));
925 if(pp) *pp = (int)ntohs(address.sin_port);
926 return clsock;
927 }
928 return (errno == EINTR || errno == EAGAIN) ? 0 : -1;
929 }
930
931
932 /* Get a client socket to an address and a port. */
933 int est_get_client_sock(const char *addr, int port){
934 struct sockaddr_in address;
935 struct linger li;
936 int ost, sock;
937 assert(addr && port >= 0);
938 if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ost) != 0) return -1;
939 memset(&address, 0, sizeof(address));
940 address.sin_family = AF_INET;
941 if(!est_inet_aton(addr, &address.sin_addr)){
942 pthread_setcancelstate(ost, NULL);
943 return -1;
944 }
945 address.sin_port = htons(port);
946 if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){
947 pthread_setcancelstate(ost, NULL);
948 return -1;
949 }
950 li.l_onoff = 1;
951 li.l_linger = 100;
952 if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&li, sizeof(li)) == -1){
953 est_sock_close(sock);
954 pthread_setcancelstate(ost, NULL);
955 return -1;
956 }
957 if(connect(sock, (struct sockaddr *)&address, sizeof(address)) == -1){
958 est_sock_close(sock);
959 pthread_setcancelstate(ost, NULL);
960 return -1;
961 }
962 pthread_setcancelstate(ost, NULL);
963 return sock;
964 }
965
966
967 /* Shutdown and close a socket. */
968 void est_sock_down(int sock){
969 assert(sock >= 0);
970 shutdown(sock, 2);
971 est_sock_close(sock);
972 }
973
974
975 /* Receive all data from a socket. */
976 char *est_sock_recv_all(int sock, int len){
977 char *buf;
978 int i, bs;
979 assert(sock >= 0 && len >= 0);
980 buf = cbmalloc(len + 1);
981 for(i = 0; i < len && (bs = recv(sock, buf + i, len - i, 0)) != 0; i += bs){
982 if(bs == -1 && errno != EINTR){
983 free(buf);
984 return NULL;
985 }
986 }
987 buf[i] = '\0';
988 return buf;
989 }
990
991
992 /* Receive a line from a socket. */
993 int est_sock_recv_line(int sock, char *buf, int max){
994 char *wp;
995 assert(sock >= 0 && buf && max > 0);
996 max--;
997 wp = buf;
998 while(wp < buf + max){
999 switch(recv(sock, wp, 1, 0)){
1000 case -1:
1001 if(errno != EINTR){
1002 *wp = '\0';
1003 return wp - buf;
1004 }
1005 break;
1006 case 0:
1007 *wp = '\0';
1008 return wp - buf;
1009 default:
1010 switch(*wp){
1011 case '\r':
1012 break;
1013 case '\n':
1014 *wp = '\0';
1015 return wp - buf;
1016 default:
1017 wp++;
1018 break;
1019 }
1020 break;
1021 }
1022 }
1023 *wp = '\0';
1024 return wp - buf;
1025 }
1026
1027
1028 /* Receive void data from a socket. */
1029 void est_sock_recv_void(int sock){
1030 fd_set rfds;
1031 struct timeval tv;
1032 char ibuf[ESTIOBUFSIZ];
1033 assert(sock >= 0);
1034 FD_ZERO(&rfds);
1035 FD_SET(sock, &rfds);
1036 tv.tv_sec = 0;
1037 tv.tv_usec = 0;
1038 if(select(sock + 1, &rfds, NULL, NULL, &tv) > 0 && FD_ISSET(sock, &rfds))
1039 recv(sock, ibuf, ESTIOBUFSIZ, 0);
1040 }
1041
1042
1043 /* Write all data into a socket. */
1044 void est_sock_send_all(int sock, const char *buf, int len){
1045 const char *rp;
1046 int rv, wb;
1047 assert(sock >= 0 && buf && len >= 0);
1048 rp = buf;
1049 rv = 0;
1050 do {
1051 wb = send(sock, rp, len, 0);
1052 switch(wb){
1053 case -1: if(errno != EINTR) return;
1054 case 0: break;
1055 default:
1056 rp += wb;
1057 len -= wb;
1058 rv += wb;
1059 break;
1060 }
1061 } while(len > 0);
1062 }
1063
1064
1065 /* Perform formatted output into a datum object. */
1066 void est_datum_printf(CBDATUM *datum, const char *format, ...){
1067 va_list ap;
1068 char *tmp, cbuf[ESTNUMBUFSIZ], tbuf[ESTNUMBUFSIZ*2];
1069 unsigned char c;
1070 int cblen, tlen;
1071 assert(datum && format);
1072 va_start(ap, format);
1073 while(*format != '\0'){
1074 if(*format == '%'){
1075 cbuf[0] = '%';
1076 cblen = 1;
1077 format++;
1078 while(strchr("0123456789 .+-", *format) && *format != '\0' && cblen < ESTNUMBUFSIZ - 1){
1079 cbuf[cblen++] = *format;
1080 format++;
1081 }
1082 cbuf[cblen++] = *format;
1083 cbuf[cblen] = '\0';
1084 switch(*format){
1085 case 's':
1086 tmp = va_arg(ap, char *);
1087 if(!tmp) tmp = "(null)";
1088 cbdatumcat(datum, tmp, -1);
1089 break;
1090 case 'd':
1091 tlen = sprintf(tbuf, cbuf, va_arg(ap, int));
1092 cbdatumcat(datum, tbuf, tlen);
1093 break;
1094 case 'o': case 'u': case 'x': case 'X': case 'c':
1095 tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned int));
1096 cbdatumcat(datum, tbuf, tlen);
1097 break;
1098 case 'e': case 'E': case 'f': case 'g': case 'G':
1099 tlen = sprintf(tbuf, cbuf, va_arg(ap, double));
1100 cbdatumcat(datum, tbuf, tlen);
1101 break;
1102 case '@':
1103 tmp = va_arg(ap, char *);
1104 if(!tmp) tmp = "(null)";
1105 while(*tmp){
1106 switch(*tmp){
1107 case '&': cbdatumcat(datum, "&amp;", 5); break;
1108 case '<': cbdatumcat(datum, "&lt;", 4); break;
1109 case '>': cbdatumcat(datum, "&gt;", 4); break;
1110 case '"': cbdatumcat(datum, "&quot;", 6); break;
1111 default:
1112 if(!((*tmp >= 0 && *tmp <= 0x8) || (*tmp >= 0x0e && *tmp <= 0x1f)))
1113 cbdatumcat(datum, tmp, 1);
1114 break;
1115 }
1116 tmp++;
1117 }
1118 break;
1119 case '?':
1120 tmp = va_arg(ap, char *);
1121 if(!tmp) tmp = "(null)";
1122 while(*tmp){
1123 c = *(unsigned char *)tmp;
1124 if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
1125 (c >= '0' && c <= '9') || (c != '\0' && strchr("_-.", c))){
1126 cbdatumcat(datum, tmp, 1);
1127 } else {
1128 tlen = sprintf(tbuf, "%%%02X", c);
1129 cbdatumcat(datum, tbuf, tlen);
1130 }
1131 tmp++;
1132 }
1133 break;
1134 case '%':
1135 cbdatumcat(datum, "%", 1);
1136 break;
1137 }
1138 } else {
1139 cbdatumcat(datum, format, 1);
1140 }
1141 format++;
1142 }
1143 va_end(ap);
1144 }
1145
1146
1147 /* Perform an interaction of a URL. */
1148 int est_url_shuttle(const char *url, const char *pxhost, int pxport, int outsec,
1149 const char *auth, const CBLIST *reqheads, const char *reqbody, int rbsiz,
1150 int *rescodep, CBMAP *resheads, CBDATUM *resbody){
1151 pthread_t th;
1152 pthread_mutex_t mutex;
1153 pthread_cond_t cond;
1154 struct timespec timeout;
1155 TARGSHUTTLE targ;
1156 int err, rv;
1157 void *rvp;
1158 pthread_mutex_init(&mutex, NULL);
1159 pthread_cond_init(&cond, NULL);
1160 targ.alive = TRUE;
1161 targ.cond = &cond;
1162 targ.url = url;
1163 targ.pxhost = pxhost;
1164 targ.pxport = pxport;
1165 targ.auth = auth;
1166 targ.reqheads = reqheads;
1167 targ.reqbody = reqbody;
1168 targ.rbsiz = rbsiz;
1169 targ.rescodep = rescodep;
1170 targ.resheads = resheads;
1171 targ.resbody = resbody;
1172 err = FALSE;
1173 if(outsec >= 0){
1174 if(pthread_mutex_lock(&mutex) == 0){
1175 if(pthread_create(&th, NULL, est_url_shuttle_impl, &targ) == 0){
1176 timeout.tv_sec = time(NULL) + outsec;
1177 timeout.tv_nsec = 1000 * 1000 * 500;
1178 rv = 0;
1179 while(targ.alive && rv != ETIMEDOUT){
1180 rv = pthread_cond_timedwait(&cond, &mutex, &timeout);
1181 }
1182 if(rv == ETIMEDOUT){
1183 pthread_cancel(th);
1184 pthread_join(th, NULL);
1185 err = TRUE;
1186 } else if(pthread_join(th, &rvp) != 0 || rvp != NULL){
1187 err = TRUE;
1188 }
1189 } else {
1190 err = TRUE;
1191 }
1192 pthread_mutex_unlock(&mutex);
1193 } else {
1194 err = TRUE;
1195 }
1196 } else {
1197 if(est_url_shuttle_impl(&targ) != NULL) err = TRUE;
1198 }
1199 if(pthread_mutex_destroy(&mutex) != 0) err = TRUE;
1200 if(pthread_cond_destroy(&cond) != 0) err = TRUE;
1201 return err ? FALSE : TRUE;
1202 }
1203
1204
1205 /* Add a header to a node connection object. */
1206 void est_node_add_header(ESTNODE *node, const char *name, const char *value){
1207 const char *vbuf;
1208 int len;
1209 assert(node && name);
1210 len = strlen(name);
1211 if(value){
1212 if((vbuf = cbmapget(node->heads, name, len, NULL)) != NULL){
1213 cbmapputcat(node->heads, name, len, ", ", 2);
1214 cbmapputcat(node->heads, name, len, value, -1);
1215 } else {
1216 cbmapput(node->heads, name, len, value, -1, FALSE);
1217 }
1218 } else {
1219 cbmapout(node->heads, name, len);
1220 }
1221 }
1222
1223
1224 /* Create a node result object. */
1225 ESTNODERES *est_noderes_new(void){
1226 ESTNODERES *nres;
1227 nres = cbmalloc(sizeof(ESTNODERES));
1228 nres->top = 0;
1229 nres->max = ESTLISTUNIT;
1230 nres->docs = cbmalloc(sizeof(ESTRESDOC) * nres->max);
1231 nres->dnum = 0;
1232 nres->hints = cbmapopenex(ESTMINIBNUM);
1233 return nres;
1234 }
1235
1236
1237 /* Add a document information to a node result object. */
1238 void est_noderes_add_doc(ESTNODERES *nres, CBMAP *attrs, char *snippet){
1239 const char *uri;
1240 assert(nres && attrs && snippet);
1241 if(!(uri = cbmapget(attrs, ESTDATTRURI, -1, NULL))){
1242 free(snippet);
1243 cbmapclose(attrs);
1244 return;
1245 }
1246 if(nres->top + nres->dnum >= nres->max){
1247 nres->max *= 2;
1248 nres->docs = cbrealloc(nres->docs, nres->max * sizeof(ESTRESDOC));
1249 }
1250 nres->docs[nres->top+nres->dnum].uri = uri;
1251 nres->docs[nres->top+nres->dnum].attrs = attrs;
1252 nres->docs[nres->top+nres->dnum].snippet = snippet;
1253 nres->dnum++;
1254 }
1255
1256
1257 /* Remove the top of result document objects in a node result object. */
1258 int est_noderes_shift(ESTNODERES *nres, CBMAP **attrp, char **snippetp){
1259 assert(nres && attrp && snippetp);
1260 if(nres->dnum < 1) return FALSE;
1261 *attrp = nres->docs[nres->top].attrs;
1262 *snippetp = nres->docs[nres->top].snippet;
1263 nres->top++;
1264 nres->dnum--;
1265 return TRUE;
1266 }
1267
1268
1269
1270 /*************************************************************************************************
1271 * private objects
1272 *************************************************************************************************/
1273
1274
1275 /* Close a socket.
1276 `sock' specifies a socket.
1277 The return value is 0 if success, else it is -1. */
1278 static int est_sock_close(int sock){
1279 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1280 assert(sock >= 0);
1281 return closesocket(sock);
1282 #else
1283 assert(sock >= 0);
1284 return close(sock);
1285 #endif
1286 }
1287
1288
1289 /* Convert a host address to network binary data.
1290 `cp' specifies a host address.
1291 `inp' specifies the pointer to an structure into which the result is to be stored.
1292 The return value is true if success, else it is false. */
1293 static int est_inet_aton(const char *cp, struct in_addr *inp){
1294 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1295 in_addr_t in;
1296 assert(cp && inp);
1297 if((in = inet_addr(cp)) == INADDR_NONE){
1298 if(!strcmp(cp, "255.255.255.255")){
1299 inp->s_addr = in;
1300 return TRUE;
1301 }
1302 return FALSE;
1303 }
1304 inp->s_addr = in;
1305 return TRUE;
1306 #else
1307 assert(cp && inp);
1308 return inet_aton(cp, inp);
1309 #endif
1310 }
1311
1312
1313 /* Perform the communication which can be canceled.
1314 `targ' specifies the pointer to a closure arguments.
1315 The return value is `NULL' if sucessful or non `NULL' value on error. */
1316 static void *est_url_shuttle_impl(void *targ){
1317 const CBLIST *reqheads;
1318 CBMAP *resheads, *elems;
1319 CBDATUM *resbody, *datum;
1320 const char *url, *pxhost, *auth, *reqbody, *tmp, *scheme, *host, *path, *query, *rp;
1321 char *addr, *enc, iobuf[ESTIOBUFSIZ], name[ESTIOBUFSIZ], *pv;
1322 int i, pxport, rbsiz, *rescodep, port, sock, *sp, size, nsiz;
1323 assert(targ);
1324 url = ((TARGSHUTTLE *)targ)->url;
1325 pxhost = ((TARGSHUTTLE *)targ)->pxhost;
1326 pxport = ((TARGSHUTTLE *)targ)->pxport;
1327 auth = ((TARGSHUTTLE *)targ)->auth;
1328 reqheads = ((TARGSHUTTLE *)targ)->reqheads;
1329 reqbody = ((TARGSHUTTLE *)targ)->reqbody;
1330 rbsiz = ((TARGSHUTTLE *)targ)->rbsiz;
1331 rescodep = ((TARGSHUTTLE *)targ)->rescodep;
1332 resheads = ((TARGSHUTTLE *)targ)->resheads;
1333 resbody = ((TARGSHUTTLE *)targ)->resbody;
1334 elems = cburlbreak(url);
1335 pthread_cleanup_push((void (*)(void *))cbmapclose, elems);
1336 scheme = cbmapget(elems, "scheme", -1, NULL);
1337 host = cbmapget(elems, "host", -1, NULL);
1338 port = (tmp = cbmapget(elems, "port", -1, NULL)) ? atoi(tmp) : 80;
1339 if(!auth) auth = cbmapget(elems, "authority", -1, NULL);
1340 if(!(path = cbmapget(elems, "path", -1, NULL))) path = "/";
1341 if(!(query = cbmapget(elems, "query", -1, NULL))) query = "";
1342 if(!scheme || cbstricmp(scheme, "http") || !host || port < 1 ||
1343 !(addr = est_get_host_addr(pxhost ? pxhost : host))){
1344 ((TARGSHUTTLE *)targ)->alive = FALSE;
1345 pthread_cond_signal(((TARGSHUTTLE *)targ)->cond);
1346 return "error";
1347 }
1348 pthread_cleanup_push((void (*)(void *))free, addr);
1349 if((sock = est_get_client_sock(addr, pxhost ? pxport : port)) == -1){
1350 ((TARGSHUTTLE *)targ)->alive = FALSE;
1351 pthread_cond_signal(((TARGSHUTTLE *)targ)->cond);
1352 return "error";
1353 }
1354 sp = cbmalloc(sizeof(int));
1355 *sp = sock;
1356 pthread_cleanup_push((void (*)(void *))est_sockpt_down, sp);
1357 datum = cbdatumopen("", 0);
1358 pthread_cleanup_push((void (*)(void *))cbdatumclose, datum);
1359 if(pxhost){
1360 est_datum_printf(datum, "%s %s HTTP/1.0\r\n", reqbody ? "POST" : "GET", url);
1361 } else if(reqbody){
1362 est_datum_printf(datum, "POST %s HTTP/1.0\r\n", path);
1363 } else if(query[0] != 0){
1364 est_datum_printf(datum, "GET %s?%s HTTP/1.0\r\n", path, query);
1365 } else {
1366 est_datum_printf(datum, "GET %s HTTP/1.0\r\n", path);
1367 }
1368 est_datum_printf(datum, "Host: %s:%d\r\n", host, port);
1369 est_datum_printf(datum, "Connection: close\r\n", path);
1370 est_datum_printf(datum, "User-Agent: %s/%s\r\n", ESTAGENTNAME, est_version);
1371 if(auth){
1372 enc = cbbaseencode(auth, -1);
1373 est_datum_printf(datum, "Authorization: Basic %s\r\n", enc);
1374 free(enc);
1375 }
1376 if(reqbody) est_datum_printf(datum, "Content-Length: %d\r\n", rbsiz);
1377 if(reqheads){
1378 for(i = 0; i < cblistnum(reqheads); i++){
1379 rp = cblistval(reqheads, i, &size);
1380 est_datum_printf(datum, rp, size);
1381 est_datum_printf(datum, "\r\n", 2);
1382 }
1383 }
1384 est_datum_printf(datum, "\r\n");
1385 est_sock_send_all(sock, cbdatumptr(datum), cbdatumsize(datum));
1386 if(reqbody) est_sock_send_all(sock, reqbody, rbsiz);
1387 if((size = est_sock_recv_line(sock, iobuf, ESTIOBUFSIZ - 1)) < 1 ||
1388 !cbstrfwmatch(iobuf, "HTTP/") || !(rp = strchr(iobuf, ' '))){
1389 ((TARGSHUTTLE *)targ)->alive = FALSE;
1390 pthread_cond_signal(((TARGSHUTTLE *)targ)->cond);
1391 return "error";
1392 }
1393 rp++;
1394 if(rescodep) *rescodep = atoi(rp);
1395 if(resheads) cbmapput(resheads, "", 0, iobuf, size, TRUE);
1396 name[0] = '\0';
1397 nsiz = 0;
1398 while((size = est_sock_recv_line(sock, iobuf, ESTIOBUFSIZ - 1)) > 0){
1399 if(resheads){
1400 if(iobuf[0] == ' ' || iobuf[0] == '\t'){
1401 if(name[0] != '\0'){
1402 iobuf[0] = ' ';
1403 cbmapputcat(resheads, name, nsiz, iobuf, size);
1404 }
1405 } else if((rp = strchr(iobuf, ':')) > iobuf){
1406 nsiz = rp - iobuf;
1407 memcpy(name, iobuf, nsiz);
1408 name[nsiz] = '\0';
1409 for(pv = name; *pv != '\0'; pv++){
1410 if(*pv >= 'A'&& *pv <= 'Z') *pv = *pv + ('a' - 'A');
1411 }
1412 rp++;
1413 if(*rp == ' ' || *rp == '\t') rp++;
1414 if(cbmapget(resheads, name, nsiz, NULL)){
1415 cbmapputcat(resheads, name, nsiz, ", ", 2);
1416 cbmapputcat(resheads, name, nsiz, pv, -1);
1417 } else {
1418 cbmapput(resheads, name, nsiz, rp, -1, TRUE);
1419 }
1420 }
1421 }
1422 }
1423 while((size = recv(sock, iobuf, ESTIOBUFSIZ, 0)) > 0){
1424 if(resbody) cbdatumcat(resbody, iobuf, size);
1425 }
1426 pthread_cleanup_pop(1);
1427 pthread_cleanup_pop(1);
1428 pthread_cleanup_pop(1);
1429 pthread_cleanup_pop(1);
1430 ((TARGSHUTTLE *)targ)->alive = FALSE;
1431 pthread_cond_signal(((TARGSHUTTLE *)targ)->cond);
1432 return NULL;
1433 }
1434
1435
1436 /* Release the socket of a pointer.
1437 `sp' specifies the pointer to a variable of a file descriptor. */
1438 static void est_sockpt_down(void *sp){
1439 est_sock_down(*(int *)sp);
1440 free(sp);
1441 }
1442
1443
1444 /* Set meta informations of a node.
1445 `node' specifies a node connection object.
1446 The return value is true if success, else it is false. */
1447 static int est_node_set_inform(ESTNODE *node){
1448 CBLIST *reqheads, *elems;
1449 CBDATUM *resbody;
1450 const char *kbuf, *ptr;
1451 char url[ESTPATHBUFSIZ], *vbuf, *pv;
1452 int rescode, err, ksiz;
1453 assert(node);
1454 err = FALSE;
1455 sprintf(url, "%s/inform", node->url);
1456 reqheads = cblistopen();
1457 if(cbmaprnum(node->heads) > 0){
1458 cbmapiterinit(node->heads);
1459 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
1460 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
1461 cblistpush(reqheads, vbuf, -1);
1462 free(vbuf);
1463 }
1464 }
1465 node->dnum = -1;
1466 node->wnum = -1;
1467 node->size = -1.0;
1468 resbody = cbdatumopen("", 0);
1469 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
1470 NULL, -1, &rescode, NULL, resbody)){
1471 node->status = -1;
1472 err = TRUE;
1473 }
1474 if(!err){
1475 node->status = rescode;
1476 if(rescode != 200) err = TRUE;
1477 }
1478 if(!err){
1479 ptr = cbdatumptr(resbody);
1480 if((pv = strchr(ptr, '\n')) != NULL){
1481 elems = cbsplit(ptr, pv - ptr, "\t");
1482 if(cblistnum(elems) == 5){
1483 if(!node->name) node->name = cbmemdup(cblistval(elems, 0, NULL), -1);
1484 if(!node->label) node->label = cbmemdup(cblistval(elems, 1, NULL), -1);
1485 node->dnum = atoi(cblistval(elems, 2, NULL));
1486 node->wnum = atoi(cblistval(elems, 3, NULL));
1487 node->size = strtod(cblistval(elems, 4, NULL), NULL);
1488 if(node->dnum < 0){
1489 node->dnum = -1;
1490 err = TRUE;
1491 }
1492 if(node->wnum < 0){
1493 node->wnum = -1;
1494 err = TRUE;
1495 }
1496 if(node->size < 0.0){
1497 node->size = -1.0;
1498 err = TRUE;
1499 }
1500 } else {
1501 err = TRUE;
1502 }
1503 cblistclose(elems);
1504 } else {
1505 err = TRUE;
1506 }
1507 }
1508 cbdatumclose(resbody);
1509 cblistclose(reqheads);
1510 return err ? FALSE : TRUE;
1511 }
1512
1513
1514 /* Parse the header of a result data.
1515 `nres' specifies a node result object.
1516 `str' specifies the header of a result data. */
1517 static void est_parse_search_header(ESTNODERES *nres, const char *str){
1518 CBLIST *lines;
1519 const char *line, *pv;
1520 int i;
1521 assert(nres && str);
1522 lines = cbsplit(str, -1, "\r\n");
1523 for(i = 0; i < cblistnum(lines); i++){
1524 line = cblistval(lines, i, NULL);
1525 if(!(pv = strchr(line, '\t')) || pv == line || pv[1] == '\0') continue;
1526 cbmapput(nres->hints, line, pv - line, pv + 1, -1, FALSE);
1527 }
1528 cblistclose(lines);
1529 }
1530
1531
1532 /* Parse a body part of a result data.
1533 `nres' specifies a node result object.
1534 `str' specifies a body part of a result data. */
1535 static void est_parse_search_body(ESTNODERES *nres, char *str){
1536 CBMAP *attrs;
1537 char *pv, *ep, *mp;
1538 pv = str;
1539 attrs = cbmapopenex(ESTMINIBNUM);
1540 while(TRUE){
1541 if(!(ep = strchr(pv, '\n')) || ep == pv) break;
1542 *ep = '\0';
1543 cbstrtrim(pv);
1544 if(*pv == '\0') break;
1545 if((mp = strchr(pv, '=')) != NULL){
1546 *mp = '\0';
1547 cbmapput(attrs, pv, -1, mp + 1, -1, TRUE);
1548 }
1549 pv = ep + 1;
1550 }
1551 while(*pv == '\r' || *pv == '\n'){
1552 pv++;
1553 }
1554 est_noderes_add_doc(nres, attrs, cbmemdup(pv, -1));
1555 }
1556
1557
1558
1559 /* END OF FILE */

  ViewVC Help
Powered by ViewVC 1.1.26