/[hyperestraier]/upstream/0.5.0/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 /upstream/0.5.0/estnode.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Fri Jul 29 21:52:03 2005 UTC (18 years, 10 months ago) by dpavlin
File MIME type: text/plain
File size: 45670 byte(s)
import of HyperEstraier 0.5.0

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

  ViewVC Help
Powered by ViewVC 1.1.26