/[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

Contents of /upstream/0.5.2/estnode.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (show 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 /*************************************************************************************************
2 * Implementation of the node API
3 * Copyright (C) 2004-2005 Mikio Hirabayashi
4 * This file is part of Hyper Estraier.
5 * Hyper Estraier is free software; you can redistribute it and/or modify it under the terms of
6 * the GNU Lesser General Public License as published by the Free Software Foundation; either
7 * version 2.1 of the License or any later version. Hyper Estraier is distributed in the hope
8 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10 * License for more details.
11 * You should have received a copy of the GNU Lesser General Public License along with Hyper
12 * Estraier; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13 * Boston, MA 02111-1307 USA.
14 *************************************************************************************************/
15
16
17 #include "estraier.h"
18 #include "estmtdb.h"
19 #include "estnode.h"
20 #include "myconf.h"
21
22 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
23 #define socklen_t int
24 #define in_addr_t int
25 #elif defined(_SYS_MACOSX_)
26 #define socklen_t int
27 #endif
28
29 #define ESTNUMBUFSIZ 32 /* size of a buffer for a number */
30 #define ESTPATHBUFSIZ 4096 /* size of a buffer for a path */
31 #define ESTIOBUFSIZ 8192 /* size of a buffer for I/O */
32 #define ESTMINIBNUM 31 /* bucket number of map for attributes */
33 #define ESTLISTUNIT 64 /* allocation unit number of a list */
34 #define ESTDNHOLDSEC 300 /* holding time of domain names */
35 #define ESTDNHOLDNUM 4096 /* holding number of domain names */
36
37 typedef struct { /* type of structure for interaction of a URL */
38 int alive; /* whether to be alive */
39 pthread_cond_t *cond; /* condition variable */
40 const char *url; /* URL */
41 const char *pxhost; /* host name of proxy */
42 int pxport; /* port number of proxy */
43 const char *auth; /* authority */
44 const CBLIST *reqheads; /* request headers */
45 const char *reqbody; /* request body */
46 int rbsiz; /* size of the request body */
47 int *rescodep; /* pointer to a variable for status code */
48 CBMAP *resheads; /* response headers */
49 CBDATUM *resbody; /* response body */
50 } TARGSHUTTLE;
51
52
53 /* private function prototypes */
54 static int est_sock_close(int sock);
55 static int est_inet_aton(const char *cp, struct in_addr *inp);
56 static void *est_url_shuttle_impl(void *targ);
57 static void est_sockpt_down(void *sp);
58 static int est_node_set_info(ESTNODE *node);
59 static void est_parse_search_header(ESTNODERES *nres, const char *str);
60 static void est_parse_search_body(ESTNODERES *nres, char *str);
61
62
63
64 /*************************************************************************************************
65 * API for the network environment
66 *************************************************************************************************/
67
68
69 /* Cache of host addresses */
70 CBMAP *est_host_addrs = NULL;
71
72
73 /* Initialize the networking environment. */
74 int est_init_net_env(void){
75 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
76 WSADATA wsaData;
77 if(est_host_addrs) return TRUE;
78 est_host_addrs = cbmapopenex(ESTDNHOLDNUM + 1);
79 return WSAStartup(MAKEWORD(2,0), &wsaData) == 0;
80 #else
81 if(est_host_addrs) return TRUE;
82 est_host_addrs = cbmapopenex(ESTDNHOLDNUM + 1);
83 return TRUE;
84 #endif
85 }
86
87
88 /* Free the networking environment. */
89 void est_free_net_env(void){
90 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
91 if(!est_host_addrs) return;
92 cbmapclose(est_host_addrs);
93 WSACleanup();
94 #else
95 if(!est_host_addrs) return;
96 cbmapclose(est_host_addrs);
97 #endif
98 }
99
100
101
102 /*************************************************************************************************
103 * API for search result of node
104 *************************************************************************************************/
105
106
107 /* Delete a node result object. */
108 void est_noderes_delete(ESTNODERES *nres){
109 int i;
110 assert(nres);
111 cbmapclose(nres->hints);
112 for(i = nres->top; i < nres->top + nres->dnum; i++){
113 free(nres->docs[i].snippet);
114 cbmapclose(nres->docs[i].attrs);
115 }
116 free(nres->docs);
117 free(nres);
118 }
119
120
121 /* Get a map object for hints of a node result object. */
122 CBMAP *est_noderes_hints(ESTNODERES *nres){
123 assert(nres);
124 return nres->hints;
125 }
126
127
128 /* Get the number of documents in a node result object. */
129 int est_noderes_doc_num(ESTNODERES *nres){
130 assert(nres);
131 return nres->dnum;
132 }
133
134
135 /* Refer a result document object in a node result object. */
136 ESTRESDOC *est_noderes_get_doc(ESTNODERES *nres, int index){
137 assert(nres && index >= 0);
138 if(index >= nres->dnum) return NULL;
139 return nres->docs + (nres->top + index);
140 }
141
142
143 /* Get the URI of a result document object. */
144 const char *est_resdoc_uri(ESTRESDOC *rdoc){
145 assert(rdoc);
146 return rdoc->uri;
147 }
148
149
150 /* Get a list of attribute names of a result document object. */
151 CBLIST *est_resdoc_attr_names(ESTRESDOC *rdoc){
152 CBLIST *names;
153 assert(rdoc);
154 names = cbmapkeys(rdoc->attrs);
155 cblistsort(names);
156 return names;
157 }
158
159
160 /* Get the value of an attribute of a result document object. */
161 const char *est_resdoc_attr(ESTRESDOC *rdoc, const char *name){
162 assert(rdoc && name);
163 return cbmapget(rdoc->attrs, name, -1, NULL);
164 }
165
166
167 /* Get the value of an attribute of a result document object. */
168 const char *est_resdoc_snippet(ESTRESDOC *rdoc){
169 assert(rdoc);
170 return rdoc->snippet;
171 }
172
173
174
175 /*************************************************************************************************
176 * API for node
177 *************************************************************************************************/
178
179
180 /* Create a node connection object. */
181 ESTNODE *est_node_new(const char *url){
182 ESTNODE *node;
183 node = cbmalloc(sizeof(ESTNODE));
184 node->url = cbmemdup(url, -1);
185 node->pxhost = NULL;
186 node->pxport = 0;
187 node->timeout = -1;
188 node->auth = NULL;
189 node->name = NULL;
190 node->label = NULL;
191 node->dnum = -1;
192 node->wnum = -1;
193 node->size = -1.0;
194 node->status = 0;
195 node->heads = cbmapopenex(ESTMINIBNUM);
196 return node;
197 }
198
199
200 /* Destroy a node connection object. */
201 void est_node_delete(ESTNODE *node){
202 assert(node);
203 cbmapclose(node->heads);
204 free(node->label);
205 free(node->name);
206 free(node->auth);
207 free(node->pxhost);
208 free(node->url);
209 free(node);
210 }
211
212
213 /* Get the status code of the last request of a node. */
214 int est_node_status(ESTNODE *node){
215 assert(node);
216 return node->status;
217 }
218
219
220 /* Set the proxy information of a node connection object. */
221 void est_node_set_proxy(ESTNODE *node, const char *host, int port){
222 assert(node && host && port >= 0);
223 free(node->pxhost);
224 node->pxhost = cbmemdup(host, -1);
225 node->pxport = port;
226 }
227
228
229 /* Set timeout of a connection. */
230 void est_node_set_timeout(ESTNODE *node, int sec){
231 assert(node && sec >= 0);
232 node->timeout = sec;
233 }
234
235
236 /* Set the authoririty information of a node connection object. */
237 void est_node_set_auth(ESTNODE *node, const char *name, const char *passwd){
238 assert(node && name && passwd);
239 free(node->auth);
240 node->auth = cbsprintf("%s:%s", name, passwd);
241 }
242
243
244 /* Add a document to a node. */
245 int est_node_put_doc(ESTNODE *node, ESTDOC *doc){
246 CBLIST *reqheads;
247 const char *kbuf;
248 char url[ESTPATHBUFSIZ], *vbuf, *reqbody;
249 int rescode, err, ksiz;
250 assert(node && doc);
251 err = FALSE;
252 sprintf(url, "%s/put_doc", node->url);
253 reqheads = cblistopen();
254 if(cbmaprnum(node->heads) > 0){
255 cbmapiterinit(node->heads);
256 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
257 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
258 cblistpush(reqheads, vbuf, -1);
259 free(vbuf);
260 }
261 }
262 cblistpush(reqheads, "Content-Type: " ESTDRAFTTYPE, -1);
263 reqbody = est_doc_dump_draft(doc);
264 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
265 reqbody, strlen(reqbody), &rescode, NULL, NULL)){
266 node->status = -1;
267 err = TRUE;
268 }
269 if(!err){
270 node->status = rescode;
271 if(rescode != 200) err = TRUE;
272 }
273 free(reqbody);
274 cblistclose(reqheads);
275 return err ? FALSE : TRUE;
276 }
277
278
279 /* Remove a document from a node. */
280 int est_node_out_doc(ESTNODE *node, int id){
281 CBLIST *reqheads;
282 CBDATUM *reqbody;
283 const char *kbuf;
284 char url[ESTPATHBUFSIZ], *vbuf;
285 int rescode, err, ksiz;
286 assert(node && id > 0);
287 err = FALSE;
288 sprintf(url, "%s/out_doc", node->url);
289 reqheads = cblistopen();
290 if(cbmaprnum(node->heads) > 0){
291 cbmapiterinit(node->heads);
292 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
293 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
294 cblistpush(reqheads, vbuf, -1);
295 free(vbuf);
296 }
297 }
298 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
299 reqbody = cbdatumopen("", 0);
300 est_datum_printf(reqbody, "id=%d", id);
301 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
302 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, NULL)){
303 node->status = -1;
304 err = TRUE;
305 }
306 if(!err){
307 node->status = rescode;
308 if(rescode != 200) err = TRUE;
309 }
310 cbdatumclose(reqbody);
311 cblistclose(reqheads);
312 return err ? FALSE : TRUE;
313 }
314
315
316 /* Remove a document specified by URI from a node. */
317 int est_node_out_doc_by_uri(ESTNODE *node, const char *uri){
318 CBLIST *reqheads;
319 CBDATUM *reqbody;
320 const char *kbuf;
321 char url[ESTPATHBUFSIZ], *vbuf;
322 int rescode, err, ksiz;
323 assert(node && uri);
324 err = FALSE;
325 sprintf(url, "%s/out_doc", node->url);
326 reqheads = cblistopen();
327 if(cbmaprnum(node->heads) > 0){
328 cbmapiterinit(node->heads);
329 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
330 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
331 cblistpush(reqheads, vbuf, -1);
332 free(vbuf);
333 }
334 }
335 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
336 reqbody = cbdatumopen("", 0);
337 est_datum_printf(reqbody, "uri=%?", uri);
338 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
339 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, NULL)){
340 node->status = -1;
341 err = TRUE;
342 }
343 if(!err){
344 node->status = rescode;
345 if(rescode != 200) err = TRUE;
346 }
347 cbdatumclose(reqbody);
348 cblistclose(reqheads);
349 return err ? FALSE : TRUE;
350 }
351
352
353 /* Retrieve a document in a node. */
354 ESTDOC *est_node_get_doc(ESTNODE *node, int id){
355 ESTDOC *doc;
356 CBLIST *reqheads;
357 CBDATUM *reqbody, *resbody;
358 const char *kbuf;
359 char url[ESTPATHBUFSIZ], *vbuf;
360 int rescode, err, ksiz;
361 assert(node && id > 0);
362 err = FALSE;
363 sprintf(url, "%s/get_doc", node->url);
364 reqheads = cblistopen();
365 if(cbmaprnum(node->heads) > 0){
366 cbmapiterinit(node->heads);
367 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
368 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
369 cblistpush(reqheads, vbuf, -1);
370 free(vbuf);
371 }
372 }
373 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
374 reqbody = cbdatumopen("", 0);
375 est_datum_printf(reqbody, "id=%d", id);
376 resbody = cbdatumopen("", 0);
377 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
378 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
379 node->status = -1;
380 err = TRUE;
381 }
382 if(!err){
383 node->status = rescode;
384 if(rescode != 200) err = TRUE;
385 }
386 doc = err ? NULL : est_doc_new_from_draft(cbdatumptr(resbody));
387 cbdatumclose(resbody);
388 cbdatumclose(reqbody);
389 cblistclose(reqheads);
390 return doc;
391 }
392
393
394 /* Retrieve a document specified by URI in a node. */
395 ESTDOC *est_node_get_doc_by_uri(ESTNODE *node, const char *uri){
396 ESTDOC *doc;
397 CBLIST *reqheads;
398 CBDATUM *reqbody, *resbody;
399 const char *kbuf;
400 char url[ESTPATHBUFSIZ], *vbuf;
401 int rescode, err, ksiz;
402 assert(node && uri);
403 err = FALSE;
404 sprintf(url, "%s/get_doc", node->url);
405 reqheads = cblistopen();
406 if(cbmaprnum(node->heads) > 0){
407 cbmapiterinit(node->heads);
408 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
409 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
410 cblistpush(reqheads, vbuf, -1);
411 free(vbuf);
412 }
413 }
414 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
415 reqbody = cbdatumopen("", 0);
416 est_datum_printf(reqbody, "uri=%?", uri);
417 resbody = cbdatumopen("", 0);
418 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
419 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
420 node->status = -1;
421 err = TRUE;
422 }
423 if(!err){
424 node->status = rescode;
425 if(rescode != 200) err = TRUE;
426 }
427 doc = err ? NULL : est_doc_new_from_draft(cbdatumptr(resbody));
428 cbdatumclose(resbody);
429 cbdatumclose(reqbody);
430 cblistclose(reqheads);
431 return doc;
432 }
433
434
435 /* Retrieve the value of an attribute of a document in a node. */
436 char *est_node_get_doc_attr(ESTNODE *node, int id, const char *name){
437 CBLIST *reqheads;
438 CBDATUM *reqbody, *resbody;
439 const char *kbuf;
440 char url[ESTPATHBUFSIZ], *vbuf;
441 int rescode, err, ksiz;
442 assert(node && id > 0);
443 err = FALSE;
444 sprintf(url, "%s/get_doc_attr", node->url);
445 reqheads = cblistopen();
446 if(cbmaprnum(node->heads) > 0){
447 cbmapiterinit(node->heads);
448 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
449 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
450 cblistpush(reqheads, vbuf, -1);
451 free(vbuf);
452 }
453 }
454 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
455 reqbody = cbdatumopen("", 0);
456 est_datum_printf(reqbody, "id=%d&attr=%?", id, name);
457 resbody = cbdatumopen("", 0);
458 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
459 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
460 node->status = -1;
461 err = TRUE;
462 }
463 if(!err){
464 node->status = rescode;
465 if(rescode != 200) err = TRUE;
466 }
467 if(err){
468 cbdatumclose(resbody);
469 vbuf = NULL;
470 } else {
471 vbuf = cbdatumtomalloc(resbody, NULL);
472 cbstrtrim(vbuf);
473 }
474 cbdatumclose(reqbody);
475 cblistclose(reqheads);
476 return vbuf;
477 }
478
479
480 /* Retrieve the value of an attribute of a document specified by URI in a node. */
481 char *est_node_get_doc_attr_by_uri(ESTNODE *node, const char *uri, const char *name){
482 CBLIST *reqheads;
483 CBDATUM *reqbody, *resbody;
484 const char *kbuf;
485 char url[ESTPATHBUFSIZ], *vbuf;
486 int rescode, err, ksiz;
487 assert(node && uri);
488 err = FALSE;
489 sprintf(url, "%s/get_doc_attr", node->url);
490 reqheads = cblistopen();
491 if(cbmaprnum(node->heads) > 0){
492 cbmapiterinit(node->heads);
493 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
494 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
495 cblistpush(reqheads, vbuf, -1);
496 free(vbuf);
497 }
498 }
499 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
500 reqbody = cbdatumopen("", 0);
501 est_datum_printf(reqbody, "uri=%?&attr=%?", uri, name);
502 resbody = cbdatumopen("", 0);
503 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
504 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
505 node->status = -1;
506 err = TRUE;
507 }
508 if(!err){
509 node->status = rescode;
510 if(rescode != 200) err = TRUE;
511 }
512 if(err){
513 cbdatumclose(resbody);
514 vbuf = NULL;
515 } else {
516 vbuf = cbdatumtomalloc(resbody, NULL);
517 cbstrtrim(vbuf);
518 }
519 cbdatumclose(reqbody);
520 cblistclose(reqheads);
521 return vbuf;
522 }
523
524
525 /* Get the ID of a document spacified by URI. */
526 int est_node_uri_to_id(ESTNODE *node, const char *uri){
527 CBLIST *reqheads;
528 CBDATUM *reqbody, *resbody;
529 const char *kbuf;
530 char url[ESTPATHBUFSIZ], *vbuf;
531 int rescode, err, ksiz, id;
532 assert(node && uri);
533 err = FALSE;
534 sprintf(url, "%s/uri_to_id", node->url);
535 reqheads = cblistopen();
536 if(cbmaprnum(node->heads) > 0){
537 cbmapiterinit(node->heads);
538 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
539 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
540 cblistpush(reqheads, vbuf, -1);
541 free(vbuf);
542 }
543 }
544 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
545 reqbody = cbdatumopen("", 0);
546 est_datum_printf(reqbody, "uri=%?", uri);
547 resbody = cbdatumopen("", 0);
548 if(!est_url_shuttle(url, node->pxhost, node->pxport, node->timeout, node->auth, reqheads,
549 cbdatumptr(reqbody), cbdatumsize(reqbody), &rescode, NULL, resbody)){
550 node->status = -1;
551 err = TRUE;
552 }
553 if(!err){
554 node->status = rescode;
555 if(rescode != 200) err = TRUE;
556 }
557 id = err ? -1 : atoi(cbdatumptr(resbody));
558 cbdatumclose(resbody);
559 cbdatumclose(reqbody);
560 cblistclose(reqheads);
561 return id;
562 }
563
564
565 /* Get the name of a node. */
566 const char *est_node_name(ESTNODE *node){
567 assert(node);
568 if(node->name) return node->name;
569 est_node_set_info(node);
570 return node->name;
571 }
572
573
574 /* Get the label of a node. */
575 const char *est_node_label(ESTNODE *node){
576 assert(node);
577 if(node->label) return node->label;
578 est_node_set_info(node);
579 return node->label;
580 }
581
582
583 /* Get the number of documents in a node. */
584 int est_node_doc_num(ESTNODE *node){
585 assert(node);
586 if(node->dnum >= 0) return node->dnum;
587 est_node_set_info(node);
588 return node->dnum;
589 }
590
591
592 /* Get the number of words in a node. */
593 int est_node_word_num(ESTNODE *node){
594 assert(node);
595 if(node->wnum >= 0) return node->wnum;
596 est_node_set_info(node);
597 return node->wnum;
598 }
599
600
601 /* Get the size of the datbase of a node. */
602 double est_node_size(ESTNODE *node){
603 assert(node);
604 if(node->size >= 0.0) return node->size;
605 est_node_set_info(node);
606 return node->size;
607 }
608
609
610 /* Search documents corresponding a condition for a node. */
611 ESTNODERES *est_node_search(ESTNODE *node, ESTCOND *cond, int depth){
612 ESTNODERES *nres;
613 const CBLIST *attrs;
614 CBLIST *reqheads;
615 CBDATUM *reqbody, *resbody;
616 const char *kbuf, *phrase, *order;
617 char buf[ESTPATHBUFSIZ], *vbuf, *ptr, *pv, *ep;
618 int i, rescode, err, ksiz, max, plen, part, end;
619 assert(node && cond && depth >= 0);
620 err = FALSE;
621 sprintf(buf, "%s/search", node->url);
622 reqheads = cblistopen();
623 if(cbmaprnum(node->heads) > 0){
624 cbmapiterinit(node->heads);
625 while((kbuf = cbmapiternext(node->heads, &ksiz)) != NULL){
626 vbuf = cbsprintf("%s: %s", kbuf, cbmapget(node->heads, kbuf, ksiz, NULL));
627 cblistpush(reqheads, vbuf, -1);
628 free(vbuf);
629 }
630 }
631 cblistpush(reqheads, "Content-Type: " ESTFORMTYPE, -1);
632 reqbody = cbdatumopen("", 0);
633 if((phrase = est_cond_phrase(cond)) != NULL) est_datum_printf(reqbody, "phrase=%?", phrase);
634 if((attrs = est_cond_attrs(cond)) != NULL){
635 for(i = 0; i < cblistnum(attrs); i++){
636 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
637 est_datum_printf(reqbody, "attr%d=%?", i + 1, cblistval(attrs, i, NULL));
638 }
639 }
640 if((max = est_cond_max(cond)) >= 0){
641 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
642 est_datum_printf(reqbody, "max=%d", max);
643 } else {
644 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
645 est_datum_printf(reqbody, "max=%d", INT_MAX / 2);
646 }
647 if((order = est_cond_order(cond)) != NULL){
648 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
649 est_datum_printf(reqbody, "order=%?", order);
650 }
651 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
652 est_datum_printf(reqbody, "options=%d", est_cond_options(cond));
653 if(cbdatumsize(reqbody) > 0) cbdatumcat(reqbody, "&", 1);
654 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 static int est_node_set_info(ESTNODE *node){
1450 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