Statistics
| Branch: | Revision:

napa-baselibs / ALTOclient / ALTOclient.c @ 2d0a8d58

History | View | Annotate | Download (37 KB)

1
/*
2
 ============================================================================
3
 Name        : ALTOclient.c
4
 Author      : T. Ewald <ewald@nw.neclab.eu>
5
 Version     : 243
6
 Proprietary : NEC Europe Ltd. PROPRIETARY INFORMATION
7
                           This software is supplied under the terms of a license
8
                           agreement or nondisclosure agreement with NEC Europe Ltd. and
9
                           may not be copied or disclosed except in accordance with the
10
                           terms of that agreement. The software and its source code
11
                           contain valuable trade secrets and confidential information
12
                           which have to be maintained in confidence.
13
                           Any unauthorized publication, transfer to third parties or
14
                           duplication of the object or source code - either totally or in
15
                           part - is prohibited.
16
 Copyright         : Copyright (c) 2004 NEC Europe Ltd. All Rights Reserved.
17
                           NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR
18
                           IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF
19
                           MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND THE
20
                           WARRANTY AGAINST LATENT DEFECTS, WITH RESPECT TO THE PROGRAM
21
                           AND THE ACCOMPANYING DOCUMENTATION.
22
                           No Liability For Consequential Damages IN NO EVENT SHALL NEC
23
                           Europe Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE
24
                           LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION,
25
                           DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS
26
                           OF INFORMATION, OR OTHER PECUNIARY LOSS AND INDIRECT,
27
                           CONSEQUENTIAL, INCIDENTAL, ECONOMIC OR PUNITIVE DAMAGES) ARISING
28
                           OUT OF THE USE OF OR INABILITY TO USE THIS PROGRAM, EVEN IF NEC
29
                           Europe Ltd. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
30
 Modification: THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
31
 Description : First try of the ALTO client
32
 ============================================================================
33
 */
34

    
35
#include "ALTOclient.h"
36
#include "ALTOclient_impl.h"
37

    
38
#include <stdarg.h>
39
#include <pthread.h>
40

    
41
/*
42
 *                 Here the reference to the accessible DBs is set
43
 */
44
static altoDbPtr ALTO_DB_req = NULL;                // Pointer to the ALTO DB for the Request
45
static altoDbPtr ALTO_DB_res = NULL;                // Pointer to the ALTO DB for the Resposne
46

    
47
static xmlDocPtr ALTO_XML_req = NULL;                // Pointer to the XML for the Request
48
static xmlDocPtr ALTO_XML_res = NULL;                // Pointer to the XML for the Request
49

    
50

    
51
// This is the varaiable where the ALTO server can be found
52
static char alto_server_url[256];
53

    
54
// And this is the struct where the XML buffer for CURL is cached
55
#ifdef USE_CURL
56
static struct curl_reply_buffer_t alto_rep_buf = {ALTO_REP_BUF_SIZE,0,""};
57
#endif
58

    
59
static char alto_reply_buf_nano[ALTO_REP_BUF_SIZE];
60

    
61
static void alto_debugf(const char* str, ...) {
62
        char msg[1024];
63
        va_list args;
64
        va_start(args, str);
65
//#ifdef USE_DEBUG_OUTPUT
66
        vsprintf(msg, str, args);
67
        //printf("[ALTOclient] %s", msg);
68
        fprintf(stderr, "[ALTOclient] %s", msg);
69
//#endif
70
        va_end(args);
71
}
72

    
73
static void alto_errorf(const char* str, ...) {
74
        char msg[1024];
75
        va_list args;
76
        va_start(args, str);
77
        vsprintf(msg, str, args);
78
        fprintf(stderr, "[ALTOclient] *** ERROR: %s", msg);
79
        va_end(args);
80
}
81

    
82
#define assertCheck(expr, msg) if(!(expr)) { alto_errorf("%s - Assertion failed: '"#expr"' (%s, line: %d) -- %s\n", __FUNCTION__, __FILE__, __LINE__, msg); exit(-1); }
83

    
84
#define returnIf(expr, msg, retval) if(expr) { alto_errorf("%s - Condition check: '"#expr"' (%s, line: %d) -- %s\n", __FUNCTION__, __FILE__, __LINE__, msg); return retval; }
85

    
86
/*
87
 *         Function to set the actual ALTO server for configuration
88
 */
89
int set_ALTO_server(char * string){
90
        // Sanity check
91
        returnIf(string == NULL, "Nothing to set here\n", -1);
92

    
93
        strncpy(alto_server_url, string, strlen(string));
94
        return 1;
95
}
96

    
97
/*
98
 *         get the address from the actual set ALTO server;
99
 */
100
char *get_ALTO_server(void){
101
        alto_debugf("%s: The ALTO server is set to: %s \n", __FUNCTION__, alto_server_url);
102
        return (char *) alto_server_url;
103
}
104

    
105

    
106

    
107

    
108

    
109

    
110

    
111

    
112
/*
113
 *         Func:                                        Convert the "Baschtl" notation into a readable
114
 *                                                         format (get IP address)
115
 *         in:                *host_string        Pointer to the string to convert
116
 *         return:        IP                                Struct where the IP and prefix is encoded
117
 */
118
struct in_addr get_ALTO_host_IP(char * host_string){
119
        struct in_addr IP;
120
        #ifdef WIN32
121
        char * str_buff = new char[strlen(host_string)];
122
        #else
123
        char str_buff[strlen(host_string)];
124
        #endif
125
        strncpy(str_buff,host_string,strlen(host_string));
126
        char *result = NULL;
127
        result = strchr(str_buff, '/');
128
        if(result != NULL) {
129
                *result = 0;
130
                IP.s_addr = inet_addr(str_buff);
131
                return IP;
132
        }if(inet_addr(host_string) != (-1)){
133
                IP.s_addr = inet_addr(host_string);
134
                return IP;
135
        }
136
        alto_debugf("%s: No IP found\n!!!", __FUNCTION__);
137
        #ifdef WIN32
138
        delete [] str_buff;
139
        #endif
140
        return IP;
141
}
142

    
143

    
144

    
145

    
146
/*
147
 *         Func:                        Convert the "Baschtl" notation into a readable format
148
 *                                         (get prefix)
149
 *         in:                *host        Pointer to the string to convert
150
 *         return:        port        struct where the IP and prefix is encoded
151
 */
152
int16_t get_ALTO_host_mask(char * host_string){
153
    int16_t res;
154
    char *result = NULL;
155
    char str_buff[256];
156

    
157
    memset(str_buff, 0, 256);
158
    strncpy(str_buff,host_string,strlen(host_string));
159
    result = strchr(str_buff, '/');
160
    if(result != NULL) {
161
        result++;
162
        res = atoi(result);
163
        return res;
164
    }
165
    // if it can't be found, it was a single host so mask is 32 bit
166
    return 32;
167
}
168

    
169

    
170
/*
171
 *  Func:        Create an ALTO XML request from a given DB
172
 *
173
 *  in:                *db                        the pointer to the DB with the elements
174
                        rc_host                the in_addr of the requesting host
175
 *  ret:        XML_doc                the XML where the request is stored in
176
 */
177
xmlDocPtr alto_create_request_XML(struct alto_db_t * db, struct in_addr rc_host, int pri_rat, int sec_rat){
178
        assertCheck(db, "internal db ptr is NULL!");
179

    
180
        // Creates a new document
181
        // <?xml version="1.0" encoding="UTF-8"?>
182
        xmlDocPtr doc = NULL;       /* document pointer */
183
        doc = xmlNewDoc(BAD_CAST "1.0");
184

    
185
        assertCheck(doc, "xmlNewDoc failed! Out of memory?");
186

    
187
        // Create the root node and name it with the correct name space
188
        // <alto xmlns='urn:ietf:params:xml:ns:p2p:alto'>
189
        // Dirty!!! Because NS is here an attribute
190
        // [TODO namespace declaration]
191
        xmlNodePtr root_node = NULL;
192
        root_node = xmlNewNode(NULL, BAD_CAST "alto");
193
    xmlNewNs(root_node, BAD_CAST "urn:ietf:params:xml:ns:p2p:alto",NULL);
194

    
195
    // link it to the document
196
    xmlDocSetRootElement(doc, root_node);
197

    
198
    // Creates a DTD declaration. Isn't mandatory.
199
    // [TODO introduce DTDs by time]
200
//        xmlDtdPtr dtd = NULL;       /* DTD pointer */
201
//  dtd = xmlCreateIntSubset(doc, BAD_CAST "root", NULL, BAD_CAST "tree2.dtd");
202

    
203
        // Here create the group rating request (node_GRR)
204
    // <group_rating_request db_version='1234'>\n"
205
    xmlNodePtr node_GRR = NULL;
206
    node_GRR = xmlNewChild(root_node, NULL, BAD_CAST "group_rating_request", NULL);
207
    xmlNewProp(node_GRR, BAD_CAST "db_version", BAD_CAST "1234");
208

    
209
    // Now create the primary rating criteria
210
    // <pri_ratcrit crit='pref'/>
211
    xmlNodePtr node_PRI = NULL;
212
    node_PRI = xmlNewChild(node_GRR, NULL, BAD_CAST "pri_ratcrit", NULL);
213
    if(pri_rat == REL_PREF){
214
            xmlNewProp(node_PRI, BAD_CAST "crit", BAD_CAST "pref");
215
    }else if(pri_rat == TOP_DIST){
216
            xmlNewProp(node_PRI, BAD_CAST "crit", BAD_CAST "dist");
217
    }else if(pri_rat == MIN_BOUN){
218
            xmlNewProp(node_PRI, BAD_CAST "crit", BAD_CAST "lat");
219
    }
220

    
221

    
222
    // Add the additional rating criteria
223
        if((sec_rat & REL_PREF) == REL_PREF){
224
                xmlNodePtr node_SEC1 = NULL;
225
                node_SEC1 = xmlNewChild(node_GRR, NULL, BAD_CAST "fur_ratcrit", NULL);
226
                xmlNewProp(node_SEC1, BAD_CAST "crit", BAD_CAST "pref");
227
        }
228
        if((sec_rat & TOP_DIST) == TOP_DIST){
229
                xmlNodePtr node_SEC2 = NULL;
230
                node_SEC2 = xmlNewChild(node_GRR, NULL, BAD_CAST "fur_ratcrit", NULL);
231
                xmlNewProp(node_SEC2, BAD_CAST "crit", BAD_CAST "dist");
232
        }
233
        if((sec_rat & MIN_BOUN) == MIN_BOUN){
234
                xmlNodePtr node_SEC4 = NULL;
235
                node_SEC4 = xmlNewChild(node_GRR, NULL, BAD_CAST "fur_ratcrit", NULL);
236
                xmlNewProp(node_SEC4, BAD_CAST "crit", BAD_CAST "lat");
237
        }
238

    
239

    
240
    // Now create the source of the request
241
    // <rc_hla><ipprefix version='4' prefix='195.37.70.39/32'/></rc_hla>
242
    xmlNodePtr node_RC_HLA = NULL;
243
    node_RC_HLA = xmlNewChild(node_GRR, NULL, BAD_CAST "rc_hla", NULL);
244

    
245
    // and within the actual source
246
    // <ipprefix version='4' prefix='195.37.70.39/32'/>
247
    xmlNodePtr node_IPP = NULL;
248
    node_IPP = xmlNewChild(node_RC_HLA, NULL, BAD_CAST "ipprefix", NULL);
249
    xmlNewProp(node_IPP, BAD_CAST "version", BAD_CAST "4");
250
//  xmlNewProp(node_IPP, BAD_CAST "prefix", BAD_CAST "195.37.70.39/32");
251
    char rc_host_str[256];
252
    strcpy(rc_host_str, inet_ntoa(rc_host));
253
    // TODO: really dirty, but it should work
254
    strcat(rc_host_str,"/32");
255
    xmlNewProp(node_IPP, BAD_CAST "prefix", BAD_CAST rc_host_str);
256

    
257
    // Now prepare the request
258
    // <cnd_hla>
259
    xmlNodePtr node_HLA = NULL;
260
    node_HLA = xmlNewChild(node_GRR, NULL, BAD_CAST "cnd_hla", NULL);
261

    
262
    // So far it went quite well, now try to create the host list
263
    // from the given ALTO_LIST
264
    // so create something like this:
265
    // <ipprefix version='4' prefix='195.37.70.39/32'/>
266
    char tmp_buff[256];
267
    struct alto_db_element_t * cur;
268
    cur = db->first;
269
    //while(cur->next != NULL){                // armin 12-jul-2010, bug reported by Andrzej
270
    while(cur != NULL){
271
            node_IPP = xmlNewChild(node_HLA, NULL, BAD_CAST "ipprefix", NULL);
272
            xmlNewProp(node_IPP, BAD_CAST "version", BAD_CAST "4");
273
            sprintf(tmp_buff,"%s/%d",inet_ntoa(cur->host), cur->host_mask);
274
            xmlNewProp(node_IPP, BAD_CAST "prefix", BAD_CAST tmp_buff);
275
            cur = cur->next;
276
    }
277

    
278
    // Dump for checking
279
        #ifdef USE_DEBUG_OUTPUT
280
    xmlDocDump(stdout, doc);
281
    #endif
282

    
283

    
284
    // Free the global variables that may have been allocated by the parser.
285
    //xmlCleanupParser(); // armin 22-jul-2010: Should only be done upon exit
286
    // see libxml2 docu
287

    
288
    // return the finsihed XML
289
    return doc;
290
}
291

    
292
/*==================================
293
       libCURL-based POST code
294
  ==================================*/
295

    
296
#ifdef USE_CURL
297

    
298
// this function will be registered with curl as a handler, which
299
// copies the http reply to a the buffer
300
size_t curl_copy_reply_to_buf(void *ptr,size_t size,size_t nmemb,void *stream){
301
    size_t realsize = size * nmemb;
302
    struct curl_reply_buffer_t *crb = (struct curl_reply_buffer_t *)stream;
303
    // error: new chunk plus trailing zero would not fit into remaining buffer
304
    if( (realsize+1) > (crb->size - crb->fill) ) return 0;
305
    memcpy( &crb->buffer[crb->fill], ptr, realsize );
306
    crb->fill += realsize;
307
    crb->buffer[crb->fill] = 0;
308
    return realsize;
309
}
310
uint16_t prefixes = 0;
311

    
312

    
313

    
314
xmlDocPtr query_ALTO_server_curl(xmlDocPtr doc, char* ALTO_server_URL){
315
        xmlDocPtr ALTO_XML_response;
316

    
317
        // starting here the ALTO list will be send out.....
318
        CURL *curl;
319
        CURLcode res;
320
        struct curl_httppost *formpost=NULL;
321
        struct curl_httppost *lastptr=NULL;
322

    
323
        curl = curl_easy_init();
324
        assertCheck(curl, "Couldn't get a handle from curl_easy_init(). abort.");
325

    
326
        //printf("Will send HTTP POST to %s\nwith form data:\n\n%s\n", alto_server_url, ALTO_XML_query);
327

    
328
        // prepare the buffer to be send
329
        xmlChar*  doctxt;
330
        int       doclen;
331
        xmlDocDumpFormatMemoryEnc(doc,&doctxt,&doclen,"utf-8",1);
332

    
333
        #ifdef USE_DEBUG_OUTPUT
334
        printf(stderr, "[ALTOclientCURL] Will send HTTP POST to %s\nwith XML data:\n\n%s\n", alto_server_url, doctxt);
335
        #endif
336

    
337
        // URL that receives this POST
338
        curl_easy_setopt(curl, CURLOPT_URL, ALTO_server_URL);
339
//        curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
340
//        curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
341
        curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
342

    
343
        // add form data
344
        curl_formadd(&formpost,
345
                                 &lastptr,
346
                                 CURLFORM_COPYNAME, "alto_xml_request",
347
//                                 CURLFORM_COPYCONTENTS, ALTO_XML_query,
348
                                 CURLFORM_COPYCONTENTS, doctxt,                // PTRCONTENTS?
349
                                 CURLFORM_END);
350

    
351
        curl_formadd(&formpost,
352
                             &lastptr,
353
                             CURLFORM_COPYNAME, "action",
354
                             CURLFORM_COPYCONTENTS, "submit",
355
                             CURLFORM_END);
356

    
357
        curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
358

    
359
        // we do not want the reply written to stdout but to our buffer
360
        alto_rep_buf.fill = 0;        // reset buffer (armin 12-jul-2010, reported by Andrzej)
361
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_copy_reply_to_buf);
362
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &alto_rep_buf);
363

    
364
        // do it!
365
        res = curl_easy_perform(curl);
366

    
367
        // always cleanup
368
        curl_easy_cleanup(curl);
369

    
370
        // then cleanup the form post chain
371
        curl_formfree(formpost);
372

    
373
        #ifdef USE_DEBUG_OUTPUT
374
        //printf("result of curl_easy_perform() is: %i\n", res);
375
        fprintf(stderr, "[ALTOclientCURL] received %i octets. the buffer is:\n\n%s\nthat's all. bye.\n", alto_rep_buf.fill, alto_rep_buf.buffer);
376
        #endif
377

    
378

    
379
        // and last but nor least, transform it into an XML doc
380
        ALTO_XML_response = xmlRecoverMemory(alto_rep_buf.buffer, sizeof(alto_rep_buf.buffer));                // <- for getting XML from memory
381

    
382
        return ALTO_XML_response;
383
}
384

    
385
#endif // USE_CURL
386

    
387
/*==================================
388
   libxml2 nanohttp based POST code
389
  ==================================*/
390

    
391
#define POST_BOUNDARY "---------------------------12408751047121013601852724877"
392

    
393
void POST_add(char* buf, const char* name, const char* value) {
394
        sprintf(buf+strlen(buf), "--"POST_BOUNDARY"\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", name, value);
395
}
396

    
397
void POST_end(char* buf) {
398
        sprintf(buf+strlen(buf), "--"POST_BOUNDARY"--\r\n\r\n");
399
}
400

    
401
void* POST_send(const char* url, const char* data) {
402
        int i;
403
        void* ctx = NULL;
404
        char header[] = "Connection: close\r\n";
405
        char contentType[] = "multipart/form-data; boundary="POST_BOUNDARY;
406
        char* ct = contentType;
407

    
408
        assertCheck(url, "ALTO server URL is NULL!");
409
        assertCheck(data, "POST data is NULL!");
410

    
411
        //ctx = xmlNanoHTTPMethod(url, "POST", data, &ct, NULL, strlen(data));
412
        for (i=0; i < 3; i++) {
413
                ctx = xmlNanoHTTPMethod(url, "POST", data, &ct, header, strlen(data)+1);
414
                if (ctx) break;
415
        }
416

    
417
        if (!ctx) {
418
                alto_debugf("*** WARNING: xmlNanoHTTPMethod failed! Make sure ALTO server is reachable (NAT issue?)..");
419
                fprintf(stderr, "URL was '%s'.", url);
420
                return NULL;
421
        }
422
        assertCheck(ctx, "xmlNanoHTTPMethod failed! Make sure ALTO server is reachable (NAT issue?)..");
423

    
424
        free(ct);
425
        return ctx;
426
}
427

    
428
// nano
429
xmlDocPtr ALTO_request_to_server(xmlDocPtr doc, char* endPoint){
430
        xmlDocPtr result = NULL;
431
        xmlChar*  doctxt = NULL;
432
        int                size = 0;
433
        int                doclen = 0;
434
        int                bytesRead = 0;
435
        int                bytesSum = 0;
436
        char*        data = NULL;
437
        size_t  dataLen = 0;
438
        void*        ctx = NULL;
439
        char*   alto_reply_buffer_ptr = alto_reply_buf_nano;
440
//        int                errorcode = 0;
441
//        FILE*        f = NULL;
442

    
443
        assertCheck(doc, "xml doc ptr is NULL!");
444
        assertCheck(endPoint, "ALTO server URL is NULL!");
445

    
446
        xmlNanoHTTPInit();
447
        xmlDocDumpFormatMemoryEnc(doc,&doctxt,&doclen,"utf-8",1);
448

    
449
        dataLen = doclen + 2048;
450
        data = malloc(dataLen);
451
        assertCheck(data, "Couldn't allocate data buffer! Out of memory?");
452
        memset(data, 0, dataLen);
453

    
454
        // build the mime multipart contents
455
        POST_add(data, "alto_xml_request", doctxt);
456
        POST_add(data, "action", "submit");
457
        POST_end(data);
458

    
459
        //printf("data:\n\n%s", data);
460
        xmlFree(doctxt);        // free temp buffer
461

    
462
        alto_debugf("%s: POST begin...\n", __FUNCTION__);
463

    
464
        // send it
465
        ctx = POST_send(endPoint, data);
466

    
467
        free(data);
468
        data = NULL;
469

    
470
        if (!ctx) return NULL;
471

    
472
        alto_debugf("%s: POST ok.\n", __FUNCTION__);
473

    
474
        memset(alto_reply_buf_nano, 0, ALTO_REP_BUF_SIZE);
475

    
476
//        bytesSum = xmlNanoHTTPRead(ctx, &alto_reply_buf_nano, ALTO_REP_BUF_SIZE);
477
        #define BLOCK_SIZE 4096
478
        bytesRead = xmlNanoHTTPRead(ctx, alto_reply_buffer_ptr, BLOCK_SIZE);
479
        bytesSum += bytesRead;
480
        while (bytesRead) {
481
                alto_reply_buffer_ptr += bytesRead;
482
                bytesRead = xmlNanoHTTPRead(ctx, alto_reply_buffer_ptr, BLOCK_SIZE);
483
                bytesSum += bytesRead;
484
        }
485

    
486
        #ifdef USE_DEBUG_OUTPUT
487
//        printf("xmlNanoHTTPRead: %d bytes read.\n", bytesRead);
488
        printf("ALTO reply (%d bytes):\n\n%s", bytesSum, alto_reply_buf_nano);
489
        #endif
490

    
491
        // dump to file
492
/*        f = fopen("http_reply.txt", "wt");
493
        fwrite(output, 1, strlen(output), f);
494
        fclose(f);*/
495

    
496
        result = xmlRecoverMemory(alto_reply_buf_nano, bytesSum);
497
//
498
// TODO: PushParser doesn't work yet somehow..
499
//
500
/*
501
        xmlParserCtxtPtr pushCtx = NULL;
502
        pushCtx = xmlCreatePushParserCtxt(NULL, NULL, output, bytesRead, NULL);
503
//        xmlInitParserCtxt(pushCtx);
504

505
        if (!pushCtx) {
506
                printf("ERROR: xmlCreatePushParserCtxt failed!\n");
507
        } else {
508
                printf("xmlCreatePushParserCtxt ok.\n");
509
        }
510

511
        while (bytesRead) {
512
                if(xmlParseChunk(pushCtx, output, bytesRead, 0) != 0) {
513
                        printf("ERROR: xmlParseChunk failed!\n");
514
                } else {
515
                        printf("xmlParseChunk ok.\n");
516
                }
517
                bytesRead = xmlNanoHTTPRead(ctx,&output,10024);
518
                printf("xmlNanoHTTPRead: %d bytes read.\n", bytesRead);
519
        }
520

521
        printf("Finalizing...\n");
522
        errorcode = xmlParseChunk(pushCtx, output, 0, 1);
523
        if(errorcode) {
524
                printf("ERROR: Final xmlParseChunk failed! errorcode=%d\n", errorcode);
525
        } else {
526
                printf("Final xmlParseChunk ok.\n");
527
        }
528

529
        result = pushCtx->myDoc;
530
        xmlFreeParserCtxt(pushCtx);
531
*/
532

    
533
        if (!result) {
534
                printf("*** ERROR: ALTO XML reply (%d bytes):\n\n%s", bytesSum, alto_reply_buf_nano);
535
                alto_errorf("%s - XML parsing failed (result == NULL)!\n", __FUNCTION__);
536
        } else {
537
                alto_debugf("%s: XML parsing ok.\n", __FUNCTION__);
538
        }
539

    
540
        xmlNanoHTTPClose(ctx);
541
        xmlNanoHTTPCleanup();
542
        return result;
543
}
544

    
545

    
546

    
547

    
548
/*
549
 *
550
 *                 HERE is the magic for the internal DB management
551
 *
552
 */
553

    
554
/*
555
 *         Initialize a ALTO DB structure
556
 */
557
struct alto_db_t * alto_db_init(void){
558
        alto_debugf("%s: Initialize an ALTO database! \n", __FUNCTION__);
559
        struct alto_db_t * db;
560
        db = malloc(sizeof(struct alto_db_t));
561
//        db = (alto_db_t *)malloc(sizeof(struct alto_db_element_t));
562
        assertCheck(db, "Couldn't allocate internal db! Out of memory?");
563

    
564
        db->first = NULL;
565
        db->last = NULL;
566
        db->num_of_elements = 0;
567
        return db;
568
}
569

    
570
/*
571
 *  Kill the DB structure
572
 */
573
int alto_free_db(struct alto_db_t * db){
574
        int res = 1;
575
        alto_debugf("%s: Clean and free ALTO database (%p)! \n", __FUNCTION__, db);
576
        returnIf(db == NULL, "No DB to be free'd.", -1);
577

    
578
        res = alto_purge_db(db);
579

    
580
        // Free the DB struct & Goodby!
581
        free(db);
582
        return res;
583
}
584

    
585
/*
586
 *  Clean/Remove all elements from the DB structure
587
 */
588
int alto_purge_db(struct alto_db_t * db){
589
//        alto_debugf("%s: Purge the ALTO database (%p)! \n", __FUNCTION__, db);
590
        returnIf(db == NULL, "No DB to be purged.", -1);
591

    
592
        // Now kill every single element
593
        struct alto_db_element_t * cur;
594
        cur = db->first;
595
        while(cur != NULL){
596
                alto_rem_element(cur);
597
                cur = db->first; //cur->next;        // armin 12-jul-2010, bug reported by Andrzej
598
        }
599

    
600
        return 1;
601
}
602

    
603

    
604

    
605
/*
606
 *         Helper function to print values of one ALTO DB element
607
 */
608
void alto_dump_element(struct alto_db_element_t * cur){
609
        // Sanity check
610
        assertCheck(cur == NULL, "No element to print values from! ABORT");
611

    
612
        // normal case, print everything
613
//        fprintf(stdout, "---> Internal Data\t");
614
//        fprintf(stdout, "Element ptr  : %p \t", cur);
615
//        fprintf(stdout, "DB   pointer : %p \t", cur->alto_db);
616
//        fprintf(stdout, "next pointer : %p \t", cur->next);
617
//        fprintf(stdout, "prev pointer : %p \t", cur->prev);
618
        alto_debugf("---> User Data\t");
619
        alto_debugf("host  : %s \t", inet_ntoa(cur->host));
620
        alto_debugf("prefix: %d \t", cur->host_mask);
621
        alto_debugf("rating: %d \t", cur->rating);
622
//        fprintf(stdout, "---> Additional Data\n");
623
//        fprintf(stdout, "Subnet       : %s \t", inet_ntoa(cur->subnet));
624
//        fprintf(stdout, "bit mask     : %d \t", cur->subnet_mask);
625
        alto_debugf("\n");
626
        return;
627
}
628

    
629
/*
630
 *         Helper function to print values of one ALTO DB element
631
 */
632
void alto_dump_db(struct alto_db_t *db){
633
        alto_debugf("Dump what's in the DB \n");
634

    
635
        // Security Check
636
        assertCheck(db, "Failure in DB structure! ABORT");
637

    
638
        // General Data
639
        alto_debugf("Number of elements in DB: %d \n", db->num_of_elements);
640
        alto_debugf("DB->first: %p \n", db->first);
641
        alto_debugf("DB->last:  %p \n", db->last);
642

    
643
        // List the elements
644
    struct alto_db_element_t * cur;
645
    cur = db->first;
646
    while(cur != NULL){
647
            alto_dump_element(cur);
648
            cur = cur->next;
649
    }
650

    
651
    // Success!?
652
        return;
653
}
654

    
655

    
656

    
657

    
658
/*
659
 *  Adds one ALTO entry to the DB
660
 */
661
int alto_add_element(struct alto_db_t * db, struct alto_db_element_t * element){
662
//        fprintf(stdout, "Add an element to the ALTO DB! \n");
663

    
664
        // Error handling
665
        returnIf((db == NULL || element == NULL), "Error in appending element on the DB! ABORT", -1);
666

    
667
        // Special case, first element in DB
668
        if(db->first == NULL && db->last == NULL){
669

    
670
                // Update DB
671
                db->first = element;
672
                db->last = element;
673
                db->num_of_elements = 1;
674

    
675
                // Update element
676
                element->next = NULL;
677
                element->prev = NULL;
678
                element->alto_db = db;
679
                element->stamp = time(NULL);
680

    
681
                // And success
682
                return 1;
683
        }
684

    
685
        // Normal case, append element at the end of the list
686
        // Update predecessor
687
        db->last->next = element;
688

    
689
        // Update element
690
        element->prev = db->last;
691
        element->next = NULL;
692
        element->alto_db = db;
693
        element->stamp = time(NULL);
694

    
695
        // Update DB
696
        db->last = element;
697
        db->num_of_elements++;
698

    
699
        // This should be it
700
        return 1;
701
}
702

    
703
int alto_rem_element(struct alto_db_element_t * element){
704

    
705
        // Sanity Check
706
        returnIf(element == NULL, "element == NULL! ABORT", -1);
707

    
708
        // Now get the DB where the element is in
709
        struct alto_db_t *db;
710
        db = element->alto_db;
711

    
712
        // Special case, last and only element in DB
713
        if(db->first == element && db->last == element){
714
                // update main DB
715
                db->first = NULL;
716
                db->last = NULL;
717
                db->num_of_elements = 0;
718
                // free element
719
                free(element);
720
                // exit
721
                return 1;
722
        }
723

    
724
        // Special case, first element in chain
725
        if(db->first == element && db->last != element){
726
                // Update successor
727
                element->next->prev = NULL;
728
                // Update DB
729
                db->first = element->next;
730
                db->num_of_elements--;
731
                // free element
732
                free(element);
733
                // exit
734
                return 1;
735
        }
736

    
737
        // Special case, last element in chain
738
        if(db->first != element && db->last == element){
739
                // Update predecessor
740
                element->prev->next = NULL;
741
                // Update DB
742
                db->last = element->prev;
743
                db->num_of_elements--;
744
                // free element
745
                free(element);
746
                // exit
747
                return 1;
748
        }
749

    
750

    
751
        // normal handling, somwhere in the DB
752
        else {
753
                // update predecessor
754
                element->prev->next = element->next;
755
                element->next->prev = element->prev;
756
                // Update DB
757
                db->num_of_elements--;
758
                // free element
759
                free(element);
760
                // exit
761
                return 1;
762
        }
763

    
764
        // Just in case something went wrong
765
        // what NEVER will happen
766
        alto_errorf("%s - Error in removing element function!\n", __FUNCTION__);
767
        return -1;
768
}
769

    
770

    
771
struct in_addr compute_subnet(struct in_addr host, int prefix){
772
        struct in_addr subn;
773
        uint32_t match_host = host.s_addr;
774
        uint32_t match_mask = 0xFFFFFFFF;
775
        match_mask <<= 32 - prefix;
776
        match_mask = ntohl(match_mask);
777
        uint32_t match_merg = match_host & match_mask;
778
//        printf("host  : %s/%d \t", inet_ntoa(host), prefix);
779
//        subn.s_addr = match_mask;
780
//        printf("mask  : %s  \t", inet_ntoa(subn));
781
        subn.s_addr = match_merg;
782
//        printf("net   : %s  \n", inet_ntoa(subn));
783
        return subn;
784
}
785

    
786

    
787

    
788
/*
789
 *         Search in an ALTO DB for the match of an host
790
 *
791
 *         value:        add                Address of the host to search for
792
 *                         db                The ALTO DB to search in
793
 *         return:        value/0        The found value / 0 in case of nothing
794
 */
795
int get_ALTO_rating_for_host(struct in_addr add, ALTO_DB_T * db){
796

    
797
        // Sanity checks
798
        returnIf(add.s_addr == 0, "Couldn't read the ALTO host IP to query! ABORT", 0);
799
        returnIf(db == NULL, "Couldn't access the DB! ABORT", 0);
800

    
801
        // walk through the DB until you find the element
802
    struct alto_db_element_t * cur;
803
    cur = db->first;
804
    while(cur != NULL){
805
            if(cur->host.s_addr == add.s_addr){
806
                    return cur->rating;
807
            }
808
            cur = cur->next;
809
    }
810

    
811
    // Here you come in case of error/not found!
812
        return 0;
813
}
814

    
815

    
816

    
817

    
818

    
819

    
820

    
821

    
822

    
823
int ask_helper_func(struct in_addr subnet, ALTO_DB_T * db){
824
        ALTO_DB_ELEMENT_T * cur = db->first;
825
        while(cur != NULL){
826
                if(subnet.s_addr == cur->host.s_addr){
827
//                        printf("Subnet : %s \t", inet_ntoa(subnet));
828
//                        printf("rating : %d \n", cur->rating);
829
                        return cur->rating;
830
                }
831
                cur = cur->next;
832
        }
833
        return 0;
834
}
835

    
836

    
837

    
838
int get_alto_rating(ALTO_DB_ELEMENT_T * element, ALTO_DB_T * db){
839

    
840
        int mask = element->host_mask;
841
        struct in_addr subnet = compute_subnet(element->host, mask);
842
//        printf("Host: %s/%d \n", inet_ntoa(element->host), mask);
843

    
844
        int i, check;
845
        for(i=mask;i>0;i--){
846
                check = ask_helper_func(subnet, db);
847
                if(check == 0){
848
                        subnet = compute_subnet(element->host, mask--);
849
                }else{
850
//                        printf("Found rating, with value: %d \n", check);
851
                        return check;
852
                }
853
        }
854
        return 0;
855
}
856

    
857

    
858

    
859
int get_alto_subnet_mask(ALTO_DB_ELEMENT_T * element, ALTO_DB_T * db){
860
        int mask = element->host_mask;
861
        struct in_addr subnet = compute_subnet(element->host, mask);
862
//        printf("Host: %s/%d \n", inet_ntoa(element->host), mask);
863
        int i;
864
        for(i=mask;i>0;i--){
865
                if((ask_helper_func(subnet, db)) == 0){
866
                        return mask;
867
                }else{
868
                        mask--;
869
                }
870
        }
871
        return 0;
872
}
873

    
874

    
875

    
876

    
877

    
878

    
879

    
880

    
881
/*
882
 *         Here the matching between the requested IPs and the delivered
883
 *         list will be done
884
 *
885
 *         in:                db_req                Pointer to the DB where the IPs are
886
 *                         db_res                Pointer to the DB where the ALTO response is
887
 *         return:        1                        Success
888
 */
889
int alto_do_the_magic(ALTO_DB_T * ALTO_db_req, ALTO_DB_T * ALTO_db_res){
890
        alto_debugf("%s: Find the rating and assign to IPs\n", __FUNCTION__);
891

    
892
        // Sanity check
893
        returnIf((ALTO_db_req == NULL || ALTO_db_res == NULL), "Errors in accessing the DBs! ABORT", 0);
894

    
895
        // Now iterate through the hosts and find the corresponding rating
896
        ALTO_DB_ELEMENT_T * cur;
897
        cur = ALTO_db_req->first;
898
        while(cur != NULL){
899

    
900
                // store the rating in the asking element
901
                cur->rating = get_alto_rating(cur, ALTO_db_res);
902

    
903
                // next DB item to query
904
                cur = cur->next;
905
        }
906

    
907
        // Aaaaaand finished!
908
        return 1;
909
}
910

    
911

    
912

    
913

    
914

    
915

    
916
int alto_parse_from_file(altoDbPtr db, char *file_name){
917
        alto_debugf("%s: Read hosts from file (%s) and store it in the Request-DB\n", __FUNCTION__, file_name);
918

    
919
        FILE *file;
920
        char line[256];
921
        file = fopen(file_name, "r");
922
        char * ptr;
923

    
924
        // Sanity checks
925
        returnIf(db == NULL, "No DB selected! ABORT", 0);
926
        returnIf(file == NULL, "Can't open the file! ABORT", 0);
927

    
928
        // Now read the lines in
929
        while(fgets(line, sizeof(line), file) != NULL ) {
930
                // parse the line, remove the comments
931
                ptr = strtok(line, " ");
932
                // create the ALTO element
933
                struct alto_db_element_t *element;
934
                element = malloc(sizeof(ALTO_DB_ELEMENT_T));
935
                element->host = get_ALTO_host_IP(ptr);
936
                element->host_mask = get_ALTO_host_mask(ptr);
937
                // and add this element to the db
938
                alto_add_element(db, element);
939
            }
940
        return 1;
941
}
942

    
943

    
944

    
945
int alto_parse_from_XML(altoDbPtr db, xmlDocPtr doc){
946
        alto_debugf("%s: Parse an XML element into the DB structure\n", __FUNCTION__);
947

    
948
        // Sanity check
949
        returnIf((db == NULL || doc == NULL), "Couldn't access XML or DB! ABORT", -1);
950

    
951
        xmlNode *cur = NULL;
952
        cur = xmlDocGetRootElement(doc);
953
        xmlChar *overall_rating = NULL;
954
        xmlChar *ipprefix = NULL;
955
        xmlChar *status_code = NULL;
956
        int ratings_done = 0;
957

    
958
        while(cur!=NULL){
959
                if (!xmlStrcmp(cur->name, BAD_CAST "group_rating_reply")) {
960
                        status_code = xmlGetProp(cur, BAD_CAST "statuscode");
961
                        if (status_code) alto_debugf("*** ALTO reply statuscode = %s\n", status_code);
962
                }
963
                if (!xmlStrcmp(cur->name, BAD_CAST "statustext")) {
964
                        xmlChar* str;
965
                        str = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
966
                        alto_debugf("***********************************************************************\n");
967
                        alto_debugf("*** ALTO reply statustext = '%s'\n", str);
968
                        alto_debugf("***********************************************************************\n");
969
                        xmlFree(str);
970
                }
971
                if (!xmlStrcmp(cur->name, BAD_CAST "cnd_hla")) {
972
                        overall_rating = xmlGetProp(cur, BAD_CAST "overall_rating");
973
                }
974
                if (!xmlStrcmp(cur->name, BAD_CAST "ipprefix")) {
975
                        ipprefix = xmlGetProp(cur, BAD_CAST "prefix");
976
                        if (!ipprefix) {
977
                                alto_debugf("Couldn't find ipprefix!\n");
978
                                break;
979
                        }
980

    
981
                        // create the ALTO element
982
                        struct alto_db_element_t *element;
983
                        element = malloc(sizeof(ALTO_DB_ELEMENT_T));
984
                        element->host = get_ALTO_host_IP((char*) ipprefix);
985
                        element->host_mask = get_ALTO_host_mask((char*) ipprefix);
986
                        if (overall_rating) {
987
                                element->rating = atoi(overall_rating);
988
                                alto_debugf("rating %s = %d\n", ipprefix, element->rating);
989
                        } else {
990
                                element->rating = 0;
991
                                alto_debugf("rating %s = %d (DEFAULT, host not in DB!)\n", ipprefix, element->rating);
992
                        }
993
                        ratings_done = 1;
994

    
995
                        // and add this element to the db
996
                        alto_add_element(db, element);
997

    
998
                } 
999
                if (cur->children != NULL) {
1000
//                        printf("cur->children == NULL \n");
1001
                        cur = cur->children;
1002
                } 
1003
                if (cur->children == NULL && cur->next != NULL) {
1004
//                        printf("cur->children == NULL && cur->next != NULL \n");
1005
                        cur = cur->next;
1006
                } 
1007
                if (cur->children == NULL && cur->next == NULL) {
1008
//                        printf("cur->children == NULL && cur->next == NULL \n");
1009
                        cur = cur->parent->next;
1010
                }
1011
        }
1012

    
1013
        if (!ratings_done) {
1014
                alto_debugf("WARNING: ALTO XML reply didn't contain rating info, no peers were rated!\n");
1015
                xmlChar* text = NULL;
1016
                int sz = 0;
1017
                xmlDocDumpMemory(doc, &text, &sz);
1018
                //fprintf(stderr, "ALTO XML reply was: (%d bytes)\n%s", sz, text);
1019
        }
1020

    
1021
        return 1;
1022
}
1023

    
1024

    
1025

    
1026
/*
1027
 *         Converts a given alto_list_t structure into the internal DB structure
1028
 *
1029
 *         in:                db                the databse where the element has to be added
1030
 *                         list        the list of the alto elements structure
1031
 *                         num                number of eements to add
1032
 *         ret:        1/-1        for success failuire
1033
 */
1034
int alto_parse_from_list(struct alto_db_t *db, struct alto_guidance_t *list, int num_of_elements){
1035
        alto_debugf("%s: Convert given list into internal DB structure\n", __FUNCTION__);
1036

    
1037
        // Sanity check
1038
        returnIf((db == NULL || list == NULL), "No lists to parse from / parse in, ABORT!", -1);
1039

    
1040
        // and now will the elements in the DB
1041
        int i;
1042
        for(i=0; i < num_of_elements; i++){
1043

    
1044
                // Create a new element
1045
                struct alto_db_element_t *element;
1046
                element = malloc(sizeof(ALTO_DB_ELEMENT_T));
1047
                element->alto_db = db;
1048
                element->next = NULL;
1049
                element->prev = NULL;
1050
                element->host = list[i].alto_host;                        // here the values come in
1051
                element->host_mask = list[i].prefix;                // here the values come in
1052
                element->rating = 0;                                                // here the values come in
1053

    
1054
                // and now append it to the DB
1055
                alto_add_element(db, element);
1056
        }
1057

    
1058
        // That's should be it
1059
        return 1;
1060
}
1061

    
1062

    
1063

    
1064

    
1065

    
1066
int alto_write_to_file(altoDbPtr db, char *file_name){
1067
        alto_debugf("%s: Write hosts to file (%s.out) \n", __FUNCTION__, file_name);
1068

    
1069
        // Sanity checks
1070
        returnIf(file_name == NULL, "Can't open the file! ABORT",-1);
1071
        returnIf(db == NULL, "No DB select! ABORT", -1);
1072

    
1073
        // Create the new file
1074
        char * str_out;
1075
        str_out = (char*)malloc(256 * sizeof(char));
1076
        strcpy (str_out,file_name);
1077
        strcat (str_out,".out");
1078

    
1079
        // create the output filename
1080
        FILE *file;
1081
        file = fopen(str_out, "a+");
1082
        returnIf(file == NULL, "Can't create the file! ABORT", 0);
1083

    
1084
        // Write everything to the file
1085
        int count = 0;
1086
        ALTO_DB_ELEMENT_T * cur = db->first;
1087
        while(cur != NULL){
1088
                fprintf(file, "%s/%d \t", inet_ntoa(cur->host), cur->host_mask);
1089
                fprintf(file, "%d \t", cur->rating);
1090
                fprintf(file, "\n");
1091
                count++;
1092
                cur = cur->next;
1093
        }
1094

    
1095
        // Return the number of sucessful written lines
1096
        return count;
1097
}
1098

    
1099

    
1100

    
1101

    
1102
/*
1103
 *         Start & Innitialize the ALTO client
1104
 */
1105
void start_ALTO_client(){
1106
        alto_debugf("START ALTO client! \n");
1107

    
1108
        // initialize the DBs
1109
        ALTO_DB_req = alto_db_init();
1110
        ALTO_DB_res = alto_db_init();
1111

    
1112
        // prepare the XML environment
1113
        LIBXML_TEST_VERSION;
1114

    
1115
#ifdef USE_CURL
1116
        // prepare CURL
1117
        // ---------------------------------------------------------------------------------
1118
        // XXX: NOTE:
1119
        // "This function is NOT THREAD SAFE. You must not call it when any other thread 
1120
        // in the program (i.e. a thread sharing the same memory) is running. This doesn't 
1121
        // just mean no other thread that is using libcurl. Because curl_global_init() calls 
1122
        // functions of other libraries that are similarly thread unsafe, it could conflict 
1123
        // with any other thread that uses these other libraries."
1124
        // ---------------------------------------------------------------------------------
1125

    
1126
        curl_global_init(CURL_GLOBAL_ALL);
1127
#endif
1128

    
1129
        // and Initialize the XMLs
1130
    ALTO_XML_req = NULL;
1131
    ALTO_XML_res = NULL;
1132
}
1133

    
1134

    
1135
/*
1136
 *         Stop & CleanUp the ALTO client
1137
 */
1138
void stop_ALTO_client(){
1139
        alto_debugf("STOP ALTO client! \n");
1140

    
1141
        // Kill the DBs
1142
        alto_free_db(ALTO_DB_req);
1143
        alto_free_db(ALTO_DB_res);
1144

    
1145
        // Kill the XML
1146
    if (ALTO_XML_req) { xmlFreeDoc(ALTO_XML_req); ALTO_XML_req = NULL; }
1147
    if (ALTO_XML_res) { xmlFreeDoc(ALTO_XML_res); ALTO_XML_res = NULL; }
1148

    
1149
        xmlCleanupParser();
1150

    
1151
#ifdef USE_CURL
1152
        // shutdown  libCurl
1153
        // XXX: NOTE: same thread un-safety warning applies!
1154
        curl_global_cleanup();
1155
#endif
1156
}
1157

    
1158

    
1159

    
1160

    
1161

    
1162

    
1163
/*
1164
 *         Function:        gets for a list in a txt file the correct rating
1165
 *
1166
 *         in:                        *txt        pointer to the list
1167
 *                                 rc_host        The Resource Consumer locator
1168
 *                                 pri_rat        Primary Rating criteria
1169
 *                                 sec_rat        Secondary Rating criteria
1170
 *         return:                1/0                Success/Erros
1171
 */
1172
int get_ALTO_guidance_for_txt(char * txt, struct in_addr rc_host, int pri_rat, int sec_rat){
1173
        alto_debugf("get_ALTO_guidance_txt(%s) was called \n", txt);
1174

    
1175
        // Sanity checks 
1176
        returnIf(txt == NULL, "Can't access the file! ABORT!", 0);
1177
        returnIf(rc_host.s_addr == NULL, "Can't read the rc_host! ABORT!", 0);
1178
        returnIf((pri_rat < 1 || pri_rat > 3), "Primary Rating Criteria wrong! ABORT!", 0);
1179
        returnIf((sec_rat < 1 || sec_rat > 8), "Secondary Rating Criteria(s) wrong! ABORT", 0);
1180

    
1181
        // first purge existing DB entries
1182
        alto_purge_db(ALTO_DB_req);
1183

    
1184
        // Step 1: fill the txt into the DB
1185
        alto_parse_from_file(ALTO_DB_req, txt);
1186

    
1187
        // do the ALTO trick / update db
1188
        do_ALTO_update(rc_host, pri_rat, sec_rat);
1189

    
1190
        // Step 3 (write values back)
1191
        alto_write_to_file(ALTO_DB_req, txt);
1192

    
1193
        // done
1194
        return 1;
1195
}
1196

    
1197
/*
1198
 *         Function:        gets for a list of elements the correct rating
1199
 *
1200
 *         in:                        *list        pointer to the list
1201
 *                                 *num        Number of elements to process
1202
 *         return:                count        Number of sucessfully processed hosts
1203
 */
1204
int get_ALTO_guidance_for_list(ALTO_GUIDANCE_T * list, int num, struct in_addr rc_host, int pri_rat, int sec_rat){
1205
        alto_debugf("get_ALTO_guidance(list, num_of_elements) was called \n");
1206

    
1207
        int count = 0;
1208

    
1209
        // Sanity checks (list)
1210
        returnIf(list == NULL, "Can't access the list!", 0);
1211

    
1212
        // Sanity checks (num of elements)
1213
        returnIf(num < 0, "<0 elements?", 0);
1214

    
1215
        // first purge existing DB entries
1216
        alto_purge_db(ALTO_DB_req);
1217

    
1218
        // Step 1 (read struct into DB)
1219
        alto_parse_from_list(ALTO_DB_req, list, num);
1220

    
1221
        // do the ALTO trick / update db
1222
        do_ALTO_update(rc_host, pri_rat, sec_rat);
1223

    
1224
        // Step 2 (write values back)
1225
        for(count = 0; count < num; count++){
1226
                list[count].rating = get_ALTO_rating_for_host(list[count].alto_host, ALTO_DB_req);
1227
        }
1228

    
1229
        // This should be it
1230
        return 1;
1231
}
1232

    
1233
/*==================================
1234
    Multi-Threaded Query
1235
  ==================================*/
1236

    
1237
static int queryState = ALTO_QUERY_READY;
1238

    
1239
static pthread_t threadId;
1240
static pthread_attr_t attr;
1241

    
1242
typedef struct {
1243
        ALTO_GUIDANCE_T* list;
1244
        int num;        // number of elements in list
1245
        struct in_addr rc_host;
1246
        int pri_rat;
1247
        int sec_rat;
1248
} ALTO_ThreadArgs_t;
1249

    
1250
ALTO_ThreadArgs_t threadArgs;
1251

    
1252
void* alto_query_thread_func(void* thread_args)
1253
{
1254
        int count = 0;
1255
        ALTO_ThreadArgs_t* args = (ALTO_ThreadArgs_t*) thread_args;
1256

    
1257
        alto_debugf("alto_query_thread_func\n");
1258

    
1259
        // this will block at some point
1260
        do_ALTO_update(args->rc_host, args->pri_rat, args->sec_rat);
1261

    
1262
        // write values back
1263
        for(count = 0; count < args->num; count++){
1264
                args->list[count].rating = get_ALTO_rating_for_host(args->list[count].alto_host, ALTO_DB_req);
1265
        }
1266

    
1267
        // signal that query is ready
1268
        queryState = ALTO_QUERY_READY;
1269

    
1270
        return thread_args;
1271
}
1272

    
1273
int ALTO_query_state() {
1274
        return queryState;
1275
}
1276

    
1277
int ALTO_query_exec(ALTO_GUIDANCE_T * list, int num, struct in_addr rc_host, int pri_rat, int sec_rat){
1278
        alto_debugf("ALTO_query_exec\n");
1279

    
1280
        // Sanity checks (list)
1281
        returnIf(list == NULL, "Can't access the list!", 0);
1282

    
1283
        // Sanity checks (num of elements)
1284
        returnIf(num < 0, "<0 elements?", 0);
1285

    
1286
        // set new state
1287
        if (queryState == ALTO_QUERY_INPROGRESS) {
1288
                alto_debugf("*** WARNING: Calling ALTO_query_exec while query is still in progress! Race condition?!\n");
1289
                return 0;
1290
        }
1291
        queryState = ALTO_QUERY_INPROGRESS;
1292

    
1293
        // first purge existing DB entries
1294
        alto_purge_db(ALTO_DB_req);
1295

    
1296
        // Step 1 (read struct into DB)
1297
        alto_parse_from_list(ALTO_DB_req, list, num);
1298

    
1299
        //ALTO_XML_req = alto_create_request_XML(ALTO_DB_req, rc_host, pri_rat, sec_rat);
1300

    
1301
        threadArgs.list = list;
1302
        threadArgs.num = num;
1303
        pthread_attr_init(&attr);
1304
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1305
        if (pthread_create(&threadId, &attr, alto_query_thread_func, &threadArgs) != 0) {
1306
                fprintf(stderr,"[ALTOclient] pthread_create failed!\n");
1307
                queryState = ALTO_QUERY_READY;
1308
                return 0;
1309
        }
1310

    
1311
        // This should be it
1312
        return 1;
1313
}
1314

    
1315

    
1316

    
1317
/*
1318
 * Function:        With this call the internal request to update the DB is triggered.
1319
 *                                 This should be done on a regual basis to keep the local ALTO-DB
1320
 *                                 up2date
1321
 */
1322

    
1323

    
1324
void do_ALTO_update(struct in_addr rc_host, int pri_rat, int sec_rat){
1325
        assertCheck(ALTO_DB_req, "ALTO_DB_req is NULL!");
1326

    
1327
        // Step 2: create an XML from the DB entries
1328
        ALTO_XML_req = alto_create_request_XML(ALTO_DB_req, rc_host, pri_rat, sec_rat);
1329

    
1330
#ifndef USE_LOCAL_REPLY_XML
1331
        // Step2a: send POST request to ALTO server
1332
        #ifdef USE_CURL
1333
        ALTO_XML_res = query_ALTO_server_curl(ALTO_XML_req, alto_server_url);
1334
        #else
1335
        ALTO_XML_res = ALTO_request_to_server(ALTO_XML_req, alto_server_url);
1336
        #endif
1337
#else
1338
        // Step2b: use for testing the local stored TXT-file
1339
        ALTO_XML_res = xmlReadFile("reply.xml",NULL,XML_PARSE_RECOVER);
1340
#endif
1341

    
1342
        if (ALTO_XML_res) {
1343
                // Step 3: Parse the XML to the DB
1344
                alto_parse_from_XML(ALTO_DB_res, ALTO_XML_res);
1345

    
1346
                // ###### Big Magic ######
1347
                // And now check for the corresponding rating
1348
                alto_do_the_magic(ALTO_DB_req, ALTO_DB_res);
1349

    
1350
                xmlFreeDoc(ALTO_XML_res);
1351
                ALTO_XML_res = NULL;
1352
        }
1353

    
1354
        // free xml data
1355
        xmlFreeDoc(ALTO_XML_req);
1356
        ALTO_XML_req = NULL;
1357

    
1358
        // purge the intermediate DB
1359
        alto_purge_db(ALTO_DB_res);
1360
}
1361

    
1362