Project

General

Profile

Statistics
| Branch: | Revision:

gdp-router-click / src / gdp_v4_router.cc @ master

History | View | Annotate | Download (210 KB)

1 62a58ed2 Rick Pratt
/*
2
**        GDPv4Router --- Click-based GDP v4 router implementation
3
**
4
**        ----- BEGIN LICENSE BLOCK -----
5
**        GDPv4Router --- Click-based GDP v4 router implementation
6
**  From the Ubiquitous Swarm Lab, 490 Cory Hall, U.C. Berkeley.
7
**
8 4b971df6 Rick Pratt
**        Copyright (c) 2017-2019, Regents of the University of California.
9 62a58ed2 Rick Pratt
**        All rights reserved.
10
**
11
**        Permission is hereby granted, without written agreement and without
12
**        license or royalty fees, to use, copy, modify, and distribute this
13
**        software and its documentation for any purpose, provided that the above
14
**        copyright notice and the following two paragraphs appear in all copies
15
**        of this software.
16
**
17
**        IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
18
**        SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
19
**        PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
20
**        EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21
**
22
**        REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
23
**        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
**        FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
25
**        IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
26
**        OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
27
**        OR MODIFICATIONS.
28
**        ----- END LICENSE BLOCK -----
29
*/
30
#include <click/config.h>
31
#include <click/error.hh>
32
#include <click/args.hh>
33
#include <click/glue.hh>
34
#include <click/standard/scheduleinfo.hh>
35
#include <click/packet_anno.hh>
36
#include <click/packet.hh>
37 f687a636 Rick Pratt
#include <click/router.hh>
38 62a58ed2 Rick Pratt
#include <unistd.h>
39
#include <sys/ioctl.h>
40
#include <sys/socket.h>
41
#include <sys/un.h>
42
#include <arpa/inet.h>
43
#include <netinet/tcp.h>
44
#include <fcntl.h>
45 2b5c3a2d Rick Pratt
#include <functional>
46
#include <chrono>
47 89b121a5 Rick Pratt
#include <thread>
48 31c2a8d8 Rick Pratt
#include "version_gdp_v4_router.hh"
49 62a58ed2 Rick Pratt
#include "gdp_v4_router.hh"
50 0a4d4011 Rick Pratt
51 62a58ed2 Rick Pratt
extern "C" {
52 0a4d4011 Rick Pratt
# include <openssl/err.h>
53
# include <netinet/in.h>
54
# include <arpa/nameser.h>
55
# include <resolv.h>
56
# include <systemd/sd-daemon.h>
57
58
// ============================================================================
59
// library reduction by duplicating a little libgdp and libep C code
60
// ============================================================================
61
62
# define EP_UT_BITSET(bit, word)        (((bit) & (word)) != 0)
63
# define EP_B64_PAD 0x04 // pad with '='
64
# define EP_B64_ENC_URL "-_@" // NOWRAP -PAD -IGNCRUD
65
66
        static const char *EncChars =
67
                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
68
69
        static char
70
        getenc (int b, const char *encoding)
71
        {
72
                assert(b >= 0 && b < 64);
73
74
                if (b == 62)
75
                        return encoding[0];
76
                if (b == 63)
77
                        return encoding[1];
78
                return EncChars[b];
79
        }
80
81
        // based on ep_b64_encode with router specific simplifications
82
        char *
83
        gdp_printable_name (const void *bbin, char *txt)
84
        {
85
                size_t bsize = sizeof(gdp_name_t);
86
                const char *encoding = EP_B64_ENC_URL;
87
                const uint8_t *bin = (uint8_t *) bbin;
88
                size_t bx, tx;                        // indexes into binary & text
89
                size_t lx;                        // index into current output line
90
                int nextc = 0;
91
92
                for (bx = tx = lx = 0; bx < bsize;)
93
                {
94
                        switch (bx % 3)
95
                        {
96
                        case 0:
97
                                txt[tx++] = getenc(bin[bx] >> 2, encoding);
98
                                lx++;
99
                                nextc = (bin[bx++] & 0x03) << 4;
100
                                break;
101
102
                        case 1:
103
                                nextc |= (bin[bx] & 0xf0) >> 4;
104
                                txt[tx++] = getenc(nextc, encoding);
105
                                lx++;
106
                                nextc = (bin[bx++] & 0x0f) << 2;
107
                                break;
108
109
                        case 2:
110
                                nextc |= (bin[bx] & 0xc0) >> 6;
111
                                txt[tx++] = getenc(nextc, encoding);
112
                                txt[tx++] = getenc(bin[bx++] & 0x3f, encoding);
113
                                lx += 2;
114
                                break;
115
                        }
116
                }
117
118
                // insert final output character
119
                switch (bx % 3)
120
                {
121
                case 0:
122
                        // no additional data to push
123
                        break;
124
125
                case 1:
126
                        txt[tx++] = getenc(nextc, encoding);
127
                        if (EP_UT_BITSET(EP_B64_PAD, encoding[2]))
128
                        {
129
                                txt[tx++] = '=';
130
                                txt[tx++] = '=';
131
                        }
132
                        break;
133
134
                case 2:
135
                        txt[tx++] = getenc(nextc, encoding);
136
                        if (EP_UT_BITSET(EP_B64_PAD, encoding[2]))
137
                                txt[tx++] = '=';
138
                        break;
139
                }
140
141
                // success!
142
                txt[tx] = '\0';
143
                return txt;
144
        }
145
146
// ============================================================================
147
148 62a58ed2 Rick Pratt
} // extern "C"
149
150
CLICK_DECLS
151
152 2b5c3a2d Rick Pratt
// UNIT TESTS
153 62a58ed2 Rick Pratt
//#define TEST_ADDR_FIND_RETRIES
154
//#define TEST_DTLS_RX_DROP
155 4b971df6 Rick Pratt
//#define TEST_ADVERT_LOAD
156 62a58ed2 Rick Pratt
157 bd851bdd Rick Pratt
// TEST_ADDR_FIND_RETRIES variations
158
#define TEST_ADDR_FIND_RETRIES_TX (ADDR_FIND_RETRIES / 2)
159
160 15a78651 Rick Pratt
// TEST_DTLS_RX_DROP default
161
#define TEST_DTLS_RX_DROP_COUNT 1
162
163 2b5c3a2d Rick Pratt
// TEST_DTLS_RX_DROP variations (uncomment exactly one TEST_DTLS_RX_DROP_NN)
164 62a58ed2 Rick Pratt
#ifdef TEST_DTLS_RX_DROP
165 2b5c3a2d Rick Pratt
//#define TEST_DTLS_RX_DROP_01
166
//#define TEST_DTLS_RX_DROP_02
167
//#define TEST_DTLS_RX_DROP_03
168
//#define TEST_DTLS_RX_DROP_04
169
//#define TEST_DTLS_RX_DROP_05
170
//#define TEST_DTLS_RX_DROP_06
171
//#define TEST_DTLS_RX_DROP_07
172
//#define TEST_DTLS_RX_DROP_08
173 b9253176 Rick Pratt
//#define TEST_DTLS_RX_DROP_09
174
//#define TEST_DTLS_RX_DROP_10
175 15a78651 Rick Pratt
//#define TEST_DTLS_RX_DROP_11
176
#define TEST_DTLS_RX_DROP_12
177 62a58ed2 Rick Pratt
#endif
178
179 2b5c3a2d Rick Pratt
#ifdef TEST_DTLS_RX_DROP_01
180 62a58ed2 Rick Pratt
// drops 1st p (test start sequence nack)
181 bd851bdd Rick Pratt
#define TEST_DTLS_RX_DROP_ITEM 0
182 62a58ed2 Rick Pratt
#define TEST_DTLS_RX_DROP_WRAP 1024
183
#endif
184 2b5c3a2d Rick Pratt
#ifdef TEST_DTLS_RX_DROP_02
185 62a58ed2 Rick Pratt
// drops 2nd p (test not start sequence nack)
186 bd851bdd Rick Pratt
#define TEST_DTLS_RX_DROP_ITEM 1
187 62a58ed2 Rick Pratt
#define TEST_DTLS_RX_DROP_WRAP 1024
188
#endif
189 2b5c3a2d Rick Pratt
#ifdef TEST_DTLS_RX_DROP_03
190 62a58ed2 Rick Pratt
// drop 1/2 from 1st p
191
#define TEST_DTLS_RX_DROP_ITEM 0
192
#define TEST_DTLS_RX_DROP_WRAP 2
193
#endif
194 2b5c3a2d Rick Pratt
#ifdef TEST_DTLS_RX_DROP_04
195 62a58ed2 Rick Pratt
// drop 1/2 from 2nd p
196
#define TEST_DTLS_RX_DROP_ITEM 1
197
#define TEST_DTLS_RX_DROP_WRAP 2
198
#endif
199 2b5c3a2d Rick Pratt
#ifdef TEST_DTLS_RX_DROP_05
200 62a58ed2 Rick Pratt
// drop 1/3 from 1st p
201
#define TEST_DTLS_RX_DROP_ITEM 0
202
#define TEST_DTLS_RX_DROP_WRAP 3
203
#endif
204 2b5c3a2d Rick Pratt
#ifdef TEST_DTLS_RX_DROP_06
205 62a58ed2 Rick Pratt
// drop 1/4 from 1st p
206
#define TEST_DTLS_RX_DROP_ITEM 0
207
#define TEST_DTLS_RX_DROP_WRAP 4
208
#endif
209 2b5c3a2d Rick Pratt
#ifdef TEST_DTLS_RX_DROP_07
210 62a58ed2 Rick Pratt
// drop 1/5 from 1st p
211
#define TEST_DTLS_RX_DROP_ITEM 0
212
#define TEST_DTLS_RX_DROP_WRAP 5
213
#endif
214 2b5c3a2d Rick Pratt
#ifdef TEST_DTLS_RX_DROP_08
215 62a58ed2 Rick Pratt
// drop 1/10 from 1st p
216
#define TEST_DTLS_RX_DROP_ITEM 0
217
#define TEST_DTLS_RX_DROP_WRAP 10
218
#endif
219 2b5c3a2d Rick Pratt
#ifdef TEST_DTLS_RX_DROP_09
220 62a58ed2 Rick Pratt
// drop 1/20 from 1st p
221
#define TEST_DTLS_RX_DROP_ITEM 0
222
#define TEST_DTLS_RX_DROP_WRAP 20
223
#endif
224 b9253176 Rick Pratt
#ifdef TEST_DTLS_RX_DROP_10
225
// drop 1/50 from 1st p
226
#define TEST_DTLS_RX_DROP_ITEM 0
227
#define TEST_DTLS_RX_DROP_WRAP 50
228
#endif
229
#ifdef TEST_DTLS_RX_DROP_11
230
// drop 1/100 from 1st p
231
#define TEST_DTLS_RX_DROP_ITEM 0
232
#define TEST_DTLS_RX_DROP_WRAP 100
233
#endif
234 15a78651 Rick Pratt
#ifdef TEST_DTLS_RX_DROP_12
235
// drop count/100 from item p
236 acabfa65 Rick Pratt
//#define TEST_DTLS_RX_DROP_ITEM 8
237
//#define TEST_DTLS_RX_DROP_WRAP 24
238 15a78651 Rick Pratt
#define TEST_DTLS_RX_DROP_ITEM 10
239 acabfa65 Rick Pratt
#define TEST_DTLS_RX_DROP_WRAP 1000
240 15a78651 Rick Pratt
// TEST_DTLS_RX_DROP default override
241
#undef TEST_DTLS_RX_DROP_COUNT
242 acabfa65 Rick Pratt
//#define TEST_DTLS_RX_DROP_COUNT 3
243 15a78651 Rick Pratt
#define TEST_DTLS_RX_DROP_COUNT 4
244 acabfa65 Rick Pratt
//#define TEST_DTLS_RX_DROP_COUNT 32
245 15a78651 Rick Pratt
#endif
246 62a58ed2 Rick Pratt
247
// =============================================================================
248
249
// interim location to ease ssl_info_callback access
250
uint8_t _debug_level;
251
252
// socket setup for mandatory fds, stored in unused fd slots (stdin, ...)
253
#define _SAV_INDEX_UDP 0
254
#define _SAV_INDEX_TCP 1
255
#define _SAV_INDEX_DIR 2
256
#define _SAV_MIN_SIZE  3
257
258 bd851bdd Rick Pratt
// FIXME: some interim net3 overlay header handling code will be
259
// apparent in these source files, because the first phases of
260
// development involved forwarding net3 pdus. While the overlay header
261
// is no longer used, as of the switchover to net4 pdus, some of the
262
// overlay header code remains intact in these source files for the
263
// time being...
264
265 62a58ed2 Rick Pratt
// track unprocessed bytes held in headroom
266
#define SET_REVEAL_ANNO(_p_, _v_)  SET_AGGREGATE_ANNO(_p_, (_v_))
267
#define REVEAL_ANNO(_p_)           AGGREGATE_ANNO(_p_)
268
269
// track pdu mlen
270
#define SET_MLEN_ANNO(_p_, _v_)    SET_EXTRA_LENGTH_ANNO(_p_, (_v_))
271
#define MLEN_ANNO(_p_)             EXTRA_LENGTH_ANNO(_p_)
272
273
// track sequence assignment
274
#define SET_SEQ_ANNO(_p_, _v_)     SET_SEQUENCE_NUMBER_ANNO(_p_, (_v_))
275
#define SEQ_ANNO(_p_)              SEQUENCE_NUMBER_ANNO(_p_)
276
277
// track p type
278
#define SET_PTYPE_ANNO(_p_, _v_)   SET_SEND_ERR_ANNO(_p_, (_v_))
279
#define PTYPE_ANNO(_p_)            SEND_ERR_ANNO(_p_)
280
281
// track p retx retries
282
#define SET_RETRIES_ANNO(_p_, _v_) SET_PAINT_ANNO(_p_, (_v_))
283
#define RETRIES_ANNO(_p_)          PAINT_ANNO(_p_)
284
285
// track p rx fd
286
static_assert(sizeof(int) <= 4, "IPSEC_SPI_ANNO cannot store int on this host");
287
#define SET_RXFD_ANNO(_p_, _v_)    SET_IPSEC_SPI_ANNO(_p_, (_v_))
288
#define RXFD_ANNO(_p_)             IPSEC_SPI_ANNO(_p_)
289
290
// track p retx aka do not assign p a new seq_mf_off within dtls_tx()
291
#define SET_SEQ_PRESET_ANNO(_p_, _v_)    SET_ICMP_PARAMPROB_ANNO(_p_, (_v_))
292
#define SEQ_PRESET_ANNO(_p_)             ICMP_PARAMPROB_ANNO(_p_)
293
294 acabfa65 Rick Pratt
// track rx halt (rx fd throttled) threshold
295
#define SET_RXHALT_ANNO(_p_, _v_)  SET_FIX_IP_SRC_ANNO(_p_, (_v_))
296
#define RXHALT_ANNO(_p_)           FIX_IP_SRC_ANNO(_p_)
297
298 b9253176 Rick Pratt
#define PTYPE_DIR          1
299
#define PTYPE_GDP_PDU      2
300
#define PTYPE_GDP_PDU_NEXT 3
301 acabfa65 Rick Pratt
#define PTYPE_GDP_PKT      4
302
#define PTYPE_GDP_PKT_FREE 5
303 62a58ed2 Rick Pratt
304
GDPv4Router::GDPv4Router()
305 987af967 Rick Pratt
        : _headroom(Packet::default_headroom),
306 68852766 Rick Pratt
          _fd_dev_urandom(-1),
307 007e01e0 Rick Pratt
          _fd_directory(-1),
308 bd851bdd Rick Pratt
          _fd_directory_status(0),
309 007e01e0 Rick Pratt
          _fd_udp_listen(-1),
310 bf8eea1e Rick Pratt
          _fd_tcp_listen(-1)
311 62a58ed2 Rick Pratt
{
312
}
313
314
GDPv4Router::~GDPv4Router()
315
{
316
}
317
318
int
319 f687a636 Rick Pratt
GDPv4Router::configure(Vector<String> &conf, ErrorHandler * errh)
320 62a58ed2 Rick Pratt
{
321
        Args args = Args(this, errh).bind(conf);
322 bf8eea1e Rick Pratt
        String arg_hostname;
323 5254ed23 Rick Pratt
        String arg_ribname;
324 bf8eea1e Rick Pratt
        char hostname_buf[ARG_BUF_SIZE];
325
        char *h;
326
        bool fqdn;
327 62a58ed2 Rick Pratt
        int index = 0;
328
        IPAddress arg_ip;
329 bf8eea1e Rick Pratt
        bool ip_bind = false;
330 62a58ed2 Rick Pratt
        uint16_t arg_udp_port;
331
        uint16_t arg_tcp_port;
332 5254ed23 Rick Pratt
        IPAddress arg_ip_rib;
333
        uint16_t arg_udp_port_rib;
334 bf8eea1e Rick Pratt
        String arg_peer_str;
335
        bool arg_peer_str_unused;
336
        char *end_str;
337 4b971df6 Rick Pratt
        dst_map_res_t gguid_dmr;
338 62a58ed2 Rick Pratt
339
    if (ninputs() != 0)
340
                return general_error("invalid input connectivity");                
341
    if (noutputs() != 0)
342
                return general_error("invalid output connectivity");                
343
344 68852766 Rick Pratt
        // must init sequence source before first generate_sequence call
345
        _fd_dev_urandom = open("/dev/urandom", O_RDONLY);
346
        if (_fd_dev_urandom == -1)
347
                return general_error("failed to open /dev/urandom");
348
        
349
        // shared id field init
350 62a58ed2 Rick Pratt
        _dr_id = generate_sequence();
351 bf8eea1e Rick Pratt
352 4e81e9a6 Rick Pratt
        // no config ? default peer : no default peer
353
        if (conf.size() == 0)
354
        {
355
                _no_config_mode = true;
356
        }
357
        else
358
        {
359
                _no_config_mode = false;
360
        }
361
362 bf8eea1e Rick Pratt
        // UDP_PORT ? user def : default
363
        args.read_or_set("UDP_PORT", arg_udp_port, DEFAULT_UDP_PORT);
364
        args.consume();
365
366
        // TCP_PORT ? user def : default
367
        args.read_or_set("TCP_PORT", arg_tcp_port, DEFAULT_TCP_PORT);
368
        args.consume();
369 62a58ed2 Rick Pratt
        
370 bf8eea1e Rick Pratt
        // GDPNAME ? user def : { reversed(HOSTNAME) | user def } + .udp_port
371
        args.read("GDPNAME", _gdpr_xname);
372
        if (args.read_status() == 0)
373
        {
374
                // HOSTNAME ? user def : tolower(gethostname())
375
                args.read("HOSTNAME", arg_hostname);
376
                if (args.read_status() == 0)
377
                {
378
                        if (gethostname(hostname_buf, ARG_BUF_MAX) < 0)
379
                        {
380
                                return general_error("gethostname error");
381
                        }
382
                        hostname_buf[ARG_BUF_MAX] = '\0';
383
                        for (h = hostname_buf; *h != '\0'; ++h)
384
                        {
385
                                *h = tolower(*h);
386
                        }
387
                        arg_hostname.append(hostname_buf);
388
                }
389
                else
390
                {
391
                        args.consume();
392
                }
393 62a58ed2 Rick Pratt
394 bf8eea1e Rick Pratt
                // reversed(HOSTNAME)
395
                strcpy(hostname_buf, arg_hostname.c_str());
396
                fqdn = false;
397
                for (h = hostname_buf; *h != '\0'; ++h)
398
                {
399
                        if (*h == '.')
400
                        {
401
                                fqdn = true;
402
                        }
403
                }
404
                if (fqdn)
405
                {
406
                        // work from back to front, reversing dot-delimited tokens
407
                        for (h = h - 1; h > hostname_buf; --h)
408
                        {
409
                                if (*h == '.')
410
                                {
411
                                        _gdpr_xname += &h[1];
412
                                        _gdpr_xname += ".";
413
                                        *h = '\0';
414
                                }
415
                        }
416
                }
417 42ff791d Rick Pratt
                // if fqdn, append remaining (first) token, else append entire string
418
                _gdpr_xname += hostname_buf;
419
420 bf8eea1e Rick Pratt
                // always append .udp_port
421
                _gdpr_xname += ".";
422
                _gdpr_xname += std::to_string(arg_udp_port).c_str();
423
        }
424
        else
425
        {
426
                args.consume();
427
        }
428 62a58ed2 Rick Pratt
429 bf8eea1e Rick Pratt
        // IP ? used def (e.g., bind to specific ip to isolate testbed) : INADDR_ANY
430
        args.read("IP", arg_ip);
431
        if (args.read_status() == 1)
432
        {
433
                args.consume();
434
                ip_bind = true;
435
        }
436
437
        // SINGLE_ROUTER ? true : default false
438
        args.read_or_set("SINGLE_ROUTER", _single_router_mode, false);
439
        args.consume();
440 b3c0cd2b Rick Pratt
441
        if (_single_router_mode == false)
442 bf8eea1e Rick Pratt
        {
443 5254ed23 Rick Pratt
                // RIBNAME ? user_supplied : default("gdp-03.eecs.berkeley.edu")
444
                args.read_or_set("RIBNAME", arg_ribname, "gdp-03.eecs.berkeley.edu");
445 b3c0cd2b Rick Pratt
                args.consume();
446
        
447 5254ed23 Rick Pratt
                // IP_RIB ? user def (e.g., no dns or testbed dir) : resolve(RIBNAME)
448
                args.read("IP_RIB", arg_ip_rib);
449 b3c0cd2b Rick Pratt
                if (args.read_status() == 0)
450 bf8eea1e Rick Pratt
                {
451 5254ed23 Rick Pratt
                        if (resolve(errh, arg_ribname, arg_ip_rib) < 0)
452 b3c0cd2b Rick Pratt
                        {
453 f687a636 Rick Pratt
                                return -1;
454 b3c0cd2b Rick Pratt
                        }
455 bf8eea1e Rick Pratt
                }
456 b3c0cd2b Rick Pratt
                args.consume();
457 62a58ed2 Rick Pratt
        
458 5254ed23 Rick Pratt
                // UDP_PORT_RIB ? user def : 9001 default
459
                args.read_or_set("UDP_PORT_RIB", arg_udp_port_rib, 9001);
460 b3c0cd2b Rick Pratt
                args.consume();
461 4b971df6 Rick Pratt
462 3aa9a35e Rick Pratt
                // ADVERT_TIMER ? user def : 128000 usec (128 msec) default
463
                args.read_or_set("ADVERT_TIMER", _advert_timer, 128000);
464 4b971df6 Rick Pratt
                args.consume();
465 b3c0cd2b Rick Pratt
        }
466 bf8eea1e Rick Pratt
        
467
        // DEBUG ? user def : DOFF default
468
        args.read_or_set("DEBUG", _debug_level, DOFF);
469
        args.consume();
470
471 4e81e9a6 Rick Pratt
        // insert a default peer, if no config
472
        if (_no_config_mode)
473 f687a636 Rick Pratt
        {
474
                if (_dr_id % 2 == 0)
475
                {
476
                        args.push_back("PEER gdp-01.eecs.berkeley.edu");
477
                }
478
                else
479
                {
480
                        args.push_back("PEER gdp-03.eecs.berkeley.edu");                        
481
                }
482
        }
483
        
484 bf8eea1e Rick Pratt
        // conf.size() covers worst (and most likely) case (100% default ports)
485
        if ((_sav = new _sav_t(_SAV_MIN_SIZE + conf.size())) == nullptr)
486
        {
487
                return general_error("new sockaddr vector");
488
        }
489
490
        // udp port listen
491 62a58ed2 Rick Pratt
        (*_sav)[_SAV_INDEX_UDP].sin_family = AF_INET;
492
        (*_sav)[_SAV_INDEX_UDP].sin_port = htons(arg_udp_port);
493 bf8eea1e Rick Pratt
        if (ip_bind)
494
        {
495
                // on an explicit ip address only (development testbed feature)
496
                (*_sav)[_SAV_INDEX_UDP].sin_addr = arg_ip.in_addr();
497
        }
498
        else
499
        {
500
                // on INADDR_ANY (production mode)
501
                (*_sav)[_SAV_INDEX_UDP].sin_addr.s_addr = INADDR_ANY;
502
        }
503 62a58ed2 Rick Pratt
504 bf8eea1e Rick Pratt
        // tcp port listen on INADDR_ANY
505 62a58ed2 Rick Pratt
        (*_sav)[_SAV_INDEX_TCP].sin_family = AF_INET;
506
        (*_sav)[_SAV_INDEX_TCP].sin_port = htons(arg_tcp_port);
507 bf8eea1e Rick Pratt
        (*_sav)[_SAV_INDEX_TCP].sin_addr.s_addr = INADDR_ANY;
508 62a58ed2 Rick Pratt
509 bf8eea1e Rick Pratt
        // directory ip + port (may be dormant if _single_router_mode)
510 62a58ed2 Rick Pratt
        (*_sav)[_SAV_INDEX_DIR].sin_family = AF_INET;
511 5254ed23 Rick Pratt
        (*_sav)[_SAV_INDEX_DIR].sin_addr = arg_ip_rib.in_addr();
512
        (*_sav)[_SAV_INDEX_DIR].sin_port = htons(arg_udp_port_rib);
513 62a58ed2 Rick Pratt
514 bf8eea1e Rick Pratt
        // this router's gdpname
515 0a4d4011 Rick Pratt
        SHA256((const unsigned char*)_gdpr_xname.c_str(), _gdpr_xname.length(),
516
                   _gdpr);
517 bf8eea1e Rick Pratt
518 d9ef385a Eric Allman
        click_chatter("Starting gdp-router-click (v%s %s %s)\n"
519 bf8eea1e Rick Pratt
                                  "\tas %s\n"
520 62a58ed2 Rick Pratt
                                  "\taka %s\n"
521 d672d917 Rick Pratt
                                  "\twith debug %d\n"
522 b3c0cd2b Rick Pratt
                                  "\tlistening on %s udp %d and tcp %d",
523 d672d917 Rick Pratt
                                  ver_major, git_branch, git_hash,
524 bf8eea1e Rick Pratt
                                  _gdpr_xname.c_str(), gdp_printable_name(_gdpr, _gdpr_pname),
525 d672d917 Rick Pratt
                                  _debug_level,
526 bf8eea1e Rick Pratt
                                  (ip_bind ? IPAddress((*_sav)[_SAV_INDEX_UDP]
527
                                                                           .sin_addr).unparse().c_str() : "any"),
528 62a58ed2 Rick Pratt
                                  ntohs((*_sav)[_SAV_INDEX_UDP].sin_port),
529 b3c0cd2b Rick Pratt
                                  ntohs((*_sav)[_SAV_INDEX_TCP].sin_port));
530
        if (_single_router_mode)
531
        {
532
                click_chatter("\tsingle router mode (no directory service)");
533
        }
534
        else
535
        {
536 4b971df6 Rick Pratt
                click_chatter("\tgdp directory on %s udp %d, advert timer %d usecs",
537 b3c0cd2b Rick Pratt
                                          IPAddress((*_sav)[_SAV_INDEX_DIR]
538
                                                                .sin_addr).unparse().c_str(),
539 4b971df6 Rick Pratt
                                          ntohs((*_sav)[_SAV_INDEX_DIR].sin_port),
540 3aa9a35e Rick Pratt
                                          _advert_timer);
541 b3c0cd2b Rick Pratt
        }
542 62a58ed2 Rick Pratt
543 bf8eea1e Rick Pratt
        // statically configured peer sa entries follow listen ports and dir port
544 62a58ed2 Rick Pratt
        index = _SAV_MIN_SIZE;
545 bf8eea1e Rick Pratt
546
        // parse peer config format: "{ resolve(dns) | ip }, [ port, ] ..."
547
        while (conf.size() > 0)
548 62a58ed2 Rick Pratt
        {
549 bf8eea1e Rick Pratt
                args.read_p("PEER", arg_peer_str);
550
                if (args.read_status() == 1)
551
                {
552
                        args.consume();
553
554
                preloaded_arg_peer_str:
555
556
                        arg_udp_port = -1;
557
558
                        // { resolve(dns) | ip } 
559
                        if (inet_pton(AF_INET, arg_peer_str.c_str(), arg_ip.data()) == 0)
560
                        {
561 f687a636 Rick Pratt
                                if (resolve(errh, arg_peer_str, arg_ip) < 0)
562 bf8eea1e Rick Pratt
                                {
563 f687a636 Rick Pratt
                                        return -1;
564 bf8eea1e Rick Pratt
                                }
565
                        }
566
567
                        // [ port, ]
568
                        args.read_p("PORT", arg_peer_str);
569
                        if (args.read_status() == 1)
570
                        {
571
                                args.consume();
572
                                arg_udp_port = strtol(arg_peer_str.c_str(), &end_str, 0);
573
                                if (*arg_peer_str.c_str() != '\0' && *end_str == '\0')
574
                                {
575
                                        arg_peer_str_unused = false;
576
                                }
577
                                else
578
                                {
579
                                        arg_udp_port = DEFAULT_UDP_PORT;
580
                                        arg_peer_str_unused = true;
581
                                }
582
                        }
583
                        else
584
                        {
585
                                arg_udp_port = DEFAULT_UDP_PORT;
586
                                arg_peer_str_unused = false;
587
                        }
588
589
                        // set arp_ip + arg_udp_port
590
                        (*_sav)[index].sin_family = AF_INET;
591
                        (*_sav)[index].sin_addr = arg_ip.in_addr();
592
                        (*_sav)[index].sin_port = htons(arg_udp_port);
593 f687a636 Rick Pratt
                        click_chatter("\t%s peer %s:%d\n",
594 4e81e9a6 Rick Pratt
                                                  (_no_config_mode ? "default" : "static"),
595 bf8eea1e Rick Pratt
                                                  IPAddress((*_sav)[index].sin_addr).unparse().c_str(),
596
                                                  ntohs((*_sav)[index].sin_port));
597
                        ++index; // after click_chatter has displayed index
598
                        
599
                        if (arg_peer_str_unused)
600
                        {
601
                                goto preloaded_arg_peer_str;
602
                        }
603
                }
604 67d687d6 Rick Pratt
                else
605
                {
606
                        return general_error("unrecognized configuration parameter");
607
                }
608 62a58ed2 Rick Pratt
        }
609 bf8eea1e Rick Pratt
610 62a58ed2 Rick Pratt
        if (conf.size() > 0)
611 1cd3f4ab Rick Pratt
        {
612 bf8eea1e Rick Pratt
                return general_error("extraneous parameters");
613 1cd3f4ab Rick Pratt
        }
614
615 bf8eea1e Rick Pratt
        // trim unused sa vector slots (due to non-default ports) to skip in startup
616
        (*_sav).resize(index);
617
        (*_sav).shrink_to_fit();
618
619 bd851bdd Rick Pratt
        // fd vector table
620
        _fdv_size = 512; // FIXME: no dynamic resize support at the moment, big init
621 62a58ed2 Rick Pratt
        if ((_fdv = new _fdv_t(_fdv_size, _fdv_init)) == nullptr)
622 bf8eea1e Rick Pratt
        {
623 c3585b14 Rick Pratt
                return general_error("fd vector new");
624 bf8eea1e Rick Pratt
        }
625 62a58ed2 Rick Pratt
626
        // insert _gdpr_ca in map to block spoof attempts
627
        _gdpr_ca = (gdp_name_ca_t *) _gdpr;
628 4b971df6 Rick Pratt
        gguid_dmr = dst_map.emplace(std::make_pair(*_gdpr_ca, dst_map_init));
629
        if (gguid_dmr.second == false)
630 bf8eea1e Rick Pratt
        {
631 62a58ed2 Rick Pratt
                return general_error("fd vector init");
632 bf8eea1e Rick Pratt
        }
633 bd851bdd Rick Pratt
        // fd_state remains FD_NONE for fd associated with ADDR_MINE
634 4b971df6 Rick Pratt
        gguid_dmr.first->second.addr_state = ADDR_MINE;
635 62a58ed2 Rick Pratt
636
        return 0;
637
}
638
639
int
640
GDPv4Router::initialize (ErrorHandler * /* errh */)
641
{
642
        int fd_connect;
643 e2a1b770 Rick Pratt
        WritablePacket *dp;
644
        otw_dir_t *otw_dir;
645
        gdp_pname_t _tmp_pname_1;
646 f687a636 Rick Pratt
647 62a58ed2 Rick Pratt
        // validate click configuration
648
        if ((ninputs() != 0) || (noutputs() != 0))
649
                return general_error("configured ninputs != 0 or noutputs != 0");
650
651 1cd3f4ab Rick Pratt
        // SINGLE ROUTER MODE
652
        if (_single_router_mode)
653
        {
654
                // tcp bridge only
655
                if (new_tcp_listen() < 0)
656
                        return general_error("new tcp listen failed");
657
658
                // systemd notify
659 0a4d4011 Rick Pratt
                sd_notify(false, "READY=1\n");
660 1cd3f4ab Rick Pratt
                return 0;
661
        }
662
        
663 62a58ed2 Rick Pratt
        // openssl pre-requisites
664
        SSL_library_init();
665
        SSL_load_error_strings();
666
        ERR_load_BIO_strings();
667
        OpenSSL_add_all_algorithms();
668
669
        // SSL_CTX is shared by all SSL sessions
670
        if ((_ssl_ctx = SSL_CTX_new(DTLSv1_2_method())) == NULL)
671
                return general_error("SSL_CTX_new failed");
672
673
        // SSL_CTX crypto defaults 
674
        if (!(SSL_CTX_set_cipher_list(_ssl_ctx, "AECDH-NULL-SHA")))
675
                return general_error("SSL_CTX_set_cipher_list failed");
676
        // SSL_CTX_set_ecdh_auto() must be before SSL_new() (no shared cipher error)
677
        // eNULL cipher negotiation fails unless ecdh is available via set_ecdh_auto
678
        if (!(SSL_CTX_set_ecdh_auto(_ssl_ctx, 1)))
679
                return general_error("SSL_CTX_set_ecdh_auto failed");
680
681
        if (new_udp_listen() < 0)
682
                return general_error("new udp listen failed");
683
684
        if (new_tcp_listen() < 0)
685
                return general_error("new tcp listen failed");
686
687
        // gdp directory
688
        if ((fd_connect = new_udp_connect(&(*_sav)[_SAV_INDEX_DIR],
689 007e01e0 Rick Pratt
                                                                          FD_DIRECTORY)) < 0)
690 62a58ed2 Rick Pratt
                return general_error("new connect directory failed");
691
        _fd_directory = fd_connect;
692 e2a1b770 Rick Pratt
693
        // directory p
694 cdbccb0d Rick Pratt
        dp = Packet::make(offsetof(otw_dir_t, eguid[1]));
695 e2a1b770 Rick Pratt
        if (dp == nullptr)
696
        {
697
                return general_error("directory flush packet allocation failed");
698
        }
699
        otw_dir = (otw_dir_t *) dp->data();
700
        otw_dir->ver = GDP_CHAN_PROTO_VERSION;
701
        otw_dir->id = htons(_dr_id++);
702
        otw_dir->cmd = GDP_CMD_DIR_FLUSH;
703 e7fa3577 Rick Pratt
        memcpy(otw_dir->eguid[0], _gdpr, sizeof(gdp_name_t));
704 e2a1b770 Rick Pratt
        // tx directory flush request
705
        datagram_tx(_fd_directory, dp, nullptr, 0);
706
        ccdbg(DVERB, "(%d)%s tx directory flush id 0x%x\n"
707
                  "\teguid[%s]",
708
                  _fd_directory, fd_to_state_name(_fd_directory), ntohs(otw_dir->id),
709 e7fa3577 Rick Pratt
                  gdp_printable_name(otw_dir->eguid[0], _tmp_pname_1));
710 e2a1b770 Rick Pratt
        // dp->kill() after retx below
711 62a58ed2 Rick Pratt
        
712
        for (int index = _SAV_MIN_SIZE; index < (int) (*_sav).size(); index++)
713
        {
714
                if ((fd_connect = new_udp_connect(&(*_sav)[index], FD_UDP_CONNECT)) < 0)
715 cdaf995a Rick Pratt
                        ccerr("new udp connect failed at %d", index);
716 62a58ed2 Rick Pratt
        }
717 2b5c3a2d Rick Pratt
        // track configured fds since they are recycled differently than dynamic fds
718
        _fd_last_configured = fd_connect;
719 62a58ed2 Rick Pratt
720 e2a1b770 Rick Pratt
        // retx directory flush request
721
        datagram_tx(_fd_directory, dp, nullptr, 0);
722
        ccdbg(DVERB, "(%d)%s retx directory flush id 0x%x\n"
723
                  "\teguid[%s]",
724
                  _fd_directory, fd_to_state_name(_fd_directory), ntohs(otw_dir->id),
725 e7fa3577 Rick Pratt
                  gdp_printable_name(otw_dir->eguid[0], _tmp_pname_1));
726 e2a1b770 Rick Pratt
        dp->kill();
727
        
728 ed6a6553 Rick Pratt
        // systemd notify
729 0a4d4011 Rick Pratt
        sd_notify(false, "READY=1\n");
730 62a58ed2 Rick Pratt
        return 0;
731
}
732
733
void
734 d89f3f24 Rick Pratt
GDPv4Router::cleanup (CleanupStage)
735 62a58ed2 Rick Pratt
{
736 7c97363d Rick Pratt
        WritablePacket *dp;
737
        otw_dir_t *otw_dir;
738
        gdp_pname_t _tmp_pname_1;
739 1cd3f4ab Rick Pratt
740
        // SINGLE ROUTER MODE
741 f687a636 Rick Pratt
        if (_single_router_mode || router()->initialized() == false)
742 1cd3f4ab Rick Pratt
                return;
743
744 7c97363d Rick Pratt
        // flush
745 cdbccb0d Rick Pratt
        dp = Packet::make(offsetof(otw_dir_t, eguid[1]));
746 7c97363d Rick Pratt
        if (dp == nullptr)
747
        {
748
                ccwarn("(%d)%s packet pool exhausted on %d",
749
                           _fd_directory, fd_to_state_name(_fd_directory),
750 cdbccb0d Rick Pratt
                           offsetof(otw_dir_t, eguid[1]));
751 7c97363d Rick Pratt
                return;
752
        }
753
        otw_dir = (otw_dir_t *) dp->data();
754
        otw_dir->ver = GDP_CHAN_PROTO_VERSION;
755
        otw_dir->id = htons(_dr_id++);
756
        otw_dir->cmd = GDP_CMD_DIR_FLUSH;
757 e7fa3577 Rick Pratt
        memcpy(otw_dir->eguid[0], _gdpr, sizeof(gdp_name_t));
758 7c97363d Rick Pratt
        // tx directory flush request
759
        datagram_tx(_fd_directory, dp, nullptr, 0);
760
        ccdbg(DVERB, "(%d)%s tx directory flush id 0x%x\n"
761
                  "\teguid[%s]",
762
                  _fd_directory, fd_to_state_name(_fd_directory), ntohs(otw_dir->id),
763 e7fa3577 Rick Pratt
                  gdp_printable_name(otw_dir->eguid[0], _tmp_pname_1));
764 7c97363d Rick Pratt
        // retx directory flush request
765
        datagram_tx(_fd_directory, dp, nullptr, 0);
766
        ccdbg(DVERB, "(%d)%s retx directory flush id 0x%x\n"
767
                  "\teguid[%s]",
768
                  _fd_directory, fd_to_state_name(_fd_directory), ntohs(otw_dir->id),
769 e7fa3577 Rick Pratt
                  gdp_printable_name(otw_dir->eguid[0], _tmp_pname_1));
770 7c97363d Rick Pratt
        dp->kill();
771 d89f3f24 Rick Pratt
772
        // close fds, but work from dynamic fds backwards so directory can be used
773
        for (uint16_t fd = (*_fdv).size(); fd > 0; --fd)
774
        {
775
                switch ((*_fdv)[fd].fd_state)
776
                {
777 acabfa65 Rick Pratt
                case FD_TCP_CLIENT:
778 d89f3f24 Rick Pratt
                case FD_DTLS_ACCEPT:
779
                case FD_DTLS_DO_HANDSHAKE:
780
                case FD_DTLS_CLIENT:
781
                case FD_DTLS_SERVER:
782
                        fd_recycle(fd);
783
                        break;
784
                case FD_DIRECTORY:
785
                case FD_UDP_LISTEN:
786 48ba4bd2 Rick Pratt
                case FD_UDP_CONNECT:
787 d89f3f24 Rick Pratt
                case FD_UDP_CONNECT_DUPE:
788
                case FD_TCP_LISTEN:
789
                        confirm_shutdown(fd);
790
                        confirm_close(fd);
791
                        break;
792
                case FD_NONE:
793
                default:
794
                        break;
795
                }
796
        }
797
        SSL_CTX_free(_ssl_ctx);
798
        
799 62a58ed2 Rick Pratt
}
800
801 bf8eea1e Rick Pratt
int
802 f687a636 Rick Pratt
GDPv4Router::resolve (ErrorHandler * errh, String &arg_name, IPAddress &arg_ip)
803 bf8eea1e Rick Pratt
{
804
        struct __res_state res_state;
805
        u_char buf[ARG_BUF_SIZE];
806
        ns_msg msg;
807
        ns_rr rr;
808
        int len;
809
        HEADER *hdr;
810
                
811
        res_ninit(&res_state);
812
        len = res_nquery(&res_state, arg_name.c_str(), C_IN, T_A,
813
                                         buf, ARG_BUF_SIZE);
814
        if (len < 0)
815
        {
816 f687a636 Rick Pratt
                errh->error("dns query failed on \"%s\"", arg_name.c_str());
817 bf8eea1e Rick Pratt
                return -1;
818
        }
819
        hdr = reinterpret_cast<HEADER*>(buf);
820
        switch (hdr->rcode)
821
        {
822
        case NOERROR:
823
                break;
824
        case FORMERR:
825 f687a636 Rick Pratt
                errh->error("dns format error on query of \"%s\"", arg_name.c_str());
826 bf8eea1e Rick Pratt
                return -1;
827
        case SERVFAIL:
828 f687a636 Rick Pratt
                errh->error("dns server failure on query of \"%s\"", arg_name.c_str());
829 bf8eea1e Rick Pratt
                return -1;
830
        case NXDOMAIN:
831 f687a636 Rick Pratt
                errh->error("dns name error on query of \"%s\"", arg_name.c_str());
832 bf8eea1e Rick Pratt
                return -1;
833
        case NOTIMP:
834 f687a636 Rick Pratt
                errh->error("dns not implemented error on query of \"%s\"",
835
                                        arg_name.c_str());
836 bf8eea1e Rick Pratt
                return -1;
837
        case REFUSED:
838 f687a636 Rick Pratt
                errh->error("dns refused error on query of \"%s\"", arg_name.c_str());
839 bf8eea1e Rick Pratt
                return -1;
840
        default:
841 f687a636 Rick Pratt
                errh->error("dns unknown error on query of \"%s\"", arg_name.c_str());
842 bf8eea1e Rick Pratt
                return -1;
843
        }
844
        if (ns_initparse(buf, len, &msg) < 0)
845
        {
846 f687a636 Rick Pratt
                errh->error("dns parsing error on query of \"%s\"", arg_name.c_str());
847 bf8eea1e Rick Pratt
                return -1;
848
        }
849
        len = ns_msg_count(msg, ns_s_an);
850
        if (len == 0)
851
        {
852 f687a636 Rick Pratt
                errh->error("dns zero messages on query of \"%s\"", arg_name.c_str());
853 bf8eea1e Rick Pratt
                return -1;
854
        }
855
        for (int i = 0; i < len; ++i)
856
        {
857
                ns_parserr(&msg, ns_s_an, i, &rr);
858
                if (ns_rr_type(rr) == T_A)
859
                {
860
                        arg_ip = ntohl(ns_get32(ns_rr_rdata(rr)));
861
                        // for now, automatic discovery always uses the first IP
862
                        break;
863
                }
864
        }
865
        res_nclose(&res_state);
866
        return 0;
867
}
868
869 62a58ed2 Rick Pratt
void
870
GDPv4Router::selected (int fd, int mask)
871
{
872 b9253176 Rick Pratt
        ccdbg(DVVERB, "\n(%d)%s %c%c", fd, fd_to_state_name(fd),
873
                    mask & SELECT_READ ? 'R' : '-', mask & SELECT_WRITE ? 'W' : '-');
874 62a58ed2 Rick Pratt
875
        if (mask & SELECT_READ)
876
        {
877
                switch ((*_fdv)[fd].fd_state)
878
                {
879
880
                case FD_DIRECTORY:
881
                {
882
                        directory_rx(fd);
883
                }
884
                break;
885
886 bd851bdd Rick Pratt
                case FD_UDP_LISTEN:
887 62a58ed2 Rick Pratt
                {
888 bd851bdd Rick Pratt
                        udp_listen_rx(fd);
889 62a58ed2 Rick Pratt
                }
890
                break;
891
                
892 bd851bdd Rick Pratt
                case FD_UDP_CONNECT:
893 62a58ed2 Rick Pratt
                {
894 bd851bdd Rick Pratt
                        udp_connect_rx(fd);
895 62a58ed2 Rick Pratt
                }
896
                break;
897
                
898
                case FD_DTLS_ACCEPT:
899
                {
900
                        ssl_accept(fd);
901
                }
902
                break;
903
904
                case FD_DTLS_DO_HANDSHAKE:
905
                {
906
                        ssl_handshake(fd);
907
                }
908
                break;
909
910 bd851bdd Rick Pratt
                case FD_TCP_LISTEN:
911 62a58ed2 Rick Pratt
                {
912 bd851bdd Rick Pratt
                        new_tcp_connect(fd);
913 62a58ed2 Rick Pratt
                }
914
                break;
915 bd851bdd Rick Pratt
916 b9253176 Rick Pratt
                case FD_DTLS_CLIENT:
917
                case FD_DTLS_SERVER:
918 bd851bdd Rick Pratt
                {
919 b9253176 Rick Pratt
                        // wake up fd rx task
920 da7bcbcb Rick Pratt
                        avow((*_fdv)[fd].rx_task != nullptr);
921 b9253176 Rick Pratt
                        (*_fdv)[fd].rx_task->reschedule();
922
                        // router fd is always SELECT_READ (add/remove performs poorly)
923 bd851bdd Rick Pratt
                }
924
                break;
925 acabfa65 Rick Pratt
                
926
                case FD_TCP_CLIENT:
927
                {
928
                         avow((*_fdv)[fd].rx_task != nullptr);
929
930
                        ccdbg(DVERB, "\n(%d)%s selected throttle %s size %d shared %s",
931
                                  fd, fd_to_state_name(fd),
932
                                  (*_fdv)[fd].rx_throttled ? "true" : "false",
933
                                  (*_fdv)[fd].zlplist.size(),
934
                                  ((*_fdv)[fd].zlplist.begin() != (*_fdv)[fd].zlplist.end() &&
935
                                   (*(*_fdv)[fd].zlplist.begin())->shared() ?
936
                                   "true" : "false"));
937
938
                        // trim any unshared zlps from zlplist front
939
                        while ((*_fdv)[fd].zlplist.size() > 0 &&
940
                                   (*(*_fdv)[fd].zlplist.begin())->shared() == false)
941
                        {
942
                                (*(*_fdv)[fd].zlplist.begin())->kill();
943
                                (*_fdv)[fd].zlplist.erase((*_fdv)[fd].zlplist.begin());
944
                        }
945
946
                        // update rx throttled state
947
                        if ((*_fdv)[fd].rx_throttled &&
948
                                (*_fdv)[fd].zlplist.size() <= TCP_RXP_PDUS_CLR)
949
                        {
950 c3585b14 Rick Pratt
                                ccdbg(DPDU, "(%d)%s selected unthrottled (%d)",
951 acabfa65 Rick Pratt
                                           fd, fd_to_state_name(fd),
952
                                           (*_fdv)[fd].zlplist.size());
953
                                add_select(fd, SELECT_READ);
954
                                (*_fdv)[fd].rx_throttled = false;
955
                        }
956
957
                         // wake up fd rx task
958
                        (*_fdv)[fd].rx_task->reschedule();
959
                }
960
                break;
961 bd851bdd Rick Pratt
962
                case FD_NONE:
963
                case FD_UDP_CONNECT_DUPE:
964 62a58ed2 Rick Pratt
                default:
965
                {
966 bd851bdd Rick Pratt
                        ccerr("(%d)%s unexpected select (%d)",
967
                                  fd, fd_to_state_name(fd), mask);
968 da7bcbcb Rick Pratt
                        aver(0);
969 62a58ed2 Rick Pratt
                }
970
                break;
971
                
972 bd851bdd Rick Pratt
                } // switch
973 62a58ed2 Rick Pratt
        }
974
                
975
        if (mask & SELECT_WRITE)
976
        {
977 bd851bdd Rick Pratt
                switch ((*_fdv)[fd].fd_state)
978
                {
979 62a58ed2 Rick Pratt
980 bd851bdd Rick Pratt
                case FD_DTLS_CLIENT:
981
                case FD_DTLS_SERVER:
982 acabfa65 Rick Pratt
                case FD_TCP_CLIENT:
983 bd851bdd Rick Pratt
                {
984
                        // wake up fd tx task
985 da7bcbcb Rick Pratt
                        avow((*_fdv)[fd].tx_task != nullptr);
986 bd851bdd Rick Pratt
                        (*_fdv)[fd].tx_task->reschedule();
987 7c97363d Rick Pratt
                        remove_select(fd, SELECT_WRITE);
988 bd851bdd Rick Pratt
                }
989
                break;
990
991
                case FD_NONE:
992
                case FD_DIRECTORY:
993
                case FD_UDP_LISTEN:
994
                case FD_UDP_CONNECT:
995
                case FD_UDP_CONNECT_DUPE:
996
                case FD_DTLS_ACCEPT:
997
                case FD_DTLS_DO_HANDSHAKE:
998
                case FD_TCP_LISTEN:
999
                {
1000
                        ccerr("(%d)%s unexpected select (%d)",
1001
                                  fd, fd_to_state_name(fd), mask);
1002 da7bcbcb Rick Pratt
                        aver(0);
1003 bd851bdd Rick Pratt
                }
1004
                break;
1005
1006
                } // switch
1007
        }
1008 4ded8992 Eric Allman
1009
        ccdbg(DVVERB, "\n>>> (%d)%s %c%c", fd, fd_to_state_name(fd),
1010
                  mask & SELECT_READ ? 'R' : '-', mask & SELECT_WRITE ? 'W' : '-');
1011 62a58ed2 Rick Pratt
}
1012
1013
int
1014
GDPv4Router::general_error (const char *event)
1015
{
1016 cdaf995a Rick Pratt
        ccerr("%s", event);
1017 62a58ed2 Rick Pratt
        return -1;
1018
}
1019
1020
uint16_t
1021
GDPv4Router::generate_sequence (void)
1022
{
1023
        uint16_t new_seq;
1024
1025 68852766 Rick Pratt
        // frequently used operation, _fd_dev_urandom remains open for quick access
1026 62a58ed2 Rick Pratt
        if (read(_fd_dev_urandom, &new_seq, sizeof(new_seq)) != 2)
1027 bd851bdd Rick Pratt
        {
1028 62a58ed2 Rick Pratt
                general_error("/dev/urandom");
1029 bd851bdd Rick Pratt
        }
1030 2b36755d Rick Pratt
        return (new_seq & SEQ_MASK);
1031 62a58ed2 Rick Pratt
}
1032
1033
int
1034
GDPv4Router::new_udp_listen (void)
1035
{
1036
        int nl_fd;
1037
        int on = 1;
1038
        //int pmtudisc_do = IP_PMTUDISC_DO;
1039
1040
        if (_fd_udp_listen != -1)
1041
        {
1042 cdaf995a Rick Pratt
                ccerr("new udp listen fd already exists");
1043 62a58ed2 Rick Pratt
                return -1;
1044
        }
1045
        
1046
        if ((nl_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1047
        {
1048 cdaf995a Rick Pratt
                ccerr("new udp listen socket");
1049 62a58ed2 Rick Pratt
                return -1;
1050
        }
1051
1052 bd851bdd Rick Pratt
        if (nl_fd >= _fdv_size || (*_fdv)[nl_fd].fd_state != FD_NONE)
1053 62a58ed2 Rick Pratt
        {
1054 cdaf995a Rick Pratt
                ccerr("new udp listen fd (%d) range or duplicate", nl_fd);
1055 62a58ed2 Rick Pratt
                goto close_fd;
1056
        }
1057
1058
        fcntl(nl_fd, F_SETFL, O_NONBLOCK);
1059
        fcntl(nl_fd, F_SETFD, FD_CLOEXEC);
1060
        setsockopt(nl_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
1061
        //setsockopt(nl_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtudisc_do, sizeof(int));
1062
1063
        if (bind(nl_fd, (struct sockaddr *) &(*_sav)[_SAV_INDEX_UDP],
1064
                         sizeof((*_sav)[_SAV_INDEX_UDP])) < 0)
1065
        {
1066 cdaf995a Rick Pratt
                ccerr("new udp listen (%d) bind (%d)", nl_fd, errno);
1067 62a58ed2 Rick Pratt
                goto close_fd;
1068
        }
1069
1070
        (*_fdv)[nl_fd].fd_state = FD_UDP_LISTEN;
1071
        _fd_udp_listen = nl_fd;
1072
        add_select(nl_fd, SELECT_READ);
1073
1074 4ded8992 Eric Allman
        ccdbg(DINFO, "(%d)%s new udp listen", nl_fd, fd_to_state_name(nl_fd));
1075 62a58ed2 Rick Pratt
        
1076
        return nl_fd;
1077
1078 2b36755d Rick Pratt
close_fd:
1079 62a58ed2 Rick Pratt
1080 684dd677 Rick Pratt
        confirm_close(nl_fd);
1081 62a58ed2 Rick Pratt
        return -1;
1082
}
1083
1084
int
1085
GDPv4Router::new_tcp_listen (void)
1086
{
1087
        int nl_fd;
1088
        int on = 1;
1089
        //int pmtudisc_do = IP_PMTUDISC_DO;
1090
 
1091
        if (_fd_tcp_listen != -1)
1092
        {
1093 cdaf995a Rick Pratt
                ccerr("new tcp listen fd already exists");
1094 62a58ed2 Rick Pratt
                return -1;
1095
        }
1096
        
1097
        if ((nl_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
1098
        {
1099 cdaf995a Rick Pratt
                ccerr("new tcp listen socket");
1100 62a58ed2 Rick Pratt
                return -1;
1101
        }
1102
1103
        fcntl(nl_fd, F_SETFL, O_NONBLOCK);
1104
        fcntl(nl_fd, F_SETFD, FD_CLOEXEC);
1105
        setsockopt(nl_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
1106
        //setsockopt(nl_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtudisc_do, sizeof(int));
1107
        
1108
        if (bind(nl_fd, (struct sockaddr *) &(*_sav)[_SAV_INDEX_TCP],
1109
                         sizeof((*_sav)[_SAV_INDEX_TCP])) < 0)
1110
        {
1111 cdaf995a Rick Pratt
                ccerr("new tcp listen (%d) bind", nl_fd);
1112 62a58ed2 Rick Pratt
                goto close_fd;
1113
        }
1114
1115
        if (listen(nl_fd, 5) < 0)
1116
        {
1117 cdaf995a Rick Pratt
                ccerr("new tcp listen (%d) error %d", nl_fd, errno);
1118 62a58ed2 Rick Pratt
                goto close_fd;
1119
        }
1120
1121
        (*_fdv)[nl_fd].fd_state = FD_TCP_LISTEN;
1122
        _fd_tcp_listen = nl_fd;
1123
        add_select(nl_fd, SELECT_READ);
1124
1125 4ded8992 Eric Allman
        ccdbg(DINFO, "(%d)%s new tcp listen", nl_fd, fd_to_state_name(nl_fd));
1126 62a58ed2 Rick Pratt
        
1127
        return nl_fd;
1128
1129 2b36755d Rick Pratt
close_fd:
1130 62a58ed2 Rick Pratt
1131 684dd677 Rick Pratt
        confirm_close(nl_fd);
1132 62a58ed2 Rick Pratt
        return -1;
1133
}
1134
1135
int
1136
GDPv4Router::new_udp_connect (struct sockaddr_in *nc_sa_in, _FD_STATE fd_state)
1137
{
1138
        int nc_fd;
1139
        int on = 1;
1140
        //int pmtudisc_do = IP_PMTUDISC_DO;
1141
 
1142 da7bcbcb Rick Pratt
        avow(nc_sa_in != nullptr);
1143 62a58ed2 Rick Pratt
        
1144
        if (nc_sa_in->sin_addr == IPAddress("127.0.0.1") && nc_sa_in->sin_port == 0)
1145
                return -1;
1146
        
1147
        if ((nc_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1148
        {
1149 cdaf995a Rick Pratt
                ccerr("new udp connect socket");
1150 62a58ed2 Rick Pratt
                return -1;
1151
        }
1152
1153 bd851bdd Rick Pratt
        if (nc_fd >= _fdv_size || (*_fdv)[nc_fd].fd_state != FD_NONE)
1154 62a58ed2 Rick Pratt
        {
1155 cdaf995a Rick Pratt
                ccerr("new udp connect (%d) range or duplicate", nc_fd);
1156 62a58ed2 Rick Pratt
                goto close_fd;
1157
        }
1158
1159
        fcntl(nc_fd, F_SETFL, O_NONBLOCK);
1160
        fcntl(nc_fd, F_SETFD, FD_CLOEXEC);
1161
        setsockopt(nc_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
1162
        //setsockopt(nc_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtudisc_do, sizeof(int));
1163
        
1164
        if (fd_state == FD_UDP_LISTEN)
1165
        {
1166
                if (bind(nc_fd, (struct sockaddr *) &(*_sav)[_SAV_INDEX_UDP],
1167
                                 sizeof((*_sav)[_SAV_INDEX_UDP])) < 0)
1168
                {
1169 cdaf995a Rick Pratt
                        ccerr("new udp connect (%d) bind", nc_fd);
1170 62a58ed2 Rick Pratt
                        goto close_fd;
1171
                }
1172
        }
1173
1174
        if (connect(nc_fd, (struct sockaddr *) nc_sa_in, sizeof(*nc_sa_in)) < 0)
1175
        {
1176 cdaf995a Rick Pratt
                ccerr("new udp connect (%d) connect", nc_fd);
1177 62a58ed2 Rick Pratt
                goto close_fd;
1178
        }
1179
1180
        (*_fdv)[nc_fd].fd_state = fd_state;
1181
1182
        (*_fdv)[nc_fd].rxp = nullptr;
1183
        
1184 b9253176 Rick Pratt
        // tasks cannot self-delete, so next fd user must delete unscheduled tasks
1185
        if ((*_fdv)[nc_fd].rx_task != nullptr)
1186
        {
1187
                delete (*_fdv)[nc_fd].rx_task;
1188
                (*_fdv)[nc_fd].rx_task = nullptr;
1189
        }
1190
        if ((*_fdv)[nc_fd].tx_task != nullptr)
1191
        {
1192
                delete (*_fdv)[nc_fd].tx_task;
1193
                (*_fdv)[nc_fd].tx_task = nullptr;                
1194
        }
1195
        
1196 62a58ed2 Rick Pratt
        if (fd_state != FD_DIRECTORY)
1197
        {
1198 987af967 Rick Pratt
                try
1199
                {
1200 b9253176 Rick Pratt
                        (*_fdv)[nc_fd].rx_task =
1201
                                new Task(static_dtls_rx, (void *)(intptr_t)nc_fd);
1202 987af967 Rick Pratt
                        (*_fdv)[nc_fd].tx_task =
1203
                                new Task(static_dtls_tx, (void *)(intptr_t)nc_fd);
1204
                }
1205
                catch (std::bad_alloc)
1206
                {
1207
                        ccerr("new udp connect (%d) tx task", nc_fd);
1208 b9253176 Rick Pratt
                        delete (*_fdv)[nc_fd].rx_task;
1209
                        (*_fdv)[nc_fd].rx_task = nullptr;
1210 987af967 Rick Pratt
                        goto close_fd;
1211
                }
1212 b9253176 Rick Pratt
                (*_fdv)[nc_fd].rx_task->initialize(this, false);
1213 987af967 Rick Pratt
                (*_fdv)[nc_fd].tx_task->initialize(this, false);
1214 62a58ed2 Rick Pratt
        }
1215
1216
        if (fd_state == FD_UDP_CONNECT)
1217
        {
1218 da7bcbcb Rick Pratt
                avow((*_fdv)[nc_fd].retx_timer == nullptr);
1219 bd851bdd Rick Pratt
                try
1220
                {
1221
                        (*_fdv)[nc_fd].retx_timer = new Timer(static_udp_connect_timer,
1222
                                                                                                  (void *)(intptr_t)nc_fd);
1223
                }
1224
                catch (std::bad_alloc)
1225 62a58ed2 Rick Pratt
                {
1226 bd851bdd Rick Pratt
                        ccerr("new udp connect (%d) retx timer", nc_fd);
1227
                        delete (*_fdv)[nc_fd].tx_task;
1228
                        (*_fdv)[nc_fd].tx_task = nullptr;
1229
                        goto close_fd;
1230 62a58ed2 Rick Pratt
                }
1231 bd851bdd Rick Pratt
                (*_fdv)[nc_fd].retx_timer->initialize(this, true);
1232
                (*_fdv)[nc_fd].retx_timer->schedule_after(FD_UDP_CONNECT_NOW_TS_DELTA);
1233 62a58ed2 Rick Pratt
        }
1234
1235 bd851bdd Rick Pratt
        add_select(nc_fd, SELECT_READ);
1236
1237 4ded8992 Eric Allman
        ccdbg(DINFO, "(%d)%s new udp connect %s:%d",
1238 cdaf995a Rick Pratt
                   nc_fd, fd_to_state_name(nc_fd),
1239
                   IPAddress(nc_sa_in->sin_addr).unparse().c_str(),
1240
                   ntohs(nc_sa_in->sin_port));
1241 62a58ed2 Rick Pratt
        
1242
        return nc_fd;
1243
1244 2b36755d Rick Pratt
close_fd:
1245 62a58ed2 Rick Pratt
1246 684dd677 Rick Pratt
        confirm_close(nc_fd);
1247 62a58ed2 Rick Pratt
        return -1;
1248
}
1249
1250
void
1251
GDPv4Router::new_tcp_connect (int fd)
1252
{
1253
        struct sockaddr_in sa_in;
1254
        socklen_t sa_in_len = sizeof(sa_in);
1255
        int nc_fd;
1256
1257
        if (fd != _fd_tcp_listen)
1258
        {
1259 cdaf995a Rick Pratt
                ccerr("new tcp connect (%d) on unexpected fd", fd);
1260 62a58ed2 Rick Pratt
                return;
1261
        }
1262
1263
        nc_fd = accept(_fd_tcp_listen, (struct sockaddr *) &sa_in, &sa_in_len);
1264
        if (nc_fd < 0)
1265
        {
1266 cdaf995a Rick Pratt
                ccerr("new_tcp_connect accept");
1267 62a58ed2 Rick Pratt
                return;
1268
        }
1269
        
1270 bd851bdd Rick Pratt
        if (nc_fd >= _fdv_size || (*_fdv)[nc_fd].fd_state != FD_NONE)
1271 62a58ed2 Rick Pratt
        {
1272 cdaf995a Rick Pratt
                ccerr("new tcp connect (%d) range or duplicate", nc_fd);
1273 684dd677 Rick Pratt
                confirm_close(nc_fd);
1274 62a58ed2 Rick Pratt
                return;
1275
        }
1276
        
1277
        fcntl(nc_fd, F_SETFL, O_NONBLOCK);
1278
        fcntl(nc_fd, F_SETFD, FD_CLOEXEC);
1279 34eff361 Eric Allman
        int enable = 1;
1280
        setsockopt(nc_fd, IPPROTO_TCP, TCP_NODELAY, (void *) &enable, sizeof enable);
1281 62a58ed2 Rick Pratt
1282 acabfa65 Rick Pratt
        (*_fdv)[nc_fd].fd_state = FD_TCP_CLIENT;
1283 62a58ed2 Rick Pratt
1284
        (*_fdv)[nc_fd].rxp = Packet::make(TCR_RXP_HDRM, nullptr, TCR_RXP_SIZE, 0);
1285
        if ((*_fdv)[nc_fd].rxp == nullptr)
1286
        {
1287 cdaf995a Rick Pratt
                ccerr("new tcp connect (%d) no rxp", nc_fd);
1288 684dd677 Rick Pratt
                confirm_close(nc_fd);
1289 62a58ed2 Rick Pratt
                return;
1290
        }
1291 b9253176 Rick Pratt
        SET_PTYPE_ANNO((*_fdv)[nc_fd].rxp, PTYPE_GDP_PDU);
1292 62a58ed2 Rick Pratt
        ccdbg(DVVERB, "(%d)%s make new rxp %p",
1293
                  fd, fd_to_state_name(fd), (*_fdv)[nc_fd].rxp);
1294
1295 bd851bdd Rick Pratt
        // track p rx fd
1296 62a58ed2 Rick Pratt
        SET_RXFD_ANNO((*_fdv)[nc_fd].rxp, nc_fd);
1297
1298
        (*_fdv)[nc_fd].rxp_want_len = 0;
1299
1300 b9253176 Rick Pratt
        // tasks cannot self-delete, so next fd user must delete unscheduled tasks
1301
        if ((*_fdv)[nc_fd].rx_task != nullptr)
1302
        {
1303
                delete (*_fdv)[nc_fd].rx_task;
1304
                (*_fdv)[nc_fd].rx_task = nullptr;
1305
        }
1306
        if ((*_fdv)[nc_fd].tx_task != nullptr)
1307
        {
1308
                delete (*_fdv)[nc_fd].tx_task;
1309
                (*_fdv)[nc_fd].tx_task = nullptr;                
1310
        }
1311 62a58ed2 Rick Pratt
        
1312 987af967 Rick Pratt
        try
1313
        {
1314 b9253176 Rick Pratt
                (*_fdv)[nc_fd].rx_task =
1315
                        new Task(static_tcp_client_rx, (void *)(intptr_t)nc_fd);
1316 987af967 Rick Pratt
                (*_fdv)[nc_fd].tx_task =
1317
                        new Task(static_tcp_client_tx, (void *)(intptr_t)nc_fd);
1318
        }
1319
        catch (std::bad_alloc)
1320
        {
1321
                ccerr("new tcp connect (%d) tx task", nc_fd);
1322
                (*_fdv)[nc_fd].rxp->kill();
1323
                (*_fdv)[nc_fd].rxp = nullptr;
1324 b9253176 Rick Pratt
                delete (*_fdv)[nc_fd].rx_task;
1325
                (*_fdv)[nc_fd].rx_task = nullptr;
1326 684dd677 Rick Pratt
                confirm_close(nc_fd);
1327 987af967 Rick Pratt
                return;
1328
        }
1329 b9253176 Rick Pratt
        (*_fdv)[nc_fd].rx_task->initialize(this, false);
1330 987af967 Rick Pratt
        (*_fdv)[nc_fd].tx_task->initialize(this, false);
1331 62a58ed2 Rick Pratt
        
1332 bd851bdd Rick Pratt
        add_select(nc_fd, SELECT_READ);
1333
1334 4ded8992 Eric Allman
        ccdbg(DINFO, "(%d)%s new tcp connect %s:%d",
1335 cdaf995a Rick Pratt
                   nc_fd, fd_to_state_name(nc_fd),
1336
                   IPAddress(sa_in.sin_addr).unparse().c_str(),
1337
                   ntohs(sa_in.sin_port));
1338 62a58ed2 Rick Pratt
}
1339
1340
void
1341
GDPv4Router::datagram_tx (int fd, WritablePacket *p,
1342 007e01e0 Rick Pratt
                                                  struct sockaddr_in *sa_in, size_t sa_in_size)
1343 62a58ed2 Rick Pratt
{
1344
        ssize_t send_len;
1345
        
1346
        if (sa_in_size == 0)
1347
        {
1348
                send_len = send(fd, p->data(), p->length(), 0);
1349
                ccdbg(DVERB, "(%d)%s dgram tx len %d",
1350
                          fd, fd_to_state_name(fd), send_len);
1351
        }
1352
        else
1353
        {
1354
                send_len = sendto(fd, p->data(), p->length(), 0,
1355
                                                  (struct sockaddr *) sa_in, sa_in_size);
1356
                ccdbg(DVERB, "(%d)%s dgram tx len %d to %s:%d",
1357
                          fd, fd_to_state_name(fd), send_len,
1358
                          IPAddress(sa_in->sin_addr).unparse().c_str(),
1359
                          ntohs(sa_in->sin_port));
1360
        }
1361
        // send/sendto error check
1362
        if (send_len != p->length())
1363
        {
1364
                if (send_len < 0)
1365
                {
1366
                        switch (errno)
1367
                        {
1368
                        case EINTR:
1369
                        case EMSGSIZE:
1370
                        case ENOBUFS:
1371
                        case ENOMEM:
1372 bd851bdd Rick Pratt
                        case ECONNREFUSED:
1373 cdaf995a Rick Pratt
                                ccwarn("(%d)%s datagram_tx p %p len %d errno %d",
1374
                                           fd, fd_to_state_name(fd), p, send_len, errno);
1375 62a58ed2 Rick Pratt
                                break;
1376 bd851bdd Rick Pratt
                        case EAGAIN: // connection oriented datagram socket, not expected
1377 62a58ed2 Rick Pratt
                        default:
1378 d89f3f24 Rick Pratt
                                ccerr("(%d)%s datagram_tx p %p len %d errno %d",
1379 62a58ed2 Rick Pratt
                                          fd, fd_to_state_name(fd), p, send_len, errno);
1380
                                break;
1381
                        }
1382
                }
1383
                else
1384
                {
1385 cdaf995a Rick Pratt
                        ccerr("(%d)%s datagram_tx p %p len %d short %d",
1386 62a58ed2 Rick Pratt
                                  fd, fd_to_state_name(fd), p, p->length(), send_len);
1387 da7bcbcb Rick Pratt
                        aver(0);
1388 62a58ed2 Rick Pratt
                }
1389
        }
1390
}
1391
1392
void
1393
GDPv4Router::udp_listen_rx (int fd)
1394
{
1395
        WritablePacket *p;
1396
        ssize_t rx_len;
1397
        struct sockaddr_in from_sa_in;
1398
        socklen_t from_len = sizeof(from_sa_in);
1399
        gdp_name_ca_t *src;
1400
        gdp_pname_t _tmp_pname_1;
1401
1402
        p = Packet::make(GDP_CMD_ROUTER_NAME_MAX_SZ);
1403 bd851bdd Rick Pratt
        if (p == nullptr)
1404
        {
1405
                ccwarn("(%d)%s packet pool exhausted on %d",
1406
                           fd, fd_to_state_name(fd), GDP_CMD_ROUTER_NAME_MAX_SZ);
1407
                return;
1408
        }
1409 62a58ed2 Rick Pratt
1410 bd851bdd Rick Pratt
        // MSG_TRUNC discards excess but rx_len will reflect full length
1411 62a58ed2 Rick Pratt
        rx_len = recvfrom(fd, p->data(), p->length(), MSG_TRUNC,
1412
                                          (struct sockaddr *)&from_sa_in, &from_len);
1413
        if (rx_len <= 0 || rx_len > p->length())
1414
        {
1415 bd851bdd Rick Pratt
                ccdbg(DVVERB, "(%d)%s recvfrom len %d p len %d unexpected, drop",
1416 62a58ed2 Rick Pratt
                          fd, fd_to_state_name(fd), rx_len, p->length());
1417
                p->kill();
1418
                return;
1419
        }
1420
1421
        otw_hlo_t *otw_hlo = (otw_hlo_t *)p->data();
1422
        
1423
        if (otw_hlo->ver != GDP_CHAN_PROTO_VERSION)
1424
        {
1425 bd851bdd Rick Pratt
                ccdbg(DVVERB, "(%d)%s rx unknown version 0x%x",
1426 62a58ed2 Rick Pratt
                          fd, fd_to_state_name(fd), otw_hlo->ver);
1427
                p->kill();
1428
                return;
1429
        }
1430
1431 bd851bdd Rick Pratt
        ccdbg(DVERB, "(%d)%s recvfrom %s:%d len %d p %p len %d\n"
1432
                  "\tsrc[%s]",
1433 62a58ed2 Rick Pratt
                  fd, fd_to_state_name(fd),
1434
                  IPAddress(from_sa_in.sin_addr).unparse().c_str(),
1435 bd851bdd Rick Pratt
                  ntohs(from_sa_in.sin_port), rx_len, p, p->length(),
1436 62a58ed2 Rick Pratt
                  gdp_printable_name(otw_hlo->src, _tmp_pname_1));
1437
1438 bd851bdd Rick Pratt
        // p->kill() called at function end
1439 62a58ed2 Rick Pratt
        switch (otw_hlo->cmd)
1440
        {
1441
1442
        case GDP_CMD_ROUTER_NAME_REQ:
1443
        {
1444
                if (rx_len < (ssize_t) GDP_CMD_ROUTER_NAME_REQ_SZ)
1445
                {
1446 bd851bdd Rick Pratt
                        ccdbg(DVVERB, "(%d)%s rx name req short len %d, drop",
1447
                                  fd, fd_to_state_name(fd), rx_len);
1448 62a58ed2 Rick Pratt
                        break;
1449
                }
1450
1451
                src = (gdp_name_ca_t *) otw_hlo->src;
1452
                
1453 c8522a6f Rick Pratt
                if (dst_map.count(*src))
1454 cdaf995a Rick Pratt
                {
1455 bd851bdd Rick Pratt
                        ccdbg(DVERB, "(%d)%s map entry exists\n"
1456
                                  "\tsrc[%s]",
1457 62a58ed2 Rick Pratt
                                  fd, fd_to_state_name(fd),
1458
                                  gdp_printable_name(otw_hlo->src, _tmp_pname_1));
1459 cdaf995a Rick Pratt
                }
1460 62a58ed2 Rick Pratt
                else
1461 cdaf995a Rick Pratt
                {
1462 bd851bdd Rick Pratt
                        ccdbg(DVERB, "(%d)%s map entry not found\n"
1463
                                  "\tsrc[%s]",
1464 62a58ed2 Rick Pratt
                                  fd, fd_to_state_name(fd),
1465
                                  gdp_printable_name(otw_hlo->src, _tmp_pname_1));
1466 cdaf995a Rick Pratt
                }
1467 62a58ed2 Rick Pratt
                                
1468 d6b275d1 Rick Pratt
                // FD_UDP_CONNECT hello reply
1469 62a58ed2 Rick Pratt
                otw_hlo->cmd = GDP_CMD_ROUTER_NAME_REP;
1470
1471
                // move src to dst, fill src
1472
                std::copy(otw_hlo->src, otw_hlo->src + sizeof(gdp_name_ca_t),
1473
                                  otw_hlo->dst);
1474
                std::copy(_gdpr, _gdpr + sizeof(gdp_name_ca_t),
1475
                                  otw_hlo->src);
1476
                datagram_tx(fd, p, &from_sa_in, sizeof(from_sa_in));
1477
        }
1478
        break;
1479
                
1480
        case GDP_CMD_ROUTER_NAME_ACK:
1481
        {
1482
                int nc_fd;
1483
                gdp_name_ca_t *cguid_ca;
1484 2c4eab43 Rick Pratt
                dst_map_it_t cguid_dmi;
1485 62a58ed2 Rick Pratt
                gdp_pname_t _tmp_pname_1;
1486
1487
                if (rx_len < (ssize_t) GDP_CMD_ROUTER_NAME_ACK_SZ)
1488
                {
1489 bd851bdd Rick Pratt
                        ccdbg(DVVERB, "(%d)%s rx name ack len %d short, drop",
1490 62a58ed2 Rick Pratt
                                  fd, fd_to_state_name(fd), rx_len);
1491
                        break;
1492
                }
1493
1494
                // validate dst
1495
                if (memcmp(_gdpr, otw_hlo->dst, sizeof(gdp_name_t)) != 0)
1496
                {
1497
                        ccdbg(DVVERB, "(%d)%s rx name ack invalid dst",
1498
                                  fd, fd_to_state_name(fd));
1499
                        break;
1500
                }
1501
1502 bd851bdd Rick Pratt
                ccdbg(DVERB, "(%d)%s rx name ack len %d",
1503
                          fd, fd_to_state_name(fd), rx_len);
1504
                
1505 d6b275d1 Rick Pratt
                // if new peer, then map and configure
1506 62a58ed2 Rick Pratt
                cguid_ca = (gdp_name_ca_t *) otw_hlo->src;
1507 2c4eab43 Rick Pratt
                cguid_dmi = dst_map.lower_bound(*cguid_ca);
1508
                if (cguid_dmi == dst_map.end() ||
1509
                        dst_map.key_comp()(*cguid_ca, cguid_dmi->first))
1510 62a58ed2 Rick Pratt
                {
1511 2c4eab43 Rick Pratt
                        cguid_dmi =
1512
                                dst_map.emplace_hint(cguid_dmi,
1513 c8522a6f Rick Pratt
                                                                         dst_map_t::value_type(*cguid_ca,
1514
                                                                                                                   dst_map_init));
1515 62a58ed2 Rick Pratt
                }
1516
                else
1517
                {
1518 d6b275d1 Rick Pratt
                        // client src may not be unique, but gdpr src must be unique
1519 bd851bdd Rick Pratt
                        ccdbg(DVERB, "(%d)%s rx name ack but already in map\n"
1520
                                  "\t[%s]",
1521
                                  fd, fd_to_state_name(fd),
1522
                                  gdp_printable_name(otw_hlo->src, _tmp_pname_1));
1523 62a58ed2 Rick Pratt
                        break;
1524
                }
1525 bd851bdd Rick Pratt
                ccdbg(DVERB, "(%d)%s rx name ack map insert\n"
1526
                          "\t[%s]",
1527 62a58ed2 Rick Pratt
                          fd, fd_to_state_name(fd),
1528
                          gdp_printable_name(otw_hlo->src, _tmp_pname_1));
1529
1530
                // move connection off listen socket...
1531
                if ((nc_fd = new_udp_connect(&from_sa_in, FD_UDP_LISTEN)) < 0)
1532
                {
1533 cdaf995a Rick Pratt
                        ccerr("(%d)%s name ack new_udp_connect failed",
1534 62a58ed2 Rick Pratt
                                  fd, fd_to_state_name(fd));
1535 acabfa65 Rick Pratt
                        dst_map_recycle(fd, cguid_dmi);
1536 62a58ed2 Rick Pratt
                        break;
1537
                }
1538
1539 bd851bdd Rick Pratt
                // udp listen has moved the connection to nc_fd
1540 2c4eab43 Rick Pratt
                cguid_dmi->second.fd = nc_fd;
1541 bd851bdd Rick Pratt
                
1542
                // no udp listen fd retx timer to delete
1543 da7bcbcb Rick Pratt
                avow((*_fdv)[nc_fd].retx_timer == nullptr);
1544 bd851bdd Rick Pratt
1545 4b971df6 Rick Pratt
                // directly connected gdp router
1546 2c4eab43 Rick Pratt
                cguid_dmi->second.addr_state = ADDR_GDPR;
1547
                avow(cguid_dmi->second.map_timer_dmip == nullptr);
1548
                avow(cguid_dmi->second.map_timer == nullptr);
1549 bd851bdd Rick Pratt
                try {
1550 2c4eab43 Rick Pratt
                        cguid_dmi->second.map_timer_dmip = new dst_map_it_t(cguid_dmi);
1551
                        cguid_dmi->second.map_timer =
1552 79f90570 Rick Pratt
                                new Timer(static_addr_gdpr_connect_timer,
1553 2c4eab43 Rick Pratt
                                                  cguid_dmi->second.map_timer_dmip);
1554 bd851bdd Rick Pratt
                }
1555
                catch (std::bad_alloc)
1556
                {
1557 4b971df6 Rick Pratt
                        ccerr("(%d)%s memory exhausted on new addr gdpr connect timer",
1558 bd851bdd Rick Pratt
                                  nc_fd, fd_to_state_name(nc_fd));
1559 4b971df6 Rick Pratt
                        delete cguid_dmi->second.map_timer_dmip;
1560
                        delete cguid_dmi->second.map_timer;
1561
                        dst_map.erase(cguid_dmi);
1562 bd851bdd Rick Pratt
                        fd_recycle(nc_fd);
1563
                        break;
1564
                }
1565 79f90570 Rick Pratt
                ccdbg(DVVERB, "(%d)%s new addr gdp connect timer %p %p",
1566 bd851bdd Rick Pratt
                          nc_fd, fd_to_state_name(nc_fd),
1567 2c4eab43 Rick Pratt
                          cguid_dmi->second.map_timer,
1568
                          cguid_dmi->second.map_timer_dmip);
1569
                cguid_dmi->second.map_timer->initialize(this, true);
1570
                cguid_dmi->second.map_timer->schedule_after(ADDR_GDPR_CONNECT_TS_DELTA);
1571 62a58ed2 Rick Pratt
                
1572 acabfa65 Rick Pratt
                // fd tracks related dst maps
1573 2c4eab43 Rick Pratt
                (*_fdv)[nc_fd].dst_mil.push_back(cguid_dmi);
1574 acabfa65 Rick Pratt
                ccdbg(DVVERB, "(%d)%s hlo fd push dguid[%s]",
1575 62a58ed2 Rick Pratt
                          nc_fd, fd_to_state_name(nc_fd),                          
1576
                          gdp_printable_name(otw_hlo->src, _tmp_pname_1));
1577 b9253176 Rick Pratt
1578
                // diagnostics
1579 33571b36 Rick Pratt
                display_state(nc_fd);
1580 62a58ed2 Rick Pratt
1581
                (*_fdv)[nc_fd].peer_port = htons(otw_hlo->lport);
1582 bd851bdd Rick Pratt
                ccdbg(DNOISY, "(%d)%s rx peer port 0x%x 0x%x",
1583 62a58ed2 Rick Pratt
                          nc_fd, fd_to_state_name(nc_fd),
1584
                          otw_hlo->lport, (*_fdv)[nc_fd].peer_port);
1585 bd851bdd Rick Pratt
1586 4ded8992 Eric Allman
                ccdbg(DINFO, "(%d)%s new udp connect (%d)%s",
1587 cdaf995a Rick Pratt
                           fd, fd_to_state_name(fd), nc_fd, fd_to_state_name(nc_fd));
1588 62a58ed2 Rick Pratt
1589
                if (new_ssl(nc_fd) < 0)
1590
                {
1591 cdaf995a Rick Pratt
                        ccerr("(%d)%s name ack new_ssl failed",
1592 62a58ed2 Rick Pratt
                                  nc_fd, fd_to_state_name(nc_fd));
1593
                        fd_recycle(nc_fd);
1594
                        break;
1595
                }
1596
        }
1597
        break;
1598
        
1599
        case GDP_CMD_ROUTER_NAME_REP:
1600
        default:
1601
        {
1602 d6b275d1 Rick Pratt
                ccdbg(DVVERB, "(%d)%s rx invalid cmd %d",
1603 62a58ed2 Rick Pratt
                          fd, fd_to_state_name(fd), otw_hlo->cmd);
1604
        }
1605
        break;
1606
        
1607
        } // switch
1608 bd851bdd Rick Pratt
1609
        p->kill();
1610 62a58ed2 Rick Pratt
}
1611
1612
void
1613
GDPv4Router::udp_connect_rx (int fd)
1614
{
1615
        WritablePacket *p;
1616
        ssize_t rx_len;
1617
        gdp_name_ca_t *cguid_ca;
1618 2c4eab43 Rick Pratt
        dst_map_it_t cguid_dmi;
1619 62a58ed2 Rick Pratt
        gdp_pname_t _tmp_pname_1;
1620
1621
        p = Packet::make(GDP_CMD_ROUTER_NAME_MAX_SZ);
1622 bd851bdd Rick Pratt
        if (p == nullptr)
1623
        {
1624
                ccwarn("(%d)%s packet pool exhausted on %d",
1625
                           fd, fd_to_state_name(fd), GDP_CMD_ROUTER_NAME_MAX_SZ);
1626
                return;
1627
        }
1628 62a58ed2 Rick Pratt
1629
        // MSG_TRUNC discards excess but rx_len will reflect full length
1630
        rx_len = recv(fd, p->data(), p->length(), MSG_TRUNC);
1631
        if (rx_len <= 0 || rx_len > p->length())
1632
        {
1633 bd851bdd Rick Pratt
                switch (errno)
1634
                {
1635
1636
                case ECONNREFUSED:
1637
                {
1638 4ded8992 Eric Allman
                        ccdbg(DINFO, "(%d)%s peer refused udp connection (errno %d)",
1639 bd851bdd Rick Pratt
                                   fd, fd_to_state_name(fd), errno);
1640
                }
1641
                break;
1642
1643
                default:
1644
                {
1645 4ded8992 Eric Allman
                        ccdbg(DINFO, "(%d)%s recv len %d p len %d errno %d",
1646 34917f5f Rick Pratt
                                   fd, fd_to_state_name(fd), rx_len, p->length(), errno);
1647 bd851bdd Rick Pratt
                }
1648
                break;
1649
1650
                } // switch
1651
1652 62a58ed2 Rick Pratt
                p->kill();
1653
                return;
1654
        }
1655
        
1656
        otw_hlo_t *otw_hlo = (otw_hlo_t *)p->data();
1657
        
1658
        if (otw_hlo->ver != GDP_CHAN_PROTO_VERSION)
1659
        {
1660
                ccdbg(DVVERB, "(%d)%s rx unknown version 0x%x",
1661
                          fd, fd_to_state_name(fd), otw_hlo->ver);
1662
                p->kill();
1663
                return;
1664
        }
1665
1666 bd851bdd Rick Pratt
        ccdbg(DVERB, "(%d)%s recv len %d p %p len %d\n"
1667
                  "\tsrc[%s]",
1668
                  fd, fd_to_state_name(fd),
1669
                  rx_len, p, p->length(),
1670 62a58ed2 Rick Pratt
                  gdp_printable_name(otw_hlo->src, _tmp_pname_1));
1671
1672 bd851bdd Rick Pratt
        // p->kill() called at function end
1673 62a58ed2 Rick Pratt
        switch (otw_hlo->cmd)
1674
        {
1675
1676
        case GDP_CMD_ROUTER_NAME_REP:
1677
        {
1678
                if (rx_len < (ssize_t) GDP_CMD_ROUTER_NAME_REP_SZ)
1679
                {
1680 bd851bdd Rick Pratt
                        ccdbg(DVVERB, "(%d)%s rx name rep short len %d, drop",
1681 62a58ed2 Rick Pratt
                                  fd, fd_to_state_name(fd), rx_len);
1682
                        break;
1683
                }
1684
1685
                // validate dst
1686
                if (memcmp(_gdpr, otw_hlo->dst, sizeof(gdp_name_ca_t)) != 0)
1687
                {
1688
                        ccdbg(DVERB, "(%d)%s rx name rep unknown dst[%s], drop",
1689
                                  fd, fd_to_state_name(fd),
1690
                                  gdp_printable_name(otw_hlo->dst, _tmp_pname_1));
1691
                        break;
1692
                }
1693
1694
                // insert if not in map, otherwise stop exchange here
1695
                cguid_ca = (gdp_name_ca_t *) otw_hlo->src;
1696 2c4eab43 Rick Pratt
                cguid_dmi = dst_map.lower_bound(*cguid_ca);
1697
                if (cguid_dmi == dst_map.end() ||
1698
                        dst_map.key_comp()(*cguid_ca, cguid_dmi->first))
1699 62a58ed2 Rick Pratt
                {
1700 2c4eab43 Rick Pratt
                        cguid_dmi =
1701
                                dst_map.emplace_hint(cguid_dmi,
1702 c8522a6f Rick Pratt
                                                                         dst_map_t::value_type(*cguid_ca,
1703
                                                                                                                   dst_map_init));
1704 62a58ed2 Rick Pratt
                }
1705
                else
1706
                {
1707 bd851bdd Rick Pratt
                        ccdbg(DVERB, "(%d)%s rx name rep set udp connect dupe\n"
1708
                                  "\tsrc[%s]",
1709 62a58ed2 Rick Pratt
                                  fd, fd_to_state_name(fd),
1710
                                  gdp_printable_name(otw_hlo->src, _tmp_pname_1));
1711 bd851bdd Rick Pratt
                        // delete udp connect fd retx timer (uncheduled by delete)
1712 da7bcbcb Rick Pratt
                        avow((*_fdv)[fd].retx_timer != nullptr);
1713 bd851bdd Rick Pratt
                        delete (*_fdv)[fd].retx_timer;
1714
                        (*_fdv)[fd].retx_timer = nullptr;
1715
                        // udp connect dupe is dormant until reanimated
1716
                        (*_fdv)[fd].fd_state = FD_UDP_CONNECT_DUPE;
1717 62a58ed2 Rick Pratt
                        break;
1718
                }
1719 bd851bdd Rick Pratt
1720
                // udp connect is on fd
1721 2c4eab43 Rick Pratt
                cguid_dmi->second.fd = fd;
1722 62a58ed2 Rick Pratt
1723 bd851bdd Rick Pratt
                // delete udp connect fd retx timer (uncheduled by delete)
1724 da7bcbcb Rick Pratt
                avow((*_fdv)[fd].retx_timer != nullptr);
1725 bd851bdd Rick Pratt
                delete (*_fdv)[fd].retx_timer;
1726
                (*_fdv)[fd].retx_timer = nullptr;
1727
1728
                // directly connected router
1729 2c4eab43 Rick Pratt
                cguid_dmi->second.addr_state = ADDR_GDPR;
1730
                avow(cguid_dmi->second.map_timer_dmip == nullptr);
1731
                avow(cguid_dmi->second.map_timer == nullptr);
1732 bd851bdd Rick Pratt
                try {
1733 2c4eab43 Rick Pratt
                        cguid_dmi->second.map_timer_dmip = new dst_map_it_t(cguid_dmi);
1734
                        cguid_dmi->second.map_timer =
1735 79f90570 Rick Pratt
                                new Timer(static_addr_gdpr_connect_timer,
1736 2c4eab43 Rick Pratt
                                                  cguid_dmi->second.map_timer_dmip);
1737 bd851bdd Rick Pratt
                }
1738
                catch (std::bad_alloc)
1739
                {
1740 4b971df6 Rick Pratt
                        ccerr("(%d)%s memory exhausted on new addr gdpr connect timer",
1741 bd851bdd Rick Pratt
                                  fd, fd_to_state_name(fd));
1742 4b971df6 Rick Pratt
                        delete cguid_dmi->second.map_timer_dmip;
1743
                        delete cguid_dmi->second.map_timer;
1744
                        dst_map.erase(cguid_dmi);
1745 bd851bdd Rick Pratt
                        fd_recycle(fd);
1746
                        break;
1747
                }
1748 79f90570 Rick Pratt
                ccdbg(DVVERB, "(%d)%s new addr gdp connect timer %p %p",
1749 bd851bdd Rick Pratt
                          fd, fd_to_state_name(fd),
1750 2c4eab43 Rick Pratt
                          cguid_dmi->second.map_timer,
1751
                          cguid_dmi->second.map_timer_dmip);
1752
                cguid_dmi->second.map_timer->initialize(this, true);
1753
                cguid_dmi->second.map_timer->schedule_after(ADDR_GDPR_CONNECT_TS_DELTA);
1754 bd851bdd Rick Pratt
                
1755 62a58ed2 Rick Pratt
                // fd tracks related map entries
1756 2c4eab43 Rick Pratt
                (*_fdv)[fd].dst_mil.push_back(cguid_dmi);
1757 bd851bdd Rick Pratt
                ccdbg(DVVERB, "(%d)%s hlo fd push map\n"
1758
                          "\tsrc[%s]",
1759 62a58ed2 Rick Pratt
                          fd, fd_to_state_name(fd),
1760
                          gdp_printable_name(otw_hlo->src, _tmp_pname_1));
1761
1762 bd851bdd Rick Pratt
                ccdbg(DVERB, "(%d)%s rx name rep map insert\n"
1763
                          "\tsrc[%s]",
1764 62a58ed2 Rick Pratt
                          fd, fd_to_state_name(fd),
1765
                          gdp_printable_name(otw_hlo->src, _tmp_pname_1));
1766 bd851bdd Rick Pratt
                // diagnostics
1767 33571b36 Rick Pratt
                display_state(fd);
1768 bd851bdd Rick Pratt
1769
                // tx GDP_CMD_ROUTER_NAME_ACK msg
1770 62a58ed2 Rick Pratt
                otw_hlo->cmd = GDP_CMD_ROUTER_NAME_ACK;
1771
                std::copy(otw_hlo->src,
1772
                                  otw_hlo->src + sizeof(gdp_name_ca_t),
1773
                                  otw_hlo->dst);
1774
                std::copy(_gdpr, _gdpr + sizeof(gdp_name_ca_t),
1775
                                  otw_hlo->src);
1776
                otw_hlo->lport = (*_sav)[_SAV_INDEX_UDP].sin_port;
1777
                datagram_tx(fd, p, nullptr, 0);
1778
1779
                if (new_ssl(fd) < 0)
1780
                {
1781 bd851bdd Rick Pratt
                        ccerr("(%d)%s name reply new_ssl error", fd, fd_to_state_name(fd));
1782 62a58ed2 Rick Pratt
                        fd_recycle(fd);
1783
                }
1784
        }
1785
        break;
1786
        
1787
        default:
1788
        {
1789
                ccdbg(DVVERB, "(%d)%s unknown cmd %d",
1790
                          fd, fd_to_state_name(fd), otw_hlo->cmd);
1791
        }
1792
        break;
1793
        
1794
        } // switch
1795 bd851bdd Rick Pratt
1796
        p->kill();
1797
}
1798
1799
void
1800
GDPv4Router::udp_connect_timer (Timer *t, int fd)
1801
{
1802
        WritablePacket *p;
1803
        otw_hlo_t *otw_hlo;
1804 acabfa65 Rick Pratt
1805
        ccdbg(DVVERB, "\n(%d)%s udp connect timer %p", fd, fd_to_state_name(fd), t);
1806
1807 da7bcbcb Rick Pratt
        avow(fd > _fd_directory && fd <= _fd_last_configured);
1808
        avow((*_fdv)[fd].fd_state == FD_UDP_CONNECT);
1809 bd851bdd Rick Pratt
1810
        p = Packet::make(GDP_CMD_ROUTER_NAME_REQ_SZ);
1811
        if (p != nullptr)
1812
        {
1813
                otw_hlo = (otw_hlo_t *)p->data();
1814
                otw_hlo->ver = GDP_CHAN_PROTO_VERSION;
1815
                otw_hlo->cmd = GDP_CMD_ROUTER_NAME_REQ;
1816
                otw_hlo->id = htons(_dr_id++);
1817
                memset(otw_hlo->dst, 0x00, sizeof(gdp_name_ca_t));
1818
                std::copy(_gdpr_ca->data(), _gdpr_ca->data() + sizeof(gdp_name_ca_t),
1819
                                  otw_hlo->src);
1820
1821 4ded8992 Eric Allman
                ccdbg(DINFO, "\n(%d)%s udp connect name req", fd, fd_to_state_name(fd));
1822 bd851bdd Rick Pratt
                datagram_tx(fd, p, nullptr, 0);
1823
        }
1824
        
1825
        // reschedule timer
1826
        t->schedule_after(FD_UDP_CONNECT_TS_DELTA);
1827 62a58ed2 Rick Pratt
}
1828
1829
void
1830 bd851bdd Rick Pratt
ssl_info_callback (const SSL *ssl, int where, int ret, const char *name)
1831 62a58ed2 Rick Pratt
{
1832 bd851bdd Rick Pratt
        ccdbg(DVVERB, "ssl_info_callback %s 0x%x %d %s %s", name, where, ret,
1833 62a58ed2 Rick Pratt
                  SSL_state_string(ssl), SSL_state_string_long(ssl));
1834
}
1835
1836
void
1837 bd851bdd Rick Pratt
server_ssl_info_callback (const SSL *ssl, int where, int ret)
1838 62a58ed2 Rick Pratt
{
1839
        ssl_info_callback(ssl, where, ret, "dtls listen");
1840
}
1841
1842
void
1843 bd851bdd Rick Pratt
client_ssl_info_callback (const SSL *ssl, int where, int ret)
1844 62a58ed2 Rick Pratt
{
1845
        ssl_info_callback(ssl, where, ret, "dtls connect");
1846
}
1847
1848
int GDPv4Router::new_ssl (int fd)
1849
{
1850
        BIO *new_bio_dgram;
1851
        struct timeval timeout;
1852
1853 da7bcbcb Rick Pratt
        avow(fd > _fd_directory && fd < (int)(*_fdv).size());
1854
        avow((*_fdv)[fd].ssl == nullptr);
1855
        avow((*_fdv)[fd].fd_state == FD_UDP_CONNECT ||
1856 2b36755d Rick Pratt
                 (*_fdv)[fd].fd_state == FD_UDP_LISTEN);
1857 62a58ed2 Rick Pratt
1858
        if (((*_fdv)[fd].ssl = SSL_new(_ssl_ctx)) == nullptr)
1859
        {
1860
                // caller owns fd_recycle
1861
                return -1;
1862
        }
1863
1864
        if (_debug_level >= DVERB)
1865 acabfa65 Rick Pratt
        {
1866 62a58ed2 Rick Pratt
                SSL_set_info_callback((*_fdv)[fd].ssl, server_ssl_info_callback);
1867 acabfa65 Rick Pratt
        }
1868 bd851bdd Rick Pratt
        // SSL_CTX_set_info_callback() diagnostics have not been required, so far
1869
        // (dated) online info say read_ahead is required, but currently not needed
1870 62a58ed2 Rick Pratt
        // SSL_CTX_set_read_ahead (ssl_ctx, 1);
1871
1872
        if ((new_bio_dgram = BIO_new_dgram(fd, BIO_NOCLOSE)) == nullptr)
1873
        {
1874 cdaf995a Rick Pratt
                ccerr("BIO_new_dgram failed");
1875 62a58ed2 Rick Pratt
                // caller owns fd_recycle
1876
                return -1;
1877
        }
1878
        
1879
        // timeouts
1880
        timeout.tv_sec = 0;
1881
        timeout.tv_usec = DGRAM_RCV_TIMEOUT;
1882
        BIO_ctrl(new_bio_dgram, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
1883
        timeout.tv_usec = DGRAM_SND_TIMEOUT;
1884
        BIO_ctrl(new_bio_dgram, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout);
1885
        // mtu discovery
1886
        BIO_ctrl(new_bio_dgram, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);
1887
        // bind dgram bio to ssl
1888
        SSL_set_bio((*_fdv)[fd].ssl, new_bio_dgram, new_bio_dgram);
1889
        if ((*_fdv)[fd].fd_state == FD_UDP_CONNECT)
1890
        {
1891
                // peer listened for hello, however we listen for initial SSL handshake
1892
                SSL_set_accept_state((*_fdv)[fd].ssl);
1893 bd851bdd Rick Pratt
                // delete udp connect fd retx timer (uncheduled by delete)
1894
                delete (*_fdv)[fd].retx_timer;
1895
                (*_fdv)[fd].retx_timer = nullptr;
1896
                // udp connect moves to dtls accept state
1897 62a58ed2 Rick Pratt
                (*_fdv)[fd].fd_state = FD_DTLS_ACCEPT;
1898
                ssl_accept(fd);
1899
        }
1900
        else // (*_fdv)[fd].fd_state == FD_UDP_LISTEN
1901
        {
1902
                struct sockaddr_in peer_sa_in;
1903
                int peer_sa_in_len = sizeof(peer_sa_in);
1904
                
1905
                if (getpeername(fd, (struct sockaddr *) &peer_sa_in,
1906
                                                (socklen_t *) &peer_sa_in_len) < 0)
1907
                {
1908 cdaf995a Rick Pratt
                        ccerr("getpeername %s", strerror (errno));
1909 62a58ed2 Rick Pratt
                        // caller owns fd_recycle
1910
                        return -1;
1911
                }
1912 bd851bdd Rick Pratt
                ccdbg(DVVERB, "(%d)%s BIO ctrl0 set connected %s:%d",
1913 62a58ed2 Rick Pratt
                          fd, fd_to_state_name(fd),
1914
                          IPAddress(peer_sa_in.sin_addr).unparse().c_str(),
1915
                          ntohs(peer_sa_in.sin_port));
1916 bd851bdd Rick Pratt
                // mandatory for ssl, but passing the wrong address is quietly accepted!
1917 4ded8992 Eric Allman
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
1918
                (void)BIO_ctrl_set_connected(new_bio_dgram, &peer_sa_in);
1919
#else
1920 62a58ed2 Rick Pratt
                (void)BIO_ctrl_set_connected(new_bio_dgram, 1, &peer_sa_in);
1921 4ded8992 Eric Allman
#endif
1922 bd851bdd Rick Pratt
                // udp listen moves to dtls handshake state
1923 62a58ed2 Rick Pratt
                (*_fdv)[fd].fd_state = FD_DTLS_DO_HANDSHAKE;
1924 bd851bdd Rick Pratt
                SSL_set_connect_state((*_fdv)[fd].ssl);
1925 62a58ed2 Rick Pratt
                ssl_handshake(fd);
1926
        }
1927
1928
        ccdbg(DVERB, "(%d)%s new ssl", fd, fd_to_state_name(fd));
1929
1930
        return fd;
1931
}
1932
1933
int
1934
GDPv4Router::ssl_accept (int fd)
1935
{
1936
        int ssl_status;
1937
        int ssl_error;
1938 2c4eab43 Rick Pratt
        dst_map_it_t cguid_dmi;
1939 62a58ed2 Rick Pratt
1940
        ssl_status = SSL_accept((*_fdv)[fd].ssl);
1941
        if (ssl_status <= 0)
1942
        {
1943
                ssl_error = SSL_get_error((*_fdv)[fd].ssl, ssl_status);
1944
                // ssl_error holds an enum, not bit flags
1945
                switch (ssl_error)
1946
                {
1947
                case SSL_ERROR_WANT_READ:
1948 b9253176 Rick Pratt
                        // router fd is always SELECT_READ (add/remove performs poorly)
1949 62a58ed2 Rick Pratt
                        break;
1950
                case SSL_ERROR_WANT_WRITE:
1951 b9253176 Rick Pratt
                        // this condition has not been spotted in the wild, so far...
1952 da7bcbcb Rick Pratt
                        aver(0);
1953 62a58ed2 Rick Pratt
                        break;
1954
                default:
1955 cdaf995a Rick Pratt
                        ccerr("(%d)%s ssl_accept unhandled ssl error (%d)",
1956 62a58ed2 Rick Pratt
                                  fd, fd_to_state_name(fd), ssl_error);
1957 da7bcbcb Rick Pratt
                        aver(0);
1958 62a58ed2 Rick Pratt
                        break;
1959
                }
1960
                ccdbg(DVVERB, "(%d)%s ssl_accept error string %s",
1961
                          fd, fd_to_state_name(fd),
1962
                          ERR_error_string(ERR_get_error(), NULL));
1963
        }
1964
        else
1965 bd851bdd Rick Pratt
        {
1966
                // dtls accept moves to dtls server state
1967 62a58ed2 Rick Pratt
                (*_fdv)[fd].fd_state = FD_DTLS_SERVER;
1968 2c4eab43 Rick Pratt
                cguid_dmi = (*_fdv)[fd].dst_mil.front();
1969
                avow(cguid_dmi->second.map_timer != nullptr);
1970
                cguid_dmi->second.map_timer->assign(static_addr_gdpr_timer,
1971
                                                                                        cguid_dmi->second.map_timer_dmip);
1972
                cguid_dmi->second.map_timer->schedule_after(ADDR_GDPR_NOW_TS_DELTA);
1973 79f90570 Rick Pratt
                ccdbg(DVVERB, "(%d)%s addr gdp connect timer reassigned to gdpr %p %p",
1974 f8f9ed32 Rick Pratt
                          fd, fd_to_state_name(fd),
1975 2c4eab43 Rick Pratt
                          cguid_dmi->second.map_timer, cguid_dmi->second.map_timer_dmip);
1976 bd851bdd Rick Pratt
        }
1977 62a58ed2 Rick Pratt
1978 4ded8992 Eric Allman
        ccdbg(DINFO, "(%d)%s ssl_accept status %d (%s)",
1979 cdaf995a Rick Pratt
                   fd, fd_to_state_name(fd), ssl_status,
1980
                   (ssl_status <= 0 ? _SSL_ERROR_NAME[ssl_error] : "-"));
1981 62a58ed2 Rick Pratt
        
1982
        return ssl_status;
1983
}
1984
1985
int
1986
GDPv4Router::ssl_handshake (int fd)
1987
{
1988
        int ssl_status;
1989
        int ssl_error;
1990 2c4eab43 Rick Pratt
        dst_map_it_t cguid_dmi;
1991 bd851bdd Rick Pratt
1992 62a58ed2 Rick Pratt
        ssl_status = SSL_do_handshake((*_fdv)[fd].ssl);
1993
        if (ssl_status <= 0)
1994
        {
1995
                ssl_error = SSL_get_error((*_fdv)[fd].ssl, ssl_status);
1996
                // ssl_error holds an enum, not bit flags
1997
                switch (ssl_error)
1998
                {
1999
                case SSL_ERROR_WANT_READ:
2000 b9253176 Rick Pratt
                        // router fd is always SELECT_READ (add/remove performs poorly)
2001 62a58ed2 Rick Pratt
                        break;
2002
                case SSL_ERROR_WANT_WRITE:
2003 b9253176 Rick Pratt
                        // this condition has not been spotted in the wild, so far...
2004 da7bcbcb Rick Pratt
                        aver(0);
2005 62a58ed2 Rick Pratt
                        break;
2006
                default:
2007 cdaf995a Rick Pratt
                        ccerr("(%d)%s ssl_handshake unhandled ssl error (%d)",
2008 62a58ed2 Rick Pratt
                                  fd, fd_to_state_name(fd), ssl_error);
2009 da7bcbcb Rick Pratt
                        aver(0);
2010 62a58ed2 Rick Pratt
                        break;
2011
                }
2012
                ccdbg(DVVERB, "(%d)%s ssl_handshake error string %s",
2013
                          fd, fd_to_state_name(fd),
2014
                          ERR_error_string(ERR_get_error(), NULL));
2015
        }
2016
        else
2017
        {
2018 f8f9ed32 Rick Pratt
                // dtls do handshake moves to dtls client state
2019 d6b275d1 Rick Pratt
                (*_fdv)[fd].fd_state = FD_DTLS_CLIENT;
2020 2c4eab43 Rick Pratt
                cguid_dmi = (*_fdv)[fd].dst_mil.front();
2021
                avow(cguid_dmi->second.map_timer != nullptr);
2022
                cguid_dmi->second.map_timer->assign(static_addr_gdpr_timer,
2023
                                                                                        cguid_dmi->second.map_timer_dmip);
2024
                cguid_dmi->second.map_timer->schedule_after(ADDR_GDPR_NOW_TS_DELTA);
2025 79f90570 Rick Pratt
                ccdbg(DVVERB, "(%d)%s addr gdp connect timer reassigned to gdpr %p %p",
2026 f8f9ed32 Rick Pratt
                          fd, fd_to_state_name(fd),
2027 2c4eab43 Rick Pratt
                          cguid_dmi->second.map_timer, cguid_dmi->second.map_timer_dmip);
2028 62a58ed2 Rick Pratt
        }        
2029
2030 4ded8992 Eric Allman
        ccdbg(DINFO, "(%d)%s ssl_handshake status %d (%s)",
2031 cdaf995a Rick Pratt
                   fd, fd_to_state_name(fd), ssl_status,
2032
                   (ssl_status <= 0 ? _SSL_ERROR_NAME[ssl_error] : "-"));
2033 62a58ed2 Rick Pratt
2034
        return ssl_status;
2035
}
2036
2037
void
2038
GDPv4Router::advertisement_rx (int fd, WritablePacket *p)
2039
{
2040 bd851bdd Rick Pratt
        otw_gdp_t *otw_gdp;
2041 62a58ed2 Rick Pratt
        uint16_t dlen;
2042
        uint32_t mlen;
2043 bd851bdd Rick Pratt
        WritablePacket *dp;
2044 62a58ed2 Rick Pratt
        otw_dir_t *otw_dir;
2045 7c97363d Rick Pratt
        gdp_name_ca_t *dguid_ca;
2046 2c4eab43 Rick Pratt
        dst_map_it_t dguid_dmi;
2047 62a58ed2 Rick Pratt
        gdp_pname_t _tmp_pname_1;
2048 bd851bdd Rick Pratt
        gdp_pname_t _tmp_pname_2;
2049 4b971df6 Rick Pratt
        bool gdpc_advert;
2050
#ifdef TEST_ADVERT_LOAD
2051
        uint32_t test_advert_load_factor = 100;
2052
#endif
2053
        
2054 acabfa65 Rick Pratt
        ccdbg(DVVERB, "(%d)%s advertisement rx p %p", fd, fd_to_state_name(fd), p);
2055
        
2056 4b971df6 Rick Pratt
#ifdef TEST_ADVERT_LOAD
2057
test_advert_load:
2058
#endif
2059
        
2060 62a58ed2 Rick Pratt
        // read fields through on-the-wire (packed) struct layout
2061 da7bcbcb Rick Pratt
        avow(p != nullptr);
2062 62a58ed2 Rick Pratt
        otw_gdp = (otw_gdp_t *) p->data();
2063
        dlen = ntohs(otw_gdp->payload_len);
2064
        mlen = (otw_gdp->hdr_len * 4) + dlen;
2065 cd9906ab Rick Pratt
        ccdbg(DVERB, "(%d)%s advert rx hlen %d dlen %d mlen %d\n"
2066 4e5c5b6f Rick Pratt
                  "\tsrc[%s]\n"
2067
                  "\tdst[%s]",
2068 bd851bdd Rick Pratt
                  fd, fd_to_state_name(fd), otw_gdp->hdr_len, dlen, mlen,
2069
                  gdp_printable_name(otw_gdp->src, _tmp_pname_1),
2070
                  gdp_printable_name(otw_gdp->dst, _tmp_pname_2));
2071 62a58ed2 Rick Pratt
2072 bd851bdd Rick Pratt
        // directory p
2073 acabfa65 Rick Pratt
        dp = Packet::make(offsetof(otw_dir_t, eguid[1][0]));
2074 bd851bdd Rick Pratt
        if (dp == nullptr)
2075 62a58ed2 Rick Pratt
        {
2076 bd851bdd Rick Pratt
                ccwarn("(%d)%s packet pool exhausted on %d",
2077 acabfa65 Rick Pratt
                           fd, fd_to_state_name(fd), offsetof(otw_dir_t, eguid[1][0]));
2078 b9253176 Rick Pratt
                goto advertisement_rx_cleanup_p;
2079 62a58ed2 Rick Pratt
        }
2080 7c97363d Rick Pratt
2081 bd851bdd Rick Pratt
        otw_dir = (otw_dir_t *) dp->data();
2082
        otw_dir->ver = GDP_CHAN_PROTO_VERSION;
2083
        otw_dir->id = htons(_dr_id++);
2084
        otw_dir->cmd = GDP_CMD_DIR_ADD;
2085 7c97363d Rick Pratt
        
2086
        dguid_ca = (gdp_name_ca_t *) otw_gdp->dst;
2087 2c4eab43 Rick Pratt
        dguid_dmi = dst_map.lower_bound(*dguid_ca);
2088
        if (dguid_dmi != dst_map.end() &&
2089
                !(dst_map.key_comp()(*dguid_ca, dguid_dmi->first)))
2090 7c97363d Rick Pratt
        {
2091
                // resolve conflicts between incoming advert and map state
2092 2c4eab43 Rick Pratt
                switch (dguid_dmi->second.addr_state)
2093 7c97363d Rick Pratt
                {
2094
2095
                case ADDR_GDPC:
2096
                {
2097 2c4eab43 Rick Pratt
                        if (fd != dguid_dmi->second.fd ||
2098 7c97363d Rick Pratt
                                memcmp(otw_gdp->src, otw_gdp->dst, sizeof(gdp_name_ca_t)) != 0)
2099
                        {
2100 b9253176 Rick Pratt
                                ccwarn("(%d)%s advert vs gdpc, drop advert\n"
2101
                                           "\tdguid[%s]",
2102
                                           fd, fd_to_state_name(fd),
2103 138a6389 Rick Pratt
                                           gdp_printable_name(otw_gdp->dst, _tmp_pname_1));
2104 4b971df6 Rick Pratt
                                dp->kill();
2105
                                goto advertisement_rx_cleanup_p;
2106 7c97363d Rick Pratt
                        }
2107
                }
2108
                break;
2109
2110
                case ADDR_NHOP:
2111
                {
2112 2c4eab43 Rick Pratt
                        if (fd != dguid_dmi->second.fd ||
2113 7c97363d Rick Pratt
                                memcmp(otw_gdp->src, otw_gdp->dst, sizeof(gdp_name_ca_t)) == 0)
2114
                        {
2115 4ded8992 Eric Allman
                                ccdbg(DINFO, "(%d)%s advert vs nhop, recycle nhop\n"
2116 b9253176 Rick Pratt
                                           "\tdguid[%s]",
2117
                                           fd, fd_to_state_name(fd),
2118 138a6389 Rick Pratt
                                           gdp_printable_name(otw_gdp->dst, _tmp_pname_1));
2119 2c4eab43 Rick Pratt
                                fd_detach_map(dguid_dmi->second.fd, dguid_dmi);
2120 acabfa65 Rick Pratt
                                dst_map_recycle(dguid_dmi->second.fd, dguid_dmi);
2121 2c4eab43 Rick Pratt
                                dguid_dmi = dst_map.end();
2122 7c97363d Rick Pratt
2123
                                // diagnostics
2124 33571b36 Rick Pratt
                                display_state(fd);
2125 7c97363d Rick Pratt
                        }
2126
                }
2127
                break;
2128
2129
                case ADDR_FIND:
2130
                {
2131 4ded8992 Eric Allman
                        ccdbg(DINFO, "(%d)%s advert vs find, recycle find\n"
2132 b9253176 Rick Pratt
                                   "\tdguid[%s]",
2133
                                   fd, fd_to_state_name(fd),
2134 138a6389 Rick Pratt
                                   gdp_printable_name(otw_gdp->dst, _tmp_pname_1));
2135 2c4eab43 Rick Pratt
                        map_no_route(fd, dguid_dmi);
2136 acabfa65 Rick Pratt
                        dst_map_recycle(fd, dguid_dmi);
2137 2c4eab43 Rick Pratt
                        dguid_dmi = dst_map.end();
2138 7c97363d Rick Pratt
2139
                        // diagnostics
2140 33571b36 Rick Pratt
                        display_state(fd);
2141 7c97363d Rick Pratt
                }
2142
                break;
2143 62a58ed2 Rick Pratt
2144 7c97363d Rick Pratt
                case ADDR_MINE:
2145
                case ADDR_GDPR:
2146
                default:
2147
                {
2148 b9253176 Rick Pratt
                        ccwarn("(%d)%s advert conflict, drop advert\n"
2149
                                   "\tdguid[%s]",
2150
                                   fd, fd_to_state_name(fd),
2151 138a6389 Rick Pratt
                                   gdp_printable_name(otw_gdp->dst, _tmp_pname_1));
2152 4b971df6 Rick Pratt
                        dp->kill();
2153
                        goto advertisement_rx_cleanup_p;
2154 7c97363d Rick Pratt
                }
2155
                break;
2156
2157
                } // switch
2158
        }
2159
2160
    // ADDR_GDPC (src == dst)
2161 bd851bdd Rick Pratt
        if (memcmp(otw_gdp->src, otw_gdp->dst, sizeof(gdp_name_ca_t)) == 0)
2162 62a58ed2 Rick Pratt
        {
2163 2c4eab43 Rick Pratt
                if (dguid_dmi == dst_map.end() ||
2164
                        dst_map.key_comp()(*dguid_ca, dguid_dmi->first))
2165 bd851bdd Rick Pratt
                {
2166 c8522a6f Rick Pratt
                        if ((*_fdv)[fd].dst_mil.size() > 0)
2167 684dd677 Rick Pratt
                        {
2168 823787eb Rick Pratt
                                ccwarn("(%d)%s reject add map[%s]\n"
2169
                                           "\tfd has owner[%s]%s",
2170 684dd677 Rick Pratt
                                           fd, fd_to_state_name(fd),
2171
                                           gdp_printable_name(otw_gdp->src, _tmp_pname_1),
2172
                                           gdp_printable_name(
2173 c8522a6f Rick Pratt
                                                   (*_fdv)[fd].dst_mil.front()->first.data(),
2174 684dd677 Rick Pratt
                                                   _tmp_pname_2),
2175
                                           addr_to_state_name(
2176 c8522a6f Rick Pratt
                                                   (*_fdv)[fd].dst_mil.front()->second.addr_state));
2177 4b971df6 Rick Pratt
                                dp->kill();
2178
                                goto advertisement_rx_cleanup_p;
2179 684dd677 Rick Pratt
                        }
2180
                        
2181 2c4eab43 Rick Pratt
                        dguid_dmi =
2182
                                dst_map.emplace_hint(dguid_dmi,
2183 c8522a6f Rick Pratt
                                                                         dst_map_t::value_type(*dguid_ca,
2184
                                                                                                                   dst_map_init));
2185 4b971df6 Rick Pratt
                        // directly connected gdp client
2186 2c4eab43 Rick Pratt
                        dguid_dmi->second.fd = fd;
2187
                        dguid_dmi->second.addr_state = ADDR_GDPC;
2188 4b971df6 Rick Pratt
                        avow(dguid_dmi->second.map_timer_dmip == nullptr);
2189
                        avow(dguid_dmi->second.map_timer == nullptr);
2190 acabfa65 Rick Pratt
                        try {
2191
                                dguid_dmi->second.map_timer_dmip = new dst_map_it_t(dguid_dmi);
2192 4b971df6 Rick Pratt
                                if (!_single_router_mode)
2193
                                {
2194
                                        dguid_dmi->second.map_timer =
2195
                                                new Timer(static_addr_gdpc_timer,
2196
                                                                  dguid_dmi->second.map_timer_dmip);
2197
                                }
2198 acabfa65 Rick Pratt
                        }
2199
                        catch (std::bad_alloc)
2200
                        {
2201
                                ccerr("(%d)%s memory exhausted on new addr gdpc",
2202
                                          fd, fd_to_state_name(fd));
2203 4b971df6 Rick Pratt
                                delete dguid_dmi->second.map_timer_dmip;
2204
                                delete dguid_dmi->second.map_timer;
2205 acabfa65 Rick Pratt
                                dst_map.erase(dguid_dmi);
2206
                                fd_recycle(fd);
2207 4b971df6 Rick Pratt
                                dp->kill();
2208
                                goto advertisement_rx_cleanup_p;
2209 acabfa65 Rick Pratt
                        }
2210 4b971df6 Rick Pratt
                        if (!_single_router_mode)
2211
                        {
2212
                                ccdbg(DVVERB, "(%d)%s new addr gdpc timer %p %p",
2213
                                          fd, fd_to_state_name(fd),
2214
                                          dguid_dmi->second.map_timer,
2215
                                          dguid_dmi->second.map_timer_dmip);
2216
                                dguid_dmi->second.map_timer->initialize(this, true);
2217
                                dguid_dmi->second.map_timer->schedule_after(
2218 3aa9a35e Rick Pratt
                                        Timestamp(0, TIMESTAMP_US(_advert_timer)));
2219 4b971df6 Rick Pratt
                        }
2220
                        
2221 bd851bdd Rick Pratt
                        ccdbg(DVVERB, "(%d)%s add map[%s]%s",
2222
                                  fd, fd_to_state_name(fd),
2223
                                  gdp_printable_name(otw_gdp->src, _tmp_pname_1),
2224 2c4eab43 Rick Pratt
                                  addr_to_state_name(dguid_dmi->second.addr_state));
2225 62a58ed2 Rick Pratt
                
2226 bd851bdd Rick Pratt
                        // fd tracks related map entries
2227 2c4eab43 Rick Pratt
                        (*_fdv)[fd].dst_mil.push_back(dguid_dmi);
2228 bd851bdd Rick Pratt
                        ccdbg(DVVERB, "(%d)%s fd push map[%s]",
2229
                                  fd, fd_to_state_name(fd),
2230
                                  gdp_printable_name(otw_gdp->src, _tmp_pname_1));
2231 62a58ed2 Rick Pratt
2232 bd851bdd Rick Pratt
                        // diagnostics
2233 33571b36 Rick Pratt
                        display_state(fd);
2234 bd851bdd Rick Pratt
                }
2235
2236 7c97363d Rick Pratt
                // advertise ADDR_GDPC reachability via ADDR_MINE
2237 e7fa3577 Rick Pratt
                memcpy(otw_dir->eguid[0], _gdpr, sizeof(gdp_name_t));
2238 bd851bdd Rick Pratt
                memcpy(otw_dir->dguid, otw_gdp->src, sizeof(gdp_name_t));
2239 4b971df6 Rick Pratt
                gdpc_advert = true;
2240 bd851bdd Rick Pratt
        }
2241
        else
2242 62a58ed2 Rick Pratt
        {
2243 1cd3f4ab Rick Pratt
                // SINGLE ROUTER MODE
2244
                if (_single_router_mode &&
2245 2c4eab43 Rick Pratt
                        (dguid_dmi == dst_map.end() ||
2246
                         dst_map.key_comp()(*dguid_ca, dguid_dmi->first)))
2247 1cd3f4ab Rick Pratt
                {
2248 2c4eab43 Rick Pratt
                        dguid_dmi =
2249
                                dst_map.emplace_hint(dguid_dmi,
2250 c8522a6f Rick Pratt
                                                                         dst_map_t::value_type(*dguid_ca,
2251
                                                                                                                   dst_map_init));
2252 2c4eab43 Rick Pratt
                        dguid_dmi->second.fd = fd;
2253
                        dguid_dmi->second.addr_state = ADDR_NHOP;
2254 acabfa65 Rick Pratt
                        try {
2255
                                dguid_dmi->second.map_timer_dmip = new dst_map_it_t(dguid_dmi);
2256
                        }
2257
                        catch (std::bad_alloc)
2258
                        {
2259
                                ccerr("(%d)%s memory exhausted on new addr nhop",
2260
                                          fd, fd_to_state_name(fd));
2261 4b971df6 Rick Pratt
                                delete dguid_dmi->second.map_timer_dmip;
2262 acabfa65 Rick Pratt
                                dst_map.erase(dguid_dmi);
2263
                                fd_recycle(fd);
2264 4b971df6 Rick Pratt
                                dp->kill();
2265
                                goto advertisement_rx_cleanup_p;
2266 acabfa65 Rick Pratt
                        }
2267 1cd3f4ab Rick Pratt
                        // _single_router_mode ADDR_NHOP does not need to start a map timer
2268
                        ccdbg(DVVERB, "(%d)%s add map[%s]%s",
2269
                                  fd, fd_to_state_name(fd),
2270
                                  gdp_printable_name(otw_gdp->src, _tmp_pname_1),
2271 2c4eab43 Rick Pratt
                                  addr_to_state_name(dguid_dmi->second.addr_state));
2272 1cd3f4ab Rick Pratt
                
2273
                        // fd tracks related map entries
2274 2c4eab43 Rick Pratt
                        (*_fdv)[fd].dst_mil.push_back(dguid_dmi);
2275 1cd3f4ab Rick Pratt
                        ccdbg(DVVERB, "(%d)%s fd push map[%s]",
2276
                                  fd, fd_to_state_name(fd),
2277
                                  gdp_printable_name(otw_gdp->src, _tmp_pname_1));
2278
2279 2c4eab43 Rick Pratt
                        dst_map_it_t eguid_dmi = (*_fdv)[fd].dst_mil.front();
2280
                        int fd_eguid = eguid_dmi->second.fd;
2281 4ded8992 Eric Allman
                        ccdbg(DINFO, "(%d)%s single router mode map\n"
2282 1cd3f4ab Rick Pratt
                                   "\tdguid[%s]%s via\n"
2283
                                   "\teguid[%s]%s on (%d)%s",
2284
                                   fd, fd_to_state_name(fd),
2285 2c4eab43 Rick Pratt
                                   gdp_printable_name(dguid_dmi->first.data(), _tmp_pname_1),
2286
                                   addr_to_state_name(dguid_dmi->second.addr_state),
2287
                                   gdp_printable_name(eguid_dmi->first.data(), _tmp_pname_2),
2288
                                   addr_to_state_name(eguid_dmi->second.addr_state),
2289 1cd3f4ab Rick Pratt
                                   fd_eguid, fd_to_state_name(fd_eguid));
2290
                        
2291
                        // diagnostics
2292 33571b36 Rick Pratt
                        display_state(fd);
2293 1cd3f4ab Rick Pratt
                }
2294
                
2295 7c97363d Rick Pratt
                // advertise ADDR_NHOP reachability via ADDR_GDPC
2296 e7fa3577 Rick Pratt
                memcpy(otw_dir->eguid[0], otw_gdp->src, sizeof(gdp_name_t));                
2297 bd851bdd Rick Pratt
                memcpy(otw_dir->dguid, otw_gdp->dst, sizeof(gdp_name_t));
2298 4b971df6 Rick Pratt
                gdpc_advert = false;                
2299 62a58ed2 Rick Pratt
        }
2300
2301 1cd3f4ab Rick Pratt
        // SINGLE ROUTER MODE
2302
        if (_single_router_mode)
2303 acabfa65 Rick Pratt
        {
2304 4b971df6 Rick Pratt
                dp->kill();
2305
                goto advertisement_rx_cleanup_p;
2306 acabfa65 Rick Pratt
        }
2307 62a58ed2 Rick Pratt
2308 4b971df6 Rick Pratt
        // advertisement retx via ADDR_GDPC timer
2309
        dguid_ca = (gdp_name_ca_t *) otw_gdp->src;
2310
        dguid_dmi = dst_map.find(*dguid_ca);
2311
        if (dguid_dmi != dst_map.end())
2312
        {
2313 9a4ade63 Rick Pratt
                if (dguid_dmi->second.dplist.size())
2314
                {        
2315
                        if (gdpc_advert)
2316 4b971df6 Rick Pratt
                        {
2317
                                ccwarn("(%d)%s gdpc advert period (re)started with size (%d)",
2318
                                           fd, fd_to_state_name(fd),
2319
                                           dguid_dmi->second.dplist.size());
2320
                        }
2321
                }
2322 9a4ade63 Rick Pratt
                else
2323
                {
2324
                        // periodic full adverts and singletons (new)
2325
                        ccdbg(DINFO, "(%d)%s gdpc advert %s",
2326
                                  fd, fd_to_state_name(fd), gdpc_advert ? "periodic" : "new");
2327
                        dguid_dmi->second.dp_timer_count = 0;
2328
                        dguid_dmi->second.dp_acks = 0;
2329
                        dguid_dmi->second.dp_loss = 0;
2330
                        dguid_dmi->second.start_ts = Timestamp::now_steady();
2331
                        dguid_dmi->second.dp_algo = ADDR_GDPC_ADVERT_EVAL_END;
2332
                        dguid_dmi->second.map_timer->schedule_now();
2333
                }
2334
2335 4b971df6 Rick Pratt
                dguid_dmi->second.dplist.push_back(dp);
2336
#ifdef TEST_ADVERT_LOAD
2337
                if (--test_advert_load_factor)
2338
                {
2339
                        goto test_advert_load;
2340
                }
2341
#endif
2342
        }
2343 62a58ed2 Rick Pratt
2344 b9253176 Rick Pratt
advertisement_rx_cleanup_p:
2345 7c97363d Rick Pratt
        
2346 60d15dbb Rick Pratt
        // recycle advert p chain (net4 not sending multi-advert pdus, so pedantic)
2347
        p_chain_recycle(p);
2348 62a58ed2 Rick Pratt
}
2349
2350
void
2351
GDPv4Router::withdraw_rx (int fd, WritablePacket *p)
2352
{
2353
        otw_gdp_t *otw_gdp;
2354
        uint16_t dlen;
2355
        uint32_t mlen;
2356 bd851bdd Rick Pratt
        WritablePacket *dp;
2357 62a58ed2 Rick Pratt
        otw_dir_t *otw_dir;
2358 7c97363d Rick Pratt
        gdp_name_ca_t *dguid_ca;
2359 2c4eab43 Rick Pratt
        dst_map_it_t dguid_dmi;
2360 62a58ed2 Rick Pratt
        gdp_pname_t _tmp_pname_1;
2361 bd851bdd Rick Pratt
        gdp_pname_t _tmp_pname_2;
2362 62a58ed2 Rick Pratt
2363 acabfa65 Rick Pratt
        ccdbg(DVVERB, "(%d)%s withdraw rx p %p", fd, fd_to_state_name(fd), p);
2364
2365 bd851bdd Rick Pratt
        // read fields through on-the-wire (packed) struct layout
2366 da7bcbcb Rick Pratt
        avow(p != nullptr);
2367 62a58ed2 Rick Pratt
        otw_gdp = (otw_gdp_t *) p->data();
2368
        dlen = ntohs(otw_gdp->payload_len);
2369
        mlen = (otw_gdp->hdr_len * 4) + dlen;
2370 cd9906ab Rick Pratt
        ccdbg(DVERB, "(%d)%s withdraw rx hlen %d dlen %d mlen %d\n"
2371 4e5c5b6f Rick Pratt
                  "\tsrc[%s]\n"
2372
                  "\tdst[%s]",
2373 bd851bdd Rick Pratt
                  fd, fd_to_state_name(fd), otw_gdp->hdr_len, dlen, mlen,
2374
                  gdp_printable_name(otw_gdp->src, _tmp_pname_1),
2375
                  gdp_printable_name(otw_gdp->dst, _tmp_pname_2));
2376 62a58ed2 Rick Pratt
2377 7c97363d Rick Pratt
        dguid_ca = (gdp_name_ca_t *) otw_gdp->dst;
2378 2c4eab43 Rick Pratt
        dguid_dmi = dst_map.find(*dguid_ca);
2379
        if (dguid_dmi != dst_map.end() && fd == dguid_dmi->second.fd)
2380 bd851bdd Rick Pratt
        {
2381 7c97363d Rick Pratt
                if (memcmp(otw_gdp->src, otw_gdp->dst, sizeof(gdp_name_ca_t)) == 0)
2382 bd851bdd Rick Pratt
                {
2383 7c97363d Rick Pratt
                        // ADDR_GDPC owns the fd, so recycle fd (which will withdraw tx)
2384 bd851bdd Rick Pratt
                        fd_recycle(fd);
2385
                }
2386 7c97363d Rick Pratt
                else
2387 bd851bdd Rick Pratt
                {
2388 87645eb1 Rick Pratt
                        if (!_single_router_mode)
2389 7c97363d Rick Pratt
                        {
2390 87645eb1 Rick Pratt
                                // ADDR_NHOP withdraw tx
2391 acabfa65 Rick Pratt
                                dp = Packet::make(offsetof(otw_dir_t, eguid[1][0]));
2392 87645eb1 Rick Pratt
                                if (dp == nullptr)
2393
                                {
2394
                                        ccwarn("(%d)%s packet pool exhausted on %d",
2395 acabfa65 Rick Pratt
                                                   fd, fd_to_state_name(fd),
2396
                                                   offsetof(otw_dir_t, eguid[1][0]));
2397 87645eb1 Rick Pratt
                                }
2398
                                else
2399
                                {
2400
                                        otw_dir = (otw_dir_t *) dp->data();
2401
                                        otw_dir->ver = GDP_CHAN_PROTO_VERSION;
2402
                                        otw_dir->id = htons(_dr_id++);
2403
                                        otw_dir->cmd = GDP_CMD_DIR_DELETE;
2404 e7fa3577 Rick Pratt
                                        memcpy(otw_dir->eguid[0], otw_gdp->src, sizeof(gdp_name_t));
2405 87645eb1 Rick Pratt
                                        memcpy(otw_dir->dguid, otw_gdp->dst, sizeof(gdp_name_t));
2406
                                        datagram_tx(_fd_directory, dp, nullptr, 0);
2407
                                        ccdbg(DVERB, "(%d)%s map withdraw tx id 0x%x\n"
2408
                                                  "\teguid[%s]\n"
2409
                                                  "\tdguid[%s]",
2410
                                                  fd, fd_to_state_name(fd),
2411
                                                  ntohs(otw_dir->id),
2412 e7fa3577 Rick Pratt
                                                  gdp_printable_name(otw_dir->eguid[0], _tmp_pname_1),
2413 87645eb1 Rick Pratt
                                                  gdp_printable_name(otw_dir->dguid, _tmp_pname_2));
2414
                                        dp->kill();
2415
                                }
2416 7c97363d Rick Pratt
                        }
2417 bd851bdd Rick Pratt
                        
2418 7c97363d Rick Pratt
                        // ADDR_NHOP owns one map, so detach map from fd and recycle
2419 2c4eab43 Rick Pratt
                        fd_detach_map(dguid_dmi->second.fd, dguid_dmi);
2420 acabfa65 Rick Pratt
                        dst_map_recycle(dguid_dmi->second.fd, dguid_dmi);
2421 bd851bdd Rick Pratt
                }
2422
                
2423 7c97363d Rick Pratt
                // diagnostics
2424 33571b36 Rick Pratt
                display_state(fd);
2425 bd851bdd Rick Pratt
        }
2426 62a58ed2 Rick Pratt
2427 60d15dbb Rick Pratt
        // recycle withdraw p (net4 not sending multi-withdraw pdus, so pedantic)
2428
        p_chain_recycle(p);
2429 62a58ed2 Rick Pratt
}
2430
2431
void
2432
GDPv4Router::directory_rx (int fd)
2433
{
2434
        WritablePacket *dp;
2435
        ssize_t recv_len;
2436
        otw_dir_t *otw_dir;
2437 4b971df6 Rick Pratt
        otw_dir_t *otw_adv;
2438 62a58ed2 Rick Pratt
        gdp_pname_t _tmp_pname_1;
2439
        gdp_pname_t _tmp_pname_2;
2440
        gdp_name_ca_t *dguid_ca;
2441 2c4eab43 Rick Pratt
        dst_map_it_t dguid_dmi;
2442 bd851bdd Rick Pratt
        gdp_name_ca_t *eguid_ca;
2443 2c4eab43 Rick Pratt
        dst_map_it_t eguid_dmi;
2444 bd851bdd Rick Pratt
        int fd_eguid;
2445 62a58ed2 Rick Pratt
        wpl_it_t wpl_it;
2446
        otw_dir_t *or_otw_dir;
2447
2448 6706c770 Rick Pratt
        ccdbg(DVVERB, "(%d)%s directory rx", fd, fd_to_state_name(fd));
2449 acabfa65 Rick Pratt
        
2450 62a58ed2 Rick Pratt
        dp = Packet::make(sizeof(otw_dir_t));
2451 bd851bdd Rick Pratt
        if (dp == nullptr)
2452
        {
2453
                ccwarn("(%d)%s packet pool exhausted on %d",
2454
                           fd, fd_to_state_name(fd), sizeof(otw_dir_t));
2455
                return;
2456
        }
2457 62a58ed2 Rick Pratt
        
2458
        // rx packet
2459
        recv_len = recv(fd, dp->data(), dp->length(), 0);
2460
        if (recv_len < 0)
2461
        {
2462
                switch (errno)
2463
                {
2464 bd851bdd Rick Pratt
2465 62a58ed2 Rick Pratt
                case EAGAIN:
2466
                case EINTR:
2467 bd851bdd Rick Pratt
                {
2468 4ded8992 Eric Allman
                        ccdbg(DINFO, "(%d)%s rx p %p len %d errno %d",
2469 cdaf995a Rick Pratt
                                   fd, fd_to_state_name(fd), dp, recv_len, errno);
2470 bd851bdd Rick Pratt
                }
2471
                break;
2472
2473
                case ECONNREFUSED:
2474
                {
2475
                        ccerr("(%d)%s rx connect refused (bad config||service down)",
2476
                                  fd, fd_to_state_name(fd), dp, recv_len, errno);
2477
                        _fd_directory_status = -1;
2478
                }
2479
                break;
2480
2481 62a58ed2 Rick Pratt
                default:
2482 bd851bdd Rick Pratt
                {
2483
                        ccerr("(%d)%s rx p %p len %d errno %d",
2484 62a58ed2 Rick Pratt
                                  fd, fd_to_state_name(fd), dp, recv_len, errno);
2485
                }
2486 bd851bdd Rick Pratt
                break;
2487
2488
                } // switch
2489
2490
                dp->kill();
2491 62a58ed2 Rick Pratt
                return;
2492
        }
2493
2494 b9253176 Rick Pratt
        // update directory fd status
2495 bd851bdd Rick Pratt
        _fd_directory_status = 0;
2496
        
2497 62a58ed2 Rick Pratt
        // check packet short or version
2498 cdbccb0d Rick Pratt
        if (recv_len < (ssize_t) offsetof(otw_dir_t, eguid[1]) ||
2499 62a58ed2 Rick Pratt
                GDP_CHAN_PROTO_VERSION != *dp->data())
2500
        {
2501 bd851bdd Rick Pratt
                ccdbg(DVVERB, "(%d)%s rx unknown version or short len %d",
2502
                          fd, fd_to_state_name(fd), recv_len);
2503 62a58ed2 Rick Pratt
                dp->kill();
2504
                return;
2505
        }
2506
2507
        // otw packed structure to access fields
2508
        otw_dir = (otw_dir_t *) dp->data();
2509 bd851bdd Rick Pratt
        
2510
        ccdbg(DVERB, "(%d)%s rx ver %d cmd %d id 0x%x len %d\n"
2511 4e5c5b6f Rick Pratt
                  "\teguid[%s]\n"
2512
                  "\tdguid[%s]",
2513 62a58ed2 Rick Pratt
                  fd, fd_to_state_name(fd),
2514 bd851bdd Rick Pratt
                  otw_dir->ver, otw_dir->cmd, ntohs(otw_dir->id), recv_len,
2515 e7fa3577 Rick Pratt
                  gdp_printable_name(otw_dir->eguid[0], _tmp_pname_1),
2516 4e5c5b6f Rick Pratt
                  gdp_printable_name(otw_dir->dguid, _tmp_pname_2));
2517 62a58ed2 Rick Pratt
2518 bd851bdd Rick Pratt
        // dp->kill() called at function end
2519 62a58ed2 Rick Pratt
        switch (otw_dir->cmd)
2520
        {
2521
2522
        case GDP_CMD_DIR_FIND:
2523
        {
2524
                // find dguid in map
2525
                dguid_ca = (gdp_name_ca_t *) otw_dir->dguid;
2526 2c4eab43 Rick Pratt
                dguid_dmi = dst_map.find(*dguid_ca);
2527
                if (dguid_dmi == dst_map.end())
2528 62a58ed2 Rick Pratt
                {
2529 bd851bdd Rick Pratt
                        ccdbg(DVERB, "(%d)%s rx id 0x%x no nhop, map not found\n"
2530
                                  "\tdguid[%s]",
2531
                                  fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2532 62a58ed2 Rick Pratt
                                  gdp_printable_name(otw_dir->dguid, _tmp_pname_1));
2533 bd851bdd Rick Pratt
                        break;
2534 62a58ed2 Rick Pratt
                }
2535
2536
                // map not interested in directory response
2537 2c4eab43 Rick Pratt
                if (dguid_dmi->second.addr_state != ADDR_FIND)
2538 62a58ed2 Rick Pratt
                {
2539 bd851bdd Rick Pratt
                        ccdbg(DVERB, "(%d)%s rx id 0x%x no nhop, map ignoring\n"
2540
                                  "\tdguid[%s]%s",
2541
                                  fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2542
                                  gdp_printable_name(otw_dir->dguid, _tmp_pname_1),
2543 2c4eab43 Rick Pratt
                                  addr_to_state_name(dguid_dmi->second.addr_state));
2544 bd851bdd Rick Pratt
                        break;
2545 62a58ed2 Rick Pratt
                }
2546
2547
                // ensure dir request id matches our request (always the first p)
2548 2c4eab43 Rick Pratt
                wpl_it = dguid_dmi->second.dplist.begin();
2549
                avow(wpl_it != dguid_dmi->second.dplist.end());
2550 da7bcbcb Rick Pratt
                avow(*wpl_it != nullptr);
2551 62a58ed2 Rick Pratt
                or_otw_dir = (otw_dir_t *) (*wpl_it)->data();
2552
                if (or_otw_dir->id != otw_dir->id) // no need to ntohs() both
2553
                {
2554 bd851bdd Rick Pratt
                        ccdbg(DVERB, "(%d)%s rx id 0x%x no nhop, id mismatch drop\n"
2555
                                  "\tdguid[%s]",
2556
                                  fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2557
                                  gdp_printable_name(otw_dir->dguid, _tmp_pname_1));
2558 62a58ed2 Rick Pratt
                        break;
2559
                }
2560
2561 4ded8992 Eric Allman
                ccdbg(DINFO, "(%d)%s rx id 0x%x not found\n"
2562 bd851bdd Rick Pratt
                           "\tdguid[%s]",
2563
                           fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2564
                           gdp_printable_name(otw_dir->dguid, _tmp_pname_1));
2565 2c4eab43 Rick Pratt
                map_no_route(fd, dguid_dmi);
2566 acabfa65 Rick Pratt
                dst_map_recycle(fd, dguid_dmi);
2567
                // dguid_dmi is invalid after dst_map_recycle
2568 2c4eab43 Rick Pratt
                dguid_dmi = dst_map.end();
2569 b9253176 Rick Pratt
2570
                // diagnostics
2571 33571b36 Rick Pratt
                display_state(fd);
2572 62a58ed2 Rick Pratt
        }
2573
        break;
2574
        
2575
        case GDP_CMD_DIR_FOUND:
2576
        {
2577
                // find dguid in map
2578
                dguid_ca = (gdp_name_ca_t *) otw_dir->dguid;
2579 2c4eab43 Rick Pratt
                dguid_dmi = dst_map.find(*dguid_ca);
2580
                if (dguid_dmi == dst_map.end())
2581 62a58ed2 Rick Pratt
                {
2582 bd851bdd Rick Pratt
                        ccdbg(DVERB, "(%d)%s rx id 0x%x nhop found, map not found\n"
2583
                                  "\tdguid[%s]",
2584
                                  fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2585 62a58ed2 Rick Pratt
                                  gdp_printable_name(otw_dir->dguid, _tmp_pname_1));
2586 bd851bdd Rick Pratt
                        break;
2587 62a58ed2 Rick Pratt
                }
2588
2589
                // map not interested in directory response
2590 2c4eab43 Rick Pratt
                if (dguid_dmi->second.addr_state != ADDR_FIND)
2591 62a58ed2 Rick Pratt
                {
2592 bd851bdd Rick Pratt
                        ccdbg(DVERB, "(%d)%s rx id 0x%x nhop found, map ignoring\n"
2593
                                  "\tdguid[%s]%s",
2594
                                  fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2595
                                  gdp_printable_name(otw_dir->dguid, _tmp_pname_1),
2596 2c4eab43 Rick Pratt
                                  addr_to_state_name(dguid_dmi->second.addr_state));
2597 bd851bdd Rick Pratt
                        break;
2598 62a58ed2 Rick Pratt
                }
2599
2600
                // ensure dir request id matches our request (always the first p)
2601 2c4eab43 Rick Pratt
                wpl_it = dguid_dmi->second.dplist.begin();
2602
                avow(wpl_it != dguid_dmi->second.dplist.end());
2603 da7bcbcb Rick Pratt
                avow(*wpl_it != nullptr);
2604 62a58ed2 Rick Pratt
                or_otw_dir = (otw_dir_t *) (*wpl_it)->data();
2605
                if (or_otw_dir->id != otw_dir->id) // no need to ntohs() both
2606
                {
2607 bd851bdd Rick Pratt
                        ccdbg(DVERB, "(%d)%s rx id 0x%x nhop found, id mismatch drop\n"
2608
                                  "\tdguid[%s]",
2609
                                  fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2610
                                  gdp_printable_name(otw_dir->dguid, _tmp_pname_1));
2611 62a58ed2 Rick Pratt
                        break;
2612
                }
2613
2614 bd851bdd Rick Pratt
                ccdbg(DVERB, "(%d)%s rx id 0x%x nhop found\n"
2615 4e5c5b6f Rick Pratt
                          "\teguid[%s]\n"
2616 bd851bdd Rick Pratt
                          "\tdguid[%s]",
2617
                          fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2618 e7fa3577 Rick Pratt
                          gdp_printable_name(otw_dir->eguid[0], _tmp_pname_1),
2619 4e5c5b6f Rick Pratt
                          gdp_printable_name(otw_dir->dguid, _tmp_pname_2));
2620 62a58ed2 Rick Pratt
2621
                // find eguid's fd in map
2622 e7fa3577 Rick Pratt
                eguid_ca = (gdp_name_ca_t *) otw_dir->eguid[0];
2623 2c4eab43 Rick Pratt
                eguid_dmi = dst_map.find(*eguid_ca);
2624
                if (eguid_dmi == dst_map.end())
2625 4e5c5b6f Rick Pratt
                {
2626 7c97363d Rick Pratt
                        ccwarn("(%d)%s nhop no egress and no p memory, erase map\n"
2627
                                   "\teguid[%s]\n"
2628
                                   "\tdguid[%s]",
2629
                                   fd, fd_to_state_name(fd),
2630 e7fa3577 Rick Pratt
                                   gdp_printable_name(otw_dir->eguid[0], _tmp_pname_1),
2631 7c97363d Rick Pratt
                                   gdp_printable_name(otw_dir->dguid, _tmp_pname_2));
2632 2c4eab43 Rick Pratt
                        map_no_route(fd, dguid_dmi);
2633 acabfa65 Rick Pratt
                        dst_map_recycle(fd, dguid_dmi);
2634
                        break;
2635 62a58ed2 Rick Pratt
                }
2636 2c4eab43 Rick Pratt
                aver(eguid_dmi->second.addr_state != ADDR_MINE);
2637
                fd_eguid = eguid_dmi->second.fd;
2638 bd851bdd Rick Pratt
                ccdbg(DVERB, "(%d)%s nhop egress\n"
2639 acabfa65 Rick Pratt
                          "\teguid[%s]%s @ (%d)%s",
2640 62a58ed2 Rick Pratt
                          fd, fd_to_state_name(fd),
2641 e7fa3577 Rick Pratt
                          gdp_printable_name(otw_dir->eguid[0], _tmp_pname_1),
2642 2c4eab43 Rick Pratt
                          addr_to_state_name(eguid_dmi->second.addr_state),
2643 62a58ed2 Rick Pratt
                          fd_eguid, fd_to_state_name(fd_eguid));
2644
2645
                // fd tracks related map entries
2646 2c4eab43 Rick Pratt
                (*_fdv)[fd_eguid].dst_mil.push_back(dguid_dmi);
2647 bd851bdd Rick Pratt
                ccdbg(DVVERB, "(%d)%s nhop egress (%d)%s push map\n"
2648
                          "\tdguid[%s]",
2649 62a58ed2 Rick Pratt
                          fd, fd_to_state_name(fd),
2650
                          fd_eguid, fd_to_state_name(fd_eguid),
2651
                          gdp_printable_name(otw_dir->dguid, _tmp_pname_1));
2652 b9253176 Rick Pratt
2653 62a58ed2 Rick Pratt
                // dguid reached via eguid fd (replaces cguid's fd placeholder)
2654 2c4eab43 Rick Pratt
                dguid_dmi->second.fd = fd_eguid;
2655
                dguid_dmi->second.addr_state = ADDR_NHOP;
2656 bd851bdd Rick Pratt
2657
                // replace addr_find_timer with addr_nhop_timer
2658 2c4eab43 Rick Pratt
                dguid_dmi->second.map_timer->assign(static_addr_nhop_timer,
2659
                                                                                        dguid_dmi->second.map_timer_dmip);
2660
                dguid_dmi->second.map_timer->schedule_after(ADDR_NHOP_TS_DELTA);
2661 bd851bdd Rick Pratt
                ccdbg(DVVERB, "(%d)%s addr find timer reassigned to nhop %p %p",
2662
                          fd_eguid, fd_to_state_name(fd_eguid),
2663 2c4eab43 Rick Pratt
                          dguid_dmi->second.map_timer, dguid_dmi->second.map_timer_dmip);
2664 bd851bdd Rick Pratt
2665 4ded8992 Eric Allman
                ccdbg(DINFO, "(%d)%s rx id 0x%x found\n"
2666 b9253176 Rick Pratt
                           "\tdguid[%s]%s via\n"
2667
                           "\teguid[%s]%s on (%d)%s",
2668
                           fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2669
                           gdp_printable_name(otw_dir->dguid, _tmp_pname_1),
2670 2c4eab43 Rick Pratt
                           addr_to_state_name(dguid_dmi->second.addr_state),
2671 e7fa3577 Rick Pratt
                           gdp_printable_name(otw_dir->eguid[0], _tmp_pname_2),
2672 2c4eab43 Rick Pratt
                           addr_to_state_name(eguid_dmi->second.addr_state),
2673 b9253176 Rick Pratt
                           fd_eguid, fd_to_state_name(fd_eguid));
2674
2675
                // diagnostics
2676 33571b36 Rick Pratt
                display_state(fd_eguid);
2677 62a58ed2 Rick Pratt
                
2678 bd851bdd Rick Pratt
                // delete stored dir request and list element
2679 62a58ed2 Rick Pratt
                ccdbg(DVVERB, "(%d)%s recycle dir p %p next %p prev %p",
2680
                          fd, fd_to_state_name(fd),
2681
                          (*wpl_it), (*wpl_it)->next(), (*wpl_it)->prev());
2682
                (*wpl_it)->kill();
2683 2c4eab43 Rick Pratt
                wpl_it = dguid_dmi->second.dplist.erase(wpl_it);
2684 62a58ed2 Rick Pratt
2685
                // tx pending p
2686 2c4eab43 Rick Pratt
                while (wpl_it != dguid_dmi->second.dplist.end())
2687 62a58ed2 Rick Pratt
                {
2688 2c4eab43 Rick Pratt
                        map_route(fd, dguid_dmi, *wpl_it);
2689 62a58ed2 Rick Pratt
2690 bd851bdd Rick Pratt
                        // p moved out, so erase list element
2691 2c4eab43 Rick Pratt
                        wpl_it = dguid_dmi->second.dplist.erase(wpl_it);
2692 bd851bdd Rick Pratt
                }
2693
        }
2694
        break;
2695
2696
        case GDP_CMD_DIR_ADD:
2697
        {
2698
                ccdbg(DVERB, "(%d)%s rx id 0x%x add ack\n"
2699 4b971df6 Rick Pratt
                          "\teguid[%s]\n"
2700 bd851bdd Rick Pratt
                          "\tdguid[%s]",
2701
                          fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2702 4b971df6 Rick Pratt
                          gdp_printable_name(otw_dir->eguid[0], _tmp_pname_1),
2703
                          gdp_printable_name(otw_dir->dguid, _tmp_pname_2));
2704 bd851bdd Rick Pratt
2705 4b971df6 Rick Pratt
                // gdpc location depends on advert type (src == dst vs not)
2706
                if (memcmp(_gdpr, otw_dir->eguid[0], sizeof(gdp_name_t)) == 0)
2707 bd851bdd Rick Pratt
                {
2708 4b971df6 Rick Pratt
                        dguid_ca = (gdp_name_ca_t *) otw_dir->dguid;
2709
                }
2710
                else
2711
                {
2712
                        dguid_ca = (gdp_name_ca_t *) otw_dir->eguid[0];
2713 bd851bdd Rick Pratt
                }
2714
2715 4b971df6 Rick Pratt
                // find dguid map
2716
                dguid_dmi = dst_map.find(*dguid_ca);
2717
                if (dguid_dmi != dst_map.end())
2718 bd851bdd Rick Pratt
                {
2719 4b971df6 Rick Pratt
                        // adverts awaiting ack are always near the front of dplist
2720
                        wpl_it = dguid_dmi->second.dplist.begin();
2721
                        while (wpl_it != dguid_dmi->second.dplist.end())
2722 bd851bdd Rick Pratt
                        {
2723 4b971df6 Rick Pratt
                                otw_adv = (otw_dir_t *) (*wpl_it)->data();
2724
                                ccdbg(DVVERB, "walk dp %p id 0x%x",
2725
                                          *wpl_it, ntohs(otw_adv->id));
2726
                                // match ack to advert by id
2727
                                if (otw_dir->id == otw_adv->id)
2728
                                {
2729
                                        (*wpl_it)->kill();
2730
                                        dguid_dmi->second.dplist.erase(wpl_it);
2731
                                        ++dguid_dmi->second.dp_acks;
2732
                                        ccdbg(DVVERB, "walk matched");
2733
                                        break;
2734
                                }
2735
                                // count each lost p once per addr_gdpc_timer interval
2736
                                if (RETRIES_ANNO(*wpl_it))
2737
                                {
2738
                                        // clear anno to trigger retx by addr_gdpc_timer
2739
                                        SET_RETRIES_ANNO(*wpl_it, 0);
2740
                                        // transfer p from front to back (not awaiting ack)
2741
                                        dguid_dmi->second.dplist.push_back(*wpl_it);
2742
                                        // erase front container after p move, implicit ++wpl_it
2743
                                        wpl_it = dguid_dmi->second.dplist.erase(wpl_it);
2744
                                        // track losses for addr_gdpc_timer eval
2745
                                        ++dguid_dmi->second.dp_loss;
2746
                                }
2747
                                else
2748
                                {
2749
                                        ++wpl_it;
2750
                                }
2751 bd851bdd Rick Pratt
                        }
2752 4b971df6 Rick Pratt
                        ccdbg(DVVERB, "walk done, moved %d", dguid_dmi->second.dp_loss);
2753 bd851bdd Rick Pratt
                }
2754
        }
2755
        break;
2756
2757
        case GDP_CMD_DIR_DELETE:
2758
        {
2759
                ccdbg(DVERB, "(%d)%s rx id 0x%x delete ack\n"
2760
                          "\tdguid[%s]",
2761
                          fd, fd_to_state_name(fd), ntohs(otw_dir->id),
2762
                          gdp_printable_name(otw_dir->dguid, _tmp_pname_1));
2763
        }
2764
        break;
2765
2766
        default:
2767
        {
2768
                ccdbg(DVVERB, "(%d)%s rx id 0x%x unexpected cmd %d, drop\n",
2769
                          fd, fd_to_state_name(fd), ntohs(otw_dir->id), otw_dir->cmd);
2770