Browse code

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 authored on 04/06/2015 08:34:19
Showing 13 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,92 @@
0
+/*
1
+ * Copyright (C) 2009 1&1 Internet AG
2
+ *
3
+ * This file is part of sip-router, a free SIP server.
4
+ *
5
+ * sip-router is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation; either version 2 of the License, or
8
+ * (at your option) any later version
9
+ *
10
+ * sip-router is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License 
16
+ * along with this program; if not, write to the Free Software 
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
+ */
19
+
20
+#ifndef _COMMON_H_
21
+#define _COMMON_H_
22
+
23
+
24
+
25
+
26
+#include <stdint.h> 
27
+
28
+
29
+
30
+
31
+/*
32
+ 0 no carrier id defined.
33
+ 1..999 are regular carrier ids.
34
+ 1000 is used as fake carrier id when merging carriers we are not interested in.
35
+ -1000..-1 used in dtm to indicate a carrier id and that no more nodes will follow (leaf node compression).
36
+ -1001 used in dtm to mark a pointer to a child node as NULL.
37
+*/
38
+#define MIN_PDB_CARRIERID 1
39
+#define MAX_PDB_CARRIERID 999
40
+#define OTHER_CARRIERID 1000
41
+#define MAX_CARRIERID 1000
42
+#define NULL_CARRIERID -1001
43
+#define PAYLOADSIZE 256
44
+
45
+
46
+#define IS_VALID_PDB_CARRIERID(id) ((id>=MIN_PDB_CARRIERID) && (id<=MAX_PDB_CARRIERID))
47
+#define IS_VALID_CARRIERID(id) ((id>=MIN_PDB_CARRIERID) && (id<=MAX_CARRIERID))
48
+
49
+#define PDB_VERSION     1
50
+
51
+
52
+
53
+typedef int16_t carrier_t;
54
+
55
+enum __attribute__((packed)) pdb_versions {
56
+    PDB_VERSION_1 = 1,
57
+    PDB_VERSION_MAX
58
+};
59
+
60
+enum __attribute__((packed)) pdb_types {
61
+    PDB_TYPE_REQUEST_ID = 0,    /* request pdb type */
62
+    PDB_TYPE_REPLY_ID,          /* reply pdb type */
63
+    PDB_TYPE_MAX
64
+};
65
+
66
+enum __attribute__((packed)) pdb_codes {
67
+    PDB_CODE_DEFAULT = 0,   /* for request */
68
+    PDB_CODE_OK,            /* for response - OK */
69
+    PDB_CODE_NOT_NUMBER,    /* for response - letters found in the number */
70
+    PDB_CODE_NOT_FOUND,     /* for response - no pdb_id found for the number */
71
+    PDB_CODE_MAX
72
+};
73
+
74
+struct __attribute__((packed)) pdb_hdr {
75
+    uint8_t version;
76
+    uint8_t type;
77
+    uint8_t code;
78
+    uint8_t length;
79
+    uint16_t id;
80
+};
81
+
82
+struct __attribute__((packed)) pdb_bdy {
83
+    char payload[PAYLOADSIZE];
84
+};
85
+
86
+struct __attribute__((packed)) pdb_msg {
87
+    struct pdb_hdr hdr;
88
+    struct pdb_bdy bdy;
89
+};
90
+
91
+#endif
... ...
@@ -26,6 +26,10 @@
26 26
 	query can be defined in milliseconds. The queying can be activated and
27 27
   	deactivated using FIFO commands.
28 28
 	</para>
29
+	<para>
30
+    More about the new communication protocol between this module and pdb_server
31
+    can be found in utils/pdbt/docs/network_protocol.txt. The current version is 1.
32
+	</para>
29 33
 	</section>
30 34
 
31 35
 	<section>
... ...
@@ -38,16 +38,15 @@
38 38
 #include <arpa/inet.h>
39 39
 #include <errno.h>
40 40
 
41
-MODULE_VERSION
42
-
43
-
44
-#define NETBUFSIZE 200
41
+#include "common.h"
45 42
 
43
+MODULE_VERSION
46 44
 
47 45
 static char* modp_server = NULL;  /*!< format: \<host\>:\<port\>,... */
48 46
 static int timeout = 50;  /*!< timeout for queries in milliseconds */
49 47
 static int timeoutlogs = -10;  /*!< for aggregating timeout logs */
50 48
 static int *active = NULL;
49
+static uint16_t *global_id = NULL;
51 50
 
52 51
 
53 52
 /*!
... ...
@@ -90,6 +89,14 @@ struct mi_root * mi_pdb_status(struct mi_root* cmd, void* param);  /* usage: kam
90 90
 struct mi_root * mi_pdb_activate(struct mi_root* cmd, void* param);  /* usage: kamctl fifo pdb_activate */
91 91
 struct mi_root * mi_pdb_deactivate(struct mi_root* cmd, void* param);  /* usage: kamctl fifo pdb_deactivate */
92 92
 
93
+/* debug function for the new client <-> server protocol */
94
+static void pdb_msg_dbg(struct pdb_msg msg, char *dbg_msg);
95
+
96
+/* build the new protocol message before transmission */
97
+static int pdb_msg_format_send(struct pdb_msg *msg,
98
+                               uint8_t version, uint8_t type,
99
+                               uint8_t code, uint16_t id,
100
+                               char *payload, uint16_t payload_len);
93 101
 
94 102
 static cmd_export_t cmds[]={
95 103
 	{ "pdb_query", (cmd_function)pdb_query, 2, pdb_query_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
... ...
@@ -150,20 +157,65 @@ struct server_list_t {
150 150
 static struct server_list_t *server_list;
151 151
 
152 152
 
153
+/* debug function for the new client <-> server protocol */
154
+static void pdb_msg_dbg(struct pdb_msg msg, char *dbg_msg) {
155
+    int i;
156
+    char buf[PAYLOADSIZE];
157
+    char *ptr = buf;
158
+
159
+    for (i = 0; i < msg.hdr.length - sizeof(msg.hdr); i++) {
160
+        ptr += sprintf(ptr,"%02X ", msg.bdy.payload[i]);
161
+    }
162
+
163
+    LM_DBG("%s\n"
164
+           "version = %d\ntype = %d\ncode = %d\nid = %d\nlen = %d\n"
165
+           "payload = %s\n",
166
+            dbg_msg,
167
+            msg.hdr.version, msg.hdr.type, msg.hdr.code, msg.hdr.id, msg.hdr.length,
168
+            buf);
169
+}
170
+
171
+/* build the message before send */
172
+static int pdb_msg_format_send(struct pdb_msg *msg,
173
+                               uint8_t version, uint8_t type,
174
+                               uint8_t code, uint16_t id,
175
+                               char *payload, uint16_t payload_len)
176
+{
177
+    msg->hdr.version    = version;
178
+    msg->hdr.type       = type;
179
+    msg->hdr.code       = code;
180
+    msg->hdr.id         = id;
181
+
182
+    if (payload == NULL) {
183
+        /* just ignore the NULL buff (called when just want to set the len) */
184
+        msg->hdr.length     = sizeof(struct pdb_hdr);
185
+        return 0;
186
+    } else {
187
+        msg->hdr.length     = sizeof(struct pdb_hdr) + payload_len;
188
+        memcpy(msg->bdy.payload, payload, payload_len);
189
+        return 0;
190
+    }
191
+
192
+    return 0;
193
+}
194
+
195
+
196
+
153 197
 /*!
154 198
  * \return 1 if query for the number succeded and the avp with the corresponding carrier id was set,
155 199
  * -1 otherwise
156 200
  */
157 201
 static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct multiparam_t *_dstavp)
158 202
 {
203
+    struct pdb_msg msg;
159 204
 	struct timeval tstart, tnow;
160 205
 	struct server_item_t *server;
161 206
 	short int carrierid, *_id;
162
-	char buf[NETBUFSIZE+1+sizeof(carrierid)];
207
+    char buf[sizeof(struct pdb_msg)];
163 208
 	size_t reqlen;
164 209
 	int_str avp_val;
165 210
 	struct usr_avp *avp;
166
-	int i, ret, nflush;
211
+	int i, ret, nflush, bytes_received;
167 212
 	long int td;
168 213
 	str number = STR_NULL;
169 214
 
... ...
@@ -209,7 +261,7 @@ static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct
209 209
 	server = server_list->head;
210 210
 	while (server) {
211 211
 		nflush = 0;
212
-		while (recv(server->sock, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) {
212
+		while (recv(server->sock, buf, sizeof(struct pdb_msg), MSG_DONTWAIT) > 0) {
213 213
 			nflush++;
214 214
 			if (gettimeofday(&tnow, NULL) != 0) {
215 215
 				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
227 227
 
228 228
 	/* prepare request */
229 229
 	reqlen = number.len + 1; /* include null termination */
230
-	if (reqlen > NETBUFSIZE) {
230
+	if (reqlen > sizeof(struct pdb_bdy)) {
231 231
 		LM_ERR("number too long '%.*s'.\n", number.len, number.s);
232 232
 		return -1;
233 233
 	}
234 234
 	strncpy(buf, number.s, number.len);
235 235
 	buf[number.len] = '\0';
236 236
 
237
-	/* send request to all servers */
238
-	server = server_list->head;
239
-	while (server) {
240
-		LM_DBG("sending request to '%s:%d'\n", server->host, server->port);
241
-		ret=sendto(server->sock, buf, reqlen, MSG_DONTWAIT, (struct sockaddr *)&(server->dstaddr), server->dstaddrlen);
242
-		if (ret < 0) {
243
-			LM_ERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
244
-		}
245
-		server = server->next;
246
-	}
247
-		
237
+    switch (PDB_VERSION) {
238
+        case PDB_VERSION_1:
239
+            pdb_msg_format_send(&msg, PDB_VERSION, PDB_TYPE_REQUEST_ID, PDB_CODE_DEFAULT, htons(*global_id), buf, reqlen);
240
+            pdb_msg_dbg(msg, "Kamailio pdb client sends:");
241
+
242
+            /* increment msg id for the next request */
243
+            *global_id = *global_id + 1;
244
+
245
+            /* send request to all servers */
246
+            server = server_list->head;
247
+            while (server) {
248
+                LM_DBG("sending request to '%s:%d'\n", server->host, server->port);
249
+                ret=sendto(server->sock, (struct pdb_msg*)&msg, msg.hdr.length, MSG_DONTWAIT, (struct sockaddr *)&(server->dstaddr), server->dstaddrlen);
250
+                if (ret < 0) {
251
+                    LM_ERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
252
+                }
253
+                server = server->next;
254
+            }
255
+            break;
256
+        default:
257
+            /* send request to all servers */
258
+            server = server_list->head;
259
+            while (server) {
260
+                LM_DBG("sending request to '%s:%d'\n", server->host, server->port);
261
+                ret=sendto(server->sock, buf, reqlen, MSG_DONTWAIT, (struct sockaddr *)&(server->dstaddr), server->dstaddrlen);
262
+                if (ret < 0) {
263
+                    LM_ERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
264
+                }
265
+                server = server->next;
266
+            }
267
+            break;
268
+    }
269
+
248 270
 	/* wait for response */
249 271
 	for (;;) {
250 272
 		if (gettimeofday(&tnow, NULL) != 0) {
... ...
@@ -267,13 +341,48 @@ static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct
267 267
 		ret=poll(server_list->fds, server_list->nserver, timeout-td);
268 268
 		for (i=0; i<server_list->nserver; i++) {
269 269
 			if (server_list->fds[i].revents & POLLIN) {
270
-				if (recv(server_list->fds[i].fd, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) { /* do not block - just in case select/poll was wrong */
271
-					buf[NETBUFSIZE] = '\0';
272
-					if (strncmp(buf, number.s, number.len) == 0) {
273
-						_id = (short int *)&(buf[reqlen]);
274
-						carrierid=ntohs(*_id); /* convert to host byte order */
275
-						goto found;
276
-					}
270
+				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 */
271
+                    switch (PDB_VERSION) {
272
+                        case PDB_VERSION_1:
273
+                            memcpy(&msg, buf, bytes_received);
274
+                            pdb_msg_dbg(msg, "Kamailio pdb client receives:");
275
+
276
+                            _id = (short int *)&(msg.hdr.id); /* make gcc happy */
277
+                            msg.hdr.id = ntohs(*_id);
278
+
279
+                            switch (msg.hdr.code) {
280
+                                case PDB_CODE_OK:
281
+                                    msg.bdy.payload[sizeof(struct pdb_bdy) - 1] = '\0';
282
+                                    if (strcmp(msg.bdy.payload, number.s) == 0) {
283
+                                        _id = (short int *)&(msg.bdy.payload[reqlen]); /* make gcc happy */
284
+                                        carrierid=ntohs(*_id); /* convert to host byte order */
285
+                                        goto found;
286
+                                    }
287
+                                    break;
288
+                                case PDB_CODE_NOT_NUMBER:
289
+                                    LM_WARN("Number %s has letters in it\n", number.s);
290
+                                    carrierid = 0;
291
+                                    goto found;
292
+                                case PDB_CODE_NOT_FOUND:
293
+                                    LM_WARN("Number %s pdb_id not found\n", number.s);
294
+                                    carrierid = 0;
295
+                                    goto found;
296
+                                default:
297
+                                    LM_WARN("Invalid code %d received\n", msg.hdr.code);
298
+                                    carrierid = 0;
299
+                                    goto found;
300
+                            }
301
+
302
+                            break;
303
+                        default:
304
+                            buf[sizeof(struct pdb_msg) - 1] = '\0';
305
+                            if (strncmp(buf, number.s, number.len) == 0) {
306
+                                _id = (short int *)&(buf[reqlen]);
307
+                                carrierid=ntohs(*_id); /* convert to host byte order */
308
+                                goto found;
309
+                            }
310
+                            break;
311
+                    }
277 312
 				}
278 313
 			}
279 314
 			server_list->fds[i].revents = 0;
... ...
@@ -664,7 +773,10 @@ static int mod_init(void)
664 664
 		shm_free(active);
665 665
 		return -1;
666 666
 	}
667
-	return 0;
667
+
668
+    global_id = (uint16_t*)shm_malloc(sizeof(uint16_t));
669
+
670
+    return 0;
668 671
 }
669 672
 
670 673
 static int child_init (int rank)
... ...
@@ -1,8 +1,8 @@
1 1
 .phony: all clean install
2 2
 
3 3
 header=common.h carrier.h dt.h dtm.h pdb_server_backend.h log.h
4
-obj=dt.o dtm.o carrier.o pdb_server_backend.o log.o
5
-pdb_server_obj=pdb_server_backend.o dtm.o log.o
4
+obj=dt.o dtm.o carrier.o pdb_server_backend.o log.o common.o
5
+pdb_server_obj=pdb_server_backend.o dtm.o log.o common.o
6 6
 cflags=-Wall -O2 -g
7 7
 # -march=x86-64
8 8
 extdep=Makefile
9 9
new file mode 100644
... ...
@@ -0,0 +1,43 @@
0
+#include "common.h"
1
+#include "log.h"
2
+#include <string.h>
3
+
4
+void pdb_msg_dbg(struct pdb_msg msg) {
5
+    int i;
6
+
7
+    LERR("version = %d\n", msg.hdr.version);
8
+    LERR("type = %d\n", msg.hdr.type);
9
+    LERR("code = %d\n", msg.hdr.code);
10
+    LERR("id = %d\n", msg.hdr.id);
11
+    LERR("len = %d\n", msg.hdr.length);
12
+    LERR("payload = ");
13
+    for (i = 0; i < msg.hdr.length - sizeof(msg.hdr); i++) {
14
+        LERR("%02X ", msg.bdy.payload[i]);
15
+    }
16
+    LERR("\n");
17
+
18
+    return ;
19
+}
20
+
21
+int pdb_msg_format_send(struct pdb_msg *msg,
22
+                        uint8_t version, uint8_t type,
23
+                        uint8_t code, uint16_t id,
24
+                        char *payload, uint16_t payload_len)
25
+{
26
+    msg->hdr.version    = version;
27
+    msg->hdr.type       = type;
28
+    msg->hdr.code       = code;
29
+    msg->hdr.id         = id;
30
+
31
+    if (payload == NULL) {
32
+        /* just ignore the NULL buff (called when just want to set the len) */
33
+        msg->hdr.length     = sizeof(struct pdb_hdr);
34
+        return 0;
35
+    } else {
36
+        msg->hdr.length     = sizeof(struct pdb_hdr) + payload_len;
37
+        memcpy(msg->bdy.payload, payload, payload_len);
38
+        return 0;
39
+    }
40
+
41
+    return 0;
42
+}
... ...
@@ -41,16 +41,60 @@
41 41
 #define OTHER_CARRIERID 1000
42 42
 #define MAX_CARRIERID 1000
43 43
 #define NULL_CARRIERID -1001
44
+#define PAYLOADSIZE 256
45
+
44 46
 
45 47
 #define IS_VALID_PDB_CARRIERID(id) ((id>=MIN_PDB_CARRIERID) && (id<=MAX_PDB_CARRIERID))
46 48
 #define IS_VALID_CARRIERID(id) ((id>=MIN_PDB_CARRIERID) && (id<=MAX_CARRIERID))
47 49
 
50
+#define PDB_VERSION     1
48 51
 
49 52
 
50 53
 
51 54
 typedef int16_t carrier_t;
52 55
 
53
-
54
-
56
+enum __attribute__((packed)) pdb_versions {
57
+    PDB_VERSION_1 = 1,
58
+    PDB_VERSION_MAX
59
+};
60
+
61
+enum __attribute__((packed)) pdb_types {
62
+    PDB_TYPE_REQUEST_ID = 0,    /* request pdb type */
63
+    PDB_TYPE_REPLY_ID,          /* reply pdb type */
64
+    PDB_TYPE_MAX
65
+};
66
+
67
+enum __attribute__((packed)) pdb_codes {
68
+    PDB_CODE_DEFAULT = 0,   /* for request */
69
+    PDB_CODE_OK,            /* for response - OK */
70
+    PDB_CODE_NOT_NUMBER,    /* for response - letters found in the number */
71
+    PDB_CODE_NOT_FOUND,     /* for response - no pdb_id found for the number */
72
+    PDB_CODE_MAX
73
+};
74
+
75
+struct __attribute__((packed)) pdb_hdr {
76
+    uint8_t version;
77
+    uint8_t type;
78
+    uint8_t code;
79
+    uint8_t length;
80
+    uint16_t id;
81
+};
82
+
83
+struct __attribute__((packed)) pdb_bdy {
84
+    char payload[PAYLOADSIZE];
85
+};
86
+
87
+struct __attribute__((packed)) pdb_msg {
88
+    struct pdb_hdr hdr;
89
+    struct pdb_bdy bdy;
90
+};
91
+
92
+
93
+
94
+void pdb_msg_dbg (struct pdb_msg msg);
95
+int pdb_msg_format_send(struct pdb_msg *msg,
96
+                            uint8_t version, uint8_t type,
97
+                            uint8_t code, uint16_t id,
98
+                            char *payload, uint16_t payload_len);
55 99
 
56 100
 #endif
... ...
@@ -14,3 +14,40 @@ Possible values for the search request:
14 14
   * 1-999 the number was found and the result represents its carrier ID
15 15
   * 1000: the number could be found, but its owned from a carriers which is
16 16
     not interesting for us and belongs to the "other carrier" group
17
+
18
+
19
+From PDB_VERSION_1 onwards the pdb request and reply looks like this:
20
+
21
+    +-------+----+----+------+--+-------+
22
+    |          header           |  body |
23
+    +-------+----+----+------+--+-------+
24
+    |version|type|code|length|id|payload|
25
+    +-------+----+----+------+--+-------+
26
+
27
+Version
28
+    Current version is 1 (0x01).
29
+
30
+Type
31
+    PDB_TYPE_REQUEST_ID = 0,    /* request pdb type */
32
+    PDB_TYPE_REPLY_ID,          /* reply pdb type */
33
+
34
+Code
35
+    PDB_CODE_DEFAULT = 0,   /* for request */
36
+    PDB_CODE_OK,            /* for response - OK */
37
+    PDB_CODE_NOT_NUMBER,    /* for response - letters found in the number */
38
+    PDB_CODE_NOT_FOUND,     /* for response - no pdb_id found for the number */
39
+
40
+Length
41
+    The length of the whole message
42
+
43
+Id
44
+    A pdb_msg id which might be used for asynchronous queries.
45
+
46
+Payload
47
+    Request number including '\0' for request.
48
+    Request number including '\0' and pdb_id for reply.
49
+
50
+Backwards compatibility with the old msg protocol is kept when the first byte
51
+received is different from the known versions ('0x01' for now)
52
+
53
+For more info about the data structures used, see common.h file.
... ...
@@ -55,10 +55,10 @@ void destroy_log(void) {
55 55
 
56 56
 
57 57
 
58
-void log_stdout(char * format, va_list ap)
58
+void log_stderr(char * format, va_list ap)
59 59
 {
60
-	vfprintf(stdout, format, ap);
61
-	fflush(stdout);
60
+	vfprintf(stderr, format, ap);
61
+	fflush(stderr);
62 62
 }
63 63
 
64 64
 
... ...
@@ -70,7 +70,7 @@ void pdb_log(int priority, char * format, ...) {
70 70
 	if (priority<=log_level) {
71 71
 		va_start(ap, format);
72 72
 		if (use_syslog) vsyslog(priority, format, ap);
73
-		else log_stdout(format, ap);
73
+		else log_stderr(format, ap);
74 74
 		va_end(ap);
75 75
 	}
76 76
 }
... ...
@@ -43,7 +43,12 @@ void pdb_log(int priority, char * format, ...);
43 43
 #define LINFO(fmt, args...) pdb_log(LOG_INFO, fmt, ## args)
44 44
 #define LDEBUG(fmt, args...) pdb_log(LOG_DEBUG, fmt, ## args)
45 45
 
46
+/* several shell exit codes for the application pdbt */
46 47
 
47
-
48
+#define PDB_OK 0              /* Everything ok */
49
+#define PDB_USE_ERROR 1       /* Wrong usage of application (unknown command, file not found, etc.) */
50
+#define PDB_NOT_IN_PDB 2      /* A queried number is not in the pdb */
51
+#define PDB_TIMEOUT 3         /* A timeout (server not responding) occured */
52
+#define PDB_OTHER 4           /* Another application error occured */
48 53
 
49 54
 #endif
... ...
@@ -65,7 +65,29 @@ void print_usage(char *program) {
65 65
 	LINFO("    -h: Print this help.\n");
66 66
 }
67 67
 
68
+int pdb_msg_server_send(int so, char *buf, size_t answerlen, struct sockaddr *fromaddr, socklen_t fromaddrlen)
69
+{
70
+	ssize_t bytes_sent;
71
+	int try = 0;
72
+	again:
73
+		bytes_sent = sendto(so, buf, answerlen, 0, fromaddr, fromaddrlen);
74
+		if (bytes_sent < 3) {
75
+			if ((errno == EINTR) && (try < 3)) {
76
+				try++;
77
+				LERR("sendto() failed - trying again. errno=%d (%s)\n", errno, strerror(errno));
78
+				goto again;
79
+			}
80
+			LERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
81
+			if ((errno==EAGAIN)||(errno==EINTR)||(errno==EWOULDBLOCK)) return 0;
82
+			return -1;
83
+		}
84
+		if (bytes_sent != answerlen) {
85
+			LERR("cannot send the whole answer (%ld/%ld).\n", (long int)bytes_sent, (long int)answerlen);
86
+			return 0;
87
+		}
68 88
 
89
+    return 0;
90
+}
69 91
 
70 92
 
71 93
 /*
... ...
@@ -77,60 +99,101 @@ void print_usage(char *program) {
77 77
 */
78 78
 int udp_server(int so)
79 79
 {
80
+    struct pdb_msg msg;
80 81
 	struct sockaddr fromaddr;
81 82
 	socklen_t fromaddrlen;
82
-	size_t answerlen;
83
+	size_t answerlen = 0;
83 84
 	ssize_t bytes_received;
84
-	ssize_t bytes_sent;
85 85
 	carrier_t carrierid;
86
-	char buf[NETBUFSIZE+1+sizeof(carrierid)]; /* additional space for '\0' termination and carrier */
86
+	char buf[sizeof(struct pdb_msg)];
87 87
 	int i;
88
-	int try;
89 88
 
90 89
 	for (;;) {
91 90
 		fromaddrlen = sizeof(fromaddr);
92
-		bytes_received = recvfrom(so, buf, NETBUFSIZE, 0, &fromaddr, &fromaddrlen);
91
+		bytes_received = recvfrom(so, buf, sizeof(struct pdb_msg), 0, &fromaddr, &fromaddrlen);
93 92
 		if (bytes_received<0) {
94
-      LERR("recvfrom() failed with errno=%d (%s)\n", errno, strerror(errno));
93
+            LERR("recvfrom() failed with errno=%d (%s)\n", errno, strerror(errno));
95 94
 			if ((errno==EAGAIN)||(errno==EINTR)||(errno==EWOULDBLOCK)) continue;
96 95
 			return -1;
97 96
 		}
98
-		
99
-		/* take only digits */
100
-		i=0;
101
-		while ((i<bytes_received) && (buf[i]>='0') && (buf[i]<='9')) i++;
102
-		buf[i]=0; /* terminate string */
103
-		i++;
104 97
 
105
-		carrierid=lookup_number(buf);
106
-		
107
-		/* convert to network byte order*/
108
-		carrierid=htons(carrierid);
98
+        switch (buf[0]) {
99
+            case PDB_VERSION_1:
100
+                /* get received bytes */
101
+                memcpy(&msg, buf, bytes_received);
102
+//                pdb_msg_dbg(msg);
103
+                short int *_id = (short int *)&(msg.hdr.id); /* make gcc happy */
104
+                msg.hdr.id = ntohs(*_id);
109 105
 
110
-		/* append carrier id to answer */
111
-		memcpy(&(buf[i]), &carrierid, sizeof(carrierid));
112
-		answerlen=i+sizeof(carrierid);
113
-		
114
-		try=0;
115
-	again:
116
-		bytes_sent = sendto(so, buf, answerlen, 0, &fromaddr, fromaddrlen);
117
-		if (bytes_sent < 3) {
118
-			if ((errno==EINTR) && (try<3)) {
119
-				try++;
120
-				LERR("sendto() failed - trying again. errno=%d (%s)\n", errno, strerror(errno));
121
-				goto again;
122
-			}
123
-			LERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
124
-			if ((errno==EAGAIN)||(errno==EINTR)||(errno==EWOULDBLOCK)) continue;
125
-			return -1;
126
-		}
127
-		if (bytes_sent != answerlen) {
128
-			LERR("cannot send the whole answer (%ld/%ld).\n", (long int)bytes_sent, (long int)answerlen);
129
-			continue;
130
-		}
131
-	}
106
+                i = 0;
107
+                while (i < strlen(msg.bdy.payload)) {
108
+                    if (msg.bdy.payload[i] < '0' || msg.bdy.payload[i] > '9') {
109
+                        pdb_msg_format_send(&msg, PDB_VERSION_1, PDB_TYPE_REPLY_ID, PDB_CODE_NOT_NUMBER, htons(msg.hdr.id), NULL, 0);
110
+                        goto msg_send;
111
+                    }
112
+                    i++;
113
+                }
114
+                /* lookup pdb_id */
115
+                carrierid=lookup_number(msg.bdy.payload);
132 116
 
133
-	return 0;
117
+                /* check if not found pdb_id */
118
+                if (carrierid == 0) {
119
+                    pdb_msg_format_send(&msg, PDB_VERSION_1, PDB_TYPE_REPLY_ID, PDB_CODE_NOT_FOUND, htons(msg.hdr.id), NULL, 0);
120
+                    goto msg_send;
121
+                }
122
+
123
+                /* convert to network byte order*/
124
+                carrierid = htons(carrierid);
125
+
126
+                /* prepare the message payload to be sent
127
+                 * add the number string and append the carrier id
128
+                 */
129
+                memcpy(buf, msg.bdy.payload, msg.hdr.length - sizeof(msg.hdr));
130
+                memcpy(buf + msg.hdr.length - sizeof(msg.hdr), &carrierid, sizeof(carrierid));
131
+
132
+                /* all ok, send pdb_msg with pdb_id in payload */
133
+                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));
134
+                goto msg_send;
135
+
136
+                break;
137
+
138
+            /* old pdb version; no pdb_msg used */
139
+            default:
140
+                /* take only digits */
141
+                i=0;
142
+                while ((i<bytes_received) && (buf[i]>='0') && (buf[i]<='9')) i++;
143
+                buf[i]=0; /* terminate string */
144
+                i++;
145
+
146
+                /* lookup pdb_id */
147
+                carrierid=lookup_number(buf);
148
+
149
+                /* convert to network byte order*/
150
+                carrierid=htons(carrierid);
151
+
152
+                /* append carrier id to answer */
153
+                memcpy(&(buf[i]), &carrierid, sizeof(carrierid));
154
+                answerlen=i+sizeof(carrierid);
155
+                goto buf_send;
156
+
157
+                break;
158
+        }
159
+
160
+msg_send:
161
+//        pdb_msg_dbg(msg);
162
+        if (pdb_msg_server_send(so, (char*)&msg, msg.hdr.length, &fromaddr, fromaddrlen) < 0) {
163
+            return -1;
164
+        }
165
+        continue;
166
+
167
+buf_send:
168
+        if (pdb_msg_server_send(so, buf, answerlen, &fromaddr, fromaddrlen)) {
169
+            return -1;
170
+        }
171
+        continue;
172
+    }
173
+
174
+	return -1;
134 175
 }
135 176
 
136 177
 
... ...
@@ -39,14 +39,10 @@
39 39
 #include "log.h"
40 40
 
41 41
 
42
+/* incremented after request sent to the server */
43
+uint16_t id = 0;
42 44
 
43
-
44
-#define NETBUFSIZE 200
45
-
46
-
47
-
48
-
49
-typedef void (*query_func_t)(char *number, char *comment, void *data);
45
+typedef int (*query_func_t)(char *number, char *comment, void *data);
50 46
 
51 47
 
52 48
 
... ...
@@ -136,13 +132,11 @@ int file_query(char *filename, query_func_t query_func, void *data) {
136 136
 	else fp = fopen(filename, "r");
137 137
 	if (fp == NULL) {
138 138
 		LERR("cannot open file '%s'\n", filename);
139
-		return -1;
139
+		return -PDB_USE_ERROR;
140 140
 	}
141 141
 	while ((read = getline(&line, &len, fp)) != -1) {
142 142
 		p=line;
143 143
 		while ((*p >= '0') && (*p <= '9') && (p < line+len)) p++;
144
-		*p='\0';
145
-		p++;
146 144
 		comment=p;
147 145
 		while ((*p >= 32) && (p < line+len)) p++;
148 146
 		*p='\0';
... ...
@@ -150,7 +144,7 @@ int file_query(char *filename, query_func_t query_func, void *data) {
150 150
 	}
151 151
 	if (line) free(line);
152 152
 	fclose(fp);
153
-	return 0;
153
+	return -PDB_OK;
154 154
 }
155 155
 
156 156
 
... ...
@@ -184,6 +178,11 @@ int import_csv(struct dt_node_t *root, char *filename) {
184 184
 	while ((read = getline(&line, &len, fp)) != -1) {
185 185
 		carrier_str=line;
186 186
 		prefix=strsep(&carrier_str, ";");
187
+		if ( carrier_str == NULL ) {
188
+			LWARNING("line %ld: no delimiter `;' found, ignoring line.\n", n); 
189
+			n++;
190
+			continue;
191
+		}
187 192
 		ret=strtol(carrier_str, NULL, 10);
188 193
 		if (!IS_VALID_PDB_CARRIERID(ret)) {
189 194
 			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_
451 451
  */
452 452
 int query_udp(char *number, int timeout, struct pollfd *pfds, struct sockaddr_in *dstaddr, socklen_t dstaddrlen)
453 453
 {
454
+    struct pdb_msg msg;
454 455
 	struct timeval tstart, tnow;
455 456
 	short int carrierid;
456
-	char buf[NETBUFSIZE+1+sizeof(carrierid)];
457
+	char buf[sizeof(struct pdb_msg)];
457 458
 	size_t reqlen;
458 459
 	int ret, nflush;
459 460
 	long int td;
461
+    ssize_t bytes_received;
462
+    short int * idptr;
463
+
460 464
 
461 465
 	if (gettimeofday(&tstart, NULL) != 0) {
462 466
 		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
465 465
 
466 466
 	/* clear recv buffer */
467 467
 	nflush = 0;
468
-	while (recv(pfds->fd, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) {
468
+	while (recv(pfds->fd, buf, sizeof(struct pdb_msg), MSG_DONTWAIT) > 0) {
469 469
 		nflush++;
470 470
 		if (gettimeofday(&tnow, NULL) != 0) {
471 471
 			LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
472
-			return -1;
472
+			return -PDB_OTHER;
473 473
 		}
474 474
 		td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
475 475
 		if (td > timeout) {
476 476
 			LWARNING("exceeded timeout while flushing recv buffer.\n");
477
-			return -1;
477
+			return -PDB_TIMEOUT;
478 478
 		}
479 479
 	}
480 480
 	
481 481
 	/* prepare request */
482 482
 	reqlen = strlen(number) + 1; /* include null termination */
483
-	if (reqlen > NETBUFSIZE) {
483
+	if (reqlen > sizeof(struct pdb_bdy)) {
484 484
 		LERR("number too long '%s'.\n", number);
485
-		return -1;
485
+		return -PDB_USE_ERROR;
486 486
 	}
487 487
 	strcpy(buf, number);
488 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
-		
489
+    switch (PDB_VERSION) {
490
+        case PDB_VERSION_1:
491
+            pdb_msg_format_send(&msg, PDB_VERSION, PDB_TYPE_REQUEST_ID, PDB_CODE_DEFAULT, htons(id), buf, reqlen);
492
+//            pdb_msg_dbg(msg);
493
+
494
+            /* increment msg id for the next request */
495
+            id++;
496
+
497
+            /* send request to all servers */
498
+            ret=sendto(pfds->fd, (struct pdb_msg*)&msg, msg.hdr.length, MSG_DONTWAIT, (struct sockaddr *)dstaddr, dstaddrlen);
499
+            if (ret < 0) {
500
+                LERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
501
+                return -1;
502
+            }
503
+            break;
504
+        default:
505
+            /* send request to all servers */
506
+            ret=sendto(pfds->fd, buf, reqlen, MSG_DONTWAIT, (struct sockaddr *)dstaddr, dstaddrlen);
507
+            if (ret < 0) {
508
+                LERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
509
+                return -PDB_OTHER;
510
+            }
511
+            break;
512
+    }
513
+
496 514
 	/* wait for response */
497 515
 	for (;;) {
498 516
 		if (gettimeofday(&tnow, NULL) != 0) {
499 517
 			LERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
500
-			return -1;
518
+			return -PDB_OTHER;
501 519
 		}
502 520
 		td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
503 521
 		if (td > timeout) {
504 522
 			LWARNING("exceeded timeout while waiting for response.\n");
505
-			return -1;
523
+			return -PDB_TIMEOUT;
506 524
 		}
507
-		
525
+
508 526
 		ret=poll(pfds, 1, timeout-td);
509 527
 		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
-				}
528
+			if ((bytes_received = recv(pfds->fd, buf, sizeof(struct pdb_msg), MSG_DONTWAIT)) > 0) { /* do not block - just in case select/poll was wrong */
529
+                switch (PDB_VERSION) {
530
+                    case PDB_VERSION_1:
531
+                        memcpy(&msg, buf, bytes_received);
532
+//                        pdb_msg_dbg(msg);
533
+                          idptr = (short int *)&(msg.hdr.id); /* make gcc happy */
534
+                          msg.hdr.id = ntohs(*idptr);
535
+
536
+
537
+                        switch (msg.hdr.code) {
538
+                            case PDB_CODE_OK:
539
+                                msg.bdy.payload[sizeof(struct pdb_bdy) - 1] = '\0';
540
+                                if (strcmp(msg.bdy.payload, number) == 0) {
541
+                                    idptr = (short int *)&(msg.bdy.payload[reqlen]); /* make gcc happy */
542
+                                    carrierid=ntohs(*idptr); /* convert to host byte order */
543
+                                    goto found;
544
+                                }
545
+                                break;
546
+                            case PDB_CODE_NOT_NUMBER:
547
+			                    LERR("Number %s has letters in it\n", number);
548
+                                carrierid = 0;
549
+                                goto found;
550
+                            case PDB_CODE_NOT_FOUND:
551
+			                    LERR("Number %s pdb_id not found\n", number);
552
+                                carrierid = 0;
553
+                                goto found;
554
+                            default:
555
+			                    LERR("Invalid code %d received\n", msg.hdr.code);
556
+                                carrierid = 0;
557
+                                goto found;
558
+                        }
559
+
560
+                        break;
561
+                    default:
562
+                        buf[sizeof(struct pdb_msg) - 1] = '\0';
563
+                        if (strcmp(buf, number) == 0) {
564
+                            idptr = (short int *)&(buf[reqlen]); /* make gcc happy */
565
+                            carrierid=ntohs(*idptr); /* convert to host byte order */
566
+                            goto found;
567
+                        }
568
+                        break;
569
+                }
516 570
 			}
517 571
 		}
518 572
 		pfds->revents = 0;
... ...
@@ -538,7 +595,7 @@ struct server_query_data_t {
538 538
 
539 539
 
540 540
 
541
-void query_mmap(char *number, char *comment, void *data) {
541
+int query_mmap(char *number, char *comment, void *data) {
542 542
 	int nmatch;
543 543
 	carrier_t carrierid;
544 544
 	struct dtm_node_t *mroot = (struct dtm_node_t *)data;
... ...
@@ -547,31 +604,39 @@ void query_mmap(char *number, char *comment, void *data) {
547 547
 
548 548
 	if (nmatch<=0) {
549 549
 		LINFO("%s:%s:%ld:%s\n", number, comment, (long int)carrierid, "not allocated, probably old");
550
+		return -PDB_NOT_IN_PDB;
550 551
 	}
551 552
 	else {
552 553
 		LINFO("%s:%s:%ld:%s\n", number, comment, (long int)carrierid, carrierid2name(carrierid));
553 554
 		/* LINFO("%s: found: carrier_id=%ld, carrier_name='%s', nmatch=%ld, comment='%s'\n", number, (long int)carrierid, carrierid2name(carrierid), (long int)nmatch, comment);
554 555
 		*/
556
+		return -PDB_OK;
555 557
 	}
556 558
 }
557 559
 
558 560
 
559 561
 
560 562
 
561
-void query_server(char *number, char *comment, void *data) {
563
+int query_server(char *number, char *comment, void *data) {
562 564
 	carrier_t carrierid;
563 565
 	struct server_query_data_t *sdata = (struct server_query_data_t *)data;
566
+	int result = 0;
564 567
 
565 568
 	carrierid = query_udp(number, sdata->timeout, &(sdata->pfds), &(sdata->dstaddr), sdata->dstaddrlen);
566 569
 
567 570
 	if (carrierid<=0) {
568
-		LINFO("%s: not_found: comment='%s'\n", number, comment);
571
+		LINFO("%s: not_found: comment='%s', result=%d\n", number, comment, carrierid);
572
+		if (carrierid < 0) {
573
+			result = carrierid; 
574
+		} else {
575
+			result = PDB_NOT_IN_PDB; 
576
+		}
569 577
 	}
570 578
 	else {
571 579
 		LINFO("%s:%ld:%s\n", number, (long int)carrierid, carrierid2name(carrierid));
572
-		/* LINFO("%s: found: carrier_id=%ld, carrier_name='%s', comment='%s'\n", number, (long int)carrierid, carrierid2name(carrierid), comment);
573
-		*/
580
+		result = PDB_OK;
574 581
 	}
582
+	return result; 
575 583
 }
576 584
 
577 585
 
... ...
@@ -604,6 +669,7 @@ int main(int argc, char *argv[]) {
604 604
 
605 605
 	char *id_str;
606 606
 	long int ret;
607
+	int exit_status = PDB_OK;
607 608
 
608 609
 	sdata.timeout=500;
609 610
 
... ...
@@ -782,7 +848,7 @@ int main(int argc, char *argv[]) {
782 782
 			if (hp == NULL) {
783 783
 				LERR("gethostbyname(%s) failed with h_errno=%d.\n", host_str, h_errno);
784 784
 				close(sockfd);
785
-				return -1;
785
+				exit (PDB_USE_ERROR);
786 786
 			}
787 787
 			memcpy(&sdata.dstaddr.sin_addr.s_addr, hp->h_addr, hp->h_length);
788 788
 			sdata.dstaddrlen=sizeof(sdata.dstaddr);
... ...
@@ -792,19 +858,30 @@ int main(int argc, char *argv[]) {
792 792
 
793 793
 			if (query_file==NULL) {
794 794
 				LINFO("\nprocessing command line parameters...\n");
795
+				if ( optind+1 >= argc) {
796
+					exit_status = PDB_USE_ERROR;
797
+				}
795 798
 				for (n=optind+1; n<argc; n++) {
796
-					query_server(argv[n], "", &sdata);
799
+					int result; 
800
+					result = query_server(argv[n], "", &sdata); 
801
+					if ( result != 0) {
802
+						exit_status = -result; 
803
+					}
797 804
 				}
798 805
 			}
799 806
 			else {
800
-				file_query(query_file, query_server, &sdata);
807
+				int result; 
808
+				result = file_query(query_file, query_server, &sdata);
809
+				if ( result != 0) {
810
+					exit_status = -result; 
811
+				}
801 812
 			}
802 813
 		}
803 814
 		else {
804 815
 			mroot=dtm_load(mmap_file);
805 816
 			if (mroot == NULL) {
806 817
 				LERR("cannot load '%s'.\n", mmap_file);
807
-				return -1;
818
+				exit(PDB_USE_ERROR);
808 819
 			}
809 820
 			
810 821
 			if (query_file==NULL) {
... ...
@@ -814,14 +891,18 @@ int main(int argc, char *argv[]) {
814 814
 				}
815 815
 			}
816 816
 			else {
817
-				file_query(query_file, query_mmap, mroot);
817
+				int result; 
818
+				result = file_query(query_file, query_mmap, mroot);
819
+				if ( result != 0) {
820
+					exit_status = -result; 
821
+				}
818 822
 			}
819 823
 		}
820 824
 	}
821 825
 	else {
822 826
 		LERR("invalid command '%s'.\n", argv[optind]);
823
-		return 1;
827
+		exit(PDB_USE_ERROR);
824 828
 	}
825 829
 
826
-	return 0;
830
+	exit (exit_status);
827 831
 }
828 832
new file mode 100644
... ...
@@ -0,0 +1,60 @@
0
+#!/usr/bin/perl
1
+use utf8;
2
+use LWP::UserAgent;
3
+use HTTP::Cookies;
4
+
5
+sub main
6
+{
7
+    # Create the fake browser (user agent).
8
+    my $ua = LWP::UserAgent->new();
9
+
10
+    # Pretend to be Internet Explorer.
11
+    $ua->agent("Windows IE 7");
12
+    # or maybe .... $ua->agent("Mozilla/8.0");
13
+
14
+    # Get some HTML.
15
+    my $response = $ua->get('http://www.bundesnetzagentur.de/cln_1421/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Nummerierung/Technische%20Nummern/Portierungskennungen/VerzeichnisPortKenn_Basepage.html?nn=268376');
16
+
17
+    unless($response->is_success) {
18
+        print "Error: " . $response->status_line;
19
+    }
20
+
21
+    # Let's save the output.
22
+    my $file = $response->decoded_content;
23
+    utf8::encode($file);
24
+    @pieces=split('\<tbody\>', $file);
25
+    @pieces2=split('\</tbody\>', $pieces[1]);
26
+    @linii=split('\</tr\>', $pieces2[0]);
27
+    foreach(@linii)
28
+    {
29
+        my($first, $rest) = split(/>/, $_, 2);
30
+        @tds=split('/td><td', $rest);
31
+        @names=split('>', $tds[0], 2);
32
+        my $name=$names[1];
33
+        $name =~ s/<p>//;
34
+        $name =~ s/<p>//;
35
+        $name =~ s/<\/p>//;
36
+        $name =~ s/<\/p>//;
37
+        $name =~ s/<//;
38
+        $name =~ s/\n//;
39
+        $name =~ s/br\/>//;
40
+        $name =~ s/br\/>//;
41
+        $name =~ s/<//;
42
+        $name =~ s/<//;
43
+        $name =~ s/\n//;
44
+        chomp($name);
45
+        @tds2=split('>', $tds[1], 2);
46
+        @tds3=split('</', $tds2[1]);
47
+        @tds4=split('<br/>', $tds3[0]);
48
+        foreach(@tds4)
49
+        {
50
+            $_ =~ s/^\n//;
51
+            if ($_ =~ /^D/)
52
+            {
53
+                    $number=substr($_,0,4);
54
+                    print "$number $name\n";
55
+            }
56
+        }
57
+    }
58
+}
59
+main();
... ...
@@ -23,14 +23,15 @@
23 23
 # the 'Bundesnetzagentur' and convert this into the format which the pdbt tool
24 24
 # understands.
25 25
 
26
-url="http://www.bundesnetzagentur.de/cln_1912/DE/Sachgebiete/Telekommunikation/RegulierungTelekommunikation/Nummernverwaltung/TechnischeNummern/Portierungskennung/VerzeichnisPortKenn_Basepage.html"
26
+#old_url="http://www.bundesnetzagentur.de/cln_1912/DE/Sachgebiete/Telekommunikation/RegulierungTelekommunikation/Nummernverwaltung/TechnischeNummern/Portierungskennung/VerzeichnisPortKenn_Basepage.html"
27
+url="http://www.bundesnetzagentur.de/cln_1421/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Nummerierung/Technische%20Nummern/Portierungskennungen/VerzeichnisPortKenn_Basepage.html?nn=268376#Inhalt"
27 28
 
28
-# fix LOCALE problem during filtering 
29
+# fix LOCALE problem during filtering
29 30
 export LANG="C"
30 31
 
31
-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>.*$//'
32
+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 } }'
32 33
 
33 34
 # probably also possible to use this:
34 35
 # http://www.bundesnetzagentur.de/cae/servlet/contentblob/156772/publicationFile/8492/KonsolidiertesVerzPortierungsk.zip
35 36
 # main page (for reference):
36
-# http://www.bundesnetzagentur.de/cln_1932/DE/Sachgebiete/Telekommunikation/RegulierungTelekommunikation/Nummernverwaltung/TechnischeNummern/Portierungskennung/KonsolidiertesVerzPortKenn_Basepage.html?nn=120380
37 37
\ No newline at end of file
38
+# http://www.bundesnetzagentur.de/cln_1932/DE/Sachgebiete/Telekommunikation/RegulierungTelekommunikation/Nummernverwaltung/TechnischeNummern/Portierungskennung/KonsolidiertesVerzPortKenn_Basepage.html?nn=120380