973e9d2a3391fb42d515893c99862e16e3482a2a
[sip-router] / utils / pdbt / pdbt.c
1 /*
2  * Copyright (C) 2009 1&1 Internet AG
3  *
4  * This file is part of sip-router, a free SIP server.
5  *
6  * sip-router is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * sip-router is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License 
17  * along with this program; if not, write to the Free Software 
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #define _GNU_SOURCE
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <fcntl.h>
27 #include <sys/time.h>
28 #include <poll.h>
29 #include <ctype.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <netdb.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include "dt.h"
37 #include "dtm.h"
38 #include "carrier.h"
39 #include "log.h"
40
41
42
43
44 #define NETBUFSIZE 200
45
46
47
48
49 typedef void (*query_func_t)(char *number, char *comment, void *data);
50
51
52
53
54 void print_usage(char *program) {
55         set_log_level(LOG_INFO);
56         LINFO("Usage: %s [<option>...] <command> [<param>...]\n", program);
57         LINFO("  %s -s <csv file> -m <mmap file> [-k <ids>] [-o] [-u <tree file>] [-l <log level>] build\n", program);
58         LINFO("  %s (-m <mmap file>|-r <host>:<port>) [-q <timeout>] [-f <query file>] [-t <carrier text file>] [-l <log level>] query <number>...\n", program);
59         LINFO("\n");
60         LINFO("  Commands:\n");
61         LINFO("    build: Build a mmap image from a csv list.\n");
62         LINFO("    query: Query a mmap image or pdb_server.\n");
63         LINFO("           Uses Numbers given on commandline or in a file (-f).\n");
64         LINFO("\n");
65         LINFO("  Options:\n");
66         LINFO("    -s <file>: Specifies the csv list.\n");
67         LINFO("               Use '-' as filename to read from stdin.\n");
68         LINFO("               Line format: <number prefix>;<carrier id>\n");
69         LINFO("               Format of carrier id: D[0-9][0-9][0-9]\n");
70         LINFO("    -m <file>: Specifies the mmap image.\n");
71         LINFO("    -f <file>: Specifies the query file.\n");
72         LINFO("               Use '-' as filename to read from stdin.\n");
73         LINFO("               Each number must be in a separate line.\n");
74         LINFO("               Numbers on the command line will not be processed.\n");
75         LINFO("    -t <file>: Specifies the file containing carrier names.\n");
76         LINFO("               In addition to the carrier code these names will be shown\n");
77         LINFO("               when querying numbers.\n");
78         LINFO("               Each carrier id and name must be in a separate line.\n");
79         LINFO("               Format: D[0-9][0-9][0-9] <name>\n");
80         LINFO("    -k <ids>: Keep these carrier ids.\n");
81         LINFO("              Merge all other carrier ids into a new id.\n");
82         LINFO("              This will save some memory.\n");
83         LINFO("              Format: <id>[,<id>...]\n");
84         LINFO("    -r <host>:<port>: Host and port to be used for remote server queries.\n");
85         LINFO("    -q <timeout>: Timeout for remote server queries in milliseconds.\n");
86         LINFO("                  Default is 500 ms.\n");
87         LINFO("    -o: Try to optimize the data structure when building a mmap image.\n");
88         LINFO("    -u: Write (possibly optimized) tree structure in human-readable format to the given file.\n");
89         LINFO("    -l <debug level>: %ld for debug level.\n", LOG_DEBUG);
90         LINFO("                      %ld for info level.\n", LOG_INFO);
91         LINFO("                      %ld for notice level.\n", LOG_NOTICE);
92         LINFO("                      %ld for warning level.\n", LOG_WARNING);
93         LINFO("                      %ld for error level.\n", LOG_ERR);
94         LINFO("                      %ld for critical level.\n", LOG_CRIT);
95         LINFO("                      %ld for alert level.\n", LOG_ALERT);
96         LINFO("                      %ld for emergency level.\n", LOG_EMERG);
97         LINFO("                      %ld to disable all messages.\n", LOG_EMERG-1);
98         LINFO("                      Default is info level.\n");
99         LINFO("    -h: Print this help.\n");
100 }
101
102
103
104
105 void print_stats(struct dt_node_t *root) {
106         int s;
107         int l;
108         int c;
109
110         LINFO("+----------------------------------------\n");
111         s = dt_size(root);
112         LINFO("| %ld nodes in tree (%ld bytes, %ld KB, %ld MB)\n", (long int)s, (long int)s*sizeof(struct dt_node_t), (long int)s*sizeof(struct dt_node_t)/1024, (long int)s*sizeof(struct dt_node_t)/1024/1024);
113         l = dt_leaves(root);
114         LINFO("| %ld nodes are leaves (%ld bytes, %ld KB, %ld MB)\n", (long int)l, (long int)l*sizeof(struct dt_node_t), (long int)l*sizeof(struct dt_node_t)/1024, (long int)l*sizeof(struct dt_node_t)/1024/1024);
115         c = dt_loaded_nodes(root);
116         LINFO("| %ld carrier nodes in tree\n", (long int)c);
117         LINFO("| \n");
118         LINFO("| After saving with leaf node compression:\n");
119         LINFO("| %ld nodes in tree (%ld bytes, %ld KB, %ld MB)\n", (long int)s-l, (long int)(s-l)*sizeof(struct dtm_node_t), (long int)(s-l)*sizeof(struct dtm_node_t)/1024, (long int)(s-l)*sizeof(struct dtm_node_t)/1024/1024);
120         LINFO("+----------------------------------------\n");
121 }
122
123
124
125
126 int file_query(char *filename, query_func_t query_func, void *data) {
127         char * p;
128         char * comment;
129         FILE * fp;
130         char * line = NULL;
131         size_t len = 0;
132         ssize_t read;
133
134         LINFO("\nprocessing query file '%s'...\n", filename);
135   if (strcmp(filename, "-")==0) fp=stdin;
136         else fp = fopen(filename, "r");
137         if (fp == NULL) {
138                 LERR("cannot open file '%s'\n", filename);
139                 return -1;
140         }
141         while ((read = getline(&line, &len, fp)) != -1) {
142                 p=line;
143                 while ((*p >= '0') && (*p <= '9') && (p < line+len)) p++;
144                 *p='\0';
145                 p++;
146                 comment=p;
147                 while ((*p >= 32) && (p < line+len)) p++;
148                 *p='\0';
149                 query_func(line, comment, data);
150         }
151         if (line) free(line);
152         fclose(fp);
153         return 0;
154 }
155
156
157
158
159 /*
160  Read a csv list from the given file and build a dtree structure.
161  Format of lines in csv file: "<number prefix>;<carrier id>".
162  Format of carrier id: "D[0-9][0-9][0-9]".
163  Returns the number of lines imported or -1 on error.
164 */
165 int import_csv(struct dt_node_t *root, char *filename) {
166         char *prefix;
167         char *carrier_str;
168         carrier_t carrier;
169         long int ret;
170
171         FILE * fp;
172         char * line = NULL;
173         size_t len = 0;
174         ssize_t read;
175         int i=0;
176         int n=1;
177
178   if (strcmp(filename, "-")==0) fp=stdin;
179         else fp = fopen(filename, "r");
180         if (fp == NULL) {
181                 LERR("cannot open file '%s'\n", filename);
182                 return -1;
183         }
184         while ((read = getline(&line, &len, fp)) != -1) {
185                 carrier_str=line;
186                 prefix=strsep(&carrier_str, ";");
187                 ret=strtol(carrier_str, NULL, 10);
188                 if (!IS_VALID_PDB_CARRIERID(ret)) {
189                         LWARNING("invalid carrier '%s' in line %ld.\n", carrier_str, (long int)n);
190                         if (line) free(line);
191                         fclose(fp);
192                         return -1;
193                 }
194                 else {
195                         carrier=ret;
196                         i++;
197                         dt_insert(root, prefix, strlen(prefix), carrier);
198                 }
199                 n++;
200         }
201         if (line) free(line);
202         fclose(fp);
203         return i;
204 }
205
206
207
208
209 /*
210  Returns 1 if the given node is a leaf node, 0 otherwise.
211 */
212 inline int dt_is_leaf(struct dt_node_t *root)
213 {
214         int i;
215
216         for (i=0; i<10; i++) {
217                 if (root->child[i]) return 0;
218         }
219
220         return 1;
221 }
222
223
224
225 /*
226  Recursively writes sequences of digits (i.e., telephone numbers/prefixes) and mapped
227  carrier ids to the given file descriptor for the entire subtree starting at the
228  given node. Each written line matches one such sequence and its mapped carried id.
229  Returns 1 on success, -1 otherwise.
230  */
231 int dt_write_tree_recursor(const struct dt_node_t *node, const int fd, char* number)
232 {
233         int i;
234         int ret;
235         int slen;
236         char *buf;
237         char *p;
238         int bufsize;
239
240         if (node == NULL) return 0;
241
242         slen = strlen(number);
243         if (slen > 0) {
244                 
245                 bufsize = slen + 1 + 1 + 3 + 1 + 1;                 // line buffer (telephone number + colon + white space + carrier ID + newline + \0)
246                 buf = (char *)malloc(bufsize);      
247                 if (buf == NULL) {
248                         LERR("could not allocate line output buffer of size %d\n", bufsize);
249                         return -1;
250                 }
251
252                 /* construct outline line */
253                 p = strncpy(buf, number, slen);
254                 p += slen;
255                 strncpy(p, ": ", 2);
256                 p += 2;
257                 ret = snprintf(p, 5, "%d\n", node->carrier);
258                 if (ret < 1 || ret > 4) {
259                         LERR("snprintf failed to write correct number of characters\n");
260                         return -1;
261                 }
262
263                 /* write line to file */
264                 ret = write(fd, (void *)buf, strlen(buf));
265                 if (ret != strlen(buf)) {
266                         LERR("could not write (complete) line output '%s' to file\n", number);
267                         return -1;
268                 }
269                 free(buf);
270         }
271
272         for (i=0;i<10;i++) {
273                 /* extend number by single digit and adjust terminating null byte */
274                 number[slen] = i + '0';
275                 number[slen+1] = '\0';      /* must always be done because other recursive invocations operate on `number' too */
276                 ret = dt_write_tree_recursor(node->child[i], fd, number);
277                 if (ret < 0) {
278                         LERR("could not write node\n");
279                         return -1;
280                 }
281         }
282
283         return 1;
284 }
285
286
287
288 /*
289  Writes tree to a file in human-readable format, i.e., ASCII.
290  Returns 1 on success, -1 otherwise.
291  */
292 int dt_write_tree(const struct dt_node_t *root, const char* filename)
293 {
294         int fd;
295         char number[25];
296         number[0] = '\0';
297
298         fd = creat(filename, S_IRWXU);
299         if (fd < 0) {
300                 LERR("cannot create file '%s'\n", filename);
301                 return -1;
302         }
303         
304         if (dt_write_tree_recursor(root, fd, (char *)&number) < 0) {
305                 LERR("writing tree to file '%s' failed\n", filename);
306                 return -1;
307         }
308
309         close(fd);
310         return 1;
311 }
312
313
314
315 /*
316   Saves the given node and all sub-nodes to an mmappable file recursively.
317   Pointers from parent to child nodes will be represented by positive numbers indexing
318   file offsets. The "pointee" address within the file will be linearly proportional to
319   this number.
320   Pointers to leaf nodes will be replaced by leaf node carrier ids encoded in negative
321   numbers, thereby discarding the leaves layer in the tree. Note that this optimization
322   accounts for the majority of space saving.
323   Returns the index of the next free node, -1 on error.
324  */
325 dtm_node_index_t save_recursor(struct dt_node_t *root, int fd, dtm_node_index_t n) {
326         dtm_node_index_t i;
327         dtm_node_index_t nn=n+1; /* next free node */
328         struct dtm_node_t node;
329         int offset;
330
331         node.carrier=root->carrier;
332         for (i=0; i<10; i++) {
333                 if (root->child[i]) {
334                         if (dt_is_leaf(root->child[i])) {
335                                 node.child[i]=-root->child[i]->carrier;
336                         }
337                         else {
338                                 node.child[i]=nn;
339                                 nn=save_recursor(root->child[i], fd, nn);
340                         }
341                 }
342                 else {
343                         node.child[i]=NULL_CARRIERID;
344                 }
345         }
346
347         offset=lseek(fd, n*sizeof(struct dtm_node_t), SEEK_SET);
348         if (offset < 0) {
349                 LERR("could not position file offset to address %d: errno=%d (%s)\n", n*sizeof(struct dtm_node_t), errno, strerror(errno));
350                 return -1;
351         }
352         if (write(fd, &node, sizeof(struct dtm_node_t)) != sizeof(struct dtm_node_t)) {
353                 LERR("could not write %d bytes of node data at file address %d: errno=%d (%s)\n", sizeof(struct dtm_node_t), offset, errno, strerror(errno));
354                 return -1;
355         }
356
357         return nn;
358 }
359
360
361
362
363 /*
364         Saves the given tree in a mmappable file.
365         Returns the number of nodes saved or -1 on error.
366 */
367 int save_mmap(struct dt_node_t *root, char *filename) {
368         int fd;
369         int n;
370
371         fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU);
372         if (fd < 0) {
373                 LERR("cannot create file '%s'\n", filename);
374                 return -1;
375         }
376
377         n=save_recursor(root, fd, 0);
378
379         close(fd);
380
381         return n;
382 }
383
384
385
386
387 /*
388  Returns 1 if carrier is found in keep_carriers, 0 otherwise.
389 */
390 int keep_carrier_func(carrier_t carrier, int keep_carriers_num, carrier_t keep_carriers[])
391 {
392         int i;
393
394         for (i=0; i<keep_carriers_num; i++) {
395                 if (keep_carriers[i]==carrier) return 1;
396         }
397
398         return 0;
399 }
400
401
402
403
404 int merge_carrier_recursor(struct dt_node_t *node, int keep_carriers_num, carrier_t keep_carriers[], carrier_t lastcarrier)
405 {
406   carrier_t currentcarrier;
407         int i;
408         int sum=0;
409
410         if (node==NULL) return 0;
411
412         if (node->carrier>0) {
413                 if (!keep_carrier_func(node->carrier, keep_carriers_num, keep_carriers)) {
414                         sum++;
415                         if (lastcarrier==0) node->carrier=0; /* first carrier we encountered. we can remove it since we are not interested in it. */
416                         else {
417                                 node->carrier=OTHER_CARRIERID; /* we already have a carrier we are interested in. this is an exception, set it to a special carrier id. */
418                         }
419                 }
420         }
421
422         if (node->carrier>0) currentcarrier=node->carrier;
423         else currentcarrier=lastcarrier;
424
425         /* merge children carriers */
426         for (i=0; i<10; i++) {
427                 sum+=merge_carrier_recursor(node->child[i], keep_carriers_num, keep_carriers, currentcarrier);
428         }
429
430         return sum;
431 }
432
433
434
435
436 /*
437  Merge all carriers not in keep_carriers into one new carrier id.
438  This will save some memory.
439  Returns the number of nodes modified.
440 */
441 int merge_carrier(struct dt_node_t *root, int keep_carriers_num, carrier_t keep_carriers[])
442 {
443         return merge_carrier_recursor(root, keep_carriers_num, keep_carriers, 0);
444 }
445
446
447
448
449 /**
450  * return the corresponding carrier id, -1 on error
451  */
452 int query_udp(char *number, int timeout, struct pollfd *pfds, struct sockaddr_in *dstaddr, socklen_t dstaddrlen)
453 {
454         struct timeval tstart, tnow;
455         short int carrierid;
456         char buf[NETBUFSIZE+1+sizeof(carrierid)];
457         size_t reqlen;
458         int ret, nflush;
459         long int td;
460
461         if (gettimeofday(&tstart, NULL) != 0) {
462                 LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
463                 return -1;
464         }
465
466         /* clear recv buffer */
467         nflush = 0;
468         while (recv(pfds->fd, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) {
469                 nflush++;
470                 if (gettimeofday(&tnow, NULL) != 0) {
471                         LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
472                         return -1;
473                 }
474                 td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
475                 if (td > timeout) {
476                         LWARNING("exceeded timeout while flushing recv buffer.\n");
477                         return -1;
478                 }
479         }
480         
481         /* prepare request */
482         reqlen = strlen(number) + 1; /* include null termination */
483         if (reqlen > NETBUFSIZE) {
484                 LERR("number too long '%s'.\n", number);
485                 return -1;
486         }
487         strcpy(buf, number);
488
489         /* send request to all servers */
490         ret=sendto(pfds->fd, buf, reqlen, MSG_DONTWAIT, (struct sockaddr *)dstaddr, dstaddrlen);
491         if (ret < 0) {
492                 LERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
493                 return -1;
494         }
495                 
496         /* wait for response */
497         for (;;) {
498                 if (gettimeofday(&tnow, NULL) != 0) {
499                         LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
500                         return -1;
501                 }
502                 td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
503                 if (td > timeout) {
504                         LWARNING("exceeded timeout while waiting for response.\n");
505                         return -1;
506                 }
507                 
508                 ret=poll(pfds, 1, timeout-td);
509                 if (pfds->revents & POLLIN) {
510                         if (recv(pfds->fd, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) { /* do not block - just in case select/poll was wrong */
511                                 buf[NETBUFSIZE] = '\0';
512                                 if (strcmp(buf, number) == 0) {
513                                         carrierid=ntohs(*((short int *)&(buf[reqlen]))); /* convert to host byte order */
514                                         goto found;
515                                 }
516                         }
517                 }
518                 pfds->revents = 0;
519         }
520
521         found:
522         if (gettimeofday(&tnow, NULL) == 0) {
523                 LINFO("got an answer in %f ms\n", ((double)(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000))/1000);
524         }
525         return carrierid;
526 }
527
528
529
530
531 struct server_query_data_t {
532         int timeout;
533         struct sockaddr_in dstaddr;
534         socklen_t dstaddrlen;
535         struct pollfd pfds;
536 };
537
538
539
540
541 void query_mmap(char *number, char *comment, void *data) {
542         int nmatch;
543         carrier_t carrierid;
544         struct dtm_node_t *mroot = (struct dtm_node_t *)data;
545
546         nmatch=dtm_longest_match(mroot, number, strlen(number), &carrierid);
547
548         if (nmatch<=0) {
549                 LINFO("%s: not_found: nmatch=%ld, comment='%s'\n", number, (long int)nmatch, comment);
550         }
551         else {
552                 LINFO("%s: found: carrier_id=%ld, carrier_name='%s', nmatch=%ld, comment='%s'\n", number, (long int)carrierid, carrierid2name(carrierid), (long int)nmatch, comment);
553         }
554 }
555
556
557
558
559 void query_server(char *number, char *comment, void *data) {
560         carrier_t carrierid;
561         struct server_query_data_t *sdata = (struct server_query_data_t *)data;
562
563         carrierid = query_udp(number, sdata->timeout, &(sdata->pfds), &(sdata->dstaddr), sdata->dstaddrlen);
564
565         if (carrierid<=0) {
566                 LINFO("%s: not_found: comment='%s'\n", number, comment);
567         }
568         else {
569                 LINFO("%s: found: carrier_id=%ld, carrier_name='%s', comment='%s'\n", number, (long int)carrierid, carrierid2name(carrierid), comment);
570         }
571 }
572
573
574
575
576 int main(int argc, char *argv[]) {
577         int n;
578         struct dt_node_t root;
579         memset(&root, 0, sizeof(root));
580         struct dtm_node_t *mroot;
581
582         int opt;
583         char *csv_file = NULL;
584         char *mmap_file = NULL;
585         char *query_file = NULL;
586         char *tree_file = NULL;
587         int optimize = 0;
588         int keep_carriers_num = 0;
589         carrier_t keep_carriers[MAX_PDB_CARRIERID+1];
590         char *host_str = NULL;
591         char *port_str = NULL;
592         unsigned short int port = 0;
593         char *tmp;
594         int log_level = LOG_INFO;
595
596         struct hostent *hp;
597         int sockfd;
598
599         struct server_query_data_t sdata;
600
601         char *id_str;
602         long int ret;
603
604         sdata.timeout=500;
605
606         init_carrier_names();
607
608         init_log("pdbt", 0);
609
610         while ((opt = getopt(argc, argv, "s:m:f:u:t:r:q:k:ol:h")) != -1) {
611                 switch (opt) {
612                 case 's':
613                         csv_file = optarg;
614                         break;
615                 case 'm':
616                         mmap_file = optarg;
617                         break;
618                 case 'f':
619                         query_file = optarg;
620                         break;
621                 case 'u':
622                         tree_file = optarg;
623                         break;
624                 case 'k':
625                         while ((id_str=strsep(&optarg, ","))) {
626                                 ret=strtol(id_str, NULL, 10);
627                                 if (!IS_VALID_PDB_CARRIERID(ret)) {
628                                         LERR("invalid carrier id '%s' specified.\n", id_str);
629                                         return -1;
630                                 }
631                                 if (keep_carriers_num>MAX_PDB_CARRIERID) {
632                                         LERR("too many carrier ids specified.\n");
633                                         return -1;
634                                 }
635                                 keep_carriers[keep_carriers_num]=ret;
636                                 keep_carriers_num++;
637                         }
638                         break;
639                 case 't':
640                         if (load_carrier_names(optarg)<0) {
641                                 LERR("cannot load carrier names from '%s'.\n", optarg);
642                                 return -1;
643                         }
644                         break;
645                 case 'r':
646                         host_str=optarg;
647
648                         tmp = strchr(host_str, ':');
649                         if (tmp == NULL) {
650                                 LERR("syntax error in remote host:port specification '%s'.\n", host_str);
651                                 return -1;
652                         }
653                         *tmp = '\0';
654                         port_str = tmp + 1;
655
656                         ret=strtol(port_str, NULL, 10);
657                         if ((ret<0) || (ret==LONG_MAX)) {
658                                 LERR("invalid timeout '%s'\n", optarg);
659                                 return -1;
660                         }
661                         port = ret;
662
663                         break;
664                 case 'q':
665                         ret=strtol(optarg, NULL, 10);
666                         if ((ret<0) || (ret>65535)) {
667                                 LERR("invalid port '%s'\n", port_str);
668                                 return -1;
669                         }
670                         sdata.timeout = ret;
671
672                         break;
673                 case 'o':
674                         optimize=1;
675                         break;
676                 case 'l':
677                         ret=strtol(optarg, NULL, 10);
678                         if ((ret<LOG_EMERG-1) || (ret>LOG_DEBUG)) {
679                                 LERR("invalid log level '%s' specified.\n", optarg);
680                                 return -1;
681                         }
682                         log_level=ret;
683                         break;
684                 case 'h':
685                         print_usage(argv[0]);
686                         return 0;
687                         break;
688                 default:
689                         LERR("invalid option '%c'.\n", opt);
690                         print_usage(argv[0]);
691                         return 1;
692                 }
693         }
694
695         set_log_level(log_level);
696
697         if (optind>=argc) {
698                 LERR("no command specified.\n");
699                 return 1;
700         }
701
702         if (strcmp(argv[optind], "build")==0) {
703                 if (csv_file==NULL) {
704                         LERR("no csv file specified.\n");
705                         return 1;
706                 }
707
708                 if (mmap_file==NULL) {
709                         LERR("no mmap file specified.\n");
710                         return 1;
711                 }
712
713                 LINFO("loading '%s'...\n", csv_file);
714                 n = import_csv(&root, csv_file);
715                 if (n < 0) {
716                         LERR("cannot import '%s'\n", csv_file);
717                         return -1;
718                 }
719                 LINFO("done.\n");
720                 LINFO("%ld lines imported\n", (long int)n);
721
722                 LINFO("Node size is %ld bytes (%ld for dtm)\n", (long int)sizeof(struct dt_node_t), (long int)sizeof(struct dtm_node_t));
723                 print_stats(&root);
724
725                 if (keep_carriers_num) {
726                         LINFO("merging carriers...\n");
727                         n=merge_carrier(&root, keep_carriers_num, keep_carriers);
728                         LINFO("done (modified %ld nodes).\n", (long int)n);
729                 }
730
731                 if (optimize) {
732                         LINFO("optimizing...\n");
733                         dt_optimize(&root);
734                         LINFO("done.\n");
735                         print_stats(&root);
736                 }
737
738                 if (tree_file != NULL) {
739                         LINFO("writing human-readable tree...\n");
740                         if (dt_write_tree(&root, tree_file) < 0) {
741                                 LERR("cannot write tree\n");
742                                 return -1;
743                     }
744                         LINFO("done.\n");
745                 }
746
747                 LINFO("saving to '%s'...\n", mmap_file);
748                 n = save_mmap(&root, mmap_file);
749                 if (n < 0) {
750                         LERR("cannot save '%s'\n", mmap_file);
751                         return -1;
752                 }
753                 LINFO("done.\n");
754                 LINFO("%ld nodes saved\n", (long int)n);
755         }
756         else if (strcmp(argv[optind], "query")==0) {
757                 if ((mmap_file!=NULL) && (host_str!=NULL)) {
758                         LERR("you cannot query a pdb_server and a mmap file at the same time.\n");
759                         return 1;
760                 }
761
762                 if ((mmap_file==NULL) && (host_str==NULL)) {
763                         LERR("neither a mmap file nor a remote host specified.\n");
764                         return 1;
765                 }
766
767                 if (mmap_file==NULL) {
768                         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
769                         if (sockfd<0) {
770                                 LERR("socket() failed with errno=%d (%s).\n", errno, strerror(errno));
771                                 return -1;
772                         }
773
774                         memset(&sdata.dstaddr, 0, sizeof(sdata.dstaddr));
775                         sdata.dstaddr.sin_family = AF_INET;
776                         sdata.dstaddr.sin_port = htons(port);
777                         hp = gethostbyname(host_str);
778                         if (hp == NULL) {
779                                 LERR("gethostbyname(%s) failed with h_errno=%d.\n", host_str, h_errno);
780                                 close(sockfd);
781                                 return -1;
782                         }
783                         memcpy(&sdata.dstaddr.sin_addr.s_addr, hp->h_addr, hp->h_length);
784                         sdata.dstaddrlen=sizeof(sdata.dstaddr);
785
786                         sdata.pfds.fd=sockfd;
787                         sdata.pfds.events=POLLIN;
788
789                         if (query_file==NULL) {
790                                 LINFO("\nprocessing command line parameters...\n");
791                                 for (n=optind+1; n<argc; n++) {
792                                         query_server(argv[n], "", &sdata);
793                                 }
794                         }
795                         else {
796                                 file_query(query_file, query_server, &sdata);
797                         }
798                 }
799                 else {
800                         mroot=dtm_load(mmap_file);
801                         if (mroot == NULL) {
802                                 LERR("cannot load '%s'.\n", mmap_file);
803                                 return -1;
804                         }
805                         
806                         if (query_file==NULL) {
807                                 LINFO("\nprocessing command line parameters...\n");
808                                 for (n=optind+1; n<argc; n++) {
809                                         query_mmap(argv[n], "", mroot);
810                                 }
811                         }
812                         else {
813                                 file_query(query_file, query_mmap, mroot);
814                         }
815                 }
816         }
817         else {
818                 LERR("invalid command '%s'.\n", argv[optind]);
819                 return 1;
820         }
821
822         return 0;
823 }