/[hyperestraier]/upstream/0.5.2/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

Annotation of /upstream/0.5.2/estnode.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (hide annotations)
Wed Aug 3 15:21:15 2005 UTC (18 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 46266 byte(s)
import upstream version 0.5.2

1 dpavlin 2 /*************************************************************************************************
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 dpavlin 9 static int est_node_set_info(ESTNODE *node);
59 dpavlin 2 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 dpavlin 9 est_node_set_info(node);
570 dpavlin 2 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 dpavlin 9 est_node_set_info(node);
579 dpavlin 2 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 dpavlin 9 est_node_set_info(node);
588 dpavlin 2 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 dpavlin 9 est_node_set_info(node);
597 dpavlin 2 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 dpavlin 9 est_node_set_info(node);
606 dpavlin 2 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 dpavlin 9 est_datum_printf(reqbody, "options=%d", est_cond_options(cond));
653     if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
654 dpavlin 2 est_datum_printf(reqbody, "depth=%d", depth);
655     resbody = cbdatumopen("", 0);
656     if(!est_url_shuttle(buf, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
657     cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
658     node->status = -1;
659     err = TRUE;
660     }
661     if(!err){
662     node->status = rescode;
663     if(rescode != 200) err = TRUE;
664     }
665     if(err){
666     cbdatumclose(resbody);
667     cbdatumclose(reqbody);
668     cblistclose(reqheads);
669     return NULL;
670     }
671     ptr = cbdatumtomalloc(resbody, NULL);
672     if(!(pv = strchr(ptr, '\n')) || pv <= ptr + 3){
673     free(ptr);
674     cbdatumclose(reqbody);
675     cblistclose(reqheads);
676     return NULL;
677     }
678     *pv = '\0';
679     if(pv[-1] == '\r') pv[-1] = '\0';
680     plen = strlen(ptr);
681     pv++;
682     ep = pv;
683     nres = est_noderes_new();
684     part = 0;
685     end = FALSE;
686     while(*ep != '\0'){
687     if(*ep == *ptr && cbstrfwmatch(ep, ptr) && ep[-1] == '\n' &&
688     (ep[plen] == '\r' || ep[plen] == '\n' || ep[plen] == ':')){
689     *ep = '\0';
690     if(part == 0){
691     est_parse_search_header(nres, pv);
692     } else {
693     est_parse_search_body(nres, pv);
694     }
695     ep += plen;
696     if(cbstrfwmatch(ep, ":END")){
697     end = TRUE;
698     break;
699     }
700     if(*ep == '\r') ep++;
701     if(*ep == '\n') ep++;
702     pv = ep;
703     part++;
704     } else {
705     ep++;
706     }
707     }
708     free(ptr);
709     cbdatumclose(reqbody);
710     cblistclose(reqheads);
711     if(!end){
712     est_noderes_delete(nres);
713     return NULL;
714     }
715     return nres;
716     }
717    
718    
719     /* Manage a user account of a node. */
720     int est_node_set_user(ESTNODE *node, const char *name, int mode){
721     CBLIST *reqheads;
722     CBDATUM *reqbody, *resbody;
723     const char *kbuf;
724     char url[ESTPATHBUFSIZ], *vbuf;
725     int rescode, err, ksiz;
726     assert(node && name);
727     err = FALSE;
728     sprintf(url, "%s/_set_user", node->url);
729     reqheads = cblistopen();
730     if(cbmaprnum(node->heads) > 0){
731     cbmapiterinit(node->heads);
732     while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
733     vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
734     cblistpush(reqheads, vbuf, -1);
735     free(vbuf);
736     }
737     }
738     cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
739     reqbody = cbdatumopen("", 0);
740     est_datum_printf(reqbody, "name=%?&mode=%d", name, mode);
741     resbody = cbdatumopen("", 0);
742     if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
743     cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
744     node->status = -1;
745     err = TRUE;
746     }
747     if(!err){
748     node->status = rescode;
749     if(rescode != 200) err = TRUE;
750     }
751     cbdatumclose(resbody);
752     cbdatumclose(reqbody);
753     cblistclose(reqheads);
754     return err ? FALSE : TRUE;
755     }
756    
757    
758     /* Manage a link of a node. */
759     int est_node_set_link(ESTNODE *node, const char *url, const char *label, int credit){
760     CBLIST *reqheads;
761     CBDATUM *reqbody, *resbody;
762     const char *kbuf;
763     char myurl[ESTPATHBUFSIZ], *vbuf;
764     int rescode, err, ksiz;
765     assert(node && url && label);
766     err = FALSE;
767     sprintf(myurl, "%s/_set_link", node->url);
768     reqheads = cblistopen();
769     if(cbmaprnum(node->heads) > 0){
770     cbmapiterinit(node->heads);
771     while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
772     vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
773     cblistpush(reqheads, vbuf, -1);
774     free(vbuf);
775     }
776     }
777     cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
778     reqbody = cbdatumopen("", 0);
779     if(credit >= 0){
780     est_datum_printf(reqbody, "url=%?&label=%?&credit=%d", url, label, credit);
781     } else {
782     est_datum_printf(reqbody, "url=%?&label=%?", url, label);
783     }
784     resbody = cbdatumopen("", 0);
785     if(!est_url_shuttle(myurl, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
786     cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
787     node->status = -1;
788     err = TRUE;
789     }
790     if(!err){
791     node->status = rescode;
792     if(rescode != 200) err = TRUE;
793     }
794     cbdatumclose(resbody);
795     cbdatumclose(reqbody);
796     cblistclose(reqheads);
797     return err ? FALSE : TRUE;
798     }
799    
800    
801    
802     /*************************************************************************************************
803     * features for experts
804     *************************************************************************************************/
805    
806    
807     /* Get the name of this host. */
808     const char *est_get_host_name(void){
809     static char host[ESTPATHBUFSIZ];
810     static int first = TRUE;
811     if(!est_host_addrs) return "127.0.0.1";
812     if(first){
813     first = FALSE;
814     if(gethostname(host, ESTPATHBUFSIZ - 1) == -1) return "127.0.0.1";
815     return host;
816     }
817     return host;
818     }
819    
820    
821     /* Get the address of a host. */
822     char *est_get_host_addr(const char *name){
823     static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
824     struct hostent *info;
825     const char *addr;
826     char *buf, *pv, vbuf[64];
827     int i, ost, nsiz, asiz, vsiz;
828     assert(name);
829     if(!est_host_addrs) return NULL;
830     if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ost) != 0) return NULL;
831     if(pthread_mutex_lock(&mymutex) != 0){
832     pthread_setcancelstate(ost, NULL);
833     return NULL;
834     }
835     nsiz = strlen(name);
836     buf = NULL;
837     if((addr = cbmapget(est_host_addrs, name, nsiz, &asiz)) != NULL){
838     buf = cbmemdup(addr, asiz);
839     if((pv = strchr(buf, '\t')) != NULL){
840     *pv = '\0';
841     if((int)time(NULL) - atoi(pv + 1) > ESTDNHOLDSEC){
842     free(buf);
843     buf = NULL;
844     }
845     }
846     cbmapmove(est_host_addrs, name, nsiz, FALSE);
847     }
848     pthread_mutex_unlock(&mymutex);
849     pthread_setcancelstate(ost, NULL);
850     if(buf){
851     if(buf[0] != '\0') return buf;
852     free(buf);
853     return NULL;
854     }
855     if((info = gethostbyname(name)) != NULL && info->h_addr_list[0]){
856     addr = inet_ntoa(*(struct in_addr *)info->h_addr_list[0]);
857     } else {
858     addr = NULL;
859     }
860     buf = addr ? cbmemdup(addr, -1) : NULL;
861     if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ost) == 0){
862     if(pthread_mutex_lock(&mymutex) == 0){
863     vsiz = sprintf(vbuf, "%s\t%d", addr ? addr : "", (int)time(NULL));
864     cbmapput(est_host_addrs, name, nsiz, vbuf, vsiz, TRUE);
865     if(cbmaprnum(est_host_addrs) > ESTDNHOLDNUM){
866     cbmapiterinit(est_host_addrs);
867     for(i = 0; i < ESTDNHOLDNUM / 4 &&
868     (addr = cbmapiternext(est_host_addrs, &asiz)) != NULL; i++){
869     cbmapout(est_host_addrs, addr, asiz);
870     }
871     }
872     pthread_mutex_unlock(&mymutex);
873     }
874     pthread_setcancelstate(ost, NULL);
875     }
876     return buf;
877     }
878    
879    
880     /* Get a server socket of an address and a port. */
881     int est_get_server_sock(const char *addr, int port){
882     struct sockaddr_in address;
883     struct linger li;
884     int ost, sock, optone;
885     assert(port > 0);
886     if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ost) != 0) return -1;
887     memset(&address, 0, sizeof(address));
888     address.sin_family = AF_INET;
889     if(!est_inet_aton(addr ? addr : "0.0.0.0", &address.sin_addr)){
890     pthread_setcancelstate(ost, NULL);
891     return -1;
892     }
893     address.sin_port = htons(port);
894     if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){
895     pthread_setcancelstate(ost, NULL);
896     return -1;
897     }
898     li.l_onoff = 1;
899     li.l_linger = 100;
900     optone = 1;
901     if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&li, sizeof(li)) == -1 ||
902     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&optone, sizeof(optone)) == -1){
903     est_sock_close(sock);
904     pthread_setcancelstate(ost, NULL);
905     return -1;
906     }
907     if(bind(sock, (struct sockaddr *)&address, sizeof(address)) == -1 ||
908     listen(sock, SOMAXCONN) == -1){
909     est_sock_close(sock);
910     pthread_setcancelstate(ost, NULL);
911     return -1;
912     }
913     pthread_setcancelstate(ost, NULL);
914     return sock;
915     }
916    
917    
918     /* Accept a connection from a client. */
919     int est_accept_conn(int sock, char *abuf, int *pp){
920     struct sockaddr_in address;
921     socklen_t socklen;
922     int clsock;
923     assert(sock >= 0);
924     socklen = sizeof(address);
925     if((clsock = accept(sock, (struct sockaddr *)&address, &socklen)) >= 0){
926     if(abuf) sprintf(abuf, "%s", inet_ntoa(address.sin_addr));
927     if(pp) *pp = (int)ntohs(address.sin_port);
928     return clsock;
929     }
930     return (errno == EINTR || errno == EAGAIN) ? 0 : -1;
931     }
932    
933    
934     /* Get a client socket to an address and a port. */
935     int est_get_client_sock(const char *addr, int port){
936     struct sockaddr_in address;
937     struct linger li;
938     int ost, sock;
939     assert(addr && port >= 0);
940     if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ost) != 0) return -1;
941     memset(&address, 0, sizeof(address));
942     address.sin_family = AF_INET;
943     if(!est_inet_aton(addr, &address.sin_addr)){
944     pthread_setcancelstate(ost, NULL);
945     return -1;
946     }
947     address.sin_port = htons(port);
948     if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){
949     pthread_setcancelstate(ost, NULL);
950     return -1;
951     }
952     li.l_onoff = 1;
953     li.l_linger = 100;
954     if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&li, sizeof(li)) == -1){
955     est_sock_close(sock);
956     pthread_setcancelstate(ost, NULL);
957     return -1;
958     }
959     if(connect(sock, (struct sockaddr *)&address, sizeof(address)) == -1){
960     est_sock_close(sock);
961     pthread_setcancelstate(ost, NULL);
962     return -1;
963     }
964     pthread_setcancelstate(ost, NULL);
965     return sock;
966     }
967    
968    
969     /* Shutdown and close a socket. */
970     void est_sock_down(int sock){
971     assert(sock >= 0);
972     shutdown(sock, 2);
973     est_sock_close(sock);
974     }
975    
976    
977     /* Receive all data from a socket. */
978     char *est_sock_recv_all(int sock, int len){
979     char *buf;
980     int i, bs;
981     assert(sock >= 0 && len >= 0);
982     buf = cbmalloc(len + 1);
983     for(i = 0; i < len && (bs = recv(sock, buf + i, len - i, 0)) != 0; i += bs){
984     if(bs == -1 && errno != EINTR){
985     free(buf);
986     return NULL;
987     }
988     }
989     buf[i] = '\0';
990     return buf;
991     }
992    
993    
994     /* Receive a line from a socket. */
995     int est_sock_recv_line(int sock, char *buf, int max){
996     char *wp;
997     assert(sock >= 0 && buf && max > 0);
998     max--;
999     wp = buf;
1000     while(wp < buf + max){
1001     switch(recv(sock, wp, 1, 0)){
1002     case -1:
1003     if(errno != EINTR){
1004     *wp = '\0';
1005     return wp - buf;
1006     }
1007     break;
1008     case 0:
1009     *wp = '\0';
1010     return wp - buf;
1011     default:
1012     switch(*wp){
1013     case '\r':
1014     break;
1015     case '\n':
1016     *wp = '\0';
1017     return wp - buf;
1018     default:
1019     wp++;
1020     break;
1021     }
1022     break;
1023     }
1024     }
1025     *wp = '\0';
1026     return wp - buf;
1027     }
1028    
1029    
1030     /* Receive void data from a socket. */
1031     void est_sock_recv_void(int sock){
1032     fd_set rfds;
1033     struct timeval tv;
1034     char ibuf[ESTIOBUFSIZ];
1035     assert(sock >= 0);
1036     FD_ZERO(&rfds);
1037     FD_SET(sock, &rfds);
1038     tv.tv_sec = 0;
1039     tv.tv_usec = 0;
1040     if(select(sock + 1, &rfds, NULL, NULL, &tv) > 0 && FD_ISSET(sock, &rfds))
1041     recv(sock, ibuf, ESTIOBUFSIZ, 0);
1042     }
1043    
1044    
1045     /* Write all data into a socket. */
1046     void est_sock_send_all(int sock, const char *buf, int len){
1047     const char *rp;
1048     int rv, wb;
1049     assert(sock >= 0 && buf && len >= 0);
1050     rp = buf;
1051     rv = 0;
1052     do {
1053     wb = send(sock, rp, len, 0);
1054     switch(wb){
1055     case -1: if(errno != EINTR) return;
1056     case 0: break;
1057     default:
1058     rp += wb;
1059     len -= wb;
1060     rv += wb;
1061     break;
1062     }
1063     } while(len > 0);
1064     }
1065    
1066    
1067     /* Perform formatted output into a datum object. */
1068     void est_datum_printf(CBDATUM *datum, const char *format, ...){
1069     va_list ap;
1070     char *tmp, cbuf[ESTNUMBUFSIZ], tbuf[ESTNUMBUFSIZ*2];
1071     unsigned char c;
1072     int cblen, tlen;
1073     assert(datum && format);
1074     va_start(ap, format);
1075     while(*format != '\0'){
1076     if(*format == '%'){
1077     cbuf[0] = '%';
1078     cblen = 1;
1079     format++;
1080     while(strchr("0123456789 .+-", *format) && *format != '\0' && cblen < ESTNUMBUFSIZ - 1){
1081     cbuf[cblen++] = *format;
1082     format++;
1083     }
1084     cbuf[cblen++] = *format;
1085     cbuf[cblen] = '\0';
1086     switch(*format){
1087     case 's':
1088     tmp = va_arg(ap, char *);
1089     if(!tmp) tmp = "(null)";
1090     cbdatumcat(datum, tmp, -1);
1091     break;
1092     case 'd':
1093     tlen = sprintf(tbuf, cbuf, va_arg(ap, int));
1094     cbdatumcat(datum, tbuf, tlen);
1095     break;
1096     case 'o': case 'u': case 'x': case 'X': case 'c':
1097     tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned int));
1098     cbdatumcat(datum, tbuf, tlen);
1099     break;
1100     case 'e': case 'E': case 'f': case 'g': case 'G':
1101     tlen = sprintf(tbuf, cbuf, va_arg(ap, double));
1102     cbdatumcat(datum, tbuf, tlen);
1103     break;
1104     case '@':
1105     tmp = va_arg(ap, char *);
1106     if(!tmp) tmp = "(null)";
1107     while(*tmp){
1108     switch(*tmp){
1109     case '&': cbdatumcat(datum, "&amp;", 5); break;
1110     case '<': cbdatumcat(datum, "&lt;", 4); break;
1111     case '>': cbdatumcat(datum, "&gt;", 4); break;
1112     case '"': cbdatumcat(datum, "&quot;", 6); break;
1113     default:
1114     if(!((*tmp >= 0 && *tmp <= 0x8) || (*tmp >= 0x0e && *tmp <= 0x1f)))
1115     cbdatumcat(datum, tmp, 1);
1116     break;
1117     }
1118     tmp++;
1119     }
1120     break;
1121     case '?':
1122     tmp = va_arg(ap, char *);
1123     if(!tmp) tmp = "(null)";
1124     while(*tmp){
1125     c = *(unsigned char *)tmp;
1126     if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
1127     (c >= '0' && c <= '9') || (c != '\0' && strchr("_-.", c))){
1128     cbdatumcat(datum, tmp, 1);
1129     } else {
1130     tlen = sprintf(tbuf, "%%%02X", c);
1131     cbdatumcat(datum, tbuf, tlen);
1132     }
1133     tmp++;
1134     }
1135     break;
1136     case '%':
1137     cbdatumcat(datum, "%", 1);
1138     break;
1139     }
1140     } else {
1141     cbdatumcat(datum, format, 1);
1142     }
1143     format++;
1144     }
1145     va_end(ap);
1146     }
1147    
1148    
1149     /* Perform an interaction of a URL. */
1150     int est_url_shuttle(const char *url, const char *pxhost, int pxport, int outsec,
1151     const char *auth, const CBLIST *reqheads, const char *reqbody, int rbsiz,
1152     int *rescodep, CBMAP *resheads, CBDATUM *resbody){
1153     pthread_t th;
1154     pthread_mutex_t mutex;
1155     pthread_cond_t cond;
1156     struct timespec timeout;
1157     TARGSHUTTLE targ;
1158     int err, rv;
1159     void *rvp;
1160     pthread_mutex_init(&mutex, NULL);
1161     pthread_cond_init(&cond, NULL);
1162     targ.alive = TRUE;
1163     targ.cond = &cond;
1164     targ.url = url;
1165     targ.pxhost = pxhost;
1166     targ.pxport = pxport;
1167     targ.auth = auth;
1168     targ.reqheads = reqheads;
1169     targ.reqbody = reqbody;
1170     targ.rbsiz = rbsiz;
1171     targ.rescodep = rescodep;
1172     targ.resheads = resheads;
1173     targ.resbody = resbody;
1174     err = FALSE;
1175     if(outsec >= 0){
1176     if(pthread_mutex_lock(&mutex) == 0){
1177     if(pthread_create(&th, NULL, est_url_shuttle_impl, &targ) == 0){
1178     timeout.tv_sec = time(NULL) + outsec;
1179     timeout.tv_nsec = 1000 * 1000 * 500;
1180     rv = 0;
1181     while(targ.alive && rv != ETIMEDOUT){
1182     rv = pthread_cond_timedwait(&cond, &mutex, &timeout);
1183     }
1184     if(rv == ETIMEDOUT){
1185     pthread_cancel(th);
1186     pthread_join(th, NULL);
1187     err = TRUE;
1188     } else if(pthread_join(th, &rvp) != 0 || rvp != NULL){
1189     err = TRUE;
1190     }
1191     } else {
1192     err = TRUE;
1193     }
1194     pthread_mutex_unlock(&mutex);
1195     } else {
1196     err = TRUE;
1197     }
1198     } else {
1199     if(est_url_shuttle_impl(&targ) != NULL) err = TRUE;
1200     }
1201     if(pthread_mutex_destroy(&mutex) != 0) err = TRUE;
1202     if(pthread_cond_destroy(&cond) != 0) err = TRUE;
1203     return err ? FALSE : TRUE;
1204     }
1205    
1206    
1207     /* Add a header to a node connection object. */
1208     void est_node_add_header(ESTNODE *node, const char *name, const char *value){
1209     const char *vbuf;
1210     int len;
1211     assert(node && name);
1212     len = strlen(name);
1213     if(value){
1214     if((vbuf = cbmapget(node->heads, name, len, NULL)) != NULL){
1215     cbmapputcat(node->heads, name, len, ", ", 2);
1216     cbmapputcat(node->heads, name, len, value, -1);
1217     } else {
1218     cbmapput(node->heads, name, len, value, -1, FALSE);
1219     }
1220     } else {
1221     cbmapout(node->heads, name, len);
1222     }
1223     }
1224    
1225    
1226     /* Create a node result object. */
1227     ESTNODERES *est_noderes_new(void){
1228     ESTNODERES *nres;
1229     nres = cbmalloc(sizeof(ESTNODERES));
1230     nres->top = 0;
1231     nres->max = ESTLISTUNIT;
1232     nres->docs = cbmalloc(sizeof(ESTRESDOC) * nres->max);
1233     nres->dnum = 0;
1234     nres->hints = cbmapopenex(ESTMINIBNUM);
1235     return nres;
1236     }
1237    
1238    
1239     /* Add a document information to a node result object. */
1240     void est_noderes_add_doc(ESTNODERES *nres, CBMAP *attrs, char *snippet){
1241     const char *uri;
1242     assert(nres && attrs && snippet);
1243     if(!(uri = cbmapget(attrs, ESTDATTRURI, -1, NULL))){
1244     free(snippet);
1245     cbmapclose(attrs);
1246     return;
1247     }
1248     if(nres->top + nres->dnum >= nres->max){
1249     nres->max *= 2;
1250     nres->docs = cbrealloc(nres->docs, nres->max * sizeof(ESTRESDOC));
1251     }
1252     nres->docs[nres->top+nres->dnum].uri = uri;
1253     nres->docs[nres->top+nres->dnum].attrs = attrs;
1254     nres->docs[nres->top+nres->dnum].snippet = snippet;
1255     nres->dnum++;
1256     }
1257    
1258    
1259     /* Remove the top of result document objects in a node result object. */
1260     int est_noderes_shift(ESTNODERES *nres, CBMAP **attrp, char **snippetp){
1261     assert(nres && attrp && snippetp);
1262     if(nres->dnum < 1) return FALSE;
1263     *attrp = nres->docs[nres->top].attrs;
1264     *snippetp = nres->docs[nres->top].snippet;
1265     nres->top++;
1266     nres->dnum--;
1267     return TRUE;
1268     }
1269    
1270    
1271    
1272     /*************************************************************************************************
1273     * private objects
1274     *************************************************************************************************/
1275    
1276    
1277     /* Close a socket.
1278     `sock' specifies a socket.
1279     The return value is 0 if success, else it is -1. */
1280     static int est_sock_close(int sock){
1281     #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1282     assert(sock >= 0);
1283     return closesocket(sock);
1284     #else
1285     assert(sock >= 0);
1286     return close(sock);
1287     #endif
1288     }
1289    
1290    
1291     /* Convert a host address to network binary data.
1292     `cp' specifies a host address.
1293     `inp' specifies the pointer to an structure into which the result is to be stored.
1294     The return value is true if success, else it is false. */
1295     static int est_inet_aton(const char *cp, struct in_addr *inp){
1296     #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1297     in_addr_t in;
1298     assert(cp && inp);
1299     if((in = inet_addr(cp)) == INADDR_NONE){
1300     if(!strcmp(cp, "255.255.255.255")){
1301     inp->s_addr = in;
1302     return TRUE;
1303     }
1304     return FALSE;
1305     }
1306     inp->s_addr = in;
1307     return TRUE;
1308     #else
1309     assert(cp && inp);
1310     return inet_aton(cp, inp);
1311     #endif
1312     }
1313    
1314    
1315     /* Perform the communication which can be canceled.
1316     `targ' specifies the pointer to a closure arguments.
1317     The return value is `NULL' if sucessful or non `NULL' value on error. */
1318     static void *est_url_shuttle_impl(void *targ){
1319     const CBLIST *reqheads;
1320     CBMAP *resheads, *elems;
1321     CBDATUM *resbody, *datum;
1322     const char *url, *pxhost, *auth, *reqbody, *tmp, *scheme, *host, *path, *query, *rp;
1323     char *addr, *enc, iobuf[ESTIOBUFSIZ], name[ESTIOBUFSIZ], *pv;
1324     int i, pxport, rbsiz, *rescodep, port, sock, *sp, size, nsiz;
1325     assert(targ);
1326     url = ((TARGSHUTTLE *)targ)->url;
1327     pxhost = ((TARGSHUTTLE *)targ)->pxhost;
1328     pxport = ((TARGSHUTTLE *)targ)->pxport;
1329     auth = ((TARGSHUTTLE *)targ)->auth;
1330     reqheads = ((TARGSHUTTLE *)targ)->reqheads;
1331     reqbody = ((TARGSHUTTLE *)targ)->reqbody;
1332     rbsiz = ((TARGSHUTTLE *)targ)->rbsiz;
1333     rescodep = ((TARGSHUTTLE *)targ)->rescodep;
1334     resheads = ((TARGSHUTTLE *)targ)->resheads;
1335     resbody = ((TARGSHUTTLE *)targ)->resbody;
1336     elems = cburlbreak(url);
1337     pthread_cleanup_push((void (*)(void *))cbmapclose, elems);
1338     scheme = cbmapget(elems, "scheme", -1, NULL);
1339     host = cbmapget(elems, "host", -1, NULL);
1340     port = (tmp = cbmapget(elems, "port", -1, NULL)) ? atoi(tmp) : 80;
1341     if(!auth) auth = cbmapget(elems, "authority", -1, NULL);
1342     if(!(path = cbmapget(elems, "path", -1, NULL))) path = "/";
1343     if(!(query = cbmapget(elems, "query", -1, NULL))) query = "";
1344     if(!scheme || cbstricmp(scheme, "http") || !host || port < 1 ||
1345     !(addr = est_get_host_addr(pxhost ? pxhost : host))){
1346     ((TARGSHUTTLE *)targ)->alive = FALSE;
1347     pthread_cond_signal(((TARGSHUTTLE *)targ)->cond);
1348     return "error";
1349     }
1350     pthread_cleanup_push((void (*)(void *))free, addr);
1351     if((sock = est_get_client_sock(addr, pxhost ? pxport : port)) == -1){
1352     ((TARGSHUTTLE *)targ)->alive = FALSE;
1353     pthread_cond_signal(((TARGSHUTTLE *)targ)->cond);
1354     return "error";
1355     }
1356     sp = cbmalloc(sizeof(int));
1357     *sp = sock;
1358     pthread_cleanup_push((void (*)(void *))est_sockpt_down, sp);
1359     datum = cbdatumopen("", 0);
1360     pthread_cleanup_push((void (*)(void *))cbdatumclose, datum);
1361     if(pxhost){
1362     est_datum_printf(datum, "%s %s HTTP/1.0\r\n", reqbody ? "POST" : "GET", url);
1363     } else if(reqbody){
1364     est_datum_printf(datum, "POST %s HTTP/1.0\r\n", path);
1365     } else if(query[0] != 0){
1366     est_datum_printf(datum, "GET %s?%s HTTP/1.0\r\n", path, query);
1367     } else {
1368     est_datum_printf(datum, "GET %s HTTP/1.0\r\n", path);
1369     }
1370     est_datum_printf(datum, "Host: %s:%d\r\n", host, port);
1371     est_datum_printf(datum, "Connection: close\r\n", path);
1372     est_datum_printf(datum, "User-Agent: %s/%s\r\n", ESTAGENTNAME, est_version);
1373     if(auth){
1374     enc = cbbaseencode(auth, -1);
1375     est_datum_printf(datum, "Authorization: Basic %s\r\n", enc);
1376     free(enc);
1377     }
1378     if(reqbody) est_datum_printf(datum, "Content-Length: %d\r\n", rbsiz);
1379     if(reqheads){
1380     for(i = 0; i < cblistnum(reqheads); i++){
1381     rp = cblistval(reqheads, i, &size);
1382     est_datum_printf(datum, rp, size);
1383     est_datum_printf(datum, "\r\n", 2);
1384     }
1385     }
1386     est_datum_printf(datum, "\r\n");
1387     est_sock_send_all(sock, cbdatumptr(datum), cbdatumsize(datum));
1388     if(reqbody) est_sock_send_all(sock, reqbody, rbsiz);
1389     if((size = est_sock_recv_line(sock, iobuf, ESTIOBUFSIZ - 1)) < 1 ||
1390     !cbstrfwmatch(iobuf, "HTTP/") || !(rp = strchr(iobuf, ' '))){
1391     ((TARGSHUTTLE *)targ)->alive = FALSE;
1392     pthread_cond_signal(((TARGSHUTTLE *)targ)->cond);
1393     return "error";
1394     }
1395     rp++;
1396     if(rescodep) *rescodep = atoi(rp);
1397     if(resheads) cbmapput(resheads, "", 0, iobuf, size, TRUE);
1398     name[0] = '\0';
1399     nsiz = 0;
1400     while((size = est_sock_recv_line(sock, iobuf, ESTIOBUFSIZ - 1)) > 0){
1401     if(resheads){
1402     if(iobuf[0] == ' ' || iobuf[0] == '\t'){
1403     if(name[0] != '\0'){
1404     iobuf[0] = ' ';
1405     cbmapputcat(resheads, name, nsiz, iobuf, size);
1406     }
1407     } else if((rp = strchr(iobuf, ':')) > iobuf){
1408     nsiz = rp - iobuf;
1409     memcpy(name, iobuf, nsiz);
1410     name[nsiz] = '\0';
1411     for(pv = name; *pv != '\0'; pv++){
1412     if(*pv >= 'A'&& *pv <= 'Z') *pv = *pv + ('a' - 'A');
1413     }
1414     rp++;
1415     if(*rp == ' ' || *rp == '\t') rp++;
1416     if(cbmapget(resheads, name, nsiz, NULL)){
1417     cbmapputcat(resheads, name, nsiz, ", ", 2);
1418     cbmapputcat(resheads, name, nsiz, pv, -1);
1419     } else {
1420     cbmapput(resheads, name, nsiz, rp, -1, TRUE);
1421     }
1422     }
1423     }
1424     }
1425     while((size = recv(sock, iobuf, ESTIOBUFSIZ, 0)) > 0){
1426     if(resbody) cbdatumcat(resbody, iobuf, size);
1427     }
1428     pthread_cleanup_pop(1);
1429     pthread_cleanup_pop(1);
1430     pthread_cleanup_pop(1);
1431     pthread_cleanup_pop(1);
1432     ((TARGSHUTTLE *)targ)->alive = FALSE;
1433     pthread_cond_signal(((TARGSHUTTLE *)targ)->cond);
1434     return NULL;
1435     }
1436    
1437    
1438     /* Release the socket of a pointer.
1439     `sp' specifies the pointer to a variable of a file descriptor. */
1440     static void est_sockpt_down(void *sp){
1441     est_sock_down(*(int *)sp);
1442     free(sp);
1443     }
1444    
1445    
1446     /* Set meta informations of a node.
1447     `node' specifies a node connection object.
1448     The return value is true if success, else it is false. */
1449 dpavlin 9 static int est_node_set_info(ESTNODE *node){
1450 dpavlin 2 CBLIST *reqheads, *elems;
1451     CBDATUM *resbody;
1452     const char *kbuf, *ptr;
1453     char url[ESTPATHBUFSIZ], *vbuf, *pv;
1454     int rescode, err, ksiz;
1455     assert(node);
1456     err = FALSE;
1457     sprintf(url, "%s/inform", node->url);
1458     reqheads = cblistopen();
1459     if(cbmaprnum(node->heads) > 0){
1460     cbmapiterinit(node->heads);
1461     while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
1462     vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
1463     cblistpush(reqheads, vbuf, -1);
1464     free(vbuf);
1465     }
1466     }
1467     node->dnum = -1;
1468     node->wnum = -1;
1469     node->size = -1.0;
1470     resbody = cbdatumopen("", 0);
1471     if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
1472     NULL, -1, &rescode, NULL, resbody)){
1473     node->status = -1;
1474     err = TRUE;
1475     }
1476     if(!err){
1477     node->status = rescode;
1478     if(rescode != 200) err = TRUE;
1479     }
1480     if(!err){
1481     ptr = cbdatumptr(resbody);
1482     if((pv = strchr(ptr, '\n')) != NULL){
1483     elems = cbsplit(ptr, pv - ptr, "\t");
1484     if(cblistnum(elems) == 5){
1485     if(!node->name) node->name = cbmemdup(cblistval(elems, 0, NULL), -1);
1486     if(!node->label) node->label = cbmemdup(cblistval(elems, 1, NULL), -1);
1487     node->dnum = atoi(cblistval(elems, 2, NULL));
1488     node->wnum = atoi(cblistval(elems, 3, NULL));
1489     node->size = strtod(cblistval(elems, 4, NULL), NULL);
1490     if(node->dnum < 0){
1491     node->dnum = -1;
1492     err = TRUE;
1493     }
1494     if(node->wnum < 0){
1495     node->wnum = -1;
1496     err = TRUE;
1497     }
1498     if(node->size < 0.0){
1499     node->size = -1.0;
1500     err = TRUE;
1501     }
1502     } else {
1503     err = TRUE;
1504     }
1505     cblistclose(elems);
1506     } else {
1507     err = TRUE;
1508     }
1509     }
1510     cbdatumclose(resbody);
1511     cblistclose(reqheads);
1512     return err ? FALSE : TRUE;
1513     }
1514    
1515    
1516     /* Parse the header of a result data.
1517     `nres' specifies a node result object.
1518     `str' specifies the header of a result data. */
1519     static void est_parse_search_header(ESTNODERES *nres, const char *str){
1520     CBLIST *lines;
1521     const char *line, *pv;
1522     int i;
1523     assert(nres && str);
1524     lines = cbsplit(str, -1, "\r\n");
1525     for(i = 0; i < cblistnum(lines); i++){
1526     line = cblistval(lines, i, NULL);
1527     if(!(pv = strchr(line, '\t')) || pv == line || pv[1] == '\0') continue;
1528     cbmapput(nres->hints, line, pv - line, pv + 1, -1, FALSE);
1529     }
1530     cblistclose(lines);
1531     }
1532    
1533    
1534     /* Parse a body part of a result data.
1535     `nres' specifies a node result object.
1536     `str' specifies a body part of a result data. */
1537     static void est_parse_search_body(ESTNODERES *nres, char *str){
1538     CBMAP *attrs;
1539     char *pv, *ep, *mp;
1540     pv = str;
1541     attrs = cbmapopenex(ESTMINIBNUM);
1542     while(TRUE){
1543     if(!(ep = strchr(pv, '\n')) || ep == pv) break;
1544     *ep = '\0';
1545     cbstrtrim(pv);
1546     if(*pv == '\0') break;
1547     if((mp = strchr(pv, '=')) != NULL){
1548     *mp = '\0';
1549     cbmapput(attrs, pv, -1, mp + 1, -1, TRUE);
1550     }
1551     pv = ep + 1;
1552     }
1553     while(*pv == '\r' || *pv == '\n'){
1554     pv++;
1555     }
1556     est_noderes_add_doc(nres, attrs, cbmemdup(pv, -1));
1557     }
1558    
1559    
1560    
1561     /* END OF FILE */

  ViewVC Help
Powered by ViewVC 1.1.26