Statistics
| Branch: | Revision:

napa-baselibs / ALTOclient / ALTOclient.c @ be521750

History | View | Annotate | Download (33.2 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

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

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

    
192
    // link it to the document
193
    xmlDocSetRootElement(doc, root_node);
194

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

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

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

    
218

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

    
236

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

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

    
254
    // Now prepare the request
255
    // <cnd_hla>
256
    xmlNodePtr node_HLA = NULL;
257
    node_HLA = xmlNewChild(node_GRR, NULL, BAD_CAST "cnd_hla", NULL);
258

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

    
275
    // Dump for checking
276
        #ifdef USE_DEBUG_OUTPUT
277
    xmlDocDump(stdout, doc);
278
    #endif
279

    
280

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

    
285
    // return the finsihed XML
286
    return doc;
287
}
288

    
289
/*==================================
290
       libCURL-based POST code
291
  ==================================*/
292

    
293
// libcurl is now obsolete!
294
#ifdef USE_CURL
295

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

    
310

    
311

    
312
xmlDocPtr query_ALTO_server_curl(xmlDocPtr doc, char* ALTO_server_URL){
313
        xmlDocPtr ALTO_XML_response;
314

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

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

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

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

    
331
        // URL that receives this POST
332
        curl_easy_setopt(curl, CURLOPT_URL, ALTO_server_URL);
333

    
334
        // add form data
335
        curl_formadd(&formpost,
336
                                 &lastptr,
337
                                 CURLFORM_COPYNAME, "alto_xml_request",
338
//                                 CURLFORM_COPYCONTENTS, ALTO_XML_query,
339
                                 CURLFORM_COPYCONTENTS, doctxt,
340
                                 CURLFORM_END);
341

    
342
        curl_formadd(&formpost,
343
                             &lastptr,
344
                             CURLFORM_COPYNAME, "action",
345
                             CURLFORM_COPYCONTENTS, "submit",
346
                             CURLFORM_END);
347

    
348
        curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
349

    
350
        // we do not want the reply written to stdout but to our buffer
351
        alto_rep_buf.fill = 0;        // reset buffer (armin 12-jul-2010, reported by Andrzej)
352
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_copy_reply_to_buf);
353
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &alto_rep_buf);
354

    
355
        // do it!
356
        res = curl_easy_perform(curl);
357

    
358
        // always cleanup
359
        curl_easy_cleanup(curl);
360

    
361
        // then cleanup the form post chain
362
        curl_formfree(formpost);
363

    
364
//  printf("result of curl_easy_perform() is: %i\n", res);
365
//  printf("received %i octetts. the buffer is:\n\n%s\nthat's all. bye.\n",alto_rep_buf.fill,alto_rep_buf.buffer);
366

    
367

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

    
371
        return ALTO_XML_response;
372
}
373

    
374
#endif // USE_CURL
375

    
376
/*==================================
377
   libxml2 nanohttp based POST code
378
  ==================================*/
379

    
380
#define POST_BOUNDARY "---------------------------12408751047121013601852724877"
381

    
382
void POST_add(char* buf, const char* name, const char* value) {
383
        sprintf(buf+strlen(buf), "--"POST_BOUNDARY"\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", name, value);
384
}
385

    
386
void POST_end(char* buf) {
387
        sprintf(buf+strlen(buf), "--"POST_BOUNDARY"--\r\n\r\n");
388
}
389

    
390
void* POST_send(const char* url, const char* data) {
391
        void* ctx;
392
        char contentType[512] = "multipart/form-data; boundary="POST_BOUNDARY;
393
        char* ct = contentType;
394

    
395
        ctx = xmlNanoHTTPMethod(url, "POST", data, &ct, NULL, strlen(data));
396

    
397
        free(ct);
398
        return ctx;
399
}
400

    
401
// nano
402
xmlDocPtr ALTO_request_to_server(xmlDocPtr doc, char* endPoint){
403
        xmlDocPtr result = NULL;
404
        int       size;
405
        xmlChar*  doctxt;
406
        int       doclen;
407
        int       bytesRead;
408
        size = 0;
409
        char*        data;
410
        size_t  dataLen = 0;
411
        void*        ctx = NULL;
412
//        int                errorcode = 0;
413
//        FILE*        f = NULL;
414

    
415
        xmlNanoHTTPInit();
416
        xmlDocDumpFormatMemoryEnc(doc,&doctxt,&doclen,"utf-8",1);
417

    
418
        dataLen = doclen + 2048;
419
        data = malloc(dataLen);
420
        memset(data, 0, dataLen);
421

    
422
        // build the mime multipart contents
423
        POST_add(data, "alto_xml_request", doctxt);
424
        POST_add(data, "action", "submit");
425
        POST_end(data);
426

    
427
        //printf("data:\n\n%s", data);
428
        xmlFree(doctxt);        // free temp buffer
429

    
430
        alto_debugf("%s: POST begin...\n", __FUNCTION__);
431

    
432
        // send it
433
        ctx = POST_send(endPoint, data);
434

    
435
        free(data);
436
        data = NULL;
437

    
438
        alto_debugf("%s: POST ok.\n", __FUNCTION__);
439
/*
440
        char output[10024];
441
        memset(output, 0, 10024);
442

443
        bytesRead = xmlNanoHTTPRead(ctx,&output,10024);
444
//        output[bytesRead] = '\n';
445
*/
446
        memset(alto_reply_buf_nano, 0, ALTO_REP_BUF_SIZE);
447

    
448
        bytesRead = xmlNanoHTTPRead(ctx, &alto_reply_buf_nano, ALTO_REP_BUF_SIZE);
449

    
450
        #ifdef USE_DEBUG_OUTPUT
451
//        printf("xmlNanoHTTPRead: %d bytes read.\n", bytesRead);
452
        printf("ALTO reply (%d bytes):\n\n%s", bytesRead, alto_reply_buf_nano);
453
        #endif
454

    
455
        // dump to file
456
/*        f = fopen("http_reply.txt", "wt");
457
        fwrite(output, 1, strlen(output), f);
458
        fclose(f);*/
459

    
460
        result = xmlRecoverMemory(alto_reply_buf_nano, bytesRead);
461
//
462
// TODO: PushParser doesn't work yet somehow..
463
//
464
/*
465
        xmlParserCtxtPtr pushCtx = NULL;
466
        pushCtx = xmlCreatePushParserCtxt(NULL, NULL, output, bytesRead, NULL);
467
//        xmlInitParserCtxt(pushCtx);
468

469
        if (!pushCtx) {
470
                printf("ERROR: xmlCreatePushParserCtxt failed!\n");
471
        } else {
472
                printf("xmlCreatePushParserCtxt ok.\n");
473
        }
474

475
        while (bytesRead) {
476
                if(xmlParseChunk(pushCtx, output, bytesRead, 0) != 0) {
477
                        printf("ERROR: xmlParseChunk failed!\n");
478
                } else {
479
                        printf("xmlParseChunk ok.\n");
480
                }
481
                bytesRead = xmlNanoHTTPRead(ctx,&output,10024);
482
                printf("xmlNanoHTTPRead: %d bytes read.\n", bytesRead);
483
        }
484

485
        printf("Finalizing...\n");
486
        errorcode = xmlParseChunk(pushCtx, output, 0, 1);
487
        if(errorcode) {
488
                printf("ERROR: Final xmlParseChunk failed! errorcode=%d\n", errorcode);
489
        } else {
490
                printf("Final xmlParseChunk ok.\n");
491
        }
492

493
        result = pushCtx->myDoc;
494
        xmlFreeParserCtxt(pushCtx);
495
*/
496

    
497
        if (!result) {
498
                alto_errorf("%s - XML parsing failed (result == NULL)!\n", __FUNCTION__);
499
        } else {
500
                alto_debugf("%s: XML parsing ok.\n", __FUNCTION__);
501
        }
502

    
503
        xmlNanoHTTPClose(ctx);
504
        return result;
505
}
506

    
507

    
508

    
509

    
510
/*
511
 *
512
 *                 HERE is the magic for the internal DB management
513
 *
514
 */
515

    
516
/*
517
 *         Initialize a ALTO DB structure
518
 */
519
struct alto_db_t * alto_db_init(void){
520
        alto_debugf("%s: Initialize an ALTO database! \n", __FUNCTION__);
521
        struct alto_db_t * db;
522
        db = malloc(sizeof(struct alto_db_t));
523
//        db = (alto_db_t *)malloc(sizeof(struct alto_db_element_t));
524
        db->first = NULL;
525
        db->last = NULL;
526
        db->num_of_elements = 0;
527
        return db;
528
}
529

    
530
/*
531
 *  Kill the DB structure
532
 */
533
int alto_free_db(struct alto_db_t * db){
534
        int res = 1;
535
        alto_debugf("%s: Clean and free ALTO database (%p)! \n", __FUNCTION__, db);
536
        returnIf(db == NULL, "No DB to be free'd.", -1);
537

    
538
        res = alto_purge_db(db);
539

    
540
        // Free the DB struct & Goodby!
541
        free(db);
542
        return res;
543
}
544

    
545
/*
546
 *  Clean/Remove all elements from the DB structure
547
 */
548
int alto_purge_db(struct alto_db_t * db){
549
//        alto_debugf("%s: Purge the ALTO database (%p)! \n", __FUNCTION__, db);
550
        returnIf(db == NULL, "No DB to be purged.", -1);
551

    
552
        // Now kill every single element
553
        struct alto_db_element_t * cur;
554
        cur = db->first;
555
        while(cur != NULL){
556
                alto_rem_element(cur);
557
                cur = db->first; //cur->next;        // armin 12-jul-2010, bug reported by Andrzej
558
        }
559

    
560
        return 1;
561
}
562

    
563

    
564

    
565
/*
566
 *         Helper function to print values of one ALTO DB element
567
 */
568
void alto_dump_element(struct alto_db_element_t * cur){
569
        // Sanity check
570
        assertCheck(cur == NULL, "No element to print values from! ABORT");
571

    
572
        // normal case, print everything
573
//        fprintf(stdout, "---> Internal Data\t");
574
//        fprintf(stdout, "Element ptr  : %p \t", cur);
575
//        fprintf(stdout, "DB   pointer : %p \t", cur->alto_db);
576
//        fprintf(stdout, "next pointer : %p \t", cur->next);
577
//        fprintf(stdout, "prev pointer : %p \t", cur->prev);
578
        alto_debugf("---> User Data\t");
579
        alto_debugf("host  : %s \t", inet_ntoa(cur->host));
580
        alto_debugf("prefix: %d \t", cur->host_mask);
581
        alto_debugf("rating: %d \t", cur->rating);
582
//        fprintf(stdout, "---> Additional Data\n");
583
//        fprintf(stdout, "Subnet       : %s \t", inet_ntoa(cur->subnet));
584
//        fprintf(stdout, "bit mask     : %d \t", cur->subnet_mask);
585
        alto_debugf("\n");
586
        return;
587
}
588

    
589
/*
590
 *         Helper function to print values of one ALTO DB element
591
 */
592
void alto_dump_db(struct alto_db_t *db){
593
        alto_debugf("Dump what's in the DB \n");
594

    
595
        // Security Check
596
        assertCheck(db, "Failure in DB structure! ABORT");
597

    
598
        // General Data
599
        alto_debugf("Number of elements in DB: %d \n", db->num_of_elements);
600
        alto_debugf("DB->first: %p \n", db->first);
601
        alto_debugf("DB->last:  %p \n", db->last);
602

    
603
        // List the elements
604
    struct alto_db_element_t * cur;
605
    cur = db->first;
606
    while(cur != NULL){
607
            alto_dump_element(cur);
608
            cur = cur->next;
609
    }
610

    
611
    // Success!?
612
        return;
613
}
614

    
615

    
616

    
617

    
618
/*
619
 *  Adds one ALTO entry to the DB
620
 */
621
int alto_add_element(struct alto_db_t * db, struct alto_db_element_t * element){
622
//        fprintf(stdout, "Add an element to the ALTO DB! \n");
623

    
624
        // Error handling
625
        returnIf((db == NULL || element == NULL), "Error in appending element on the DB! ABORT", -1);
626

    
627
        // Special case, first element in DB
628
        if(db->first == NULL && db->last == NULL){
629

    
630
                // Update DB
631
                db->first = element;
632
                db->last = element;
633
                db->num_of_elements = 1;
634

    
635
                // Update element
636
                element->next = NULL;
637
                element->prev = NULL;
638
                element->alto_db = db;
639
                element->stamp = time(NULL);
640

    
641
                // And success
642
                return 1;
643
        }
644

    
645
        // Normal case, append element at the end of the list
646
        // Update predecessor
647
        db->last->next = element;
648

    
649
        // Update element
650
        element->prev = db->last;
651
        element->next = NULL;
652
        element->alto_db = db;
653
        element->stamp = time(NULL);
654

    
655
        // Update DB
656
        db->last = element;
657
        db->num_of_elements++;
658

    
659
        // This should be it
660
        return 1;
661
}
662

    
663
int alto_rem_element(struct alto_db_element_t * element){
664

    
665
        // Sanity Check
666
        returnIf(element == NULL, "element == NULL! ABORT", -1);
667

    
668
        // Now get the DB where the element is in
669
        struct alto_db_t *db;
670
        db = element->alto_db;
671

    
672
        // Special case, last and only element in DB
673
        if(db->first == element && db->last == element){
674
                // update main DB
675
                db->first = NULL;
676
                db->last = NULL;
677
                db->num_of_elements = 0;
678
                // free element
679
                free(element);
680
                // exit
681
                return 1;
682
        }
683

    
684
        // Special case, first element in chain
685
        if(db->first == element && db->last != element){
686
                // Update successor
687
                element->next->prev = NULL;
688
                // Update DB
689
                db->first = element->next;
690
                db->num_of_elements--;
691
                // free element
692
                free(element);
693
                // exit
694
                return 1;
695
        }
696

    
697
        // Special case, last element in chain
698
        if(db->first != element && db->last == element){
699
                // Update predecessor
700
                element->prev->next = NULL;
701
                // Update DB
702
                db->last = element->prev;
703
                db->num_of_elements--;
704
                // free element
705
                free(element);
706
                // exit
707
                return 1;
708
        }
709

    
710

    
711
        // normal handling, somwhere in the DB
712
        else {
713
                // update predecessor
714
                element->prev->next = element->next;
715
                element->next->prev = element->prev;
716
                // Update DB
717
                db->num_of_elements--;
718
                // free element
719
                free(element);
720
                // exit
721
                return 1;
722
        }
723

    
724
        // Just in case something went wrong
725
        // what NEVER will happen
726
        alto_errorf("%s - Error in removing element function!\n", __FUNCTION__);
727
        return -1;
728
}
729

    
730

    
731
struct in_addr compute_subnet(struct in_addr host, int prefix){
732
        struct in_addr subn;
733
        uint32_t match_host = host.s_addr;
734
        uint32_t match_mask = 0xFFFFFFFF;
735
        match_mask <<= 32 - prefix;
736
        match_mask = ntohl(match_mask);
737
        uint32_t match_merg = match_host & match_mask;
738
//        printf("host  : %s/%d \t", inet_ntoa(host), prefix);
739
//        subn.s_addr = match_mask;
740
//        printf("mask  : %s  \t", inet_ntoa(subn));
741
        subn.s_addr = match_merg;
742
//        printf("net   : %s  \n", inet_ntoa(subn));
743
        return subn;
744
}
745

    
746

    
747

    
748
/*
749
 *         Search in an ALTO DB for the match of an host
750
 *
751
 *         value:        add                Address of the host to search for
752
 *                         db                The ALTO DB to search in
753
 *         return:        value/0        The found value / 0 in case of nothing
754
 */
755
int get_ALTO_rating_for_host(struct in_addr add, ALTO_DB_T * db){
756

    
757
        // Sanity checks
758
        returnIf(add.s_addr == 0, "Couldn't read the ALTO host IP to query! ABORT", 0);
759
        returnIf(db == NULL, "Couldn't access the DB! ABORT", 0);
760

    
761
        // walk through the DB until you find the element
762
    struct alto_db_element_t * cur;
763
    cur = db->first;
764
    while(cur != NULL){
765
            if(cur->host.s_addr == add.s_addr){
766
                    return cur->rating;
767
            }
768
            cur = cur->next;
769
    }
770

    
771
    // Here you come in case of error/not found!
772
        return 0;
773
}
774

    
775

    
776

    
777

    
778

    
779

    
780

    
781

    
782

    
783
int ask_helper_func(struct in_addr subnet, ALTO_DB_T * db){
784
        ALTO_DB_ELEMENT_T * cur = db->first;
785
        while(cur != NULL){
786
                if(subnet.s_addr == cur->host.s_addr){
787
//                        printf("Subnet : %s \t", inet_ntoa(subnet));
788
//                        printf("rating : %d \n", cur->rating);
789
                        return cur->rating;
790
                }
791
                cur = cur->next;
792
        }
793
        return 0;
794
}
795

    
796

    
797

    
798
int get_alto_rating(ALTO_DB_ELEMENT_T * element, ALTO_DB_T * db){
799

    
800
        int mask = element->host_mask;
801
        struct in_addr subnet = compute_subnet(element->host, mask);
802
//        printf("Host: %s/%d \n", inet_ntoa(element->host), mask);
803

    
804
        int i, check;
805
        for(i=mask;i>0;i--){
806
                check = ask_helper_func(subnet, db);
807
                if(check == 0){
808
                        subnet = compute_subnet(element->host, mask--);
809
                }else{
810
//                        printf("Found rating, with value: %d \n", check);
811
                        return check;
812
                }
813
        }
814
        return 0;
815
}
816

    
817

    
818

    
819
int get_alto_subnet_mask(ALTO_DB_ELEMENT_T * element, ALTO_DB_T * db){
820
        int mask = element->host_mask;
821
        struct in_addr subnet = compute_subnet(element->host, mask);
822
//        printf("Host: %s/%d \n", inet_ntoa(element->host), mask);
823
        int i;
824
        for(i=mask;i>0;i--){
825
                if((ask_helper_func(subnet, db)) == 0){
826
                        return mask;
827
                }else{
828
                        mask--;
829
                }
830
        }
831
        return 0;
832
}
833

    
834

    
835

    
836

    
837

    
838

    
839

    
840

    
841
/*
842
 *         Here the matching between the requested IPs and the delivered
843
 *         list will be done
844
 *
845
 *         in:                db_req                Pointer to the DB where the IPs are
846
 *                         db_res                Pointer to the DB where the ALTO response is
847
 *         return:        1                        Success
848
 */
849
int alto_do_the_magic(ALTO_DB_T * ALTO_db_req, ALTO_DB_T * ALTO_db_res){
850
        alto_debugf("%s: Find the rating and assign to IPs\n", __FUNCTION__);
851

    
852
        // Sanity check
853
        returnIf((ALTO_db_req == NULL || ALTO_db_res == NULL), "Errors in accessing the DBs! ABORT", 0);
854

    
855
        // Now iterate through the hosts and find the corresponding rating
856
        ALTO_DB_ELEMENT_T * cur;
857
        cur = ALTO_db_req->first;
858
        while(cur != NULL){
859

    
860
                // store the rating in the asking element
861
                cur->rating = get_alto_rating(cur, ALTO_db_res);
862

    
863
                // next DB item to query
864
                cur = cur->next;
865
        }
866

    
867
        // Aaaaaand finished!
868
        return 1;
869
}
870

    
871

    
872

    
873

    
874

    
875

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

    
879
        FILE *file;
880
        char line[256];
881
        file = fopen(file_name, "r");
882
        char * ptr;
883

    
884
        // Sanity checks
885
        returnIf(db == NULL, "No DB selected! ABORT", 0);
886
        returnIf(file == NULL, "Can't open the file! ABORT", 0);
887

    
888
        // Now read the lines in
889
        while(fgets(line, sizeof(line), file) != NULL ) {
890
                // parse the line, remove the comments
891
                ptr = strtok(line, " ");
892
                // create the ALTO element
893
                struct alto_db_element_t *element;
894
                element = malloc(sizeof(ALTO_DB_ELEMENT_T));
895
                element->host = get_ALTO_host_IP(ptr);
896
                element->host_mask = get_ALTO_host_mask(ptr);
897
                // and add this element to the db
898
                alto_add_element(db, element);
899
            }
900
        return 1;
901
}
902

    
903

    
904

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

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

    
911
        xmlNode *cur = NULL;
912
        cur = xmlDocGetRootElement(doc);
913
        xmlChar *overall_rating, *ipprefix = NULL;
914

    
915
        while(cur!=NULL){
916
                if(!xmlStrcmp(cur->name, BAD_CAST "cnd_hla")){
917
                        overall_rating = xmlGetProp(cur, BAD_CAST "overall_rating");
918
                }if(!xmlStrcmp(cur->name, BAD_CAST "ipprefix")){
919
                        ipprefix = xmlGetProp(cur, BAD_CAST "prefix");
920

    
921
                        // create the ALTO element
922
                        struct alto_db_element_t *element;
923
                        element = malloc(sizeof(ALTO_DB_ELEMENT_T));
924
                        element->host = get_ALTO_host_IP((char*) ipprefix);
925
                        element->host_mask = get_ALTO_host_mask((char*) ipprefix);
926
                        element->rating = atoi(overall_rating);
927

    
928
                        // and add this element to the db
929
                        alto_add_element(db, element);
930

    
931
                } if(cur->children != NULL){
932
//                        printf("cur->children == NULL \n");
933
                        cur = cur->children;
934
                } if(cur->children == NULL && cur->next != NULL){
935
//                        printf("cur->children == NULL && cur->next != NULL \n");
936
                        cur = cur->next;
937
                } if(cur->children == NULL && cur->next == NULL){
938
//                        printf("cur->children == NULL && cur->next == NULL \n");
939
                        cur = cur->parent->next;
940
                }
941
        }
942

    
943
        return 1;
944
}
945

    
946

    
947

    
948
/*
949
 *         Converts a given alto_list_t structure into the internal DB structure
950
 *
951
 *         in:                db                the databse where the element has to be added
952
 *                         list        the list of the alto elements structure
953
 *                         num                number of eements to add
954
 *         ret:        1/-1        for success failuire
955
 */
956
int alto_parse_from_list(struct alto_db_t *db, struct alto_guidance_t *list, int num_of_elements){
957
        alto_debugf("%s: Convert given list into internal DB structure\n", __FUNCTION__);
958

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

    
962
        // and now will the elements in the DB
963
        int i;
964
        for(i=0; i < num_of_elements; i++){
965

    
966
                // Create a new element
967
                struct alto_db_element_t *element;
968
                element = malloc(sizeof(ALTO_DB_ELEMENT_T));
969
                element->alto_db = db;
970
                element->next = NULL;
971
                element->prev = NULL;
972
                element->host = list[i].alto_host;                        // here the values come in
973
                element->host_mask = list[i].prefix;                // here the values come in
974
                element->rating = 0;                                                // here the values come in
975

    
976
                // and now append it to the DB
977
                alto_add_element(db, element);
978
        }
979

    
980
        // That's should be it
981
        return 1;
982
}
983

    
984

    
985

    
986

    
987

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

    
991
        // Sanity checks
992
        returnIf(file_name == NULL, "Can't open the file! ABORT",-1);
993
        returnIf(db == NULL, "No DB select! ABORT", -1);
994

    
995
        // Create the new file
996
        char * str_out;
997
        str_out = (char*)malloc(256 * sizeof(char));
998
        strcpy (str_out,file_name);
999
        strcat (str_out,".out");
1000

    
1001
        // create the output filename
1002
        FILE *file;
1003
        file = fopen(str_out, "a+");
1004
        returnIf(file == NULL, "Can't create the file! ABORT", 0);
1005

    
1006
        // Write everything to the file
1007
        int count = 0;
1008
        ALTO_DB_ELEMENT_T * cur = db->first;
1009
        while(cur != NULL){
1010
                fprintf(file, "%s/%d \t", inet_ntoa(cur->host), cur->host_mask);
1011
                fprintf(file, "%d \t", cur->rating);
1012
                fprintf(file, "\n");
1013
                count++;
1014
                cur = cur->next;
1015
        }
1016

    
1017
        // Return the number of sucessful written lines
1018
        return count;
1019
}
1020

    
1021

    
1022

    
1023

    
1024
/*
1025
 *         Start & Innitialize the ALTO client
1026
 */
1027
void start_ALTO_client(){
1028
        alto_debugf("START ALTO client! \n");
1029

    
1030
        // initialize the DBs
1031
        ALTO_DB_req = alto_db_init();
1032
        ALTO_DB_res = alto_db_init();
1033

    
1034
        // prepare the XML environment
1035
        LIBXML_TEST_VERSION;
1036

    
1037
        // and Initialize the XMLs
1038
    ALTO_XML_req = NULL;
1039
    ALTO_XML_res = NULL;
1040

    
1041

    
1042
}
1043

    
1044

    
1045
/*
1046
 *         Stop & CleanUp the ALTO client
1047
 */
1048
void stop_ALTO_client(){
1049
        alto_debugf("STOP ALTO client! \n");
1050

    
1051
        // Kill the DBs
1052
        alto_free_db(ALTO_DB_req);
1053
        alto_free_db(ALTO_DB_res);
1054

    
1055
        // Kill the XML
1056
    if (ALTO_XML_req) { xmlFreeDoc(ALTO_XML_req); ALTO_XML_req = NULL; }
1057
    if (ALTO_XML_res) { xmlFreeDoc(ALTO_XML_res); ALTO_XML_res = NULL; }
1058

    
1059
        xmlCleanupParser();
1060
}
1061

    
1062

    
1063

    
1064

    
1065

    
1066

    
1067
/*
1068
 *         Function:        gets for a list in a txt file the correct rating
1069
 *
1070
 *         in:                        *txt        pointer to the list
1071
 *                                 rc_host        The Resource Consumer locator
1072
 *                                 pri_rat        Primary Rating criteria
1073
 *                                 sec_rat        Secondary Rating criteria
1074
 *         return:                1/0                Success/Erros
1075
 */
1076
int get_ALTO_guidance_for_txt(char * txt, struct in_addr rc_host, int pri_rat, int sec_rat){
1077
        alto_debugf("get_ALTO_guidance_txt(%s) was called \n", txt);
1078

    
1079
        // Sanity checks 
1080
        returnIf(txt == NULL, "Can't access the file! ABORT!", 0);
1081
        returnIf(rc_host.s_addr == NULL, "Can't read the rc_host! ABORT!", 0);
1082
        returnIf((pri_rat < 1 || pri_rat > 3), "Primary Rating Criteria wrong! ABORT!", 0);
1083
        returnIf((sec_rat < 1 || sec_rat > 8), "Secondary Rating Criteria(s) wrong! ABORT", 0);
1084

    
1085
        // first purge existing DB entries
1086
        alto_purge_db(ALTO_DB_req);
1087

    
1088
        // Step 1: fill the txt into the DB
1089
        alto_parse_from_file(ALTO_DB_req, txt);
1090

    
1091
        // do the ALTO trick / update db
1092
        do_ALTO_update(rc_host, pri_rat, sec_rat);
1093

    
1094
        // Step 3 (write values back)
1095
        alto_write_to_file(ALTO_DB_req, txt);
1096

    
1097
        // done
1098
        return 1;
1099
}
1100

    
1101
/*
1102
 *         Function:        gets for a list of elements the correct rating
1103
 *
1104
 *         in:                        *list        pointer to the list
1105
 *                                 *num        Number of elements to process
1106
 *         return:                count        Number of sucessfully processed hosts
1107
 */
1108
int get_ALTO_guidance_for_list(ALTO_GUIDANCE_T * list, int num, struct in_addr rc_host, int pri_rat, int sec_rat){
1109
        alto_debugf("get_ALTO_guidance(list, num_of_elements) was called \n");
1110

    
1111
        int count = 0;
1112

    
1113
        // Sanity checks (list)
1114
        returnIf(list == NULL, "Can't access the list!", 0);
1115

    
1116
        // Sanity checks (num of elements)
1117
        returnIf(num < 0, "<0 elements?", 0);
1118

    
1119
        // first purge existing DB entries
1120
        alto_purge_db(ALTO_DB_req);
1121

    
1122
        // Step 1 (read struct into DB)
1123
        alto_parse_from_list(ALTO_DB_req, list, num);
1124

    
1125
        // do the ALTO trick / update db
1126
        do_ALTO_update(rc_host, pri_rat, sec_rat);
1127

    
1128
        // Step 2 (write values back)
1129
        for(count = 0; count < num; count++){
1130
                list[count].rating = get_ALTO_rating_for_host(list[count].alto_host, ALTO_DB_req);
1131
        }
1132

    
1133
        // This should be it
1134
        return 1;
1135
}
1136

    
1137
/*==================================
1138
    Multi-Threaded Query
1139
  ==================================*/
1140

    
1141
static int queryState = ALTO_QUERY_READY;
1142

    
1143
static pthread_t threadId;
1144
static pthread_attr_t attr;
1145

    
1146
typedef struct {
1147
        ALTO_GUIDANCE_T* list;
1148
        int num;        // number of elements in list
1149
        struct in_addr rc_host;
1150
        int pri_rat;
1151
        int sec_rat;
1152
} ALTO_ThreadArgs_t;
1153

    
1154
ALTO_ThreadArgs_t threadArgs;
1155

    
1156
void* alto_query_thread_func(void* thread_args)
1157
{
1158
        int count = 0;
1159
        ALTO_ThreadArgs_t* args = (ALTO_ThreadArgs_t*) thread_args;
1160

    
1161
        alto_debugf("alto_query_thread_func\n");
1162

    
1163
        // this will block at some point
1164
        do_ALTO_update(args->rc_host, args->pri_rat, args->sec_rat);
1165

    
1166
        // write values back
1167
        for(count = 0; count < args->num; count++){
1168
                args->list[count].rating = get_ALTO_rating_for_host(args->list[count].alto_host, ALTO_DB_req);
1169
        }
1170

    
1171
        // signal that query is ready
1172
        queryState = ALTO_QUERY_READY;
1173

    
1174
        return thread_args;
1175
}
1176

    
1177
int ALTO_query_state() {
1178
        return queryState;
1179
}
1180

    
1181
int ALTO_query_exec(ALTO_GUIDANCE_T * list, int num, struct in_addr rc_host, int pri_rat, int sec_rat){
1182
        alto_debugf("ALTO_query_exec\n");
1183

    
1184
        // Sanity checks (list)
1185
        returnIf(list == NULL, "Can't access the list!", 0);
1186

    
1187
        // Sanity checks (num of elements)
1188
        returnIf(num < 0, "<0 elements?", 0);
1189

    
1190
        // set new state
1191
        queryState = ALTO_QUERY_INPROGRESS;
1192

    
1193
        // first purge existing DB entries
1194
        alto_purge_db(ALTO_DB_req);
1195

    
1196
        // Step 1 (read struct into DB)
1197
        alto_parse_from_list(ALTO_DB_req, list, num);
1198

    
1199
        //ALTO_XML_req = alto_create_request_XML(ALTO_DB_req, rc_host, pri_rat, sec_rat);
1200

    
1201
        threadArgs.list = list;
1202
        threadArgs.num = num;
1203
        pthread_attr_init(&attr);
1204
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1205
        if (pthread_create(&threadId, &attr, alto_query_thread_func, &threadArgs) != 0) {
1206
                fprintf(stderr,"[ALTOclient] pthread_create failed!\n");
1207
                queryState = ALTO_QUERY_READY;
1208
                return 0;
1209
        }
1210

    
1211
        // This should be it
1212
        return 1;
1213
}
1214

    
1215

    
1216

    
1217
/*
1218
 * Function:        With this call the internal request to update the DB is triggered.
1219
 *                                 This should be done on a regual basis to keep the local ALTO-DB
1220
 *                                 up2date
1221
 */
1222

    
1223

    
1224
void do_ALTO_update(struct in_addr rc_host, int pri_rat, int sec_rat){
1225

    
1226
        // Step 2: create an XML from the DB entries
1227
        ALTO_XML_req = alto_create_request_XML(ALTO_DB_req, rc_host, pri_rat, sec_rat);
1228

    
1229
#ifndef USE_LOCAL_REPLY_XML
1230
        // Step2a: send POST request to ALTO server
1231
        #ifdef USE_CURL
1232
        ALTO_XML_res = query_ALTO_server_curl(ALTO_XML_req, alto_server_url);
1233
        #else
1234
        ALTO_XML_res = ALTO_request_to_server(ALTO_XML_req, alto_server_url);
1235
        #endif
1236
#else
1237
        // Step2b: use for testing the local stored TXT-file
1238
        ALTO_XML_res = xmlReadFile("reply.xml",NULL,XML_PARSE_RECOVER);
1239
#endif
1240

    
1241
        // Step 3: Parse the XML to the DB
1242
        alto_parse_from_XML(ALTO_DB_res, ALTO_XML_res);
1243

    
1244
        // ###### Big Magic ######
1245
        // And now check for the corresponding rating
1246
        alto_do_the_magic(ALTO_DB_req, ALTO_DB_res);
1247

    
1248
        // free xml data
1249
        xmlFreeDoc(ALTO_XML_req);
1250
        xmlFreeDoc(ALTO_XML_res);
1251
        ALTO_XML_req = NULL;
1252
        ALTO_XML_res = NULL;
1253

    
1254
        // purge the intermediate DB
1255
        alto_purge_db(ALTO_DB_res);
1256
}
1257

    
1258

    
1259

    
1260

    
1261

    
1262

    
1263

    
1264

    
1265