Browse Source

pdb: new protocol between pdb_server and kama pdb module

Modified the communication protocol between the pdb clent <-> server such
that the server will give more feedback on scenarios like "pdb_id not found" or
"request number contains letters". New msg types or reply codes can be easily
added. Curent version of the protocol is 1 (0x01).
Also backwards compatibility is maintained when the first received byte is
different than the known versions (now, just 0x01).
Updated the http link for the get_carrier_germany script. Created a new perl
script to get german carrier id.
Updated doku (utils/pdbt/docs/network_protocol.txt).

added the perls script
Stefan Mititelu 10 năm trước cách đây
mục cha
commit
f995edfb7f

+ 92 - 0
modules/pdb/common.h

@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2009 1&1 Internet AG
+ *
+ * This file is part of sip-router, a free SIP server.
+ *
+ * sip-router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * sip-router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+
+
+
+#include <stdint.h> 
+
+
+
+
+/*
+ 0 no carrier id defined.
+ 1..999 are regular carrier ids.
+ 1000 is used as fake carrier id when merging carriers we are not interested in.
+ -1000..-1 used in dtm to indicate a carrier id and that no more nodes will follow (leaf node compression).
+ -1001 used in dtm to mark a pointer to a child node as NULL.
+*/
+#define MIN_PDB_CARRIERID 1
+#define MAX_PDB_CARRIERID 999
+#define OTHER_CARRIERID 1000
+#define MAX_CARRIERID 1000
+#define NULL_CARRIERID -1001
+#define PAYLOADSIZE 256
+
+
+#define IS_VALID_PDB_CARRIERID(id) ((id>=MIN_PDB_CARRIERID) && (id<=MAX_PDB_CARRIERID))
+#define IS_VALID_CARRIERID(id) ((id>=MIN_PDB_CARRIERID) && (id<=MAX_CARRIERID))
+
+#define PDB_VERSION     1
+
+
+
+typedef int16_t carrier_t;
+
+enum __attribute__((packed)) pdb_versions {
+    PDB_VERSION_1 = 1,
+    PDB_VERSION_MAX
+};
+
+enum __attribute__((packed)) pdb_types {
+    PDB_TYPE_REQUEST_ID = 0,    /* request pdb type */
+    PDB_TYPE_REPLY_ID,          /* reply pdb type */
+    PDB_TYPE_MAX
+};
+
+enum __attribute__((packed)) pdb_codes {
+    PDB_CODE_DEFAULT = 0,   /* for request */
+    PDB_CODE_OK,            /* for response - OK */
+    PDB_CODE_NOT_NUMBER,    /* for response - letters found in the number */
+    PDB_CODE_NOT_FOUND,     /* for response - no pdb_id found for the number */
+    PDB_CODE_MAX
+};
+
+struct __attribute__((packed)) pdb_hdr {
+    uint8_t version;
+    uint8_t type;
+    uint8_t code;
+    uint8_t length;
+    uint16_t id;
+};
+
+struct __attribute__((packed)) pdb_bdy {
+    char payload[PAYLOADSIZE];
+};
+
+struct __attribute__((packed)) pdb_msg {
+    struct pdb_hdr hdr;
+    struct pdb_bdy bdy;
+};
+
+#endif

+ 4 - 0
modules/pdb/doc/pdb_admin.xml

@@ -25,6 +25,10 @@
   	parallel and use the first answer, that comes back. A timeout for the
   	parallel and use the first answer, that comes back. A timeout for the
 	query can be defined in milliseconds. The queying can be activated and
 	query can be defined in milliseconds. The queying can be activated and
   	deactivated using FIFO commands.
   	deactivated using FIFO commands.
+	</para>
+	<para>
+    More about the new communication protocol between this module and pdb_server
+    can be found in utils/pdbt/docs/network_protocol.txt. The current version is 1.
 	</para>
 	</para>
 	</section>
 	</section>
 
 

+ 139 - 27
modules/pdb/pdb.c

@@ -38,16 +38,15 @@
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #include <errno.h>
 #include <errno.h>
 
 
-MODULE_VERSION
-
-
-#define NETBUFSIZE 200
+#include "common.h"
 
 
+MODULE_VERSION
 
 
 static char* modp_server = NULL;  /*!< format: \<host\>:\<port\>,... */
 static char* modp_server = NULL;  /*!< format: \<host\>:\<port\>,... */
 static int timeout = 50;  /*!< timeout for queries in milliseconds */
 static int timeout = 50;  /*!< timeout for queries in milliseconds */
 static int timeoutlogs = -10;  /*!< for aggregating timeout logs */
 static int timeoutlogs = -10;  /*!< for aggregating timeout logs */
 static int *active = NULL;
 static int *active = NULL;
+static uint16_t *global_id = NULL;
 
 
 
 
 /*!
 /*!
@@ -90,6 +89,14 @@ struct mi_root * mi_pdb_status(struct mi_root* cmd, void* param);  /* usage: kam
 struct mi_root * mi_pdb_activate(struct mi_root* cmd, void* param);  /* usage: kamctl fifo pdb_activate */
 struct mi_root * mi_pdb_activate(struct mi_root* cmd, void* param);  /* usage: kamctl fifo pdb_activate */
 struct mi_root * mi_pdb_deactivate(struct mi_root* cmd, void* param);  /* usage: kamctl fifo pdb_deactivate */
 struct mi_root * mi_pdb_deactivate(struct mi_root* cmd, void* param);  /* usage: kamctl fifo pdb_deactivate */
 
 
+/* debug function for the new client <-> server protocol */
+static void pdb_msg_dbg(struct pdb_msg msg, char *dbg_msg);
+
+/* build the new protocol message before transmission */
+static int pdb_msg_format_send(struct pdb_msg *msg,
+                               uint8_t version, uint8_t type,
+                               uint8_t code, uint16_t id,
+                               char *payload, uint16_t payload_len);
 
 
 static cmd_export_t cmds[]={
 static cmd_export_t cmds[]={
 	{ "pdb_query", (cmd_function)pdb_query, 2, pdb_query_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
 	{ "pdb_query", (cmd_function)pdb_query, 2, pdb_query_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
@@ -150,20 +157,65 @@ struct server_list_t {
 static struct server_list_t *server_list;
 static struct server_list_t *server_list;
 
 
 
 
+/* debug function for the new client <-> server protocol */
+static void pdb_msg_dbg(struct pdb_msg msg, char *dbg_msg) {
+    int i;
+    char buf[PAYLOADSIZE];
+    char *ptr = buf;
+
+    for (i = 0; i < msg.hdr.length - sizeof(msg.hdr); i++) {
+        ptr += sprintf(ptr,"%02X ", msg.bdy.payload[i]);
+    }
+
+    LM_DBG("%s\n"
+           "version = %d\ntype = %d\ncode = %d\nid = %d\nlen = %d\n"
+           "payload = %s\n",
+            dbg_msg,
+            msg.hdr.version, msg.hdr.type, msg.hdr.code, msg.hdr.id, msg.hdr.length,
+            buf);
+}
+
+/* build the message before send */
+static int pdb_msg_format_send(struct pdb_msg *msg,
+                               uint8_t version, uint8_t type,
+                               uint8_t code, uint16_t id,
+                               char *payload, uint16_t payload_len)
+{
+    msg->hdr.version    = version;
+    msg->hdr.type       = type;
+    msg->hdr.code       = code;
+    msg->hdr.id         = id;
+
+    if (payload == NULL) {
+        /* just ignore the NULL buff (called when just want to set the len) */
+        msg->hdr.length     = sizeof(struct pdb_hdr);
+        return 0;
+    } else {
+        msg->hdr.length     = sizeof(struct pdb_hdr) + payload_len;
+        memcpy(msg->bdy.payload, payload, payload_len);
+        return 0;
+    }
+
+    return 0;
+}
+
+
+
 /*!
 /*!
  * \return 1 if query for the number succeded and the avp with the corresponding carrier id was set,
  * \return 1 if query for the number succeded and the avp with the corresponding carrier id was set,
  * -1 otherwise
  * -1 otherwise
  */
  */
 static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct multiparam_t *_dstavp)
 static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct multiparam_t *_dstavp)
 {
 {
+    struct pdb_msg msg;
 	struct timeval tstart, tnow;
 	struct timeval tstart, tnow;
 	struct server_item_t *server;
 	struct server_item_t *server;
 	short int carrierid, *_id;
 	short int carrierid, *_id;
-	char buf[NETBUFSIZE+1+sizeof(carrierid)];
+    char buf[sizeof(struct pdb_msg)];
 	size_t reqlen;
 	size_t reqlen;
 	int_str avp_val;
 	int_str avp_val;
 	struct usr_avp *avp;
 	struct usr_avp *avp;
-	int i, ret, nflush;
+	int i, ret, nflush, bytes_received;
 	long int td;
 	long int td;
 	str number = STR_NULL;
 	str number = STR_NULL;
 
 
@@ -209,7 +261,7 @@ static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct
 	server = server_list->head;
 	server = server_list->head;
 	while (server) {
 	while (server) {
 		nflush = 0;
 		nflush = 0;
-		while (recv(server->sock, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) {
+		while (recv(server->sock, buf, sizeof(struct pdb_msg), MSG_DONTWAIT) > 0) {
 			nflush++;
 			nflush++;
 			if (gettimeofday(&tnow, NULL) != 0) {
 			if (gettimeofday(&tnow, NULL) != 0) {
 				LM_ERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
 				LM_ERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
@@ -227,24 +279,46 @@ static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct
 
 
 	/* prepare request */
 	/* prepare request */
 	reqlen = number.len + 1; /* include null termination */
 	reqlen = number.len + 1; /* include null termination */
-	if (reqlen > NETBUFSIZE) {
+	if (reqlen > sizeof(struct pdb_bdy)) {
 		LM_ERR("number too long '%.*s'.\n", number.len, number.s);
 		LM_ERR("number too long '%.*s'.\n", number.len, number.s);
 		return -1;
 		return -1;
 	}
 	}
 	strncpy(buf, number.s, number.len);
 	strncpy(buf, number.s, number.len);
 	buf[number.len] = '\0';
 	buf[number.len] = '\0';
 
 
-	/* send request to all servers */
-	server = server_list->head;
-	while (server) {
-		LM_DBG("sending request to '%s:%d'\n", server->host, server->port);
-		ret=sendto(server->sock, buf, reqlen, MSG_DONTWAIT, (struct sockaddr *)&(server->dstaddr), server->dstaddrlen);
-		if (ret < 0) {
-			LM_ERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
-		}
-		server = server->next;
-	}
-		
+    switch (PDB_VERSION) {
+        case PDB_VERSION_1:
+            pdb_msg_format_send(&msg, PDB_VERSION, PDB_TYPE_REQUEST_ID, PDB_CODE_DEFAULT, htons(*global_id), buf, reqlen);
+            pdb_msg_dbg(msg, "Kamailio pdb client sends:");
+
+            /* increment msg id for the next request */
+            *global_id = *global_id + 1;
+
+            /* send request to all servers */
+            server = server_list->head;
+            while (server) {
+                LM_DBG("sending request to '%s:%d'\n", server->host, server->port);
+                ret=sendto(server->sock, (struct pdb_msg*)&msg, msg.hdr.length, MSG_DONTWAIT, (struct sockaddr *)&(server->dstaddr), server->dstaddrlen);
+                if (ret < 0) {
+                    LM_ERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
+                }
+                server = server->next;
+            }
+            break;
+        default:
+            /* send request to all servers */
+            server = server_list->head;
+            while (server) {
+                LM_DBG("sending request to '%s:%d'\n", server->host, server->port);
+                ret=sendto(server->sock, buf, reqlen, MSG_DONTWAIT, (struct sockaddr *)&(server->dstaddr), server->dstaddrlen);
+                if (ret < 0) {
+                    LM_ERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
+                }
+                server = server->next;
+            }
+            break;
+    }
+
 	/* wait for response */
 	/* wait for response */
 	for (;;) {
 	for (;;) {
 		if (gettimeofday(&tnow, NULL) != 0) {
 		if (gettimeofday(&tnow, NULL) != 0) {
@@ -267,13 +341,48 @@ static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct
 		ret=poll(server_list->fds, server_list->nserver, timeout-td);
 		ret=poll(server_list->fds, server_list->nserver, timeout-td);
 		for (i=0; i<server_list->nserver; i++) {
 		for (i=0; i<server_list->nserver; i++) {
 			if (server_list->fds[i].revents & POLLIN) {
 			if (server_list->fds[i].revents & POLLIN) {
-				if (recv(server_list->fds[i].fd, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) { /* do not block - just in case select/poll was wrong */
-					buf[NETBUFSIZE] = '\0';
-					if (strncmp(buf, number.s, number.len) == 0) {
-						_id = (short int *)&(buf[reqlen]);
-						carrierid=ntohs(*_id); /* convert to host byte order */
-						goto found;
-					}
+				if ((bytes_received = recv(server_list->fds[i].fd, buf,  sizeof(struct pdb_msg), MSG_DONTWAIT)) > 0) { /* do not block - just in case select/poll was wrong */
+                    switch (PDB_VERSION) {
+                        case PDB_VERSION_1:
+                            memcpy(&msg, buf, bytes_received);
+                            pdb_msg_dbg(msg, "Kamailio pdb client receives:");
+
+                            _id = (short int *)&(msg.hdr.id); /* make gcc happy */
+                            msg.hdr.id = ntohs(*_id);
+
+                            switch (msg.hdr.code) {
+                                case PDB_CODE_OK:
+                                    msg.bdy.payload[sizeof(struct pdb_bdy) - 1] = '\0';
+                                    if (strcmp(msg.bdy.payload, number.s) == 0) {
+                                        _id = (short int *)&(msg.bdy.payload[reqlen]); /* make gcc happy */
+                                        carrierid=ntohs(*_id); /* convert to host byte order */
+                                        goto found;
+                                    }
+                                    break;
+                                case PDB_CODE_NOT_NUMBER:
+                                    LM_WARN("Number %s has letters in it\n", number.s);
+                                    carrierid = 0;
+                                    goto found;
+                                case PDB_CODE_NOT_FOUND:
+                                    LM_WARN("Number %s pdb_id not found\n", number.s);
+                                    carrierid = 0;
+                                    goto found;
+                                default:
+                                    LM_WARN("Invalid code %d received\n", msg.hdr.code);
+                                    carrierid = 0;
+                                    goto found;
+                            }
+
+                            break;
+                        default:
+                            buf[sizeof(struct pdb_msg) - 1] = '\0';
+                            if (strncmp(buf, number.s, number.len) == 0) {
+                                _id = (short int *)&(buf[reqlen]);
+                                carrierid=ntohs(*_id); /* convert to host byte order */
+                                goto found;
+                            }
+                            break;
+                    }
 				}
 				}
 			}
 			}
 			server_list->fds[i].revents = 0;
 			server_list->fds[i].revents = 0;
@@ -664,7 +773,10 @@ static int mod_init(void)
 		shm_free(active);
 		shm_free(active);
 		return -1;
 		return -1;
 	}
 	}
-	return 0;
+
+    global_id = (uint16_t*)shm_malloc(sizeof(uint16_t));
+
+    return 0;
 }
 }
 
 
 static int child_init (int rank)
 static int child_init (int rank)

+ 2 - 2
utils/pdbt/Makefile

@@ -1,8 +1,8 @@
 .phony: all clean install
 .phony: all clean install
 
 
 header=common.h carrier.h dt.h dtm.h pdb_server_backend.h log.h
 header=common.h carrier.h dt.h dtm.h pdb_server_backend.h log.h
-obj=dt.o dtm.o carrier.o pdb_server_backend.o log.o
-pdb_server_obj=pdb_server_backend.o dtm.o log.o
+obj=dt.o dtm.o carrier.o pdb_server_backend.o log.o common.o
+pdb_server_obj=pdb_server_backend.o dtm.o log.o common.o
 cflags=-Wall -O2 -g
 cflags=-Wall -O2 -g
 # -march=x86-64
 # -march=x86-64
 extdep=Makefile
 extdep=Makefile

+ 43 - 0
utils/pdbt/common.c

@@ -0,0 +1,43 @@
+#include "common.h"
+#include "log.h"
+#include <string.h>
+
+void pdb_msg_dbg(struct pdb_msg msg) {
+    int i;
+
+    LERR("version = %d\n", msg.hdr.version);
+    LERR("type = %d\n", msg.hdr.type);
+    LERR("code = %d\n", msg.hdr.code);
+    LERR("id = %d\n", msg.hdr.id);
+    LERR("len = %d\n", msg.hdr.length);
+    LERR("payload = ");
+    for (i = 0; i < msg.hdr.length - sizeof(msg.hdr); i++) {
+        LERR("%02X ", msg.bdy.payload[i]);
+    }
+    LERR("\n");
+
+    return ;
+}
+
+int pdb_msg_format_send(struct pdb_msg *msg,
+                        uint8_t version, uint8_t type,
+                        uint8_t code, uint16_t id,
+                        char *payload, uint16_t payload_len)
+{
+    msg->hdr.version    = version;
+    msg->hdr.type       = type;
+    msg->hdr.code       = code;
+    msg->hdr.id         = id;
+
+    if (payload == NULL) {
+        /* just ignore the NULL buff (called when just want to set the len) */
+        msg->hdr.length     = sizeof(struct pdb_hdr);
+        return 0;
+    } else {
+        msg->hdr.length     = sizeof(struct pdb_hdr) + payload_len;
+        memcpy(msg->bdy.payload, payload, payload_len);
+        return 0;
+    }
+
+    return 0;
+}

+ 46 - 2
utils/pdbt/common.h

@@ -41,16 +41,60 @@
 #define OTHER_CARRIERID 1000
 #define OTHER_CARRIERID 1000
 #define MAX_CARRIERID 1000
 #define MAX_CARRIERID 1000
 #define NULL_CARRIERID -1001
 #define NULL_CARRIERID -1001
+#define PAYLOADSIZE 256
+
 
 
 #define IS_VALID_PDB_CARRIERID(id) ((id>=MIN_PDB_CARRIERID) && (id<=MAX_PDB_CARRIERID))
 #define IS_VALID_PDB_CARRIERID(id) ((id>=MIN_PDB_CARRIERID) && (id<=MAX_PDB_CARRIERID))
 #define IS_VALID_CARRIERID(id) ((id>=MIN_PDB_CARRIERID) && (id<=MAX_CARRIERID))
 #define IS_VALID_CARRIERID(id) ((id>=MIN_PDB_CARRIERID) && (id<=MAX_CARRIERID))
 
 
+#define PDB_VERSION     1
 
 
 
 
 
 
 typedef int16_t carrier_t;
 typedef int16_t carrier_t;
 
 
-
-
+enum __attribute__((packed)) pdb_versions {
+    PDB_VERSION_1 = 1,
+    PDB_VERSION_MAX
+};
+
+enum __attribute__((packed)) pdb_types {
+    PDB_TYPE_REQUEST_ID = 0,    /* request pdb type */
+    PDB_TYPE_REPLY_ID,          /* reply pdb type */
+    PDB_TYPE_MAX
+};
+
+enum __attribute__((packed)) pdb_codes {
+    PDB_CODE_DEFAULT = 0,   /* for request */
+    PDB_CODE_OK,            /* for response - OK */
+    PDB_CODE_NOT_NUMBER,    /* for response - letters found in the number */
+    PDB_CODE_NOT_FOUND,     /* for response - no pdb_id found for the number */
+    PDB_CODE_MAX
+};
+
+struct __attribute__((packed)) pdb_hdr {
+    uint8_t version;
+    uint8_t type;
+    uint8_t code;
+    uint8_t length;
+    uint16_t id;
+};
+
+struct __attribute__((packed)) pdb_bdy {
+    char payload[PAYLOADSIZE];
+};
+
+struct __attribute__((packed)) pdb_msg {
+    struct pdb_hdr hdr;
+    struct pdb_bdy bdy;
+};
+
+
+
+void pdb_msg_dbg (struct pdb_msg msg);
+int pdb_msg_format_send(struct pdb_msg *msg,
+                            uint8_t version, uint8_t type,
+                            uint8_t code, uint16_t id,
+                            char *payload, uint16_t payload_len);
 
 
 #endif
 #endif

+ 37 - 0
utils/pdbt/docs/network_protocol.txt

@@ -14,3 +14,40 @@ Possible values for the search request:
   * 1-999 the number was found and the result represents its carrier ID
   * 1-999 the number was found and the result represents its carrier ID
   * 1000: the number could be found, but its owned from a carriers which is
   * 1000: the number could be found, but its owned from a carriers which is
     not interesting for us and belongs to the "other carrier" group
     not interesting for us and belongs to the "other carrier" group
+
+
+From PDB_VERSION_1 onwards the pdb request and reply looks like this:
+
+    +-------+----+----+------+--+-------+
+    |          header           |  body |
+    +-------+----+----+------+--+-------+
+    |version|type|code|length|id|payload|
+    +-------+----+----+------+--+-------+
+
+Version
+    Current version is 1 (0x01).
+
+Type
+    PDB_TYPE_REQUEST_ID = 0,    /* request pdb type */
+    PDB_TYPE_REPLY_ID,          /* reply pdb type */
+
+Code
+    PDB_CODE_DEFAULT = 0,   /* for request */
+    PDB_CODE_OK,            /* for response - OK */
+    PDB_CODE_NOT_NUMBER,    /* for response - letters found in the number */
+    PDB_CODE_NOT_FOUND,     /* for response - no pdb_id found for the number */
+
+Length
+    The length of the whole message
+
+Id
+    A pdb_msg id which might be used for asynchronous queries.
+
+Payload
+    Request number including '\0' for request.
+    Request number including '\0' and pdb_id for reply.
+
+Backwards compatibility with the old msg protocol is kept when the first byte
+received is different from the known versions ('0x01' for now)
+
+For more info about the data structures used, see common.h file.

+ 4 - 4
utils/pdbt/log.c

@@ -55,10 +55,10 @@ void destroy_log(void) {
 
 
 
 
 
 
-void log_stdout(char * format, va_list ap)
+void log_stderr(char * format, va_list ap)
 {
 {
-	vfprintf(stdout, format, ap);
-	fflush(stdout);
+	vfprintf(stderr, format, ap);
+	fflush(stderr);
 }
 }
 
 
 
 
@@ -70,7 +70,7 @@ void pdb_log(int priority, char * format, ...) {
 	if (priority<=log_level) {
 	if (priority<=log_level) {
 		va_start(ap, format);
 		va_start(ap, format);
 		if (use_syslog) vsyslog(priority, format, ap);
 		if (use_syslog) vsyslog(priority, format, ap);
-		else log_stdout(format, ap);
+		else log_stderr(format, ap);
 		va_end(ap);
 		va_end(ap);
 	}
 	}
 }
 }

+ 6 - 1
utils/pdbt/log.h

@@ -43,7 +43,12 @@ void pdb_log(int priority, char * format, ...);
 #define LINFO(fmt, args...) pdb_log(LOG_INFO, fmt, ## args)
 #define LINFO(fmt, args...) pdb_log(LOG_INFO, fmt, ## args)
 #define LDEBUG(fmt, args...) pdb_log(LOG_DEBUG, fmt, ## args)
 #define LDEBUG(fmt, args...) pdb_log(LOG_DEBUG, fmt, ## args)
 
 
+/* several shell exit codes for the application pdbt */
 
 
-
+#define PDB_OK 0              /* Everything ok */
+#define PDB_USE_ERROR 1       /* Wrong usage of application (unknown command, file not found, etc.) */
+#define PDB_NOT_IN_PDB 2      /* A queried number is not in the pdb */
+#define PDB_TIMEOUT 3         /* A timeout (server not responding) occured */
+#define PDB_OTHER 4           /* Another application error occured */
 
 
 #endif
 #endif

+ 102 - 39
utils/pdbt/pdb_server.c

@@ -65,7 +65,29 @@ void print_usage(char *program) {
 	LINFO("    -h: Print this help.\n");
 	LINFO("    -h: Print this help.\n");
 }
 }
 
 
+int pdb_msg_server_send(int so, char *buf, size_t answerlen, struct sockaddr *fromaddr, socklen_t fromaddrlen)
+{
+	ssize_t bytes_sent;
+	int try = 0;
+	again:
+		bytes_sent = sendto(so, buf, answerlen, 0, fromaddr, fromaddrlen);
+		if (bytes_sent < 3) {
+			if ((errno == EINTR) && (try < 3)) {
+				try++;
+				LERR("sendto() failed - trying again. errno=%d (%s)\n", errno, strerror(errno));
+				goto again;
+			}
+			LERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
+			if ((errno==EAGAIN)||(errno==EINTR)||(errno==EWOULDBLOCK)) return 0;
+			return -1;
+		}
+		if (bytes_sent != answerlen) {
+			LERR("cannot send the whole answer (%ld/%ld).\n", (long int)bytes_sent, (long int)answerlen);
+			return 0;
+		}
 
 
+    return 0;
+}
 
 
 
 
 /*
 /*
@@ -77,60 +99,101 @@ void print_usage(char *program) {
 */
 */
 int udp_server(int so)
 int udp_server(int so)
 {
 {
+    struct pdb_msg msg;
 	struct sockaddr fromaddr;
 	struct sockaddr fromaddr;
 	socklen_t fromaddrlen;
 	socklen_t fromaddrlen;
-	size_t answerlen;
+	size_t answerlen = 0;
 	ssize_t bytes_received;
 	ssize_t bytes_received;
-	ssize_t bytes_sent;
 	carrier_t carrierid;
 	carrier_t carrierid;
-	char buf[NETBUFSIZE+1+sizeof(carrierid)]; /* additional space for '\0' termination and carrier */
+	char buf[sizeof(struct pdb_msg)];
 	int i;
 	int i;
-	int try;
 
 
 	for (;;) {
 	for (;;) {
 		fromaddrlen = sizeof(fromaddr);
 		fromaddrlen = sizeof(fromaddr);
-		bytes_received = recvfrom(so, buf, NETBUFSIZE, 0, &fromaddr, &fromaddrlen);
+		bytes_received = recvfrom(so, buf, sizeof(struct pdb_msg), 0, &fromaddr, &fromaddrlen);
 		if (bytes_received<0) {
 		if (bytes_received<0) {
-      LERR("recvfrom() failed with errno=%d (%s)\n", errno, strerror(errno));
+            LERR("recvfrom() failed with errno=%d (%s)\n", errno, strerror(errno));
 			if ((errno==EAGAIN)||(errno==EINTR)||(errno==EWOULDBLOCK)) continue;
 			if ((errno==EAGAIN)||(errno==EINTR)||(errno==EWOULDBLOCK)) continue;
 			return -1;
 			return -1;
 		}
 		}
-		
-		/* take only digits */
-		i=0;
-		while ((i<bytes_received) && (buf[i]>='0') && (buf[i]<='9')) i++;
-		buf[i]=0; /* terminate string */
-		i++;
 
 
-		carrierid=lookup_number(buf);
-		
-		/* convert to network byte order*/
-		carrierid=htons(carrierid);
+        switch (buf[0]) {
+            case PDB_VERSION_1:
+                /* get received bytes */
+                memcpy(&msg, buf, bytes_received);
+//                pdb_msg_dbg(msg);
+                short int *_id = (short int *)&(msg.hdr.id); /* make gcc happy */
+                msg.hdr.id = ntohs(*_id);
 
 
-		/* append carrier id to answer */
-		memcpy(&(buf[i]), &carrierid, sizeof(carrierid));
-		answerlen=i+sizeof(carrierid);
-		
-		try=0;
-	again:
-		bytes_sent = sendto(so, buf, answerlen, 0, &fromaddr, fromaddrlen);
-		if (bytes_sent < 3) {
-			if ((errno==EINTR) && (try<3)) {
-				try++;
-				LERR("sendto() failed - trying again. errno=%d (%s)\n", errno, strerror(errno));
-				goto again;
-			}
-			LERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
-			if ((errno==EAGAIN)||(errno==EINTR)||(errno==EWOULDBLOCK)) continue;
-			return -1;
-		}
-		if (bytes_sent != answerlen) {
-			LERR("cannot send the whole answer (%ld/%ld).\n", (long int)bytes_sent, (long int)answerlen);
-			continue;
-		}
-	}
+                i = 0;
+                while (i < strlen(msg.bdy.payload)) {
+                    if (msg.bdy.payload[i] < '0' || msg.bdy.payload[i] > '9') {
+                        pdb_msg_format_send(&msg, PDB_VERSION_1, PDB_TYPE_REPLY_ID, PDB_CODE_NOT_NUMBER, htons(msg.hdr.id), NULL, 0);
+                        goto msg_send;
+                    }
+                    i++;
+                }
+                /* lookup pdb_id */
+                carrierid=lookup_number(msg.bdy.payload);
 
 
-	return 0;
+                /* check if not found pdb_id */
+                if (carrierid == 0) {
+                    pdb_msg_format_send(&msg, PDB_VERSION_1, PDB_TYPE_REPLY_ID, PDB_CODE_NOT_FOUND, htons(msg.hdr.id), NULL, 0);
+                    goto msg_send;
+                }
+
+                /* convert to network byte order*/
+                carrierid = htons(carrierid);
+
+                /* prepare the message payload to be sent
+                 * add the number string and append the carrier id
+                 */
+                memcpy(buf, msg.bdy.payload, msg.hdr.length - sizeof(msg.hdr));
+                memcpy(buf + msg.hdr.length - sizeof(msg.hdr), &carrierid, sizeof(carrierid));
+
+                /* all ok, send pdb_msg with pdb_id in payload */
+                pdb_msg_format_send(&msg, PDB_VERSION_1, PDB_TYPE_REPLY_ID, PDB_CODE_OK, htons(msg.hdr.id), buf, msg.hdr.length - sizeof(msg.hdr) + sizeof(carrierid));
+                goto msg_send;
+
+                break;
+
+            /* old pdb version; no pdb_msg used */
+            default:
+                /* take only digits */
+                i=0;
+                while ((i<bytes_received) && (buf[i]>='0') && (buf[i]<='9')) i++;
+                buf[i]=0; /* terminate string */
+                i++;
+
+                /* lookup pdb_id */
+                carrierid=lookup_number(buf);
+
+                /* convert to network byte order*/
+                carrierid=htons(carrierid);
+
+                /* append carrier id to answer */
+                memcpy(&(buf[i]), &carrierid, sizeof(carrierid));
+                answerlen=i+sizeof(carrierid);
+                goto buf_send;
+
+                break;
+        }
+
+msg_send:
+//        pdb_msg_dbg(msg);
+        if (pdb_msg_server_send(so, (char*)&msg, msg.hdr.length, &fromaddr, fromaddrlen) < 0) {
+            return -1;
+        }
+        continue;
+
+buf_send:
+        if (pdb_msg_server_send(so, buf, answerlen, &fromaddr, fromaddrlen)) {
+            return -1;
+        }
+        continue;
+    }
+
+	return -1;
 }
 }
 
 
 
 

+ 126 - 45
utils/pdbt/pdbt.c

@@ -39,14 +39,10 @@
 #include "log.h"
 #include "log.h"
 
 
 
 
+/* incremented after request sent to the server */
+uint16_t id = 0;
 
 
-
-#define NETBUFSIZE 200
-
-
-
-
-typedef void (*query_func_t)(char *number, char *comment, void *data);
+typedef int (*query_func_t)(char *number, char *comment, void *data);
 
 
 
 
 
 
@@ -136,13 +132,11 @@ int file_query(char *filename, query_func_t query_func, void *data) {
 	else fp = fopen(filename, "r");
 	else fp = fopen(filename, "r");
 	if (fp == NULL) {
 	if (fp == NULL) {
 		LERR("cannot open file '%s'\n", filename);
 		LERR("cannot open file '%s'\n", filename);
-		return -1;
+		return -PDB_USE_ERROR;
 	}
 	}
 	while ((read = getline(&line, &len, fp)) != -1) {
 	while ((read = getline(&line, &len, fp)) != -1) {
 		p=line;
 		p=line;
 		while ((*p >= '0') && (*p <= '9') && (p < line+len)) p++;
 		while ((*p >= '0') && (*p <= '9') && (p < line+len)) p++;
-		*p='\0';
-		p++;
 		comment=p;
 		comment=p;
 		while ((*p >= 32) && (p < line+len)) p++;
 		while ((*p >= 32) && (p < line+len)) p++;
 		*p='\0';
 		*p='\0';
@@ -150,7 +144,7 @@ int file_query(char *filename, query_func_t query_func, void *data) {
 	}
 	}
 	if (line) free(line);
 	if (line) free(line);
 	fclose(fp);
 	fclose(fp);
-	return 0;
+	return -PDB_OK;
 }
 }
 
 
 
 
@@ -184,6 +178,11 @@ int import_csv(struct dt_node_t *root, char *filename) {
 	while ((read = getline(&line, &len, fp)) != -1) {
 	while ((read = getline(&line, &len, fp)) != -1) {
 		carrier_str=line;
 		carrier_str=line;
 		prefix=strsep(&carrier_str, ";");
 		prefix=strsep(&carrier_str, ";");
+		if ( carrier_str == NULL ) {
+			LWARNING("line %ld: no delimiter `;' found, ignoring line.\n", n); 
+			n++;
+			continue;
+		}
 		ret=strtol(carrier_str, NULL, 10);
 		ret=strtol(carrier_str, NULL, 10);
 		if (!IS_VALID_PDB_CARRIERID(ret)) {
 		if (!IS_VALID_PDB_CARRIERID(ret)) {
 			LWARNING("invalid carrier '%s' in line %ld.\n", carrier_str, (long int)n);
 			LWARNING("invalid carrier '%s' in line %ld.\n", carrier_str, (long int)n);
@@ -451,12 +450,16 @@ int merge_carrier(struct dt_node_t *root, int keep_carriers_num, carrier_t keep_
  */
  */
 int query_udp(char *number, int timeout, struct pollfd *pfds, struct sockaddr_in *dstaddr, socklen_t dstaddrlen)
 int query_udp(char *number, int timeout, struct pollfd *pfds, struct sockaddr_in *dstaddr, socklen_t dstaddrlen)
 {
 {
+    struct pdb_msg msg;
 	struct timeval tstart, tnow;
 	struct timeval tstart, tnow;
 	short int carrierid;
 	short int carrierid;
-	char buf[NETBUFSIZE+1+sizeof(carrierid)];
+	char buf[sizeof(struct pdb_msg)];
 	size_t reqlen;
 	size_t reqlen;
 	int ret, nflush;
 	int ret, nflush;
 	long int td;
 	long int td;
+    ssize_t bytes_received;
+    short int * idptr;
+
 
 
 	if (gettimeofday(&tstart, NULL) != 0) {
 	if (gettimeofday(&tstart, NULL) != 0) {
 		LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
 		LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
@@ -465,54 +468,108 @@ int query_udp(char *number, int timeout, struct pollfd *pfds, struct sockaddr_in
 
 
 	/* clear recv buffer */
 	/* clear recv buffer */
 	nflush = 0;
 	nflush = 0;
-	while (recv(pfds->fd, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) {
+	while (recv(pfds->fd, buf, sizeof(struct pdb_msg), MSG_DONTWAIT) > 0) {
 		nflush++;
 		nflush++;
 		if (gettimeofday(&tnow, NULL) != 0) {
 		if (gettimeofday(&tnow, NULL) != 0) {
 			LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
 			LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
-			return -1;
+			return -PDB_OTHER;
 		}
 		}
 		td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
 		td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
 		if (td > timeout) {
 		if (td > timeout) {
 			LWARNING("exceeded timeout while flushing recv buffer.\n");
 			LWARNING("exceeded timeout while flushing recv buffer.\n");
-			return -1;
+			return -PDB_TIMEOUT;
 		}
 		}
 	}
 	}
 	
 	
 	/* prepare request */
 	/* prepare request */
 	reqlen = strlen(number) + 1; /* include null termination */
 	reqlen = strlen(number) + 1; /* include null termination */
-	if (reqlen > NETBUFSIZE) {
+	if (reqlen > sizeof(struct pdb_bdy)) {
 		LERR("number too long '%s'.\n", number);
 		LERR("number too long '%s'.\n", number);
-		return -1;
+		return -PDB_USE_ERROR;
 	}
 	}
 	strcpy(buf, number);
 	strcpy(buf, number);
 
 
-	/* send request to all servers */
-	ret=sendto(pfds->fd, buf, reqlen, MSG_DONTWAIT, (struct sockaddr *)dstaddr, dstaddrlen);
-	if (ret < 0) {
-		LERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
-		return -1;
-	}
-		
+    switch (PDB_VERSION) {
+        case PDB_VERSION_1:
+            pdb_msg_format_send(&msg, PDB_VERSION, PDB_TYPE_REQUEST_ID, PDB_CODE_DEFAULT, htons(id), buf, reqlen);
+//            pdb_msg_dbg(msg);
+
+            /* increment msg id for the next request */
+            id++;
+
+            /* send request to all servers */
+            ret=sendto(pfds->fd, (struct pdb_msg*)&msg, msg.hdr.length, MSG_DONTWAIT, (struct sockaddr *)dstaddr, dstaddrlen);
+            if (ret < 0) {
+                LERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
+                return -1;
+            }
+            break;
+        default:
+            /* send request to all servers */
+            ret=sendto(pfds->fd, buf, reqlen, MSG_DONTWAIT, (struct sockaddr *)dstaddr, dstaddrlen);
+            if (ret < 0) {
+                LERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
+                return -PDB_OTHER;
+            }
+            break;
+    }
+
 	/* wait for response */
 	/* wait for response */
 	for (;;) {
 	for (;;) {
 		if (gettimeofday(&tnow, NULL) != 0) {
 		if (gettimeofday(&tnow, NULL) != 0) {
 			LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
 			LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
-			return -1;
+			return -PDB_OTHER;
 		}
 		}
 		td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
 		td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
 		if (td > timeout) {
 		if (td > timeout) {
 			LWARNING("exceeded timeout while waiting for response.\n");
 			LWARNING("exceeded timeout while waiting for response.\n");
-			return -1;
+			return -PDB_TIMEOUT;
 		}
 		}
-		
+
 		ret=poll(pfds, 1, timeout-td);
 		ret=poll(pfds, 1, timeout-td);
 		if (pfds->revents & POLLIN) {
 		if (pfds->revents & POLLIN) {
-			if (recv(pfds->fd, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) { /* do not block - just in case select/poll was wrong */
-				buf[NETBUFSIZE] = '\0';
-				if (strcmp(buf, number) == 0) {
-					carrierid=ntohs(*((short int *)&(buf[reqlen]))); /* convert to host byte order */
-					goto found;
-				}
+			if ((bytes_received = recv(pfds->fd, buf, sizeof(struct pdb_msg), MSG_DONTWAIT)) > 0) { /* do not block - just in case select/poll was wrong */
+                switch (PDB_VERSION) {
+                    case PDB_VERSION_1:
+                        memcpy(&msg, buf, bytes_received);
+//                        pdb_msg_dbg(msg);
+                          idptr = (short int *)&(msg.hdr.id); /* make gcc happy */
+                          msg.hdr.id = ntohs(*idptr);
+
+
+                        switch (msg.hdr.code) {
+                            case PDB_CODE_OK:
+                                msg.bdy.payload[sizeof(struct pdb_bdy) - 1] = '\0';
+                                if (strcmp(msg.bdy.payload, number) == 0) {
+                                    idptr = (short int *)&(msg.bdy.payload[reqlen]); /* make gcc happy */
+                                    carrierid=ntohs(*idptr); /* convert to host byte order */
+                                    goto found;
+                                }
+                                break;
+                            case PDB_CODE_NOT_NUMBER:
+			                    LERR("Number %s has letters in it\n", number);
+                                carrierid = 0;
+                                goto found;
+                            case PDB_CODE_NOT_FOUND:
+			                    LERR("Number %s pdb_id not found\n", number);
+                                carrierid = 0;
+                                goto found;
+                            default:
+			                    LERR("Invalid code %d received\n", msg.hdr.code);
+                                carrierid = 0;
+                                goto found;
+                        }
+
+                        break;
+                    default:
+                        buf[sizeof(struct pdb_msg) - 1] = '\0';
+                        if (strcmp(buf, number) == 0) {
+                            idptr = (short int *)&(buf[reqlen]); /* make gcc happy */
+                            carrierid=ntohs(*idptr); /* convert to host byte order */
+                            goto found;
+                        }
+                        break;
+                }
 			}
 			}
 		}
 		}
 		pfds->revents = 0;
 		pfds->revents = 0;
@@ -538,7 +595,7 @@ struct server_query_data_t {
 
 
 
 
 
 
-void query_mmap(char *number, char *comment, void *data) {
+int query_mmap(char *number, char *comment, void *data) {
 	int nmatch;
 	int nmatch;
 	carrier_t carrierid;
 	carrier_t carrierid;
 	struct dtm_node_t *mroot = (struct dtm_node_t *)data;
 	struct dtm_node_t *mroot = (struct dtm_node_t *)data;
@@ -547,31 +604,39 @@ void query_mmap(char *number, char *comment, void *data) {
 
 
 	if (nmatch<=0) {
 	if (nmatch<=0) {
 		LINFO("%s:%s:%ld:%s\n", number, comment, (long int)carrierid, "not allocated, probably old");
 		LINFO("%s:%s:%ld:%s\n", number, comment, (long int)carrierid, "not allocated, probably old");
+		return -PDB_NOT_IN_PDB;
 	}
 	}
 	else {
 	else {
 		LINFO("%s:%s:%ld:%s\n", number, comment, (long int)carrierid, carrierid2name(carrierid));
 		LINFO("%s:%s:%ld:%s\n", number, comment, (long int)carrierid, carrierid2name(carrierid));
 		/* LINFO("%s: found: carrier_id=%ld, carrier_name='%s', nmatch=%ld, comment='%s'\n", number, (long int)carrierid, carrierid2name(carrierid), (long int)nmatch, comment);
 		/* LINFO("%s: found: carrier_id=%ld, carrier_name='%s', nmatch=%ld, comment='%s'\n", number, (long int)carrierid, carrierid2name(carrierid), (long int)nmatch, comment);
 		*/
 		*/
+		return -PDB_OK;
 	}
 	}
 }
 }
 
 
 
 
 
 
 
 
-void query_server(char *number, char *comment, void *data) {
+int query_server(char *number, char *comment, void *data) {
 	carrier_t carrierid;
 	carrier_t carrierid;
 	struct server_query_data_t *sdata = (struct server_query_data_t *)data;
 	struct server_query_data_t *sdata = (struct server_query_data_t *)data;
+	int result = 0;
 
 
 	carrierid = query_udp(number, sdata->timeout, &(sdata->pfds), &(sdata->dstaddr), sdata->dstaddrlen);
 	carrierid = query_udp(number, sdata->timeout, &(sdata->pfds), &(sdata->dstaddr), sdata->dstaddrlen);
 
 
 	if (carrierid<=0) {
 	if (carrierid<=0) {
-		LINFO("%s: not_found: comment='%s'\n", number, comment);
+		LINFO("%s: not_found: comment='%s', result=%d\n", number, comment, carrierid);
+		if (carrierid < 0) {
+			result = carrierid; 
+		} else {
+			result = PDB_NOT_IN_PDB; 
+		}
 	}
 	}
 	else {
 	else {
 		LINFO("%s:%ld:%s\n", number, (long int)carrierid, carrierid2name(carrierid));
 		LINFO("%s:%ld:%s\n", number, (long int)carrierid, carrierid2name(carrierid));
-		/* LINFO("%s: found: carrier_id=%ld, carrier_name='%s', comment='%s'\n", number, (long int)carrierid, carrierid2name(carrierid), comment);
-		*/
+		result = PDB_OK;
 	}
 	}
+	return result; 
 }
 }
 
 
 
 
@@ -604,6 +669,7 @@ int main(int argc, char *argv[]) {
 
 
 	char *id_str;
 	char *id_str;
 	long int ret;
 	long int ret;
+	int exit_status = PDB_OK;
 
 
 	sdata.timeout=500;
 	sdata.timeout=500;
 
 
@@ -782,7 +848,7 @@ int main(int argc, char *argv[]) {
 			if (hp == NULL) {
 			if (hp == NULL) {
 				LERR("gethostbyname(%s) failed with h_errno=%d.\n", host_str, h_errno);
 				LERR("gethostbyname(%s) failed with h_errno=%d.\n", host_str, h_errno);
 				close(sockfd);
 				close(sockfd);
-				return -1;
+				exit (PDB_USE_ERROR);
 			}
 			}
 			memcpy(&sdata.dstaddr.sin_addr.s_addr, hp->h_addr, hp->h_length);
 			memcpy(&sdata.dstaddr.sin_addr.s_addr, hp->h_addr, hp->h_length);
 			sdata.dstaddrlen=sizeof(sdata.dstaddr);
 			sdata.dstaddrlen=sizeof(sdata.dstaddr);
@@ -792,19 +858,30 @@ int main(int argc, char *argv[]) {
 
 
 			if (query_file==NULL) {
 			if (query_file==NULL) {
 				LINFO("\nprocessing command line parameters...\n");
 				LINFO("\nprocessing command line parameters...\n");
+				if ( optind+1 >= argc) {
+					exit_status = PDB_USE_ERROR;
+				}
 				for (n=optind+1; n<argc; n++) {
 				for (n=optind+1; n<argc; n++) {
-					query_server(argv[n], "", &sdata);
+					int result; 
+					result = query_server(argv[n], "", &sdata); 
+					if ( result != 0) {
+						exit_status = -result; 
+					}
 				}
 				}
 			}
 			}
 			else {
 			else {
-				file_query(query_file, query_server, &sdata);
+				int result; 
+				result = file_query(query_file, query_server, &sdata);
+				if ( result != 0) {
+					exit_status = -result; 
+				}
 			}
 			}
 		}
 		}
 		else {
 		else {
 			mroot=dtm_load(mmap_file);
 			mroot=dtm_load(mmap_file);
 			if (mroot == NULL) {
 			if (mroot == NULL) {
 				LERR("cannot load '%s'.\n", mmap_file);
 				LERR("cannot load '%s'.\n", mmap_file);
-				return -1;
+				exit(PDB_USE_ERROR);
 			}
 			}
 			
 			
 			if (query_file==NULL) {
 			if (query_file==NULL) {
@@ -814,14 +891,18 @@ int main(int argc, char *argv[]) {
 				}
 				}
 			}
 			}
 			else {
 			else {
-				file_query(query_file, query_mmap, mroot);
+				int result; 
+				result = file_query(query_file, query_mmap, mroot);
+				if ( result != 0) {
+					exit_status = -result; 
+				}
 			}
 			}
 		}
 		}
 	}
 	}
 	else {
 	else {
 		LERR("invalid command '%s'.\n", argv[optind]);
 		LERR("invalid command '%s'.\n", argv[optind]);
-		return 1;
+		exit(PDB_USE_ERROR);
 	}
 	}
 
 
-	return 0;
+	exit (exit_status);
 }
 }

+ 60 - 0
utils/pdbt/scripts/get_carrier_names_germany.pl

@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+use utf8;
+use LWP::UserAgent;
+use HTTP::Cookies;
+
+sub main
+{
+    # Create the fake browser (user agent).
+    my $ua = LWP::UserAgent->new();
+
+    # Pretend to be Internet Explorer.
+    $ua->agent("Windows IE 7");
+    # or maybe .... $ua->agent("Mozilla/8.0");
+
+    # Get some HTML.
+    my $response = $ua->get('http://www.bundesnetzagentur.de/cln_1421/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Nummerierung/Technische%20Nummern/Portierungskennungen/VerzeichnisPortKenn_Basepage.html?nn=268376');
+
+    unless($response->is_success) {
+        print "Error: " . $response->status_line;
+    }
+
+    # Let's save the output.
+    my $file = $response->decoded_content;
+    utf8::encode($file);
+    @pieces=split('\<tbody\>', $file);
+    @pieces2=split('\</tbody\>', $pieces[1]);
+    @linii=split('\</tr\>', $pieces2[0]);
+    foreach(@linii)
+    {
+        my($first, $rest) = split(/>/, $_, 2);
+        @tds=split('/td><td', $rest);
+        @names=split('>', $tds[0], 2);
+        my $name=$names[1];
+        $name =~ s/<p>//;
+        $name =~ s/<p>//;
+        $name =~ s/<\/p>//;
+        $name =~ s/<\/p>//;
+        $name =~ s/<//;
+        $name =~ s/\n//;
+        $name =~ s/br\/>//;
+        $name =~ s/br\/>//;
+        $name =~ s/<//;
+        $name =~ s/<//;
+        $name =~ s/\n//;
+        chomp($name);
+        @tds2=split('>', $tds[1], 2);
+        @tds3=split('</', $tds2[1]);
+        @tds4=split('<br/>', $tds3[0]);
+        foreach(@tds4)
+        {
+            $_ =~ s/^\n//;
+            if ($_ =~ /^D/)
+            {
+                    $number=substr($_,0,4);
+                    print "$number $name\n";
+            }
+        }
+    }
+}
+main();

+ 5 - 4
utils/pdbt/scripts/get_carrier_names_germany.sh

@@ -23,14 +23,15 @@
 # the 'Bundesnetzagentur' and convert this into the format which the pdbt tool
 # the 'Bundesnetzagentur' and convert this into the format which the pdbt tool
 # understands.
 # understands.
 
 
-url="http://www.bundesnetzagentur.de/cln_1912/DE/Sachgebiete/Telekommunikation/RegulierungTelekommunikation/Nummernverwaltung/TechnischeNummern/Portierungskennung/VerzeichnisPortKenn_Basepage.html"
+#old_url="http://www.bundesnetzagentur.de/cln_1912/DE/Sachgebiete/Telekommunikation/RegulierungTelekommunikation/Nummernverwaltung/TechnischeNummern/Portierungskennung/VerzeichnisPortKenn_Basepage.html"
+url="http://www.bundesnetzagentur.de/cln_1421/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Nummerierung/Technische%20Nummern/Portierungskennungen/VerzeichnisPortKenn_Basepage.html?nn=268376#Inhalt"
 
 
-# fix LOCALE problem during filtering 
+# fix LOCALE problem during filtering
 export LANG="C"
 export LANG="C"
 
 
-wget -O - "$url" | recode latin1..utf8 | sed 's/^*.Verzeichnis der Portierungskennungen//' | awk '/<tbody>/, /<\/tbody>/' | tr -d '\r' | tr '\n' '@' | sed 's/<\/table>.*$//' | sed 's/<\/tbody>.*$//'
+wget -O - "$url" | recode latin1..utf8 | sed 's/^*.Verzeichnis der Portierungskennungen//' | awk '/<tbody>/, /<\/tbody>/' | tr -d '\r' | tr '\n' '@' | sed 's/<\/table>.*$//' | sed 's/<\/tbody>.*$//' | awk -F "</td" -v RS="</tr" '{ gsub(/.*>/,"",$1) gsub(/.*>/,"",$2); if ( $1 != "") { printf "%s %s\n",$2,$1 } }'
 
 
 # probably also possible to use this:
 # probably also possible to use this:
 # http://www.bundesnetzagentur.de/cae/servlet/contentblob/156772/publicationFile/8492/KonsolidiertesVerzPortierungsk.zip
 # http://www.bundesnetzagentur.de/cae/servlet/contentblob/156772/publicationFile/8492/KonsolidiertesVerzPortierungsk.zip
 # main page (for reference):
 # main page (for reference):
-# http://www.bundesnetzagentur.de/cln_1932/DE/Sachgebiete/Telekommunikation/RegulierungTelekommunikation/Nummernverwaltung/TechnischeNummern/Portierungskennung/KonsolidiertesVerzPortKenn_Basepage.html?nn=120380
+# http://www.bundesnetzagentur.de/cln_1932/DE/Sachgebiete/Telekommunikation/RegulierungTelekommunikation/Nummernverwaltung/TechnischeNummern/Portierungskennung/KonsolidiertesVerzPortKenn_Basepage.html?nn=120380