From d11b6f06f8d606266a76c28a63ba24e8837fda3d Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 2 Feb 2017 13:29:18 +0100 Subject: [PATCH 01/51] README.md [MAINTENANCE]: content revised --- README.md | 58 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index ee8bda4..8634d37 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,58 @@ -# Classbench - -Utility for generation of firewall/OpenFlow rules based on original (no longer maintained) [Classbench](http://www.arl.wustl.edu/classbench/). +# ClassBench-ng +A tool for generation of synthetic classification rule sets for benchmarking, which is based on original (no longer maintained) [ClassBench](http://www.arl.wustl.edu/classbench/). +Format of the generated rules can be one of the following: +- IPv4 5-tuple +- IPv6 5-tuple +- OpenFlow ## Requirements - Ruby 1.9.3+ - RubyGems - ``` sudo gem install open4 ruby-ip docopt ipaddress ``` ## Installation ``` -git clone https://github.com/lucansky/classbench-ng.git -make # Downloads, patches and compiles db_generator in ./vendor/db_generator/db_generator +git clone https://github.com/classbench-ng/classbench-ng.git +make # Downloads, patches and compiles db_generator in ./vendor/db_generator ``` -### Patching classbench -Due to statically initialized arrays in ClassBench, patching is required which increases the limit. -Patch is automatically applied by make in process of downloading ClassBench. -(see vendor/Makefile) +### Patching ClassBench +Original ClassBench is improved using patches in `./patches` directory and the size of its statically initialized arrays is increased, where necessary. +These changes are automatically applied on downloaded ClassBench during ClassBench-ng installation (see `./vendor/Makefile`). ## Usage ``` ./classbench analyse FILE ``` -Analyses file, expecting FILE to be ovs-ofctl dump. -Fields extracted from dump are: -- dl_dst, dl_src, dl_type, dl_vlan, dl_vlan_pcp, -- eth_type, in_port, -- nw_dst, nw_proto, nw_src, nw_tos, -- tp_dst, tp_src +Analyses FILE, expecting FILE to be in the format used by `ovs-ofctl`. +Fields extracted from FILE are: +- in_port +- dl_src, dl_dst, eth_type, dl_vlan, dl_vlan_pcp +- nw_src, nw_dst, nw_tos, nw_proto, +- tp_src, tp_dst -Output's original Classbench seed with openflow YAML structure as last section. +The output is an original ClassBench seed with an OpenFlow YAML structure as the last section. ``` -./classbench generate v4 SEED [--count=100] [--db-generator=] +./classbench generate v4 SEED [--count=] [--db-generator=] ``` -Generates --count of OpenFlow rules. -If seed without OpenFlow section is provided, regular 5-tuples are generated. -Output format is "attribute=value", joined by ", ". +Generates IPv4 5-tuples or OpenFlow rules following properties from SEED. +OpenFlow rules are generated only if SEED contains OpenFlow section. +- `--count=` specifies the number of generated 5-tuples/rules (default: `100`) +- `--db-generator=` specifies path to a ClassBench binary (default: `./vendor/db_generator/db_generator`) + +The output consists of `attribute=value` pairs joined by `, `. +``` +./classbench generate v6 [--count=] +``` +Generates IPv6 5-tuples rules following properties from SEED. +- `--count=` specifies the number of generated 5-tuples (default: `100`) + +The output consists of `attribute=value` pairs joined by `, `. + +``` +./classbench -h | --help +``` +Prints deatiled usage information. From 9461b9cfd57b68b25884bf9f4cadca3c61155a21 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 2 Feb 2017 13:33:08 +0100 Subject: [PATCH 02/51] vendor/Makefile [MAINTENANCE]: increasing the size of static arrays as a part of 'patch' target --- vendor/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vendor/Makefile b/vendor/Makefile index 17217dd..40238a6 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -13,10 +13,11 @@ patch: download # Apply patches from ../patches git apply --directory=vendor/db_generator ../patches/ipv6.patch -compile: patch # Patching PortList (extension of preallocated array is necessary) # Raise limit of L5 rules from 200 to 20000. sed -i 's/200/20000/' db_generator/PortList.h +compile: patch + # Recurse to ClassBench compilation make -C db_generator -B db_generator From 08f83e113ede1a050b5aef4a477e98e6677aad05 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 2 Feb 2017 13:42:52 +0100 Subject: [PATCH 03/51] seeds [FEATURE]: OpenFlow seeds of rule sets used in the ClassBench-ng paper --- seeds/of1_seed | 476 +++ seeds/of2_seed | 8656 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 9132 insertions(+) create mode 100644 seeds/of1_seed create mode 100644 seeds/of2_seed diff --git a/seeds/of1_seed b/seeds/of1_seed new file mode 100644 index 0000000..d8de126 --- /dev/null +++ b/seeds/of1_seed @@ -0,0 +1,476 @@ +-scale +13778 +# +-prots +0 0.3103498330672086 0.9679607109448082 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.032039289055191766 +17 0.2551894324285092 0.6968145620022753 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.3031854379977247 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +6 0.25243141239657424 0.7044278320874066 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.29557216791259344 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +1 0.18202932210770795 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +# +-flags +0 0x0000/0x0000,1.00000000 +17 0x0000/0x0000,1.00000000 +6 0x0000/0x0000,1.00000000 +1 0x0000/0x0000,1.00000000 +# +-extra +0 +# +-spar +# +-spem +0.9197080291970803 67:67 +0.0364963503649635 2888:2888 +0.0072992700729927005 443:443 +0.0364963503649635 22:22 +# +-dpar +# +-dpem +0.05199462124607799 8192:8192 +0.05199462124607799 1:1 +0.05199462124607799 2048:2048 +0.005378753922008068 61440:61440 +0.005378753922008068 57344:57344 +0.05199462124607799 4096:4096 +0.05199462124607799 256:256 +0.005378753922008068 65024:65024 +0.05199462124607799 4:4 +0.05199462124607799 64:64 +0.005378753922008068 65408:65408 +0.05199462124607799 8:8 +0.005378753922008068 65520:65520 +0.05199462124607799 16384:16384 +0.03182429403854774 67:67 +0.005378753922008068 65532:65532 +0.05199462124607799 2:2 +0.05199462124607799 32768:32768 +0.05199462124607799 16:16 +0.05199462124607799 1024:1024 +0.005378753922008068 63488:63488 +0.04885701479157328 68:68 +0.05199462124607799 32:32 +0.005378753922008068 65528:65528 +0.005378753922008068 65472:65472 +0.005378753922008068 49152:49152 +0.05199462124607799 128:128 +0.005378753922008068 65280:65280 +0.05199462124607799 512:512 +0.005378753922008068 64512:64512 +0.005378753922008068 65504:65504 +0.0017929179740026895 443:443 +0.0017929179740026895 8443:8443 +0.005378753922008068 65534:65534 +0.0017929179740026895 22:22 +0.0017929179740026895 3389:3389 +0.00044822949350067237 45518:45518 +0.00044822949350067237 45530:45530 +0.00044822949350067237 40502:40502 +0.00044822949350067237 45527:45527 +0.00044822949350067237 45521:45521 +0.00044822949350067237 35008:35008 +0.00044822949350067237 45524:45524 +0.00044822949350067237 38356:38356 +0.00044822949350067237 57929:57929 +0.00044822949350067237 38352:38352 +0.00044822949350067237 38365:38365 +# +-wc_wc +64,0.9994803845154585 32,1.0 +40,8.660258075690655e-05 32,1.0 +56,8.660258075690655e-05 24,1.0 +55,8.660258075690655e-05 23,1.0 +62,8.660258075690655e-05 30,1.0 +36,8.660258075690655e-05 4,1.0 +52,8.660258075690655e-05 20,1.0 +# +-wc_hi +# +-hi_wc +# +-hi_hi +# +-wc_lo +# +-lo_wc +# +-hi_lo +# +-lo_hi +# +-lo_lo +# +-wc_ar +# +-ar_wc +# +-hi_ar +# +-ar_hi +# +-wc_em +64,1.0 32,1.0 +# +-em_wc +# +-hi_em +# +-em_hi +# +-lo_ar +# +-ar_lo +# +-lo_em +# +-em_lo +# +-ar_ar +# +-ar_em +# +-em_ar +# +-em_em +64,1.0 32,1.0 +# +-snest +1 +# +-sskew +0 0.0 1.0 0.9545500251382605 +1 0.0 1.0 0.5359929339025468 +2 0.0 1.0 0.9880907752041772 +3 0.75 0.25 0.9747003994673769 +4 0.8 0.2 0.6956144159791576 +5 0.8333333333333334 0.16666666666666666 0.9832229580573951 +6 0.7142857142857143 0.2857142857142857 0.6842970166652276 +7 0.7777777777777778 0.2222222222222222 0.7461365099806825 +8 0.9 0.1 0.9967700258397932 +9 0.8181818181818182 0.18181818181818182 0.9690445516809689 +10 1.0 0.0 0.0 +11 1.0 0.0 0.0 +12 0.9230769230769231 0.07692307692307693 0.7176470588235294 +13 0.8571428571428571 0.14285714285714285 0.6678082191780822 +14 1.0 0.0 0.0 +15 1.0 0.0 0.0 +16 0.9375 0.0625 0.9976069398743643 +17 1.0 0.0 0.0 +18 0.8235294117647058 0.17647058823529413 0.49452782989368355 +19 0.85 0.15 0.49063710872296934 +20 0.9565217391304348 0.043478260869565216 0.7818181818181819 +21 0.7916666666666666 0.20833333333333334 0.748101963356065 +22 0.7586206896551724 0.2413793103448276 0.6276331456287173 +23 0.6111111111111112 0.3888888888888889 0.49384178996279193 +24 0.62 0.38 0.3075823236773248 +25 0.5757575757575758 0.42424242424242425 0.23646709280295494 +26 0.5425531914893617 0.4574468085106383 0.18149615429139418 +27 0.49635036496350365 0.5036496350364964 0.13074395855860385 +28 0.2807017543859649 0.7192982456140351 0.38317258552895755 +29 0.35051546391752575 0.6494845360824743 0.3448024522585926 +30 0.49375 0.50625 0.22833426861204636 +31 0.6569037656903766 0.34309623430962344 0.04181184668989549 +32 0.0 0.0 0.0 +# +-dnest +2 +# +-dskew +0 0.0 1.0 0.027447698744769822 +1 0.0 1.0 0.26004659289458354 +2 0.5 0.5 0.9992122883024813 +3 0.3333333333333333 0.6666666666666666 0.48807394156231365 +4 0.75 0.25 0.950891460744448 +5 0.6 0.4 0.9697815500620608 +6 0.8571428571428571 0.14285714285714285 0.9450511945392491 +7 0.875 0.125 0.10588235294117643 +8 0.8888888888888888 0.1111111111111111 0.9375 +9 0.8 0.2 0.9489707434776052 +10 1.0 0.0 0.0 +11 1.0 0.0 0.0 +12 1.0 0.0 0.0 +13 0.9166666666666666 0.08333333333333333 0.012987012987012991 +14 1.0 0.0 0.0 +15 1.0 0.0 0.0 +16 0.9230769230769231 0.07692307692307693 0.7102803738317758 +17 0.8571428571428571 0.14285714285714285 0.43175287356321834 +18 0.625 0.375 0.4813902218940979 +19 0.6818181818181818 0.3181818181818182 0.47424064275916133 +20 0.6071428571428571 0.39285714285714285 0.4404761904761905 +21 0.7692307692307693 0.23076923076923078 0.5677248677248677 +22 0.8958333333333334 0.10416666666666667 0.6551219512195121 +23 0.7924528301886793 0.20754716981132076 0.4103077091547137 +24 0.8125 0.1875 0.38967230944842884 +25 0.8947368421052632 0.10526315789473684 0.2707473635946813 +26 0.8809523809523809 0.11904761904761904 0.2 +27 0.9148936170212766 0.0851063829787234 0.23967470760233917 +28 1.0 0.0 0.0 +29 1.0 0.0 0.0 +30 0.9285714285714286 0.07142857142857142 0.5 +31 1.0 0.0 0.0 +32 0.0 0.0 0.0 +# +-pcorr +1 0.0 +2 0.0 +3 0.0 +4 0.0 +5 0.0 +6 0.0 +7 0.0 +8 0.0 +9 0.0 +10 0.0 +11 0.0 +12 0.0 +13 0.0 +14 0.0 +15 0.0 +16 0.0 +17 0.0 +18 0.0 +19 0.0 +20 0.0 +21 0.0 +22 0.0 +23 0.0 +24 0.0 +25 0.0 +26 0.0 +27 0.0 +28 0.0 +29 0.0 +30 0.0 +31 0.0 +32 0.0 +# +-openflow +--- +in_port: + '71': 2 + '50': 2 + '393': 2 + '471': 2 + '249': 2 + '308': 2 + '180': 2 + '522': 2 + '81': 2 + '69': 2 + '70': 2 + '360': 2 + '1': 2 + '269': 2 + '173': 2 + '470': 2 + '310': 2 + '289': 2 + '521': 2 + '37554': 1 + '37618': 1 + '37742': 1 + '37653': 1 + '37553': 1 + '37677': 1 + '37612': 1 + '37702': 1 + '37715': 1 + '37607': 1 + '37660': 1 + '37598': 1 + '37670': 1 + '37703': 1 + '37640': 1 + '37672': 1 + '37696': 1 + '37597': 1 + '36736': 1 + '37737': 1 + '37621': 1 + '37225': 1 + '37690': 1 + '37562': 1 + '37680': 1 + '37617': 1 + '36697': 1 + '37555': 1 + '37716': 1 + '37611': 1 + '37561': 1 + '37581': 1 + '37663': 1 + '37714': 1 + '36666': 1 + '36464': 1 + '37606': 1 + '37681': 1 + '37605': 1 + '37748': 1 + '37616': 1 + '36662': 1 + '37725': 1 + '37664': 1 + '37700': 1 + '36717': 1 + '37548': 1 + '37719': 1 + '36803': 1 + '37710': 1 + '37673': 1 + '37676': 1 + '37587': 1 + '37651': 1 + '37659': 1 + '37685': 1 + '37602': 1 + '37579': 1 + '37600': 1 + '37620': 1 + '37614': 1 + '37695': 1 + '37648': 1 + '37549': 1 + '37736': 1 + '37705': 1 + '37678': 1 + '37662': 1 + '37622': 1 + '37665': 1 + '37642': 1 + '37720': 1 + '37722': 1 + '37655': 1 + '36646': 1 + '37713': 1 + '37744': 1 + '37647': 1 + '37686': 1 + '37727': 1 + '37563': 1 + '37738': 1 + '37080': 1 + '37550': 1 + '37552': 1 + '37675': 1 + '37583': 1 + '36361': 1 + '37551': 1 + '37646': 1 + '37656': 1 + '36658': 1 + '37545': 1 + '37601': 1 + '37643': 1 + '37657': 1 + '37560': 1 + '37084': 1 + '37741': 1 + '37743': 1 + '37585': 1 + '37556': 1 + '37683': 1 + '37688': 1 +eth_type: + '0x800': 9502 +dl_src: + fa:16:3e: 838 +dl_dst: + 01:80:c2: 1 + 01:00:0c: 4 + 00:e0:2b: 3 + fa:16:3e: 12534 + ff:ff:ff: 6 + '01:00:00': 85 + c2:81:09: 15 + '00:00:00': 2 +unique_vlan_ids_count: 0 +empty_rules_count: 3190 +rule_distribution: +- attributes: + - dl_dst + count: 1016 +- attributes: + - in_port + count: 142 +- attributes: + - dl_src + - eth_type + - nw_proto + - nw_src + - tp_dst + count: 384 +- attributes: + - dl_dst + - nw_dst + count: 180 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + - tp_dst + count: 1710 +- attributes: + - nw_src + count: 3 +- attributes: + - nw_dst + - tp_dst + - tp_src + count: 71 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + - nw_src + count: 7224 +- attributes: + - nw_dst + count: 81 +- attributes: + - dl_dst + - nw_dst + - tp_dst + - tp_src + count: 54 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + count: 46 +- attributes: + - dl_dst + - nw_dst + - nw_src + count: 2408 +- attributes: + - dl_src + count: 81 +- attributes: + - dl_src + - nw_src + count: 228 +- attributes: + - dl_src + - eth_type + - nw_proto + - nw_src + count: 138 +- attributes: + - dl_dst + - dl_src + - nw_dst + - nw_src + - tp_dst + - tp_src + count: 7 +- attributes: + - dl_dst + - nw_dst + - nw_src + - tp_dst + - tp_src + count: 5 +# diff --git a/seeds/of2_seed b/seeds/of2_seed new file mode 100644 index 0000000..ddb2b90 --- /dev/null +++ b/seeds/of2_seed @@ -0,0 +1,8656 @@ +-scale +16431 +# +-prots +0 0.7094516462783762 0.2838637728403534 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.7161362271596465 +17 0.09822895745846266 0.8736059479553904 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.12639405204460966 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +6 0.10553222567098777 0.8131487889273357 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.18685121107266436 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +1 0.08678717059217333 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +# +-flags +0 0x0000/0x0000,1.00000000 +17 0x0000/0x0000,1.00000000 +6 0x0000/0x0000,1.00000000 +1 0x0000/0x0000,1.00000000 +# +-extra +0 +# +-spar +# +-spem +0.018806899856252994 67:67 +0.9808337326305702 445:445 +0.00023957834211787255 443:443 +0.00011978917105893628 2049:2049 +# +-dpar +# +-dpem +0.0027039206849932404 2048:2048 +0.0009013068949977468 61440:61440 +0.0027039206849932404 4096:4096 +0.001013970256872465 57344:57344 +0.0027039206849932404 256:256 +0.0009013068949977468 65024:65024 +0.0027039206849932404 64:64 +0.0009013068949977468 65408:65408 +0.0027039206849932404 8:8 +0.0009013068949977468 65520:65520 +0.015434880576836413 67:67 +0.0027039206849932404 2:2 +0.0009013068949977468 65532:65532 +0.004506534474988734 68:68 +0.0027039206849932404 1024:1024 +0.0009013068949977468 63488:63488 +0.0027039206849932404 4:4 +0.0009013068949977468 65528:65528 +0.0027039206849932404 32:32 +0.0009013068949977468 65472:65472 +0.0009013068949977468 49152:49152 +0.0027039206849932404 8192:8192 +0.0027039206849932404 128:128 +0.0009013068949977468 65280:65280 +0.0028165840468679587 32768:32768 +0.0027039206849932404 16384:16384 +0.0027039206849932404 16:16 +0.0009013068949977468 65504:65504 +0.0027039206849932404 512:512 +0.0009013068949977468 64512:64512 +0.0009013068949977468 65534:65534 +0.0027039206849932404 1:1 +0.0004506534474988734 22:22 +0.0004506534474988734 3389:3389 +0.0004506534474988734 443:443 +0.00011266336187471834 34719:34719 +0.00011266336187471834 57768:57768 +0.00011266336187471834 56047:56047 +0.00011266336187471834 60616:60616 +0.00011266336187471834 59836:59836 +0.00011266336187471834 56178:56178 +0.00011266336187471834 57143:57143 +0.00011266336187471834 34044:34044 +0.00011266336187471834 34905:34905 +0.00011266336187471834 59412:59412 +0.00011266336187471834 57743:57743 +0.00011266336187471834 59535:59535 +0.00011266336187471834 58303:58303 +0.00011266336187471834 56816:56816 +0.00011266336187471834 60760:60760 +0.00011266336187471834 60146:60146 +0.00011266336187471834 55614:55614 +0.00011266336187471834 34966:34966 +0.00011266336187471834 58060:58060 +0.00011266336187471834 32949:32949 +0.00011266336187471834 58394:58394 +0.00011266336187471834 56050:56050 +0.00011266336187471834 59598:59598 +0.00011266336187471834 59095:59095 +0.00011266336187471834 60219:60219 +0.00011266336187471834 59381:59381 +0.00011266336187471834 35540:35540 +0.00011266336187471834 34703:34703 +0.00011266336187471834 60722:60722 +0.00011266336187471834 35511:35511 +0.00011266336187471834 55996:55996 +0.00011266336187471834 55988:55988 +0.00011266336187471834 34426:34426 +0.00011266336187471834 60416:60416 +0.00011266336187471834 58102:58102 +0.00011266336187471834 33534:33534 +0.00011266336187471834 60693:60693 +0.00011266336187471834 56608:56608 +0.00011266336187471834 35545:35545 +0.00011266336187471834 34652:34652 +0.00011266336187471834 34488:34488 +0.00011266336187471834 60561:60561 +0.00011266336187471834 56479:56479 +0.00011266336187471834 59651:59651 +0.00011266336187471834 58208:58208 +0.00011266336187471834 60364:60364 +0.00011266336187471834 56424:56424 +0.00011266336187471834 59544:59544 +0.00011266336187471834 34438:34438 +0.00011266336187471834 33821:33821 +0.00011266336187471834 35393:35393 +0.00011266336187471834 60848:60848 +0.00011266336187471834 59063:59063 +0.00011266336187471834 57746:57746 +0.00011266336187471834 57899:57899 +0.00011266336187471834 57808:57808 +0.00011266336187471834 58412:58412 +0.00011266336187471834 58219:58219 +0.00011266336187471834 56996:56996 +0.00011266336187471834 57264:57264 +0.00011266336187471834 55949:55949 +0.00011266336187471834 60111:60111 +0.00011266336187471834 59508:59508 +0.00011266336187471834 33574:33574 +0.00011266336187471834 59245:59245 +0.00011266336187471834 58678:58678 +0.00011266336187471834 33361:33361 +0.00011266336187471834 59620:59620 +0.00011266336187471834 59390:59390 +0.00011266336187471834 58672:58672 +0.00011266336187471834 34066:34066 +0.00011266336187471834 56589:56589 +0.00011266336187471834 60012:60012 +0.00011266336187471834 56187:56187 +0.00011266336187471834 35483:35483 +0.00011266336187471834 34722:34722 +0.00011266336187471834 60574:60574 +0.00011266336187471834 57804:57804 +0.00011266336187471834 33948:33948 +0.00011266336187471834 59299:59299 +0.00011266336187471834 58986:58986 +0.00011266336187471834 34218:34218 +0.00011266336187471834 59821:59821 +0.00011266336187471834 56543:56543 +0.00011266336187471834 35475:35475 +0.00011266336187471834 60432:60432 +0.00011266336187471834 55842:55842 +0.00011266336187471834 57088:57088 +0.00011266336187471834 57197:57197 +0.00011266336187471834 58199:58199 +0.00011266336187471834 59639:59639 +0.00011266336187471834 60461:60461 +0.00011266336187471834 57549:57549 +0.00011266336187471834 59487:59487 +0.00011266336187471834 58932:58932 +0.00011266336187471834 35136:35136 +0.00011266336187471834 59715:59715 +0.00011266336187471834 58780:58780 +0.00011266336187471834 57479:57479 +0.00011266336187471834 56519:56519 +0.00011266336187471834 32873:32873 +0.00011266336187471834 59571:59571 +0.00011266336187471834 57456:57456 +0.00011266336187471834 58256:58256 +0.00011266336187471834 58229:58229 +0.00011266336187471834 56625:56625 +0.00011266336187471834 56219:56219 +0.00011266336187471834 57307:57307 +0.00011266336187471834 33091:33091 +0.00011266336187471834 57691:57691 +0.00011266336187471834 60293:60293 +0.00011266336187471834 57393:57393 +0.00011266336187471834 58776:58776 +0.00011266336187471834 60571:60571 +0.00011266336187471834 59371:59371 +0.00011266336187471834 58824:58824 +0.00011266336187471834 57123:57123 +0.00011266336187471834 56488:56488 +0.00011266336187471834 57488:57488 +0.00011266336187471834 34832:34832 +0.00011266336187471834 60216:60216 +0.00011266336187471834 59691:59691 +0.00011266336187471834 33462:33462 +0.00011266336187471834 35527:35527 +0.00011266336187471834 34540:34540 +0.00011266336187471834 57257:57257 +0.00011266336187471834 59298:59298 +0.00011266336187471834 34819:34819 +0.00011266336187471834 32998:32998 +0.00011266336187471834 60818:60818 +0.00011266336187471834 56036:56036 +0.00011266336187471834 34512:34512 +0.00011266336187471834 59649:59649 +0.00011266336187471834 57477:57477 +0.00011266336187471834 59248:59248 +0.00011266336187471834 58983:58983 +0.00011266336187471834 57201:57201 +0.00011266336187471834 58547:58547 +0.00011266336187471834 56711:56711 +0.00011266336187471834 59943:59943 +0.00011266336187471834 58684:58684 +0.00011266336187471834 57498:57498 +0.00011266336187471834 34229:34229 +0.00011266336187471834 33393:33393 +0.00011266336187471834 59779:59779 +0.00011266336187471834 35261:35261 +0.00011266336187471834 34150:34150 +0.00011266336187471834 57306:57306 +0.00011266336187471834 34814:34814 +0.00011266336187471834 58977:58977 +0.00011266336187471834 59358:59358 +0.00011266336187471834 57721:57721 +0.00011266336187471834 34038:34038 +0.00011266336187471834 60540:60540 +0.00011266336187471834 57979:57979 +0.00011266336187471834 34823:34823 +0.00011266336187471834 33674:33674 +0.00011266336187471834 60700:60700 +0.00011266336187471834 35544:35544 +0.00011266336187471834 60763:60763 +0.00011266336187471834 35403:35403 +0.00011266336187471834 34348:34348 +0.00011266336187471834 58430:58430 +0.00011266336187471834 35197:35197 +0.00011266336187471834 33902:33902 +0.00011266336187471834 59501:59501 +0.00011266336187471834 58844:58844 +0.00011266336187471834 34983:34983 +0.00011266336187471834 56145:56145 +0.00011266336187471834 58453:58453 +0.00011266336187471834 55864:55864 +0.00011266336187471834 33872:33872 +0.00011266336187471834 32952:32952 +0.00011266336187471834 56832:56832 +0.00011266336187471834 34143:34143 +0.00011266336187471834 34692:34692 +0.00011266336187471834 56129:56129 +0.00011266336187471834 60836:60836 +0.00011266336187471834 35331:35331 +0.00011266336187471834 34331:34331 +0.00011266336187471834 33933:33933 +0.00011266336187471834 60253:60253 +0.00011266336187471834 32801:32801 +0.00011266336187471834 59795:59795 +0.00011266336187471834 59230:59230 +0.00011266336187471834 33995:33995 +0.00011266336187471834 32874:32874 +0.00011266336187471834 34403:34403 +0.00011266336187471834 35518:35518 +0.00011266336187471834 34377:34377 +0.00011266336187471834 34801:34801 +0.00011266336187471834 34474:34474 +0.00011266336187471834 33235:33235 +0.00011266336187471834 33374:33374 +0.00011266336187471834 59050:59050 +0.00011266336187471834 59950:59950 +0.00011266336187471834 59570:59570 +0.00011266336187471834 33183:33183 +0.00011266336187471834 57998:57998 +0.00011266336187471834 58313:58313 +0.00011266336187471834 58591:58591 +0.00011266336187471834 59197:59197 +0.00011266336187471834 58690:58690 +0.00011266336187471834 58957:58957 +0.00011266336187471834 56854:56854 +0.00011266336187471834 55845:55845 +0.00011266336187471834 33285:33285 +0.00011266336187471834 56373:56373 +0.00011266336187471834 55926:55926 +0.00011266336187471834 58622:58622 +0.00011266336187471834 56101:56101 +0.00011266336187471834 60572:60572 +0.00011266336187471834 60747:60747 +0.00011266336187471834 33335:33335 +0.00011266336187471834 60728:60728 +0.00011266336187471834 60529:60529 +0.00011266336187471834 60876:60876 +0.00011266336187471834 59375:59375 +0.00011266336187471834 59219:59219 +0.00011266336187471834 57969:57969 +0.00011266336187471834 57135:57135 +0.00011266336187471834 35400:35400 +0.00011266336187471834 56286:56286 +0.00011266336187471834 58791:58791 +0.00011266336187471834 56126:56126 +0.00011266336187471834 59739:59739 +0.00011266336187471834 57976:57976 +0.00011266336187471834 57776:57776 +0.00011266336187471834 57491:57491 +0.00011266336187471834 57335:57335 +0.00011266336187471834 57063:57063 +0.00011266336187471834 58799:58799 +0.00011266336187471834 57892:57892 +0.00011266336187471834 60373:60373 +0.00011266336187471834 59400:59400 +0.00011266336187471834 34633:34633 +0.00011266336187471834 56410:56410 +0.00011266336187471834 60893:60893 +0.00011266336187471834 60892:60892 +0.00011266336187471834 58871:58871 +0.00011266336187471834 57162:57162 +0.00011266336187471834 55730:55730 +0.00011266336187471834 56731:56731 +0.00011266336187471834 58378:58378 +0.00011266336187471834 60525:60525 +0.00011266336187471834 33140:33140 +0.00011266336187471834 60107:60107 +0.00011266336187471834 58090:58090 +0.00011266336187471834 59761:59761 +0.00011266336187471834 58012:58012 +0.00011266336187471834 33360:33360 +0.00011266336187471834 59869:59869 +0.00011266336187471834 35315:35315 +0.00011266336187471834 33839:33839 +0.00011266336187471834 59297:59297 +0.00011266336187471834 59346:59346 +0.00011266336187471834 57247:57247 +0.00011266336187471834 56936:56936 +0.00011266336187471834 57696:57696 +0.00011266336187471834 33409:33409 +0.00011266336187471834 57843:57843 +0.00011266336187471834 33254:33254 +0.00011266336187471834 59316:59316 +0.00011266336187471834 59527:59527 +0.00011266336187471834 33738:33738 +0.00011266336187471834 60627:60627 +0.00011266336187471834 56830:56830 +0.00011266336187471834 60341:60341 +0.00011266336187471834 59513:59513 +0.00011266336187471834 60721:60721 +0.00011266336187471834 58068:58068 +0.00011266336187471834 59432:59432 +0.00011266336187471834 56461:56461 +0.00011266336187471834 34081:34081 +0.00011266336187471834 34728:34728 +0.00011266336187471834 56184:56184 +0.00011266336187471834 56025:56025 +0.00011266336187471834 58450:58450 +0.00011266336187471834 59733:59733 +0.00011266336187471834 58619:58619 +0.00011266336187471834 58460:58460 +0.00011266336187471834 58375:58375 +0.00011266336187471834 34827:34827 +0.00011266336187471834 34361:34361 +0.00011266336187471834 60559:60559 +0.00011266336187471834 34481:34481 +0.00011266336187471834 35444:35444 +0.00011266336187471834 35039:35039 +0.00011266336187471834 33917:33917 +0.00011266336187471834 59704:59704 +0.00011266336187471834 33045:33045 +0.00011266336187471834 59027:59027 +0.00011266336187471834 59262:59262 +0.00011266336187471834 56518:56518 +0.00011266336187471834 55818:55818 +0.00011266336187471834 59312:59312 +0.00011266336187471834 56459:56459 +0.00011266336187471834 60021:60021 +0.00011266336187471834 59040:59040 +0.00011266336187471834 60883:60883 +0.00011266336187471834 33082:33082 +0.00011266336187471834 58101:58101 +0.00011266336187471834 60326:60326 +0.00011266336187471834 34675:34675 +0.00011266336187471834 58427:58427 +0.00011266336187471834 56655:56655 +0.00011266336187471834 32805:32805 +0.00011266336187471834 59142:59142 +0.00011266336187471834 60882:60882 +0.00011266336187471834 35143:35143 +0.00011266336187471834 56231:56231 +0.00011266336187471834 59842:59842 +0.00011266336187471834 55887:55887 +0.00011266336187471834 33545:33545 +0.00011266336187471834 58893:58893 +0.00011266336187471834 35070:35070 +0.00011266336187471834 34191:34191 +0.00011266336187471834 59984:59984 +0.00011266336187471834 32941:32941 +0.00011266336187471834 59743:59743 +0.00011266336187471834 58925:58925 +0.00011266336187471834 57927:57927 +0.00011266336187471834 56335:56335 +0.00011266336187471834 34873:34873 +0.00011266336187471834 57369:57369 +0.00011266336187471834 59622:59622 +0.00011266336187471834 34943:34943 +0.00011266336187471834 34815:34815 +0.00011266336187471834 59642:59642 +0.00011266336187471834 34242:34242 +0.00011266336187471834 58436:58436 +0.00011266336187471834 34574:34574 +0.00011266336187471834 34119:34119 +0.00011266336187471834 58627:58627 +0.00011266336187471834 34203:34203 +0.00011266336187471834 35537:35537 +0.00011266336187471834 58869:58869 +0.00011266336187471834 57763:57763 +0.00011266336187471834 32774:32774 +0.00011266336187471834 34718:34718 +0.00011266336187471834 34269:34269 +0.00011266336187471834 60260:60260 +0.00011266336187471834 58018:58018 +0.00011266336187471834 34569:34569 +0.00011266336187471834 32778:32778 +0.00011266336187471834 34160:34160 +0.00011266336187471834 33758:33758 +0.00011266336187471834 33294:33294 +0.00011266336187471834 57327:57327 +0.00011266336187471834 56530:56530 +0.00011266336187471834 56108:56108 +0.00011266336187471834 60581:60581 +0.00011266336187471834 58958:58958 +0.00011266336187471834 33608:33608 +0.00011266336187471834 60038:60038 +0.00011266336187471834 34857:34857 +0.00011266336187471834 35076:35076 +0.00011266336187471834 33730:33730 +0.00011266336187471834 59861:59861 +0.00011266336187471834 57187:57187 +0.00011266336187471834 56960:56960 +0.00011266336187471834 56247:56247 +0.00011266336187471834 55929:55929 +0.00011266336187471834 60612:60612 +0.00011266336187471834 58006:58006 +0.00011266336187471834 34146:34146 +0.00011266336187471834 60834:60834 +0.00011266336187471834 57925:57925 +0.00011266336187471834 55783:55783 +0.00011266336187471834 60988:60988 +0.00011266336187471834 58848:58848 +0.00011266336187471834 56871:56871 +0.00011266336187471834 32974:32974 +0.00011266336187471834 58870:58870 +0.00011266336187471834 57263:57263 +0.00011266336187471834 60377:60377 +0.00011266336187471834 58268:58268 +0.00011266336187471834 35460:35460 +0.00011266336187471834 57415:57415 +0.00011266336187471834 56507:56507 +0.00011266336187471834 59752:59752 +0.00011266336187471834 56462:56462 +0.00011266336187471834 56602:56602 +0.00011266336187471834 60521:60521 +0.00011266336187471834 33983:33983 +0.00011266336187471834 59353:59353 +0.00011266336187471834 59190:59190 +0.00011266336187471834 55968:55968 +0.00011266336187471834 60869:60869 +0.00011266336187471834 34942:34942 +0.00011266336187471834 34856:34856 +0.00011266336187471834 32905:32905 +0.00011266336187471834 33507:33507 +0.00011266336187471834 58094:58094 +0.00011266336187471834 56333:56333 +0.00011266336187471834 55649:55649 +0.00011266336187471834 35268:35268 +0.00011266336187471834 59185:59185 +0.00011266336187471834 60925:60925 +0.00011266336187471834 60526:60526 +0.00011266336187471834 58522:58522 +0.00011266336187471834 59264:59264 +0.00011266336187471834 34937:34937 +0.00011266336187471834 33489:33489 +0.00011266336187471834 35495:35495 +0.00011266336187471834 60246:60246 +0.00011266336187471834 34730:34730 +0.00011266336187471834 58892:58892 +0.00011266336187471834 58890:58890 +0.00011266336187471834 58598:58598 +0.00011266336187471834 59692:59692 +0.00011266336187471834 59256:59256 +0.00011266336187471834 33957:33957 +0.00011266336187471834 60031:60031 +0.00011266336187471834 33175:33175 +0.00011266336187471834 60766:60766 +0.00011266336187471834 33432:33432 +0.00011266336187471834 33157:33157 +0.00011266336187471834 57920:57920 +0.00011266336187471834 34456:34456 +0.00011266336187471834 58198:58198 +0.00011266336187471834 58192:58192 +0.00011266336187471834 35023:35023 +0.00011266336187471834 35045:35045 +0.00011266336187471834 34187:34187 +0.00011266336187471834 56152:56152 +0.00011266336187471834 56104:56104 +0.00011266336187471834 33754:33754 +0.00011266336187471834 34340:34340 +0.00011266336187471834 57097:57097 +0.00011266336187471834 58189:58189 +0.00011266336187471834 57106:57106 +0.00011266336187471834 60808:60808 +0.00011266336187471834 57815:57815 +0.00011266336187471834 34608:34608 +0.00011266336187471834 57058:57058 +0.00011266336187471834 35328:35328 +0.00011266336187471834 35106:35106 +0.00011266336187471834 32818:32818 +0.00011266336187471834 58391:58391 +0.00011266336187471834 35132:35132 +0.00011266336187471834 60229:60229 +0.00011266336187471834 60776:60776 +0.00011266336187471834 35323:35323 +0.00011266336187471834 60643:60643 +0.00011266336187471834 35557:35557 +0.00011266336187471834 60764:60764 +0.00011266336187471834 56887:56887 +0.00011266336187471834 34636:34636 +0.00011266336187471834 59573:59573 +0.00011266336187471834 56394:56394 +0.00011266336187471834 59829:59829 +0.00011266336187471834 34852:34852 +0.00011266336187471834 35283:35283 +0.00011266336187471834 58052:58052 +0.00011266336187471834 57060:57060 +0.00011266336187471834 58351:58351 +0.00011266336187471834 56760:56760 +0.00011266336187471834 57303:57303 +0.00011266336187471834 35387:35387 +0.00011266336187471834 33763:33763 +0.00011266336187471834 59265:59265 +0.00011266336187471834 57055:57055 +0.00011266336187471834 59417:59417 +0.00011266336187471834 59037:59037 +0.00011266336187471834 59408:59408 +0.00011266336187471834 55854:55854 +0.00011266336187471834 33837:33837 +0.00011266336187471834 59800:59800 +0.00011266336187471834 33826:33826 +0.00011266336187471834 59447:59447 +0.00011266336187471834 59206:59206 +0.00011266336187471834 58416:58416 +0.00011266336187471834 34116:34116 +0.00011266336187471834 34958:34958 +0.00011266336187471834 33593:33593 +0.00011266336187471834 33289:33289 +0.00011266336187471834 60200:60200 +0.00011266336187471834 58389:58389 +0.00011266336187471834 57733:57733 +0.00011266336187471834 34216:34216 +0.00011266336187471834 33231:33231 +0.00011266336187471834 35204:35204 +0.00011266336187471834 59906:59906 +0.00011266336187471834 56553:56553 +0.00011266336187471834 56557:56557 +0.00011266336187471834 58038:58038 +0.00011266336187471834 58956:58956 +0.00011266336187471834 34087:34087 +0.00011266336187471834 58171:58171 +0.00011266336187471834 57664:57664 +0.00011266336187471834 56357:56357 +0.00011266336187471834 59196:59196 +0.00011266336187471834 32919:32919 +0.00011266336187471834 60214:60214 +0.00011266336187471834 55921:55921 +0.00011266336187471834 59139:59139 +0.00011266336187471834 56688:56688 +0.00011266336187471834 32961:32961 +0.00011266336187471834 33074:33074 +0.00011266336187471834 58661:58661 +0.00011266336187471834 59988:59988 +0.00011266336187471834 56910:56910 +0.00011266336187471834 56207:56207 +0.00011266336187471834 34645:34645 +0.00011266336187471834 33450:33450 +0.00011266336187471834 33719:33719 +0.00011266336187471834 34343:34343 +0.00011266336187471834 33347:33347 +0.00011266336187471834 58952:58952 +0.00011266336187471834 59703:59703 +0.00011266336187471834 33828:33828 +0.00011266336187471834 59123:59123 +0.00011266336187471834 56635:56635 +0.00011266336187471834 56945:56945 +0.00011266336187471834 56366:56366 +0.00011266336187471834 35256:35256 +0.00011266336187471834 57783:57783 +0.00011266336187471834 58111:58111 +0.00011266336187471834 60779:60779 +0.00011266336187471834 58939:58939 +0.00011266336187471834 57495:57495 +0.00011266336187471834 57995:57995 +0.00011266336187471834 56258:56258 +0.00011266336187471834 33064:33064 +0.00011266336187471834 58710:58710 +0.00011266336187471834 33160:33160 +0.00011266336187471834 60150:60150 +0.00011266336187471834 58597:58597 +0.00011266336187471834 55718:55718 +0.00011266336187471834 58138:58138 +0.00011266336187471834 56669:56669 +0.00011266336187471834 33149:33149 +0.00011266336187471834 58629:58629 +0.00011266336187471834 33084:33084 +0.00011266336187471834 35285:35285 +0.00011266336187471834 33457:33457 +0.00011266336187471834 60971:60971 +0.00011266336187471834 60191:60191 +0.00011266336187471834 35213:35213 +0.00011266336187471834 60895:60895 +0.00011266336187471834 58812:58812 +0.00011266336187471834 56021:56021 +0.00011266336187471834 35107:35107 +0.00011266336187471834 57072:57072 +0.00011266336187471834 55983:55983 +0.00011266336187471834 57358:57358 +0.00011266336187471834 55936:55936 +0.00011266336187471834 60239:60239 +0.00011266336187471834 55659:55659 +0.00011266336187471834 56885:56885 +0.00011266336187471834 59204:59204 +0.00011266336187471834 56290:56290 +0.00011266336187471834 60707:60707 +0.00011266336187471834 59855:59855 +0.00011266336187471834 57656:57656 +0.00011266336187471834 59956:59956 +0.00011266336187471834 59808:59808 +0.00011266336187471834 60608:60608 +0.00011266336187471834 57440:57440 +0.00011266336187471834 56268:56268 +0.00011266336187471834 58567:58567 +0.00011266336187471834 34665:34665 +0.00011266336187471834 33120:33120 +0.00011266336187471834 35246:35246 +0.00011266336187471834 33154:33154 +0.00011266336187471834 32886:32886 +0.00011266336187471834 56925:56925 +0.00011266336187471834 35192:35192 +0.00011266336187471834 34153:34153 +0.00011266336187471834 60405:60405 +0.00011266336187471834 55877:55877 +0.00011266336187471834 59847:59847 +0.00011266336187471834 33035:33035 +0.00011266336187471834 59217:59217 +0.00011266336187471834 58159:58159 +0.00011266336187471834 59035:59035 +0.00011266336187471834 32809:32809 +0.00011266336187471834 60098:60098 +0.00011266336187471834 59119:59119 +0.00011266336187471834 58792:58792 +0.00011266336187471834 57849:57849 +0.00011266336187471834 35354:35354 +0.00011266336187471834 60872:60872 +0.00011266336187471834 60774:60774 +0.00011266336187471834 60336:60336 +0.00011266336187471834 55893:55893 +0.00011266336187471834 60646:60646 +0.00011266336187471834 60136:60136 +0.00011266336187471834 60128:60128 +0.00011266336187471834 55852:55852 +0.00011266336187471834 60114:60114 +0.00011266336187471834 35265:35265 +0.00011266336187471834 57447:57447 +0.00011266336187471834 58882:58882 +0.00011266336187471834 57116:57116 +0.00011266336187471834 56769:56769 +0.00011266336187471834 59357:59357 +0.00011266336187471834 34342:34342 +0.00011266336187471834 33881:33881 +0.00011266336187471834 57333:57333 +0.00011266336187471834 58665:58665 +0.00011266336187471834 57624:57624 +0.00011266336187471834 57424:57424 +0.00011266336187471834 35244:35244 +0.00011266336187471834 58566:58566 +0.00011266336187471834 58496:58496 +0.00011266336187471834 33898:33898 +0.00011266336187471834 60050:60050 +0.00011266336187471834 56975:56975 +0.00011266336187471834 57532:57532 +0.00011266336187471834 57003:57003 +0.00011266336187471834 34717:34717 +0.00011266336187471834 33392:33392 +0.00011266336187471834 56115:56115 +0.00011266336187471834 59982:59982 +0.00011266336187471834 57937:57937 +0.00011266336187471834 35457:35457 +0.00011266336187471834 35291:35291 +0.00011266336187471834 58379:58379 +0.00011266336187471834 34724:34724 +0.00011266336187471834 34318:34318 +0.00011266336187471834 57680:57680 +0.00011266336187471834 60552:60552 +0.00011266336187471834 60041:60041 +0.00011266336187471834 58451:58451 +0.00011266336187471834 34770:34770 +0.00011266336187471834 33992:33992 +0.00011266336187471834 57350:57350 +0.00011266336187471834 56328:56328 +0.00011266336187471834 33873:33873 +0.00011266336187471834 32870:32870 +0.00011266336187471834 34793:34793 +0.00011266336187471834 59454:59454 +0.00011266336187471834 58184:58184 +0.00011266336187471834 60878:60878 +0.00011266336187471834 58332:58332 +0.00011266336187471834 34289:34289 +0.00011266336187471834 60062:60062 +0.00011266336187471834 56648:56648 +0.00011266336187471834 56732:56732 +0.00011266336187471834 55606:55606 +0.00011266336187471834 58206:58206 +0.00011266336187471834 32851:32851 +0.00011266336187471834 60329:60329 +0.00011266336187471834 57119:57119 +0.00011266336187471834 33244:33244 +0.00011266336187471834 58587:58587 +0.00011266336187471834 56782:56782 +0.00011266336187471834 35186:35186 +0.00011266336187471834 57766:57766 +0.00011266336187471834 33772:33772 +0.00011266336187471834 35079:35079 +0.00011266336187471834 60278:60278 +0.00011266336187471834 34784:34784 +0.00011266336187471834 33239:33239 +0.00011266336187471834 58076:58076 +0.00011266336187471834 58388:58388 +0.00011266336187471834 57080:57080 +0.00011266336187471834 33441:33441 +0.00011266336187471834 34513:34513 +0.00011266336187471834 55780:55780 +0.00011266336187471834 60577:60577 +0.00011266336187471834 57913:57913 +0.00011266336187471834 55722:55722 +0.00011266336187471834 35284:35284 +0.00011266336187471834 35114:35114 +0.00011266336187471834 56857:56857 +0.00011266336187471834 34541:34541 +0.00011266336187471834 32926:32926 +0.00011266336187471834 58447:58447 +0.00011266336187471834 57729:57729 +0.00011266336187471834 57524:57524 +0.00011266336187471834 56306:56306 +0.00011266336187471834 56512:56512 +0.00011266336187471834 58851:58851 +0.00011266336187471834 57797:57797 +0.00011266336187471834 58148:58148 +0.00011266336187471834 57545:57545 +0.00011266336187471834 35321:35321 +0.00011266336187471834 59838:59838 +0.00011266336187471834 33143:33143 +0.00011266336187471834 60095:60095 +0.00011266336187471834 57989:57989 +0.00011266336187471834 59124:59124 +0.00011266336187471834 58618:58618 +0.00011266336187471834 56967:56967 +0.00011266336187471834 59921:59921 +0.00011266336187471834 34252:34252 +0.00011266336187471834 56649:56649 +0.00011266336187471834 59201:59201 +0.00011266336187471834 35257:35257 +0.00011266336187471834 60637:60637 +0.00011266336187471834 58676:58676 +0.00011266336187471834 58252:58252 +0.00011266336187471834 57192:57192 +0.00011266336187471834 57082:57082 +0.00011266336187471834 55643:55643 +0.00011266336187471834 57694:57694 +0.00011266336187471834 55915:55915 +0.00011266336187471834 34207:34207 +0.00011266336187471834 57819:57819 +0.00011266336187471834 56548:56548 +0.00011266336187471834 33699:33699 +0.00011266336187471834 57465:57465 +0.00011266336187471834 56096:56096 +0.00011266336187471834 34180:34180 +0.00011266336187471834 33680:33680 +0.00011266336187471834 58186:58186 +0.00011266336187471834 33133:33133 +0.00011266336187471834 34282:34282 +0.00011266336187471834 60703:60703 +0.00011266336187471834 33124:33124 +0.00011266336187471834 60533:60533 +0.00011266336187471834 59320:59320 +0.00011266336187471834 34126:34126 +0.00011266336187471834 57531:57531 +0.00011266336187471834 33134:33134 +0.00011266336187471834 59996:59996 +0.00011266336187471834 58272:58272 +0.00011266336187471834 60783:60783 +0.00011266336187471834 59559:59559 +0.00011266336187471834 56693:56693 +0.00011266336187471834 60483:60483 +0.00011266336187471834 59503:59503 +0.00011266336187471834 33056:33056 +0.00011266336187471834 60850:60850 +0.00011266336187471834 60474:60474 +0.00011266336187471834 56151:56151 +0.00011266336187471834 35535:35535 +0.00011266336187471834 60236:60236 +0.00011266336187471834 56127:56127 +0.00011266336187471834 32881:32881 +0.00011266336187471834 56922:56922 +0.00011266336187471834 55935:55935 +0.00011266336187471834 57029:57029 +0.00011266336187471834 34824:34824 +0.00011266336187471834 35492:35492 +0.00011266336187471834 60028:60028 +0.00011266336187471834 59790:59790 +0.00011266336187471834 57203:57203 +0.00011266336187471834 55704:55704 +0.00011266336187471834 57474:57474 +0.00011266336187471834 56076:56076 +0.00011266336187471834 33381:33381 +0.00011266336187471834 58356:58356 +0.00011266336187471834 34778:34778 +0.00011266336187471834 34089:34089 +0.00011266336187471834 32930:32930 +0.00011266336187471834 57493:57493 +0.00011266336187471834 35546:35546 +0.00011266336187471834 32898:32898 +0.00011266336187471834 60384:60384 +0.00011266336187471834 59588:59588 +0.00011266336187471834 57331:57331 +0.00011266336187471834 57481:57481 +0.00011266336187471834 34978:34978 +0.00011266336187471834 58197:58197 +0.00011266336187471834 57343:57343 +0.00011266336187471834 35066:35066 +0.00011266336187471834 58798:58798 +0.00011266336187471834 33493:33493 +0.00011266336187471834 33023:33023 +0.00011266336187471834 55713:55713 +0.00011266336187471834 60945:60945 +0.00011266336187471834 57294:57294 +0.00011266336187471834 59117:59117 +0.00011266336187471834 60857:60857 +0.00011266336187471834 58520:58520 +0.00011266336187471834 34789:34789 +0.00011266336187471834 34386:34386 +0.00011266336187471834 56924:56924 +0.00011266336187471834 59911:59911 +0.00011266336187471834 57588:57588 +0.00011266336187471834 34241:34241 +0.00011266336187471834 35496:35496 +0.00011266336187471834 33198:33198 +0.00011266336187471834 60698:60698 +0.00011266336187471834 60162:60162 +0.00011266336187471834 34732:34732 +0.00011266336187471834 58459:58459 +0.00011266336187471834 56670:56670 +0.00011266336187471834 57442:57442 +0.00011266336187471834 34073:34073 +0.00011266336187471834 57226:57226 +0.00011266336187471834 58228:58228 +0.00011266336187471834 57730:57730 +0.00011266336187471834 56427:56427 +0.00011266336187471834 59450:59450 +0.00011266336187471834 57964:57964 +0.00011266336187471834 60250:60250 +0.00011266336187471834 32986:32986 +0.00011266336187471834 59781:59781 +0.00011266336187471834 56959:56959 +0.00011266336187471834 60163:60163 +0.00011266336187471834 56765:56765 +0.00011266336187471834 55762:55762 +0.00011266336187471834 57275:57275 +0.00011266336187471834 57507:57507 +0.00011266336187471834 34522:34522 +0.00011266336187471834 34352:34352 +0.00011266336187471834 33643:33643 +0.00011266336187471834 57045:57045 +0.00011266336187471834 60457:60457 +0.00011266336187471834 56848:56848 +0.00011266336187471834 33912:33912 +0.00011266336187471834 60811:60811 +0.00011266336187471834 58564:58564 +0.00011266336187471834 33468:33468 +0.00011266336187471834 35074:35074 +0.00011266336187471834 34230:34230 +0.00011266336187471834 32826:32826 +0.00011266336187471834 57511:57511 +0.00011266336187471834 58433:58433 +0.00011266336187471834 35206:35206 +0.00011266336187471834 34537:34537 +0.00011266336187471834 34935:34935 +0.00011266336187471834 58075:58075 +0.00011266336187471834 60135:60135 +0.00011266336187471834 58563:58563 +0.00011266336187471834 35276:35276 +0.00011266336187471834 59170:59170 +0.00011266336187471834 56620:56620 +0.00011266336187471834 55874:55874 +0.00011266336187471834 58254:58254 +0.00011266336187471834 58340:58340 +0.00011266336187471834 56249:56249 +0.00011266336187471834 34614:34614 +0.00011266336187471834 33889:33889 +0.00011266336187471834 32911:32911 +0.00011266336187471834 57686:57686 +0.00011266336187471834 56276:56276 +0.00011266336187471834 58030:58030 +0.00011266336187471834 35081:35081 +0.00011266336187471834 56776:56776 +0.00011266336187471834 57953:57953 +0.00011266336187471834 57085:57085 +0.00011266336187471834 35385:35385 +0.00011266336187471834 60487:60487 +0.00011266336187471834 58238:58238 +0.00011266336187471834 34892:34892 +0.00011266336187471834 34763:34763 +0.00011266336187471834 35466:35466 +0.00011266336187471834 60248:60248 +0.00011266336187471834 34933:34933 +0.00011266336187471834 58849:58849 +0.00011266336187471834 59129:59129 +0.00011266336187471834 55803:55803 +0.00011266336187471834 57108:57108 +0.00011266336187471834 57453:57453 +0.00011266336187471834 60917:60917 +0.00011266336187471834 32902:32902 +0.00011266336187471834 33603:33603 +0.00011266336187471834 34606:34606 +0.00011266336187471834 59798:59798 +0.00011266336187471834 56048:56048 +0.00011266336187471834 35548:35548 +0.00011266336187471834 59519:59519 +0.00011266336187471834 59728:59728 +0.00011266336187471834 59176:59176 +0.00011266336187471834 35516:35516 +0.00011266336187471834 34466:34466 +0.00011266336187471834 33572:33572 +0.00011266336187471834 58064:58064 +0.00011266336187471834 34902:34902 +0.00011266336187471834 58088:58088 +0.00011266336187471834 33130:33130 +0.00011266336187471834 55812:55812 +0.00011266336187471834 59429:59429 +0.00011266336187471834 35053:35053 +0.00011266336187471834 59349:59349 +0.00011266336187471834 56697:56697 +0.00011266336187471834 60814:60814 +0.00011266336187471834 34056:34056 +0.00011266336187471834 33095:33095 +0.00011266336187471834 59973:59973 +0.00011266336187471834 56497:56497 +0.00011266336187471834 35264:35264 +0.00011266336187471834 34602:34602 +0.00011266336187471834 33927:33927 +0.00011266336187471834 59894:59894 +0.00011266336187471834 58888:58888 +0.00011266336187471834 57614:57614 +0.00011266336187471834 56808:56808 +0.00011266336187471834 59392:59392 +0.00011266336187471834 57571:57571 +0.00011266336187471834 60479:60479 +0.00011266336187471834 59322:59322 +0.00011266336187471834 58153:58153 +0.00011266336187471834 34678:34678 +0.00011266336187471834 58403:58403 +0.00011266336187471834 56618:56618 +0.00011266336187471834 33751:33751 +0.00011266336187471834 35149:35149 +0.00011266336187471834 59967:59967 +0.00011266336187471834 59011:59011 +0.00011266336187471834 59405:59405 +0.00011266336187471834 58274:58274 +0.00011266336187471834 60476:60476 +0.00011266336187471834 58092:58092 +0.00011266336187471834 56770:56770 +0.00011266336187471834 34845:34845 +0.00011266336187471834 34233:34233 +0.00011266336187471834 60900:60900 +0.00011266336187471834 33971:33971 +0.00011266336187471834 33314:33314 +0.00011266336187471834 35217:35217 +0.00011266336187471834 58773:58773 +0.00011266336187471834 59235:59235 +0.00011266336187471834 58830:58830 +0.00011266336187471834 35386:35386 +0.00011266336187471834 60080:60080 +0.00011266336187471834 56727:56727 +0.00011266336187471834 35316:35316 +0.00011266336187471834 58840:58840 +0.00011266336187471834 33713:33713 +0.00011266336187471834 60503:60503 +0.00011266336187471834 57974:57974 +0.00011266336187471834 55617:55617 +0.00011266336187471834 59415:59415 +0.00011266336187471834 59510:59510 +0.00011266336187471834 59406:59406 +0.00011266336187471834 56354:56354 +0.00011266336187471834 32822:32822 +0.00011266336187471834 59841:59841 +0.00011266336187471834 57122:57122 +0.00011266336187471834 58273:58273 +0.00011266336187471834 34094:34094 +0.00011266336187471834 34284:34284 +0.00011266336187471834 34380:34380 +0.00011266336187471834 32948:32948 +0.00011266336187471834 56235:56235 +0.00011266336187471834 34649:34649 +0.00011266336187471834 56016:56016 +0.00011266336187471834 55796:55796 +0.00011266336187471834 58628:58628 +0.00011266336187471834 34470:34470 +0.00011266336187471834 60324:60324 +0.00011266336187471834 59882:59882 +0.00011266336187471834 57508:57508 +0.00011266336187471834 35421:35421 +0.00011266336187471834 60269:60269 +0.00011266336187471834 33002:33002 +0.00011266336187471834 59797:59797 +0.00011266336187471834 56952:56952 +0.00011266336187471834 35050:35050 +0.00011266336187471834 58484:58484 +0.00011266336187471834 32794:32794 +0.00011266336187471834 58842:58842 +0.00011266336187471834 34795:34795 +0.00011266336187471834 34915:34915 +0.00011266336187471834 34572:34572 +0.00011266336187471834 60017:60017 +0.00011266336187471834 58873:58873 +0.00011266336187471834 35547:35547 +0.00011266336187471834 34711:34711 +0.00011266336187471834 56332:56332 +0.00011266336187471834 33633:33633 +0.00011266336187471834 56192:56192 +0.00011266336187471834 56990:56990 +0.00011266336187471834 34644:34644 +0.00011266336187471834 33874:33874 +0.00011266336187471834 60465:60465 +0.00011266336187471834 58650:58650 +0.00011266336187471834 58506:58506 +0.00011266336187471834 57543:57543 +0.00011266336187471834 59540:59540 +0.00011266336187471834 35198:35198 +0.00011266336187471834 33533:33533 +0.00011266336187471834 60864:60864 +0.00011266336187471834 34209:34209 +0.00011266336187471834 58396:58396 +0.00011266336187471834 56011:56011 +0.00011266336187471834 34249:34249 +0.00011266336187471834 33317:33317 +0.00011266336187471834 57824:57824 +0.00011266336187471834 56676:56676 +0.00011266336187471834 59526:59526 +0.00011266336187471834 57760:57760 +0.00011266336187471834 35287:35287 +0.00011266336187471834 33520:33520 +0.00011266336187471834 60589:60589 +0.00011266336187471834 56496:56496 +0.00011266336187471834 56312:56312 +0.00011266336187471834 58535:58535 +0.00011266336187471834 56529:56529 +0.00011266336187471834 33243:33243 +0.00011266336187471834 60477:60477 +0.00011266336187471834 32770:32770 +0.00011266336187471834 33522:33522 +0.00011266336187471834 56920:56920 +0.00011266336187471834 60204:60204 +0.00011266336187471834 59960:59960 +0.00011266336187471834 58839:58839 +0.00011266336187471834 35413:35413 +0.00011266336187471834 35172:35172 +0.00011266336187471834 33896:33896 +0.00011266336187471834 57052:57052 +0.00011266336187471834 33464:33464 +0.00011266336187471834 59953:59953 +0.00011266336187471834 33388:33388 +0.00011266336187471834 33355:33355 +0.00011266336187471834 33986:33986 +0.00011266336187471834 33809:33809 +0.00011266336187471834 57230:57230 +0.00011266336187471834 59144:59144 +0.00011266336187471834 57851:57851 +0.00011266336187471834 33439:33439 +0.00011266336187471834 60557:60557 +0.00011266336187471834 56017:56017 +0.00011266336187471834 58806:58806 +0.00011266336187471834 57040:57040 +0.00011266336187471834 34981:34981 +0.00011266336187471834 34547:34547 +0.00011266336187471834 59333:59333 +0.00011266336187471834 58637:58637 +0.00011266336187471834 34232:34232 +0.00011266336187471834 56633:56633 +0.00011266336187471834 34454:34454 +0.00011266336187471834 34113:34113 +0.00011266336187471834 58850:58850 +0.00011266336187471834 34908:34908 +0.00011266336187471834 33929:33929 +0.00011266336187471834 34010:34010 +0.00011266336187471834 60271:60271 +0.00011266336187471834 58295:58295 +0.00011266336187471834 58706:58706 +0.00011266336187471834 56097:56097 +0.00011266336187471834 58277:58277 +0.00011266336187471834 35171:35171 +0.00011266336187471834 55680:55680 +0.00011266336187471834 35200:35200 +0.00011266336187471834 33901:33901 +0.00011266336187471834 60820:60820 +0.00011266336187471834 35036:35036 +0.00011266336187471834 59643:59643 +0.00011266336187471834 56901:56901 +0.00011266336187471834 59944:59944 +0.00011266336187471834 59127:59127 +0.00011266336187471834 55758:55758 +0.00011266336187471834 58507:58507 +0.00011266336187471834 33745:33745 +0.00011266336187471834 35461:35461 +0.00011266336187471834 33228:33228 +0.00011266336187471834 35292:35292 +0.00011266336187471834 57690:57690 +0.00011266336187471834 34880:34880 +0.00011266336187471834 58220:58220 +0.00011266336187471834 59177:59177 +0.00011266336187471834 56053:56053 +0.00011266336187471834 35281:35281 +0.00011266336187471834 35293:35293 +0.00011266336187471834 57837:57837 +0.00011266336187471834 57573:57573 +0.00011266336187471834 59846:59846 +0.00011266336187471834 56873:56873 +0.00011266336187471834 33664:33664 +0.00011266336187471834 56558:56558 +0.00011266336187471834 33676:33676 +0.00011266336187471834 58947:58947 +0.00011266336187471834 60843:60843 +0.00011266336187471834 57318:57318 +0.00011266336187471834 57209:57209 +0.00011266336187471834 34347:34347 +0.00011266336187471834 33418:33418 +0.00011266336187471834 35108:35108 +0.00011266336187471834 58417:58417 +0.00011266336187471834 57146:57146 +0.00011266336187471834 59018:59018 +0.00011266336187471834 57426:57426 +0.00011266336187471834 56472:56472 +0.00011266336187471834 60753:60753 +0.00011266336187471834 57864:57864 +0.00011266336187471834 57984:57984 +0.00011266336187471834 35098:35098 +0.00011266336187471834 34366:34366 +0.00011266336187471834 60536:60536 +0.00011266336187471834 60153:60153 +0.00011266336187471834 34500:34500 +0.00011266336187471834 33885:33885 +0.00011266336187471834 60353:60353 +0.00011266336187471834 58699:58699 +0.00011266336187471834 33985:33985 +0.00011266336187471834 58365:58365 +0.00011266336187471834 33323:33323 +0.00011266336187471834 59213:59213 +0.00011266336187471834 56180:56180 +0.00011266336187471834 34111:34111 +0.00011266336187471834 57942:57942 +0.00011266336187471834 34869:34869 +0.00011266336187471834 57574:57574 +0.00011266336187471834 60158:60158 +0.00011266336187471834 56721:56721 +0.00011266336187471834 35443:35443 +0.00011266336187471834 55795:55795 +0.00011266336187471834 35513:35513 +0.00011266336187471834 60471:60471 +0.00011266336187471834 59222:59222 +0.00011266336187471834 57196:57196 +0.00011266336187471834 57972:57972 +0.00011266336187471834 57190:57190 +0.00011266336187471834 57004:57004 +0.00011266336187471834 35130:35130 +0.00011266336187471834 35037:35037 +0.00011266336187471834 34520:34520 +0.00011266336187471834 60765:60765 +0.00011266336187471834 59713:59713 +0.00011266336187471834 59668:59668 +0.00011266336187471834 57595:57595 +0.00011266336187471834 59340:59340 +0.00011266336187471834 56370:56370 +0.00011266336187471834 56992:56992 +0.00011266336187471834 33540:33540 +0.00011266336187471834 59134:59134 +0.00011266336187471834 32934:32934 +0.00011266336187471834 34581:34581 +0.00011266336187471834 33288:33288 +0.00011266336187471834 57934:57934 +0.00011266336187471834 56511:56511 +0.00011266336187471834 60829:60829 +0.00011266336187471834 60371:60371 +0.00011266336187471834 59424:59424 +0.00011266336187471834 59160:59160 +0.00011266336187471834 34839:34839 +0.00011266336187471834 56353:56353 +0.00011266336187471834 55759:55759 +0.00011266336187471834 35047:35047 +0.00011266336187471834 35022:35022 +0.00011266336187471834 60011:60011 +0.00011266336187471834 60954:60954 +0.00011266336187471834 33997:33997 +0.00011266336187471834 57050:57050 +0.00011266336187471834 60423:60423 +0.00011266336187471834 56772:56772 +0.00011266336187471834 33088:33088 +0.00011266336187471834 60520:60520 +0.00011266336187471834 57914:57914 +0.00011266336187471834 55913:55913 +0.00011266336187471834 56771:56771 +0.00011266336187471834 35004:35004 +0.00011266336187471834 56961:56961 +0.00011266336187471834 60409:60409 +0.00011266336187471834 57906:57906 +0.00011266336187471834 56932:56932 +0.00011266336187471834 58716:58716 +0.00011266336187471834 58211:58211 +0.00011266336187471834 56514:56514 +0.00011266336187471834 57572:57572 +0.00011266336187471834 55789:55789 +0.00011266336187471834 60713:60713 +0.00011266336187471834 33456:33456 +0.00011266336187471834 35542:35542 +0.00011266336187471834 34400:34400 +0.00011266336187471834 58214:58214 +0.00011266336187471834 55828:55828 +0.00011266336187471834 34458:34458 +0.00011266336187471834 58914:58914 +0.00011266336187471834 60321:60321 +0.00011266336187471834 55792:55792 +0.00011266336187471834 35014:35014 +0.00011266336187471834 59539:59539 +0.00011266336187471834 59161:59161 +0.00011266336187471834 33804:33804 +0.00011266336187471834 58404:58404 +0.00011266336187471834 57829:57829 +0.00011266336187471834 60605:60605 +0.00011266336187471834 59623:59623 +0.00011266336187471834 56334:56334 +0.00011266336187471834 56224:56224 +0.00011266336187471834 56213:56213 +0.00011266336187471834 57473:57473 +0.00011266336187471834 57769:57769 +0.00011266336187471834 60697:60697 +0.00011266336187471834 33258:33258 +0.00011266336187471834 59789:59789 +0.00011266336187471834 55711:55711 +0.00011266336187471834 59814:59814 +0.00011266336187471834 34934:34934 +0.00011266336187471834 59719:59719 +0.00011266336187471834 57102:57102 +0.00011266336187471834 34598:34598 +0.00011266336187471834 58421:58421 +0.00011266336187471834 34009:34009 +0.00011266336187471834 59671:59671 +0.00011266336187471834 57928:57928 +0.00011266336187471834 56283:56283 +0.00011266336187471834 57412:57412 +0.00011266336187471834 60922:60922 +0.00011266336187471834 60532:60532 +0.00011266336187471834 56652:56652 +0.00011266336187471834 34250:34250 +0.00011266336187471834 35377:35377 +0.00011266336187471834 34412:34412 +0.00011266336187471834 58735:58735 +0.00011266336187471834 56445:56445 +0.00011266336187471834 33854:33854 +0.00011266336187471834 33466:33466 +0.00011266336187471834 32938:32938 +0.00011266336187471834 32901:32901 +0.00011266336187471834 59077:59077 +0.00011266336187471834 57066:57066 +0.00011266336187471834 34938:34938 +0.00011266336187471834 59709:59709 +0.00011266336187471834 56668:56668 +0.00011266336187471834 33171:33171 +0.00011266336187471834 59550:59550 +0.00011266336187471834 60385:60385 +0.00011266336187471834 59895:59895 +0.00011266336187471834 57695:57695 +0.00011266336187471834 57788:57788 +0.00011266336187471834 35404:35404 +0.00011266336187471834 34102:34102 +0.00011266336187471834 33925:33925 +0.00011266336187471834 60491:60491 +0.00011266336187471834 58739:58739 +0.00011266336187471834 59477:59477 +0.00011266336187471834 57715:57715 +0.00011266336187471834 55979:55979 +0.00011266336187471834 59525:59525 +0.00011266336187471834 58157:58157 +0.00011266336187471834 34479:34479 +0.00011266336187471834 60967:60967 +0.00011266336187471834 58823:58823 +0.00011266336187471834 59961:59961 +0.00011266336187471834 33277:33277 +0.00011266336187471834 33012:33012 +0.00011266336187471834 57138:57138 +0.00011266336187471834 56210:56210 +0.00011266336187471834 35026:35026 +0.00011266336187471834 33051:33051 +0.00011266336187471834 57132:57132 +0.00011266336187471834 57625:57625 +0.00011266336187471834 58905:58905 +0.00011266336187471834 55610:55610 +0.00011266336187471834 34155:34155 +0.00011266336187471834 33635:33635 +0.00011266336187471834 58757:58757 +0.00011266336187471834 56338:56338 +0.00011266336187471834 33600:33600 +0.00011266336187471834 34927:34927 +0.00011266336187471834 33447:33447 +0.00011266336187471834 58515:58515 +0.00011266336187471834 34656:34656 +0.00011266336187471834 33479:33479 +0.00011266336187471834 59347:59347 +0.00011266336187471834 34029:34029 +0.00011266336187471834 57759:57759 +0.00011266336187471834 59617:59617 +0.00011266336187471834 59569:59569 +0.00011266336187471834 33783:33783 +0.00011266336187471834 57589:57589 +0.00011266336187471834 56712:56712 +0.00011266336187471834 59897:59897 +0.00011266336187471834 34648:34648 +0.00011266336187471834 56777:56777 +0.00011266336187471834 56317:56317 +0.00011266336187471834 60632:60632 +0.00011266336187471834 33006:33006 +0.00011266336187471834 32972:32972 +0.00011266336187471834 59945:59945 +0.00011266336187471834 34828:34828 +0.00011266336187471834 57548:57548 +0.00011266336187471834 57422:57422 +0.00011266336187471834 58233:58233 +0.00011266336187471834 56979:56979 +0.00011266336187471834 34944:34944 +0.00011266336187471834 34378:34378 +0.00011266336187471834 33333:33333 +0.00011266336187471834 59062:59062 +0.00011266336187471834 34762:34762 +0.00011266336187471834 58855:58855 +0.00011266336187471834 56376:56376 +0.00011266336187471834 33770:33770 +0.00011266336187471834 34220:34220 +0.00011266336187471834 57623:57623 +0.00011266336187471834 58164:58164 +0.00011266336187471834 56942:56942 +0.00011266336187471834 33351:33351 +0.00011266336187471834 57712:57712 +0.00011266336187471834 57128:57128 +0.00011266336187471834 33295:33295 +0.00011266336187471834 56883:56883 +0.00011266336187471834 33906:33906 +0.00011266336187471834 60909:60909 +0.00011266336187471834 56616:56616 +0.00011266336187471834 32833:32833 +0.00011266336187471834 57185:57185 +0.00011266336187471834 32782:32782 +0.00011266336187471834 59191:59191 +0.00011266336187471834 60731:60731 +0.00011266336187471834 58843:58843 +0.00011266336187471834 58487:58487 +0.00011266336187471834 56168:56168 +0.00011266336187471834 33269:33269 +0.00011266336187471834 59427:59427 +0.00011266336187471834 34532:34532 +0.00011266336187471834 33364:33364 +0.00011266336187471834 34759:34759 +0.00011266336187471834 60484:60484 +0.00011266336187471834 56522:56522 +0.00011266336187471834 59169:59169 +0.00011266336187471834 60137:60137 +0.00011266336187471834 57945:57945 +0.00011266336187471834 56583:56583 +0.00011266336187471834 57225:57225 +0.00011266336187471834 33144:33144 +0.00011266336187471834 60998:60998 +0.00011266336187471834 56734:56734 +0.00011266336187471834 59879:59879 +0.00011266336187471834 56663:56663 +0.00011266336187471834 58154:58154 +0.00011266336187471834 57379:57379 +0.00011266336187471834 57086:57086 +0.00011266336187471834 57533:57533 +0.00011266336187471834 57007:57007 +0.00011266336187471834 56778:56778 +0.00011266336187471834 59391:59391 +0.00011266336187471834 32916:32916 +0.00011266336187471834 32896:32896 +0.00011266336187471834 59203:59203 +0.00011266336187471834 60554:60554 +0.00011266336187471834 34925:34925 +0.00011266336187471834 32994:32994 +0.00011266336187471834 60995:60995 +0.00011266336187471834 59317:59317 +0.00011266336187471834 35059:35059 +0.00011266336187471834 33659:33659 +0.00011266336187471834 58581:58581 +0.00011266336187471834 56023:56023 +0.00011266336187471834 59562:59562 +0.00011266336187471834 56007:56007 +0.00011266336187471834 34689:34689 +0.00011266336187471834 56110:56110 +0.00011266336187471834 32889:32889 +0.00011266336187471834 33808:33808 +0.00011266336187471834 60283:60283 +0.00011266336187471834 57232:57232 +0.00011266336187471834 57770:57770 +0.00011266336187471834 33650:33650 +0.00011266336187471834 33226:33226 +0.00011266336187471834 59884:59884 +0.00011266336187471834 56940:56940 +0.00011266336187471834 57758:57758 +0.00011266336187471834 35174:35174 +0.00011266336187471834 60043:60043 +0.00011266336187471834 58531:58531 +0.00011266336187471834 57144:57144 +0.00011266336187471834 34020:34020 +0.00011266336187471834 56928:56928 +0.00011266336187471834 55992:55992 +0.00011266336187471834 57628:57628 +0.00011266336187471834 35432:35432 +0.00011266336187471834 33039:33039 +0.00011266336187471834 60148:60148 +0.00011266336187471834 59954:59954 +0.00011266336187471834 58689:58689 +0.00011266336187471834 56117:56117 +0.00011266336187471834 59534:59534 +0.00011266336187471834 34560:34560 +0.00011266336187471834 33255:33255 +0.00011266336187471834 58815:58815 +0.00011266336187471834 33047:33047 +0.00011266336187471834 58395:58395 +0.00011266336187471834 34813:34813 +0.00011266336187471834 56262:56262 +0.00011266336187471834 57871:57871 +0.00011266336187471834 60926:60926 +0.00011266336187471834 60197:60197 +0.00011266336187471834 35478:35478 +0.00011266336187471834 34190:34190 +0.00011266336187471834 55805:55805 +0.00011266336187471834 60245:60245 +0.00011266336187471834 59092:59092 +0.00011266336187471834 33141:33141 +0.00011266336187471834 34643:34643 +0.00011266336187471834 58325:58325 +0.00011266336187471834 59516:59516 +0.00011266336187471834 60992:60992 +0.00011266336187471834 60849:60849 +0.00011266336187471834 58822:58822 +0.00011266336187471834 57789:57789 +0.00011266336187471834 57407:57407 +0.00011266336187471834 58577:58577 +0.00011266336187471834 58331:58331 +0.00011266336187471834 60684:60684 +0.00011266336187471834 59278:59278 +0.00011266336187471834 58307:58307 +0.00011266336187471834 33836:33836 +0.00011266336187471834 58561:58561 +0.00011266336187471834 57156:57156 +0.00011266336187471834 35319:35319 +0.00011266336187471834 59151:59151 +0.00011266336187471834 57812:57812 +0.00011266336187471834 56707:56707 +0.00011266336187471834 34705:34705 +0.00011266336187471834 59465:59465 +0.00011266336187471834 57893:57893 +0.00011266336187471834 34527:34527 +0.00011266336187471834 59933:59933 +0.00011266336187471834 57155:57155 +0.00011266336187471834 56994:56994 +0.00011266336187471834 33596:33596 +0.00011266336187471834 35267:35267 +0.00011266336187471834 34273:34273 +0.00011266336187471834 59563:59563 +0.00011266336187471834 58344:58344 +0.00011266336187471834 57239:57239 +0.00011266336187471834 34196:34196 +0.00011266336187471834 56031:56031 +0.00011266336187471834 55716:55716 +0.00011266336187471834 57504:57504 +0.00011266336187471834 35462:35462 +0.00011266336187471834 57781:57781 +0.00011266336187471834 60144:60144 +0.00011266336187471834 34034:34034 +0.00011266336187471834 57569:57569 +0.00011266336187471834 56717:56717 +0.00011266336187471834 60555:60555 +0.00011266336187471834 33460:33460 +0.00011266336187471834 32914:32914 +0.00011266336187471834 56779:56779 +0.00011266336187471834 60669:60669 +0.00011266336187471834 59578:59578 +0.00011266336187471834 57183:57183 +0.00011266336187471834 57145:57145 +0.00011266336187471834 33959:33959 +0.00011266336187471834 60583:60583 +0.00011266336187471834 59787:59787 +0.00011266336187471834 32996:32996 +0.00011266336187471834 34396:34396 +0.00011266336187471834 34007:34007 +0.00011266336187471834 56741:56741 +0.00011266336187471834 58217:58217 +0.00011266336187471834 34631:34631 +0.00011266336187471834 34800:34800 +0.00011266336187471834 59955:59955 +0.00011266336187471834 35117:35117 +0.00011266336187471834 60451:60451 +0.00011266336187471834 56453:56453 +0.00011266336187471834 33416:33416 +0.00011266336187471834 56463:56463 +0.00011266336187471834 35390:35390 +0.00011266336187471834 35159:35159 +0.00011266336187471834 34736:34736 +0.00011266336187471834 60899:60899 +0.00011266336187471834 59687:59687 +0.00011266336187471834 59479:59479 +0.00011266336187471834 33820:33820 +0.00011266336187471834 57681:57681 +0.00011266336187471834 57710:57710 +0.00011266336187471834 56542:56542 +0.00011266336187471834 60611:60611 +0.00011266336187471834 59332:59332 +0.00011266336187471834 59759:59759 +0.00011266336187471834 59331:59331 +0.00011266336187471834 34507:34507 +0.00011266336187471834 60948:60948 +0.00011266336187471834 34995:34995 +0.00011266336187471834 33742:33742 +0.00011266336187471834 60624:60624 +0.00011266336187471834 59987:59987 +0.00011266336187471834 34701:34701 +0.00011266336187471834 34921:34921 +0.00011266336187471834 60937:60937 +0.00011266336187471834 60097:60097 +0.00011266336187471834 57075:57075 +0.00011266336187471834 34706:34706 +0.00011266336187471834 34317:34317 +0.00011266336187471834 60235:60235 +0.00011266336187471834 59455:59455 +0.00011266336187471834 32795:32795 +0.00011266336187471834 59624:59624 +0.00011266336187471834 59042:59042 +0.00011266336187471834 56175:56175 +0.00011266336187471834 60683:60683 +0.00011266336187471834 34445:34445 +0.00011266336187471834 60482:60482 +0.00011266336187471834 57409:57409 +0.00011266336187471834 60171:60171 +0.00011266336187471834 34235:34235 +0.00011266336187471834 34959:34959 +0.00011266336187471834 58467:58467 +0.00011266336187471834 57304:57304 +0.00011266336187471834 59255:59255 +0.00011266336187471834 55898:55898 +0.00011266336187471834 60528:60528 +0.00011266336187471834 57421:57421 +0.00011266336187471834 33875:33875 +0.00011266336187471834 58728:58728 +0.00011266336187471834 57371:57371 +0.00011266336187471834 33341:33341 +0.00011266336187471834 58623:58623 +0.00011266336187471834 56660:56660 +0.00011266336187471834 56759:56759 +0.00011266336187471834 35169:35169 +0.00011266336187471834 33657:33657 +0.00011266336187471834 59386:59386 +0.00011266336187471834 57170:57170 +0.00011266336187471834 33096:33096 +0.00011266336187471834 60518:60518 +0.00011266336187471834 58512:58512 +0.00011266336187471834 59926:59926 +0.00011266336187471834 59934:59934 +0.00011266336187471834 56728:56728 +0.00011266336187471834 34804:34804 +0.00011266336187471834 59893:59893 +0.00011266336187471834 57362:57362 +0.00011266336187471834 57112:57112 +0.00011266336187471834 56105:56105 +0.00011266336187471834 34023:34023 +0.00011266336187471834 32990:32990 +0.00011266336187471834 59010:59010 +0.00011266336187471834 58803:58803 +0.00011266336187471834 56624:56624 +0.00011266336187471834 60133:60133 +0.00011266336187471834 60320:60320 +0.00011266336187471834 35528:35528 +0.00011266336187471834 57711:57711 +0.00011266336187471834 56790:56790 +0.00011266336187471834 56919:56919 +0.00011266336187471834 57784:57784 +0.00011266336187471834 33208:33208 +0.00011266336187471834 56478:56478 +0.00011266336187471834 34174:34174 +0.00011266336187471834 58207:58207 +0.00011266336187471834 60793:60793 +0.00011266336187471834 60264:60264 +0.00011266336187471834 33691:33691 +0.00011266336187471834 58128:58128 +0.00011266336187471834 57337:57337 +0.00011266336187471834 34557:34557 +0.00011266336187471834 32935:32935 +0.00011266336187471834 55609:55609 +0.00011266336187471834 34057:34057 +0.00011266336187471834 33303:33303 +0.00011266336187471834 59702:59702 +0.00011266336187471834 58000:58000 +0.00011266336187471834 35166:35166 +0.00011266336187471834 56978:56978 +0.00011266336187471834 56666:56666 +0.00011266336187471834 60853:60853 +0.00011266336187471834 59502:59502 +0.00011266336187471834 55706:55706 +0.00011266336187471834 58212:58212 +0.00011266336187471834 34963:34963 +0.00011266336187471834 55894:55894 +0.00011266336187471834 33541:33541 +0.00011266336187471834 33535:33535 +0.00011266336187471834 33497:33497 +0.00011266336187471834 59109:59109 +0.00011266336187471834 55963:55963 +0.00011266336187471834 34305:34305 +0.00011266336187471834 57961:57961 +0.00011266336187471834 60569:60569 +0.00011266336187471834 60599:60599 +0.00011266336187471834 59751:59751 +0.00011266336187471834 57698:57698 +0.00011266336187471834 59226:59226 +0.00011266336187471834 57115:57115 +0.00011266336187471834 35555:35555 +0.00011266336187471834 33389:33389 +0.00011266336187471834 57521:57521 +0.00011266336187471834 35104:35104 +0.00011266336187471834 56564:56564 +0.00011266336187471834 56437:56437 +0.00011266336187471834 57607:57607 +0.00011266336187471834 58671:58671 +0.00011266336187471834 55923:55923 +0.00011266336187471834 60708:60708 +0.00011266336187471834 35105:35105 +0.00011266336187471834 56650:56650 +0.00011266336187471834 32847:32847 +0.00011266336187471834 33080:33080 +0.00011266336187471834 56493:56493 +0.00011266336187471834 55865:55865 +0.00011266336187471834 35419:35419 +0.00011266336187471834 60178:60178 +0.00011266336187471834 35541:35541 +0.00011266336187471834 60393:60393 +0.00011266336187471834 33099:33099 +0.00011266336187471834 60903:60903 +0.00011266336187471834 56809:56809 +0.00011266336187471834 35376:35376 +0.00011266336187471834 34118:34118 +0.00011266336187471834 57938:57938 +0.00011266336187471834 59980:59980 +0.00011266336187471834 57099:57099 +0.00011266336187471834 34106:34106 +0.00011266336187471834 60588:60588 +0.00011266336187471834 60311:60311 +0.00011266336187471834 57357:57357 +0.00011266336187471834 57459:57459 +0.00011266336187471834 58334:58334 +0.00011266336187471834 56270:56270 +0.00011266336187471834 35428:35428 +0.00011266336187471834 34298:34298 +0.00011266336187471834 60907:60907 +0.00011266336187471834 60595:60595 +0.00011266336187471834 58595:58595 +0.00011266336187471834 34270:34270 +0.00011266336187471834 58874:58874 +0.00011266336187471834 60752:60752 +0.00011266336187471834 59522:59522 +0.00011266336187471834 58478:58478 +0.00011266336187471834 35227:35227 +0.00011266336187471834 33683:33683 +0.00011266336187471834 57463:57463 +0.00011266336187471834 60991:60991 +0.00011266336187471834 56406:56406 +0.00011266336187471834 56128:56128 +0.00011266336187471834 33204:33204 +0.00011266336187471834 56630:56630 +0.00011266336187471834 58162:58162 +0.00011266336187471834 34734:34734 +0.00011266336187471834 57879:57879 +0.00011266336187471834 34551:34551 +0.00011266336187471834 60433:60433 +0.00011266336187471834 33956:33956 +0.00011266336187471834 58753:58753 +0.00011266336187471834 34295:34295 +0.00011266336187471834 59712:59712 +0.00011266336187471834 57204:57204 +0.00011266336187471834 56955:56955 +0.00011266336187471834 56349:56349 +0.00011266336187471834 34601:34601 +0.00011266336187471834 34947:34947 +0.00011266336187471834 60956:60956 +0.00011266336187471834 34912:34912 +0.00011266336187471834 34254:34254 +0.00011266336187471834 58237:58237 +0.00011266336187471834 56653:56653 +0.00011266336187471834 60759:60759 +0.00011266336187471834 60445:60445 +0.00011266336187471834 60408:60408 +0.00011266336187471834 58333:58333 +0.00011266336187471834 59660:59660 +0.00011266336187471834 34864:34864 +0.00011266336187471834 55850:55850 +0.00011266336187471834 60361:60361 +0.00011266336187471834 58024:58024 +0.00011266336187471834 34293:34293 +0.00011266336187471834 34957:34957 +0.00011266336187471834 34399:34399 +0.00011266336187471834 59511:59511 +0.00011266336187471834 35380:35380 +0.00011266336187471834 60839:60839 +0.00011266336187471834 56491:56491 +0.00011266336187471834 34673:34673 +0.00011266336187471834 60891:60891 +0.00011266336187471834 59810:59810 +0.00011266336187471834 35486:35486 +0.00011266336187471834 58865:58865 +0.00011266336187471834 33397:33397 +0.00011266336187471834 33210:33210 +0.00011266336187471834 58347:58347 +0.00011266336187471834 56433:56433 +0.00011266336187471834 57814:57814 +0.00011266336187471834 35220:35220 +0.00011266336187471834 35176:35176 +0.00011266336187471834 59032:59032 +0.00011266336187471834 59767:59767 +0.00011266336187471834 35161:35161 +0.00011266336187471834 60919:60919 +0.00011266336187471834 34707:34707 +0.00011266336187471834 34398:34398 +0.00011266336187471834 32955:32955 +0.00011266336187471834 60659:60659 +0.00011266336187471834 34571:34571 +0.00011266336187471834 33841:33841 +0.00011266336187471834 58996:58996 +0.00011266336187471834 55727:55727 +0.00011266336187471834 60538:60538 +0.00011266336187471834 60510:60510 +0.00011266336187471834 58960:58960 +0.00011266336187471834 58954:58954 +0.00011266336187471834 55868:55868 +0.00011266336187471834 59280:59280 +0.00011266336187471834 56209:56209 +0.00011266336187471834 55993:55993 +0.00011266336187471834 34740:34740 +0.00011266336187471834 33723:33723 +0.00011266336187471834 33232:33232 +0.00011266336187471834 59111:59111 +0.00011266336187471834 34579:34579 +0.00011266336187471834 56143:56143 +0.00011266336187471834 57668:57668 +0.00011266336187471834 56240:56240 +0.00011266336187471834 55752:55752 +0.00011266336187471834 34716:34716 +0.00011266336187471834 34042:34042 +0.00011266336187471834 60950:60950 +0.00011266336187471834 57732:57732 +0.00011266336187471834 57130:57130 +0.00011266336187471834 34236:34236 +0.00011266336187471834 59313:59313 +0.00011266336187471834 57305:57305 +0.00011266336187471834 34597:34597 +0.00011266336187471834 33375:33375 +0.00011266336187471834 34251:34251 +0.00011266336187471834 33658:33658 +0.00011266336187471834 32780:32780 +0.00011266336187471834 59902:59902 +0.00011266336187471834 58536:58536 +0.00011266336187471834 34948:34948 +0.00011266336187471834 34002:34002 +0.00011266336187471834 56158:56158 +0.00011266336187471834 56287:56287 +0.00011266336187471834 56898:56898 +0.00011266336187471834 35417:35417 +0.00011266336187471834 59017:59017 +0.00011266336187471834 35151:35151 +0.00011266336187471834 33112:33112 +0.00011266336187471834 58370:58370 +0.00011266336187471834 35366:35366 +0.00011266336187471834 60714:60714 +0.00011266336187471834 58319:58319 +0.00011266336187471834 35494:35494 +0.00011266336187471834 34486:34486 +0.00011266336187471834 34370:34370 +0.00011266336187471834 55882:55882 +0.00011266336187471834 34745:34745 +0.00011266336187471834 35338:35338 +0.00011266336187471834 60618:60618 +0.00011266336187471834 59667:59667 +0.00011266336187471834 33487:33487 +0.00011266336187471834 60871:60871 +0.00011266336187471834 57640:57640 +0.00011266336187471834 34290:34290 +0.00011266336187471834 56221:56221 +0.00011266336187471834 33687:33687 +0.00011266336187471834 60375:60375 +0.00011266336187471834 35449:35449 +0.00011266336187471834 59147:59147 +0.00011266336187471834 56594:56594 +0.00011266336187471834 34308:34308 +0.00011266336187471834 59506:59506 +0.00011266336187471834 55940:55940 +0.00011266336187471834 60287:60287 +0.00011266336187471834 55928:55928 +0.00011266336187471834 58574:58574 +0.00011266336187471834 60804:60804 +0.00011266336187471834 56399:56399 +0.00011266336187471834 33668:33668 +0.00011266336187471834 56323:56323 +0.00011266336187471834 59416:59416 +0.00011266336187471834 58203:58203 +0.00011266336187471834 57811:57811 +0.00011266336187471834 57093:57093 +0.00011266336187471834 35109:35109 +0.00011266336187471834 33135:33135 +0.00011266336187471834 60745:60745 +0.00011266336187471834 33316:33316 +0.00011266336187471834 55804:55804 +0.00011266336187471834 56724:56724 +0.00011266336187471834 59940:59940 +0.00011266336187471834 33061:33061 +0.00011266336187471834 57830:57830 +0.00011266336187471834 58580:58580 +0.00011266336187471834 32836:32836 +0.00011266336187471834 58267:58267 +0.00011266336187471834 59925:59925 +0.00011266336187471834 59786:59786 +0.00011266336187471834 35067:35067 +0.00011266336187471834 58733:58733 +0.00011266336187471834 56658:56658 +0.00011266336187471834 33579:33579 +0.00011266336187471834 58734:58734 +0.00011266336187471834 56295:56295 +0.00011266336187471834 56572:56572 +0.00011266336187471834 60014:60014 +0.00011266336187471834 34753:34753 +0.00011266336187471834 58280:58280 +0.00011266336187471834 57384:57384 +0.00011266336187471834 33563:33563 +0.00011266336187471834 57338:57338 +0.00011266336187471834 56917:56917 +0.00011266336187471834 56579:56579 +0.00011266336187471834 33046:33046 +0.00011266336187471834 58971:58971 +0.00011266336187471834 33420:33420 +0.00011266336187471834 57166:57166 +0.00011266336187471834 34092:34092 +0.00011266336187471834 58731:58731 +0.00011266336187471834 60319:60319 +0.00011266336187471834 56447:56447 +0.00011266336187471834 55872:55872 +0.00011266336187471834 60990:60990 +0.00011266336187471834 35260:35260 +0.00011266336187471834 59483:59483 +0.00011266336187471834 58509:58509 +0.00011266336187471834 34894:34894 +0.00011266336187471834 32828:32828 +0.00011266336187471834 58708:58708 +0.00011266336187471834 58653:58653 +0.00011266336187471834 56382:56382 +0.00011266336187471834 59104:59104 +0.00011266336187471834 59505:59505 +0.00011266336187471834 59112:59112 +0.00011266336187471834 34259:34259 +0.00011266336187471834 33647:33647 +0.00011266336187471834 60434:60434 +0.00011266336187471834 34826:34826 +0.00011266336187471834 55914:55914 +0.00011266336187471834 60748:60748 +0.00011266336187471834 57903:57903 +0.00011266336187471834 58316:58316 +0.00011266336187471834 56142:56142 +0.00011266336187471834 56131:56131 +0.00011266336187471834 35209:35209 +0.00011266336187471834 56559:56559 +0.00011266336187471834 59302:59302 +0.00011266336187471834 33142:33142 +0.00011266336187471834 59012:59012 +0.00011266336187471834 33855:33855 +0.00011266336187471834 60633:60633 +0.00011266336187471834 57705:57705 +0.00011266336187471834 33747:33747 +0.00011266336187471834 58758:58758 +0.00011266336187471834 59107:59107 +0.00011266336187471834 58045:58045 +0.00011266336187471834 33532:33532 +0.00011266336187471834 35467:35467 +0.00011266336187471834 56440:56440 +0.00011266336187471834 33483:33483 +0.00011266336187471834 58902:58902 +0.00011266336187471834 60796:60796 +0.00011266336187471834 60358:60358 +0.00011266336187471834 35509:35509 +0.00011266336187471834 34471:34471 +0.00011266336187471834 59446:59446 +0.00011266336187471834 34355:34355 +0.00011266336187471834 33188:33188 +0.00011266336187471834 57021:57021 +0.00011266336187471834 34336:34336 +0.00011266336187471834 57858:57858 +0.00011266336187471834 58558:58558 +0.00011266336187471834 35418:35418 +0.00011266336187471834 57611:57611 +0.00011266336187471834 57237:57237 +0.00011266336187471834 33645:33645 +0.00011266336187471834 57446:57446 +0.00011266336187471834 59908:59908 +0.00011266336187471834 58643:58643 +0.00011266336187471834 56263:56263 +0.00011266336187471834 59426:59426 +0.00011266336187471834 32967:32967 +0.00011266336187471834 33651:33651 +0.00011266336187471834 58476:58476 +0.00011266336187471834 34910:34910 +0.00011266336187471834 56598:56598 +0.00011266336187471834 34965:34965 +0.00011266336187471834 33068:33068 +0.00011266336187471834 59718:59718 +0.00011266336187471834 57767:57767 +0.00011266336187471834 56420:56420 +0.00011266336187471834 60426:60426 +0.00011266336187471834 58384:58384 +0.00011266336187471834 33822:33822 +0.00011266336187471834 33578:33578 +0.00011266336187471834 56819:56819 +0.00011266336187471834 58554:58554 +0.00011266336187471834 60656:60656 +0.00011266336187471834 57094:57094 +0.00011266336187471834 56745:56745 +0.00011266336187471834 33319:33319 +0.00011266336187471834 57194:57194 +0.00011266336187471834 55885:55885 +0.00011266336187471834 59451:59451 +0.00011266336187471834 59028:59028 +0.00011266336187471834 55843:55843 +0.00011266336187471834 34197:34197 +0.00011266336187471834 32892:32892 +0.00011266336187471834 60769:60769 +0.00011266336187471834 59682:59682 +0.00011266336187471834 33033:33033 +0.00011266336187471834 60781:60781 +0.00011266336187471834 34634:34634 +0.00011266336187471834 33197:33197 +0.00011266336187471834 32920:32920 +0.00011266336187471834 57639:57639 +0.00011266336187471834 59099:59099 +0.00011266336187471834 59631:59631 +0.00011266336187471834 55670:55670 +0.00011266336187471834 57182:57182 +0.00011266336187471834 60027:60027 +0.00011266336187471834 56508:56508 +0.00011266336187471834 57485:57485 +0.00011266336187471834 56138:56138 +0.00011266336187471834 34356:34356 +0.00011266336187471834 33283:33283 +0.00011266336187471834 34294:34294 +0.00011266336187471834 60220:60220 +0.00011266336187471834 59164:59164 +0.00011266336187471834 57538:57538 +0.00011266336187471834 55797:55797 +0.00011266336187471834 55624:55624 +0.00011266336187471834 59524:59524 +0.00011266336187471834 56982:56982 +0.00011266336187471834 33038:33038 +0.00011266336187471834 57005:57005 +0.00011266336187471834 56303:56303 +0.00011266336187471834 57962:57962 +0.00011266336187471834 33604:33604 +0.00011266336187471834 33242:33242 +0.00011266336187471834 58283:58283 +0.00011266336187471834 59202:59202 +0.00011266336187471834 56862:56862 +0.00011266336187471834 35514:35514 +0.00011266336187471834 34901:34901 +0.00011266336187471834 60930:60930 +0.00011266336187471834 35211:35211 +0.00011266336187471834 60084:60084 +0.00011266336187471834 60575:60575 +0.00011266336187471834 57821:57821 +0.00011266336187471834 33043:33043 +0.00011266336187471834 34952:34952 +0.00011266336187471834 33750:33750 +0.00011266336187471834 57494:57494 +0.00011266336187471834 58613:58613 +0.00011266336187471834 56679:56679 +0.00011266336187471834 32964:32964 +0.00011266336187471834 56875:56875 +0.00011266336187471834 58042:58042 +0.00011266336187471834 57008:57008 +0.00011266336187471834 58115:58115 +0.00011266336187471834 57839:57839 +0.00011266336187471834 58790:58790 +0.00011266336187471834 58862:58862 +0.00011266336187471834 33749:33749 +0.00011266336187471834 34743:34743 +0.00011266336187471834 56929:56929 +0.00011266336187471834 56900:56900 +0.00011266336187471834 34498:34498 +0.00011266336187471834 32812:32812 +0.00011266336187471834 56682:56682 +0.00011266336187471834 33345:33345 +0.00011266336187471834 57885:57885 +0.00011266336187471834 56326:56326 +0.00011266336187471834 58968:58968 +0.00011266336187471834 57535:57535 +0.00011266336187471834 60123:60123 +0.00011266336187471834 56610:56610 +0.00011266336187471834 35410:35410 +0.00011266336187471834 56487:56487 +0.00011266336187471834 55950:55950 +0.00011266336187471834 57034:57034 +0.00011266336187471834 32900:32900 +0.00011266336187471834 35399:35399 +0.00011266336187471834 55673:55673 +0.00011266336187471834 57500:57500 +0.00011266336187471834 56292:56292 +0.00011266336187471834 59848:59848 +0.00011266336187471834 60190:60190 +0.00011266336187471834 57404:57404 +0.00011266336187471834 33539:33539 +0.00011266336187471834 35326:35326 +0.00011266336187471834 59720:59720 +0.00011266336187471834 56293:56293 +0.00011266336187471834 57745:57745 +0.00011266336187471834 33287:33287 +0.00011266336187471834 33962:33962 +0.00011266336187471834 33769:33769 +0.00011266336187471834 59335:59335 +0.00011266336187471834 33305:33305 +0.00011266336187471834 57259:57259 +0.00011266336187471834 35480:35480 +0.00011266336187471834 57898:57898 +0.00011266336187471834 58919:58919 +0.00011266336187471834 57709:57709 +0.00011266336187471834 34836:34836 +0.00011266336187471834 58553:58553 +0.00011266336187471834 56160:56160 +0.00011266336187471834 34654:34654 +0.00011266336187471834 34516:34516 +0.00011266336187471834 33562:33562 +0.00011266336187471834 57537:57537 +0.00011266336187471834 56470:56470 +0.00011266336187471834 33975:33975 +0.00011266336187471834 58482:58482 +0.00011266336187471834 56498:56498 +0.00011266336187471834 33594:33594 +0.00011266336187471834 55616:55616 +0.00011266336187471834 35468:35468 +0.00011266336187471834 59636:59636 +0.00011266336187471834 59130:59130 +0.00011266336187471834 58929:58929 +0.00011266336187471834 58357:58357 +0.00011266336187471834 58748:58748 +0.00011266336187471834 56926:56926 +0.00011266336187471834 60279:60279 +0.00011266336187471834 57682:57682 +0.00011266336187471834 33054:33054 +0.00011266336187471834 57867:57867 +0.00011266336187471834 35056:35056 +0.00011266336187471834 59343:59343 +0.00011266336187471834 58039:58039 +0.00011266336187471834 34416:34416 +0.00011266336187471834 33775:33775 +0.00011266336187471834 58713:58713 +0.00011266336187471834 56502:56502 +0.00011266336187471834 59914:59914 +0.00011266336187471834 34173:34173 +0.00011266336187471834 60640:60640 +0.00011266336187471834 57269:57269 +0.00011266336187471834 59291:59291 +0.00011266336187471834 60494:60494 +0.00011266336187471834 58058:58058 +0.00011266336187471834 60033:60033 +0.00011266336187471834 34384:34384 +0.00011266336187471834 56275:56275 +0.00011266336187471834 60530:60530 +0.00011266336187471834 35031:35031 +0.00011266336187471834 32976:32976 +0.00011266336187471834 55778:55778 +0.00011266336187471834 59863:59863 +0.00011266336187471834 57741:57741 +0.00011266336187471834 55684:55684 +0.00011266336187471834 60489:60489 +0.00011266336187471834 34205:34205 +0.00011266336187471834 33581:33581 +0.00011266336187471834 57742:57742 +0.00011266336187471834 58481:58481 +0.00011266336187471834 59469:59469 +0.00011266336187471834 35396:35396 +0.00011266336187471834 59774:59774 +0.00011266336187471834 34931:34931 +0.00011266336187471834 57308:57308 +0.00011266336187471834 35288:35288 +0.00011266336187471834 35044:35044 +0.00011266336187471834 58282:58282 +0.00011266336187471834 56503:56503 +0.00011266336187471834 57017:57017 +0.00011266336187471834 57604:57604 +0.00011266336187471834 35102:35102 +0.00011266336187471834 34028:34028 +0.00011266336187471834 60928:60928 +0.00011266336187471834 59647:59647 +0.00011266336187471834 33263:33263 +0.00011266336187471834 33169:33169 +0.00011266336187471834 58575:58575 +0.00011266336187471834 56664:56664 +0.00011266336187471834 60160:60160 +0.00011266336187471834 56102:56102 +0.00011266336187471834 33566:33566 +0.00011266336187471834 33327:33327 +0.00011266336187471834 60910:60910 +0.00011266336187471834 34017:34017 +0.00011266336187471834 34807:34807 +0.00011266336187471834 35049:35049 +0.00011266336187471834 60619:60619 +0.00011266336187471834 58194:58194 +0.00011266336187471834 59533:59533 +0.00011266336187471834 34074:34074 +0.00011266336187471834 58602:58602 +0.00011266336187471834 58079:58079 +0.00011266336187471834 57700:57700 +0.00011266336187471834 35314:35314 +0.00011266336187471834 60430:60430 +0.00011266336187471834 33862:33862 +0.00011266336187471834 55911:55911 +0.00011266336187471834 33705:33705 +0.00011266336187471834 56300:56300 +0.00011266336187471834 57386:57386 +0.00011266336187471834 59873:59873 +0.00011266336187471834 55690:55690 +0.00011266336187471834 34096:34096 +0.00011266336187471834 32927:32927 +0.00011266336187471834 60566:60566 +0.00011266336187471834 34802:34802 +0.00011266336187471834 55822:55822 +0.00011266336187471834 58066:58066 +0.00011266336187471834 33671:33671 +0.00011266336187471834 35069:35069 +0.00011266336187471834 34228:34228 +0.00011266336187471834 32945:32945 +0.00011266336187471834 57348:57348 +0.00011266336187471834 34876:34876 +0.00011266336187471834 59273:59273 +0.00011266336187471834 34941:34941 +0.00011266336187471834 57795:57795 +0.00011266336187471834 57554:57554 +0.00011266336187471834 57490:57490 +0.00011266336187471834 60809:60809 +0.00011266336187471834 59924:59924 +0.00011266336187471834 34621:34621 +0.00011266336187471834 55766:55766 +0.00011266336187471834 33557:33557 +0.00011266336187471834 57685:57685 +0.00011266336187471834 60139:60139 +0.00011266336187471834 57434:57434 +0.00011266336187471834 58540:58540 +0.00011266336187471834 35402:35402 +0.00011266336187471834 34632:34632 +0.00011266336187471834 32962:32962 +0.00011266336187471834 60120:60120 +0.00011266336187471834 59826:59826 +0.00011266336187471834 55972:55972 +0.00011266336187471834 34913:34913 +0.00011266336187471834 59850:59850 +0.00011266336187471834 58377:58377 +0.00011266336187471834 57332:57332 +0.00011266336187471834 33760:33760 +0.00011266336187471834 56378:56378 +0.00011266336187471834 60890:60890 +0.00011266336187471834 57526:57526 +0.00011266336187471834 35356:35356 +0.00011266336187471834 33262:33262 +0.00011266336187471834 34528:34528 +0.00011266336187471834 34480:34480 +0.00011266336187471834 55884:55884 +0.00011266336187471834 35352:35352 +0.00011266336187471834 58428:58428 +0.00011266336187471834 60480:60480 +0.00011266336187471834 35313:35313 +0.00011266336187471834 34367:34367 +0.00011266336187471834 56880:56880 +0.00011266336187471834 59323:59323 +0.00011266336187471834 59131:59131 +0.00011266336187471834 58472:58472 +0.00011266336187471834 34440:34440 +0.00011266336187471834 34975:34975 +0.00011266336187471834 57895:57895 +0.00011266336187471834 57147:57147 +0.00011266336187471834 57061:57061 +0.00011266336187471834 58360:58360 +0.00011266336187471834 58082:58082 +0.00011266336187471834 59915:59915 +0.00011266336187471834 59067:59067 +0.00011266336187471834 35558:35558 +0.00011266336187471834 59499:59499 +0.00011266336187471834 57345:57345 +0.00011266336187471834 56391:56391 +0.00011266336187471834 55627:55627 +0.00011266336187471834 35373:35373 +0.00011266336187471834 59545:59545 +0.00011266336187471834 55938:55938 +0.00011266336187471834 58767:58767 +0.00011266336187471834 34630:34630 +0.00011266336187471834 56468:56468 +0.00011266336187471834 56781:56781 +0.00011266336187471834 33320:33320 +0.00011266336187471834 34504:34504 +0.00011266336187471834 59918:59918 +0.00011266336187471834 57620:57620 +0.00011266336187471834 34767:34767 +0.00011266336187471834 58976:58976 +0.00011266336187471834 58054:58054 +0.00011266336187471834 56345:56345 +0.00011266336187471834 60723:60723 +0.00011266336187471834 60688:60688 +0.00011266336187471834 59428:59428 +0.00011266336187471834 56100:56100 +0.00011266336187471834 55967:55967 +0.00011266336187471834 56546:56546 +0.00011266336187471834 34726:34726 +0.00011266336187471834 33446:33446 +0.00011266336187471834 58583:58583 +0.00011266336187471834 59986:59986 +0.00011266336187471834 34896:34896 +0.00011266336187471834 58519:58519 +0.00011266336187471834 55901:55901 +0.00011266336187471834 60026:60026 +0.00011266336187471834 32897:32897 +0.00011266336187471834 56206:56206 +0.00011266336187471834 58915:58915 +0.00011266336187471834 34198:34198 +0.00011266336187471834 57847:57847 +0.00011266336187471834 57947:57947 +0.00011266336187471834 60101:60101 +0.00011266336187471834 57096:57096 +0.00011266336187471834 35448:35448 +0.00011266336187471834 56617:56617 +0.00011266336187471834 34176:34176 +0.00011266336187471834 60179:60179 +0.00011266336187471834 60519:60519 +0.00011266336187471834 33470:33470 +0.00011266336187471834 60037:60037 +0.00011266336187471834 34887:34887 +0.00011266336187471834 58002:58002 +0.00011266336187471834 33677:33677 +0.00011266336187471834 58499:58499 +0.00011266336187471834 57244:57244 +0.00011266336187471834 33852:33852 +0.00011266336187471834 33415:33415 +0.00011266336187471834 33152:33152 +0.00011266336187471834 56586:56586 +0.00011266336187471834 60297:60297 +0.00011266336187471834 56521:56521 +0.00011266336187471834 59549:59549 +0.00011266336187471834 35362:35362 +0.00011266336187471834 34865:34865 +0.00011266336187471834 34609:34609 +0.00011266336187471834 58397:58397 +0.00011266336187471834 57124:57124 +0.00011266336187471834 56273:56273 +0.00011266336187471834 35441:35441 +0.00011266336187471834 34003:34003 +0.00011266336187471834 33547:33547 +0.00011266336187471834 60984:60984 +0.00011266336187471834 60692:60692 +0.00011266336187471834 58361:58361 +0.00011266336187471834 57282:57282 +0.00011266336187471834 33817:33817 +0.00011266336187471834 33114:33114 +0.00011266336187471834 56186:56186 +0.00011266336187471834 56428:56428 +0.00011266336187471834 33819:33819 +0.00011266336187471834 55859:55859 +0.00011266336187471834 59167:59167 +0.00011266336187471834 59021:59021 +0.00011266336187471834 57863:57863 +0.00011266336187471834 60641:60641 +0.00011266336187471834 60170:60170 +0.00011266336187471834 58291:58291 +0.00011266336187471834 55939:55939 +0.00011266336187471834 34064:34064 +0.00011266336187471834 60124:60124 +0.00011266336187471834 33485:33485 +0.00011266336187471834 59823:59823 +0.00011266336187471834 33181:33181 +0.00011266336187471834 32981:32981 +0.00011266336187471834 56908:56908 +0.00011266336187471834 56039:56039 +0.00011266336187471834 55825:55825 +0.00011266336187471834 35099:35099 +0.00011266336187471834 33973:33973 +0.00011266336187471834 33370:33370 +0.00011266336187471834 32894:32894 +0.00011266336187471834 33471:33471 +0.00011266336187471834 33423:33423 +0.00011266336187471834 57150:57150 +0.00011266336187471834 32819:32819 +0.00011266336187471834 57249:57249 +0.00011266336187471834 60458:60458 +0.00011266336187471834 59054:59054 +0.00011266336187471834 57285:57285 +0.00011266336187471834 35003:35003 +0.00011266336187471834 33215:33215 +0.00011266336187471834 57632:57632 +0.00011266336187471834 57298:57298 +0.00011266336187471834 60931:60931 +0.00011266336187471834 58392:58392 +0.00011266336187471834 57985:57985 +0.00011266336187471834 58201:58201 +0.00011266336187471834 56375:56375 +0.00011266336187471834 58134:58134 +0.00011266336187471834 58264:58264 +0.00011266336187471834 57792:57792 +0.00011266336187471834 35262:35262 +0.00011266336187471834 33847:33847 +0.00011266336187471834 59963:59963 +0.00011266336187471834 56904:56904 +0.00011266336187471834 60585:60585 +0.00011266336187471834 60105:60105 +0.00011266336187471834 33017:33017 +0.00011266336187471834 59792:59792 +0.00011266336187471834 58680:58680 +0.00011266336187471834 35401:35401 +0.00011266336187471834 60282:60282 +0.00011266336187471834 58048:58048 +0.00011266336187471834 34201:34201 +0.00011266336187471834 60456:60456 +0.00011266336187471834 34322:34322 +0.00011266336187471834 33701:33701 +0.00011266336187471834 59463:59463 +0.00011266336187471834 33610:33610 +0.00011266336187471834 58611:58611 +0.00011266336187471834 56448:56448 +0.00011266336187471834 58149:58149 +0.00011266336187471834 58049:58049 +0.00011266336187471834 58928:58928 +0.00011266336187471834 34744:34744 +0.00011266336187471834 60768:60768 +0.00011266336187471834 56850:56850 +0.00011266336187471834 56634:56634 +0.00011266336187471834 59804:59804 +0.00011266336187471834 34219:34219 +0.00011266336187471834 60513:60513 +0.00011266336187471834 59656:59656 +0.00011266336187471834 56348:56348 +0.00011266336187471834 55760:55760 +0.00011266336187471834 58841:58841 +0.00011266336187471834 60727:60727 +0.00011266336187471834 60291:60291 +0.00011266336187471834 59376:59376 +0.00011266336187471834 59207:59207 +0.00011266336187471834 35230:35230 +0.00011266336187471834 33832:33832 +0.00011266336187471834 33818:33818 +0.00011266336187471834 56636:56636 +0.00011266336187471834 56327:56327 +0.00011266336187471834 55927:55927 +0.00011266336187471834 34772:34772 +0.00011266336187471834 34161:34161 +0.00011266336187471834 32893:32893 +0.00011266336187471834 55919:55919 +0.00011266336187471834 34946:34946 +0.00011266336187471834 33350:33350 +0.00011266336187471834 56236:56236 +0.00011266336187471834 34794:34794 +0.00011266336187471834 33584:33584 +0.00011266336187471834 61000:61000 +0.00011266336187471834 60422:60422 +0.00011266336187471834 60522:60522 +0.00011266336187471834 33989:33989 +0.00011266336187471834 33042:33042 +0.00011266336187471834 59421:59421 +0.00011266336187471834 60208:60208 +0.00011266336187471834 34364:34364 +0.00011266336187471834 59583:59583 +0.00011266336187471834 57133:57133 +0.00011266336187471834 35078:35078 +0.00011266336187471834 59770:59770 +0.00011266336187471834 58582:58582 +0.00011266336187471834 33667:33667 +0.00011266336187471834 33332:33332 +0.00011266336187471834 57890:57890 +0.00011266336187471834 59445:59445 +0.00011266336187471834 58909:58909 +0.00011266336187471834 58510:58510 +0.00011266336187471834 35082:35082 +0.00011266336187471834 34244:34244 +0.00011266336187471834 58935:58935 +0.00011266336187471834 34264:34264 +0.00011266336187471834 33223:33223 +0.00011266336187471834 56828:56828 +0.00011266336187471834 58528:58528 +0.00011266336187471834 57716:57716 +0.00011266336187471834 57428:57428 +0.00011266336187471834 35063:35063 +0.00011266336187471834 59118:59118 +0.00011266336187471834 56673:56673 +0.00011266336187471834 55707:55707 +0.00011266336187471834 60846:60846 +0.00011266336187471834 58083:58083 +0.00011266336187471834 56595:56595 +0.00011266336187471834 58879:58879 +0.00011266336187471834 58549:58549 +0.00011266336187471834 35162:35162 +0.00011266336187471834 57894:57894 +0.00011266336187471834 57881:57881 +0.00011266336187471834 60314:60314 +0.00011266336187471834 60576:60576 +0.00011266336187471834 58502:58502 +0.00011266336187471834 58110:58110 +0.00011266336187471834 57053:57053 +0.00011266336187471834 56554:56554 +0.00011266336187471834 60634:60634 +0.00011266336187471834 32907:32907 +0.00011266336187471834 57161:57161 +0.00011266336187471834 56523:56523 +0.00011266336187471834 35234:35234 +0.00011266336187471834 33883:33883 +0.00011266336187471834 58276:58276 +0.00011266336187471834 60823:60823 +0.00011266336187471834 55708:55708 +0.00011266336187471834 34420:34420 +0.00011266336187471834 57813:57813 +0.00011266336187471834 57692:57692 +0.00011266336187471834 58287:58287 +0.00011266336187471834 56121:56121 +0.00011266336187471834 33279:33279 +0.00011266336187471834 59788:59788 +0.00011266336187471834 33774:33774 +0.00011266336187471834 57103:57103 +0.00011266336187471834 56313:56313 +0.00011266336187471834 34423:34423 +0.00011266336187471834 33894:33894 +0.00011266336187471834 34607:34607 +0.00011266336187471834 33161:33161 +0.00011266336187471834 33166:33166 +0.00011266336187471834 59175:59175 +0.00011266336187471834 34575:34575 +0.00011266336187471834 60002:60002 +0.00011266336187471834 34577:34577 +0.00011266336187471834 56483:56483 +0.00011266336187471834 33710:33710 +0.00011266336187471834 33137:33137 +0.00011266336187471834 55667:55667 +0.00011266336187471834 58106:58106 +0.00011266336187471834 56358:56358 +0.00011266336187471834 35253:35253 +0.00011266336187471834 59172:59172 +0.00011266336187471834 56446:56446 +0.00011266336187471834 34050:34050 +0.00011266336187471834 60273:60273 +0.00011266336187471834 34588:34588 +0.00011266336187471834 34490:34490 +0.00011266336187471834 60486:60486 +0.00011266336187471834 58872:58872 +0.00011266336187471834 58188:58188 +0.00011266336187471834 35456:35456 +0.00011266336187471834 33455:33455 +0.00011266336187471834 58657:58657 +0.00011266336187471834 60339:60339 +0.00011266336187471834 56957:56957 +0.00011266336187471834 58470:58470 +0.00011266336187471834 59055:59055 +0.00011266336187471834 34542:34542 +0.00011266336187471834 60867:60867 +0.00011266336187471834 59635:59635 +0.00011266336187471834 33365:33365 +0.00011266336187471834 34669:34669 +0.00011266336187471834 33359:33359 +0.00011266336187471834 56233:56233 +0.00011266336187471834 58744:58744 +0.00011266336187471834 33777:33777 +0.00011266336187471834 60888:60888 +0.00011266336187471834 35165:35165 +0.00011266336187471834 60729:60729 +0.00011266336187471834 56315:56315 +0.00011266336187471834 58372:58372 +0.00011266336187471834 57751:57751 +0.00011266336187471834 60238:60238 +0.00011266336187471834 55985:55985 +0.00011266336187471834 32858:32858 +0.00011266336187471834 34773:34773 +0.00011266336187471834 34993:34993 +0.00011266336187471834 60193:60193 +0.00011266336187471834 59474:59474 +0.00011266336187471834 34521:34521 +0.00011266336187471834 55991:55991 +0.00011266336187471834 35344:35344 +0.00011266336187471834 56714:56714 +0.00011266336187471834 33811:33811 +0.00011266336187471834 33280:33280 +0.00011266336187471834 34090:34090 +0.00011266336187471834 33510:33510 +0.00011266336187471834 34482:34482 +0.00011266336187471834 60934:60934 +0.00011266336187471834 34809:34809 +0.00011266336187471834 34549:34549 +0.00011266336187471834 56766:56766 +0.00011266336187471834 60916:60916 +0.00011266336187471834 55829:55829 +0.00011266336187471834 60431:60431 +0.00011266336187471834 56853:56853 +0.00011266336187471834 60673:60673 +0.00011266336187471834 34838:34838 +0.00011266336187471834 55687:55687 +0.00011266336187471834 35158:35158 +0.00011266336187471834 58717:58717 +0.00011266336187471834 60638:60638 +0.00011266336187471834 60473:60473 +0.00011266336187471834 33478:33478 +0.00011266336187471834 60821:60821 +0.00011266336187471834 34447:34447 +0.00011266336187471834 57580:57580 +0.00011266336187471834 60056:60056 +0.00011266336187471834 60626:60626 +0.00011266336187471834 56471:56471 +0.00011266336187471834 34518:34518 +0.00011266336187471834 34133:34133 +0.00011266336187471834 33386:33386 +0.00011266336187471834 56006:56006 +0.00011266336187471834 33527:33527 +0.00011266336187471834 33122:33122 +0.00011266336187471834 59407:59407 +0.00011266336187471834 34132:34132 +0.00011266336187471834 57822:57822 +0.00011266336187471834 33203:33203 +0.00011266336187471834 34476:34476 +0.00011266336187471834 33070:33070 +0.00011266336187471834 60740:60740 +0.00011266336187471834 59108:59108 +0.00011266336187471834 58525:58525 +0.00011266336187471834 56103:56103 +0.00011266336187471834 34639:34639 +0.00011266336187471834 34459:34459 +0.00011266336187471834 59837:59837 +0.00011266336187471834 56605:56605 +0.00011266336187471834 56489:56489 +0.00011266336187471834 58726:58726 +0.00011266336187471834 57702:57702 +0.00011266336187471834 34496:34496 +0.00011266336187471834 57287:57287 +0.00011266336187471834 34065:34065 +0.00011266336187471834 34032:34032 +0.00011266336187471834 58364:58364 +0.00011266336187471834 59775:59775 +0.00011266336187471834 58187:58187 +0.00011266336187471834 57518:57518 +0.00011266336187471834 55925:55925 +0.00011266336187471834 56988:56988 +0.00011266336187471834 59211:59211 +0.00011266336187471834 57397:57397 +0.00011266336187471834 59354:59354 +0.00011266336187471834 35447:35447 +0.00011266336187471834 59168:59168 +0.00011266336187471834 58610:58610 +0.00011266336187471834 34307:34307 +0.00011266336187471834 58089:58089 +0.00011266336187471834 60225:60225 +0.00011266336187471834 57931:57931 +0.00011266336187471834 56893:56893 +0.00011266336187471834 58301:58301 +0.00011266336187471834 32787:32787 +0.00011266336187471834 59951:59951 +0.00011266336187471834 55981:55981 +0.00011266336187471834 59337:59337 +0.00011266336187471834 59006:59006 +0.00011266336187471834 58505:58505 +0.00011266336187471834 35127:35127 +0.00011266336187471834 56066:56066 +0.00011266336187471834 35252:35252 +0.00011266336187471834 59002:59002 +0.00011266336187471834 57609:57609 +0.00011266336187471834 35129:35129 +0.00011266336187471834 34595:34595 +0.00011266336187471834 33924:33924 +0.00011266336187471834 60446:60446 +0.00011266336187471834 35210:35210 +0.00011266336187471834 55648:55648 +0.00011266336187471834 57677:57677 +0.00011266336187471834 57010:57010 +0.00011266336187471834 35231:35231 +0.00011266336187471834 59181:59181 +0.00011266336187471834 57316:57316 +0.00011266336187471834 60369:60369 +0.00011266336187471834 33356:33356 +0.00011266336187471834 33111:33111 +0.00011266336187471834 35073:35073 +0.00011266336187471834 34088:34088 +0.00011266336187471834 60750:60750 +0.00011266336187471834 58695:58695 +0.00011266336187471834 57790:57790 +0.00011266336187471834 56200:56200 +0.00011266336187471834 33417:33417 +0.00011266336187471834 57874:57874 +0.00011266336187471834 56266:56266 +0.00011266336187471834 33612:33612 +0.00011266336187471834 57432:57432 +0.00011266336187471834 56855:56855 +0.00011266336187471834 60181:60181 +0.00011266336187471834 56154:56154 +0.00011266336187471834 60290:60290 +0.00011266336187471834 56611:56611 +0.00011266336187471834 58807:58807 +0.00011266336187471834 56311:56311 +0.00011266336187471834 56457:56457 +0.00011266336187471834 55863:55863 +0.00011266336187471834 57436:57436 +0.00011266336187471834 33869:33869 +0.00011266336187471834 34084:34084 +0.00011266336187471834 57990:57990 +0.00011266336187471834 56009:56009 +0.00011266336187471834 60941:60941 +0.00011266336187471834 60837:60837 +0.00011266336187471834 34033:34033 +0.00011266336187471834 57164:57164 +0.00011266336187471834 55880:55880 +0.00011266336187471834 60778:60778 +0.00011266336187471834 59760:59760 +0.00011266336187471834 59556:59556 +0.00011266336187471834 60694:60694 +0.00011266336187471834 33227:33227 +0.00011266336187471834 60994:60994 +0.00011266336187471834 35085:35085 +0.00011266336187471834 58410:58410 +0.00011266336187471834 60889:60889 +0.00011266336187471834 57163:57163 +0.00011266336187471834 58380:58380 +0.00011266336187471834 56045:56045 +0.00011266336187471834 59780:59780 +0.00011266336187471834 57773:57773 +0.00011266336187471834 33031:33031 +0.00011266336187471834 59851:59851 +0.00011266336187471834 59274:59274 +0.00011266336187471834 59287:59287 +0.00011266336187471834 55837:55837 +0.00011266336187471834 60210:60210 +0.00011266336187471834 60687:60687 +0.00011266336187471834 57949:57949 +0.00011266336187471834 60534:60534 +0.00011266336187471834 33367:33367 +0.00011266336187471834 58868:58868 +0.00011266336187471834 35100:35100 +0.00011266336187471834 60798:60798 +0.00011266336187471834 55879:55879 +0.00011266336187471834 33599:33599 +0.00011266336187471834 34049:34049 +0.00011266336187471834 34660:34660 +0.00011266336187471834 59240:59240 +0.00011266336187471834 34559:34559 +0.00011266336187471834 33799:33799 +0.00011266336187471834 58130:58130 +0.00011266336187471834 57472:57472 +0.00011266336187471834 32825:32825 +0.00011266336187471834 34955:34955 +0.00011266336187471834 60524:60524 +0.00011266336187471834 57703:57703 +0.00011266336187471834 33216:33216 +0.00011266336187471834 60842:60842 +0.00011266336187471834 59968:59968 +0.00011266336187471834 35502:35502 +0.00011266336187471834 58062:58062 +0.00011266336187471834 34076:34076 +0.00011266336187471834 59685:59685 +0.00011266336187471834 56678:56678 +0.00011266336187471834 34026:34026 +0.00011266336187471834 57835:57835 +0.00011266336187471834 56153:56153 +0.00011266336187471834 56951:56951 +0.00011266336187471834 58771:58771 +0.00011266336187471834 57764:57764 +0.00011266336187471834 33473:33473 +0.00011266336187471834 59557:59557 +0.00011266336187471834 57514:57514 +0.00011266336187471834 34878:34878 +0.00011266336187471834 34098:34098 +0.00011266336187471834 33348:33348 +0.00011266336187471834 60593:60593 +0.00011266336187471834 35135:35135 +0.00011266336187471834 59137:59137 +0.00011266336187471834 56026:56026 +0.00011266336187471834 35296:35296 +0.00011266336187471834 56817:56817 +0.00011266336187471834 33404:33404 +0.00011266336187471834 34167:34167 +0.00011266336187471834 33018:33018 +0.00011266336187471834 57679:57679 +0.00011266336187471834 57601:57601 +0.00011266336187471834 35297:35297 +0.00011266336187471834 59581:59581 +0.00011266336187471834 59212:59212 +0.00011266336187471834 59094:59094 +0.00011266336187471834 57530:57530 +0.00011266336187471834 56897:56897 +0.00011266336187471834 35349:35349 +0.00011266336187471834 59662:59662 +0.00011266336187471834 58097:58097 +0.00011266336187471834 57635:57635 +0.00011266336187471834 60404:60404 +0.00011266336187471834 59740:59740 +0.00011266336187471834 35118:35118 +0.00011266336187471834 34047:34047 +0.00011266336187471834 33996:33996 +0.00011266336187471834 35552:35552 +0.00011266336187471834 35164:35164 +0.00011266336187471834 56681:56681 +0.00011266336187471834 59043:59043 +0.00011266336187471834 57592:57592 +0.00011266336187471834 57347:57347 +0.00011266336187471834 35439:35439 +0.00011266336187471834 33736:33736 +0.00011266336187471834 58414:58414 +0.00011266336187471834 34310:34310 +0.00011266336187471834 56740:56740 +0.00011266336187471834 34914:34914 +0.00011266336187471834 57905:57905 +0.00011266336187471834 55897:55897 +0.00011266336187471834 33275:33275 +0.00011266336187471834 33063:33063 +0.00011266336187471834 59992:59992 +0.00011266336187471834 56878:56878 +0.00011266336187471834 56167:56167 +0.00011266336187471834 60427:60427 +0.00011266336187471834 58236:58236 +0.00011266336187471834 58065:58065 +0.00011266336187471834 33237:33237 +0.00011266336187471834 59572:59572 +0.00011266336187471834 33966:33966 +0.00011266336187471834 58901:58901 +0.00011266336187471834 55772:55772 +0.00011266336187471834 34093:34093 +0.00011266336187471834 60500:60500 +0.00011266336187471834 58805:58805 +0.00011266336187471834 58337:58337 +0.00011266336187471834 33021:33021 +0.00011266336187471834 58109:58109 +0.00011266336187471834 56860:56860 +0.00011266336187471834 60154:60154 +0.00011266336187471834 58997:58997 +0.00011266336187471834 60860:60860 +0.00011266336187471834 60042:60042 +0.00011266336187471834 56552:56552 +0.00011266336187471834 34973:34973 +0.00011266336187471834 56972:56972 +0.00011266336187471834 56826:56826 +0.00011266336187471834 55871:55871 +0.00011266336187471834 33329:33329 +0.00011266336187471834 58541:58541 +0.00011266336187471834 57782:57782 +0.00011266336187471834 33138:33138 +0.00011266336187471834 57382:57382 +0.00011266336187471834 33147:33147 +0.00011266336187471834 58240:58240 +0.00011266336187471834 34334:34334 +0.00011266336187471834 55723:55723 +0.00011266336187471834 56743:56743 +0.00011266336187471834 57902:57902 +0.00011266336187471834 59877:59877 +0.00011266336187471834 34200:34200 +0.00011266336187471834 32821:32821 +0.00011266336187471834 60092:60092 +0.00011266336187471834 59275:59275 +0.00011266336187471834 57648:57648 +0.00011266336187471834 60780:60780 +0.00011266336187471834 33292:33292 +0.00011266336187471834 59949:59949 +0.00011266336187471834 57388:57388 +0.00011266336187471834 58033:58033 +0.00011266336187471834 55705:55705 +0.00011266336187471834 34923:34923 +0.00011266336187471834 60413:60413 +0.00011266336187471834 56824:56824 +0.00011266336187471834 33125:33125 +0.00011266336187471834 59825:59825 +0.00011266336187471834 57406:57406 +0.00011266336187471834 56230:56230 +0.00011266336187471834 60294:60294 +0.00011266336187471834 57152:57152 +0.00011266336187471834 32775:32775 +0.00011266336187471834 58539:58539 +0.00011266336187471834 33871:33871 +0.00011266336187471834 56255:56255 +0.00011266336187471834 60756:60756 +0.00011266336187471834 34039:34039 +0.00011266336187471834 32839:32839 +0.00011266336187471834 60504:60504 +0.00011266336187471834 58538:58538 +0.00011266336187471834 56058:56058 +0.00011266336187471834 33627:33627 +0.00011266336187471834 34053:34053 +0.00011266336187471834 58196:58196 +0.00011266336187471834 58027:58027 +0.00011266336187471834 60999:60999 +0.00011266336187471834 34350:34350 +0.00011266336187471834 32769:32769 +0.00011266336187471834 59937:59937 +0.00011266336187471834 55817:55817 +0.00011266336187471834 55757:55757 +0.00011266336187471834 60840:60840 +0.00011266336187471834 35359:35359 +0.00011266336187471834 58569:58569 +0.00011266336187471834 58552:58552 +0.00011266336187471834 57525:57525 +0.00011266336187471834 33221:33221 +0.00011266336187471834 59150:59150 +0.00011266336187471834 59828:59828 +0.00011266336187471834 33086:33086 +0.00011266336187471834 34573:34573 +0.00011266336187471834 60013:60013 +0.00011266336187471834 56984:56984 +0.00011266336187471834 33602:33602 +0.00011266336187471834 59536:59536 +0.00011266336187471834 32803:32803 +0.00011266336187471834 56980:56980 +0.00011266336187471834 34760:34760 +0.00011266336187471834 58167:58167 +0.00011266336187471834 59993:59993 +0.00011266336187471834 56271:56271 +0.00011266336187471834 33887:33887 +0.00011266336187471834 60089:60089 +0.00011266336187471834 57023:57023 +0.00011266336187471834 56060:56060 +0.00011266336187471834 57661:57661 +0.00011266336187471834 33851:33851 +0.00011266336187471834 58743:58743 +0.00011266336187471834 33053:33053 +0.00011266336187471834 32906:32906 +0.00011266336187471834 60826:60826 +0.00011266336187471834 34508:34508 +0.00011266336187471834 59301:59301 +0.00011266336187471834 34315:34315 +0.00011266336187471834 60309:60309 +0.00011266336187471834 35435:35435 +0.00011266336187471834 58945:58945 +0.00011266336187471834 56426:56426 +0.00011266336187471834 33639:33639 +0.00011266336187471834 60590:60590 +0.00011266336187471834 57724:57724 +0.00011266336187471834 56947:56947 +0.00011266336187471834 60078:60078 +0.00011266336187471834 59899:59899 +0.00011266336187471834 59754:59754 +0.00011266336187471834 56464:56464 +0.00011266336187471834 33625:33625 +0.00011266336187471834 34443:34443 +0.00011266336187471834 34992:34992 +0.00011266336187471834 33737:33737 +0.00011266336187471834 34324:34324 +0.00011266336187471834 57880:57880 +0.00011266336187471834 56280:56280 +0.00011266336187471834 55960:55960 +0.00011266336187471834 32862:32862 +0.00011266336187471834 55738:55738 +0.00011266336187471834 34475:34475 +0.00011266336187471834 34280:34280 +0.00011266336187471834 56506:56506 +0.00011266336187471834 59690:59690 +0.00011266336187471834 57266:57266 +0.00011266336187471834 58630:58630 +0.00011266336187471834 35024:35024 +0.00011266336187471834 57208:57208 +0.00011266336187471834 34616:34616 +0.00011266336187471834 60368:60368 +0.00011266336187471834 59314:59314 +0.00011266336187471834 60259:60259 +0.00011266336187471834 60901:60901 +0.00011266336187471834 60055:60055 +0.00011266336187471834 34531:34531 +0.00011266336187471834 59763:59763 +0.00011266336187471834 58836:58836 +0.00011266336187471834 33328:33328 +0.00011266336187471834 60115:60115 +0.00011266336187471834 57489:57489 +0.00011266336187471834 57315:57315 +0.00011266336187471834 55861:55861 +0.00011266336187471834 59214:59214 +0.00011266336187471834 56212:56212 +0.00011266336187471834 35001:35001 +0.00011266336187471834 59521:59521 +0.00011266336187471834 57605:57605 +0.00011266336187471834 57349:57349 +0.00011266336187471834 60515:60515 +0.00011266336187471834 34110:34110 +0.00011266336187471834 60438:60438 +0.00011266336187471834 34217:34217 +0.00011266336187471834 60116:60116 +0.00011266336187471834 56710:56710 +0.00011266336187471834 56933:56933 +0.00011266336187471834 55691:55691 +0.00011266336187471834 58654:58654 +0.00011266336187471834 58445:58445 +0.00011266336187471834 56501:56501 +0.00011266336187471834 35312:35312 +0.00011266336187471834 58053:58053 +0.00011266336187471834 33509:33509 +0.00011266336187471834 34924:34924 +0.00011266336187471834 32924:32924 +0.00011266336187471834 60819:60819 +0.00011266336187471834 34383:34383 +0.00011266336187471834 35235:35235 +0.00011266336187471834 34015:34015 +0.00011266336187471834 35365:35365 +0.00011266336187471834 60685:60685 +0.00011266336187471834 59632:59632 +0.00011266336187471834 56193:56193 +0.00011266336187471834 59736:59736 +0.00011266336187471834 57688:57688 +0.00011266336187471834 34720:34720 +0.00011266336187471834 34136:34136 +0.00011266336187471834 60481:60481 +0.00011266336187471834 60268:60268 +0.00011266336187471834 57458:57458 +0.00011266336187471834 57757:57757 +0.00011266336187471834 59442:59442 +0.00011266336187471834 58443:58443 +0.00011266336187471834 34139:34139 +0.00011266336187471834 59794:59794 +0.00011266336187471834 56876:56876 +0.00011266336187471834 56747:56747 +0.00011266336187471834 60151:60151 +0.00011266336187471834 58125:58125 +0.00011266336187471834 34536:34536 +0.00011266336187471834 58772:58772 +0.00011266336187471834 56304:56304 +0.00011266336187471834 32942:32942 +0.00011266336187471834 58461:58461 +0.00011266336187471834 57986:57986 +0.00011266336187471834 60076:60076 +0.00011266336187471834 60788:60788 +0.00011266336187471834 56921:56921 +0.00011266336187471834 35226:35226 +0.00011266336187471834 57401:57401 +0.00011266336187471834 56606:56606 +0.00011266336187471834 35407:35407 +0.00011266336187471834 57267:57267 +0.00011266336187471834 58474:58474 +0.00011266336187471834 58422:58422 +0.00011266336187471834 56742:56742 +0.00011266336187471834 56639:56639 +0.00011266336187471834 56162:56162 +0.00011266336187471834 59039:59039 +0.00011266336187471834 57227:57227 +0.00011266336187471834 33587:33587 +0.00011266336187471834 32808:32808 +0.00011266336187471834 59517:59517 +0.00011266336187471834 59964:59964 +0.00011266336187471834 56661:56661 +0.00011266336187471834 56122:56122 +0.00011266336187471834 59135:59135 +0.00011266336187471834 33438:33438 +0.00011266336187471834 58175:58175 +0.00011266336187471834 59093:59093 +0.00011266336187471834 55750:55750 +0.00011266336187471834 60251:60251 +0.00011266336187471834 34585:34585 +0.00011266336187471834 59978:59978 +0.00011266336187471834 56831:56831 +0.00011266336187471834 60636:60636 +0.00011266336187471834 34502:34502 +0.00011266336187471834 34381:34381 +0.00011266336187471834 59261:59261 +0.00011266336187471834 57221:57221 +0.00011266336187471834 60138:60138 +0.00011266336187471834 32909:32909 +0.00011266336187471834 60221:60221 +0.00011266336187471834 56966:56966 +0.00011266336187471834 56495:56495 +0.00011266336187471834 60609:60609 +0.00011266336187471834 58638:58638 +0.00011266336187471834 55661:55661 +0.00011266336187471834 33911:33911 +0.00011266336187471834 60276:60276 +0.00011266336187471834 59904:59904 +0.00011266336187471834 56894:56894 +0.00011266336187471834 58465:58465 +0.00011266336187471834 55709:55709 +0.00011266336187471834 57224:57224 +0.00011266336187471834 60265:60265 +0.00011266336187471834 57392:57392 +0.00011266336187471834 35375:35375 +0.00011266336187471834 58265:58265 +0.00011266336187471834 57591:57591 +0.00011266336187471834 33097:33097 +0.00011266336187471834 60064:60064 +0.00011266336187471834 57777:57777 +0.00011266336187471834 57098:57098 +0.00011266336187471834 32923:32923 +0.00011266336187471834 58514:58514 +0.00011266336187471834 33582:33582 +0.00011266336187471834 56316:56316 +0.00011266336187471834 56314:56314 +0.00011266336187471834 33206:33206 +0.00011266336187471834 58786:58786 +0.00011266336187471834 35090:35090 +0.00011266336187471834 35015:35015 +0.00011266336187471834 59542:59542 +0.00011266336187471834 58031:58031 +0.00011266336187471834 34453:34453 +0.00011266336187471834 32975:32975 +0.00011266336187471834 57973:57973 +0.00011266336187471834 60965:60965 +0.00011266336187471834 60365:60365 +0.00011266336187471834 58485:58485 +0.00011266336187471834 57912:57912 +0.00011266336187471834 34306:34306 +0.00011266336187471834 33414:33414 +0.00011266336187471834 56783:56783 +0.00011266336187471834 33253:33253 +0.00011266336187471834 60143:60143 +0.00011266336187471834 35411:35411 +0.00011266336187471834 33266:33266 +0.00011266336187471834 60558:60558 +0.00011266336187471834 56971:56971 +0.00011266336187471834 34954:34954 +0.00011266336187471834 33310:33310 +0.00011266336187471834 35500:35500 +0.00011266336187471834 33302:33302 +0.00011266336187471834 57274:57274 +0.00011266336187471834 35239:35239 +0.00011266336187471834 60478:60478 +0.00011266336187471834 60025:60025 +0.00011266336187471834 33853:33853 +0.00011266336187471834 33607:33607 +0.00011266336187471834 58182:58182 +0.00011266336187471834 55647:55647 +0.00011266336187471834 34714:34714 +0.00011266336187471834 57988:57988 +0.00011266336187471834 56749:56749 +0.00011266336187471834 33297:33297 +0.00011266336187471834 58612:58612 +0.00011266336187471834 58172:58172 +0.00011266336187471834 55784:55784 +0.00011266336187471834 56582:56582 +0.00011266336187471834 34668:34668 +0.00011266336187471834 60215:60215 +0.00011266336187471834 57660:57660 +0.00011266336187471834 35249:35249 +0.00011266336187471834 35216:35216 +0.00011266336187471834 34214:34214 +0.00011266336187471834 57597:57597 +0.00011266336187471834 59086:59086 +0.00011266336187471834 56560:56560 +0.00011266336187471834 60023:60023 +0.00011266336187471834 34725:34725 +0.00011266336187471834 59260:59260 +0.00011266336187471834 33936:33936 +0.00011266336187471834 60625:60625 +0.00011266336187471834 56578:56578 +0.00011266336187471834 34112:34112 +0.00011266336187471834 34543:34543 +0.00011266336187471834 57576:57576 +0.00011266336187471834 56063:56063 +0.00011266336187471834 33229:33229 +0.00011266336187471834 58096:58096 +0.00011266336187471834 57823:57823 +0.00011266336187471834 56603:56603 +0.00011266336187471834 33219:33219 +0.00011266336187471834 60046:60046 +0.00011266336187471834 57786:57786 +0.00011266336187471834 58784:58784 +0.00011266336187471834 58387:58387 +0.00011266336187471834 59345:59345 +0.00011266336187471834 56753:56753 +0.00011266336187471834 59308:59308 +0.00011266336187471834 58702:58702 +0.00011266336187471834 57602:57602 +0.00011266336187471834 57886:57886 +0.00011266336187471834 33139:33139 +0.00011266336187471834 55756:55756 +0.00011266336187471834 60104:60104 +0.00011266336187471834 35153:35153 +0.00011266336187471834 60712:60712 +0.00011266336187471834 57109:57109 +0.00011266336187471834 60594:60594 +0.00011266336187471834 59155:59155 +0.00011266336187471834 55761:55761 +0.00011266336187471834 34442:34442 +0.00011266336187471834 60951:60951 +0.00011266336187471834 57527:57527 +0.00011266336187471834 60996:60996 +0.00011266336187471834 55660:55660 +0.00011266336187471834 34468:34468 +0.00011266336187471834 34101:34101 +0.00011266336187471834 35243:35243 +0.00011266336187471834 33444:33444 +0.00011266336187471834 58516:58516 +0.00011266336187471834 33131:33131 +0.00011266336187471834 34657:34657 +0.00011266336187471834 55995:55995 +0.00011266336187471834 56989:56989 +0.00011266336187471834 56672:56672 +0.00011266336187471834 55651:55651 +0.00011266336187471834 33401:33401 +0.00011266336187471834 33800:33800 +0.00011266336187471834 58248:58248 +0.00011266336187471834 56737:56737 +0.00011266336187471834 59339:59339 +0.00011266336187471834 57908:57908 +0.00011266336187471834 34680:34680 +0.00011266336187471834 60030:60030 +0.00011266336187471834 33377:33377 +0.00011266336187471834 32939:32939 +0.00011266336187471834 58789:58789 +0.00011266336187471834 56351:56351 +0.00011266336187471834 33293:33293 +0.00011266336187471834 35473:35473 +0.00011266336187471834 60546:60546 +0.00011266336187471834 58449:58449 +0.00011266336187471834 34291:34291 +0.00011266336187471834 58766:58766 +0.00011266336187471834 58477:58477 +0.00011266336187471834 60929:60929 +0.00011266336187471834 57111:57111 +0.00011266336187471834 34237:34237 +0.00011266336187471834 33726:33726 +0.00011266336187471834 35258:35258 +0.00011266336187471834 34544:34544 +0.00011266336187471834 33382:33382 +0.00011266336187471834 57372:57372 +0.00011266336187471834 56844:56844 +0.00011266336187471834 57054:57054 +0.00011266336187471834 56768:56768 +0.00011266336187471834 56369:56369 +0.00011266336187471834 55746:55746 +0.00011266336187471834 60591:60591 +0.00011266336187471834 59726:59726 +0.00011266336187471834 34349:34349 +0.00011266336187471834 55889:55889 +0.00011266336187471834 60539:60539 +0.00011266336187471834 55700:55700 +0.00011266336187471834 35133:35133 +0.00011266336187471834 35035:35035 +0.00011266336187471834 58662:58662 +0.00011266336187471834 57342:57342 +0.00011266336187471834 33431:33431 +0.00011266336187471834 32810:32810 +0.00011266336187471834 58253:58253 +0.00011266336187471834 60155:60155 +0.00011266336187471834 59748:59748 +0.00011266336187471834 57110:57110 +0.00011266336187471834 56267:56267 +0.00011266336187471834 58401:58401 +0.00011266336187471834 60004:60004 +0.00011266336187471834 34859:34859 +0.00011266336187471834 59801:59801 +0.00011266336187471834 35337:35337 +0.00011266336187471834 58497:58497 +0.00011266336187471834 57512:57512 +0.00011266336187471834 57846:57846 +0.00011266336187471834 58161:58161 +0.00011266336187471834 56449:56449 +0.00011266336187471834 33752:33752 +0.00011266336187471834 56309:56309 +0.00011266336187471834 35282:35282 +0.00011266336187471834 58037:58037 +0.00011266336187471834 34526:34526 +0.00011266336187471834 33256:33256 +0.00011266336187471834 57120:57120 +0.00011266336187471834 58524:58524 +0.00011266336187471834 58306:58306 +0.00011266336187471834 60087:60087 +0.00011266336187471834 58504:58504 +0.00011266336187471834 60172:60172 +0.00011266336187471834 33979:33979 +0.00011266336187471834 57608:57608 +0.00011266336187471834 57799:57799 +0.00011266336187471834 57177:57177 +0.00011266336187471834 56342:56342 +0.00011266336187471834 34213:34213 +0.00011266336187471834 59237:59237 +0.00011266336187471834 60644:60644 +0.00011266336187471834 56642:56642 +0.00011266336187471834 59707:59707 +0.00011266336187471834 56647:56647 +0.00011266336187471834 33155:33155 +0.00011266336187471834 34311:34311 +0.00011266336187471834 34511:34511 +0.00011266336187471834 33069:33069 +0.00011266336187471834 59420:59420 +0.00011266336187471834 55932:55932 +0.00011266336187471834 35248:35248 +0.00011266336187471834 34159:34159 +0.00011266336187471834 60565:60565 +0.00011266336187471834 56999:56999 +0.00011266336187471834 57233:57233 +0.00011266336187471834 33394:33394 +0.00011266336187471834 33073:33073 +0.00011266336187471834 57148:57148 +0.00011266336187471834 34848:34848 +0.00011266336187471834 56725:56725 +0.00011266336187471834 59673:59673 +0.00011266336187471834 55849:55849 +0.00011266336187471834 58975:58975 +0.00011266336187471834 34095:34095 +0.00011266336187471834 58594:58594 +0.00011266336187471834 56359:56359 +0.00011266336187471834 57762:57762 +0.00011266336187471834 58697:58697 +0.00011266336187471834 58560:58560 +0.00011266336187471834 35071:35071 +0.00011266336187471834 55676:55676 +0.00011266336187471834 58026:58026 +0.00011266336187471834 57497:57497 +0.00011266336187471834 33025:33025 +0.00011266336187471834 60828:60828 +0.00011266336187471834 57653:57653 +0.00011266336187471834 34127:34127 +0.00011266336187471834 60511:60511 +0.00011266336187471834 57960:57960 +0.00011266336187471834 58809:58809 +0.00011266336187471834 35505:35505 +0.00011266336187471834 33565:33565 +0.00011266336187471834 59419:59419 +0.00011266336187471834 59558:59558 +0.00011266336187471834 56537:56537 +0.00011266336187471834 58586:58586 +0.00011266336187471834 55726:55726 +0.00011266336187471834 58938:58938 +0.00011266336187471834 56201:56201 +0.00011266336187471834 55946:55946 +0.00011266336187471834 59482:59482 +0.00011266336187471834 34016:34016 +0.00011266336187471834 58080:58080 +0.00011266336187471834 33554:33554 +0.00011266336187471834 59840:59840 +0.00011266336187471834 58742:58742 +0.00011266336187471834 56899:56899 +0.00011266336187471834 56113:56113 +0.00011266336187471834 35058:35058 +0.00011266336187471834 35033:35033 +0.00011266336187471834 34014:34014 +0.00011266336187471834 33688:33688 +0.00011266336187471834 60090:60090 +0.00011266336187471834 59106:59106 +0.00011266336187471834 60052:60052 +0.00011266336187471834 34208:34208 +0.00011266336187471834 33322:33322 +0.00011266336187471834 32989:32989 +0.00011266336187471834 60877:60877 +0.00011266336187471834 60672:60672 +0.00011266336187471834 56797:56797 +0.00011266336187471834 56190:56190 +0.00011266336187471834 59782:59782 +0.00011266336187471834 33810:33810 +0.00011266336187471834 32877:32877 +0.00011266336187471834 59771:59771 +0.00011266336187471834 59500:59500 +0.00011266336187471834 55720:55720 +0.00011266336187471834 34729:34729 +0.00011266336187471834 58722:58722 +0.00011266336187471834 34877:34877 +0.00011266336187471834 57142:57142 +0.00011266336187471834 57236:57236 +0.00011266336187471834 57482:57482 +0.00011266336187471834 59742:59742 +0.00011266336187471834 59311:59311 +0.00011266336187471834 58142:58142 +0.00011266336187471834 55677:55677 +0.00011266336187471834 33013:33013 +0.00011266336187471834 59216:59216 +0.00011266336187471834 60412:60412 +0.00011266336187471834 60492:60492 +0.00011266336187471834 57167:57167 +0.00011266336187471834 33213:33213 +0.00011266336187471834 57744:57744 +0.00011266336187471834 34494:34494 +0.00011266336187471834 59729:59729 +0.00011266336187471834 33268:33268 +0.00011266336187471834 60315:60315 +0.00011266336187471834 60741:60741 +0.00011266336187471834 60270:60270 +0.00011266336187471834 58298:58298 +0.00011266336187471834 33844:33844 +0.00011266336187471834 60233:60233 +0.00011266336187471834 59019:59019 +0.00011266336187471834 33762:33762 +0.00011266336187471834 57658:57658 +0.00011266336187471834 58308:58308 +0.00011266336187471834 58127:58127 +0.00011266336187471834 56294:56294 +0.00011266336187471834 34558:34558 +0.00011266336187471834 57272:57272 +0.00011266336187471834 55644:55644 +0.00011266336187471834 34658:34658 +0.00011266336187471834 59538:59538 +0.00011266336187471834 59228:59228 +0.00011266336187471834 34485:34485 +0.00011266336187471834 55799:55799 +0.00011266336187471834 56584:56584 +0.00011266336187471834 55978:55978 +0.00011266336187471834 32861:32861 +0.00011266336187471834 35222:35222 +0.00011266336187471834 56013:56013 +0.00011266336187471834 55669:55669 +0.00011266336187471834 34685:34685 +0.00011266336187471834 34041:34041 +0.00011266336187471834 34389:34389 +0.00011266336187471834 58200:58200 +0.00011266336187471834 35538:35538 +0.00011266336187471834 56005:56005 +0.00011266336187471834 33921:33921 +0.00011266336187471834 58147:58147 +0.00011266336187471834 34846:34846 +0.00011266336187471834 60516:60516 +0.00011266336187471834 60224:60224 +0.00011266336187471834 58527:58527 +0.00011266336187471834 35208:35208 +0.00011266336187471834 33981:33981 +0.00011266336187471834 59350:59350 +0.00011266336187471834 56132:56132 +0.00011266336187471834 33536:33536 +0.00011266336187471834 34733:34733 +0.00011266336187471834 60127:60127 +0.00011266336187471834 33508:33508 +0.00011266336187471834 57258:57258 +0.00011266336187471834 34344:34344 +0.00011266336187471834 57323:57323 +0.00011266336187471834 34850:34850 +0.00011266336187471834 59777:59777 +0.00011266336187471834 59750:59750 +0.00011266336187471834 32802:32802 +0.00011266336187471834 57212:57212 +0.00011266336187471834 56288:56288 +0.00011266336187471834 57016:57016 +0.00011266336187471834 35123:35123 +0.00011266336187471834 33467:33467 +0.00011266336187471834 35152:35152 +0.00011266336187471834 34272:34272 +0.00011266336187471834 33102:33102 +0.00011266336187471834 60550:60550 +0.00011266336187471834 57462:57462 +0.00011266336187471834 58646:58646 +0.00011266336187471834 35195:35195 +0.00011266336187471834 57725:57725 +0.00011266336187471834 35048:35048 +0.00011266336187471834 56889:56889 +0.00011266336187471834 33675:33675 +0.00011266336187471834 57567:57567 +0.00011266336187471834 35163:35163 +0.00011266336187471834 34297:34297 +0.00011266336187471834 34822:34822 +0.00011266336187471834 56726:56726 +0.00011266336187471834 57191:57191 +0.00011266336187471834 34058:34058 +0.00011266336187471834 57059:57059 +0.00011266336187471834 34566:34566 +0.00011266336187471834 55896:55896 +0.00011266336187471834 57189:57189 +0.00011266336187471834 34765:34765 +0.00011266336187471834 34612:34612 +0.00011266336187471834 56629:56629 +0.00011266336187471834 34843:34843 +0.00011266336187471834 58348:58348 +0.00011266336187471834 58777:58777 +0.00011266336187471834 33780:33780 +0.00011266336187471834 59098:59098 +0.00011266336187471834 55612:55612 +0.00011266336187471834 58562:58562 +0.00011266336187471834 35363:35363 +0.00011266336187471834 56568:56568 +0.00011266336187471834 33396:33396 +0.00011266336187471834 33363:33363 +0.00011266336187471834 55918:55918 +0.00011266336187471834 57320:57320 +0.00011266336187471834 35440:35440 +0.00011266336187471834 59481:59481 +0.00011266336187471834 59326:59326 +0.00011266336187471834 35030:35030 +0.00011266336187471834 60296:60296 +0.00011266336187471834 59116:59116 +0.00011266336187471834 59277:59277 +0.00011266336187471834 56939:56939 +0.00011266336187471834 33260:33260 +0.00011266336187471834 59932:59932 +0.00011266336187471834 59593:59593 +0.00011266336187471834 57755:57755 +0.00011266336187471834 60400:60400 +0.00011266336187471834 32978:32978 +0.00011266336187471834 34791:34791 +0.00011266336187471834 56091:56091 +0.00011266336187471834 59497:59497 +0.00011266336187471834 35240:35240 +0.00011266336187471834 34487:34487 +0.00011266336187471834 34415:34415 +0.00011266336187471834 60402:60402 +0.00011266336187471834 56301:56301 +0.00011266336187471834 58489:58489 +0.00011266336187471834 59900:59900 +0.00011266336187471834 56644:56644 +0.00011266336187471834 58696:58696 +0.00011266336187471834 34777:34777 +0.00011266336187471834 56074:56074 +0.00011266336187471834 33259:33259 +0.00011266336187471834 33877:33877 +0.00011266336187471834 58921:58921 +0.00011266336187471834 56956:56956 +0.00011266336187471834 56256:56256 +0.00011266336187471834 55908:55908 +0.00011266336187471834 34374:34374 +0.00011266336187471834 58829:58829 +0.00011266336187471834 58754:58754 +0.00011266336187471834 35394:35394 +0.00011266336187471834 34956:34956 +0.00011266336187471834 33961:33961 +0.00011266336187471834 55790:55790 +0.00011266336187471834 58163:58163 +0.00011266336187471834 35088:35088 +0.00011266336187471834 58675:58675 +0.00011266336187471834 60822:60822 +0.00011266336187471834 57231:57231 +0.00011266336187471834 55608:55608 +0.00011266336187471834 59205:59205 +0.00011266336187471834 59489:59489 +0.00011266336187471834 57215:57215 +0.00011266336187471834 59626:59626 +0.00011266336187471834 35543:35543 +0.00011266336187471834 59247:59247 +0.00011266336187471834 33740:33740 +0.00011266336187471834 60512:60512 +0.00011266336187471834 60275:60275 +0.00011266336187471834 56977:56977 +0.00011266336187471834 56556:56556 +0.00011266336187471834 34247:34247 +0.00011266336187471834 60791:60791 +0.00011266336187471834 33735:33735 +0.00011266336187471834 60304:60304 +0.00011266336187471834 56411:56411 +0.00011266336187471834 33743:33743 +0.00011266336187471834 33249:33249 +0.00011266336187471834 59641:59641 +0.00011266336187471834 60444:60444 +0.00011266336187471834 34786:34786 +0.00011266336187471834 60463:60463 +0.00011266336187471834 56041:56041 +0.00011266336187471834 57610:57610 +0.00011266336187471834 56059:56059 +0.00011266336187471834 59870:59870 +0.00011266336187471834 34867:34867 +0.00011266336187471834 58724:58724 +0.00011266336187471834 58056:58056 +0.00011266336187471834 55916:55916 +0.00011266336187471834 58603:58603 +0.00011266336187471834 56863:56863 +0.00011266336187471834 33233:33233 +0.00011266336187471834 56525:56525 +0.00011266336187471834 60858:60858 +0.00011266336187471834 58880:58880 +0.00011266336187471834 57356:57356 +0.00011266336187471834 33059:33059 +0.00011266336187471834 60980:60980 +0.00011266336187471834 57262:57262 +0.00011266336187471834 34642:34642 +0.00011266336187471834 33098:33098 +0.00011266336187471834 59753:59753 +0.00011266336187471834 35442:35442 +0.00011266336187471834 55801:55801 +0.00011266336187471834 59547:59547 +0.00011266336187471834 35391:35391 +0.00011266336187471834 34898:34898 +0.00011266336187471834 57509:57509 +0.00011266336187471834 35254:35254 +0.00011266336187471834 34240:34240 +0.00011266336187471834 55917:55917 +0.00011266336187471834 58296:58296 +0.00011266336187471834 57765:57765 +0.00011266336187471834 59061:59061 +0.00011266336187471834 57378:57378 +0.00011266336187471834 32993:32993 +0.00011266336187471834 33005:33005 +0.00011266336187471834 33569:33569 +0.00011266336187471834 34067:34067 +0.00011266336187471834 58725:58725 +0.00011266336187471834 60254:60254 +0.00011266336187471834 56202:56202 +0.00011266336187471834 33907:33907 +0.00011266336187471834 34904:34904 +0.00011266336187471834 33434:33434 +0.00011266336187471834 58530:58530 +0.00011266336187471834 34866:34866 +0.00011266336187471834 34223:34223 +0.00011266336187471834 58573:58573 +0.00011266336187471834 59974:59974 +0.00011266336187471834 58262:58262 +0.00011266336187471834 57652:57652 +0.00011266336187471834 59015:59015 +0.00011266336187471834 55891:55891 +0.00011266336187471834 55786:55786 +0.00011266336187471834 34341:34341 +0.00011266336187471834 58989:58989 +0.00011266336187471834 57663:57663 +0.00011266336187471834 56400:56400 +0.00011266336187471834 32815:32815 +0.00011266336187471834 35110:35110 +0.00011266336187471834 56137:56137 +0.00011266336187471834 33560:33560 +0.00011266336187471834 58432:58432 +0.00011266336187471834 34394:34394 +0.00011266336187471834 33976:33976 +0.00011266336187471834 56183:56183 +0.00011266336187471834 56032:56032 +0.00011266336187471834 57273:57273 +0.00011266336187471834 34781:34781 +0.00011266336187471834 60567:60567 +0.00011266336187471834 57621:57621 +0.00011266336187471834 55770:55770 +0.00011266336187471834 33278:33278 +0.00011266336187471834 60973:60973 +0.00011266336187471834 60993:60993 +0.00011266336187471834 33026:33026 +0.00011266336187471834 58949:58949 +0.00011266336187471834 33177:33177 +0.00011266336187471834 57968:57968 +0.00011266336187471834 57252:57252 +0.00011266336187471834 35405:35405 +0.00011266336187471834 33884:33884 +0.00011266336187471834 59384:59384 +0.00011266336187471834 34256:34256 +0.00011266336187471834 59586:59586 +0.00011266336187471834 59966:59966 +0.00011266336187471834 33519:33519 +0.00011266336187471834 57288:57288 +0.00011266336187471834 34687:34687 +0.00011266336187471834 57136:57136 +0.00011266336187471834 57064:57064 +0.00011266336187471834 33443:33443 +0.00011266336187471834 56892:56892 +0.00011266336187471834 56331:56331 +0.00011266336187471834 57073:57073 +0.00011266336187471834 60498:60498 +0.00011266336187471834 33551:33551 +0.00011266336187471834 60117:60117 +0.00011266336187471834 35032:35032 +0.00011266336187471834 57817:57817 +0.00011266336187471834 55732:55732 +0.00011266336187471834 33733:33733 +0.00011266336187471834 57754:57754 +0.00011266336187471834 56524:56524 +0.00011266336187471834 57214:57214 +0.00011266336187471834 59080:59080 +0.00011266336187471834 56454:56454 +0.00011266336187471834 59579:59579 +0.00011266336187471834 59935:59935 +0.00011266336187471834 34142:34142 +0.00011266336187471834 59862:59862 +0.00011266336187471834 56226:56226 +0.00011266336187471834 35146:35146 +0.00011266336187471834 33424:33424 +0.00011266336187471834 59488:59488 +0.00011266336187471834 58794:58794 +0.00011266336187471834 60034:60034 +0.00011266336187471834 33512:33512 +0.00011266336187471834 35236:35236 +0.00011266336187471834 33300:33300 +0.00011266336187471834 55934:55934 +0.00011266336187471834 34830:34830 +0.00011266336187471834 59965:59965 +0.00011266336187471834 57366:57366 +0.00011266336187471834 56849:56849 +0.00011266336187471834 33761:33761 +0.00011266336187471834 32786:32786 +0.00011266336187471834 60762:60762 +0.00011266336187471834 56386:56386 +0.00011266336187471834 35437:35437 +0.00011266336187471834 34100:34100 +0.00011266336187471834 32866:32866 +0.00011266336187471834 59126:59126 +0.00011266336187471834 56509:56509 +0.00011266336187471834 32806:32806 +0.00011266336187471834 56829:56829 +0.00011266336187471834 60345:60345 +0.00011266336187471834 59303:59303 +0.00011266336187471834 60733:60733 +0.00011266336187471834 59038:59038 +0.00011266336187471834 59860:59860 +0.00011266336187471834 60784:60784 +0.00011266336187471834 58616:58616 +0.00011266336187471834 55782:55782 +0.00011266336187471834 60094:60094 +0.00011266336187471834 58906:58906 +0.00011266336187471834 60880:60880 +0.00011266336187471834 56965:56965 +0.00011266336187471834 60663:60663 +0.00011266336187471834 58438:58438 +0.00011266336187471834 56465:56465 +0.00011266336187471834 34672:34672 +0.00011266336187471834 60981:60981 +0.00011266336187471834 57954:57954 +0.00011266336187471834 60347:60347 +0.00011266336187471834 35113:35113 +0.00011266336187471834 55773:55773 +0.00011266336187471834 35414:35414 +0.00011266336187471834 33940:33940 +0.00011266336187471834 59208:59208 +0.00011266336187471834 56125:56125 +0.00011266336187471834 32788:32788 +0.00011266336187471834 55827:55827 +0.00011266336187471834 34679:34679 +0.00011266336187471834 58099:58099 +0.00011266336187471834 32777:32777 +0.00011266336187471834 32995:32995 +0.00011266336187471834 35012:35012 +0.00011266336187471834 57618:57618 +0.00011266336187471834 35089:35089 +0.00011266336187471834 59917:59917 +0.00011266336187471834 56051:56051 +0.00011266336187471834 60392:60392 +0.00011266336187471834 58626:58626 +0.00011266336187471834 58259:58259 +0.00011266336187471834 56065:56065 +0.00011266336187471834 58736:58736 +0.00011266336187471834 56516:56516 +0.00011266336187471834 56253:56253 +0.00011266336187471834 34797:34797 +0.00011266336187471834 34061:34061 +0.00011266336187471834 58084:58084 +0.00011266336187471834 34439:34439 +0.00011266336187471834 34335:34335 +0.00011266336187471834 33652:33652 +0.00011266336187471834 34107:34107 +0.00011266336187471834 60327:60327 +0.00011266336187471834 60863:60863 +0.00011266336187471834 56798:56798 +0.00011266336187471834 33734:33734 +0.00011266336187471834 58667:58667 +0.00011266336187471834 60523:60523 +0.00011266336187471834 58635:58635 +0.00011266336187471834 56757:56757 +0.00011266336187471834 59756:59756 +0.00011266336187471834 35065:35065 +0.00011266336187471834 58409:58409 +0.00011266336187471834 55787:55787 +0.00011266336187471834 60943:60943 +0.00011266336187471834 60660:60660 +0.00011266336187471834 57911:57911 +0.00011266336187471834 57246:57246 +0.00011266336187471834 34186:34186 +0.00011266336187471834 59849:59849 +0.00011266336187471834 34117:34117 +0.00011266336187471834 57118:57118 +0.00011266336187471834 33085:33085 +0.00011266336187471834 60419:60419 +0.00011266336187471834 58813:58813 +0.00011266336187471834 58797:58797 +0.00011266336187471834 32979:32979 +0.00011266336187471834 56713:56713 +0.00011266336187471834 57499:57499 +0.00011266336187471834 57561:57561 +0.00011266336187471834 56551:56551 +0.00011266336187471834 56176:56176 +0.00011266336187471834 33725:33725 +0.00011266336187471834 33234:33234 +0.00011266336187471834 34268:34268 +0.00011266336187471834 56251:56251 +0.00011266336187471834 60156:60156 +0.00011266336187471834 33425:33425 +0.00011266336187471834 34862:34862 +0.00011266336187471834 34622:34622 +0.00011266336187471834 34021:34021 +0.00011266336187471834 33081:33081 +0.00011266336187471834 58243:58243 +0.00011266336187471834 32969:32969 +0.00011266336187471834 57326:57326 +0.00011266336187471834 57565:57565 +0.00011266336187471834 55945:55945 +0.00011266336187471834 56402:56402 +0.00011266336187471834 59044:59044 +0.00011266336187471834 56116:56116 +0.00011266336187471834 58980:58980 +0.00011266336187471834 57213:57213 +0.00011266336187471834 59994:59994 +0.00011266336187471834 34491:34491 +0.00011266336187471834 57121:57121 +0.00011266336187471834 57689:57689 +0.00011266336187471834 35038:35038 +0.00011266336187471834 58605:58605 +0.00011266336187471834 56613:56613 +0.00011266336187471834 34379:34379 +0.00011266336187471834 33196:33196 +0.00011266336187471834 59552:59552 +0.00011266336187471834 58350:58350 +0.00011266336187471834 34212:34212 +0.00011266336187471834 33486:33486 +0.00011266336187471834 57519:57519 +0.00011266336187471834 57364:57364 +0.00011266336187471834 56355:56355 +0.00011266336187471834 34713:34713 +0.00011266336187471834 60875:60875 +0.00011266336187471834 34818:34818 +0.00011266336187471834 59977:59977 +0.00011266336187471834 59100:59100 +0.00011266336187471834 60915:60915 +0.00011266336187471834 35350:35350 +0.00011266336187471834 57158:57158 +0.00011266336187471834 59653:59653 +0.00011266336187471834 57125:57125 +0.00011266336187471834 56087:56087 +0.00011266336187471834 33905:33905 +0.00011266336187471834 32928:32928 +0.00011266336187471834 59090:59090 +0.00011266336187471834 60237:60237 +0.00011266336187471834 58402:58402 +0.00011266336187471834 34121:34121 +0.00011266336187471834 34175:34175 +0.00011266336187471834 56628:56628 +0.00011266336187471834 55742:55742 +0.00011266336187471834 60614:60614 +0.00011266336187471834 57457:57457 +0.00011266336187471834 60284:60284 +0.00011266336187471834 59745:59745 +0.00011266336187471834 56374:56374 +0.00011266336187471834 34138:34138 +0.00011266336187471834 60904:60904 +0.00011266336187471834 58359:58359 +0.00011266336187471834 59266:59266 +0.00011266336187471834 56532:56532 +0.00011266336187471834 58913:58913 +0.00011266336187471834 34984:34984 +0.00011266336187471834 59972:59972 +0.00011266336187471834 59179:59179 +0.00011266336187471834 33309:33309 +0.00011266336187471834 57083:57083 +0.00011266336187471834 55607:55607 +0.00011266336187471834 34589:34589 +0.00011266336187471834 60738:60738 +0.00011266336187471834 57583:57583 +0.00011266336187471834 56232:56232 +0.00011266336187471834 33469:33469 +0.00011266336187471834 59351:59351 +0.00011266336187471834 57433:57433 +0.00011266336187471834 60955:60955 +0.00011266336187471834 56612:56612 +0.00011266336187471834 60352:60352 +0.00011266336187471834 56070:56070 +0.00011266336187471834 33029:33029 +0.00011266336187471834 32871:32871 +0.00011266336187471834 34661:34661 +0.00011266336187471834 59310:59310 +0.00011266336187471834 60129:60129 +0.00011266336187471834 35156:35156 +0.00011266336187471834 33728:33728 +0.00011266336187471834 34790:34790 +0.00011266336187471834 33422:33422 +0.00011266336187471834 34204:34204 +0.00011266336187471834 58738:58738 +0.00011266336187471834 57805:57805 +0.00011266336187471834 59058:59058 +0.00011266336187471834 35395:35395 +0.00011266336187471834 33926:33926 +0.00011266336187471834 33801:33801 +0.00011266336187471834 59282:59282 +0.00011266336187471834 57047:57047 +0.00011266336187471834 33993:33993 +0.00011266336187471834 57853:57853 +0.00011266336187471834 33767:33767 +0.00011266336187471834 60667:60667 +0.00011266336187471834 60435:60435 +0.00011266336187471834 59102:59102 +0.00011266336187471834 59174:59174 +0.00011266336187471834 57683:57683 +0.00011266336187471834 60289:60289 +0.00011266336187471834 34362:34362 +0.00011266336187471834 56089:56089 +0.00011266336187471834 60851:60851 +0.00011266336187471834 33805:33805 +0.00011266336187471834 34874:34874 +0.00011266336187471834 60855:60855 +0.00011266336187471834 59698:59698 +0.00011266336187471834 34185:34185 +0.00011266336187471834 33055:33055 +0.00011266336187471834 33313:33313 +0.00011266336187471834 33662:33662 +0.00011266336187471834 60299:60299 +0.00011266336187471834 34210:34210 +0.00011266336187471834 35299:35299 +0.00011266336187471834 59373:59373 +0.00011266336187471834 35214:35214 +0.00011266336187471834 33145:33145 +0.00011266336187471834 58415:58415 +0.00011266336187471834 57793:57793 +0.00011266336187471834 34888:34888 +0.00011266336187471834 33022:33022 +0.00011266336187471834 56539:56539 +0.00011266336187471834 59607:59607 +0.00011266336187471834 34327:34327 +0.00011266336187471834 60467:60467 +0.00011266336187471834 58309:58309 +0.00011266336187471834 56563:56563 +0.00011266336187471834 57547:57547 +0.00011266336187471834 34949:34949 +0.00011266336187471834 34738:34738 +0.00011266336187471834 58463:58463 +0.00011266336187471834 56000:56000 +0.00011266336187471834 60771:60771 +0.00011266336187471834 58745:58745 +0.00011266336187471834 34382:34382 +0.00011266336187471834 60389:60389 +0.00011266336187471834 56641:56641 +0.00011266336187471834 33480:33480 +0.00011266336187471834 33461:33461 +0.00011266336187471834 60333:60333 +0.00011266336187471834 60048:60048 +0.00011266336187471834 56566:56566 +0.00011266336187471834 59178:59178 +0.00011266336187471834 58867:58867 +0.00011266336187471834 60812:60812 +0.00011266336187471834 59411:59411 +0.00011266336187471834 57859:57859 +0.00011266336187471834 59249:59249 +0.00011266336187471834 57570:57570 +0.00011266336187471834 33567:33567 +0.00011266336187471834 32921:32921 +0.00011266336187471834 34510:34510 +0.00011266336187471834 57617:57617 +0.00011266336187471834 59082:59082 +0.00011266336187471834 57801:57801 +0.00011266336187471834 34917:34917 +0.00011266336187471834 34798:34798 +0.00011266336187471834 34162:34162 +0.00011266336187471834 60997:60997 +0.00011266336187471834 56467:56467 +0.00011266336187471834 57936:57936 +0.00011266336187471834 56384:56384 +0.00011266336187471834 34576:34576 +0.00011266336187471834 33524:33524 +0.00011266336187471834 59022:59022 +0.00011266336187471834 58752:58752 +0.00011266336187471834 59370:59370 +0.00011266336187471834 57340:57340 +0.00011266336187471834 59585:59585 +0.00011266336187471834 59834:59834 +0.00011266336187471834 34152:34152 +0.00011266336187471834 34950:34950 +0.00011266336187471834 55662:55662 +0.00011266336187471834 33238:33238 +0.00011266336187471834 59734:59734 +0.00011266336187471834 57896:57896 +0.00011266336187471834 57955:57955 +0.00011266336187471834 34792:34792 +0.00011266336187471834 57771:57771 +0.00011266336187471834 56815:56815 +0.00011266336187471834 33865:33865 +0.00011266336187471834 33621:33621 +0.00011266336187471834 57044:57044 +0.00011266336187471834 35429:35429 +0.00011266336187471834 57129:57129 +0.00011266336187471834 33129:33129 +0.00011266336187471834 60549:60549 +0.00011266336187471834 57875:57875 +0.00011266336187471834 57872:57872 +0.00011266336187471834 59991:59991 +0.00011266336187471834 33117:33117 +0.00011266336187471834 59165:59165 +0.00011266336187471834 56891:56891 +0.00011266336187471834 58249:58249 +0.00011266336187471834 57228:57228 +0.00011266336187471834 56136:56136 +0.00011266336187471834 60786:60786 +0.00011266336187471834 35232:35232 +0.00011266336187471834 33484:33484 +0.00011266336187471834 60277:60277 +0.00011266336187471834 35083:35083 +0.00011266336187471834 34517:34517 +0.00011266336187471834 60604:60604 +0.00011266336187471834 59931:59931 +0.00011266336187471834 35062:35062 +0.00011266336187471834 60602:60602 +0.00011266336187471834 35041:35041 +0.00011266336187471834 33126:33126 +0.00011266336187471834 33187:33187 +0.00011266336187471834 59281:59281 +0.00011266336187471834 33764:33764 +0.00011266336187471834 59666:59666 +0.00011266336187471834 59152:59152 +0.00011266336187471834 57299:57299 +0.00011266336187471834 35184:35184 +0.00011266336187471834 57630:57630 +0.00011266336187471834 57290:57290 +0.00011266336187471834 57647:57647 +0.00011266336187471834 59694:59694 +0.00011266336187471834 35170:35170 +0.00011266336187471834 34467:34467 +0.00011266336187471834 33954:33954 +0.00011266336187471834 33186:33186 +0.00011266336187471834 60746:60746 +0.00011266336187471834 58009:58009 +0.00011266336187471834 60316:60316 +0.00011266336187471834 57067:57067 +0.00011266336187471834 56486:56486 +0.00011266336187471834 34296:34296 +0.00011266336187471834 33771:33771 +0.00011266336187471834 34638:34638 +0.00011266336187471834 56414:56414 +0.00011266336187471834 59548:59548 +0.00011266336187471834 33947:33947 +0.00011266336187471834 34171:34171 +0.00011266336187471834 56796:56796 +0.00011266336187471834 33564:33564 +0.00011266336187471834 59359:59359 +0.00011266336187471834 56245:56245 +0.00011266336187471834 59843:59843 +0.00011266336187471834 33846:33846 +0.00011266336187471834 55883:55883 +0.00011266336187471834 57992:57992 +0.00011266336187471834 57551:57551 +0.00011266336187471834 56042:56042 +0.00011266336187471834 33079:33079 +0.00011266336187471834 60927:60927 +0.00011266336187471834 56938:56938 +0.00011266336187471834 59188:59188 +0.00011266336187471834 56014:56014 +0.00011266336187471834 34484:34484 +0.00011266336187471834 59029:59029 +0.00011266336187471834 56690:56690 +0.00011266336187471834 58429:58429 +0.00011266336187471834 59430:59430 +0.00011266336187471834 56242:56242 +0.00011266336187471834 33083:33083 +0.00011266336187471834 59768:59768 +0.00011266336187471834 57672:57672 +0.00011266336187471834 34782:34782 +0.00011266336187471834 58204:58204 +0.00011266336187471834 34276:34276 +0.00011266336187471834 35094:35094 +0.00011266336187471834 34363:34363 +0.00011266336187471834 58121:58121 +0.00011266336187471834 35180:35180 +0.00011266336187471834 35131:35131 +0.00011266336187471834 57056:57056 +0.00011266336187471834 56381:56381 +0.00011266336187471834 60777:60777 +0.00011266336187471834 33027:33027 +0.00011266336187471834 33194:33194 +0.00011266336187471834 60374:60374 +0.00011266336187471834 34195:34195 +0.00011266336187471834 58546:58546 +0.00011266336187471834 56632:56632 +0.00011266336187471834 34979:34979 +0.00011266336187471834 57387:57387 +0.00011266336187471834 56241:56241 +0.00011266336187471834 57665:57665 +0.00011266336187471834 33299:33299 +0.00011266336187471834 35445:35445 +0.00011266336187471834 34206:34206 +0.00011266336187471834 59948:59948 +0.00011266336187471834 59103:59103 +0.00011266336187471834 58967:58967 +0.00011266336187471834 34561:34561 +0.00011266336187471834 58729:58729 +0.00011266336187471834 56028:56028 +0.00011266336187471834 58762:58762 +0.00011266336187471834 35501:35501 +0.00011266336187471834 58191:58191 +0.00011266336187471834 55721:55721 +0.00011266336187471834 59305:59305 +0.00011266336187471834 34170:34170 +0.00011266336187471834 55625:55625 +0.00011266336187471834 60464:60464 +0.00011266336187471834 58304:58304 +0.00011266336187471834 55954:55954 +0.00011266336187471834 59352:59352 +0.00011266336187471834 56329:56329 +0.00011266336187471834 60455:60455 +0.00011266336187471834 58570:58570 +0.00011266336187471834 35553:35553 +0.00011266336187471834 35408:35408 +0.00011266336187471834 59762:59762 +0.00011266336187471834 33672:33672 +0.00011266336187471834 58008:58008 +0.00011266336187471834 59876:59876 +0.00011266336187471834 59661:59661 +0.00011266336187471834 59046:59046 +0.00011266336187471834 57464:57464 +0.00011266336187471834 59597:59597 +0.00011266336187471834 55957:55957 +0.00011266336187471834 60330:60330 +0.00011266336187471834 58326:58326 +0.00011266336187471834 56998:56998 +0.00011266336187471834 35145:35145 +0.00011266336187471834 60832:60832 +0.00011266336187471834 58974:58974 +0.00011266336187471834 35398:35398 +0.00011266336187471834 35008:35008 +0.00011266336187471834 58700:58700 +0.00011266336187471834 33899:33899 +0.00011266336187471834 34554:34554 +0.00011266336187471834 60099:60099 +0.00011266336187471834 58112:58112 +0.00011266336187471834 34292:34292 +0.00011266336187471834 57039:57039 +0.00011266336187471834 55847:55847 +0.00011266336187471834 33655:33655 +0.00011266336187471834 58284:58284 +0.00011266336187471834 57697:57697 +0.00011266336187471834 59831:59831 +0.00011266336187471834 59744:59744 +0.00011266336187471834 33511:33511 +0.00011266336187471834 55836:55836 +0.00011266336187471834 60799:60799 +0.00011266336187471834 59758:59758 +0.00011266336187471834 58302:58302 +0.00011266336187471834 34805:34805 +0.00011266336187471834 55788:55788 +0.00011266336187471834 60671:60671 +0.00011266336187471834 59531:59531 +0.00011266336187471834 58501:58501 +0.00011266336187471834 55997:55997 +0.00011266336187471834 60206:60206 +0.00011266336187471834 59182:59182 +0.00011266336187471834 58437:58437 +0.00011266336187471834 57575:57575 +0.00011266336187471834 60414:60414 +0.00011266336187471834 32869:32869 +0.00011266336187471834 35122:35122 +0.00011266336187471834 34596:34596 +0.00011266336187471834 57450:57450 +0.00011266336187471834 33958:33958 +0.00011266336187471834 34069:34069 +0.00011266336187471834 56010:56010 +0.00011266336187471834 56935:56935 +0.00011266336187471834 60802:60802 +0.00011266336187471834 59272:59272 +0.00011266336187471834 56062:56062 +0.00011266336187471834 56020:56020 +0.00011266336187471834 57556:57556 +0.00011266336187471834 59071:59071 +0.00011266336187471834 59246:59246 +0.00011266336187471834 34803:34803 +0.00011266336187471834 58500:58500 +0.00011266336187471834 56341:56341 +0.00011266336187471834 34594:34594 +0.00011266336187471834 60100:60100 +0.00011266336187471834 34708:34708 +0.00011266336187471834 59942:59942 +0.00011266336187471834 57977:57977 +0.00011266336187471834 55671:55671 +0.00011266336187471834 59769:59769 +0.00011266336187471834 58242:58242 +0.00011266336187471834 60015:60015 +0.00011266336187471834 56305:56305 +0.00011266336187471834 60232:60232 +0.00011266336187471834 33984:33984 +0.00011266336187471834 35453:35453 +0.00011266336187471834 59871:59871 +0.00011266336187471834 57737:57737 +0.00011266336187471834 57444:57444 +0.00011266336187471834 56352:56352 +0.00011266336187471834 60885:60885 +0.00011266336187471834 57031:57031 +0.00011266336187471834 58924:58924 +0.00011266336187471834 56626:56626 +0.00011266336187471834 55989:55989 +0.00011266336187471834 56458:56458 +0.00011266336187471834 58245:58245 +0.00011266336187471834 32970:32970 +0.00011266336187471834 58761:58761 +0.00011266336187471834 57277:57277 +0.00011266336187471834 56729:56729 +0.00011266336187471834 59541:59541 +0.00011266336187471834 57484:57484 +0.00011266336187471834 34976:34976 +0.00011266336187471834 34967:34967 +0.00011266336187471834 34492:34492 +0.00011266336187471834 35381:35381 +0.00011266336187471834 34538:34538 +0.00011266336187471834 59276:59276 +0.00011266336187471834 32997:32997 +0.00011266336187471834 55982:55982 +0.00011266336187471834 34224:34224 +0.00011266336187471834 57028:57028 +0.00011266336187471834 55905:55905 +0.00011266336187471834 59372:59372 +0.00011266336187471834 35397:35397 +0.00011266336187471834 34316:34316 +0.00011266336187471834 60773:60773 +0.00011266336187471834 33840:33840 +0.00011266336187471834 58854:58854 +0.00011266336187471834 57261:57261 +0.00011266336187471834 33781:33781 +0.00011266336187471834 59722:59722 +0.00011266336187471834 33969:33969 +0.00011266336187471834 35061:35061 +0.00011266336187471834 34591:34591 +0.00011266336187471834 56886:56886 +0.00011266336187471834 32784:32784 +0.00011266336187471834 56840:56840 +0.00011266336187471834 34968:34968 +0.00011266336187471834 56421:56421 +0.00011266336187471834 56079:56079 +0.00011266336187471834 56722:56722 +0.00011266336187471834 56149:56149 +0.00011266336187471834 57657:57657 +0.00011266336187471834 35168:35168 +0.00011266336187471834 33700:33700 +0.00011266336187471834 58712:58712 +0.00011266336187471834 56037:56037 +0.00011266336187471834 34495:34495 +0.00011266336187471834 55857:55857 +0.00011266336187471834 57087:57087 +0.00011266336187471834 57868:57868 +0.00011266336187471834 33864:33864 +0.00011266336187471834 32876:32876 +0.00011266336187471834 34982:34982 +0.00011266336187471834 32875:32875 +0.00011266336187471834 59283:59283 +0.00011266336187471834 56398:56398 +0.00011266336187471834 34851:34851 +0.00011266336187471834 33858:33858 +0.00011266336187471834 60845:60845 +0.00011266336187471834 56133:56133 +0.00011266336187471834 33724:33724 +0.00011266336187471834 57939:57939 +0.00011266336187471834 56983:56983 +0.00011266336187471834 34433:34433 +0.00011266336187471834 33634:33634 +0.00011266336187471834 60286:60286 +0.00011266336187471834 35525:35525 +0.00011266336187471834 34945:34945 +0.00011266336187471834 56285:56285 +0.00011266336187471834 56806:56806 +0.00011266336187471834 56764:56764 +0.00011266336187471834 60719:60719 +0.00011266336187471834 35351:35351 +0.00011266336187471834 35183:35183 +0.00011266336187471834 55906:55906 +0.00011266336187471834 59560:59560 +0.00011266336187471834 32951:32951 +0.00011266336187471834 57043:57043 +0.00011266336187471834 60362:60362 +0.00011266336187471834 34151:34151 +0.00011266336187471834 33827:33827 +0.00011266336187471834 35490:35490 +0.00011266336187471834 34731:34731 +0.00011266336187471834 33797:33797 +0.00011266336187471834 59008:59008 +0.00011266336187471834 33052:33052 +0.00011266336187471834 57313:57313 +0.00011266336187471834 56986:56986 +0.00011266336187471834 33092:33092 +0.00011266336187471834 34704:34704 +0.00011266336187471834 60959:60959 +0.00011266336187471834 59431:59431 +0.00011266336187471834 56719:56719 +0.00011266336187471834 59601:59601 +0.00011266336187471834 35364:35364 +0.00011266336187471834 59785:59785 +0.00011266336187471834 58887:58887 +0.00011266336187471834 33654:33654 +0.00011266336187471834 60642:60642 +0.00011266336187471834 59403:59403 +0.00011266336187471834 58542:58542 +0.00011266336187471834 56196:56196 +0.00011266336187471834 57165:57165 +0.00011266336187471834 56480:56480 +0.00011266336187471834 33217:33217 +0.00011266336187471834 57825:57825 +0.00011266336187471834 57270:57270 +0.00011266336187471834 59470:59470 +0.00011266336187471834 33207:33207 +0.00011266336187471834 34552:34552 +0.00011266336187471834 35310:35310 +0.00011266336187471834 56291:56291 +0.00011266336187471834 56701:56701 +0.00011266336187471834 55831:55831 +0.00011266336187471834 33649:33649 +0.00011266336187471834 57523:57523 +0.00011266336187471834 56024:56024 +0.00011266336187471834 33067:33067 +0.00011266336187471834 55689:55689 +0.00011266336187471834 33209:33209 +0.00011266336187471834 60217:60217 +0.00011266336187471834 57930:57930 +0.00011266336187471834 33019:33019 +0.00011266336187471834 33008:33008 +0.00011266336187471834 34313:34313 +0.00011266336187471834 56343:56343 +0.00011266336187471834 32860:32860 +0.00011266336187471834 33550:33550 +0.00011266336187471834 58095:58095 +0.00011266336187471834 57924:57924 +0.00011266336187471834 56172:56172 +0.00011266336187471834 55952:55952 +0.00011266336187471834 34393:34393 +0.00011266336187471834 57361:57361 +0.00011266336187471834 57731:57731 +0.00011266336187471834 57958:57958 +0.00011266336187471834 60789:60789 +0.00011266336187471834 59811:59811 +0.00011266336187471834 35412:35412 +0.00011266336187471834 58234:58234 +0.00011266336187471834 32797:32797 +0.00011266336187471834 59644:59644 +0.00011266336187471834 57787:57787 +0.00011266336187471834 55696:55696 +0.00011266336187471834 57026:57026 +0.00011266336187471834 57952:57952 +0.00011266336187471834 32913:32913 +0.00011266336187471834 56567:56567 +0.00011266336187471834 34928:34928 +0.00011266336187471834 59998:59998 +0.00011266336187471834 57785:57785 +0.00011266336187471834 34690:34690 +0.00011266336187471834 34535:34535 +0.00011266336187471834 33190:33190 +0.00011266336187471834 34148:34148 +0.00011266336187471834 34006:34006 +0.00011266336187471834 58225:58225 +0.00011266336187471834 57650:57650 +0.00011266336187471834 56686:56686 +0.00011266336187471834 33312:33312 +0.00011266336187471834 60079:60079 +0.00011266336187471834 33274:33274 +0.00011266336187471834 60380:60380 +0.00011266336187471834 60292:60292 +0.00011266336187471834 60355:60355 +0.00011266336187471834 56974:56974 +0.00011266336187471834 60859:60859 +0.00011266336187471834 59845:59845 +0.00011266336187471834 58624:58624 +0.00011266336187471834 58073:58073 +0.00011266336187471834 57400:57400 +0.00011266336187471834 34780:34780 +0.00011266336187471834 58286:58286 +0.00011266336187471834 34919:34919 +0.00011266336187471834 58495:58495 +0.00011266336187471834 59983:59983 +0.00011266336187471834 57761:57761 +0.00011266336187471834 57916:57916 +0.00011266336187471834 56417:56417 +0.00011266336187471834 34590:34590 +0.00011266336187471834 35324:35324 +0.00011266336187471834 33453:33453 +0.00011266336187471834 57018:57018 +0.00011266336187471834 35409:35409 +0.00011266336187471834 56281:56281 +0.00011266336187471834 57100:57100 +0.00011266336187471834 56412:56412 +0.00011266336187471834 34568:34568 +0.00011266336187471834 33694:33694 +0.00011266336187471834 59523:59523 +0.00011266336187471834 60553:60553 +0.00011266336187471834 57932:57932 +0.00011266336187471834 56515:56515 +0.00011266336187471834 34025:34025 +0.00011266336187471834 59676:59676 +0.00011266336187471834 57619:57619 +0.00011266336187471834 55733:55733 +0.00011266336187471834 34130:34130 +0.00011266336187471834 34243:34243 +0.00011266336187471834 60897:60897 +0.00011266336187471834 59285:59285 +0.00011266336187471834 60053:60053 +0.00011266336187471834 59033:59033 +0.00011266336187471834 59772:59772 +0.00011266336187471834 34683:34683 +0.00011266336187471834 59356:59356 +0.00011266336187471834 32779:32779 +0.00011266336187471834 58817:58817 +0.00011266336187471834 59618:59618 +0.00011266336187471834 58674:58674 +0.00011266336187471834 59096:59096 +0.00011266336187471834 33589:33589 +0.00011266336187471834 33518:33518 +0.00011266336187471834 60077:60077 +0.00011266336187471834 56601:56601 +0.00011266336187471834 55886:55886 +0.00011266336187471834 35517:35517 +0.00011266336187471834 35427:35427 +0.00011266336187471834 55666:55666 +0.00011266336187471834 59418:59418 +0.00011266336187471834 56337:56337 +0.00011266336187471834 56022:56022 +0.00011266336187471834 34624:34624 +0.00011266336187471834 59923:59923 +0.00011266336187471834 57441:57441 +0.00011266336187471834 59819:59819 +0.00011266336187471834 35477:35477 +0.00011266336187471834 58381:58381 +0.00011266336187471834 57140:57140 +0.00011266336187471834 59592:59592 +0.00011266336187471834 57963:57963 +0.00011266336187471834 34045:34045 +0.00011266336187471834 33779:33779 +0.00011266336187471834 57651:57651 +0.00011266336187471834 58222:58222 +0.00011266336187471834 60986:60986 +0.00011266336187471834 56785:56785 +0.00011266336187471834 60623:60623 +0.00011266336187471834 59113:59113 +0.00011266336187471834 35091:35091 +0.00011266336187471834 33538:33538 +0.00011266336187471834 56363:56363 +0.00011266336187471834 55984:55984 +0.00011266336187471834 60964:60964 +0.00011266336187471834 33158:33158 +0.00011266336187471834 59085:59085 +0.00011266336187471834 35128:35128 +0.00011266336187471834 32857:32857 +0.00011266336187471834 58263:58263 +0.00011266336187471834 34693:34693 +0.00011266336187471834 60879:60879 +0.00011266336187471834 58576:58576 +0.00011266336187471834 56365:56365 +0.00011266336187471834 58324:58324 +0.00011266336187471834 34401:34401 +0.00011266336187471834 59947:59947 +0.00011266336187471834 32929:32929 +0.00011266336187471834 59976:59976 +0.00011266336187471834 59379:59379 +0.00011266336187471834 57218:57218 +0.00011266336187471834 57940:57940 +0.00011266336187471834 56034:56034 +0.00011266336187471834 34425:34425 +0.00011266336187471834 34742:34742 +0.00011266336187471834 33727:33727 +0.00011266336187471834 60378:60378 +0.00011266336187471834 59180:59180 +0.00011266336187471834 60256:60256 +0.00011266336187471834 34497:34497 +0.00011266336187471834 34360:34360 +0.00011266336187471834 60969:60969 +0.00011266336187471834 58385:58385 +0.00011266336187471834 57910:57910 +0.00011266336187471834 56204:56204 +0.00011266336187471834 58355:58355 +0.00011266336187471834 56111:56111 +0.00011266336187471834 33897:33897 +0.00011266336187471834 57027:57027 +0.00011266336187471834 33908:33908 +0.00011266336187471834 60071:60071 +0.00011266336187471834 59561:59561 +0.00011266336187471834 60141:60141 +0.00011266336187471834 35470:35470 +0.00011266336187471834 56405:56405 +0.00011266336187471834 60212:60212 +0.00011266336187471834 58114:58114 +0.00011266336187471834 57220:57220 +0.00011266336187471834 55990:55990 +0.00011266336187471834 33814:33814 +0.00011266336187471834 60267:60267 +0.00011266336187471834 34330:34330 +0.00011266336187471834 58644:58644 +0.00011266336187471834 34451:34451 +0.00011266336187471834 60977:60977 +0.00011266336187471834 59920:59920 +0.00011266336187471834 55736:55736 +0.00011266336187471834 34906:34906 +0.00011266336187471834 59985:59985 +0.00011266336187471834 57255:57255 +0.00011266336187471834 60001:60001 +0.00011266336187471834 35530:35530 +0.00011266336187471834 34509:34509 +0.00011266336187471834 57025:57025 +0.00011266336187471834 34005:34005 +0.00011266336187471834 35304:35304 +0.00011266336187471834 56068:56068 +0.00011266336187471834 58631:58631 +0.00011266336187471834 56837:56837 +0.00011266336187471834 57454:57454 +0.00011266336187471834 34019:34019 +0.00011266336187471834 35355:35355 +0.00011266336187471834 60459:60459 +0.00011266336187471834 58655:58655 +0.00011266336187471834 57558:57558 +0.00011266336187471834 56599:56599 +0.00011266336187471834 34024:34024 +0.00011266336187471834 34239:34239 +0.00011266336187471834 55755:55755 +0.00011266336187471834 56592:56592 +0.00011266336187471834 32988:32988 +0.00011266336187471834 57919:57919 +0.00011266336187471834 59369:59369 +0.00011266336187471834 58908:58908 +0.00011266336187471834 57779:57779 +0.00011266336187471834 34886:34886 +0.00011266336187471834 60262:60262 +0.00011266336187471834 34429:34429 +0.00011266336187471834 34338:34338 +0.00011266336187471834 59387:59387 +0.00011266336187471834 59125:59125 +0.00011266336187471834 57126:57126 +0.00011266336187471834 60065:60065 +0.00011266336187471834 57596:57596 +0.00011266336187471834 34890:34890 +0.00011266336187471834 58100:58100 +0.00011266336187471834 57114:57114 +0.00011266336187471834 34737:34737 +0.00011266336187471834 34613:34613 +0.00011266336187471834 60410:60410 +0.00011266336187471834 60108:60108 +0.00011266336187471834 34752:34752 +0.00011266336187471834 56550:56550 +0.00011266336187471834 32915:32915 +0.00011266336187471834 58151:58151 +0.00011266336187471834 56408:56408 +0.00011266336187471834 58322:58322 +0.00011266336187471834 58250:58250 +0.00011266336187471834 58269:58269 +0.00011266336187471834 35054:35054 +0.00011266336187471834 34893:34893 +0.00011266336187471834 34299:34299 +0.00011266336187471834 34281:34281 +0.00011266336187471834 33123:33123 +0.00011266336187471834 60058:60058 +0.00011266336187471834 56367:56367 +0.00011266336187471834 57186:57186 +0.00011266336187471834 59835:59835 +0.00011266336187471834 56299:56299 +0.00011266336187471834 58534:58534 +0.00011266336187471834 55650:55650 +0.00011266336187471834 32790:32790 +0.00011266336187471834 58718:58718 +0.00011266336187471834 58551:58551 +0.00011266336187471834 56526:56526 +0.00011266336187471834 56033:56033 +0.00011266336187471834 57354:57354 +0.00011266336187471834 56839:56839 +0.00011266336187471834 58995:58995 +0.00011266336187471834 58707:58707 +0.00011266336187471834 57670:57670 +0.00011266336187471834 58701:58701 +0.00011266336187471834 58493:58493 +0.00011266336187471834 34567:34567 +0.00011266336187471834 33391:33391 +0.00011266336187471834 59683:59683 +0.00011266336187471834 60912:60912 +0.00011266336187471834 55856:55856 +0.00011266336187471834 60370:60370 +0.00011266336187471834 34775:34775 +0.00011266336187471834 60307:60307 +0.00011266336187471834 56361:56361 +0.00011266336187471834 33946:33946 +0.00011266336187471834 57970:57970 +0.00011266336187471834 56791:56791 +0.00011266336187471834 35006:35006 +0.00011266336187471834 34358:34358 +0.00011266336187471834 58979:58979 +0.00011266336187471834 55764:55764 +0.00011266336187471834 34163:34163 +0.00011266336187471834 58687:58687 +0.00011266336187471834 57982:57982 +0.00011266336187471834 33499:33499 +0.00011266336187471834 32937:32937 +0.00011266336187471834 33648:33648 +0.00011266336187471834 33482:33482 +0.00011266336187471834 56528:56528 +0.00011266336187471834 35357:35357 +0.00011266336187471834 57587:57587 +0.00011266336187471834 35438:35438 +0.00011266336187471834 57090:57090 +0.00011266336187471834 56324:56324 +0.00011266336187471834 56279:56279 +0.00011266336187471834 33573:33573 +0.00011266336187471834 58652:58652 +0.00011266336187471834 60298:60298 +0.00011266336187471834 58596:58596 +0.00011266336187471834 58386:58386 +0.00011266336187471834 58098:58098 +0.00011266336187471834 56991:56991 +0.00011266336187471834 60586:60586 +0.00011266336187471834 60306:60306 +0.00011266336187471834 57403:57403 +0.00011266336187471834 56535:56535 +0.00011266336187471834 56944:56944 +0.00011266336187471834 60349:60349 +0.00011266336187471834 34986:34986 +0.00011266336187471834 32835:32835 +0.00011266336187471834 59874:59874 +0.00011266336187471834 57069:57069 +0.00011266336187471834 58028:58028 +0.00011266336187471834 59725:59725 +0.00011266336187471834 58621:58621 +0.00011266336187471834 58021:58021 +0.00011266336187471834 33165:33165 +0.00011266336187471834 59136:59136 +0.00011266336187471834 60939:60939 +0.00011266336187471834 56234:56234 +0.00011266336187471834 35533:35533 +0.00011266336187471834 34424:34424 +0.00011266336187471834 56216:56216 +0.00011266336187471834 35300:35300 +0.00011266336187471834 60249:60249 +0.00011266336187471834 33823:33823 +0.00011266336187471834 59321:59321 +0.00011266336187471834 39732:39732 +0.00011266336187471834 33916:33916 +0.00011266336187471834 58749:58749 +0.00011266336187471834 57217:57217 +0.00011266336187471834 34435:34435 +0.00011266336187471834 33945:33945 +0.00011266336187471834 56733:56733 +0.00011266336187471834 56377:56377 +0.00011266336187471834 58458:58458 +0.00011266336187471834 32968:32968 +0.00011266336187471834 33795:33795 +0.00011266336187471834 33537:33537 +0.00011266336187471834 57798:57798 +0.00011266336187471834 57009:57009 +0.00011266336187471834 59615:59615 +0.00011266336187471834 34837:34837 +0.00011266336187471834 58889:58889 +0.00011266336187471834 34710:34710 +0.00011266336187471834 32887:32887 +0.00011266336187471834 58999:58999 +0.00011266336187471834 57502:57502 +0.00011266336187471834 57312:57312 +0.00011266336187471834 57113:57113 +0.00011266336187471834 56827:56827 +0.00011266336187471834 58846:58846 +0.00011266336187471834 58439:58439 +0.00011266336187471834 34962:34962 +0.00011266336187471834 60886:60886 +0.00011266336187471834 60072:60072 +0.00011266336187471834 59364:59364 +0.00011266336187471834 56533:56533 +0.00011266336187471834 33271:33271 +0.00011266336187471834 56435:56435 +0.00011266336187471834 33866:33866 +0.00011266336187471834 58617:58617 +0.00011266336187471834 58555:58555 +0.00011266336187471834 34550:34550 +0.00011266336187471834 33246:33246 +0.00011266336187471834 33978:33978 +0.00011266336187471834 57359:57359 +0.00011266336187471834 35476:35476 +0.00011266336187471834 57153:57153 +0.00011266336187471834 55774:55774 +0.00011266336187471834 60495:60495 +0.00011266336187471834 55656:55656 +0.00011266336187471834 35406:35406 +0.00011266336187471834 57475:57475 +0.00011266336187471834 58550:58550 +0.00011266336187471834 58376:58376 +0.00011266336187471834 55810:55810 +0.00011266336187471834 34615:34615 +0.00011266336187471834 59509:59509 +0.00011266336187471834 58275:58275 +0.00011266336187471834 56364:56364 +0.00011266336187471834 60541:60541 +0.00011266336187471834 58828:58828 +0.00011266336187471834 35311:35311 +0.00011266336187471834 59189:59189 +0.00011266336187471834 58087:58087 +0.00011266336187471834 33689:33689 +0.00011266336187471834 58779:58779 +0.00011266336187471834 32789:32789 +0.00011266336187471834 59619:59619 +0.00011266336187471834 55808:55808 +0.00011266336187471834 34988:34988 +0.00011266336187471834 34533:34533 +0.00011266336187471834 59013:59013 +0.00011266336187471834 56347:56347 +0.00011266336187471834 33778:33778 +0.00011266336187471834 33490:33490 +0.00011266336187471834 57869:57869 +0.00011266336187471834 58190:58190 +0.00011266336187471834 55999:55999 +0.00011266336187471834 56252:56252 +0.00011266336187471834 34427:34427 +0.00011266336187471834 60075:60075 +0.00011266336187471834 56906:56906 +0.00011266336187471834 60580:60580 +0.00011266336187471834 35317:35317 +0.00011266336187471834 57901:57901 +0.00011266336187471834 58317:58317 +0.00011266336187471834 58070:58070 +0.00011266336187471834 33776:33776 +0.00011266336187471834 60351:60351 +0.00011266336187471834 59791:59791 +0.00011266336187471834 58239:58239 +0.00011266336187471834 57584:57584 +0.00011266336187471834 58808:58808 +0.00011266336187471834 58139:58139 +0.00011266336187471834 57566:57566 +0.00011266336187471834 59901:59901 +0.00011266336187471834 59079:59079 +0.00011266336187471834 57693:57693 +0.00011266336187471834 32931:32931 +0.00011266336187471834 57740:57740 +0.00011266336187471834 59404:59404 +0.00011266336187471834 35055:35055 +0.00011266336187471834 33867:33867 +0.00011266336187471834 58876:58876 +0.00011266336187471834 33184:33184 +0.00011266336187471834 56171:56171 +0.00011266336187471834 57606:57606 +0.00011266336187471834 35434:35434 +0.00011266336187471834 56362:56362 +0.00011266336187471834 60102:60102 +0.00011266336187471834 58123:58123 +0.00011266336187471834 55964:55964 +0.00011266336187471834 35474:35474 +0.00011266336187471834 56555:56555 +0.00011266336187471834 57603:57603 +0.00011266336187471834 55657:55657 +0.00011266336187471834 33794:33794 +0.00011266336187471834 33517:33517 +0.00011266336187471834 33044:33044 +0.00011266336187471834 58781:58781 +0.00011266336187471834 56838:56838 +0.00011266336187471834 33346:33346 +0.00011266336187471834 60429:60429 +0.00011266336187471834 58232:58232 +0.00011266336187471834 55672:55672 +0.00011266336187471834 56269:56269 +0.00011266336187471834 59047:59047 +0.00011266336187471834 57550:57550 +0.00011266336187471834 34215:34215 +0.00011266336187471834 34054:34054 +0.00011266336187471834 35286:35286 +0.00011266336187471834 56970:56970 +0.00011266336187471834 56802:56802 +0.00011266336187471834 56191:56191 +0.00011266336187471834 58838:58838 +0.00011266336187471834 57408:57408 +0.00011266336187471834 58559:58559 +0.00011266336187471834 59394:59394 +0.00011266336187471834 58969:58969 +0.00011266336187471834 59969:59969 +0.00011266336187471834 58179:58179 +0.00011266336187471834 34779:34779 +0.00011266336187471834 34637:34637 +0.00011266336187471834 33706:33706 +0.00011266336187471834 34395:34395 +0.00011266336187471834 60342:60342 +0.00011266336187471834 58912:58912 +0.00011266336187471834 60449:60449 +0.00011266336187471834 60443:60443 +0.00011266336187471834 55969:55969 +0.00011266336187471834 59294:59294 +0.00011266336187471834 58041:58041 +0.00011266336187471834 57844:57844 +0.00011266336187471834 55717:55717 +0.00011266336187471834 55907:55907 +0.00011266336187471834 32820:32820 +0.00011266336187471834 34178:34178 +0.00011266336187471834 33543:33543 +0.00011266336187471834 35374:35374 +0.00011266336187471834 34619:34619 +0.00011266336187471834 55994:55994 +0.00011266336187471834 60562:60562 +0.00011266336187471834 58169:58169 +0.00011266336187471834 57235:57235 +0.00011266336187471834 60396:60396 +0.00011266336187471834 59812:59812 +0.00011266336187471834 59551:59551 +0.00011266336187471834 32830:32830 +0.00011266336187471834 57735:57735 +0.00011266336187471834 57655:57655 +0.00011266336187471834 33109:33109 +0.00011266336187471834 55634:55634 +0.00011266336187471834 58648:58648 +0.00011266336187471834 58352:58352 +0.00011266336187471834 35111:35111 +0.00011266336187471834 33613:33613 +0.00011266336187471834 59514:59514 +0.00011266336187471834 55621:55621 +0.00011266336187471834 60218:60218 +0.00011266336187471834 57351:57351 +0.00011266336187471834 60944:60944 +0.00011266336187471834 34478:34478 +0.00011266336187471834 60213:60213 +0.00011266336187471834 59591:59591 +0.00011266336187471834 57654:57654 +0.00011266336187471834 59402:59402 +0.00011266336187471834 58318:58318 +0.00011266336187471834 58714:58714 +0.00011266336187471834 32842:32842 +0.00011266336187471834 57297:57297 +0.00011266336187471834 34939:34939 +0.00011266336187471834 34907:34907 +0.00011266336187471834 57510:57510 +0.00011266336187471834 34483:34483 +0.00011266336187471834 32992:32992 +0.00011266336187471834 56415:56415 +0.00011266336187471834 60767:60767 +0.00011266336187471834 33195:33195 +0.00011266336187471834 34353:34353 +0.00011266336187471834 55959:55959 +0.00011266336187471834 35270:35270 +0.00011266336187471834 35221:35221 +0.00011266336187471834 57878:57878 +0.00011266336187471834 57314:57314 +0.00011266336187471834 34177:34177 +0.00011266336187471834 33504:33504 +0.00011266336187471834 35526:35526 +0.00011266336187471834 33766:33766 +0.00011266336187471834 56958:56958 +0.00011266336187471834 32917:32917 +0.00011266336187471834 59672:59672 +0.00011266336187471834 58998:58998 +0.00011266336187471834 35274:35274 +0.00011266336187471834 34653:34653 +0.00011266336187471834 32947:32947 +0.00011266336187471834 60441:60441 +0.00011266336187471834 33153:33153 +0.00011266336187471834 57841:57841 +0.00011266336187471834 58795:58795 +0.00011266336187471834 55830:55830 +0.00011266336187471834 34650:34650 +0.00011266336187471834 58878:58878 +0.00011266336187471834 58448:58448 +0.00011266336187471834 60367:60367 +0.00011266336187471834 59717:59717 +0.00011266336187471834 58903:58903 +0.00011266336187471834 57455:57455 +0.00011266336187471834 35018:35018 +0.00011266336187471834 58590:58590 +0.00011266336187471834 32885:32885 +0.00011266336187471834 57476:57476 +0.00011266336187471834 34008:34008 +0.00011266336187471834 60598:60598 +0.00011266336187471834 57848:57848 +0.00011266336187471834 56638:56638 +0.00011266336187471834 56439:56439 +0.00011266336187471834 34469:34469 +0.00011266336187471834 60947:60947 +0.00011266336187471834 58479:58479 +0.00011266336187471834 57956:57956 +0.00011266336187471834 33968:33968 +0.00011266336187471834 58801:58801 +0.00011266336187471834 57199:57199 +0.00011266336187471834 34829:34829 +0.00011266336187471834 59638:59638 +0.00011266336187471834 59577:59577 +0.00011266336187471834 57667:57667 +0.00011266336187471834 57513:57513 +0.00011266336187471834 55655:55655 +0.00011266336187471834 33477:33477 +0.00011266336187471834 32781:32781 +0.00011266336187471834 35539:35539 +0.00011266336187471834 59913:59913 +0.00011266336187471834 34109:34109 +0.00011266336187471834 33449:33449 +0.00011266336187471834 34768:34768 +0.00011266336187471834 33264:33264 +0.00011266336187471834 59348:59348 +0.00011266336187471834 33240:33240 +0.00011266336187471834 32944:32944 +0.00011266336187471834 60257:60257 +0.00011266336187471834 33974:33974 +0.00011266336187471834 33784:33784 +0.00011266336187471834 34617:34617 +0.00011266336187471834 34194:34194 +0.00011266336187471834 35271:35271 +0.00011266336187471834 56085:56085 +0.00011266336187471834 34501:34501 +0.00011266336187471834 33475:33475 +0.00011266336187471834 59567:59567 +0.00011266336187471834 55881:55881 +0.00011266336187471834 59409:59409 +0.00011266336187471834 59374:59374 +0.00011266336187471834 34587:34587 +0.00011266336187471834 57291:57291 +0.00011266336187471834 60397:60397 +0.00011266336187471834 56284:56284 +0.00011266336187471834 59024:59024 +0.00011266336187471834 57727:57727 +0.00011266336187471834 34853:34853 +0.00011266336187471834 57870:57870 +0.00011266336187471834 57845:57845 +0.00011266336187471834 59604:59604 +0.00011266336187471834 57542:57542 +0.00011266336187471834 60650:60650 +0.00011266336187471834 33426:33426 +0.00011266336187471834 59878:59878 +0.00011266336187471834 59670:59670 +0.00011266336187471834 32950:32950 +0.00011266336187471834 33252:33252 +0.00011266336187471834 33427:33427 +0.00011266336187471834 57461:57461 +0.00011266336187471834 60091:60091 +0.00011266336187471834 35021:35021 +0.00011266336187471834 57068:57068 +0.00011266336187471834 57141:57141 +0.00011266336187471834 55961:55961 +0.00011266336187471834 60060:60060 +0.00011266336187471834 57127:57127 +0.00011266336187471834 59195:59195 +0.00011266336187471834 60835:60835 +0.00011266336187471834 58475:58475 +0.00011266336187471834 59664:59664 +0.00011266336187471834 33202:33202 +0.00011266336187471834 60074:60074 +0.00011266336187471834 33787:33787 +0.00011266336187471834 35134:35134 +0.00011266336187471834 55816:55816 +0.00011266336187471834 33915:33915 +0.00011266336187471834 59839:59839 +0.00011266336187471834 34817:34817 +0.00011266336187471834 55892:55892 +0.00011266336187471834 58035:58035 +0.00011266336187471834 56695:56695 +0.00011266336187471834 34723:34723 +0.00011266336187471834 34461:34461 +0.00011266336187471834 56941:56941 +0.00011266336187471834 55941:55941 +0.00011266336187471834 34664:34664 +0.00011266336187471834 59669:59669 +0.00011266336187471834 57562:57562 +0.00011266336187471834 33340:33340 +0.00011266336187471834 59686:59686 +0.00011266336187471834 33515:33515 +0.00011266336187471834 56814:56814 +0.00011266336187471834 59678:59678 +0.00011266336187471834 60439:60439 +0.00011266336187471834 56627:56627 +0.00011266336187471834 58859:58859 +0.00011266336187471834 34245:34245 +0.00011266336187471834 58279:58279 +0.00011266336187471834 33638:33638 +0.00011266336187471834 33136:33136 +0.00011266336187471834 33661:33661 +0.00011266336187471834 58523:58523 +0.00011266336187471834 56677:56677 +0.00011266336187471834 58981:58981 +0.00011266336187471834 58231:58231 +0.00011266336187471834 56691:56691 +0.00011266336187471834 60985:60985 +0.00011266336187471834 58578:58578 +0.00011266336187471834 56203:56203 +0.00011266336187471834 58930:58930 +0.00011266336187471834 56536:56536 +0.00011266336187471834 34816:34816 +0.00011266336187471834 33128:33128 +0.00011266336187471834 60830:60830 +0.00011266336187471834 57915:57915 +0.00011266336187471834 58608:58608 +0.00011266336187471834 55703:55703 +0.00011266336187471834 57883:57883 +0.00011266336187471834 56746:56746 +0.00011266336187471834 35353:35353 +0.00011266336187471834 59802:59802 +0.00011266336187471834 32987:32987 +0.00011266336187471834 34841:34841 +0.00011266336187471834 60005:60005 +0.00011266336187471834 57425:57425 +0.00011266336187471834 59218:59218 +0.00011266336187471834 56784:56784 +0.00011266336187471834 60797:60797 +0.00011266336187471834 56513:56513 +0.00011266336187471834 59397:59397 +0.00011266336187471834 56018:56018 +0.00011266336187471834 33598:33598 +0.00011266336187471834 59883:59883 +0.00011266336187471834 56438:56438 +0.00011266336187471834 35369:35369 +0.00011266336187471834 34620:34620 +0.00011266336187471834 59716:59716 +0.00011266336187471834 34265:34265 +0.00011266336187471834 32817:32817 +0.00011266336187471834 56319:56319 +0.00011266336187471834 35520:35520 +0.00011266336187471834 55807:55807 +0.00011266336187471834 34371:34371 +0.00011266336187471834 56466:56466 +0.00011266336187471834 34987:34987 +0.00011266336187471834 58036:58036 +0.00011266336187471834 33842:33842 +0.00011266336187471834 33378:33378 +0.00011266336187471834 34406:34406 +0.00011266336187471834 33121:33121 +0.00011266336187471834 35389:35389 +0.00011266336187471834 34368:34368 +0.00011266336187471834 33476:33476 +0.00011266336187471834 58943:58943 +0.00011266336187471834 59755:59755 +0.00011266336187471834 59471:59471 +0.00011266336187471834 34147:34147 +0.00011266336187471834 59628:59628 +0.00011266336187471834 55858:55858 +0.00011266336187471834 57706:57706 +0.00011266336187471834 56864:56864 +0.00011266336187471834 33583:33583 +0.00011266336187471834 59927:59927 +0.00011266336187471834 60134:60134 +0.00011266336187471834 59253:59253 +0.00011266336187471834 58568:58568 +0.00011266336187471834 34333:34333 +0.00011266336187471834 55715:55715 +0.00011266336187471834 33066:33066 +0.00011266336187471834 59460:59460 +0.00011266336187471834 59290:59290 +0.00011266336187471834 60113:60113 +0.00011266336187471834 57807:57807 +0.00011266336187471834 34105:34105 +0.00011266336187471834 35034:35034 +0.00011266336187471834 34141:34141 +0.00011266336187471834 60570:60570 +0.00011266336187471834 35332:35332 +0.00011266336187471834 33714:33714 +0.00011266336187471834 57205:57205 +0.00011266336187471834 33788:33788 +0.00011266336187471834 60493:60493 +0.00011266336187471834 59610:59610 +0.00011266336187471834 57253:57253 +0.00011266336187471834 56946:56946 +0.00011266336187471834 33146:33146 +0.00011266336187471834 60247:60247 +0.00011266336187471834 59803:59803 +0.00011266336187471834 56477:56477 +0.00011266336187471834 55739:55739 +0.00011266336187471834 35080:35080 +0.00011266336187471834 58953:58953 +0.00011266336187471834 56444:56444 +0.00011266336187471834 35188:35188 +0.00011266336187471834 35367:35367 +0.00011266336187471834 58293:58293 +0.00011266336187471834 58104:58104 +0.00011266336187471834 58235:58235 +0.00011266336187471834 57534:57534 +0.00011266336187471834 60987:60987 +0.00011266336187471834 57417:57417 +0.00011266336187471834 56788:56788 +0.00011266336187471834 57311:57311 +0.00011266336187471834 55867:55867 +0.00011266336187471834 33987:33987 +0.00011266336187471834 59930:59930 +0.00011266336187471834 58965:58965 +0.00011266336187471834 33273:33273 +0.00011266336187471834 60007:60007 +0.00011266336187471834 55955:55955 +0.00011266336187471834 35370:35370 +0.00011266336187471834 33400:33400 +0.00011266336187471834 60617:60617 +0.00011266336187471834 60453:60453 +0.00011266336187471834 59688:59688 +0.00011266336187471834 56845:56845 +0.00011266336187471834 58454:58454 +0.00011266336187471834 35103:35103 +0.00011266336187471834 58944:58944 +0.00011266336187471834 56055:56055 +0.00011266336187471834 59156:59156 +0.00011266336187471834 59999:59999 +0.00011266336187471834 60775:60775 +0.00011266336187471834 56818:56818 +0.00011266336187471834 56120:56120 +0.00011266336187471834 57405:57405 +0.00011266336187471834 56756:56756 +0.00011266336187471834 60854:60854 +0.00011266336187471834 60175:60175 +0.00011266336187471834 34437:34437 +0.00011266336187471834 33773:33773 +0.00011266336187471834 57794:57794 +0.00011266336187471834 57555:57555 +0.00011266336187471834 59132:59132 +0.00011266336187471834 34246:34246 +0.00011266336187471834 32838:32838 +0.00011266336187471834 56436:56436 +0.00011266336187471834 58241:58241 +0.00011266336187471834 58005:58005 +0.00011266336187471834 33406:33406 +0.00011266336187471834 35245:35245 +0.00011266336187471834 34013:34013 +0.00011266336187471834 59034:59034 +0.00011266336187471834 34796:34796 +0.00011266336187471834 58444:58444 +0.00011266336187471834 35345:35345 +0.00011266336187471834 32859:32859 +0.00011266336187471834 32791:32791 +0.00011266336187471834 60962:60962 +0.00011266336187471834 35556:35556 +0.00011266336187471834 60145:60145 +0.00011266336187471834 58985:58985 +0.00011266336187471834 58741:58741 +0.00011266336187471834 58051:58051 +0.00011266336187471834 32925:32925 +0.00011266336187471834 60958:60958 +0.00011266336187471834 59128:59128 +0.00011266336187471834 59981:59981 +0.00011266336187471834 58787:58787 +0.00011266336187471834 57594:57594 +0.00011266336187471834 56735:56735 +0.00011266336187471834 57826:57826 +0.00011266336187471834 56259:56259 +0.00011266336187471834 35155:35155 +0.00011266336187471834 58814:58814 +0.00011266336187471834 35454:35454 +0.00011266336187471834 56144:56144 +0.00011266336187471834 56504:56504 +0.00011266336187471834 60187:60187 +0.00011266336187471834 58609:58609 +0.00011266336187471834 58406:58406 +0.00011266336187471834 56866:56866 +0.00011266336187471834 58900:58900 +0.00011266336187471834 34918:34918 +0.00011266336187471834 33928:33928 +0.00011266336187471834 60730:60730 +0.00011266336187471834 60631:60631 +0.00011266336187471834 58013:58013 +0.00011266336187471834 56510:56510 +0.00011266336187471834 56859:56859 +0.00011266336187471834 58785:58785 +0.00011266336187471834 57836:57836 +0.00011266336187471834 34580:34580 +0.00011266336187471834 58353:58353 +0.00011266336187471834 60953:60953 +0.00011266336187471834 57646:57646 +0.00011266336187471834 57051:57051 +0.00011266336187471834 60976:60976 +0.00011266336187471834 58366:58366 +0.00011266336187471834 56931:56931 +0.00011266336187471834 33617:33617 +0.00011266336187471834 56413:56413 +0.00011266336187471834 32912:32912 +0.00011266336187471834 59009:59009 +0.00011266336187471834 33261:33261 +0.00011266336187471834 57929:57929 +0.00011266336187471834 56565:56565 +0.00011266336187471834 34277:34277 +0.00011266336187471834 60706:60706 +0.00011266336187471834 56220:56220 +0.00011266336187471834 34114:34114 +0.00011266336187471834 33343:33343 +0.00011266336187471834 56822:56822 +0.00011266336187471834 34428:34428 +0.00011266336187471834 33528:33528 +0.00011266336187471834 59475:59475 +0.00011266336187471834 55838:55838 +0.00011266336187471834 35092:35092 +0.00011266336187471834 56517:56517 +0.00011266336187471834 56308:56308 +0.00011266336187471834 33016:33016 +0.00011266336187471834 56948:56948 +0.00011266336187471834 35465:35465 +0.00011266336187471834 60509:60509 +0.00011266336187471834 60710:60710 +0.00011266336187471834 56164:56164 +0.00011266336187471834 56194:56194 +0.00011266336187471834 57810:57810 +0.00011266336187471834 55977:55977 +0.00011266336187471834 59325:59325 +0.00011266336187471834 58452:58452 +0.00011266336187471834 56918:56918 +0.00011266336187471834 56423:56423 +0.00011266336187471834 55948:55948 +0.00011266336187471834 55793:55793 +0.00011266336187471834 60140:60140 +0.00011266336187471834 59267:59267 +0.00011266336187471834 58993:58993 +0.00011266336187471834 58788:58788 +0.00011266336187471834 57726:57726 +0.00011266336187471834 56600:56600 +0.00011266336187471834 35112:35112 +0.00011266336187471834 60442:60442 +0.00011266336187471834 34164:34164 +0.00011266336187471834 60176:60176 +0.00011266336187471834 33935:33935 +0.00011266336187471834 33859:33859 +0.00011266336187471834 35302:35302 +0.00011266336187471834 60584:60584 +0.00011266336187471834 59318:59318 +0.00011266336187471834 34376:34376 +0.00011266336187471834 34325:34325 +0.00011266336187471834 59449:59449 +0.00011266336187471834 58984:58984 +0.00011266336187471834 57449:57449 +0.00011266336187471834 59448:59448 +0.00011266336187471834 60066:60066 +0.00011266336187471834 59466:59466 +0.00011266336187471834 60653:60653 +0.00011266336187471834 33371:33371 +0.00011266336187471834 35488:35488 +0.00011266336187471834 58647:58647 +0.00011266336187471834 57503:57503 +0.00011266336187471834 57586:57586 +0.00011266336187471834 56969:56969 +0.00011266336187471834 34234:34234 +0.00011266336187471834 33494:33494 +0.00011266336187471834 60174:60174 +0.00011266336187471834 34903:34903 +0.00011266336187471834 34166:34166 +0.00011266336187471834 59616:59616 +0.00011266336187471834 60735:60735 +0.00011266336187471834 57585:57585 +0.00011266336187471834 56141:56141 +0.00011266336187471834 35272:35272 +0.00011266336187471834 35219:35219 +0.00011266336187471834 34860:34860 +0.00011266336187471834 60228:60228 +0.00011266336187471834 56593:56593 +0.00011266336187471834 55731:55731 +0.00011266336187471834 60982:60982 +0.00011266336187471834 56452:56452 +0.00011266336187471834 35269:35269 +0.00011266336187471834 33336:33336 +0.00011266336187471834 59444:59444 +0.00011266336187471834 33937:33937 +0.00011266336187471834 33368:33368 +0.00011266336187471834 60758:60758 +0.00011266336187471834 33440:33440 +0.00011266336187471834 34188:34188 +0.00011266336187471834 56911:56911 +0.00011266336187471834 34974:34974 +0.00011266336187471834 60817:60817 +0.00011266336187471834 59232:59232 +0.00011266336187471834 34747:34747 +0.00011266336187471834 32958:32958 +0.00011266336187471834 59105:59105 +0.00011266336187471834 60152:60152 +0.00011266336187471834 57202:57202 +0.00011266336187471834 34385:34385 +0.00011266336187471834 60852:60852 +0.00011266336187471834 35554:35554 +0.00011266336187471834 32772:32772 +0.00011266336187471834 34222:34222 +0.00011266336187471834 60198:60198 +0.00011266336187471834 58016:58016 +0.00011266336187471834 33159:33159 +0.00011266336187471834 59257:59257 +0.00011266336187471834 58290:58290 +0.00011266336187471834 57486:57486 +0.00011266336187471834 34911:34911 +0.00011266336187471834 33951:33951 +0.00011266336187471834 33806:33806 +0.00011266336187471834 59520:59520 +0.00011266336187471834 58131:58131 +0.00011266336187471834 56841:56841 +0.00011266336187471834 33715:33715 +0.00011266336187471834 55966:55966 +0.00011266336187471834 59898:59898 +0.00011266336187471834 56093:56093 +0.00011266336187471834 59633:59633 +0.00011266336187471834 58877:58877 +0.00011266336187471834 33000:33000 +0.00011266336187471834 33529:33529 +0.00011266336187471834 58288:58288 +0.00011266336187471834 57707:57707 +0.00011266336187471834 34916:34916 +0.00011266336187471834 58511:58511 +0.00011266336187471834 56748:56748 +0.00011266336187471834 33178:33178 +0.00011266336187471834 33107:33107 +0.00011266336187471834 60920:60920 +0.00011266336187471834 58599:58599 +0.00011266336187471834 34922:34922 +0.00011266336187471834 58666:58666 +0.00011266336187471834 34990:34990 +0.00011266336187471834 33666:33666 +0.00011266336187471834 58720:58720 +0.00011266336187471834 60348:60348 +0.00011266336187471834 35068:35068 +0.00011266336187471834 35203:35203 +0.00011266336187471834 34323:34323 +0.00011266336187471834 58270:58270 +0.00011266336187471834 60968:60968 +0.00011266336187471834 57325:57325 +0.00011266336187471834 57193:57193 +0.00011266336187471834 56851:56851 +0.00011266336187471834 35368:35368 +0.00011266336187471834 58140:58140 +0.00011266336187471834 60337:60337 +0.00011266336187471834 59163:59163 +0.00011266336187471834 33276:33276 +0.00011266336187471834 34677:34677 +0.00011266336187471834 35551:35551 +0.00011266336187471834 32837:32837 +0.00011266336187471834 35303:35303 +0.00011266336187471834 55646:55646 +0.00011266336187471834 59854:59854 +0.00011266336187471834 59710:59710 +0.00011266336187471834 60806:60806 +0.00011266336187471834 34392:34392 +0.00011266336187471834 59480:59480 +0.00011266336187471834 34584:34584 +0.00011266336187471834 33561:33561 +0.00011266336187471834 59091:59091 +0.00011266336187471834 33115:33115 +0.00011266336187471834 57717:57717 +0.00011266336187471834 60560:60560 +0.00011266336187471834 60344:60344 +0.00011266336187471834 58885:58885 +0.00011266336187471834 56834:56834 +0.00011266336187471834 59244:59244 +0.00011266336187471834 56786:56786 +0.00011266336187471834 33895:33895 +0.00011266336187471834 56684:56684 +0.00011266336187471834 58604:58604 +0.00011266336187471834 60305:60305 +0.00011266336187471834 57897:57897 +0.00011266336187471834 59864:59864 +0.00011266336187471834 58209:58209 +0.00011266336187471834 55835:55835 +0.00011266336187471834 57944:57944 +0.00011266336187471834 57081:57081 +0.00011266336187471834 60234:60234 +0.00011266336187471834 57265:57265 +0.00011266336187471834 59271:59271 +0.00011266336187471834 59045:59045 +0.00011266336187471834 58135:58135 +0.00011266336187471834 55975:55975 +0.00011266336187471834 56307:56307 +0.00011266336187471834 59241:59241 +0.00011266336187471834 57840:57840 +0.00011266336187471834 34221:34221 +0.00011266336187471834 57888:57888 +0.00011266336187471834 57268:57268 +0.00011266336187471834 55686:55686 +0.00011266336187471834 60887:60887 +0.00011266336187471834 58592:58592 +0.00011266336187471834 57860:57860 +0.00011266336187471834 60666:60666 +0.00011266336187471834 55976:55976 +0.00011266336187471834 34882:34882 +0.00011266336187471834 58694:58694 +0.00011266336187471834 60543:60543 +0.00011266336187471834 58588:58588 +0.00011266336187471834 56868:56868 +0.00011266336187471834 57772:57772 +0.00011266336187471834 33151:33151 +0.00011266336187471834 34072:34072 +0.00011266336187471834 60049:60049 +0.00011266336187471834 56114:56114 +0.00011266336187471834 58778:58778 +0.00011266336187471834 57416:57416 +0.00011266336187471834 59225:59225 +0.00011266336187471834 58116:58116 +0.00011266336187471834 35218:35218 +0.00011266336187471834 34929:34929 +0.00011266336187471834 60240:60240 +0.00011266336187471834 60192:60192 +0.00011266336187471834 33972:33972 +0.00011266336187471834 56095:56095 +0.00011266336187471834 33090:33090 +0.00011266336187471834 60130:60130 +0.00011266336187471834 58747:58747 +0.00011266336187471834 59757:59757 +0.00011266336187471834 34115:34115 +0.00011266336187471834 34075:34075 +0.00011266336187471834 58413:58413 +0.00011266336187471834 58305:58305 +0.00011266336187471834 56538:56538 +0.00011266336187471834 34592:34592 +0.00011266336187471834 34278:34278 +0.00011266336187471834 60665:60665 +0.00011266336187471834 60531:60531 +0.00011266336187471834 60125:60125 +0.00011266336187471834 58730:58730 +0.00011266336187471834 33100:33100 +0.00011266336187471834 59731:59731 +0.00011266336187471834 56823:56823 +0.00011266336187471834 33251:33251 +0.00011266336187471834 56954:56954 +0.00011266336187471834 58660:58660 +0.00011266336187471834 55698:55698 +0.00011266336187471834 34721:34721 +0.00011266336187471834 60544:60544 +0.00011266336187471834 35060:35060 +0.00011266336187471834 60923:60923 +0.00011266336187471834 57857:57857 +0.00011266336187471834 33087:33087 +0.00011266336187471834 32936:32936 +0.00011266336187471834 58327:58327 +0.00011266336187471834 58346:58346 +0.00011266336187471834 58764:58764 +0.00011266336187471834 60600:60600 +0.00011266336187471834 33433:33433 +0.00011266336187471834 59498:59498 +0.00011266336187471834 59084:59084 +0.00011266336187471834 57756:57756 +0.00011266336187471834 33860:33860 +0.00011266336187471834 59936:59936 +0.00011266336187471834 57281:57281 +0.00011266336187471834 35327:35327 +0.00011266336187471834 34889:34889 +0.00011266336187471834 60391:60391 +0.00011266336187471834 33980:33980 +0.00011266336187471834 60610:60610 +0.00011266336187471834 57636:57636 +0.00011266336187471834 59621:59621 +0.00011266336187471834 34060:34060 +0.00011266336187471834 59072:59072 +0.00011266336187471834 57577:57577 +0.00011266336187471834 60177:60177 +0.00011266336187471834 56615:56615 +0.00011266336187471834 33225:33225 +0.00011266336187471834 58529:58529 +0.00011266336187471834 57865:57865 +0.00011266336187471834 34199:34199 +0.00011266336187471834 57933:57933 +0.00011266336187471834 57638:57638 +0.00011266336187471834 57699:57699 +0.00011266336187471834 34863:34863 +0.00011266336187471834 58962:58962 +0.00011266336187471834 55626:55626 +0.00011266336187471834 58491:58491 +0.00011266336187471834 56432:56432 +0.00011266336187471834 34951:34951 +0.00011266336187471834 59186:59186 +0.00011266336187471834 57778:57778 +0.00011266336187471834 35423:35423 +0.00011266336187471834 55820:55820 +0.00011266336187471834 60205:60205 +0.00011266336187471834 34080:34080 +0.00011266336187471834 35549:35549 +0.00011266336187471834 60382:60382 +0.00011266336187471834 59599:59599 +0.00011266336187471834 34855:34855 +0.00011266336187471834 33892:33892 +0.00011266336187471834 60898:60898 +0.00011266336187471834 57431:57431 +0.00011266336187471834 56098:56098 +0.00011266336187471834 59014:59014 +0.00011266336187471834 57317:57317 +0.00011266336187471834 56490:56490 +0.00011266336187471834 57559:57559 +0.00011266336187471834 58897:58897 +0.00011266336187471834 58014:58014 +0.00011266336187471834 58069:58069 +0.00011266336187471834 35455:35455 +0.00011266336187471834 56811:56811 +0.00011266336187471834 59721:59721 +0.00011266336187471834 33011:33011 +0.00011266336187471834 34688:34688 +0.00011266336187471834 56195:56195 +0.00011266336187471834 58226:58226 +0.00011266336187471834 35532:35532 +0.00011266336187471834 33920:33920 +0.00011266336187471834 58071:58071 +0.00011266336187471834 56752:56752 +0.00011266336187471834 60635:60635 +0.00011266336187471834 59396:59396 +0.00011266336187471834 55834:55834 +0.00011266336187471834 58615:58615 +0.00011266336187471834 56499:56499 +0.00011266336187471834 59263:59263 +0.00011266336187471834 56541:56541 +0.00011266336187471834 60831:60831 +0.00011266336187471834 33516:33516 +0.00011266336187471834 56561:56561 +0.00011266336187471834 59689:59689 +0.00011266336187471834 55848:55848 +0.00011266336187471834 59268:59268 +0.00011266336187471834 58034:58034 +0.00011266336187471834 56943:56943 +0.00011266336187471834 56429:56429 +0.00011266336187471834 57243:57243 +0.00011266336187471834 57722:57722 +0.00011266336187471834 58875:58875 +0.00011266336187471834 57207:57207 +0.00011266336187471834 35096:35096 +0.00011266336187471834 35002:35002 +0.00011266336187471834 34659:34659 +0.00011266336187471834 58941:58941 +0.00011266336187471834 57238:57238 +0.00011266336187471834 60739:60739 +0.00011266336187471834 58420:58420 +0.00011266336187471834 59439:59439 +0.00011266336187471834 60195:60195 +0.00011266336187471834 58004:58004 +0.00011266336187471834 57950:57950 +0.00011266336187471834 58059:58059 +0.00011266336187471834 56867:56867 +0.00011266336187471834 55629:55629 +0.00011266336187471834 56852:56852 +0.00011266336187471834 55832:55832 +0.00011266336187471834 59565:59565 +0.00011266336187471834 33802:33802 +0.00011266336187471834 58338:58338 +0.00011266336187471834 56762:56762 +0.00011266336187471834 34388:34388 +0.00011266336187471834 58457:58457 +0.00011266336187471834 34134:34134 +0.00011266336187471834 34499:34499 +0.00011266336187471834 59459:59459 +0.00011266336187471834 59005:59005 +0.00011266336187471834 56754:56754 +0.00011266336187471834 34430:34430 +0.00011266336187471834 35534:35534 +0.00011266336187471834 56325:56325 +0.00011266336187471834 34698:34698 +0.00011266336187471834 60112:60112 +0.00011266336187471834 58244:58244 +0.00011266336187471834 35343:35343 +0.00011266336187471834 34266:34266 +0.00011266336187471834 33696:33696 +0.00011266336187471834 55947:55947 +0.00011266336187471834 35479:35479 +0.00011266336187471834 56692:56692 +0.00011266336187471834 56500:56500 +0.00011266336187471834 33156:33156 +0.00011266336187471834 59818:59818 +0.00011266336187471834 58543:58543 +0.00011266336187471834 33558:33558 +0.00011266336187471834 34695:34695 +0.00011266336187471834 58281:58281 +0.00011266336187471834 58122:58122 +0.00011266336187471834 57006:57006 +0.00011266336187471834 35348:35348 +0.00011266336187471834 34419:34419 +0.00011266336187471834 60547:60547 +0.00011266336187471834 59422:59422 +0.00011266336187471834 57419:57419 +0.00011266336187471834 57809:57809 +0.00011266336187471834 57160:57160 +0.00011266336187471834 56419:56419 +0.00011266336187471834 59484:59484 +0.00011266336187471834 57435:57435 +0.00011266336187471834 60469:60469 +0.00011266336187471834 55683:55683 +0.00011266336187471834 60649:60649 +0.00011266336187471834 33383:33383 +0.00011266336187471834 59020:59020 +0.00011266336187471834 33411:33411 +0.00011266336187471834 33119:33119 +0.00011266336187471834 60016:60016 +0.00011266336187471834 58129:58129 +0.00011266336187471834 34991:34991 +0.00011266336187471834 59693:59693 +0.00011266336187471834 57557:57557 +0.00011266336187471834 56383:56383 +0.00011266336187471834 58607:58607 +0.00011266336187471834 59066:59066 +0.00011266336187471834 59555:59555 +0.00011266336187471834 56914:56914 +0.00011266336187471834 33732:33732 +0.00011266336187471834 33379:33379 +0.00011266336187471834 58642:58642 +0.00011266336187471834 57234:57234 +0.00011266336187471834 57752:57752 +0.00011266336187471834 58349:58349 +0.00011266336187471834 59658:59658 +0.00011266336187471834 59473:59473 +0.00011266336187471834 58899:58899 +0.00011266336187471834 56520:56520 +0.00011266336187471834 60725:60725 +0.00011266336187471834 56662:56662 +0.00011266336187471834 34503:34503 +0.00011266336187471834 35125:35125 +0.00011266336187471834 60010:60010 +0.00011266336187471834 58922:58922 +0.00011266336187471834 57918:57918 +0.00011266336187471834 58864:58864 +0.00011266336187471834 57176:57176 +0.00011266336187471834 35384:35384 +0.00011266336187471834 34926:34926 +0.00011266336187471834 59922:59922 +0.00011266336187471834 60537:60537 +0.00011266336187471834 33812:33812 +0.00011266336187471834 56588:56588 +0.00011266336187471834 56577:56577 +0.00011266336187471834 35550:35550 +0.00011266336187471834 57169:57169 +0.00011266336187471834 56807:56807 +0.00011266336187471834 34739:34739 +0.00011266336187471834 33010:33010 +0.00011266336187471834 60983:60983 +0.00011266336187471834 59928:59928 +0.00011266336187471834 33684:33684 +0.00011266336187471834 60568:60568 +0.00011266336187471834 58503:58503 +0.00011266336187471834 59048:59048 +0.00011266336187471834 57642:57642 +0.00011266336187471834 60322:60322 +0.00011266336187471834 58440:58440 +0.00011266336187471834 35191:35191 +0.00011266336187471834 33007:33007 +0.00011266336187471834 58490:58490 +0.00011266336187471834 35498:35498 +0.00011266336187471834 33245:33245 +0.00011266336187471834 35336:35336 +0.00011266336187471834 59875:59875 +0.00011266336187471834 56064:56064 +0.00011266336187471834 59334:59334 +0.00011266336187471834 32973:32973 +0.00011266336187471834 57520:57520 +0.00011266336187471834 33502:33502 +0.00011266336187471834 59070:59070 +0.00011266336187471834 35177:35177 +0.00011266336187471834 33014:33014 +0.00011266336187471834 56534:56534 +0.00011266336187471834 34524:34524 +0.00011266336187471834 33049:33049 +0.00011266336187471834 60460:60460 +0.00011266336187471834 59328:59328 +0.00011266336187471834 60754:60754 +0.00011266336187471834 35499:35499 +0.00011266336187471834 33116:33116 +0.00011266336187471834 59385:59385 +0.00011266336187471834 56211:56211 +0.00011266336187471834 33606:33606 +0.00011266336187471834 59515:59515 +0.00011266336187471834 34123:34123 +0.00011266336187471834 58688:58688 +0.00011266336187471834 58446:58446 +0.00011266336187471834 59296:59296 +0.00011266336187471834 60069:60069 +0.00011266336187471834 59097:59097 +0.00011266336187471834 59000:59000 +0.00011266336187471834 59437:59437 +0.00011266336187471834 33570:33570 +0.00011266336187471834 59221:59221 +0.00011266336187471834 59081:59081 +0.00011266336187471834 58886:58886 +0.00011266336187471834 34812:34812 +0.00011266336187471834 60648:60648 +0.00011266336187471834 56689:56689 +0.00011266336187471834 32954:32954 +0.00011266336187471834 57981:57981 +0.00011266336187471834 56843:56843 +0.00011266336187471834 35320:35320 +0.00011266336187471834 56637:56637 +0.00011266336187471834 55751:55751 +0.00011266336187471834 56019:56019 +0.00011266336187471834 35205:35205 +0.00011266336187471834 57997:57997 +0.00011266336187471834 59059:59059 +0.00011266336187471834 58341:58341 +0.00011266336187471834 35425:35425 +0.00011266336187471834 57077:57077 +0.00011266336187471834 56801:56801 +0.00011266336187471834 60902:60902 +0.00011266336187471834 57613:57613 +0.00011266336187471834 33757:33757 +0.00011266336187471834 60372:60372 +0.00011266336187471834 58982:58982 +0.00011266336187471834 55768:55768 +0.00011266336187471834 33632:33632 +0.00011266336187471834 59905:59905 +0.00011266336187471834 59121:59121 +0.00011266336187471834 55748:55748 +0.00011266336187471834 33704:33704 +0.00011266336187471834 34387:34387 +0.00011266336187471834 60676:60676 +0.00011266336187471834 35507:35507 +0.00011266336187471834 56368:56368 +0.00011266336187471834 56170:56170 +0.00011266336187471834 60468:60468 +0.00011266336187471834 60032:60032 +0.00011266336187471834 56177:56177 +0.00011266336187471834 56185:56185 +0.00011266336187471834 34449:34449 +0.00011266336187471834 56356:56356 +0.00011266336187471834 34764:34764 +0.00011266336187471834 58057:58057 +0.00011266336187471834 55860:55860 +0.00011266336187471834 60357:60357 +0.00011266336187471834 55633:55633 +0.00011266336187471834 55776:55776 +0.00011266336187471834 60847:60847 +0.00011266336187471834 34670:34670 +0.00011266336187471834 60199:60199 +0.00011266336187471834 56580:56580 +0.00011266336187471834 35075:35075 +0.00011266336187471834 55870:55870 +0.00011266336187471834 57739:57739 +0.00011266336187471834 60044:60044 +0.00011266336187471834 33296:33296 +0.00011266336187471834 59324:59324 +0.00011266336187471834 32888:32888 +0.00011266336187471834 33556:33556 +0.00011266336187471834 60942:60942 +0.00011266336187471834 59304:59304 +0.00011266336187471834 57179:57179 +0.00011266336187471834 33782:33782 +0.00011266336187471834 35325:35325 +0.00011266336187471834 33990:33990 +0.00011266336187471834 56030:56030 +0.00011266336187471834 33744:33744 +0.00011266336187471834 59630:59630 +0.00011266336187471834 34682:34682 +0.00011266336187471834 35121:35121 +0.00011266336187471834 33785:33785 +0.00011266336187471834 58339:58339 +0.00011266336187471834 33845:33845 +0.00011266336187471834 59114:59114 +0.00011266336187471834 57935:57935 +0.00011266336187471834 59724:59724 +0.00011266336187471834 59378:59378 +0.00011266336187471834 59289:59289 +0.00011266336187471834 58783:58783 +0.00011266336187471834 58825:58825 +0.00011266336187471834 58105:58105 +0.00011266336187471834 33890:33890 +0.00011266336187471834 57089:57089 +0.00011266336187471834 59025:59025 +0.00011266336187471834 56046:56046 +0.00011266336187471834 56861:56861 +0.00011266336187471834 58150:58150 +0.00011266336187471834 60699:60699 +0.00011266336187471834 58007:58007 +0.00011266336187471834 34623:34623 +0.00011266336187471834 33032:33032 +0.00011266336187471834 60164:60164 +0.00011266336187471834 33720:33720 +0.00011266336187471834 59051:59051 +0.00011266336187471834 60036:60036 +0.00011266336187471834 56385:56385 +0.00011266336187471834 59399:59399 +0.00011266336187471834 58156:58156 +0.00011266336187471834 57666:57666 +0.00011266336187471834 56683:56683 +0.00011266336187471834 60040:60040 +0.00011266336187471834 33385:33385 +0.00011266336187471834 59227:59227 +0.00011266336187471834 56148:56148 +0.00011266336187471834 34872:34872 +0.00011266336187471834 34193:34193 +0.00011266336187471834 59919:59919 +0.00011266336187471834 58022:58022 +0.00011266336187471834 59398:59398 +0.00011266336187471834 32848:32848 +0.00011266336187471834 60167:60167 +0.00011266336187471834 59532:59532 +0.00011266336187471834 33506:33506 +0.00011266336187471834 34686:34686 +0.00011266336187471834 59355:59355 +0.00011266336187471834 56156:56156 +0.00011266336187471834 60019:60019 +0.00011266336187471834 58093:58093 +0.00011266336187471834 57684:57684 +0.00011266336187471834 34035:34035 +0.00011266336187471834 60376:60376 +0.00011266336187471834 59681:59681 +0.00011266336187471834 34391:34391 +0.00011266336187471834 59140:59140 +0.00011266336187471834 55682:55682 +0.00011266336187471834 57022:57022 +0.00011266336187471834 56188:56188 +0.00011266336187471834 34165:34165 +0.00011266336187471834 56651:56651 +0.00011266336187471834 57172:57172 +0.00011266336187471834 32823:32823 +0.00011266336187471834 58117:58117 +0.00011266336187471834 58972:58972 +0.00011266336187471834 56631:56631 +0.00011266336187471834 55618:55618 +0.00011266336187471834 32816:32816 +0.00011266336187471834 34709:34709 +0.00011266336187471834 58633:58633 +0.00011266336187471834 34329:34329 +0.00011266336187471834 58354:58354 +0.00011266336187471834 55980:55980 +0.00011266336187471834 55904:55904 +0.00011266336187471834 34570:34570 +0.00011266336187471834 59824:59824 +0.00011266336187471834 59679:59679 +0.00011266336187471834 56029:56029 +0.00011266336187471834 58328:58328 +0.00011266336187471834 34930:34930 +0.00011266336187471834 34868:34868 +0.00011266336187471834 33843:33843 +0.00011266336187471834 59634:59634 +0.00011266336187471834 59360:59360 +0.00011266336187471834 35280:35280 +0.00011266336187471834 58620:58620 +0.00011266336187471834 34275:34275 +0.00011266336187471834 59440:59440 +0.00011266336187471834 58003:58003 +0.00011266336187471834 33050:33050 +0.00011266336187471834 34785:34785 +0.00011266336187471834 33205:33205 +0.00011266336187471834 56923:56923 +0.00011266336187471834 35178:35178 +0.00011266336187471834 34279:34279 +0.00011266336187471834 34258:34258 +0.00011266336187471834 33179:33179 +0.00011266336187471834 56544:56544 +0.00011266336187471834 59148:59148 +0.00011266336187471834 35503:35503 +0.00011266336187471834 60209:60209 +0.00011266336187471834 58074:58074 +0.00011266336187471834 57049:57049 +0.00011266336187471834 59645:59645 +0.00011266336187471834 60816:60816 +0.00011266336187471834 60018:60018 +0.00011266336187471834 57515:57515 +0.00011266336187471834 32903:32903 +0.00011266336187471834 60551:60551 +0.00011266336187471834 33442:33442 +0.00011266336187471834 33904:33904 +0.00011266336187471834 60824:60824 +0.00011266336187471834 60063:60063 +0.00011266336187471834 59820:59820 +0.00011266336187471834 33698:33698 +0.00011266336187471834 56596:56596 +0.00011266336187471834 60110:60110 +0.00011266336187471834 35426:35426 +0.00011266336187471834 56895:56895 +0.00011266336187471834 33960:33960 +0.00011266336187471834 33106:33106 +0.00011266336187471834 56882:56882 +0.00011266336187471834 59122:59122 +0.00011266336187471834 32960:32960 +0.00011266336187471834 56738:56738 +0.00011266336187471834 60704:60704 +0.00011266336187471834 60009:60009 +0.00011266336187471834 59053:59053 +0.00011266336187471834 32965:32965 +0.00011266336187471834 57966:57966 +0.00011266336187471834 55767:55767 +0.00011266336187471834 60833:60833 +0.00011266336187471834 60545:60545 +0.00011266336187471834 35341:35341 +0.00011266336187471834 58508:58508 +0.00011266336187471834 58342:58342 +0.00011266336187471834 33882:33882 +0.00011266336187471834 33711:33711 +0.00011266336187471834 56787:56787 +0.00011266336187471834 35019:35019 +0.00011266336187471834 33454:33454 +0.00011266336187471834 60280:60280 +0.00011266336187471834 56685:56685 +0.00011266336187471834 60029:60029 +0.00011266336187471834 60716:60716 +0.00011266336187471834 33192:33192 +0.00011266336187471834 33498:33498 +0.00011266336187471834 58029:58029 +0.00011266336187471834 59941:59941 +0.00011266336187471834 35142:35142 +0.00011266336187471834 33036:33036 +0.00011266336187471834 60924:60924 +0.00011266336187471834 58782:58782 +0.00011266336187471834 56392:56392 +0.00011266336187471834 59589:59589 +0.00011266336187471834 57633:57633 +0.00011266336187471834 57101:57101 +0.00011266336187471834 34253:34253 +0.00011266336187471834 34556:34556 +0.00011266336187471834 60082:60082 +0.00011266336187471834 33717:33717 +0.00011266336187471834 58894:58894 +0.00011266336187471834 55658:55658 +0.00011266336187471834 55931:55931 +0.00011266336187471834 60450:60450 +0.00011266336187471834 56736:56736 +0.00011266336187471834 55714:55714 +0.00011266336187471834 34699:34699 +0.00011266336187471834 60960:60960 +0.00011266336187471834 33679:33679 +0.00011266336187471834 60689:60689 +0.00011266336187471834 35087:35087 +0.00011266336187471834 60302:60302 +0.00011266336187471834 59490:59490 +0.00011266336187471834 56150:56150 +0.00011266336187471834 59971:59971 +0.00011266336187471834 34124:34124 +0.00011266336187471834 58857:58857 +0.00011266336187471834 57443:57443 +0.00011266336187471834 32943:32943 +0.00011266336187471834 60272:60272 +0.00011266336187471834 60972:60972 +0.00011266336187471834 58765:58765 +0.00011266336187471834 32849:32849 +0.00011266336187471834 32854:32854 +0.00011266336187471834 33712:33712 +0.00011266336187471834 56614:56614 +0.00011266336187471834 56223:56223 +0.00011266336187471834 35487:35487 +0.00011266336187471834 59223:59223 +0.00011266336187471834 56389:56389 +0.00011266336187471834 35510:35510 +0.00011266336187471834 34870:34870 +0.00011266336187471834 56372:56372 +0.00011266336187471834 34519:34519 +0.00011266336187471834 33267:33267 +0.00011266336187471834 57616:57616 +0.00011266336187471834 56820:56820 +0.00011266336187471834 59625:59625 +0.00011266336187471834 58537:58537 +0.00011266336187471834 59259:59259 +0.00011266336187471834 33531:33531 +0.00011266336187471834 59553:59553 +0.00011266336187471834 60601:60601 +0.00011266336187471834 56261:56261 +0.00011266336187471834 57420:57420 +0.00011266336187471834 58907:58907 +0.00011266336187471834 57996:57996 +0.00011266336187471834 56640:56640 +0.00011266336187471834 57921:57921 +0.00011266336187471834 56623:56623 +0.00011266336187471834 60403:60403 +0.00011266336187471834 58832:58832 +0.00011266336187471834 58818:58818 +0.00011266336187471834 60827:60827 +0.00011266336187471834 57411:57411 +0.00011266336187471834 35512:35512 +0.00011266336187471834 60454:60454 +0.00011266336187471834 34666:34666 +0.00011266336187471834 33505:33505 +0.00011266336187471834 57827:57827 +0.00011266336187471834 57451:57451 +0.00011266336187471834 32891:32891 +0.00011266336187471834 34936:34936 +0.00011266336187471834 60742:60742 +0.00011266336187471834 58213:58213 +0.00011266336187471834 56092:56092 +0.00011266336187471834 60896:60896 +0.00011266336187471834 58177:58177 +0.00011266336187471834 34831:34831 +0.00011266336187471834 59157:59157 +0.00011266336187471834 57250:57250 +0.00011266336187471834 56812:56812 +0.00011266336187471834 55869:55869 +0.00011266336187471834 35383:35383 +0.00011266336187471834 58852:58852 +0.00011266336187471834 59654:59654 +0.00011266336187471834 57563:57563 +0.00011266336187471834 33220:33220 +0.00011266336187471834 59258:59258 +0.00011266336187471834 57749:57749 +0.00011266336187471834 57309:57309 +0.00011266336187471834 57057:57057 +0.00011266336187471834 34849:34849 +0.00011266336187471834 56416:56416 +0.00011266336187471834 35251:35251 +0.00011266336187471834 33611:33611 +0.00011266336187471834 58565:58565 +0.00011266336187471834 55890:55890 +0.00011266336187471834 35446:35446 +0.00011266336187471834 33093:33093 +0.00011266336187471834 56282:56282 +0.00011266336187471834 35120:35120 +0.00011266336187471834 33590:33590 +0.00011266336187471834 33214:33214 +0.00011266336187471834 33108:33108 +0.00011266336187471834 32985:32985 +0.00011266336187471834 60652:60652 +0.00011266336187471834 34691:34691 +0.00011266336187471834 34448:34448 +0.00011266336187471834 34421:34421 +0.00011266336187471834 58399:58399 +0.00011266336187471834 34172:34172 +0.00011266336187471834 60682:60682 +0.00011266336187471834 34885:34885 +0.00011266336187471834 57159:57159 +0.00011266336187471834 35052:35052 +0.00011266336187471834 34267:34267 +0.00011266336187471834 33813:33813 +0.00011266336187471834 34515:34515 +0.00011266336187471834 60035:60035 +0.00011266336187471834 58663:58663 +0.00011266336187471834 34131:34131 +0.00011266336187471834 55910:55910 +0.00011266336187471834 60989:60989 +0.00011266336187471834 32982:32982 +0.00011266336187471834 59286:59286 +0.00011266336187471834 35160:35160 +0.00011266336187471834 33626:33626 +0.00011266336187471834 59929:59929 +0.00011266336187471834 59611:59611 +0.00011266336187471834 60227:60227 +0.00011266336187471834 34036:34036 +0.00011266336187471834 33544:33544 +0.00011266336187471834 33977:33977 +0.00011266336187471834 57582:57582 +0.00011266336187471834 55826:55826 +0.00011266336187471834 58845:58845 +0.00011266336187471834 33472:33472 +0.00011266336187471834 34082:34082 +0.00011266336187471834 57360:57360 +0.00011266336187471834 35508:35508 +0.00011266336187471834 60587:60587 +0.00011266336187471834 59575:59575 +0.00011266336187471834 33685:33685 +0.00011266336187471834 60472:60472 +0.00011266336187471834 60201:60201 +0.00011266336187471834 59997:59997 +0.00011266336187471834 59368:59368 +0.00011266336187471834 56004:56004 +0.00011266336187471834 59807:59807 +0.00011266336187471834 55645:55645 +0.00011266336187471834 56431:56431 +0.00011266336187471834 58898:58898 +0.00011266336187471834 57943:57943 +0.00011266336187471834 33791:33791 +0.00011266336187471834 57184:57184 +0.00011266336187471834 56804:56804 +0.00011266336187471834 33004:33004 +0.00011266336187471834 35452:35452 +0.00011266336187471834 60301:60301 +0.00011266336187471834 35009:35009 +0.00011266336187471834 60873:60873 +0.00011266336187471834 34183:34183 +0.00011266336187471834 33953:33953 +0.00011266336187471834 58916:58916 +0.00011266336187471834 60709:60709 +0.00011266336187471834 60003:60003 +0.00011266336187471834 57627:57627 +0.00011266336187471834 33167:33167 +0.00011266336187471834 33324:33324 +0.00011266336187471834 56460:56460 +0.00011266336187471834 59288:59288 +0.00011266336187471834 55802:55802 +0.00011266336187471834 34184:34184 +0.00011266336187471834 56298:56298 +0.00011266336187471834 33094:33094 +0.00011266336187471834 57389:57389 +0.00011266336187471834 34255:34255 +0.00011266336187471834 58368:58368 +0.00011266336187471834 57800:57800 +0.00011266336187471834 58335:58335 +0.00011266336187471834 59881:59881 +0.00011266336187471834 59423:59423 +0.00011266336187471834 59242:59242 +0.00011266336187471834 60548:60548 +0.00011266336187471834 57385:57385 +0.00011266336187471834 60169:60169 +0.00011266336187471834 60970:60970 +0.00011266336187471834 59595:59595 +0.00011266336187471834 56215:56215 +0.00011266336187471834 34546:34546 +0.00011266336187471834 33876:33876 +0.00011266336187471834 55902:55902 +0.00011266336187471834 33182:33182 +0.00011266336187471834 59341:59341 +0.00011266336187471834 58310:58310 +0.00011266336187471834 58545:58545 +0.00011266336187471834 34676:34676 +0.00011266336187471834 33605:33605 +0.00011266336187471834 849:849 +0.00011266336187471834 55664:55664 +0.00011266336187471834 60499:60499 +0.00011266336187471834 33923:33923 +0.00011266336187471834 56657:56657 +0.00011266336187471834 32910:32910 +0.00011266336187471834 59584:59584 +0.00011266336187471834 33577:33577 +0.00011266336187471834 60868:60868 +0.00011266336187471834 59199:59199 +0.00011266336187471834 33955:33955 +0.00011266336187471834 57037:57037 +0.00011266336187471834 60966:60966 +0.00011266336187471834 59478:59478 +0.00011266336187471834 56119:56119 +0.00011266336187471834 35007:35007 +0.00011266336187471834 57701:57701 +0.00011266336187471834 57062:57062 +0.00011266336187471834 60398:60398 +0.00011266336187471834 56813:56813 +0.00011266336187471834 35458:35458 +0.00011266336187471834 35433:35433 +0.00011266336187471834 55636:55636 +0.00011266336187471834 33630:33630 +0.00011266336187471834 59464:59464 +0.00011266336187471834 33290:33290 +0.00011266336187471834 59458:59458 +0.00011266336187471834 59075:59075 +0.00011266336187471834 60732:60732 +0.00011266336187471834 60281:60281 +0.00011266336187471834 55933:55933 +0.00011266336187471834 35342:35342 +0.00011266336187471834 57391:57391 +0.00011266336187471834 34441:34441 +0.00011266336187471834 60334:60334 +0.00011266336187471834 56197:56197 +0.00011266336187471834 32904:32904 +0.00011266336187471834 59078:59078 +0.00011266336187471834 60366:60366 +0.00011266336187471834 56835:56835 +0.00011266336187471834 34001:34001 +0.00011266336187471834 33076:33076 +0.00011266336187471834 59892:59892 +0.00011266336187471834 34135:34135 +0.00011266336187471834 60770:60770 +0.00011266336187471834 35095:35095 +0.00011266336187471834 34969:34969 +0.00011266336187471834 55724:55724 +0.00011266336187471834 34145:34145 +0.00011266336187471834 33943:33943 +0.00011266336187471834 55912:55912 +0.00011266336187471834 35187:35187 +0.00011266336187471834 33337:33337 +0.00011266336187471834 34997:34997 +0.00011266336187471834 57626:57626 +0.00011266336187471834 57168:57168 +0.00011266336187471834 58834:58834 +0.00011266336187471834 55942:55942 +0.00011266336187471834 57365:57365 +0.00011266336187471834 60914:60914 +0.00011266336187471834 34593:34593 +0.00011266336187471834 58800:58800 +0.00011266336187471834 57522:57522 +0.00011266336187471834 57011:57011 +0.00011266336187471834 59566:59566 +0.00011266336187471834 35173:35173 +0.00011266336187471834 34681:34681 +0.00011266336187471834 56590:56590 +0.00011266336187471834 33857:33857 +0.00011266336187471834 59708:59708 +0.00011266336187471834 33755:33755 +0.00011266336187471834 32827:32827 +0.00011266336187471834 59414:59414 +0.00011266336187471834 57336:57336 +0.00011266336187471834 33458:33458 +0.00011266336187471834 60720:60720 +0.00011266336187471834 34285:34285 +0.00011266336187471834 33999:33999 +0.00011266336187471834 32956:32956 +0.00011266336187471834 58251:58251 +0.00011266336187471834 56890:56890 +0.00011266336187471834 58431:58431 +0.00011266336187471834 33298:33298 +0.00011266336187471834 56805:56805 +0.00011266336187471834 55888:55888 +0.00011266336187471834 57629:57629 +0.00011266336187471834 33110:33110 +0.00011266336187471834 56846:56846 +0.00011266336187471834 60387:60387 +0.00011266336187471834 59149:59149 +0.00011266336187471834 56792:56792 +0.00011266336187471834 55688:55688 +0.00011266336187471834 33445:33445 +0.00011266336187471834 33180:33180 +0.00011266336187471834 59158:59158 +0.00011266336187471834 58961:58961 +0.00011266336187471834 56094:56094 +0.00011266336187471834 59939:59939 +0.00011266336187471834 57024:57024 +0.00011266336187471834 56739:56739 +0.00011266336187471834 59970:59970 +0.00011266336187471834 55729:55729 +0.00011266336187471834 56865:56865 +0.00011266336187471834 60022:60022 +0.00011266336187471834 57861:57861 +0.00011266336187471834 56067:56067 +0.00011266336187471834 34548:34548 +0.00011266336187471834 33729:33729 +0.00011266336187471834 57452:57452 +0.00011266336187471834 56896:56896 +0.00011266336187471834 58946:58946 +0.00011266336187471834 56700:56700 +0.00011266336187471834 57278:57278 +0.00011266336187471834 60838:60838 +0.00011266336187471834 60715:60715 +0.00011266336187471834 35289:35289 +0.00011266336187471834 35515:35515 +0.00011266336187471834 33998:33998 +0.00011266336187471834 34989:34989 +0.00011266336187471834 59383:59383 +0.00011266336187471834 59306:59306 +0.00011266336187471834 57346:57346 +0.00011266336187471834 55702:55702 +0.00011266336187471834 34811:34811 +0.00011266336187471834 56371:56371 +0.00011266336187471834 34446:34446 +0.00011266336187471834 33601:33601 +0.00011266336187471834 57321:57321 +0.00011266336187471834 60000:60000 +0.00011266336187471834 56003:56003 +0.00011266336187471834 57012:57012 +0.00011266336187471834 34037:34037 +0.00011266336187471834 57223:57223 +0.00011266336187471834 34603:34603 +0.00011266336187471834 58658:58658 +0.00011266336187471834 35137:35137 +0.00011266336187471834 59036:59036 +0.00011266336187471834 57615:57615 +0.00011266336187471834 57065:57065 +0.00011266336187471834 59766:59766 +0.00011266336187471834 34303:34303 +0.00011266336187471834 57838:57838 +0.00011266336187471834 35084:35084 +0.00011266336187471834 56229:56229 +0.00011266336187471834 60607:60607 +0.00011266336187471834 59041:59041 +0.00011266336187471834 58881:58881 +0.00011266336187471834 59856:59856 +0.00011266336187471834 59238:59238 +0.00011266336187471834 34506:34506 +0.00011266336187471834 34120:34120 +0.00011266336187471834 55728:55728 +0.00011266336187471834 35017:35017 +0.00011266336187471834 56774:56774 +0.00011266336187471834 60957:60957 +0.00011266336187471834 59896:59896 +0.00011266336187471834 58711:58711 +0.00011266336187471834 60668:60668 +0.00011266336187471834 56169:56169 +0.00011266336187471834 32831:32831 +0.00011266336187471834 60963:60963 +0.00011266336187471834 60360:60360 +0.00011266336187471834 57241:57241 +0.00011266336187471834 59957:59957 +0.00011266336187471834 33552:33552 +0.00011266336187471834 55734:55734 +0.00011266336187471834 33384:33384 +0.00011266336187471834 57070:57070 +0.00011266336187471834 57418:57418 +0.00011266336187471834 57149:57149 +0.00011266336187471834 59735:59735 +0.00011266336187471834 60202:60202 +0.00011266336187471834 34712:34712 +0.00011266336187471834 55685:55685 +0.00011266336187471834 60629:60629 +0.00011266336187471834 57048:57048 +0.00011266336187471834 33089:33089 +0.00011266336187471834 59068:59068 +0.00011266336187471834 59001:59001 +0.00011266336187471834 35193:35193 +0.00011266336187471834 34375:34375 +0.00011266336187471834 56793:56793 +0.00011266336187471834 34108:34108 +0.00011266336187471834 60331:60331 +0.00011266336187471834 59885:59885 +0.00011266336187471834 33037:33037 +0.00011266336187471834 57377:57377 +0.00011266336187471834 56244:56244 +0.00011266336187471834 34211:34211 +0.00011266336187471834 57687:57687 +0.00011266336187471834 59064:59064 +0.00011266336187471834 60655:60655 +0.00011266336187471834 56619:56619 +0.00011266336187471834 57598:57598 +0.00011266336187471834 33620:33620 +0.00011266336187471834 56107:56107 +0.00011266336187471834 59546:59546 +0.00011266336187471834 33459:33459 +0.00011266336187471834 34085:34085 +0.00011266336187471834 60020:60020 +0.00011266336187471834 34304:34304 +0.00011266336187471834 59023:59023 +0.00011266336187471834 57708:57708 +0.00011266336187471834 34883:34883 +0.00011266336187471834 60628:60628 +0.00011266336187471834 59659:59659 +0.00011266336187471834 35086:35086 +0.00011266336187471834 60913:60913 +0.00011266336187471834 58230:58230 +0.00011266336187471834 55615:55615 +0.00011266336187471834 33349:33349 +0.00011266336187471834 56339:56339 +0.00011266336187471834 33835:33835 +0.00011266336187471834 32843:32843 +0.00011266336187471834 34283:34283 +0.00011266336187471834 34062:34062 +0.00011266336187471834 60394:60394 +0.00011266336187471834 58978:58978 +0.00011266336187471834 58732:58732 +0.00011266336187471834 35228:35228 +0.00011266336187471834 60222:60222 +0.00011266336187471834 58826:58826 +0.00011266336187471834 56675:56675 +0.00011266336187471834 33321:33321 +0.00011266336187471834 33306:33306 +0.00011266336187471834 59382:59382 +0.00011266336187471834 59793:59793 +0.00011266336187471834 57828:57828 +0.00011266336187471834 56214:56214 +0.00011266336187471834 34000:34000 +0.00011266336187471834 59741:59741 +0.00011266336187471834 59233:59233 +0.00011266336187471834 57188:57188 +0.00011266336187471834 59747:59747 +0.00011266336187471834 57923:57923 +0.00011266336187471834 57967:57967 +0.00011266336187471834 60938:60938 +0.00011266336187471834 57856:57856 +0.00011266336187471834 34156:34156 +0.00011266336187471834 58418:58418 +0.00011266336187471834 55638:55638 +0.00011266336187471834 33373:33373 +0.00011266336187471834 59435:59435 +0.00011266336187471834 58462:58462 +0.00011266336187471834 59580:59580 +0.00011266336187471834 60535:60535 +0.00011266336187471834 58442:58442 +0.00011266336187471834 57850:57850 +0.00011266336187471834 58224:58224 +0.00011266336187471834 57480:57480 +0.00011266336187471834 58011:58011 +0.00011266336187471834 59700:59700 +0.00011266336187471834 56581:56581 +0.00011266336187471834 60386:60386 +0.00011266336187471834 59485:59485 +0.00011266336187471834 60844:60844 +0.00011266336187471834 60407:60407 +0.00011266336187471834 56715:56715 +0.00011266336187471834 57301:57301 +0.00011266336187471834 34761:34761 +0.00011266336187471834 33913:33913 +0.00011266336187471834 56485:56485 +0.00011266336187471834 60184:60184 +0.00011266336187471834 60946:60946 +0.00011266336187471834 59101:59101 +0.00011266336187471834 57289:57289 +0.00011266336187471834 60317:60317 +0.00011266336187471834 59727:59727 +0.00011266336187471834 32883:32883 +0.00011266336187471834 57803:57803 +0.00011266336187471834 60940:60940 +0.00011266336187471834 59866:59866 +0.00011266336187471834 33721:33721 +0.00011266336187471834 60792:60792 +0.00011266336187471834 59239:59239 +0.00011266336187471834 57675:57675 +0.00011266336187471834 57806:57806 +0.00011266336187471834 56451:56451 +0.00011266336187471834 34055:34055 +0.00011266336187471834 56902:56902 +0.00011266336187471834 60061:60061 +0.00011266336187471834 34751:34751 +0.00011266336187471834 34641:34641 +0.00011266336187471834 58649:58649 +0.00011266336187471834 34757:34757 +0.00011266336187471834 58483:58483 +0.00011266336187471834 33168:33168 +0.00011266336187471834 60662:60662 +0.00011266336187471834 56222:56222 +0.00011266336187471834 35141:35141 +0.00011266336187471834 59166:59166 +0.00011266336187471834 59236:59236 +0.00011266336187471834 60508:60508 +0.00011266336187471834 58585:58585 +0.00011266336187471834 56916:56916 +0.00011266336187471834 59377:59377 +0.00011266336187471834 60908:60908 +0.00011266336187471834 33395:33395 +0.00011266336187471834 58108:58108 +0.00011266336187471834 56718:56718 +0.00011266336187471834 58118:58118 +0.00011266336187471834 59889:59889 +0.00011266336187471834 60726:60726 +0.00011266336187471834 33991:33991 +0.00011266336187471834 58768:58768 +0.00011266336187471834 56884:56884 +0.00011266336187471834 56881:56881 +0.00011266336187471834 35330:35330 +0.00011266336187471834 32890:32890 +0.00011266336187471834 55637:55637 +0.00011266336187471834 33663:33663 +0.00011266336187471834 58441:58441 +0.00011266336187471834 57889:57889 +0.00011266336187471834 33474:33474 +0.00011266336187471834 34940:34940 +0.00011266336187471834 34226:34226 +0.00011266336187471834 60952:60952 +0.00011266336187471834 33354:33354 +0.00011266336187471834 60894:60894 +0.00011266336187471834 57216:57216 +0.00011266336187471834 34525:34525 +0.00011266336187471834 57536:57536 +0.00011266336187471834 32879:32879 +0.00011266336187471834 57095:57095 +0.00011266336187471834 34137:34137 +0.00011266336187471834 34048:34048 +0.00011266336187471834 55924:55924 +0.00011266336187471834 33525:33525 +0.00011266336187471834 34260:34260 +0.00011266336187471834 55701:55701 +0.00011266336187471834 34040:34040 +0.00011266336187471834 59815:59815 +0.00011266336187471834 58950:58950 +0.00011266336187471834 34647:34647 +0.00011266336187471834 34599:34599 +0.00011266336187471834 32932:32932 +0.00011266336187471834 60563:60563 +0.00011266336187471834 56330:56330 +0.00011266336187471834 55944:55944 +0.00011266336187471834 58469:58469 +0.00011266336187471834 35016:35016 +0.00011266336187471834 34960:34960 +0.00011266336187471834 60354:60354 +0.00011266336187471834 56264:56264 +0.00011266336187471834 34051:34051 +0.00011266336187471834 60189:60189 +0.00011266336187471834 57423:57423 +0.00011266336187471834 34861:34861 +0.00011266336187471834 56072:56072 +0.00011266336187471834 35484:35484 +0.00011266336187471834 60620:60620 +0.00011266336187471834 57107:57107 +0.00011266336187471834 32800:32800 +0.00011266336187471834 60447:60447 +0.00011266336187471834 56799:56799 +0.00011266336187471834 59456:59456 +0.00011266336187471834 59293:59293 +0.00011266336187471834 59292:59292 +0.00011266336187471834 35485:35485 +0.00011266336187471834 58103:58103 +0.00011266336187471834 59594:59594 +0.00011266336187471834 57013:57013 +0.00011266336187471834 57178:57178 +0.00011266336187471834 33825:33825 +0.00011266336187471834 59959:59959 +0.00011266336187471834 56199:56199 +0.00011266336187471834 58963:58963 +0.00011266336187471834 35472:35472 +0.00011266336187471834 60168:60168 +0.00011266336187471834 59574:59574 +0.00011266336187471834 57738:57738 +0.00011266336187471834 33629:33629 +0.00011266336187471834 58923:58923 +0.00011266336187471834 59778:59778 +0.00011266336187471834 35097:35097 +0.00011266336187471834 33428:33428 +0.00011266336187471834 60744:60744 +0.00011266336187471834 33793:33793 +0.00011266336187471834 60675:60675 +0.00011266336187471834 34257:34257 +0.00011266336187471834 58456:58456 +0.00011266336187471834 34460:34460 +0.00011266336187471834 33609:33609 +0.00011266336187471834 60231:60231 +0.00011266336187471834 59300:59300 +0.00011266336187471834 59629:59629 +0.00011266336187471834 58367:58367 +0.00011266336187471834 35333:35333 +0.00011266336187471834 33618:33618 +0.00011266336187471834 60613:60613 +0.00011266336187471834 57211:57211 +0.00011266336187471834 60825:60825 +0.00011266336187471834 34875:34875 +0.00011266336187471834 35064:35064 +0.00011266336187471834 35307:35307 +0.00011266336187471834 59200:59200 +0.00011266336187471834 58464:58464 +0.00011266336187471834 57948:57948 +0.00011266336187471834 56174:56174 +0.00011266336187471834 56794:56794 +0.00011266336187471834 55973:55973 +0.00011266336187471834 33436:33436 +0.00011266336187471834 59832:59832 +0.00011266336187471834 35225:35225 +0.00011266336187471834 34961:34961 +0.00011266336187471834 59518:59518 +0.00011266336187471834 55815:55815 +0.00011266336187471834 59252:59252 +0.00011266336187471834 55678:55678 +0.00011266336187471834 34457:34457 +0.00011266336187471834 59154:59154 +0.00011266336187471834 57884:57884 +0.00011266336187471834 56573:56573 +0.00011266336187471834 60603:60603 +0.00011266336187471834 60288:60288 +0.00011266336187471834 33722:33722 +0.00011266336187471834 33331:33331 +0.00011266336187471834 55623:55623 +0.00011266336187471834 35521:35521 +0.00011266336187471834 56968:56968 +0.00011266336187471834 33789:33789 +0.00011266336187471834 56088:56088 +0.00011266336187471834 57280:57280 +0.00011266336187471834 33628:33628 +0.00011266336187471834 33963:33963 +0.00011266336187471834 58715:58715 +0.00011266336187471834 55873:55873 +0.00011266336187471834 34271:34271 +0.00011266336187471834 34539:34539 +0.00011266336187471834 33247:33247 +0.00011266336187471834 56709:56709 +0.00011266336187471834 56680:56680 +0.00011266336187471834 60664:60664 +0.00011266336187471834 55619:55619 +0.00011266336187471834 56687:56687 +0.00011266336187471834 60711:60711 +0.00011266336187471834 60517:60517 +0.00011266336187471834 33065:33065 +0.00011266336187471834 33488:33488 +0.00011266336187471834 56858:56858 +0.00011266336187471834 33496:33496 +0.00011266336187471834 58278:58278 +0.00011266336187471834 33041:33041 +0.00011266336187471834 58933:58933 +0.00011266336187471834 58216:58216 +0.00011266336187471834 56393:56393 +0.00011266336187471834 58181:58181 +0.00011266336187471834 55909:55909 +0.00011266336187471834 32814:32814 +0.00011266336187471834 60388:60388 +0.00011266336187471834 33211:33211 +0.00011266336187471834 60582:60582 +0.00011266336187471834 57855:57855 +0.00011266336187471834 56937:56937 +0.00011266336187471834 34407:34407 +0.00011266336187471834 59284:59284 +0.00011266336187471834 60490:60490 +0.00011266336187471834 58632:58632 +0.00011266336187471834 58047:58047 +0.00011266336187471834 57374:57374 +0.00011266336187471834 56027:56027 +0.00011266336187471834 56907:56907 +0.00011266336187471834 59234:59234 +0.00011266336187471834 58685:58685 +0.00011266336187471834 57368:57368 +0.00011266336187471834 58990:58990 +0.00011266336187471834 56422:56422 +0.00011266336187471834 58174:58174 +0.00011266336187471834 33693:33693 +0.00011266336187471834 58119:58119 +0.00011266336187471834 34754:34754 +0.00011266336187471834 56346:56346 +0.00011266336187471834 56146:56146 +0.00011266336187471834 55681:55681 +0.00011266336187471834 33909:33909 +0.00011266336187471834 55791:55791 +0.00011266336187471834 35422:35422 +0.00011266336187471834 57599:57599 +0.00011266336187471834 55794:55794 +0.00011266336187471834 59796:59796 +0.00011266336187471834 56173:56173 +0.00011266336187471834 60406:60406 +0.00011266336187471834 59646:59646 +0.00011266336187471834 33410:33410 +0.00011266336187471834 57649:57649 +0.00011266336187471834 60918:60918 +0.00011266336187471834 60870:60870 +0.00011266336187471834 55613:55613 +0.00011266336187471834 57181:57181 +0.00011266336187471834 35489:35489 +0.00011266336187471834 35124:35124 +0.00011266336187471834 34755:34755 +0.00011266336187471834 35242:35242 +0.00011266336187471834 34079:34079 +0.00011266336187471834 58866:58866 +0.00011266336187471834 55642:55642 +0.00011266336187471834 60338:60338 +0.00011266336187471834 57396:57396 +0.00011266336187471834 33932:33932 +0.00011266336187471834 59853:59853 +0.00011266336187471834 60935:60935 +0.00011266336187471834 34417:34417 +0.00011266336187471834 58246:58246 +0.00011266336187471834 55635:55635 +0.00011266336187471834 35322:35322 +0.00011266336187471834 33281:33281 +0.00011266336187471834 57600:57600 +0.00011266336187471834 34083:34083 +0.00011266336187471834 32918:32918 +0.00011266336187471834 58390:58390 +0.00011266336187471834 60470:60470 +0.00011266336187471834 60318:60318 +0.00011266336187471834 32980:32980 +0.00011266336187471834 57293:57293 +0.00011266336187471834 58393:58393 +0.00011266336187471834 60810:60810 +0.00011266336187471834 56109:56109 +0.00011266336187471834 55855:55855 +0.00011266336187471834 59990:59990 +0.00011266336187471834 34068:34068 +0.00011266336187471834 60415:60415 +0.00011266336187471834 57564:57564 +0.00011266336187471834 33944:33944 +0.00011266336187471834 56609:56609 +0.00011266336187471834 34238:34238 +0.00011266336187471834 57460:57460 +0.00011266336187471834 35481:35481 +0.00011266336187471834 35202:35202 +0.00011266336187471834 34262:34262 +0.00011266336187471834 59069:59069 +0.00011266336187471834 34103:34103 +0.00011266336187471834 59192:59192 +0.00011266336187471834 33369:33369 +0.00011266336187471834 34091:34091 +0.00011266336187471834 60131:60131 +0.00011266336187471834 60961:60961 +0.00011266336187471834 59491:59491 +0.00011266336187471834 57492:57492 +0.00011266336187471834 56665:56665 +0.00011266336187471834 57137:57137 +0.00011266336187471834 55823:55823 +0.00011266336187471834 58193:58193 +0.00011266336187471834 34909:34909 +0.00011266336187471834 60622:60622 +0.00011266336187471834 34274:34274 +0.00011266336187471834 32946:32946 +0.00011266336187471834 58517:58517 +0.00011266336187471834 56078:56078 +0.00011266336187471834 35241:35241 +0.00011266336187471834 59858:59858 +0.00011266336187471834 33588:33588 +0.00011266336187471834 33176:33176 +0.00011266336187471834 59872:59872 +0.00011266336187471834 56767:56767 +0.00011266336187471834 60180:60180 +0.00011266336187471834 58113:58113 +0.00011266336187471834 34434:34434 +0.00011266336187471834 56084:56084 +0.00011266336187471834 57373:57373 +0.00011266336187471834 59336:59336 +0.00011266336187471834 34154:34154 +0.00011266336187471834 59655:59655 +0.00011266336187471834 57723:57723 +0.00011266336187471834 34422:34422 +0.00011266336187471834 57774:57774 +0.00011266336187471834 34844:34844 +0.00011266336187471834 58061:58061 +0.00011266336187471834 58025:58025 +0.00011266336187471834 32863:32863 +0.00011266336187471834 56997:56997 +0.00011266336187471834 56963:56963 +0.00011266336187471834 58705:58705 +0.00011266336187471834 59674:59674 +0.00011266336187471834 58931:58931 +0.00011266336187471834 57092:57092 +0.00011266336187471834 33291:33291 +0.00011266336187471834 59730:59730 +0.00011266336187471834 57673:57673 +0.00011266336187471834 57659:57659 +0.00011266336187471834 34694:34694 +0.00011266336187471834 33568:33568 +0.00011266336187471834 60874:60874 +0.00011266336187471834 33838:33838 +0.00011266336187471834 59319:59319 +0.00011266336187471834 58709:58709 +0.00011266336187471834 55974:55974 +0.00011266336187471834 34288:34288 +0.00011266336187471834 33964:33964 +0.00011266336187471834 59749:59749 +0.00011266336187471834 55692:55692 +0.00011266336187471834 34980:34980 +0.00011266336187471834 58473:58473 +0.00011266336187471834 57922:57922 +0.00011266336187471834 57180:57180 +0.00011266336187471834 34884:34884 +0.00011266336187471834 59784:59784 +0.00011266336187471834 33886:33886 +0.00011266336187471834 33914:33914 +0.00011266336187471834 58920:58920 +0.00011266336187471834 35298:35298 +0.00011266336187471834 60325:60325 +0.00011266336187471834 59582:59582 +0.00011266336187471834 58521:58521 +0.00011266336187471834 58408:58408 +0.00011266336187471834 33429:33429 +0.00011266336187471834 58124:58124 +0.00011266336187471834 55987:55987 +0.00011266336187471834 60974:60974 +0.00011266336187471834 60039:60039 +0.00011266336187471834 57402:57402 +0.00011266336187471834 57284:57284 +0.00011266336187471834 34302:34302 +0.00011266336187471834 33768:33768 +0.00011266336187471834 58816:58816 +0.00011266336187471834 34534:34534 +0.00011266336187471834 56750:56750 +0.00011266336187471834 32824:32824 +0.00011266336187471834 55998:55998 +0.00011266336187471834 55951:55951 +0.00011266336187471834 60313:60313 +0.00011266336187471834 58704:58704 +0.00011266336187471834 57957:57957 +0.00011266336187471834 34806:34806 +0.00011266336187471834 33690:33690 +0.00011266336187471834 55699:55699 +0.00011266336187471834 34582:34582 +0.00011266336187471834 60596:60596 +0.00011266336187471834 55693:55693 +0.00011266336187471834 59504:59504 +0.00011266336187471834 34562:34562 +0.00011266336187471834 60785:60785 +0.00011266336187471834 59380:59380 +0.00011266336187471834 34169:34169 +0.00011266336187471834 55652:55652 +0.00011266336187471834 58589:58589 +0.00011266336187471834 34431:34431 +0.00011266336187471834 59146:59146 +0.00011266336187471834 33716:33716 +0.00011266336187471834 57862:57862 +0.00011266336187471834 57612:57612 +0.00011266336187471834 34820:34820 +0.00011266336187471834 33695:33695 +0.00011266336187471834 60496:60496 +0.00011266336187471834 60428:60428 +0.00011266336187471834 57994:57994 +0.00011266336187471834 33164:33164 +0.00011266336187471834 58050:58050 +0.00011266336187471834 59494:59494 +0.00011266336187471834 32867:32867 +0.00011266336187471834 33849:33849 +0.00011266336187471834 33352:33352 +0.00011266336187471834 57980:57980 +0.00011266336187471834 33193:33193 +0.00011266336187471834 57669:57669 +0.00011266336187471834 34286:34286 +0.00011266336187471834 34750:34750 +0.00011266336187471834 58466:58466 +0.00011266336187471834 56181:56181 +0.00011266336187471834 56182:56182 +0.00011266336187471834 34390:34390 +0.00011266336187471834 56585:56585 +0.00011266336187471834 55719:55719 +0.00011266336187471834 55821:55821 +0.00011266336187471834 59528:59528 +0.00011266336187471834 34899:34899 +0.00011266336187471834 56052:56052 +0.00011266336187471834 34413:34413 +0.00011266336187471834 34097:34097 +0.00011266336187471834 59243:59243 +0.00011266336187471834 34414:34414 +0.00011266336187471834 56800:56800 +0.00011266336187471834 34727:34727 +0.00011266336187471834 34369:34369 +0.00011266336187471834 59438:59438 +0.00011266336187471834 58382:58382 +0.00011266336187471834 34140:34140 +0.00011266336187471834 55986:55986 +0.00011266336187471834 57593:57593 +0.00011266336187471834 55668:55668 +0.00011266336187471834 58533:58533 +0.00011266336187471834 35189:35189 +0.00011266336187471834 35175:35175 +0.00011266336187471834 33660:33660 +0.00011266336187471834 57852:57852 +0.00011266336187471834 55813:55813 +0.00011266336187471834 34409:34409 +0.00011266336187471834 35229:35229 +0.00011266336187471834 33665:33665 +0.00011266336187471834 56751:56751 +0.00011266336187471834 32855:32855 +0.00011266336187471834 57439:57439 +0.00011266336187471834 35334:35334 +0.00011266336187471834 34144:34144 +0.00011266336187471834 56297:56297 +0.00011266336187471834 57398:57398 +0.00011266336187471834 56040:56040 +0.00011266336187471834 58601:58601 +0.00011266336187471834 60395:60395 +0.00011266336187471834 33236:33236 +0.00011266336187471834 57505:57505 +0.00011266336187471834 57471:57471 +0.00011266336187471834 60093:60093 +0.00011266336187471834 55809:55809 +0.00011266336187471834 35273:35273 +0.00011266336187471834 32856:32856 +0.00011266336187471834 34408:34408 +0.00011266336187471834 33586:33586 +0.00011266336187471834 35000:35000 +0.00011266336187471834 33113:33113 +0.00011266336187471834 59467:59467 +0.00011266336187471834 56995:56995 +0.00011266336187471834 56434:56434 +0.00011266336187471834 56344:56344 +0.00011266336187471834 56015:56015 +0.00011266336187471834 60045:60045 +0.00011266336187471834 59859:59859 +0.00011266336187471834 58634:58634 +0.00011266336187471834 34339:34339 +0.00011266336187471834 60096:60096 +0.00011266336187471834 59393:59393 +0.00011266336187471834 35464:35464 +0.00011266336187471834 58677:58677 +0.00011266336187471834 56704:56704 +0.00011266336187471834 56123:56123 +0.00011266336187471834 60884:60884 +0.00011266336187471834 58746:58746 +0.00011266336187471834 60186:60186 +0.00011266336187471834 56604:56604 +0.00011266336187471834 34464:34464 +0.00011266336187471834 34640:34640 +0.00011266336187471834 58833:58833 +0.00011266336187471834 57971:57971 +0.00011266336187471834 56696:56696 +0.00011266336187471834 33030:33030 +0.00011266336187471834 59016:59016 +0.00011266336187471834 33339:33339 +0.00011266336187471834 59888:59888 +0.00011266336187471834 34629:34629 +0.00011266336187471834 60340:60340 +0.00011266336187471834 34628:34628 +0.00011266336187471834 35250:35250 +0.00011266336187471834 59088:59088 +0.00011266336187471834 59833:59833 +0.00011266336187471834 58492:58492 +0.00011266336187471834 35116:35116 +0.00011266336187471834 55840:55840 +0.00011266336187471834 60328:60328 +0.00011266336187471834 59868:59868 +0.00011266336187471834 60680:60680 +0.00011266336187471834 57926:57926 +0.00011266336187471834 34122:34122 +0.00011266336187471834 59049:59049 +0.00011266336187471834 33888:33888 +0.00011266336187471834 33619:33619 +0.00011266336187471834 55806:55806 +0.00011266336187471834 59816:59816 +0.00011266336187471834 33893:33893 +0.00011266336187471834 60678:60678 +0.00011266336187471834 55846:55846 +0.00011266336187471834 34808:34808 +0.00011266336187471834 33967:33967 +0.00011266336187471834 34735:34735 +0.00011266336187471834 59365:59365 +0.00011266336187471834 34847:34847 +0.00011266336187471834 56002:56002 +0.00011266336187471834 33403:33403 +0.00011266336187471834 60702:60702 +0.00011266336187471834 58934:58934 +0.00011266336187471834 57466:57466 +0.00011266336187471834 57035:57035 +0.00011266336187471834 34970:34970 +0.00011266336187471834 59173:59173 +0.00011266336187471834 34514:34514 +0.00011266336187471834 59056:59056 +0.00011266336187471834 34583:34583 +0.00011266336187471834 59495:59495 +0.00011266336187471834 58937:58937 +0.00011266336187471834 56930:56930 +0.00011266336187471834 56001:56001 +0.00011266336187471834 60188:60188 +0.00011266336187471834 59640:59640 +0.00011266336187471834 57352:57352 +0.00011266336187471834 33748:33748 +0.00011266336187471834 33075:33075 +0.00011266336187471834 60343:60343 +0.00011266336187471834 60194:60194 +0.00011266336187471834 35157:35157 +0.00011266336187471834 58168:58168 +0.00011266336187471834 57904:57904 +0.00011266336187471834 34149:34149 +0.00011266336187471834 56130:56130 +0.00011266336187471834 34553:34553 +0.00011266336187471834 58994:58994 +0.00011266336187471834 58170:58170 +0.00011266336187471834 58804:58804 +0.00011266336187471834 59441:59441 +0.00011266336187471834 60686:60686 +0.00011266336187471834 60323:60323 +0.00011266336187471834 57553:57553 +0.00011266336187471834 33376:33376 +0.00011266336187471834 34357:34357 +0.00011266336187471834 34663:34663 +0.00011266336187471834 60165:60165 +0.00011266336187471834 56166:56166 +0.00011266336187471834 34586:34586 +0.00011266336187471834 60813:60813 +0.00011266336187471834 32977:32977 +0.00011266336187471834 33741:33741 +0.00011266336187471834 35013:35013 +0.00011266336187471834 33829:33829 +0.00011266336187471834 59907:59907 +0.00011266336187471834 34444:34444 +0.00011266336187471834 32844:32844 +0.00011266336187471834 56482:56482 +0.00011266336187471834 60383:60383 +0.00011266336187471834 60142:60142 +0.00011266336187471834 55970:55970 +0.00011266336187471834 56443:56443 +0.00011266336187471834 57139:57139 +0.00011266336187471834 35277:35277 +0.00011266336187471834 59220:59220 +0.00011266336187471834 57030:57030 +0.00011266336187471834 57718:57718 +0.00011266336187471834 32922:32922 +0.00011266336187471834 32983:32983 +0.00011266336187471834 58955:58955 +0.00011266336187471834 35046:35046 +0.00011266336187471834 33575:33575 +0.00011266336187471834 33034:33034 +0.00011266336187471834 34771:34771 +0.00011266336187471834 55876:55876 +0.00011266336187471834 56810:56810 +0.00011266336187471834 60067:60067 +0.00011266336187471834 59153:59153 +0.00011266336187471834 56322:56322 +0.00011266336187471834 34410:34410 +0.00011266336187471834 58255:58255 +0.00011266336187471834 33585:33585 +0.00011266336187471834 60047:60047 +0.00011266336187471834 56934:56934 +0.00011266336187471834 55630:55630 +0.00011266336187471834 56179:56179 +0.00011266336187471834 58426:58426 +0.00011266336187471834 33163:33163 +0.00011266336187471834 32880:32880 +0.00011266336187471834 33546:33546 +0.00011266336187471834 35504:35504 +0.00011266336187471834 55922:55922 +0.00011266336187471834 59443:59443 +0.00011266336187471834 60242:60242 +0.00011266336187471834 60335:60335 +0.00011266336187471834 58330:58330 +0.00011266336187471834 58145:58145 +0.00011266336187471834 56494:56494 +0.00011266336187471834 58673:58673 +0.00011266336187471834 60506:60506 +0.00011266336187471834 59958:59958 +0.00011266336187471834 34402:34402 +0.00011266336187471834 33334:33334 +0.00011266336187471834 34320:34320 +0.00011266336187471834 58329:58329 +0.00011266336187471834 60006:60006 +0.00011266336187471834 60654:60654 +0.00011266336187471834 57544:57544 +0.00011266336187471834 59401:59401 +0.00011266336187471834 59309:59309 +0.00011266336187471834 57036:57036 +0.00011266336187471834 35215:35215 +0.00011266336187471834 58032:58032 +0.00011266336187471834 56208:56208 +0.00011266336187471834 35072:35072 +0.00011266336187471834 60911:60911 +0.00011266336187471834 57175:57175 +0.00011266336187471834 33463:33463 +0.00011266336187471834 56404:56404 +0.00011266336187471834 33718:33718 +0.00011266336187471834 59764:59764 +0.00011266336187471834 57437:57437 +0.00011266336187471834 56646:56646 +0.00011266336187471834 58315:58315 +0.00011266336187471834 57341:57341 +0.00011266336187471834 34578:34578 +0.00011266336187471834 35263:35263 +0.00011266336187471834 34261:34261 +0.00011266336187471834 34301:34301 +0.00011266336187471834 34248:34248 +0.00011266336187471834 34078:34078 +0.00011266336187471834 58336:58336 +0.00011266336187471834 58258:58258 +0.00011266336187471834 34411:34411 +0.00011266336187471834 56621:56621 +0.00011266336187471834 55811:55811 +0.00011266336187471834 58992:58992 +0.00011266336187471834 34063:34063 +0.00011266336187471834 33513:33513 +0.00011266336187471834 59665:59665 +0.00011266336187471834 35305:35305 +0.00011266336187471834 34436:34436 +0.00011266336187471834 58584:58584 +0.00011266336187471834 55833:55833 +0.00011266336187471834 32796:32796 +0.00011266336187471834 58210:58210 +0.00011266336187471834 33831:33831 +0.00011266336187471834 59746:59746 +0.00011266336187471834 57271:57271 +0.00011266336187471834 33307:33307 +0.00011266336187471834 56403:56403 +0.00011266336187471834 57380:57380 +0.00011266336187471834 58398:58398 +0.00011266336187471834 33057:33057 +0.00011266336187471834 56720:56720 +0.00011266336187471834 58668:58668 +0.00011266336187471834 59677:59677 +0.00011266336187471834 58670:58670 +0.00011266336187471834 35294:35294 +0.00011266336187471834 34835:34835 +0.00011266336187471834 33597:33597 +0.00011266336187471834 57528:57528 +0.00011266336187471834 57001:57001 +0.00011266336187471834 55763:55763 +0.00011266336187471834 59650:59650 +0.00011266336187471834 35424:35424 +0.00011266336187471834 57834:57834 +0.00011266336187471834 33503:33503 +0.00011266336187471834 60615:60615 +0.00011266336187471834 34879:34879 +0.00011266336187471834 33910:33910 +0.00011266336187471834 59486:59486 +0.00011266336187471834 57643:57643 +0.00011266336187471834 34600:34600 +0.00011266336187471834 32963:32963 +0.00011266336187471834 56237:56237 +0.00011266336187471834 55781:55781 +0.00011266336187471834 56667:56667 +0.00011266336187471834 59912:59912 +0.00011266336187471834 55920:55920 +0.00011266336187471834 60579:60579 +0.00011266336187471834 34999:34999 +0.00011266336187471834 33103:33103 +0.00011266336187471834 58918:58918 +0.00011266336187471834 57941:57941 +0.00011266336187471834 60258:60258 +0.00011266336187471834 57198:57198 +0.00011266336187471834 58891:58891 +0.00011266336187471834 55653:55653 +0.00011266336187471834 60103:60103 +0.00011266336187471834 59315:59315 +0.00011266336187471834 57578:57578 +0.00011266336187471834 56228:56228 +0.00011266336187471834 58926:58926 +0.00011266336187471834 60263:60263 +0.00011266336187471834 33491:33491 +0.00011266336187471834 59962:59962 +0.00011266336187471834 60936:60936 +0.00011266336187471834 59496:59496 +0.00011266336187471834 60881:60881 +0.00011266336187471834 58682:58682 +0.00011266336187471834 57720:57720 +0.00011266336187471834 60173:60173 +0.00011266336187471834 59194:59194 +0.00011266336187471834 58532:58532 +0.00011266336187471834 57410:57410 +0.00011266336187471834 57117:57117 +0.00011266336187471834 60621:60621 +0.00011266336187471834 57240:57240 +0.00011266336187471834 57210:57210 +0.00011266336187471834 58942:58942 +0.00011266336187471834 59995:59995 +0.00011266336187471834 58015:58015 +0.00011266336187471834 58556:58556 +0.00011266336187471834 58160:58160 +0.00011266336187471834 57104:57104 +0.00011266336187471834 60054:60054 +0.00011266336187471834 60841:60841 +0.00011266336187471834 60149:60149 +0.00011266336187471834 58488:58488 +0.00011266336187471834 55862:55862 +0.00011266336187471834 33880:33880 +0.00011266336187471834 59684:59684 +0.00011266336187471834 35278:35278 +0.00011266336187471834 57302:57302 +0.00011266336187471834 57002:57002 +0.00011266336187471834 32783:32783 +0.00011266336187471834 59229:59229 +0.00011266336187471834 57399:57399 +0.00011266336187471834 35275:35275 +0.00011266336187471834 57541:57541 +0.00011266336187471834 56869:56869 +0.00011266336187471834 59366:59366 +0.00011266336187471834 58498:58498 +0.00011266336187471834 58141:58141 +0.00011266336187471834 56008:56008 +0.00011266336187471834 60390:60390 +0.00011266336187471834 32832:32832 +0.00011266336187471834 33218:33218 +0.00011266336187471834 34287:34287 +0.00011266336187471834 58991:58991 +0.00011266336187471834 35309:35309 +0.00011266336187471834 34227:34227 +0.00011266336187471834 34158:34158 +0.00011266336187471834 60696:60696 +0.00011266336187471834 56953:56953 +0.00011266336187471834 33965:33965 +0.00011266336187471834 58202:58202 +0.00011266336187471834 60556:60556 +0.00011266336187471834 58759:58759 +0.00011266336187471834 57134:57134 +0.00011266336187471834 56562:56562 +0.00011266336187471834 57448:57448 +0.00011266336187471834 57041:57041 +0.00011266336187471834 56118:56118 +0.00011266336187471834 55798:55798 +0.00011266336187471834 34825:34825 +0.00011266336187471834 58043:58043 +0.00011266336187471834 57975:57975 +0.00011266336187471834 55875:55875 +0.00011266336187471834 59453:59453 +0.00011266336187471834 59696:59696 +0.00011266336187471834 56250:56250 +0.00011266336187471834 56903:56903 +0.00011266336187471834 60226:60226 +0.00011266336187471834 56450:56450 +0.00011266336187471834 59210:59210 +0.00011266336187471834 58970:58970 +0.00011266336187471834 34783:34783 +0.00011266336187471834 34300:34300 +0.00011266336187471834 60070:60070 +0.00011266336187471834 33555:33555 +0.00011266336187471834 33413:33413 +0.00011266336187471834 56549:56549 +0.00011266336187471834 32807:32807 +0.00011266336187471834 59410:59410 +0.00011266336187471834 56803:56803 +0.00011266336187471834 56874:56874 +0.00011266336187471834 34314:34314 +0.00011266336187471834 56993:56993 +0.00011266336187471834 33930:33930 +0.00011266336187471834 59576:59576 +0.00011266336187471834 57042:57042 +0.00011266336187471834 32899:32899 +0.00011266336187471834 55735:55735 +0.00011266336187471834 34618:34618 +0.00011266336187471834 60865:60865 +0.00011266336187471834 33591:33591 +0.00011266336187471834 35043:35043 +0.00011266336187471834 33759:33759 +0.00011266336187471834 60743:60743 +0.00011266336187471834 59817:59817 +0.00011266336187471834 56755:56755 +0.00011266336187471834 59637:59637 +0.00011266336187471834 59307:59307 +0.00011266336187471834 60182:60182 +0.00011266336187471834 59162:59162 +0.00011266336187471834 57719:57719 +0.00011266336187471834 35126:35126 +0.00011266336187471834 35101:35101 +0.00011266336187471834 35042:35042 +0.00011266336187471834 58821:58821 +0.00011266336187471834 32953:32953 +0.00011266336187471834 56360:56360 +0.00011266336187471834 33492:33492 +0.00011266336187471834 58557:58557 +0.00011266336187471834 33850:33850 +0.00011266336187471834 57254:57254 +0.00011266336187471834 59367:59367 +0.00011266336187471834 35392:35392 +0.00011266336187471834 34605:34605 +0.00011266336187471834 60310:60310 +0.00011266336187471834 56274:56274 +0.00011266336187471834 56395:56395 +0.00011266336187471834 56239:56239 +0.00011266336187471834 57445:57445 +0.00011266336187471834 58693:58693 +0.00011266336187471834 58679:58679 +0.00011266336187471834 58266:58266 +0.00011266336187471834 60051:60051 +0.00011266336187471834 59613:59613 +0.00011266336187471834 55769:55769 +0.00011266336187471834 60737:60737 +0.00011266336187471834 58363:58363 +0.00011266336187471834 56597:56597 +0.00011266336187471834 34418:34418 +0.00011266336187471834 58371:58371 +0.00011266336187471834 33366:33366 +0.00011266336187471834 57978:57978 +0.00011266336187471834 56205:56205 +0.00011266336187471834 60437:60437 +0.00011266336187471834 59602:59602 +0.00011266336187471834 58727:58727 +0.00011266336187471834 33868:33868 +0.00011266336187471834 60705:60705 +0.00011266336187471834 60657:60657 +0.00011266336187471834 59184:59184 +0.00011266336187471834 58314:58314 +0.00011266336187471834 57748:57748 +0.00011266336187471834 60424:60424 +0.00011266336187471834 33270:33270 +0.00011266336187471834 33861:33861 +0.00011266336187471834 58086:58086 +0.00011266336187471834 34749:34749 +0.00011266336187471834 56905:56905 +0.00011266336187471834 57816:57816 +0.00011266336187471834 32845:32845 +0.00011266336187471834 59389:59389 +0.00011266336187471834 56949:56949 +0.00011266336187471834 56388:56388 +0.00011266336187471834 57353:57353 +0.00011266336187471834 59344:59344 +0.00011266336187471834 57496:57496 +0.00011266336187471834 32850:32850 +0.00011266336187471834 58910:58910 +0.00011266336187471834 60736:60736 +0.00011266336187471834 34627:34627 +0.00011266336187471834 56057:56057 +0.00011266336187471834 56836:56836 +0.00011266336187471834 58383:58383 +0.00011266336187471834 56054:56054 +0.00011266336187471834 58221:58221 +0.00011266336187471834 57714:57714 +0.00011266336187471834 57487:57487 +0.00011266336187471834 56441:56441 +0.00011266336187471834 59564:59564 +0.00011266336187471834 56082:56082 +0.00011266336187471834 34523:34523 +0.00011266336187471834 59138:59138 +0.00011266336187471834 34022:34022 +0.00011266336187471834 60782:60782 +0.00011266336187471834 60359:60359 +0.00011266336187471834 34696:34696 +0.00011266336187471834 57671:57671 +0.00011266336187471834 55628:55628 +0.00011266336187471834 59436:59436 +0.00011266336187471834 59224:59224 +0.00011266336187471834 56350:56350 +0.00011266336187471834 57467:57467 +0.00011266336187471834 32872:32872 +0.00011266336187471834 58593:58593 +0.00011266336187471834 34964:34964 +0.00011266336187471834 33988:33988 +0.00011266336187471834 33697:33697 +0.00011266336187471834 56147:56147 +0.00011266336187471834 33071:33071 +0.00011266336187471834 32933:32933 +0.00011266336187471834 59590:59590 +0.00011266336187471834 56671:56671 +0.00011266336187471834 58740:58740 +0.00011266336187471834 57802:57802 +0.00011266336187471834 56484:56484 +0.00011266336187471834 33807:33807 +0.00011266336187471834 59087:59087 +0.00011266336187471834 58178:58178 +0.00011266336187471834 56927:56927 +0.00011266336187471834 33353:33353 +0.00011266336187471834 56912:56912 +0.00011266336187471834 55777:55777 +0.00011266336187471834 35057:35057 +0.00011266336187471834 60630:60630 +0.00011266336187471834 57279:57279 +0.00011266336187471834 35318:35318 +0.00011266336187471834 60462:60462 +0.00011266336187471834 35167:35167 +0.00011266336187471834 33201:33201 +0.00011266336187471834 58423:58423 +0.00011266336187471834 33009:33009 +0.00011266336187471834 35559:35559 +0.00011266336187471834 33020:33020 +0.00011266336187471834 60308:60308 +0.00011266336187471834 35306:35306 +0.00011266336187471834 33189:33189 +0.00011266336187471834 59251:59251 +0.00011266336187471834 57907:57907 +0.00011266336187471834 35185:35185 +0.00011266336187471834 33523:33523 +0.00011266336187471834 60211:60211 +0.00011266336187471834 34635:34635 +0.00011266336187471834 59606:59606 +0.00011266336187471834 60312:60312 +0.00011266336187471834 59065:59065 +0.00011266336187471834 56981:56981 +0.00011266336187471834 55971:55971 +0.00011266336187471834 33994:33994 +0.00011266336187471834 33549:33549 +0.00011266336187471834 60159:60159 +0.00011266336187471834 58400:58400 +0.00011266336187471834 35346:35346 +0.00011266336187471834 33286:33286 +0.00011266336187471834 60606:60606 +0.00011266336187471834 60119:60119 +0.00011266336187471834 58205:58205 +0.00011266336187471834 35266:35266 +0.00011266336187471834 60295:60295 +0.00011266336187471834 60436:60436 +0.00011266336187471834 57079:57079 +0.00011266336187471834 33451:33451 +0.00011266336187471834 32966:32966 +0.00011266336187471834 32959:32959 +0.00011266336187471834 32785:32785 +0.00011266336187471834 59903:59903 +0.00011266336187471834 58494:58494 +0.00011266336187471834 55895:55895 +0.00011266336187471834 34881:34881 +0.00011266336187471834 60658:60658 +0.00011266336187471834 59857:59857 +0.00011266336187471834 35451:35451 +0.00011266336187471834 57568:57568 +0.00011266336187471834 57854:57854 +0.00011266336187471834 57674:57674 +0.00011266336187471834 60244:60244 +0.00011266336187471834 58973:58973 +0.00011266336187471834 58769:58769 +0.00011266336187471834 57704:57704 +0.00011266336187471834 58686:58686 +0.00011266336187471834 34972:34972 +0.00011266336187471834 32957:32957 +0.00011266336187471834 58285:58285 +0.00011266336187471834 56659:56659 +0.00011266336187471834 32865:32865 +0.00011266336187471834 60592:60592 +0.00011266336187471834 57987:57987 +0.00011266336187471834 56571:56571 +0.00011266336187471834 60564:60564 +0.00011266336187471834 58831:58831 +0.00011266336187471834 34489:34489 +0.00011266336187471834 34373:34373 +0.00011266336187471834 33342:33342 +0.00011266336187471834 59254:59254 +0.00011266336187471834 60161:60161 +0.00011266336187471834 57074:57074 +0.00011266336187471834 33390:33390 +0.00011266336187471834 33304:33304 +0.00011266336187471834 33118:33118 +0.00011266336187471834 33646:33646 +0.00011266336187471834 60157:60157 +0.00011266336187471834 56081:56081 +0.00011266336187471834 60207:60207 +0.00011266336187471834 60932:60932 +0.00011266336187471834 34651:34651 +0.00011266336187471834 33559:33559 +0.00011266336187471834 57775:57775 +0.00011266336187471834 60252:60252 +0.00011266336187471834 34326:34326 +0.00011266336187471834 33024:33024 +0.00011266336187471834 59074:59074 +0.00011266336187471834 57581:57581 +0.00011266336187471834 33162:33162 +0.00011266336187471834 55785:55785 +0.00011266336187471834 59737:59737 +0.00011266336187471834 35119:35119 +0.00011266336187471834 58345:58345 +0.00011266336187471834 57734:57734 +0.00011266336187471834 35301:35301 +0.00011266336187471834 35207:35207 +0.00011266336187471834 33344:33344 +0.00011266336187471834 57891:57891 +0.00011266336187471834 59073:59073 +0.00011266336187471834 57832:57832 +0.00011266336187471834 59425:59425 +0.00011266336187471834 58861:58861 +0.00011266336187471834 33048:33048 +0.00011266336187471834 56225:56225 +0.00011266336187471834 57038:57038 +0.00011266336187471834 34263:34263 +0.00011266336187471834 56569:56569 +0.00011266336187471834 58063:58063 +0.00011266336187471834 58419:58419 +0.00011266336187471834 35420:35420 +0.00011266336187471834 56409:56409 +0.00011266336187471834 35237:35237 +0.00011266336187471834 57478:57478 +0.00011266336187471834 57078:57078 +0.00011266336187471834 35077:35077 +0.00011266336187471834 34611:34611 +0.00011266336187471834 33530:33530 +0.00011266336187471834 33746:33746 +0.00011266336187471834 59680:59680 +0.00011266336187471834 34871:34871 +0.00011266336187471834 59193:59193 +0.00011266336187471834 58755:58755 +0.00011266336187471834 33301:33301 +0.00011266336187471834 33387:33387 +0.00011266336187471834 59031:59031 +0.00011266336187471834 55632:55632 +0.00011266336187471834 33542:33542 +0.00011266336187471834 57644:57644 +0.00011266336187471834 33514:33514 +0.00011266336187471834 58072:58072 +0.00011266336187471834 57033:57033 +0.00011266336187471834 35469:35469 +0.00011266336187471834 57736:57736 +0.00011266336187471834 58884:58884 +0.00011266336187471834 60421:60421 +0.00011266336187471834 58683:58683 +0.00011266336187471834 35329:35329 +0.00011266336187471834 33900:33900 +0.00011266336187471834 60502:60502 +0.00011266336187471834 33172:33172 +0.00011266336187471834 60285:60285 +0.00011266336187471834 35450:35450 +0.00011266336187471834 59916:59916 +0.00011266336187471834 33308:33308 +0.00011266336187471834 33040:33040 +0.00011266336187471834 60086:60086 +0.00011266336187471834 57260:57260 +0.00011266336187471834 33265:33265 +0.00011266336187471834 59507:59507 +0.00011266336187471834 35430:35430 +0.00011266336187471834 33174:33174 +0.00011266336187471834 60734:60734 +0.00011266336187471834 60068:60068 +0.00011266336187471834 58468:58468 +0.00011266336187471834 58820:58820 +0.00011266336187471834 35290:35290 +0.00011266336187471834 57222:57222 +0.00011266336187471834 56705:56705 +0.00011266336187471834 33338:33338 +0.00011266336187471834 59026:59026 +0.00011266336187471834 33848:33848 +0.00011266336187471834 56789:56789 +0.00011266336187471834 58126:58126 +0.00011266336187471834 33731:33731 +0.00011266336187471834 33670:33670 +0.00011266336187471834 32846:32846 +0.00011266336187471834 59269:59269 +0.00011266336187471834 33949:33949 +0.00011266336187471834 33830:33830 +0.00011266336187471834 35493:35493 +0.00011266336187471834 59089:59089 +0.00011266336187471834 33315:33315 +0.00011266336187471834 58323:58323 +0.00011266336187471834 56976:56976 +0.00011266336187471834 55900:55900 +0.00011266336187471834 33595:33595 +0.00011266336187471834 59711:59711 +0.00011266336187471834 57753:57753 +0.00011266336187471834 34834:34834 +0.00011266336187471834 58010:58010 +0.00011266336187471834 57157:57157 +0.00011266336187471834 56257:56257 +0.00011266336187471834 58802:58802 +0.00011266336187471834 58544:58544 +0.00011266336187471834 60542:60542 +0.00011266336187471834 59133:59133 +0.00011266336187471834 60121:60121 +0.00011266336187471834 56430:56430 +0.00011266336187471834 32773:32773 +0.00011266336187471834 56217:56217 +0.00011266336187471834 57131:57131 +0.00011266336187471834 55841:55841 +0.00011266336187471834 34563:34563 +0.00011266336187471834 33437:33437 +0.00011266336187471834 60381:60381 +0.00011266336187471834 34842:34842 +0.00011266336187471834 60346:60346 +0.00011266336187471834 60088:60088 +0.00011266336187471834 34077:34077 +0.00011266336187471834 58904:58904 +0.00011266336187471834 35308:35308 +0.00011266336187471834 33803:33803 +0.00011266336187471834 33199:33199 +0.00011266336187471834 57831:57831 +0.00011266336187471834 33318:33318 +0.00011266336187471834 32999:32999 +0.00011266336187471834 55765:55765 +0.00011266336187471834 33919:33919 +0.00011266336187471834 56985:56985 +0.00011266336187471834 56473:56473 +0.00011266336187471834 35115:35115 +0.00011266336187471834 58640:58640 +0.00011266336187471834 34684:34684 +0.00011266336187471834 33230:33230 +0.00011266336187471834 60979:60979 +0.00011266336187471834 33402:33402 +0.00011266336187471834 59886:59886 +0.00011266336187471834 58940:58940 +0.00011266336187471834 34337:34337 +0.00011266336187471834 59279:59279 +0.00011266336187471834 57645:57645 +0.00011266336187471834 56278:56278 +0.00011266336187471834 57154:57154 +0.00011266336187471834 60975:60975 +0.00011266336187471834 34545:34545 +0.00011266336187471834 60203:60203 +0.00011266336187471834 59462:59462 +0.00011266336187471834 58835:58835 +0.00011266336187471834 33592:33592 +0.00011266336187471834 58895:58895 +0.00011266336187471834 34655:34655 +0.00011266336187471834 57747:57747 +0.00011266336187471834 57634:57634 +0.00011266336187471834 58988:58988 +0.00011266336187471834 33062:33062 +0.00011266336187471834 60921:60921 +0.00011266336187471834 56189:56189 +0.00011266336187471834 34702:34702 +0.00011266336187471834 33421:33421 +0.00011266336187471834 33501:33501 +0.00011266336187471834 55937:55937 +0.00011266336187471834 39733:39733 +0.00011266336187471834 56964:56964 +0.00011266336187471834 58166:58166 +0.00011266336187471834 55641:55641 +0.00011266336187471834 60300:60300 +0.00011266336187471834 34741:34741 +0.00011266336187471834 55663:55663 +0.00011266336187471834 32813:32813 +0.00011266336187471834 56425:56425 +0.00011266336187471834 34404:34404 +0.00011266336187471834 60452:60452 +0.00011266336187471834 60475:60475 +0.00011266336187471834 35416:35416 +0.00011266336187471834 34189:34189 +0.00011266336187471834 33028:33028 +0.00011266336187471834 59844:59844 +0.00011266336187471834 60448:60448 +0.00011266336187471834 32852:32852 +0.00011266336187471834 57363:57363 +0.00011266336187471834 57242:57242 +0.00011266336187471834 34799:34799 +0.00011266336187471834 32840:32840 +0.00011266336187471834 60118:60118 +0.00011266336187471834 34776:34776 +0.00011266336187471834 60933:60933 +0.00011266336187471834 59627:59627 +0.00011266336187471834 58081:58081 +0.00011266336187471834 59938:59938 +0.00011266336187471834 58067:58067 +0.00011266336187471834 57084:57084 +0.00011266336187471834 58133:58133 +0.00011266336187471834 34472:34472 +0.00011266336187471834 34674:34674 +0.00011266336187471834 59461:59461 +0.00011266336187471834 35335:35335 +0.00011266336187471834 57579:57579 +0.00011266336187471834 57430:57430 +0.00011266336187471834 56645:56645 +0.00011266336187471834 56289:56289 +0.00011266336187471834 34646:34646 +0.00011266336187471834 58827:58827 +0.00011266336187471834 56043:56043 +0.00011266336187471834 34932:34932 +0.00011266336187471834 34018:34018 +0.00011266336187471834 32984:32984 +0.00011266336187471834 59946:59946 +0.00011266336187471834 59198:59198 +0.00011266336187471834 59596:59596 +0.00011266336187471834 58424:58424 +0.00011266336187471834 59989:59989 +0.00011266336187471834 59614:59614 +0.00011266336187471834 56407:56407 +0.00011266336187471834 56547:56547 +0.00011266336187471834 58107:58107 +0.00011266336187471834 57015:57015 +0.00011266336187471834 34493:34493 +0.00011266336187471834 32834:32834 +0.00011266336187471834 57339:57339 +0.00011266336187471834 59783:59783 +0.00011266336187471834 59329:59329 +0.00011266336187471834 35339:35339 +0.00011266336187471834 60411:60411 +0.00011266336187471834 58703:58703 +0.00011266336187471834 55744:55744 +0.00011266336187471834 32991:32991 +0.00011266336187471834 58651:58651 +0.00011266336187471834 34756:34756 +0.00011266336187471834 60717:60717 +0.00011266336187471834 33101:33101 +0.00011266336187471834 57796:57796 +0.00011266336187471834 34977:34977 +0.00011266336187471834 56879:56879 +0.00011266336187471834 60505:60505 +0.00011266336187471834 58518:58518 +0.00011266336187471834 33405:33405 +0.00011266336187471834 33615:33615 +0.00011266336187471834 35011:35011 +0.00011266336187471834 60647:60647 +0.00011266336187471834 59806:59806 +0.00011266336187471834 60183:60183 +0.00011266336187471834 34011:34011 +0.00011266336187471834 33631:33631 +0.00011266336187471834 60757:60757 +0.00011266336187471834 58571:58571 +0.00011266336187471834 58227:58227 +0.00011266336187471834 34128:34128 +0.00011266336187471834 33580:33580 +0.00011266336187471834 57438:57438 +0.00011266336187471834 35519:35519 +0.00011266336187471834 58294:58294 +0.00011266336187471834 58863:58863 +0.00011266336187471834 57295:57295 +0.00011266336187471834 59799:59799 +0.00011266336187471834 58120:58120 +0.00011266336187471834 33870:33870 +0.00011266336187471834 57019:57019 +0.00011266336187471834 33824:33824 +0.00011266336187471834 55930:55930 +0.00011266336187471834 58698:58698 +0.00011266336187471834 56587:56587 +0.00011266336187471834 35040:35040 +0.00011266336187471834 57330:57330 +0.00011266336187471834 35190:35190 +0.00011266336187471834 58289:58289 +0.00011266336187471834 34748:34748 +0.00011266336187471834 33408:33408 +0.00011266336187471834 35361:35361 +0.00011266336187471834 59295:59295 +0.00011266336187471834 60803:60803 +0.00011266336187471834 58896:58896 +0.00011266336187471834 55694:55694 +0.00011266336187471834 33669:33669 +0.00011266336187471834 59909:59909 +0.00011266336187471834 34477:34477 +0.00011266336187471834 57394:57394 +0.00011266336187471834 57413:57413 +0.00011266336187471834 33678:33678 +0.00011266336187471834 57375:57375 +0.00011266336187471834 56847:56847 +0.00011266336187471834 57965:57965 +0.00011266336187471834 58793:58793 +0.00011266336187471834 57370:57370 +0.00011266336187471834 56962:56962 +0.00011266336187471834 32884:32884 +0.00011266336187471834 56476:56476 +0.00011266336187471834 56390:56390 +0.00011266336187471834 55771:55771 +0.00011266336187471834 33792:33792 +0.00011266336187471834 33673:33673 +0.00011266336187471834 33325:33325 +0.00011266336187471834 59361:59361 +0.00011266336187471834 56265:56265 +0.00011266336187471834 32853:32853 +0.00011266336187471834 60418:60418 +0.00011266336187471834 56973:56973 +0.00011266336187471834 34346:34346 +0.00011266336187471834 58001:58001 +0.00011266336187471834 34181:34181 +0.00011266336187471834 56321:56321 +0.00011266336187471834 55710:55710 +0.00011266336187471834 56198:56198 +0.00011266336187471834 60122:60122 +0.00011266336187471834 34046:34046 +0.00011266336187471834 33903:33903 +0.00011266336187471834 35506:35506 +0.00011266336187471834 32864:32864 +0.00011266336187471834 57622:57622 +0.00011266336187471834 56401:56401 +0.00011266336187471834 58691:58691 +0.00011266336187471834 58165:58165 +0.00011266336187471834 59880:59880 +0.00011266336187471834 58856:58856 +0.00011266336187471834 58645:58645 +0.00011266336187471834 57390:57390 +0.00011266336187471834 60488:60488 +0.00011266336187471834 59270:59270 +0.00011266336187471834 56699:56699 +0.00011266336187471834 56340:56340 +0.00011266336187471834 34071:34071 +0.00011266336187471834 57276:57276 +0.00011266336187471834 32811:32811 +0.00011266336187471834 34004:34004 +0.00011266336187471834 57296:57296 +0.00011266336187471834 57546:57546 +0.00011266336187471834 56492:56492 +0.00011266336187471834 34354:34354 +0.00011266336187471834 32776:32776 +0.00011266336187471834 59765:59765 +0.00011266336187471834 59675:59675 +0.00011266336187471834 33448:33448 +0.00011266336187471834 33212:33212 +0.00011266336187471834 32798:32798 +0.00011266336187471834 55741:55741 +0.00011266336187471834 60772:60772 +0.00011266336187471834 56763:56763 +0.00011266336187471834 55754:55754 +0.00011266336187471834 34895:34895 +0.00011266336187471834 60425:60425 +0.00011266336187471834 56842:56842 +0.00011266336187471834 33241:33241 +0.00011266336187471834 60639:60639 +0.00011266336187471834 56083:56083 +0.00011266336187471834 57334:57334 +0.00011266336187471834 34985:34985 +0.00011266336187471834 55965:55965 +0.00011266336187471834 35179:35179 +0.00011266336187471834 56505:56505 +0.00011266336187471834 56106:56106 +0.00011266336187471834 35201:35201 +0.00011266336187471834 59776:59776 +0.00011266336187471834 56708:56708 +0.00011266336187471834 34897:34897 +0.00011266336187471834 56795:56795 +0.00011266336187471834 32829:32829 +0.00011266336187471834 60057:60057 +0.00011266336187471834 56277:56277 +0.00011266336187471834 55695:55695 +0.00011266336187471834 34455:34455 +0.00011266336187471834 58358:58358 +0.00011266336187471834 56012:56012 +0.00011266336187471834 33412:33412 +0.00011266336187471834 33790:33790 +0.00011266336187471834 60787:60787 +0.00011266336187471834 57631:57631 +0.00011266336187471834 56035:56035 +0.00011266336187471834 56545:56545 +0.00011266336187471834 57414:57414 +0.00011266336187471834 59612:59612 +0.00011266336187471834 60008:60008 +0.00011266336187471834 33105:33105 +0.00011266336187471834 60255:60255 +0.00011266336187471834 34070:34070 +0.00011266336187471834 34900:34900 +0.00011266336187471834 33553:33553 +0.00011266336187471834 33372:33372 +0.00011266336187471834 33001:33001 +0.00011266336187471834 59083:59083 +0.00011266336187471834 35147:35147 +0.00011266336187471834 33708:33708 +0.00011266336187471834 34365:34365 +0.00011266336187471834 34168:34168 +0.00011266336187471834 34030:34030 +0.00011266336187471834 60861:60861 +0.00011266336187471834 59865:59865 +0.00011266336187471834 56157:56157 +0.00011266336187471834 33282:33282 +0.00011266336187471834 59537:59537 +0.00011266336187471834 58320:58320 +0.00011266336187471834 59472:59472 +0.00011266336187471834 57637:57637 +0.00011266336187471834 35295:35295 +0.00011266336187471834 60379:60379 +0.00011266336187471834 57251:57251 +0.00011266336187471834 56775:56775 +0.00011266336187471834 55725:55725 +0.00011266336187471834 58299:58299 +0.00011266336187471834 33435:33435 +0.00011266336187471834 58837:58837 +0.00011266336187471834 60132:60132 +0.00011266336187471834 58883:58883 +0.00011266336187471834 60497:60497 +0.00011266336187471834 58434:58434 +0.00011266336187471834 57206:57206 +0.00011266336187471834 60420:60420 +0.00011266336187471834 58966:58966 +0.00011266336187471834 56761:56761 +0.00011266336187471834 56825:56825 +0.00011266336187471834 34432:34432 +0.00011266336187471834 58373:58373 +0.00011266336187471834 34125:34125 +0.00011266336187471834 56044:56044 +0.00011266336187471834 56856:56856 +0.00011266336187471834 59141:59141 +0.00011266336187471834 58756:58756 +0.00011266336187471834 33015:33015 +0.00011266336187471834 33765:33765 +0.00011266336187471834 57873:57873 +0.00011266336187471834 60126:60126 +0.00011266336187471834 59822:59822 +0.00011266336187471834 59145:59145 +0.00011266336187471834 59608:59608 +0.00011266336187471834 34833:34833 +0.00011266336187471834 34667:34667 +0.00011266336187471834 60597:60597 +0.00011266336187471834 58077:58077 +0.00011266336187471834 55878:55878 +0.00011266336187471834 58435:58435 +0.00011266336187471834 57292:57292 +0.00011266336187471834 56112:56112 +0.00011266336187471834 58579:58579 +0.00011266336187471834 56135:56135 +0.00011266336187471834 57900:57900 +0.00011266336187471834 35463:35463 +0.00011266336187471834 57866:57866 +0.00011266336187471834 34059:34059 +0.00011266336187471834 55675:55675 +0.00011266336187471834 33191:33191 +0.00011266336187471834 60274:60274 +0.00011266336187471834 33419:33419 +0.00011266336187471834 35247:35247 +0.00011266336187471834 34043:34043 +0.00011266336187471834 59338:59338 +0.00011266336187471834 59600:59600 +0.00011266336187471834 58257:58257 +0.00011266336187471834 60261:60261 +0.00011266336187471834 58750:58750 +0.00011266336187471834 58572:58572 +0.00011266336187471834 35148:35148 +0.00011266336187471834 59492:59492 +0.00011266336187471834 35378:35378 +0.00011266336187471834 56302:56302 +0.00011266336187471834 55779:55779 +0.00011266336187471834 33380:33380 +0.00011266336187471834 57173:57173 +0.00011266336187471834 33330:33330 +0.00011266336187471834 60866:60866 +0.00011266336187471834 60661:60661 +0.00011266336187471834 34405:34405 +0.00011266336187471834 58020:58020 +0.00011266336187471834 56246:56246 +0.00011266336187471834 56387:56387 +0.00011266336187471834 34697:34697 +0.00011266336187471834 33060:33060 +0.00011266336187471834 56086:56086 +0.00011266336187471834 58271:58271 +0.00011266336187471834 57256:57256 +0.00011266336187471834 56165:56165 +0.00011266336187471834 57991:57991 +0.00011266336187471834 57151:57151 +0.00011266336187471834 59705:59705 +0.00011266336187471834 34626:34626 +0.00011266336187471834 55851:55851 +0.00011266336187471834 35139:35139 +0.00011266336187471834 33548:33548 +0.00011266336187471834 56694:56694 +0.00011266336187471834 60401:60401 +0.00011266336187471834 35360:35360 +0.00011266336187471834 34192:34192 +0.00011266336187471834 60399:60399 +0.00011266336187471834 33521:33521 +0.00011266336187471834 56379:56379 +0.00011266336187471834 34179:34179 +0.00011266336187471834 57540:57540 +0.00011266336187471834 33942:33942 +0.00011266336187471834 58471:58471 +0.00011266336187471834 55953:55953 +0.00011266336187471834 58600:58600 +0.00011266336187471834 57395:57395 +0.00011266336187471834 33786:33786 +0.00011266336187471834 57329:57329 +0.00011266336187471834 33641:33641 +0.00011266336187471834 58311:58311 +0.00011266336187471834 60800:60800 +0.00011266336187471834 60749:60749 +0.00011266336187471834 60670:60670 +0.00011266336187471834 56870:56870 +0.00011266336187471834 56909:56909 +0.00011266336187471834 57713:57713 +0.00011266336187471834 34769:34769 +0.00011266336187471834 57780:57780 +0.00011266336187471834 56730:56730 +0.00011266336187471834 57993:57993 +0.00011266336187471834 35536:35536 +0.00011266336187471834 55824:55824 +0.00011266336187471834 60501:60501 +0.00011266336187471834 59330:59330 +0.00011266336187471834 35523:35523 +0.00011266336187471834 35093:35093 +0.00011266336187471834 34700:34700 +0.00011266336187471834 60794:60794 +0.00011266336187471834 57882:57882 +0.00011266336187471834 57820:57820 +0.00011266336187471834 34953:34953 +0.00011266336187471834 34321:34321 +0.00011266336187471834 58917:58917 +0.00011266336187471834 35196:35196 +0.00011266336187471834 59060:59060 +0.00011266336187471834 35560:35560 +0.00011266336187471834 56243:56243 +0.00011266336187471834 60266:60266 +0.00011266336187471834 56888:56888 +0.00011266336187471834 59738:59738 +0.00011266336187471834 34465:34465 +0.00011266336187471834 34505:34505 +0.00011266336187471834 33284:33284 +0.00011266336187471834 35150:35150 +0.00011266336187471834 56576:56576 +0.00011266336187471834 33952:33952 +0.00011266336187471834 58763:58763 +0.00011266336187471834 35279:35279 +0.00011266336187471834 57324:57324 +0.00011266336187471834 60805:60805 +0.00011266336187471834 59159:59159 +0.00011266336187471834 56090:56090 +0.00011266336187471834 58796:58796 +0.00011266336187471834 57200:57200 +0.00011266336187471834 34555:34555 +0.00011266336187471834 59852:59852 +0.00011266336187471834 34774:34774 +0.00011266336187471834 55611:55611 +0.00011266336187471834 59605:59605 +0.00011266336187471834 57560:57560 +0.00011266336187471834 56038:56038 +0.00011266336187471834 58055:58055 +0.00011266336187471834 57999:57999 +0.00011266336187471834 56607:56607 +0.00011266336187471834 55943:55943 +0.00011266336187471834 55631:55631 +0.00011266336187471834 33250:33250 +0.00011266336187471834 35529:35529 +0.00011266336187471834 35482:35482 +0.00011266336187471834 34529:34529 +0.00011266336187471834 56915:56915 +0.00011266336187471834 34099:34099 +0.00011266336187471834 35182:35182 +0.00011266336187471834 56872:56872 +0.00011266336187471834 60507:60507 +0.00011266336187471834 59910:59910 +0.00011266336187471834 35020:35020 +0.00011266336187471834 59231:59231 +0.00011266336187471834 58860:58860 +0.00011266336187471834 59363:59363 +0.00011266336187471834 58040:58040 +0.00011266336187471834 58085:58085 +0.00011266336187471834 58260:58260 +0.00011266336187471834 57000:57000 +0.00011266336187471834 35051:35051 +0.00011266336187471834 34332:34332 +0.00011266336187471834 34788:34788 +0.00011266336187471834 60147:60147 +0.00011266336187471834 60527:60527 +0.00011266336187471834 59030:59030 +0.00011266336187471834 57506:57506 +0.00011266336187471834 58180:58180 +0.00011266336187471834 33682:33682 +0.00011266336187471834 33938:33938 +0.00011266336187471834 57174:57174 +0.00011266336187471834 57283:57283 +0.00011266336187471834 33571:33571 +0.00011266336187471834 59952:59952 +0.00011266336187471834 58964:58964 +0.00011266336187471834 57171:57171 +0.00011266336187471834 57286:57286 +0.00011266336187471834 55674:55674 +0.00011266336187471834 34182:34182 +0.00011266336187471834 58078:58078 +0.00011266336187471834 56821:56821 +0.00011266336187471834 33644:33644 +0.00011266336187471834 60755:60755 +0.00011266336187471834 59057:59057 +0.00011266336187471834 57310:57310 +0.00011266336187471834 56296:56296 +0.00011266336187471834 57539:57539 +0.00011266336187471834 56077:56077 +0.00011266336187471834 55639:55639 +0.00011266336187471834 58656:58656 +0.00011266336187471834 35372:35372 +0.00011266336187471834 58659:58659 +0.00011266336187471834 56622:56622 +0.00011266336187471834 58215:58215 +0.00011266336187471834 60223:60223 +0.00011266336187471834 60073:60073 +0.00011266336187471834 33796:33796 +0.00011266336187471834 58023:58023 +0.00011266336187471834 34309:34309 +0.00011266336187471834 33856:33856 +0.00011266336187471834 59773:59773 +0.00011266336187471834 59076:59076 +0.00011266336187471834 57014:57014 +0.00011266336187471834 60166:60166 +0.00011266336187471834 56758:56758 +0.00011266336187471834 34359:34359 +0.00011266336187471834 33815:33815 +0.00011266336187471834 33692:33692 +0.00011266336187471834 58606:58606 +0.00011266336187471834 60815:60815 +0.00011266336187471834 35459:35459 +0.00011266336187471834 35522:35522 +0.00011266336187471834 56248:56248 +0.00011266336187471834 56049:56049 +0.00011266336187471834 33636:33636 +0.00011266336187471834 33132:33132 +0.00011266336187471834 55899:55899 +0.00011266336187471834 55800:55800 +0.00011266336187471834 56475:56475 +0.00011266336187471834 59568:59568 +0.00011266336187471834 60674:60674 +0.00011266336187471834 33104:33104 +0.00011266336187471834 60801:60801 +0.00011266336187471834 59493:59493 +0.00011266336187471834 58297:58297 +0.00011266336187471834 59457:59457 +0.00011266336187471834 57676:57676 +0.00011266336187471834 34840:34840 +0.00011266336187471834 60690:60690 +0.00011266336187471834 32841:32841 +0.00011266336187471834 33311:33311 +0.00011266336187471834 34766:34766 +0.00011266336187471834 57229:57229 +0.00011266336187471834 35025:35025 +0.00011266336187471834 59512:59512 +0.00011266336187471834 57383:57383 +0.00011266336187471834 57071:57071 +0.00011266336187471834 56139:56139 +0.00011266336187471834 34031:34031 +0.00011266336187471834 57248:57248 +0.00011266336187471834 35027:35027 +0.00011266336187471834 34971:34971 +0.00011266336187471834 35491:35491 +0.00011266336187471834 58155:58155 +0.00011266336187471834 57020:57020 +0.00011266336187471834 58183:58183 +0.00011266336187471834 56698:56698 +0.00011266336187471834 35431:35431 +0.00011266336187471834 34858:34858 +0.00011266336187471834 56469:56469 +0.00011266336187471834 33756:33756 +0.00011266336187471834 33185:33185 +0.00011266336187471834 58137:58137 +0.00011266336187471834 55749:55749 +0.00011266336187471834 58770:58770 +0.00011266336187471834 57328:57328 +0.00011266336187471834 33407:33407 +0.00011266336187471834 60185:60185 +0.00011266336187471834 32882:32882 +0.00011266336187471834 55745:55745 +0.00011266336187471834 60356:60356 +0.00011266336187471834 60350:60350 +0.00011266336187471834 60578:60578 +0.00011266336187471834 58173:58173 +0.00011266336187471834 60573:60573 +0.00011266336187471834 59699:59699 +0.00011266336187471834 59327:59327 +0.00011266336187471834 58927:58927 +0.00011266336187471834 56418:56418 +0.00011266336187471834 55740:55740 +0.00011266336187471834 56318:56318 +0.00011266336187471834 34746:34746 +0.00011266336187471834 60856:60856 +0.00011266336187471834 56071:56071 +0.00011266336187471834 55853:55853 +0.00011266336187471834 59413:59413 +0.00011266336187471834 59805:59805 +0.00011266336187471834 57833:57833 +0.00011266336187471834 34564:34564 +0.00011266336187471834 59052:59052 +0.00011266336187471834 32804:32804 +0.00011266336187471834 55819:55819 +0.00011266336187471834 34052:34052 +0.00011266336187471834 56163:56163 +0.00011266336187471834 56061:56061 +0.00011266336187471834 58455:58455 +0.00011266336187471834 55866:55866 +0.00011266336187471834 58936:58936 +0.00011266336187471834 35028:35028 +0.00011266336187471834 57791:57791 +0.00011266336187471834 57427:57427 +0.00011266336187471834 57076:57076 +0.00011266336187471834 59110:59110 +0.00011266336187471834 35029:35029 +0.00011266336187471834 35531:35531 +0.00011266336187471834 33430:33430 +0.00011266336187471834 56654:56654 +0.00011266336187471834 56531:56531 +0.00011266336187471834 59209:59209 +0.00011266336187471834 34662:34662 +0.00011266336187471834 33702:33702 +0.00011266336187471834 33753:33753 +0.00011266336187471834 57750:57750 +0.00011266336187471834 33686:33686 +0.00011266336187471834 32799:32799 +0.00011266336187471834 58343:58343 +0.00011266336187471834 57641:57641 +0.00011266336187471834 33879:33879 +0.00011266336187471834 33072:33072 +0.00011266336187471834 60695:60695 +0.00011266336187471834 35358:35358 +0.00011266336187471834 60807:60807 +0.00011266336187471834 60751:60751 +0.00011266336187471834 59187:59187 +0.00011266336187471834 58513:58513 +0.00011266336187471834 59468:59468 +0.00011266336187471834 57517:57517 +0.00011266336187471834 56159:56159 +0.00011266336187471834 58636:58636 +0.00011266336187471834 56833:56833 +0.00011266336187471834 57590:57590 +0.00011266336187471834 55747:55747 +0.00011266336187471834 33077:33077 +0.00011266336187471834 55640:55640 +0.00011266336187471834 33452:33452 +0.00011266336187471834 57529:57529 +0.00011266336187471834 56570:56570 +0.00011266336187471834 59004:59004 +0.00011266336187471834 59732:59732 +0.00011266336187471834 56260:56260 +0.00011266336187471834 60677:60677 +0.00011266336187471834 57877:57877 +0.00011266336187471834 60081:60081 +0.00011266336187471834 56706:56706 +0.00011266336187471834 57662:57662 +0.00011266336187471834 56073:56073 +0.00011266336187471834 35224:35224 +0.00011266336187471834 33934:33934 +0.00011266336187471834 35259:35259 +0.00011266336187471834 60059:60059 +0.00011266336187471834 33399:33399 +0.00011266336187471834 56140:56140 +0.00011266336187471834 33816:33816 +0.00011266336187471834 60761:60761 +0.00011266336187471834 58407:58407 +0.00011266336187471834 56703:56703 +0.00011266336187471834 34610:34610 +0.00011266336187471834 60724:60724 +0.00011266336187471834 58664:58664 +0.00011266336187471834 35340:35340 +0.00011266336187471834 57376:57376 +0.00011266336187471834 58810:58810 +0.00011266336187471834 56227:56227 +0.00011266336187471834 33941:33941 +0.00011266336187471834 33257:33257 +0.00011266336187471834 59120:59120 +0.00011266336187471834 56099:56099 +0.00011266336187471834 56474:56474 +0.00011266336187471834 58737:58737 +0.00011266336187471834 58152:58152 +0.00011266336187471834 34462:34462 +0.00011266336187471834 33624:33624 +0.00011266336187471834 33495:33495 +0.00011266336187471834 56950:56950 +0.00011266336187471834 60978:60978 +0.00011266336187471834 60083:60083 +0.00011266336187471834 56574:56574 +0.00011266336187471834 60718:60718 +0.00011266336187471834 59603:59603 +0.00011266336187471834 57501:57501 +0.00011266336187471834 60485:60485 +0.00011266336187471834 59975:59975 +0.00011266336187471834 34994:34994 +0.00011266336187471834 34328:34328 +0.00011266336187471834 35347:35347 +0.00011266336187471834 59529:59529 +0.00011266336187471834 57300:57300 +0.00011266336187471834 59587:59587 +0.00011266336187471834 58641:58641 +0.00011266336187471834 35154:35154 +0.00011266336187471834 60332:60332 +0.00011266336187471834 32940:32940 +0.00011266336187471834 34452:34452 +0.00011266336187471834 59827:59827 +0.00011266336187471834 34351:34351 +0.00011266336187471834 33150:33150 +0.00011266336187471834 55962:55962 +0.00011266336187471834 34157:34157 +0.00011266336187471834 33918:33918 +0.00011266336187471834 58185:58185 +0.00011266336187471834 34854:34854 +0.00011266336187471834 34671:34671 +0.00011266336187471834 34397:34397 +0.00011266336187471834 34891:34891 +0.00011266336187471834 32868:32868 +0.00011266336187471834 57381:57381 +0.00011266336187471834 35138:35138 +0.00011266336187471834 58548:58548 +0.00011266336187471834 55958:55958 +0.00011266336187471834 60679:60679 +0.00011266336187471834 57468:57468 +0.00011266336187471834 56455:56455 +0.00011266336187471834 34604:34604 +0.00011266336187471834 58719:58719 +0.00011266336187471834 56987:56987 +0.00011266336187471834 55903:55903 +0.00011266336187471834 57909:57909 +0.00011266336187471834 57469:57469 +0.00011266336187471834 60651:60651 +0.00011266336187471834 59452:59452 +0.00011266336187471834 58669:58669 +0.00011266336187471834 56380:56380 +0.00011266336187471834 59652:59652 +0.00011266336187471834 58046:58046 +0.00011266336187471834 35371:35371 +0.00011266336187471834 59115:59115 +0.00011266336187471834 33398:33398 +0.00011266336187471834 58321:58321 +0.00011266336187471834 58261:58261 +0.00011266336187471834 58017:58017 +0.00011266336187471834 58091:58091 +0.00011266336187471834 60514:60514 +0.00011266336187471834 56716:56716 +0.00011266336187471834 56396:56396 +0.00011266336187471834 58639:58639 +0.00011266336187471834 33614:33614 +0.00011266336187471834 58486:58486 +0.00011266336187471834 35524:35524 +0.00011266336187471834 33148:33148 +0.00011266336187471834 57219:57219 +0.00011266336187471834 35140:35140 +0.00011266336187471834 33170:33170 +0.00011266336187471834 58625:58625 +0.00011266336187471834 35382:35382 +0.00011266336187471834 32793:32793 +0.00011266336187471834 59890:59890 +0.00011266336187471834 58143:58143 +0.00011266336187471834 56540:56540 +0.00011266336187471834 56254:56254 +0.00011266336187471834 58911:58911 +0.00011266336187471834 56272:56272 +0.00011266336187471834 59433:59433 +0.00011266336187471834 34027:34027 +0.00011266336187471834 58247:58247 +0.00011266336187471834 57319:57319 +0.00011266336187471834 56744:56744 +0.00011266336187471834 59714:59714 +0.00011266336187471834 58811:58811 +0.00011266336187471834 57951:57951 +0.00011266336187471834 33576:33576 +0.00011266336187471834 58987:58987 +0.00011266336187471834 33739:33739 +0.00011266336187471834 60691:60691 +0.00011266336187471834 33623:33623 +0.00011266336187471834 34998:34998 +0.00011266336187471834 59813:59813 +0.00011266336187471834 57429:57429 +0.00011266336187471834 32971:32971 +0.00011266336187471834 59215:59215 +0.00011266336187471834 33358:33358 +0.00011266336187471834 35194:35194 +0.00011266336187471834 59171:59171 +0.00011266336187471834 58951:58951 +0.00011266336187471834 32771:32771 +0.00011266336187471834 57355:57355 +0.00011266336187471834 35212:35212 +0.00011266336187471834 34530:34530 +0.00011266336187471834 32792:32792 +0.00011266336187471834 33970:33970 +0.00011266336187471834 59706:59706 +0.00011266336187471834 57105:57105 +0.00011266336187471834 56877:56877 +0.00011266336187471834 56481:56481 +0.00011266336187471834 56723:56723 +0.00011266336187471834 57367:57367 +0.00011266336187471834 56575:56575 +0.00011266336187471834 35238:35238 +0.00011266336187471834 59663:59663 +0.00011266336187471834 34821:34821 +0.00011266336187471834 60363:60363 +0.00011266336187471834 60230:60230 +0.00011266336187471834 59395:59395 +0.00011266336187471834 35010:35010 +0.00011266336187471834 59891:59891 +0.00011266336187471834 33500:33500 +0.00011266336187471834 33640:33640 +0.00011266336187471834 59701:59701 +0.00011266336187471834 59867:59867 +0.00011266336187471834 59648:59648 +0.00011266336187471834 56780:56780 +0.00011266336187471834 58195:58195 +0.00011266336187471834 58775:58775 +0.00011266336187471834 59003:59003 +0.00011266336187471834 33709:33709 +0.00011266336187471834 60905:60905 +0.00011266336187471834 56456:56456 +0.00011266336187471834 34758:34758 +0.00011266336187471834 34715:34715 +0.00011266336187471834 56161:56161 +0.00011266336187471834 59830:59830 +0.00011266336187471834 55622:55622 +0.00011266336187471834 32895:32895 +0.00011266336187471834 57322:57322 +0.00011266336187471834 33642:33642 +0.00011266336187471834 56773:56773 +0.00011266336187471834 57887:57887 +0.00011266336187471834 55743:55743 +0.00011266336187471834 60949:60949 +0.00011266336187471834 56702:56702 +0.00011266336187471834 58692:58692 +0.00011266336187471834 33637:33637 +0.00011266336187471834 56674:56674 +0.00011266336187471834 60085:60085 +0.00011266336187471834 59697:59697 +0.00011266336187471834 58723:58723 +0.00011266336187471834 58405:58405 +0.00011266336187471834 57195:57195 +0.00011266336187471834 33950:33950 +0.00011266336187471834 34225:34225 +0.00011266336187471834 33653:33653 +0.00011266336187471834 58847:58847 +0.00011266336187471834 58959:58959 +0.00011266336187471834 57983:57983 +0.00011266336187471834 33622:33622 +0.00011266336187471834 60681:60681 +0.00011266336187471834 33616:33616 +0.00011266336187471834 56397:56397 +0.00011266336187471834 33982:33982 +0.00011266336187471834 34565:34565 +0.00011266336187471834 33058:33058 +0.00011266336187471834 58853:58853 +0.00011266336187471834 58721:58721 +0.00011266336187471834 33173:33173 +0.00011266336187471834 57842:57842 +0.00011266336187471834 35379:35379 +0.00011266336187471834 60906:60906 +0.00011266336187471834 56134:56134 +0.00011266336187471834 55814:55814 +0.00011266336187471834 35233:35233 +0.00011266336187471834 35005:35005 +0.00011266336187471834 34312:34312 +0.00011266336187471834 35436:35436 +0.00011266336187471834 59657:59657 +0.00011266336187471834 59143:59143 +0.00011266336187471834 60109:60109 +0.00011266336187471834 58312:58312 +0.00011266336187471834 33200:33200 +0.00011266336187471834 56069:56069 +0.00011266336187471834 59342:59342 +0.00011266336187471834 56075:56075 +0.00011266336187471834 34202:34202 +0.00011266336187471834 34104:34104 +0.00011266336187471834 58614:58614 +0.00011266336187471834 55775:55775 +0.00011266336187471834 33707:33707 +0.00011266336187471834 33703:33703 +0.00011266336187471834 57959:57959 +0.00011266336187471834 34787:34787 +0.00011266336187471834 55753:55753 +0.00011266336187471834 34086:34086 +0.00011266336187471834 59250:59250 +0.00011266336187471834 60196:60196 +0.00011266336187471834 57470:57470 +0.00011266336187471834 55844:55844 +0.00011266336187471834 57046:57046 +0.00011266336187471834 59809:59809 +0.00011266336187471834 58948:58948 +0.00011266336187471834 33834:33834 +0.00011266336187471834 57876:57876 +0.00011266336187471834 34012:34012 +0.00011266336187471834 59723:59723 +0.00011266336187471834 59530:59530 +0.00011266336187471834 60106:60106 +0.00011266336187471834 58044:58044 +0.00011266336187471834 55620:55620 +0.00011266336187471834 34129:34129 +0.00011266336187471834 56913:56913 +0.00011266336187471834 56527:56527 +0.00011266336187471834 35181:35181 +0.00011266336187471834 34473:34473 +0.00011266336187471834 55679:55679 +0.00011266336187471834 35144:35144 +0.00011266336187471834 33833:33833 +0.00011266336187471834 33222:33222 +0.00011266336187471834 34450:34450 +0.00011266336187471834 59434:59434 +0.00011266336187471834 55712:55712 +0.00011266336187471834 60862:60862 +0.00011266336187471834 55697:55697 +0.00011266336187471834 35199:35199 +0.00011266336187471834 59979:59979 +0.00011266336187471834 34625:34625 +0.00011266336187471834 58146:58146 +0.00011266336187471834 34345:34345 +0.00011266336187471834 58774:58774 +0.00011266336187471834 58681:58681 +0.00011266336187471834 56310:56310 +0.00011266336187471834 34319:34319 +0.00011266336187471834 58480:58480 +0.00011266336187471834 60440:60440 +0.00011266336187471834 56320:56320 +0.00011266336187471834 55654:55654 +0.00011266336187471834 56056:56056 +0.00011266336187471834 58858:58858 +0.00011266336187471834 58223:58223 +0.00011266336187471834 60790:60790 +0.00011266336187471834 58526:58526 +0.00011266336187471834 33224:33224 +0.00011266336187471834 56643:56643 +0.00011266336187471834 55839:55839 +0.00011266336187471834 56238:56238 +0.00011266336187471834 57678:57678 +0.00011266336187471834 56124:56124 +0.00011266336187471834 35255:35255 +0.00011266336187471834 56218:56218 +0.00011266336187471834 33891:33891 +0.00011266336187471834 58369:58369 +0.00011266336187471834 57032:57032 +0.00011266336187471834 56080:56080 +0.00011266336187471834 55956:55956 +0.00011266336187471834 33248:33248 +0.00011266336187471834 60701:60701 +0.00011266336187471834 58300:58300 +0.00011266336187471834 59554:59554 +0.00011266336187471834 58132:58132 +0.00011266336187471834 35388:35388 +0.00011266336187471834 60303:60303 +0.00011266336187471834 58158:58158 +0.00011266336187471834 60645:60645 +0.00011266336187471834 33362:33362 +0.00011266336187471834 59543:59543 +0.00011266336187471834 58292:58292 +0.00011266336187471834 59388:59388 +0.00011266336187471834 56442:56442 +0.00011266336187471834 32878:32878 +0.00011266336187471834 35223:35223 +0.00011266336187471834 58819:58819 +0.00011266336187471834 58136:58136 +0.00011266336187471834 33939:33939 +0.00011266336187471834 34372:34372 +0.00011266336187471834 58176:58176 +0.00011266336187471834 58019:58019 +0.00011266336187471834 55737:55737 +0.00011266336187471834 60024:60024 +0.00011266336187471834 56336:56336 +0.00011266336187471834 33326:33326 +0.00011266336187471834 56591:56591 +0.00011266336187471834 34810:34810 +0.00011266336187471834 59007:59007 +0.00011266336187471834 59609:59609 +0.00011266336187471834 58760:58760 +0.00011266336187471834 57917:57917 +0.00011266336187471834 58218:58218 +0.00011266336187471834 33272:33272 +0.00011266336187471834 34231:34231 +0.00011266336187471834 58374:58374 +0.00011266336187471834 33656:33656 +0.00011266336187471834 35497:35497 +0.00011266336187471834 57483:57483 +0.00011266336187471834 32908:32908 +0.00011266336187471834 59183:59183 +0.00011266336187471834 57818:57818 +0.00011266336187471834 33878:33878 +0.00011266336187471834 33003:33003 +0.00011266336187471834 57091:57091 +0.00011266336187471834 60795:60795 +0.00011266336187471834 59695:59695 +0.00011266336187471834 56155:56155 +0.00011266336187471834 55665:55665 +0.00011266336187471834 33922:33922 +0.00011266336187471834 60466:60466 +0.00011266336187471834 34463:34463 +0.00011266336187471834 60243:60243 +0.00011266336187471834 58411:58411 +0.00011266336187471834 56656:56656 +0.00011266336187471834 34996:34996 +0.00011266336187471834 58362:58362 +0.00011266336187471834 35471:35471 +0.00011266336187471834 33357:33357 +0.00011266336187471834 57728:57728 +0.00011266336187471834 57516:57516 +0.00011266336187471834 34920:34920 +0.00011266336187471834 33931:33931 +0.00011266336187471834 33481:33481 +0.00011266336187471834 60417:60417 +0.00011266336187471834 57552:57552 +0.00011266336187471834 33863:33863 +0.00011266336187471834 60241:60241 +0.00011266336187471834 33465:33465 +0.00011266336187471834 58144:58144 +0.00011266336187471834 35415:35415 +0.00011266336187471834 33798:33798 +0.00011266336187471834 58425:58425 +0.00011266336187471834 33127:33127 +0.00011266336187471834 33078:33078 +0.00011266336187471834 33526:33526 +0.00011266336187471834 59887:59887 +0.00011266336187471834 58751:58751 +0.00011266336187471834 57946:57946 +0.00011266336187471834 57245:57245 +0.00011266336187471834 33681:33681 +0.00011266336187471834 59476:59476 +0.00011266336187471834 59362:59362 +# +-wc_wc +64,0.9984116479152879 32,1.0 +40,0.00026472534745201854 32,1.0 +55,0.00026472534745201854 23,1.0 +56,0.00026472534745201854 24,1.0 +62,0.00026472534745201854 30,1.0 +36,0.00026472534745201854 4,1.0 +52,0.00026472534745201854 20,1.0 +# +-wc_hi +# +-hi_wc +# +-hi_hi +# +-wc_lo +# +-lo_wc +# +-hi_lo +# +-lo_hi +# +-lo_lo +# +-wc_ar +# +-ar_wc +# +-hi_ar +# +-ar_hi +# +-wc_em +64,1.0 32,1.0 +# +-em_wc +# +-hi_em +# +-em_hi +# +-lo_ar +# +-ar_lo +# +-lo_em +# +-em_lo +# +-ar_ar +# +-ar_em +# +-em_ar +# +-em_em +64,1.0 32,1.0 +# +-snest +1 +# +-sskew +0 0.0 1.0 0.9889719219328158 +1 0.0 1.0 0.6585888077858881 +2 0.0 1.0 0.997082494498179 +3 0.75 0.25 0.9998044009779951 +4 0.8 0.2 0.961823535384303 +5 0.8333333333333334 0.16666666666666666 0.9978632478632479 +6 0.7142857142857143 0.2857142857142857 0.9098166127292342 +7 0.8888888888888888 0.1111111111111111 0.0 +8 0.7777777777777778 0.2222222222222222 0.9365384615384615 +9 0.7272727272727273 0.2727272727272727 0.957197856439339 +10 1.0 0.0 0.0 +11 1.0 0.0 0.0 +12 1.0 0.0 0.0 +13 0.9285714285714286 0.07142857142857142 0.5 +14 1.0 0.0 0.0 +15 1.0 0.0 0.0 +16 1.0 0.0 0.0 +17 0.9333333333333333 0.06666666666666667 0.9958847736625515 +18 0.8125 0.1875 0.24325092355782893 +19 0.7894736842105263 0.21052631578947367 0.7117055334830427 +20 1.0 0.0 0.0 +21 0.8260869565217391 0.17391304347826086 0.6953227931488801 +22 0.7037037037037037 0.2962962962962963 0.5713022165387894 +23 0.6571428571428571 0.34285714285714286 0.4480738059721748 +24 0.6595744680851063 0.3404255319148936 0.2589909102924567 +25 0.5166666666666667 0.48333333333333334 0.2002120733636143 +26 0.550561797752809 0.449438202247191 0.1436688471727894 +27 0.5193798449612403 0.4806201550387597 0.10299577214899797 +28 0.20512820512820512 0.7948717948717948 0.39740355852410186 +29 0.2857142857142857 0.7142857142857143 0.34246536796536803 +30 0.5333333333333333 0.4666666666666667 0.19494047619047622 +31 0.6742857142857143 0.32571428571428573 0.08646616541353384 +32 0.0 0.0 0.0 +# +-dnest +2 +# +-dskew +0 0.0 1.0 0.7320334742472607 +1 0.0 1.0 0.6482798833819242 +2 0.5 0.5 0.99867197875166 +3 0.6666666666666666 0.3333333333333333 0.0 +4 0.6666666666666666 0.3333333333333333 0.9990661841951675 +5 0.75 0.25 0.996720927509076 +6 0.8 0.2 0.9678472138281156 +7 1.0 0.0 0.0 +8 0.8333333333333334 0.16666666666666666 0.999516265570202 +9 0.8571428571428571 0.14285714285714285 0.9990315942379857 +10 1.0 0.0 0.0 +11 1.0 0.0 0.0 +12 1.0 0.0 0.0 +13 1.0 0.0 0.0 +14 1.0 0.0 0.0 +15 1.0 0.0 0.0 +16 0.875 0.125 0.696078431372549 +17 0.6666666666666666 0.3333333333333333 0.5857400547902921 +18 0.5 0.5 0.4346560846560847 +19 0.5555555555555556 0.4444444444444444 0.5687523342670401 +20 0.56 0.44 0.4505772005772006 +21 0.7777777777777778 0.2222222222222222 0.5625000000000001 +22 0.8636363636363636 0.13636363636363635 0.5474747474747474 +23 0.82 0.18 0.37029089175011926 +24 0.864406779661017 0.13559322033898305 0.2604166666666667 +25 0.8955223880597015 0.1044776119402985 0.16666666666666669 +26 0.8648648648648649 0.13513513513513514 0.316523400191022 +27 0.9285714285714286 0.07142857142857142 0.2456140350877193 +28 1.0 0.0 0.0 +29 1.0 0.0 0.0 +30 0.8888888888888888 0.1111111111111111 0.5 +31 1.0 0.0 0.0 +32 0.0 0.0 0.0 +# +-pcorr +1 0.0 +2 0.0 +3 0.0 +4 0.0 +5 0.0 +6 0.0 +7 0.0 +8 0.0 +9 0.0 +10 0.0 +11 0.0 +12 0.0 +13 0.0 +14 0.0 +15 0.0 +16 0.0 +17 0.0 +18 0.0 +19 0.0 +20 0.0 +21 0.0 +22 0.0 +23 0.0 +24 0.0 +25 0.0 +26 0.0 +27 0.0 +28 0.0 +29 0.0 +30 0.0 +31 0.0 +32 0.0 +# +-openflow +--- +in_port: + '37': 2 + '108': 2 + '311': 2 + '33': 2 + '41': 2 + '29': 2 + '134': 2 + '486': 2 + '91': 2 + '117': 2 + '61': 2 + '23': 2 + '106': 2 + '5': 2 + '49': 2 + '54': 2 + '107': 2 + '129': 2 + '81': 2 + '209': 2 + '42': 2 + '310': 2 + '37554': 1 + '37698': 1 + '37584': 1 + '37653': 1 + '37669': 1 + '37553': 1 + '37612': 1 + '37599': 1 + '37702': 1 + '37715': 1 + '37607': 1 + '37660': 1 + '37598': 1 + '37603': 1 + '37703': 1 + '37670': 1 + '37640': 1 + '37696': 1 + '37597': 1 + '36736': 1 + '37737': 1 + '37697': 1 + '37621': 1 + '37701': 1 + '37735': 1 + '37699': 1 + '37562': 1 + '37588': 1 + '37658': 1 + '37617': 1 + '36697': 1 + '37590': 1 + '37586': 1 + '37555': 1 + '37716': 1 + '37712': 1 + '37611': 1 + '37561': 1 + '37663': 1 + '37714': 1 + '37604': 1 + '36666': 1 + '36464': 1 + '37606': 1 + '37605': 1 + '37681': 1 + '37671': 1 + '37616': 1 + '37645': 1 + '36662': 1 + '37725': 1 + '37700': 1 + '36717': 1 + '36803': 1 + '37710': 1 + '37587': 1 + '37544': 1 + '37659': 1 + '37721': 1 + '37685': 1 + '37602': 1 + '36369': 1 + '37579': 1 + '37600': 1 + '37667': 1 + '37614': 1 + '37281': 1 + '37648': 1 + '37549': 1 + '37679': 1 + '37678': 1 + '37736': 1 + '37662': 1 + '37622': 1 + '37665': 1 + '36646': 1 + '37720': 1 + '37722': 1 + '37655': 1 + '37713': 1 + '37717': 1 + '37649': 1 + '37686': 1 + '37727': 1 + '37563': 1 + '37738': 1 + '37080': 1 + '37682': 1 + '37550': 1 + '37552': 1 + '37583': 1 + '37675': 1 + '37709': 1 + '36361': 1 + '37613': 1 + '37551': 1 + '37684': 1 + '37656': 1 + '37547': 1 + '36658': 1 + '37277': 1 + '37545': 1 + '36786': 1 + '37601': 1 + '37580': 1 + '37282': 1 + '37657': 1 + '37565': 1 + '37543': 1 + '37084': 1 + '37546': 1 + '37743': 1 + '37585': 1 + '37693': 1 + '37556': 1 + '37683': 1 + '37689': 1 + '37688': 1 +eth_type: + '0x800': 4774 +dl_src: + fa:16:3e: 235 +dl_dst: + 01:80:c2: 1 + 01:00:0c: 4 + 00:e0:2b: 3 + fa:16:3e: 15619 + ff:ff:ff: 12 + '01:00:00': 74 + c2:81:09: 16 + '00:50:56': 1 + '00:00:00': 4 +unique_vlan_ids_count: 0 +empty_rules_count: 3890 +rule_distribution: +- attributes: + - dl_dst + count: 1331 +- attributes: + - in_port + count: 162 +- attributes: + - dl_dst + - nw_dst + count: 88 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + - tp_dst + count: 528 +- attributes: + - nw_src + count: 6 +- attributes: + - nw_dst + - tp_dst + - tp_src + count: 137 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + - nw_src + count: 4170 +- attributes: + - nw_dst + count: 157 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + count: 16 +- attributes: + - dl_dst + - nw_dst + - tp_dst + - tp_src + count: 20 +- attributes: + - dl_dst + - nw_dst + - nw_src + count: 1390 +- attributes: + - dl_src + count: 57 +- attributes: + - dl_src + - nw_src + count: 118 +- attributes: + - dl_src + - eth_type + - nw_proto + - nw_src + count: 60 +- attributes: + - dl_dst + - nw_dst + - nw_src + - tp_dst + - tp_src + count: 8191 +# From 643ebf4e545d4fe61ff27173cc5cc373c0f12d7f Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 2 Feb 2017 14:01:06 +0100 Subject: [PATCH 04/51] vendor/Makefile [FEATURE]: added downloading of original ClassBench parameter files --- README.md | 4 +++- vendor/Makefile | 13 +++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8634d37..9c3203e 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,12 @@ Format of the generated rules can be one of the following: ``` sudo gem install open4 ruby-ip docopt ipaddress ``` + ## Installation ``` git clone https://github.com/classbench-ng/classbench-ng.git -make # Downloads, patches and compiles db_generator in ./vendor/db_generator +make # Downloads, patches and compiles original ClassBench in ./vendor/db_generator + # Downloads parameter files of original ClassBench to ./vendor/parameter_files ``` ### Patching ClassBench diff --git a/vendor/Makefile b/vendor/Makefile index 40238a6..cc82794 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -1,14 +1,23 @@ # Compilation of classbench +# Potential backup time +BACKUP_TIME=$(shell date --rfc-3339=seconds | tr ' ' '_') + all: compile download: - # Make backup of db_generator if exists - -[ -d db_generator ] && mv db_generator db_generator-$(shell date --rfc-3339=seconds | tr ' ' '_') + # Make backup of db_generator, if exists + -[ -d db_generator ] && mv db_generator db_generator-$(BACKUP_TIME) # Download and unpack ClassBench wget -O- -q http://www.arl.wustl.edu/classbench/db_generator.tar.gz | tar -xvz + # Make backup of parameter_files, if exists + -[ -d parameter_files ] && mv parameter_files parameter_files-$(BACKUP_TIME) + + # Download and unpack ClassBench + wget -O- -q http://www.arl.wustl.edu/classbench/parameter_files.tar.gz | tar -xvz + patch: download # Apply patches from ../patches git apply --directory=vendor/db_generator ../patches/ipv6.patch From a1a220b960cae49640ea6eb4e240f1920e538449 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Fri, 17 Feb 2017 17:46:12 +0100 Subject: [PATCH 05/51] .gitignore [FEATURE]: ignore directories with downloaded ClassBench parameter files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index fbb3d27..e3270a5 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ NOTES* .DS_Store vendor/db_generator vendor/db_generator-* +vendor/parameter_files +vendor/parameter_files-* From bbf1b4f1c0cb74995d4e69026190c701a5439e28 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Fri, 17 Feb 2017 17:48:35 +0100 Subject: [PATCH 06/51] vendor/Makefile [MAINTENANCE]: corrected typo in a comment --- vendor/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vendor/Makefile b/vendor/Makefile index cc82794..8d8688e 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -15,7 +15,7 @@ download: # Make backup of parameter_files, if exists -[ -d parameter_files ] && mv parameter_files parameter_files-$(BACKUP_TIME) - # Download and unpack ClassBench + # Download and unpack ClassBBnch parameter files wget -O- -q http://www.arl.wustl.edu/classbench/parameter_files.tar.gz | tar -xvz patch: download @@ -27,6 +27,5 @@ patch: download sed -i 's/200/20000/' db_generator/PortList.h compile: patch - # Recurse to ClassBench compilation make -C db_generator -B db_generator From e39996f62767ec7581253a79c03dda6086fa2ac2 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Fri, 17 Feb 2017 17:51:36 +0100 Subject: [PATCH 07/51] lib/classbench/generator.rb [FEATURE]: separate random generation of the device part of a src/dst MAC address --- lib/classbench/generator.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/classbench/generator.rb b/lib/classbench/generator.rb index 42ac08c..e453a73 100644 --- a/lib/classbench/generator.rb +++ b/lib/classbench/generator.rb @@ -143,7 +143,9 @@ def generate_rules(count) end return classbench_rules.map do |rule| + random_openflow_type = pregenerated_rule_types.sample + rule.remove_missing_attributes(random_openflow_type) #p random_openflow_type @@ -159,15 +161,16 @@ def generate_rules(count) rule.attributes["eth_type"] = pregenerated_eth_types.sample end - random_device_mac = (1..3).collect { "%02x" % [rand(255)] }.join(":") + random_dst_device_mac = (1..3).collect { "%02x" % [rand(255)] }.join(":") if attribute == "dl_dst" random_vendor = pregenerated_dl_dsts.sample - rule.attributes["dl_dst"] = random_vendor + ":" + random_device_mac + rule.attributes["dl_dst"] = random_vendor + ":" + random_dst_device_mac end + random_src_device_mac = (1..3).collect { "%02x" % [rand(255)] }.join(":") if attribute == "dl_src" random_vendor = pregenerated_dl_srcs.sample - rule.attributes["dl_src"] = random_vendor + ":" + random_device_mac + rule.attributes["dl_src"] = random_vendor + ":" + random_src_device_mac end if attribute == "dl_vlan" From 01b5f4d00dbd1e9d3e2f9a8b0dd05608b2503f5f Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Fri, 17 Feb 2017 17:54:58 +0100 Subject: [PATCH 08/51] OF rules generation [BUGFIX]: use a rule type with nw_proto/tp_src/tp_dst iff a ClassBench-generated rule contains a non-wildcard nw_proto/tp_src/tp_dst field --- lib/classbench/generator.rb | 9 ++++++++- lib/classbench/rule.rb | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/classbench/generator.rb b/lib/classbench/generator.rb index e453a73..2596875 100644 --- a/lib/classbench/generator.rb +++ b/lib/classbench/generator.rb @@ -144,7 +144,14 @@ def generate_rules(count) return classbench_rules.map do |rule| - random_openflow_type = pregenerated_rule_types.sample + begin + random_openflow_type = pregenerated_rule_types.sample + end while ((random_openflow_type.include?("nw_proto") and rule.attributes["nw_proto"] == 0) or + ((not random_openflow_type.include?("nw_proto")) and (not rule.attributes["nw_proto"] == 0)) or + (random_openflow_type.include?("tp_src") and rule.attributes["tp_src"] == (0..65535)) or + ((not random_openflow_type.include?("tp_src")) and (not rule.attributes["tp_src"] == (0..65535))) or + (random_openflow_type.include?("tp_dst") and rule.attributes["tp_dst"] == (0..65535)) or + ((not random_openflow_type.include?("tp_dst")) and (not rule.attributes["tp_dst"] == (0..65535)))) rule.remove_missing_attributes(random_openflow_type) diff --git a/lib/classbench/rule.rb b/lib/classbench/rule.rb index 47ce8d5..6a90997 100644 --- a/lib/classbench/rule.rb +++ b/lib/classbench/rule.rb @@ -101,6 +101,7 @@ def l2_vendor(type) def to_vswitch_format attributes.to_a. + reject {|k,v| k == "nw_proto" and v == 0}. # nw_proto is removed when wildcard reject {|k,v| v == (0..65535)}. # tp_src and tp_dst is removed when wildcard map {|k,v| (v.is_a?(Range) and v.first == v.last) ? [k, v.first] : [k,v] }. # if port range is [x..x] => x map {|k,v| "#{k}=#{v}" }.join(", ") # Openflow format From 8e2a414b2523f950deaee502529536bd583659d4 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Mon, 3 Apr 2017 17:58:33 +0200 Subject: [PATCH 09/51] README.md: language a typographical fixes --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9c3203e..a4a7f11 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ sudo gem install open4 ruby-ip docopt ipaddress ``` git clone https://github.com/classbench-ng/classbench-ng.git make # Downloads, patches and compiles original ClassBench in ./vendor/db_generator - # Downloads parameter files of original ClassBench to ./vendor/parameter_files + # Downloads the parameter files of original ClassBench to ./vendor/parameter_files ``` ### Patching ClassBench @@ -40,14 +40,14 @@ The output is an original ClassBench seed with an OpenFlow YAML structure as the ./classbench generate v4 SEED [--count=] [--db-generator=] ``` Generates IPv4 5-tuples or OpenFlow rules following properties from SEED. -OpenFlow rules are generated only if SEED contains OpenFlow section. +OpenFlow rules are generated only if SEED contains an OpenFlow section. - `--count=` specifies the number of generated 5-tuples/rules (default: `100`) -- `--db-generator=` specifies path to a ClassBench binary (default: `./vendor/db_generator/db_generator`) +- `--db-generator=` specifies the path to a ClassBench binary (default: `./vendor/db_generator/db_generator`) The output consists of `attribute=value` pairs joined by `, `. ``` -./classbench generate v6 [--count=] +./classbench generate v6 SEED [--count=] ``` Generates IPv6 5-tuples rules following properties from SEED. - `--count=` specifies the number of generated 5-tuples (default: `100`) From b1230b6f81f2762012e09f13e0975fbb3d931134 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 6 Apr 2017 15:01:00 +0200 Subject: [PATCH 10/51] Rules generation [MAINTENANCE]: separate command-line options for generation of IPv4, IPv6, and OpenFlow rule sets --- classbench | 12 +++++++++--- lib/classbench.rb | 12 ++++++++---- lib/classbench/generator.rb | 26 +++++++++++++++++--------- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/classbench b/classbench index 7d88359..3c0d952 100755 --- a/classbench +++ b/classbench @@ -11,7 +11,8 @@ Classbench utility Usage: #{__FILE__} analyse FILE #{__FILE__} generate v4 [--count=] [--db-generator=] - #{__FILE__} generate v6 [--count=] + #{__FILE__} generate v6 [--count=] [--db-generator=] + #{__FILE__} generate of [--count=] [--db-generator=] #{__FILE__} -h | --help #{__FILE__} version @@ -39,8 +40,13 @@ begin if opts["analyse"] Classbench::analyse(opts["FILE"]) elsif opts["generate"] - #pp opts - Classbench::generate(opts[""], (opts["--count"].to_i), opts["--db-generator"]) + if opts["v4"] + Classbench::generate("v4", opts[""], (opts["--count"].to_i), opts["--db-generator"]) + elsif opts["v6"] + Classbench::generate("v6", opts[""], (opts["--count"].to_i), opts["--db-generator"]) + elsif opts["of"] + Classbench::generate("of", opts[""], (opts["--count"].to_i), opts["--db-generator"]) + end elsif opts["version"] puts "Version: #{Classbench::VERSION}" end diff --git a/lib/classbench.rb b/lib/classbench.rb index b594031..bb5e05c 100644 --- a/lib/classbench.rb +++ b/lib/classbench.rb @@ -42,13 +42,17 @@ def self.analyse(filename) end - def self.generate(filename, count, db_generator_path) + def self.generate(format, filename, count, db_generator_path) generator = Generator.new(filename, db_generator_path) - has_openflow = generator.parse_seed + if format == "of" + if !generator.parse_seed + return + end + end #puts YAML.dump(generator.openflow_section) - rules = generator.generate_rules(count) - if has_openflow + rules = generator.generate_rules(format, count) + if format == "of" rules.map!(&:to_vswitch_format) end diff --git a/lib/classbench/generator.rb b/lib/classbench/generator.rb index 2596875..5fa26f3 100644 --- a/lib/classbench/generator.rb +++ b/lib/classbench/generator.rb @@ -113,15 +113,23 @@ def pregenerate_eth_types end ########################## - def generate_classbench_rules(count) + def generate_classbench_rules(format, count) current_dir = File.dirname(__FILE__) tmp_filters = Tempfile.new('filters') - # db_generator -c filename #{count} 0 0 0 tmp/#{rand} - # Call classbench - #system(current_dir+"/db_generator", "-c", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path, " > /dev/null") - pid, stdin, stdout, stderr = Open4::popen4(self.db_generator_path, "-c", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path) - ignored, status = Process::waitpid2 pid + if format == "v6" + # db_generator -c6 filename #{count} 0 0 0 tmp/#{rand} + # Call classbench + #system(current_dir+"/db_generator", "-c6", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path, " > /dev/null") + pid, stdin, stdout, stderr = Open4::popen4(self.db_generator_path, "-c6", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path) + ignored, status = Process::waitpid2 pid + else # format == "v4" || format format == "of" + # db_generator -c filename #{count} 0 0 0 tmp/#{rand} + # Call classbench + #system(current_dir+"/db_generator", "-c", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path, " > /dev/null") + pid, stdin, stdout, stderr = Open4::popen4(self.db_generator_path, "-c", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path) + ignored, status = Process::waitpid2 pid + end #STDERR.puts "done" #puts status @@ -135,10 +143,10 @@ def generate_classbench_rules(count) return raw_rules end - def generate_rules(count) - generate_classbench_rules(count) + def generate_rules(format, count) + generate_classbench_rules(format, count) - if not self.openflow_section + if format != "of" return self.raw_rules end From 082ebffe79cb1ee10ef6747e12790d265920a79b Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 6 Apr 2017 15:07:43 +0200 Subject: [PATCH 11/51] [MAINTENANCE]: source code cleanup --- classbench | 7 +++---- lib/classbench/generator.rb | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/classbench b/classbench index 3c0d952..f57c7d2 100755 --- a/classbench +++ b/classbench @@ -49,9 +49,8 @@ begin end elsif opts["version"] puts "Version: #{Classbench::VERSION}" - end - # TODO: --version + end -rescue Docopt::Exit => e - STDERR.puts e.message + rescue Docopt::Exit => e + STDERR.puts e.message end diff --git a/lib/classbench/generator.rb b/lib/classbench/generator.rb index 5fa26f3..4c7aa40 100644 --- a/lib/classbench/generator.rb +++ b/lib/classbench/generator.rb @@ -57,7 +57,7 @@ def parse_seed #p self.openflow_section rescue NoMethodError - STDERR.puts "No openflow section found in seed." + STDERR.puts "No openflow section found in the seed." return false end From afb3713f3926cb1bf1ad5c4a5c631a5543146c79 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 6 Apr 2017 15:08:49 +0200 Subject: [PATCH 12/51] usage [MAINTENANCE]: hidden command line parameter "version" --- classbench | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/classbench b/classbench index f57c7d2..7d06440 100755 --- a/classbench +++ b/classbench @@ -14,7 +14,6 @@ Usage: #{__FILE__} generate v6 [--count=] [--db-generator=] #{__FILE__} generate of [--count=] [--db-generator=] #{__FILE__} -h | --help - #{__FILE__} version Options: --db-generator= Path to binary of original db_generator [default: ./vendor/db_generator/db_generator] @@ -34,6 +33,9 @@ Generator accept's Classbench seed with openflow section. Output's one rule per line in format "attribute=value", joined by ", ". DOCOPT +# Add the following line to the DOCOPT's "Options" pattern to show support of +# "version" parameter. +# #{__FILE__} version begin opts = Docopt::docopt(doc) From 976e98d6afd4247c90203fd88a5e13da967b39b1 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Fri, 7 Apr 2017 09:10:45 +0200 Subject: [PATCH 13/51] [MAINTENANCE]: unified README.md and ClassBench-ng's command line help --- README.md | 33 +++++++++++++++++++++------------ classbench | 44 ++++++++++++++++++++++++-------------------- 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index a4a7f11..c2dfc14 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ClassBench-ng A tool for generation of synthetic classification rule sets for benchmarking, which is based on original (no longer maintained) [ClassBench](http://www.arl.wustl.edu/classbench/). -Format of the generated rules can be one of the following: +The format of the generated rules can be one of the following: - IPv4 5-tuple - IPv6 5-tuple - OpenFlow @@ -21,7 +21,7 @@ make # Downloads, patches and compiles original ClassBench in ./vendor/db_gene ### Patching ClassBench Original ClassBench is improved using patches in `./patches` directory and the size of its statically initialized arrays is increased, where necessary. -These changes are automatically applied on downloaded ClassBench during ClassBench-ng installation (see `./vendor/Makefile`). +These changes are automatically applied on downloaded original ClassBench during ClassBench-ng installation (see `./vendor/Makefile`). ## Usage ``` @@ -29,8 +29,8 @@ These changes are automatically applied on downloaded ClassBench during ClassBen ``` Analyses FILE, expecting FILE to be in the format used by `ovs-ofctl`. Fields extracted from FILE are: -- in_port -- dl_src, dl_dst, eth_type, dl_vlan, dl_vlan_pcp +- in_port, +- dl_src, dl_dst, eth_type, dl_vlan, dl_vlan_pcp, - nw_src, nw_dst, nw_tos, nw_proto, - tp_src, tp_dst @@ -39,18 +39,27 @@ The output is an original ClassBench seed with an OpenFlow YAML structure as the ``` ./classbench generate v4 SEED [--count=] [--db-generator=] ``` -Generates IPv4 5-tuples or OpenFlow rules following properties from SEED. -OpenFlow rules are generated only if SEED contains an OpenFlow section. -- `--count=` specifies the number of generated 5-tuples/rules (default: `100`) -- `--db-generator=` specifies the path to a ClassBench binary (default: `./vendor/db_generator/db_generator`) +Generates IPv4 5-tuples following the properties from SEED. +- `--count=` specifies the number of 5-tuples to be generated (default: `100`) +- `--db-generator=` specifies the path to an original ClassBench binary (default: `./vendor/db_generator/db_generator`) -The output consists of `attribute=value` pairs joined by `, `. +The output format is the same as of original ClassBench outputs. + +``` +./classbench generate v6 SEED [--count=] [--db-generator=] +``` +Generates IPv6 5-tuples following the properties from SEED. +- `--count=` specifies the number of 5-tuples to be generated (default: `100`) +- `--db-generator=` specifies the path to an original ClassBench binary (default: `./vendor/db_generator/db_generator`) + +The output format is the same as of original ClassBench outputs. ``` -./classbench generate v6 SEED [--count=] +./classbench generate of SEED [--count=] [--db-generator=] ``` -Generates IPv6 5-tuples rules following properties from SEED. -- `--count=` specifies the number of generated 5-tuples (default: `100`) +Generates OpenFlow rules following the properties from SEED that has to contain an OpenFlow section. +- `--count=` specifies the number of rules to be generated (default: `100`) +- `--db-generator=` specifies the path to an original ClassBench binary (default: `./vendor/db_generator/db_generator`) The output consists of `attribute=value` pairs joined by `, `. diff --git a/classbench b/classbench index 7d06440..3f9afc1 100755 --- a/classbench +++ b/classbench @@ -5,32 +5,36 @@ require_relative "lib/classbench" require "pp" require "docopt" doc = < [--count=] [--db-generator=] - #{__FILE__} generate v6 [--count=] [--db-generator=] - #{__FILE__} generate of [--count=] [--db-generator=] + #{__FILE__} generate v4 SEED [--count=] [--db-generator=] + #{__FILE__} generate v6 SEED [--count=] [--db-generator=] + #{__FILE__} generate of SEED [--count=] [--db-generator=] #{__FILE__} -h | --help Options: - --db-generator= Path to binary of original db_generator [default: ./vendor/db_generator/db_generator] - --count= Count of rules to generate [default: 100] + --db-generator= Path to an original ClassBench binary. + [default: ./vendor/db_generator/db_generator] + --count= The number of rules to be generated. + [default: 100] -h --help Show this screen. -Analyser accept's as input ovs-ofctl dump. -Fields extracted from dump are: - - dl_dst, dl_src, dl_type, (dl_vlan, dl_vlan_pcp,) - - eth_type, in_port, - - nw_dst, nw_proto, nw_src, nw_tos, - - tp_dst, tp_src -Output is original Classbench seed - with openflow YAML structure as last section. +Analyser accepts as an input an ovs-ofctl dump. +Fields extracted from the dump are: + - in_port, + - dl_src, dl_dst, eth_type, dl_vlan, dl_vlan_pcp, + - nw_src, nw_dst, nw_tos, nw_proto, + - tp_src, tp_dst +The output is an original ClassBench seed with an OpenFlow YAML structure as +the last section. -Generator accept's Classbench seed with openflow section. -Output's one rule per line in format "attribute=value", joined by ", ". +Generator accepts as an input an original ClassBench seed that has to contain +an OpenFlow section in case of "generate of". +The output is either the same as of original ClassBench outputs or it consists +of "attribute=value" pairs joined by ", ". DOCOPT # Add the following line to the DOCOPT's "Options" pattern to show support of @@ -43,11 +47,11 @@ begin Classbench::analyse(opts["FILE"]) elsif opts["generate"] if opts["v4"] - Classbench::generate("v4", opts[""], (opts["--count"].to_i), opts["--db-generator"]) + Classbench::generate("v4", opts["SEED"], (opts["--count"].to_i), opts["--db-generator"]) elsif opts["v6"] - Classbench::generate("v6", opts[""], (opts["--count"].to_i), opts["--db-generator"]) + Classbench::generate("v6", opts["SEED"], (opts["--count"].to_i), opts["--db-generator"]) elsif opts["of"] - Classbench::generate("of", opts[""], (opts["--count"].to_i), opts["--db-generator"]) + Classbench::generate("of", opts["SEED"], (opts["--count"].to_i), opts["--db-generator"]) end elsif opts["version"] puts "Version: #{Classbench::VERSION}" From 9f89ec26f77ed920e43e635846b061f8e3d931c6 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Mon, 12 Jun 2017 11:11:54 +0200 Subject: [PATCH 14/51] Create LICENSE --- LICENSE | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From 3bc209fe2c2104c8132cd3e1b02effbc09481cbb Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Fri, 7 Jul 2017 17:31:44 +0200 Subject: [PATCH 15/51] ipv6_patch [FEATURE]: extended patch that also corects memory handling --- patches/ipv6.patch | 281 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 259 insertions(+), 22 deletions(-) diff --git a/patches/ipv6.patch b/patches/ipv6.patch index 5e92174..95fb650 100644 --- a/patches/ipv6.patch +++ b/patches/ipv6.patch @@ -1,5 +1,33 @@ +diff --git a/ExtraList.cc b/ExtraList.cc +index d09f0aa..4b309fe 100644 +--- a/ExtraList.cc ++++ b/ExtraList.cc +@@ -17,6 +17,7 @@ ExtraList::ExtraList(int P1) { + for (int i = 1; i <= P; i++){ + // Create header list + struct ExtraListHeader *temp = new struct ExtraListHeader; ++ temp->field = NULL; + temp->next = NULL; + temp->prev = last; + if (i == 1) { +@@ -39,11 +40,12 @@ ExtraList::~ExtraList() { + for (int j = 0; j < N; j++){ + tempI = temp->field[j]; + // Delete list of values +- delete(tempI->value); +- delete(tempI->prob); ++ delete[] (tempI->value); ++ delete[] (tempI->prob); ++ delete(tempI); + } + first = first->next; +- delete(temp->field); ++ delete[] (temp->field); + delete(temp); + } + } diff --git a/FilterList.cc b/FilterList.cc -index c123529..fce2c09 100644 +index c123529..4677276 100644 --- a/FilterList.cc +++ b/FilterList.cc @@ -11,6 +11,9 @@ @@ -12,7 +40,44 @@ index c123529..fce2c09 100644 FilterList::FilterList() { first = last = NULL; -@@ -125,35 +128,66 @@ void FilterList::push(struct filter filt) { +@@ -20,6 +23,9 @@ FilterList::FilterList() { + FilterList::~FilterList() { + struct FilterList_item *temp; + while (first != NULL) { ++ if (first->filt.num_ext_field > 0) { ++ delete[] (first->filt.ext_field); ++ } + temp = first->next; + delete(first); + first = temp; +@@ -57,7 +63,7 @@ struct FilterList_item* FilterList::operator()(int i) { + void FilterList::insert(struct FilterList_item *item, struct filter filt) { + struct FilterList_item *newitem; + newitem = new struct FilterList_item; +- newitem->filt = filt; ++ copy_filter(newitem->filt, filt); + newitem->prev = item->prev; + newitem->next = item; + if (first == item) first = newitem; +@@ -72,7 +78,7 @@ void FilterList::insert(struct FilterList_item *item, struct filter filt) { + void FilterList::operator&=(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->prev = last; + temp->next = NULL; + if (num == 0){ +@@ -110,7 +116,7 @@ void FilterList::operator=(FilterList* L) { + void FilterList::push(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->next = first; + temp->prev = NULL; + if (num == 0){ +@@ -125,35 +131,66 @@ void FilterList::push(struct filter filt) { // Print the contents of the FilterList. void FilterList::print(FILE* fp) { @@ -103,11 +168,39 @@ index c123529..fce2c09 100644 // Print source port fprintf(fp, "%d : %d\t", tempfilt->filt.sp[0], tempfilt->filt.sp[1]); +diff --git a/FlagList.cc b/FlagList.cc +index 074c4e7..9a214cf 100644 +--- a/FlagList.cc ++++ b/FlagList.cc +@@ -27,8 +27,8 @@ FlagList::~FlagList() { + first[i] = temp; + } + } +- delete(first); +- delete(last); ++ delete[] (first); ++ delete[] (last); + } + + void FlagList::choose(float p, int prot, unsigned *flags, unsigned *flags_mask){ +diff --git a/PortList.cc b/PortList.cc +index 34ad3c2..4b26d15 100644 +--- a/PortList.cc ++++ b/PortList.cc +@@ -22,7 +22,7 @@ PortList::PortList(int N1) { + } + } + +-PortList::~PortList() { delete ports; } ++PortList::~PortList() { delete[] ports; } + + void PortList::read(int t, FILE *fp) { + int done = 0; diff --git a/PrefixList.cc b/PrefixList.cc -index a3df1dc..740d7ea 100644 +index a3df1dc..c3e23e5 100644 --- a/PrefixList.cc +++ b/PrefixList.cc -@@ -11,14 +11,14 @@ +@@ -11,21 +11,21 @@ #include "PrefixList.h" PrefixList::PrefixList() { @@ -124,6 +217,15 @@ index a3df1dc..740d7ea 100644 } } } + + PrefixList::~PrefixList() { +- for (int type = 0; type < 25; type++) delete prefixes[type]; +- delete prefixes; ++ for (int type = 0; type < 25; type++) delete[] prefixes[type]; ++ delete[] prefixes; + } + + void PrefixList::read(FILE* fp){ @@ -102,14 +102,14 @@ void PrefixList::read_type(int type, FILE *fp) { int tlen = 0; int slen = 0; @@ -313,6 +415,21 @@ index 2d39529..1df63a2 100644 }; class PrefixList { +diff --git a/ProtList.cc b/ProtList.cc +index a4bc451..b9bd739 100644 +--- a/ProtList.cc ++++ b/ProtList.cc +@@ -24,8 +24,8 @@ ProtList::ProtList() { + } + + ProtList::~ProtList() { +- for (int i = 0; i < 25; i++) delete protocols[i].pt_prob; +- delete protocols; ++ for (int i = 0; i < 25; i++) delete[] protocols[i].pt_prob; ++ delete[] protocols; + } + + void ProtList::read(FILE *fp) { diff --git a/README b/README index 116aac2..f104e85 100644 --- a/README @@ -346,9 +463,18 @@ index 116aac2..f104e85 100644 -flags diff --git a/TupleBST.cc b/TupleBST.cc -index 9163d9b..32e0cc8 100644 +index 9163d9b..911f1d5 100644 --- a/TupleBST.cc +++ b/TupleBST.cc +@@ -17,7 +17,7 @@ TupleBST::TupleBST() { + + TupleBST::~TupleBST() { + if (root != NULL) cleanup(root); +- delete(ListOfFilterIndexPtrs); ++ delete[] (ListOfFilterIndexPtrs); + } + + void TupleBST::cleanup(TupleBST_item* node){ @@ -34,7 +34,7 @@ void TupleBST::cleanup(TupleBST_item* node){ int TupleBST::scope(FiveTuple* ftuple){ @@ -359,7 +485,7 @@ index 9163d9b..32e0cc8 100644 } diff --git a/custom_db.cc b/custom_db.cc -index 6f8d193..0484e53 100644 +index 6f8d193..ccb8b2e 100644 --- a/custom_db.cc +++ b/custom_db.cc @@ -20,7 +20,9 @@ @@ -372,7 +498,40 @@ index 6f8d193..0484e53 100644 int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothness, float addr_scope, float port_scope, int branch){ -@@ -464,33 +466,64 @@ void select_ports(int port_type, struct filter *temp_filter, PortList *sparL, Po +@@ -81,6 +83,9 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + // Temporary filter + // struct filter temp_filter; + struct filter *temp_filters = new struct filter[num_filters+1]; ++ for (int i = 0; i < num_filters+1; i++) { ++ temp_filters[i].num_ext_field = 0; ++ } + dlist *Flist = new dlist; + struct range temp_range; + struct ppair temp_ppair; +@@ -143,6 +148,8 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + printf(" \tdone\n"); + // Free up memory + delete(protL); ++ delete(flagL); ++ delete(extraL); + delete(sparL); + delete(spemL); + delete(dparL); +@@ -219,7 +226,12 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + // printf(" \tdone\n"); + + // Delete data structures +- delete(temp_filters); ++ for (int i = 0; i < num_filters+1; i++) { ++ if (temp_filters[i].num_ext_field > 0) { ++ delete[] (temp_filters[i].ext_field); ++ } ++ } ++ delete[] (temp_filters); + // printf("Done with custom_db\n"); + + return filter_cnt; +@@ -464,33 +476,64 @@ void select_ports(int port_type, struct filter *temp_filter, PortList *sparL, Po } void fprint_filter(FILE *fp, struct filter *filt){ @@ -561,7 +720,7 @@ index 3344759..afa53fb 100644 } diff --git a/dbintree.cc b/dbintree.cc -index 9274710..a2f76d1 100644 +index 9274710..9a53299 100644 --- a/dbintree.cc +++ b/dbintree.cc @@ -13,13 +13,13 @@ @@ -583,7 +742,30 @@ index 9274710..a2f76d1 100644 skew[u] = 0; corr[u] = 0; p1child[u] = 0; -@@ -99,13 +99,13 @@ void dbintree::read_skew(FILE* fp_in){ +@@ -28,10 +28,10 @@ dbintree::dbintree() { + } + + dbintree::~dbintree() { +- delete(skew); +- delete(corr); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (corr); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } +@@ -39,6 +39,7 @@ dbintree::~dbintree() { + void dbintree::delete_node(struct tnode *me){ + if (me->child0 != NULL) delete_node(me->child0); + if (me->child1 != NULL) delete_node(me->child1); ++ delete(me->stubList); + delete(me); + return; + } +@@ -99,13 +100,13 @@ void dbintree::read_skew(FILE* fp_in){ // printf("matches = %d\n",matches); // printf("level = %d, skew = %.4f\n",level,skew); if (matches == 4) { @@ -599,7 +781,7 @@ index 9274710..a2f76d1 100644 exit(1); } // printf("Read line: %d\t%.4f\t%.4f\t%.4f\n",level,p1_t,p2_t,f_skew); -@@ -147,7 +147,7 @@ void dbintree::read_corr(FILE* fp_in){ +@@ -147,7 +148,7 @@ void dbintree::read_corr(FILE* fp_in){ void dbintree::print_skew(FILE *fp) { fprintf(fp,"Level\tp1\tp2\tSkew\n"); @@ -608,7 +790,7 @@ index 9274710..a2f76d1 100644 fprintf(fp,"%d\t%.4f\t%.4f\t%.4f\n", i,p1child[i],p2child[i],skew[i]); } -@@ -157,14 +157,14 @@ void dbintree::print_skew(FILE *fp) { +@@ -157,14 +158,14 @@ void dbintree::print_skew(FILE *fp) { void dbintree::print_corr(FILE *fp) { fprintf(fp,"Level\tCorr\n"); @@ -625,7 +807,7 @@ index 9274710..a2f76d1 100644 // Create copy of list dlist *temp_list = new dlist(); (*temp_list)=(Flist); -@@ -221,7 +221,7 @@ void dbintree::add2child_stublist(struct tnode *node, int dir, int filt){ +@@ -221,7 +222,7 @@ void dbintree::add2child_stublist(struct tnode *node, int dir, int filt){ return; } @@ -634,7 +816,7 @@ index 9274710..a2f76d1 100644 int Flist_size = 0; int lev = node->lvl; -@@ -237,21 +237,21 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str +@@ -237,21 +238,21 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str // printf("Flist_size = %d\n",Flist_size); double temp; @@ -663,7 +845,7 @@ index 9274710..a2f76d1 100644 } // Allocate temp_list's -@@ -297,7 +297,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str +@@ -297,7 +298,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str // printf("Flist_size = %d, tempList: ",Flist_size); tempList->print(stdout); printf("\n"); // if lev1_flag == 1, dump all lev1 filters to one side // printf("lev = %d, MyNest = %d, Nest = %d, lev1_flag = %d\n",lev,MyNest,Nest,lev1_flag); @@ -672,7 +854,7 @@ index 9274710..a2f76d1 100644 // printf("add_stub: Enforcing nesting limit\n"); // Add all filters to stublist and let the finish_node process distribute them int fptr; -@@ -331,7 +331,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str +@@ -331,7 +332,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str // sa_len > lvl // Prevent prefix nesting sa = sa << lev; @@ -681,7 +863,7 @@ index 9274710..a2f76d1 100644 // sa now equals next "bit" of source address if (filters[fptr].sa_len == (lev+1)) { // Source prefix will be exhausted at next level -@@ -407,7 +407,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str +@@ -407,7 +408,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str return; } @@ -690,7 +872,7 @@ index 9274710..a2f76d1 100644 int Flist_size = 0; int stubList_size = 0; int lev = node->lvl; -@@ -479,20 +479,20 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, +@@ -479,20 +480,20 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, double temp; int path; @@ -717,7 +899,7 @@ index 9274710..a2f76d1 100644 } // Create an empty list -@@ -519,7 +519,7 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, +@@ -519,7 +520,7 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, // If at the nesting threshold and list has more than one child, // then split list (allocate all nodes with level == lev1 to one path) // printf("lev = %d, MyNest = %d, Nest = %d, lev1_flag = %d\n",lev,MyNest,Nest,lev1_flag); @@ -5271,7 +5453,7 @@ index 0000000..2f10279 diff --git a/makefile b/makefile old mode 100755 new mode 100644 -index 773f4c1..2c86037 +index 773f4c1..ca7b1d8 --- a/makefile +++ b/makefile @@ -9,8 +9,9 @@ @@ -5281,7 +5463,7 @@ index 773f4c1..2c86037 +LIB = -I./ip-address/include ##CFLAGS = -g -pg -CFLAGS = -O2 -+CFLAGS = -O2 -g -std=c++11 $(LIB) ++CFLAGS = -O2 -std=c++11 $(LIB) .cc.o: ${CC} ${CFLAGS} -c $*.cc @@ -5438,7 +5620,7 @@ index 38771e7..fbac9d3 100644 // Check source address match diff --git a/sbintree.cc b/sbintree.cc -index d755099..6a83b51 100644 +index d755099..062fbaf 100644 --- a/sbintree.cc +++ b/sbintree.cc @@ -13,12 +13,12 @@ @@ -5458,6 +5640,19 @@ index d755099..6a83b51 100644 skew[u] = 0; p1child[u] = 0; p2child[u] = 0; +@@ -26,9 +26,9 @@ sbintree::sbintree() { + } + + sbintree::~sbintree() { +- delete(skew); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } @@ -96,13 +96,13 @@ void sbintree::read_skew(FILE* fp_in){ // printf("matches = %d\n",matches); // printf("level = %d, skew = %.4f\n",level,skew); @@ -5536,6 +5731,17 @@ index d755099..6a83b51 100644 // Allocate nest_list dlist *nest_list = new dlist(); dlist *other_list = new dlist(); +@@ -291,6 +291,10 @@ void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr + add_node(me, lev1, 1, addr1, other_list, filters, MyNest); + } + } ++ ++ // Deallocate nest_list ++ delete(nest_list); ++ delete(other_list); + } + else { + // Othewise, branch based on branching probability and skew diff --git a/sbintree.h b/sbintree.h index b085696..937d941 100644 --- a/sbintree.h @@ -5550,7 +5756,7 @@ index b085696..937d941 100644 public: sbintree(); diff --git a/stdinc.h b/stdinc.h -index f566e0f..f731846 100644 +index f566e0f..3c2f685 100644 --- a/stdinc.h +++ b/stdinc.h @@ -10,6 +10,7 @@ @@ -5589,6 +5795,37 @@ index f566e0f..f731846 100644 int sa_len; // IP source address mask length int da_len; // IP destination address mask length int sp[2]; // Transport source port range [low,high] +@@ -69,6 +70,30 @@ struct filter { + int *ext_field; // Pointer to array of extra header fields + }; + ++// Do a deep copy of orig filter ++inline void copy_filter(struct filter& copy, struct filter orig) { ++ copy.sa = orig.sa; ++ copy.da = orig.da; ++ copy.sa_len = orig.sa_len; ++ copy.da_len = orig.da_len; ++ copy.sp[0] = orig.sp[0]; ++ copy.sp[1] = orig.sp[1]; ++ copy.dp[0] = orig.dp[0]; ++ copy.dp[1] = orig.dp[1]; ++ copy.prot_num = orig.prot_num; ++ copy.flags = orig.flags; ++ copy.flags_mask = orig.flags_mask; ++ copy.num_ext_field = orig.num_ext_field; ++ if (copy.num_ext_field > 0) { ++ copy.ext_field = new int[copy.num_ext_field]; ++ for (int i = 0; i < copy.num_ext_field; i++) { ++ copy.ext_field[i] = orig.ext_field[i]; ++ } ++ } else { ++ copy.ext_field = NULL; ++ } ++} ++ + struct range { + int low; + int high; diff --git a/uint128_t.cc b/uint128_t.cc new file mode 100644 index 0000000..1e16bbd From fac75261af193d164a423f8b790ef0250ae53107 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Mon, 10 Jul 2017 09:47:58 +0200 Subject: [PATCH 16/51] patches [FEATURE]: patch with improvements of IP prefixes generation in the original ClassBench and patch combining ClassBench improvements with IPv6 support --- patches/improvements.patch | 9463 +++++++++++++++++++++++++ patches/improvements_ipv6.patch | 11178 ++++++++++++++++++++++++++++++ vendor/Makefile | 4 +- 3 files changed, 20644 insertions(+), 1 deletion(-) create mode 100644 patches/improvements.patch create mode 100644 patches/improvements_ipv6.patch diff --git a/patches/improvements.patch b/patches/improvements.patch new file mode 100644 index 0000000..2323a82 --- /dev/null +++ b/patches/improvements.patch @@ -0,0 +1,9463 @@ +diff --git a/ExtraList.cc b/ExtraList.cc +index d09f0aa..4b309fe 100644 +--- a/ExtraList.cc ++++ b/ExtraList.cc +@@ -17,6 +17,7 @@ ExtraList::ExtraList(int P1) { + for (int i = 1; i <= P; i++){ + // Create header list + struct ExtraListHeader *temp = new struct ExtraListHeader; ++ temp->field = NULL; + temp->next = NULL; + temp->prev = last; + if (i == 1) { +@@ -39,11 +40,12 @@ ExtraList::~ExtraList() { + for (int j = 0; j < N; j++){ + tempI = temp->field[j]; + // Delete list of values +- delete(tempI->value); +- delete(tempI->prob); ++ delete[] (tempI->value); ++ delete[] (tempI->prob); ++ delete(tempI); + } + first = first->next; +- delete(temp->field); ++ delete[] (temp->field); + delete(temp); + } + } +diff --git a/FilterList.cc b/FilterList.cc +index c123529..2467dfd 100644 +--- a/FilterList.cc ++++ b/FilterList.cc +@@ -17,9 +17,12 @@ FilterList::FilterList() { + num = 0; + } + +-FilterList::~FilterList() { ++FilterList::~FilterList() { + struct FilterList_item *temp; + while (first != NULL) { ++ if (first->filt.num_ext_field > 0) { ++ delete[] (first->filt.ext_field); ++ } + temp = first->next; + delete(first); + first = temp; +@@ -41,7 +44,7 @@ void FilterList::clear() { + struct FilterList_item* FilterList::operator()(int i) { + if (i <= 0 || (i > num && num > 0)) { + fprintf(stderr,"FilterList::operator(): item %d out of range, num = %d\n",i,num); +- exit(1); ++ exit(1); + } + // Items are maintained in-order + // Index i items to the "right" +@@ -57,7 +60,7 @@ struct FilterList_item* FilterList::operator()(int i) { + void FilterList::insert(struct FilterList_item *item, struct filter filt) { + struct FilterList_item *newitem; + newitem = new struct FilterList_item; +- newitem->filt = filt; ++ copy_filter(newitem->filt, filt); + newitem->prev = item->prev; + newitem->next = item; + if (first == item) first = newitem; +@@ -72,7 +75,7 @@ void FilterList::insert(struct FilterList_item *item, struct filter filt) { + void FilterList::operator&=(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->prev = last; + temp->next = NULL; + if (num == 0){ +@@ -110,7 +113,7 @@ void FilterList::operator=(FilterList* L) { + void FilterList::push(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->next = first; + temp->prev = NULL; + if (num == 0){ +@@ -121,14 +124,14 @@ void FilterList::push(struct filter filt) { + first = temp; + num++; + return; +-} ++} + + // Print the contents of the FilterList. + void FilterList::print(FILE* fp) { + int addr[4]; + unsigned temp; + struct FilterList_item *tempfilt; +- ++ + for (tempfilt = first; tempfilt != NULL; tempfilt = tempfilt->next){ + // Print new filter character + fprintf(fp,"@"); +@@ -143,7 +146,7 @@ void FilterList::print(FILE* fp) { + fprintf(fp, "%d.%d.%d.%d/%d\t", + addr[0], addr[1], addr[2], addr[3], + tempfilt->filt.sa_len); +- // Print destination address ++ // Print destination address + addr[0] = addr[1] = addr[2] = addr[3] = 0; + temp = 0; + temp = tempfilt->filt.da; +@@ -154,13 +157,13 @@ void FilterList::print(FILE* fp) { + fprintf(fp, "%d.%d.%d.%d/%d\t", + addr[0], addr[1], addr[2], addr[3], + tempfilt->filt.da_len); +- // Print source port ++ // Print source port + fprintf(fp, "%d : %d\t", + tempfilt->filt.sp[0], tempfilt->filt.sp[1]); +- // Print destination port ++ // Print destination port + fprintf(fp, "%d : %d\t", + tempfilt->filt.dp[0], tempfilt->filt.dp[1]); +- // Print protocol ++ // Print protocol + if (tempfilt->filt.prot_num == 0) fprintf(fp, "0x00/0x00\t"); + else fprintf(fp, "0x%02x/0xFF\t", tempfilt->filt.prot_num); + // Print flags +@@ -170,8 +173,8 @@ void FilterList::print(FILE* fp) { + for (int j = 0; j < tempfilt->filt.num_ext_field; j++){ + fprintf(fp, "%d\t", + tempfilt->filt.ext_field[j]); +- } +- // Print newline ++ } ++ // Print newline + fprintf(fp,"\n"); + } + } +diff --git a/FlagList.cc b/FlagList.cc +index 074c4e7..9a214cf 100644 +--- a/FlagList.cc ++++ b/FlagList.cc +@@ -27,8 +27,8 @@ FlagList::~FlagList() { + first[i] = temp; + } + } +- delete(first); +- delete(last); ++ delete[] (first); ++ delete[] (last); + } + + void FlagList::choose(float p, int prot, unsigned *flags, unsigned *flags_mask){ +diff --git a/PortList.cc b/PortList.cc +index 34ad3c2..4b26d15 100644 +--- a/PortList.cc ++++ b/PortList.cc +@@ -22,7 +22,7 @@ PortList::PortList(int N1) { + } + } + +-PortList::~PortList() { delete ports; } ++PortList::~PortList() { delete[] ports; } + + void PortList::read(int t, FILE *fp) { + int done = 0; +diff --git a/PrefixList.cc b/PrefixList.cc +index a3df1dc..58f75e1 100644 +--- a/PrefixList.cc ++++ b/PrefixList.cc +@@ -24,8 +24,8 @@ PrefixList::PrefixList() { + } + + PrefixList::~PrefixList() { +- for (int type = 0; type < 25; type++) delete prefixes[type]; +- delete prefixes; ++ for (int type = 0; type < 25; type++) delete[] prefixes[type]; ++ delete[] prefixes; + } + + void PrefixList::read(FILE* fp){ +diff --git a/ProtList.cc b/ProtList.cc +index a4bc451..b9bd739 100644 +--- a/ProtList.cc ++++ b/ProtList.cc +@@ -24,8 +24,8 @@ ProtList::ProtList() { + } + + ProtList::~ProtList() { +- for (int i = 0; i < 25; i++) delete protocols[i].pt_prob; +- delete protocols; ++ for (int i = 0; i < 25; i++) delete[] protocols[i].pt_prob; ++ delete[] protocols; + } + + void ProtList::read(FILE *fp) { +diff --git a/README b/README +index 116aac2..f104e85 100644 +--- a/README ++++ b/README +@@ -75,17 +75,17 @@ PPC + 10 AR/WC source port arbitrary range, destination port wildcard + 11 HI/AR source port [1024:65535], destination port arbitrary range + 12 AR/HI source port arbitrary range, destination port [1024:65535] +-13 LO/AR source port [0:1023], destination port arbitrary range +-14 AR/LO source port arbitrary range, destination port [0:1023] +-15 AR/AR source port arbitrary range, destination port arbitrary range +-16 WC/EM source port wildcard, destination port exact match +-17 EM/WC source port exact match, destination port wildcard +-18 HI/EM source port [1024:65535], destination port exact match +-19 EM/HI source port exact match, destination port [1024:65535] +-20 LO/EM source port [0:1023], destination port exact match +-21 EM/LO source port exact match, destination port [0:1023] ++13 WC/EM source port wildcard, destination port exact match ++14 EM/WC source port exact match, destination port wildcard ++15 HI/EM source port [1024:65535], destination port exact match ++16 EM/HI source port exact match, destination port [1024:65535] ++17 LO/AR source port [0:1023], destination port arbitrary range ++18 AR/LO source port arbitraty range, destination port [0:1023] ++19 LO/EM source port [0:1023], destination port exact match ++20 EM/LO source port exact match, destination port [0:1023] ++21 AR/AR source port arbitraty range, destination port arbitrary range + 22 AR/EM source port arbitrary range, destination port exact match +-23 EM/AR source port exact match, destination port exact match arbitrary range ++23 EM/AR source port exact match, destination port arbitrary range + 24 EM/EM source port exact match, destination port exact match + + -flags +diff --git a/TupleBST.cc b/TupleBST.cc +index 9163d9b..da91dcc 100644 +--- a/TupleBST.cc ++++ b/TupleBST.cc +@@ -17,7 +17,7 @@ TupleBST::TupleBST() { + + TupleBST::~TupleBST() { + if (root != NULL) cleanup(root); +- delete(ListOfFilterIndexPtrs); ++ delete[] (ListOfFilterIndexPtrs); + } + + void TupleBST::cleanup(TupleBST_item* node){ +diff --git a/custom_db.cc b/custom_db.cc +index 6f8d193..3ec8a52 100644 +--- a/custom_db.cc ++++ b/custom_db.cc +@@ -20,15 +20,58 @@ + #include "redundant_filter_check.h" + #include "TupleBST.h" + #include "custom_db.h" ++#include "ip_prefix.h" ++#include "trie.h" ++#include "filter_graph.h" ++ ++ ++/* ++ * Transforms a pruned source/destination trie into a set of edges from/to the ++ * 's'/'t' node in the filter graph. ++ * The given trie is recursively traversed. When the traversed node is a prefix ++ * node, adding of the corresponding edge from/to the 's'/'t' node of the ++ * filter graph is triggered. Weight of the added edge is set according to the ++ * number of prefixes represented by the current prefix node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node A pointer to the current trie node. ++ * @param src_trie The trie node referenced by parameter node belongs to ++ * the source trie (TRUE) or the destination trie (FALSE). ++ * @param prefix_str The prefix represented by the current node encoded as a ++ * string of bit values. ++ * @param graph A pointer to the filter graph object. ++ */ ++void trie_to_graph(const trie_node* node, bool src_trie, string prefix_str, Filter_graph* graph) { ++ if (node != NULL) { // non-empty subtree ++ int prefix_count = node->prefixes; ++ if (prefix_count > 0) { // prefix node ++ // add current prefix to the filter graph, either as "s_prefix" or as "t_prefix" ++ IP_prefix prefix(prefix_str, true); ++ if (src_trie) { ++ graph->add_s_prefix(prefix, prefix_count); ++ } else { ++ graph->add_t_prefix(prefix, prefix_count); ++ } ++ } ++ // call this function on both zero and one subtrees ++ trie_to_graph(node->zero, src_trie, prefix_str + "0", graph); ++ trie_to_graph(node->one, src_trie, prefix_str + "1", graph); ++ } else { // empty subtree ++ return; ++ } ++} // end trie_to_graph() + + + int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothness, float addr_scope, float port_scope, int branch){ + ++ // generate 100 times more filters (because of successive trie pruning) ++ int temp_num_filters = num_filters * 100; ++ + printf("Initializing data structures...\n"); + // Read in scale + int scale = read_scale(fp_in); + // printf("scale = %d\n",scale); +- float scale_factor = (float)num_filters/(float)scale; ++ float scale_factor = (float)temp_num_filters/(float)scale; + // printf("scale_factor = %.4f\n",scale); + + // Read protocol parameters, initialize data structure +@@ -80,7 +123,10 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + + // Temporary filter + // struct filter temp_filter; +- struct filter *temp_filters = new struct filter[num_filters+1]; ++ struct filter *temp_filters = new struct filter[temp_num_filters+1]; ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ temp_filters[i].num_ext_field = 0; ++ } + dlist *Flist = new dlist; + struct range temp_range; + struct ppair temp_ppair; +@@ -89,7 +135,7 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + printf("Creating application specifications...\n"); + + // For all filters: +- for (int i = 1; i <= num_filters; i++){ ++ for (int i = 1; i <= temp_num_filters; i++){ + // Select a protocol via random number + p = drand48(); + temp_filters[i].prot_num = protL->choose_prot((float)p); +@@ -143,6 +189,8 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + printf(" \tdone\n"); + // Free up memory + delete(protL); ++ delete(flagL); ++ delete(extraL); + delete(sparL); + delete(spemL); + delete(dparL); +@@ -180,10 +228,9 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + } + // printf("Flist = "); (*Flist).print(stdout); printf("\n"); + (*Stree).build_tree(Flist,temp_filters); +- delete(Stree); + /* + printf("Flist = "); (*Flist).print(stdout); printf("\n"); +- for (int i = 1; i <= num_filters; i++) ++ for (int i = 1; i <= temp_num_filters; i++) + printf("filter[%d].sa = %u/%d\n",i,temp_filters[i].sa,temp_filters[i].sa_len); + */ + printf(" \tdone\n"); +@@ -203,13 +250,245 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + + (*Dtree).build_tree(Flist,temp_filters); + // printf("Flist = "); (*Flist).print(stdout); printf("\n"); +- delete(Dtree); + printf(" \tdone\n"); + + delete(Flist); + ++ ++// **************************************************************************** ++// START of IMPROVEMENTS implemented in ClassBench-ng ++// **************************************************************************** ++ ++ // transform filter set into filter graph and insert source/destination ++ // prefixes of filters into corresponding tries ++ Filter_graph graph; ++ Trie src_trie; ++ Trie dst_trie; ++ for (int i = 1; i <= temp_num_filters; i++) { ++ graph.add_filter(&(temp_filters[i])); ++ src_trie.insert(IP_prefix(temp_filters[i].sa, temp_filters[i].sa_len)); ++ dst_trie.insert(IP_prefix(temp_filters[i].da, temp_filters[i].da_len)); ++ } ++ ++ // get statistics of source and destination tries ++ trie_stats src_trie_stats, dst_trie_stats; ++ src_trie.get_stats(src_trie_stats); ++ dst_trie.get_stats(dst_trie_stats); ++ ++ // initialize data structures for trie-related distributions ++ vector src_prefixes(129,0); ++ vector src_one_child(129,0); ++ vector src_two_children(129,0); ++ vector src_skew(129,0); ++ vector dst_prefixes(129,0); ++ vector dst_one_child(129,0); ++ vector dst_two_children(129,0); ++ vector dst_skew(129,0); ++ ++ // get source and destination prefix length distributions ++ // Use prefix length distributions from already generated source and ++ // destination prefix sets as ClassBench-generated rule sets follow them ++ // quite precisely. ++ for (int i = 0; i < 129; i++) { ++ src_prefixes[i] = (float)src_trie_stats.classbench.prefix_lengths[i] / ++ (float)src_trie_stats.classbench.prefixes; ++ dst_prefixes[i] = (float)dst_trie_stats.classbench.prefix_lengths[i] / ++ (float)dst_trie_stats.classbench.prefixes; ++ } ++ ++ // get other src distributions ++ // Copy the values that were already read from the parameter file into Stree. ++ for (int i = 0; i <= 32; i++) { ++ src_one_child[i] = Stree->get_p1child()[i]; ++ src_two_children[i] = Stree->get_p2child()[i]; ++ src_skew[i] = Stree->get_skew()[i]; ++ } ++ delete(Stree); ++ ++ // get other dst distributions ++ // Copy the values that were already read from the parameter file into Dtree. ++ for (int i = 0; i <= 32; i++) { ++ dst_one_child[i] = Dtree->get_p1child()[i]; ++ dst_two_children[i] = Dtree->get_p2child()[i]; ++ dst_skew[i] = Dtree->get_skew()[i]; ++ } ++ delete(Dtree); ++ ++ // prune source and destination tries to 1/100 of the original prefix sets ++ src_trie.prune(num_filters, src_prefixes, src_one_child, ++ src_two_children, src_skew); ++ dst_trie.prune(num_filters, dst_prefixes, dst_one_child, ++ dst_two_children, dst_skew); ++ ++ // extend filter graph according to pruned tries ++ trie_to_graph(src_trie.get_root(), true, "", &graph); ++ trie_to_graph(dst_trie.get_root(), false, "", &graph); ++ ++ // modify the filter graph to conform with the flow network specification ++ graph.to_flow_network(); ++ ++ // compute maximum flow for the current flow network ++ int max_flow = graph.max_flow(); ++ ++ // auxiliary variables for construction of the set of pruned filters ++ struct filter* pruned_filters = new struct filter[temp_num_filters+1]; ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ pruned_filters[i].num_ext_field = 0; ++ } ++ int pruned_filters_i = 1; ++ ++ /* ++ * 1st phase of construction of the set of pruned filters ++ */ ++ // iterate over all filters ++ const node_list_item* node; ++ node = graph.get_src_nodes(); ++ while (node != NULL) { ++ neighbour_list_item* neighbour = node->neighbours; ++ while (neighbour != NULL) { ++ filter_list_item* filter = neighbour->filters; ++ for (int i = 0; i < neighbour->flow; i++) { ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ // copy filters from the maximum flow to the pruned_filters array ++ copy_filter(pruned_filters[pruned_filters_i], *(filter->filter)); ++ pruned_filters_i++; ++ filter = filter->next; ++ } ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ neighbour = neighbour->next; ++ } ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ node = node->next; ++ } ++ ++ /* ++ * 2nd phase of construction of the set of pruned filters ++ */ ++ // auxiliary variables for looking for not fully utilized source prefixes ++ neighbour_list_item* s_neighbour = (graph.get_s_node() != NULL) ? ++ graph.get_s_node()->neighbours : NULL; ++ // iterate over all destination prefixes ++ node = graph.get_dst_nodes(); ++ while (node != NULL) { ++ neighbour_list_item* neighbour = node->neighbours; ++ if (neighbour != NULL) { ++ int free_weight = neighbour->weight - neighbour->flow; ++ // auxiliary variables for looking for not fully utilized filters with ++ // current destination prefix ++ const node_list_item* src_node = graph.get_src_nodes(); ++ neighbour_list_item* src_neighbour; ++ filter_list_item* src_filter; ++ int src_filter_index = 0; ++ // for each not fully utilized destination prefix ++ for (int i = 0; i < free_weight; i++) { ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ ++// FILTERS start -------------------------------------------------------------- ++ ++ // iterate over all filters with current destination prefix ++ while (src_node != NULL) { ++ src_neighbour = src_node->neighbours; ++ while (src_neighbour != NULL) { ++ if (src_neighbour->node->prefix == node->prefix) { ++ src_filter = src_neighbour->filters; ++ // skip over all filters from the maximum flow ++ for (; ++ src_filter_index < src_neighbour->flow; ++ src_filter_index++) { ++ src_filter = src_filter->next; ++ } ++ if (src_filter != NULL) {// this filter is not fully ++ // utilized ++ ++// SOURCE PREFIXES start ------------------------------------------------------ ++ ++ // find the first not fully utilized source prefix ++ while (s_neighbour != NULL) { ++ // if this source prefix is not fully utilized ++ if (s_neighbour->flow < s_neighbour->weight) { ++ // create local copy of the selected filter and ++ // modify its source prefix ++ struct filter pruned_filter; ++ copy_filter(pruned_filter, *(src_filter->filter)); ++ pruned_filter.sa = ++ s_neighbour->node->prefix.get_prefix_unsigned(); ++ pruned_filter.sa_len = ++ s_neighbour->node->prefix.get_length(); ++ // inset the filter into the pruned_filters array ++ pruned_filters[pruned_filters_i++] = ++ pruned_filter; ++ // increment flow value through used edges ++ s_neighbour->flow++; ++ src_neighbour->flow++; ++ neighbour->flow++; ++ // terminate looking for the next not fully ++ // utilized source prefix ++ break; ++ } ++ s_neighbour = s_neighbour->next; ++ } ++ // always terminate looking for not fully utilized ++ // filters because of the following reasons: ++ // * if not fully utilized source prefix was found, ++ // move to the next not fully utilized destination ++ // prefix ++ // * if not fully utilized source prefix was not ++ // found, terminate inserting filters into the ++ // pruned_filters array at all ++ break; ++ ++// SOURCE PREFIES end --------------------------------------------------------- ++ ++ } else { // this filter is fully utilized ++ src_filter_index = 0; ++ } ++ } ++ src_neighbour = src_neighbour->next; ++ } ++ // if the previous cycle was broken, break also this cycle ++ // (because of the same reasons) ++ if (src_neighbour != NULL) { ++ break; ++ } ++ src_node = src_node->next; ++ } ++ // if either all filters or prefixes are fully utilized, terminate ++ // looking for not fully utilized filters ++ if ((src_node == NULL) || (s_neighbour == NULL)) { ++ break; ++ } ++ ++// FILTERS end ---------------------------------------------------------------- ++ ++ } ++ } ++ // if all source prefixes are fully utilized or enough filters have been ++ // selected, terminate looking for not fully utilized destination prefixes ++ if ((s_neighbour == NULL) || (pruned_filters_i == num_filters+1)) { ++ break; ++ } ++ node = node->next; ++ } ++ ++// **************************************************************************** ++// END of IMPROVEMENTS implemented in ClassBench-ng ++// **************************************************************************** ++ ++ + printf("Removing redundant filters and ordering nested filters...\n"); +- int filter_cnt = remove_redundant_filters(num_filters,filters,temp_filters); ++ int filter_cnt = remove_redundant_filters(pruned_filters_i-1,filters,pruned_filters); + printf(" \tdone\n"); + + // Resolve conflicts, throw away filters if necessary +@@ -219,7 +498,16 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + // printf(" \tdone\n"); + + // Delete data structures +- delete(temp_filters); ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ if (temp_filters[i].num_ext_field > 0) { ++ delete[] (temp_filters[i].ext_field); ++ } ++ if (pruned_filters[i].num_ext_field > 0) { ++ delete[] (pruned_filters[i].ext_field); ++ } ++ } ++ delete[] (temp_filters); ++ delete[] (pruned_filters); + // printf("Done with custom_db\n"); + + return filter_cnt; +diff --git a/dbintree.cc b/dbintree.cc +index 9274710..bb45062 100644 +--- a/dbintree.cc ++++ b/dbintree.cc +@@ -28,10 +28,10 @@ dbintree::dbintree() { + } + + dbintree::~dbintree() { +- delete(skew); +- delete(corr); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (corr); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } +@@ -39,6 +39,7 @@ dbintree::~dbintree() { + void dbintree::delete_node(struct tnode *me){ + if (me->child0 != NULL) delete_node(me->child0); + if (me->child1 != NULL) delete_node(me->child1); ++ delete(me->stubList); + delete(me); + return; + } +diff --git a/dbintree.h b/dbintree.h +index 5509fc3..d189380 100644 +--- a/dbintree.h ++++ b/dbintree.h +@@ -51,4 +51,15 @@ class dbintree { + void print_corr(FILE*); // print correlation per level + void build_tree(dlist* Flist, struct filter filters[]); + void lsort(); // sort nodes by level ++ ++ // get methods for selected private members ++ inline float* get_skew() { ++ return skew; ++ }; ++ inline float* get_p1child() { ++ return p1child; ++ }; ++ inline float* get_p2child() { ++ return p2child; ++ }; + }; +diff --git a/filter_graph.cc b/filter_graph.cc +new file mode 100644 +index 0000000..726869a +--- /dev/null ++++ b/filter_graph.cc +@@ -0,0 +1,785 @@ ++// filter_graph.cc: Filter_graph class definition ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "stdinc.h" ++#include "flow_network.h" ++#include "filter_graph.h" ++ ++// Library includes ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Auxiliary (non-member) functions ************************************* ++ ++ ++/* ++ * Private function that builds a flow network corresponding to the filter ++ * graph. ++ * In three iterations the function traverses all edges of the filter graph ++ * (i.e., s_node->src_nodes, src_nodes->dst_nodes, and dst_nodes->t_node edges) ++ * and constructs the flow network corresponding to this graph. Each edge of ++ * the filter graph can be represented by at most two edges of the flow ++ * network -- a forward and backward edge. Note that they are included into the ++ * flow network only if their residual capacity is greater than zero. ++ * The function expects that the input graph is already a valid flow network, ++ * i.e., it contains only one node without input edges (the 's' node) and only ++ * one node without output edges (the 't' node). ++ * @param network Reference to the (most probably empty) flow network object. ++ * @param graph Pointer to the constant filter graph object. ++ */ ++void build_flow_network(Flow_network& network, const Filter_graph* graph) { ++ // declatarion of "phase" variables ++ const node_list_item* list; ++ int src_list; ++ int dst_list; ++ ++ // iteration through three phases ++ for (int i = 0; i < 3; i++) { ++ // setting of phase variables ++ switch (i) { ++ case 0: // edges from the 's' node to destination nodes ++ list = graph->get_s_node(); ++ src_list = 0; ++ dst_list = 1; ++ break; ++ case 1: // edges from source nodes to destination nodes ++ list = graph->get_src_nodes(); ++ src_list = 1; ++ dst_list = 2; ++ break; ++ case 2: // edges from destination nodes to the 'd' node ++ list = graph->get_dst_nodes(); ++ src_list = 2; ++ dst_list = 3; ++ break; ++ } ++ ++ // iteration over all nodes in the list ++ while (list != NULL) { ++ neighbour_list_item* neighbour = list->neighbours; ++ // iteration over all neighbours (i.e., edges of the filter graph) ++ while (neighbour != NULL) { ++ // compute residual capacity of forward and backward edges ++ int capacity_forward = neighbour->weight - neighbour->flow; ++ int capacity_backward = neighbour->flow; ++ // insert the forward edge, if it has capacity > 0 ++ if (capacity_forward > 0) { ++ network.add_edge(list->prefix, src_list, ++ neighbour->node->prefix, dst_list, ++ neighbour, true, capacity_forward); ++ } ++ // insert the backward edge, if it has capacity > 0 ++ if (capacity_backward > 0) { ++ network.add_edge(neighbour->node->prefix, dst_list, ++ list->prefix, src_list, ++ neighbour, false, capacity_backward); ++ } ++ // move to the next edge ++ neighbour = neighbour->next; ++ } ++ // move to the next node ++ list = list->next; ++ } ++ } ++} // end build_flow_network() ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++/* ++ * Private static function that creates deep copy of the original list. ++ */ ++node_list_item* Filter_graph::copy_node_list(const node_list_item* orig) { ++ // initialize pointer to copied node list ++ node_list_item* result = (orig == NULL) ? ++ NULL : ++ new node_list_item; ++ ++ // node list level of copying ++ node_list_item* copy = result; ++ while (orig != NULL) { ++ // list item members initialization ++ copy->prefix = orig->prefix; ++ copy->pruned = orig->pruned; ++ copy->neighbours = (orig->neighbours == NULL) ? ++ NULL : ++ new neighbour_list_item; ++ copy->next = (orig->next == NULL) ? ++ NULL : ++ new node_list_item; ++ ++ // neighbour list level of copying ++ neighbour_list_item* orig_neighbours = orig->neighbours; ++ neighbour_list_item* copy_neighbours = copy->neighbours; ++ while (orig_neighbours != NULL) { ++ // list item members initialization ++ copy_neighbours->node = NULL; // cannot be initialized directly ++ // (points to different node list) ++ copy_neighbours->weight = orig_neighbours->weight; ++ copy_neighbours->flow = orig_neighbours->flow; ++ copy_neighbours->filters = (orig_neighbours->filters == NULL) ? ++ NULL : ++ new filter_list_item; ++ copy_neighbours->next = (orig_neighbours->next == NULL) ? ++ NULL : ++ new neighbour_list_item; ++ ++ // filter list level of copying ++ filter_list_item* orig_filters = orig_neighbours->filters; ++ filter_list_item* copy_filters = copy_neighbours->filters; ++ while (orig_filters != NULL) { ++ // list item members initialization ++ copy_filters->filter = orig_filters->filter; ++ copy_filters->next = (orig_filters->next == NULL) ? ++ NULL : ++ new filter_list_item; ++ // move to the next item of filter list ++ copy_filters = copy_filters->next; ++ orig_filters = orig_filters->next; ++ } ++ ++ // move to the next item of neighbour list ++ copy_neighbours = copy_neighbours->next; ++ orig_neighbours = orig_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ copy = copy->next; ++ orig = orig->next; ++ } ++ ++ return result; ++} // end copy_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole node list. ++ */ ++void Filter_graph::remove_node_list(node_list_item** list) { ++ // traverse all nodes ++ while ((*list) != NULL) { ++ // get pointer to the first node ++ node_list_item* first_node = *list; ++ ++ // correctly deallocate its whole neighbour list ++ remove_neighbour_list(&(first_node->neighbours)); ++ ++ // move to the next node list item and deallocate the current one ++ node_list_item* next_node = first_node->next; ++ delete first_node; ++ *list = next_node; ++ } ++} // end remove_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole neighbour ++ * list. ++ */ ++void Filter_graph::remove_neighbour_list(neighbour_list_item** list) { ++ // traverse all neighbours ++ while ((*list) != NULL) { ++ // get pointer to the first neighbour ++ neighbour_list_item* first_neighbour = *list; ++ ++ // correctly deallocate it whole filter list ++ remove_filter_list(&(first_neighbour->filters)); ++ ++ // move to the next neighbour list item and deallocate the current one ++ neighbour_list_item* next_neighbour = first_neighbour->next; ++ delete first_neighbour; ++ *list = next_neighbour; ++ } ++} // end remove_neighbour_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole filter list. ++ */ ++void Filter_graph::remove_filter_list(filter_list_item** list) { ++ // traverse all filters ++ while ((*list) != NULL) { ++ // get pointer to the first filter ++ filter_list_item* first_filter = *list; ++ ++ // move to the next filter list item and deallocate the current one ++ filter_list_item* next_filter = first_filter->next; ++ delete first_filter; ++ *list = next_filter; ++ } ++} // end remove_filter_list() ++ ++ ++/* ++ * Private static function that sets correct values of neighbour node pointers, ++ * which cannot be correctly initialized during copying. ++ */ ++void Filter_graph::set_neighbour_nodes(const node_list_item* orig, ++ node_list_item* src, ++ node_list_item* dst) { ++ // traverse all nodes ++ while (orig != NULL) { ++ neighbour_list_item* orig_neighbours = orig->neighbours; ++ neighbour_list_item* src_neighbours = src->neighbours; ++ ++ // traverse all neighbours ++ while (orig_neighbours != NULL) { ++ // set correct neighbour node pointer ++ src_neighbours->node = find_node(orig_neighbours->node->prefix, dst); ++ ++ // move to the next item of neighbour list ++ orig_neighbours = orig_neighbours->next; ++ src_neighbours = src_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ orig = orig->next; ++ src = src->next; ++ } ++ ++ return; ++} // end set_neighbour_nodes() ++ ++ ++/* ++ * Private static function that looks for node with the given prefix in the ++ * given list of nodes. ++ */ ++node_list_item* Filter_graph::find_node(const IP_prefix& prefix, ++ node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ if (list->prefix == prefix) { ++ // corresponding node - return pointer to it ++ return list; ++ } else { ++ // node with different prefix - move to the next item of node list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding node was not found ++ return NULL; ++} // end find_node() ++ ++ ++/* ++ * Private static function that looks for the corresponding neighbour node in ++ * the given list of neighbours. ++ */ ++neighbour_list_item* Filter_graph::find_neighbour( ++ const node_list_item* neighbour, ++ neighbour_list_item* list) { ++ // traverse all neighbour nodes ++ while (list != NULL) { ++ if (list->node->prefix == neighbour->prefix) { ++ // corresponding neighbour node - return pointer to it ++ return list; ++ } else { ++ // neighbour node corresponding to different prefix node - move to the ++ // next item of neighbour list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding neighbour node was not found ++ return NULL; ++} // end find_neighbour() ++ ++ ++/* ++ * Private static function that looks for the filter node pointing to the ++ * specified filter in the given list of filters. ++ */ ++filter_list_item* Filter_graph::find_filter(const struct filter* filter, ++ filter_list_item* list) { ++ // traverse all filter nodes ++ while (list != NULL) { ++ if (list->filter == filter) { ++ // corresponding filter node - return pointer to it ++ return list; ++ } else { ++ // filter node pointing to different filter - move to the next item of ++ // filter list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding filter node was not found ++ return NULL; ++} // end find_filter() ++ ++ ++/* ++ * Private static function that inserts a node representing the given IP prefix ++ * at the beginning of the given list of nodes. ++ */ ++void Filter_graph::insert_node(const IP_prefix& prefix, ++ node_list_item** list) { ++ // allocate and initialize new prefix node ++ node_list_item* node = new node_list_item; ++ node->prefix = prefix; ++ node->pruned = false; ++ node->neighbours = NULL; ++ ++ // insert new prefix node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_node() ++ ++ ++/* ++ * Private static function that inserts a neighbour node corresponding to the ++ * given prefix node at the beginning of the given list of neighbour nodes. ++ */ ++void Filter_graph::insert_neighbour(node_list_item* neighbour, ++ neighbour_list_item** list) { ++ // allocate and initialize new neighbour node ++ neighbour_list_item* node = new neighbour_list_item; ++ node->node = neighbour; ++ node->weight = 0; ++ node->flow = 0; ++ node->filters = NULL; ++ ++ // insert new neighbour node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_neighbour() ++ ++ ++/* ++ * Private static function that inserts a filter node pointing to the given ++ * filter at the beginning of the given list of filter nodes. ++ */ ++void Filter_graph::insert_filter(const struct filter* filter, ++ filter_list_item** list) { ++ // allocate and initialize new filter node ++ filter_list_item* node = new filter_list_item; ++ node->filter = filter; ++ ++ // insert new filter node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_filter() ++ ++ ++/* ++ * Private static function that prints specified node list, including all ++ * sublists (i.e., neighbour lists and filter lists). ++ */ ++void Filter_graph::print_node_list(const node_list_item* nodes) { ++ while (nodes != NULL) { ++ // print node list items ++ cout << "+-> " << nodes->prefix.get_prefix() << "/" ++ << nodes->prefix.get_length() << endl; ++ neighbour_list_item* neighbours = nodes->neighbours; ++ while (neighbours != NULL) { ++ // print neighbour list items ++ cout << "| +-> " << neighbours->node->prefix.get_prefix() << "/" ++ << neighbours->node->prefix.get_length() << " " ++ << "(" ++ << neighbours->flow << "/" ++ << neighbours->weight ++ << ")" << endl; ++ filter_list_item* filters = neighbours->filters; ++ while (filters != NULL) { ++ // print filter list items ++ cout << "| | +-> " << filters->filter->sp[0] << ":" ++ << filters->filter->sp[1] << " " ++ << filters->filter->dp[0] << ":" ++ << filters->filter->dp[1] << " " ++ << filters->filter->prot_num << endl; ++ // move to the next filter ++ filters = filters->next; ++ } ++ // moce tothe next neighbour ++ neighbours = neighbours->next; ++ } ++ // move to the next node ++ nodes = nodes->next; ++ } ++} // end print_node_list() ++ ++ ++/* ++ * Private function that removes non-pruned nodes and resets the "pruned" ++ * flag of pruned nodes of the filter graph. ++ */ ++void Filter_graph::remove_and_reset() { ++ for (int i = 0; i < 4; i++) { ++ // select the correct node list for iteration ++ node_list_item** node_ptr; ++ switch (i) { ++ case 0: ++ node_ptr = &s_node; ++ break; ++ case 1: ++ node_ptr = &src_nodes; ++ break; ++ case 2: ++ node_ptr = &dst_nodes; ++ break; ++ case 3: ++ node_ptr = &t_node; ++ break; ++ } ++ ++ // iterate over all nodes in the list ++ while ((*node_ptr) != NULL) { ++ node_list_item* node = *node_ptr; ++ if (node->pruned == false) { // remove the non-pruned node ++ (*node_ptr) = node->next; ++ delete node; ++ } else { // reset the "pruned" flag of the pruned node ++ node->pruned = false; ++ node_ptr = &(node->next); ++ } ++ } ++ } ++} // end remove_and_reset() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++/* ++ * Default constructor. ++ */ ++Filter_graph::Filter_graph() { ++ src_nodes = NULL; ++ dst_nodes = NULL; ++ s_node = NULL; ++ t_node = NULL; ++} // end Filter_graph() ++ ++ ++/* ++ * Copy constructor. ++ */ ++Filter_graph::Filter_graph(const Filter_graph& orig) { ++ // acquire members of the original object ++ const node_list_item* orig_src_nodes = orig.get_src_nodes(); ++ const node_list_item* orig_dst_nodes = orig.get_dst_nodes(); ++ const node_list_item* orig_s_node = orig.get_s_node(); ++ const node_list_item* orig_t_node = orig.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(orig_src_nodes); ++ dst_nodes = copy_node_list(orig_dst_nodes); ++ s_node = copy_node_list(orig_s_node); ++ t_node = copy_node_list(orig_t_node); ++ ++ // set pointers to neighbour nodes ++ set_neighbour_nodes(orig_t_node, t_node, NULL); ++ set_neighbour_nodes(orig_dst_nodes, dst_nodes, t_node); ++ set_neighbour_nodes(orig_src_nodes, src_nodes, dst_nodes); ++ set_neighbour_nodes(orig_s_node, s_node, src_nodes); ++} // end Filter_graph() ++ ++ ++/* ++ * Destructor. ++ */ ++Filter_graph::~Filter_graph() { ++ remove_node_list(&s_node); ++ remove_node_list(&src_nodes); ++ remove_node_list(&dst_nodes); ++ remove_node_list(&t_node); ++} // end ~Filter_graph() ++ ++ ++/* ++ * Copy assignment. ++ */ ++Filter_graph& Filter_graph::operator=(const Filter_graph& copy) { ++ // destruct the original object ++ remove_node_list(&s_node); ++ remove_node_list(&src_nodes); ++ remove_node_list(&dst_nodes); ++ remove_node_list(&t_node); ++ ++ // acquire members of the copied object ++ const node_list_item* copy_src_nodes = copy.get_src_nodes(); ++ const node_list_item* copy_dst_nodes = copy.get_dst_nodes(); ++ const node_list_item* copy_s_node = copy.get_s_node(); ++ const node_list_item* copy_t_node = copy.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(copy_src_nodes); ++ dst_nodes = copy_node_list(copy_dst_nodes); ++ s_node = copy_node_list(copy_s_node); ++ t_node = copy_node_list(copy_t_node); ++ ++ // set pointers to neighbour nodes ++ set_neighbour_nodes(copy_t_node, t_node, NULL); ++ set_neighbour_nodes(copy_dst_nodes, dst_nodes, t_node); ++ set_neighbour_nodes(copy_src_nodes, src_nodes, dst_nodes); ++ set_neighbour_nodes(copy_s_node, s_node, src_nodes); ++ ++ // return the original object with new content ++ return *this; ++} // end operator=() ++ ++ ++/* ++ * Modifies filter graph to add the specified filter into the set of filters ++ * represented by the graph. ++ */ ++void Filter_graph::add_filter(const struct filter* filter) { ++ // acquire source and destination prefixes ++ IP_prefix src_pref(filter->sa, filter->sa_len); ++ IP_prefix dst_pref(filter->da, filter->da_len); ++ ++ // find source prefix node and insert such node if it does not exist ++ node_list_item* src_node = find_node(src_pref, src_nodes); ++ if (src_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(src_pref, &src_nodes); ++ src_node = src_nodes; ++ } ++ ++ // find destination prefix node and insert such node if it does not exist ++ node_list_item* dst_node = find_node(dst_pref, dst_nodes); ++ if (dst_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(dst_pref, &dst_nodes); ++ dst_node = dst_nodes; ++ } ++ ++ // find neighbour node corresponding to the filter and insert such node if ++ // it does not exist ++ neighbour_list_item* neighbour = find_neighbour(dst_node, ++ src_node->neighbours); ++ if (neighbour == NULL) { ++ // neighbour is inserted at the beginning of the list ++ insert_neighbour(dst_node, &(src_node->neighbours)); ++ neighbour = src_node->neighbours; ++ } ++ ++ // find filter node pointing to the specified filter and insert such node if ++ // it does not exist ++ filter_list_item* filter_node = find_filter(filter, neighbour->filters); ++ if (filter_node == NULL) { ++ insert_filter(filter, &(neighbour->filters)); ++ neighbour->weight += 1; ++ } ++} // end add_filter() ++ ++ ++/* ++ * Adds an edge from the 's' node to a node representing the given prefix ++ * within the source nodes list and sets its weight to the given value. ++ */ ++void Filter_graph::add_s_prefix(const IP_prefix& prefix, const int weight) { ++ // check existence of the 's' node and allocate it if it does not exist ++ if (s_node == NULL) { ++ insert_node(IP_prefix(), &s_node); ++ s_node->pruned = true; ++ } ++ ++ // find a node representing the given prefix within the source nodes list ++ // (existence of such node is not checked since it should always exist) ++ node_list_item* src_node = find_node(prefix, src_nodes); ++ ++ // find a neighbour node corresponding to the given prefix ++ neighbour_list_item* neighbour = find_neighbour(src_node, ++ s_node->neighbours); ++ if (neighbour == NULL) { // the neighbour node does not exist ++ // insert the node at the beginning of the list ++ insert_neighbour(src_node, &(s_node->neighbours)); ++ neighbour = s_node->neighbours; ++ // set neighbour node's weight member ++ neighbour->weight = weight; ++ } else { // the neighbour node exists ++ // adjust neighbour node's weight member accordingly ++ neighbour->weight += weight; ++ } ++ ++ // set source node's pruned flag to true ++ src_node->pruned = true; ++} // end add_s_prefix() ++ ++ ++/* ++ * Adds an edge from a node representing the given prefix within the ++ * destination nodes list to the 't' node and sets its weight to the given ++ * value. ++ */ ++void Filter_graph::add_t_prefix(const IP_prefix& prefix, const int weight) { ++ // check existence of the 't' node and allocate it if it does not exist ++ if (t_node == NULL) { ++ insert_node(IP_prefix(), &t_node); ++ t_node->pruned = true; ++ } ++ ++ // find a node representing the given prefix within the destination nodes ++ // list ++ // (existence of such node is not checked since it should always exist) ++ node_list_item* dst_node = find_node(prefix, dst_nodes); ++ ++ // find a neighbour node corresponding to the 't' node ++ neighbour_list_item* neighbour = find_neighbour(t_node, ++ dst_node->neighbours); ++ if (neighbour == NULL) { // the neighbour node does not exist ++ // insert the node at the beginning of the list ++ insert_neighbour(t_node, &(dst_node->neighbours)); ++ neighbour = dst_node->neighbours; ++ // set neighbour node's weight member ++ neighbour->weight = weight; ++ } else { // the neighbour node exists ++ // adjust neighbour node's weight member accordingly ++ neighbour->weight += weight; ++ } ++ ++ // set destination node's pruned flag to true ++ dst_node->pruned = true; ++} // end add_t_prefix() ++ ++ ++/* ++ * Modifies the filter graph such that it conforms with the flow network ++ * specification -- i.e., it has only one node without input edges (the ++ * 's' node) and only one node without output edges (the 't' node). ++ */ ++void Filter_graph::to_flow_network() { ++ // 1) remove filters containing at least one non-pruned prefix ++ node_list_item* node = src_nodes; ++ while (node != NULL) { ++ if (node->pruned == false) { // remove all neighbours of this node ++ remove_neighbour_list(&(node->neighbours)); ++ } else { // remove only neighbours pointing to a non-pruned node ++ neighbour_list_item** neighbour_ptr = &(node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ neighbour_list_item* neighbour = *neighbour_ptr; ++ if (neighbour->node->pruned == false) { // remove this neighbour ++ remove_filter_list(&(neighbour->filters)); ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } else { // just move to the next neighbour ++ neighbour_ptr = &(neighbour->next); ++ } ++ } ++ } ++ node = node->next; ++ } ++ ++ // 2) remove non-pruned nodes and reset the "pruned" flag of other nodes ++ remove_and_reset(); ++ ++ // 3) BFS to set the "pruned" flag of visited nodes with at least one ++ // neighbour and the 's' and 't' nodes ++ queue q; ++ q.push(s_node); ++ // do the BFS ++ while (!q.empty()) { ++ // dequeue the front element of the queue ++ node_list_item* node = q.front(); ++ q.pop(); ++ // set the "pruned" flag if the list of neighbours is non-empty ++ if (node->neighbours != NULL) { ++ node->pruned = true; ++ } ++ // insert neighbours into the queue ++ neighbour_list_item* neighbour = node->neighbours; ++ while (neighbour != NULL) { ++ q.push(neighbour->node); ++ neighbour = neighbour->next; ++ } ++ } ++ // set the "pruned" flag of the 's' and 't' nodes ++ s_node->pruned = true; ++ t_node->pruned = true; ++ ++ // 4) remove edges from the 's' node going to non-pruned nodes ++ neighbour_list_item** neighbour_ptr = &(s_node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ neighbour_list_item* neighbour = *neighbour_ptr; ++ if (neighbour->node->pruned == false) { // remove this edge ++ // there are no filters represented by edges from the 's' node ++ (*neighbour_ptr) = neighbour->next; ++ delete neighbour; ++ } else { // move to the next edge ++ neighbour_ptr = &(neighbour->next); ++ } ++ } ++ ++ // 5) remove edges to the 't' node going from non-pruned nodes ++ node = dst_nodes; ++ while (node != NULL) { ++ if (node->pruned == false) { // remove all edges going from this node ++ remove_neighbour_list(&(node->neighbours)); ++ } ++ // move to the next node ++ node = node->next; ++ } ++ ++ // 6) remove non-pruned nodes (and reset the "pruned" flag of other nodes) ++ remove_and_reset(); ++} // end to_flow_network() ++ ++ ++/* ++ * Computes maximum flow using Dinic's algorithm. ++ */ ++int Filter_graph::max_flow() { ++ int max_flow = 0; ++ int flow_inc; ++ ++ do { // iterate until the flow cannot be improved ++ // build flow network corresponding to the filter graph ++ Flow_network network; ++ build_flow_network(network, this); ++ ++ // transform the flow network into the level graph ++ network.to_level_graph(); ++ ++ // compute a blocking flow in the flow network and update the flow in the ++ // filter graph accordingly ++ flow_inc = network.find_blocking_flow(); ++ max_flow += flow_inc; ++ } while (flow_inc != 0); ++ ++ return max_flow; ++} // end max_flow() ++ ++ ++/* ++ * Prints the filter graph. ++ */ ++void Filter_graph::print() { ++ cout << "S_NODE:" << endl; ++ print_node_list(s_node); ++ cout << "--------------------" << endl; ++ ++ cout << "SRC_NODES:" << endl; ++ print_node_list(src_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "DST_NODES:" << endl; ++ print_node_list(dst_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "T_NODE:" << endl; ++ print_node_list(t_node); ++ cout << "--------------------" << endl; ++} +diff --git a/filter_graph.h b/filter_graph.h +new file mode 100644 +index 0000000..601f2cd +--- /dev/null ++++ b/filter_graph.h +@@ -0,0 +1,437 @@ ++// filter_graph.h: header file for Filter_graph class ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef FILTER_GRAPH_H ++#define FILTER_GRAPH_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++ ++// Forward declarations (including typedef) to resolve circular dependency ++typedef struct node_list_item node_list_item; ++typedef struct neighbour_list_item neighbour_list_item; ++typedef struct filter_list_item filter_list_item; ++ ++/* ++ * A structure representing an item in a list of graph nodes. ++ */ ++struct node_list_item { ++ // IP prefix represented by this node ++ IP_prefix prefix; ++ ++ // Flag that is utilized for "pruning" filters once the complete filter ++ // graph is constructed ++ bool pruned; ++ ++ // List of neighbours ++ neighbour_list_item* neighbours; ++ ++ // Next item in list of graph nodes ++ node_list_item* next; ++}; ++ ++/* ++ * A structure representing an item in a list of neighbours of a graph node. ++ */ ++struct neighbour_list_item { ++ // Pointer to neighbour node within list of graph nodes ++ node_list_item* node; ++ ++ // Weight of filter graph's edge between neighbouring nodes ++ int weight; ++ ++ // Flow through filter graph's edge between neighbouring nodes ++ int flow; ++ ++ // List of filters that specify prefixes of neighbouring nodes ++ filter_list_item* filters; ++ ++ // Next item in list of neighbours ++ neighbour_list_item* next; ++}; ++ ++/* ++ * A Structure representing an item in a list of filters that specify prefixes ++ * of neighbouring graph nodes. ++ */ ++struct filter_list_item { ++ // Pointer to representation of filter ++ // (struct filter is defined in stdinc.h included in custom_db.cc) ++ const struct filter* filter; ++ ++ // Next item in list of filters ++ filter_list_item* next; ++}; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a set of filters as a filter graph -- i.e., ++ * weighted directed bipartite graph with special source (s) and terminate (t) ++ * nodes -- that is constructed according to filters' source and destination ++ * prefixes and pruned source and destination prefix tries. ++ */ ++class Filter_graph { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * Lists of source and destination nodes of the filter graph. ++ */ ++ node_list_item* src_nodes; ++ node_list_item* dst_nodes; ++ ++ /* ++ * Special nodes 's' and 't' of the filter graph. ++ */ ++ node_list_item* s_node; ++ node_list_item* t_node; ++ ++ /* ++ * Private static function that creates deep copy of the original list. ++ * The function creates new instances of all items from the original list ++ * (as well as all sublists) and sets the value of their components ++ * according to this original list. The only exception is pointer to ++ * neighbour node, which is initialized to NULL (it points to different ++ * list, thus it cannot be initialized to correct value during copying). ++ * @param orig Pointer to the constant original node list. ++ * @return Pointer to the copy of the original node list. ++ */ ++ static node_list_item* copy_node_list(const node_list_item* orig); ++ ++ /* ++ * Private static function that correctly deallocates the whole node ++ * list. ++ * The function traverses the given node list and all its sublists and ++ * starting from the inner-most list it deallocates all the traversed ++ * list items. ++ * @ param list Pointer to pointer to node list that is to be ++ * deallocated. ++ */ ++ static void remove_node_list(node_list_item** list); ++ ++ /* ++ * Private static function that correctly deallocates the whole neighbour ++ * list. ++ * The function traverses the given neighbour list and all its sublists ++ * and starting from the inner-most list it deallocates all the traversed ++ * list items. ++ * @param Pointer to pointer to the neighbour list that is to be ++ * deallocated. ++ */ ++ static void remove_neighbour_list(neighbour_list_item** list); ++ ++ /* ++ * Private static function that correctly deallocates the whole filter ++ * list. ++ * The function traverses the given filter list and deallocates all the ++ * traversed list items. ++ * @param Pointer to pointer to the filter list that is to be ++ * deallocated. ++ */ ++ static void remove_filter_list(filter_list_item** list); ++ ++ /* ++ * Private static function that sets correct values of neighbour node ++ * pointers, which cannot be correctly initialized during copying. ++ * The function simultaneously traverses neighbours lists in orig and src ++ * node lists. For each neighbour node from orig list it looks for ++ * corresponding item in dst node list and stores pointer to this node to ++ * current item in src list. ++ * @param orig Pointer to the constant original node list. ++ * @param src Pointer to the list of source nodes (neighbour node ++ * pointers of this list are set). ++ * @param dst Pointer to the list of destination nodes (nodes of this ++ * list act as targets of neighbour node pointers within ++ * src node list). ++ */ ++ static void set_neighbour_nodes(const node_list_item* orig, ++ node_list_item* src, ++ node_list_item* dst); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for node with the given prefix in ++ * the given list of nodes. ++ * @param prefix Reference to a constant IP prefix of node that the ++ * function looks for in the list. ++ * @param list Pointer to list of nodes that is traversed during ++ * looking for node with the given IP prefix. ++ * @return Pointer to found node or NULL. ++ */ ++ static node_list_item* find_node(const IP_prefix& prefix, ++ node_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the corresponding neighbour ++ * node in the given list of neighbours. ++ * @param neighbour Pointer to a constant prefix node whose neighbour ++ * node the function looks for in the list. ++ * @param list Pointer to the list of neighbour nodes that is ++ * traversed during looking for the node corresponding ++ * to the given prefix node. ++ * @return Pointer to the found neighbour node or NULL. ++ */ ++ static neighbour_list_item* find_neighbour( ++ const node_list_item* neighbour, ++ neighbour_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the filter node pointing to the ++ * specified filter in the given list of filters. ++ * @param filter Pointer to the constant filter that is referenced by ++ * the filter node the function looks for in the list. ++ * @param list Pointer to the list of filter nodes that is traversed ++ * during looking for a node pointing to the given ++ * filter. ++ * @return Pointer to the found filter node or NULL. ++ */ ++ static filter_list_item* find_filter(const struct filter* filter, ++ filter_list_item* list); ++ ++ /* ++ * Private static function that inserts a node representing the given IP ++ * prefix at the beginning of the given list of nodes. ++ * @param prefix Reference to a constant IP prefix that is going to be ++ * represented by the inserted node. ++ * @param list Pointer to pointer to the list of nodes that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_node(const IP_prefix& prefix, ++ node_list_item** list); ++ ++ /* ++ * Private static function that inserts a neighbour node corresponding to ++ * the given prefix node at the beginning of the given list of ++ * neighbour nodes. ++ * @param neighbour Pointer to a prefix node whose neighbour node is ++ * going to be inserted. ++ * @param list Pointer to pointer to the list of neighbours that ++ * is going to be extended by the inserted node. ++ */ ++ static void insert_neighbour(node_list_item* neighbour, ++ neighbour_list_item** list); ++ ++ /* ++ * Private static function that inserts a filter node pointing to the ++ * given filter at the beginning of the given list of filter nodes. ++ * @param node Pointer to the constant filter that is going to be ++ * referenced by the inserted filter node. ++ * @param list Pointer to pointer to the list of filters that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_filter(const struct filter* filter, ++ filter_list_item** list); ++ ++ /* ++ * Private static function that prints specified node list, including all ++ * sublists (i.e., neighbour lists and filter lists). ++ * @param nodes Pointer to the constant list of nodes that is to be ++ * printed. ++ */ ++ static void print_node_list(const node_list_item* nodes); ++ ++ /* ++ * Private function that removes non-pruned nodes and resets the "pruned" ++ * flag of pruned nodes of the filter graph. ++ * The function performs the specified function on all nodes of the ++ * filter graph (i.e., source and destination nodes as well as the 's' ++ * and 't' nodes). ++ * The function expects that neighbours list referenced from the ++ * non-pruned nodes have been correctly deallocated before calling this ++ * function. ++ */ ++ void remove_and_reset(); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * All pointers are initialized to NULL. ++ */ ++ Filter_graph(); ++ ++ /* ++ * Copy constructor. ++ * All pointers are initialized to a deep copy of corresponding members ++ * of the original object. ++ * @param orig Reference to the constant original object. ++ */ ++ Filter_graph(const Filter_graph& orig); ++ ++ /* ++ * Destructor. ++ * Correctly deallocates all lists that are referenced by object members. ++ */ ++ ~Filter_graph(); ++ ++ /* ++ * Copy assignment. ++ * The original object is destructed and its new content is constructed ++ * in similar way as in the copy constructor. ++ * @param copy Reference to the constant copied object. ++ * @return Reference to the original object with new content. ++ */ ++ Filter_graph& operator= (const Filter_graph& copy); ++ ++ /* ++ * Get function for the src_nodes member. ++ * @return Pointer to the constant list of source nodes. ++ */ ++ inline const node_list_item* get_src_nodes() const { ++ return src_nodes; ++ } // end get_src_nodes() ++ ++ /* ++ * Get function for the dst_nodes member. ++ * @return Pointer to the constant list of destination nodes. ++ */ ++ inline const node_list_item* get_dst_nodes() const { ++ return dst_nodes; ++ } // end get_dst_nodes() ++ ++ /* ++ * Get function for the s_node member. ++ * @return Pointer to the constant special 's' node. ++ */ ++ inline const node_list_item* get_s_node() const { ++ return s_node; ++ } // end get_s_node() ++ ++ /* ++ * Get function for the t_node member. ++ * @return Pointer to the constant special 't' node. ++ */ ++ inline const node_list_item* get_t_node() const { ++ return t_node; ++ } // end get_t_node() ++ ++ /* ++ * Modifies filter graph to add the specified filter into the set of ++ * filters represented by the graph. ++ * The function searches src_nodes and dst_nodes lists for nodes ++ * representing source and destination prefixes of the given filter and ++ * inserts such nodes into these lists if they are not found. Next, the ++ * function seraches neighbours list of source prefix node for neighbour ++ * node representing destination prefix of the given filter and inserts ++ * such neighbour node into the list if it is not found. Finally, the ++ * function searches filters list of neighbouring node for pointer to the ++ * given filter and inserts such pointer into the list if it is not ++ * found. Along with inserting new filter pointer to the list, the ++ * function increments weight item of neighbouring node representation. ++ * @param filter Pointer to a constant structure representing inserted ++ * filter. ++ */ ++ void add_filter(const struct filter* filter); ++ ++ /* ++ * Adds an edge from the 's' node to a node representing the given prefix ++ * within the source nodes list and sets its weight to the given value. ++ * First of all, the function checks whether the 's' node has already ++ * been allocated and allocates this node in case it does not yet exist. ++ * Next, the function searches the neighbours list of the 's' node for a ++ * neighbour node representing the given prefix. If such neighbour node ++ * exists, the function just adds the given weight to the current value ++ * of its weight counter. If such neighbour node does not exist, the ++ * function inserts the node into the list and sets its weight counter to ++ * the given value. The function also sets the "pruned" flag of the node ++ * representing the given prefix to true. ++ * The implementation expects that all filters have already been added to ++ * the filter graph and that only prefixes of a pruned source trie are ++ * added using this function. In such a case the source nodes list always ++ * contains a node representing the given prefix. ++ * @param prefix Reference to the IP_prefix object that determines a ++ * target node of the edge from the 's' node. ++ * @param weight Weight of the newly created edge. ++ */ ++ void add_s_prefix(const IP_prefix& prefix, const int weight); ++ ++ /* ++ * Adds an edge from a node representing the given prefix within the ++ * destination nodes list to the 't' node and sets its weight to the ++ * given value. ++ * First of all, the function checks whether the 't' node has already ++ * been allocated and allocates this node in case it does not yet exist. ++ * Next, the function searches the neighbours list of the node ++ * representing the given prefix within the destination nodes list for a ++ * neighbour node representing the 't' node. If such neighbour node ++ * exists, the function just adds the given weight to the current value ++ * of its weight counter. If such neighbour node does not exist, the ++ * function inserts the node into the list and sets its weight counter to ++ * the given value. The function also sets the "pruned" flag of the node ++ * representing the given prefix to true. ++ * The implementation expects that all filters have already been added to ++ * the filter graph and that only prefixes of a pruned destination trie ++ * are added using this function. In such a case the destination nodes ++ * list always contains a node representing the given prefix. ++ * @param prefix Reference to the IP_prefix object that determines a ++ * source node of the edge towards the 't' node. ++ * @param weight Weight of the newly created edge. ++ */ ++ void add_t_prefix(const IP_prefix& prefix, const int weight); ++ ++ /* ++ * Modifies the filter graph such that it conforms with the flow network ++ * specification -- i.e., it has only one node without input edges (the ++ * 's' node) and only one node without output edges (the 't' node). ++ * First of all, the function removes all edges representing filters with ++ * at least one non-pruned prefix and all nodes representing non-pruned ++ * prefixes. During this step, the "pruned" flag of the remaining nodes ++ * is also set to false. Next, the filter graph is traversed in a BFS ++ * manner and the "pruned" flag is set to true for all visited nodes with ++ * at least one input edge and one output edge. Finally, the function ++ * removes all edges going from the 's' node/to the 't' node that do not ++ * end/start in a node with the set "pruned" flag. These non-pruned nodes ++ * are also removed from the graph in this final step. ++ * The function expects that all steps of the filter graph construction ++ * (i.e., adding filters, s-prefixes, and t-prefixes) have already been ++ * performed before its invocation. ++ */ ++ void to_flow_network(); ++ ++ /* ++ * Computes maximum flow using Dinic's algorithm. ++ * The function builds a flow network corresponding to the filter graph, ++ * transforms it to a level graph and updates the flow through the filter ++ * graph according to a blocking flow through the level graph. This way ++ * the flow through the filter graph is iteratively updated until there ++ * are paths from the 's' node to the 't' node in the level graph. ++ * The flow network is represented by an object of the Flow_network, ++ * which also allows transformation into the corresponding level graph. ++ * @return The value of the maximum flow through the filter graph. ++ */ ++ int max_flow(); ++ ++ /* ++ * Prints the filter graph. ++ */ ++ void print(); ++}; ++ ++#endif +diff --git a/flow_network.cc b/flow_network.cc +new file mode 100644 +index 0000000..b5523da +--- /dev/null ++++ b/flow_network.cc +@@ -0,0 +1,592 @@ ++// flow_network.cc: Flow_network class definition ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "flow_network.h" ++ ++// Library includes ++#include ++#include ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions (related to filter graph) ************************** ++ ++ ++/* ++ * Private static function that creates deep copy of the original list. ++ */ ++net_node_list_item* Flow_network::copy_node_list(const net_node_list_item* orig) { ++ // initialize pointer to copied node list ++ net_node_list_item* result = (orig == NULL) ? ++ NULL : ++ new net_node_list_item; ++ ++ // node list level of copying ++ net_node_list_item* copy = result; ++ while (orig != NULL) { ++ // list item members initialization ++ copy->prefix = orig->prefix; ++ copy->visited = orig->visited; ++ copy->neighbours = (orig->neighbours == NULL) ? ++ NULL : ++ new net_neighbour_list_item; ++ copy->next = (orig->next == NULL) ? ++ NULL : ++ new net_node_list_item; ++ ++ // neighbour list level of copying ++ net_neighbour_list_item* orig_neighbours = orig->neighbours; ++ net_neighbour_list_item* copy_neighbours = copy->neighbours; ++ while (orig_neighbours != NULL) { ++ // list item members initialization ++ copy_neighbours->src_node = copy; ++ copy_neighbours->dst_node = NULL; // cannot be initialized directly ++ // (points to different node list) ++ copy_neighbours->capacity = orig_neighbours->capacity; ++ copy_neighbours->flow = orig_neighbours->flow; ++ copy_neighbours->orig_edge = orig_neighbours->orig_edge; ++ copy_neighbours->forward_edge = orig_neighbours->forward_edge; ++ copy_neighbours->next = (orig_neighbours->next == NULL) ? ++ NULL : ++ new net_neighbour_list_item; ++ ++ // move to the next item of neighbour list ++ copy_neighbours = copy_neighbours->next; ++ orig_neighbours = orig_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ copy = copy->next; ++ orig = orig->next; ++ } ++ ++ return result; ++} // end copy_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole node list. ++ */ ++void Flow_network::remove_node_list(net_node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ net_neighbour_list_item* neighbours = list->neighbours; ++ ++ // traverse all neighbours ++ while (neighbours != NULL) { ++ // move to the next neighbour list item and deallocate the current one ++ net_neighbour_list_item* current_neighbour = neighbours; ++ neighbours = neighbours->next; ++ delete current_neighbour; ++ } ++ ++ // move to the next node list item and deallocate the current one ++ net_node_list_item* current_node = list; ++ list = list->next; ++ delete current_node; ++ } ++ ++ return; ++} // end remove_node_list() ++ ++ ++/* ++ * Private static function that sets correct values of destination node ++ * pointers, which cannot be correctly initialized during copying. ++ */ ++void Flow_network::set_destination_nodes(const net_node_list_item* orig, ++ net_node_list_item* copy, ++ net_node_list_item* prev, ++ net_node_list_item* next) { ++ // traverse all nodes ++ while (orig != NULL) { ++ net_neighbour_list_item* orig_neighbours = orig->neighbours; ++ net_neighbour_list_item* copy_neighbours = copy->neighbours; ++ ++ // traverse all neighbours ++ while (orig_neighbours != NULL) { ++ // set correct destination node pointer ++ if (orig_neighbours->forward_edge) { // forward edge ++ copy_neighbours->dst_node = ++ find_node(orig_neighbours->dst_node->prefix, next); ++ } else { // backward edge ++ copy_neighbours->dst_node = ++ find_node(orig_neighbours->dst_node->prefix, prev); ++ } ++ ++ // move to the next item of neighbour list ++ orig_neighbours = orig_neighbours->next; ++ copy_neighbours = copy_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ orig = orig->next; ++ copy = copy->next; ++ } ++ ++ return; ++} // end set_destination_nodes() ++ ++ ++/* ++ * Private static function that looks for node with the given prefix in the ++ * given list of nodes. ++ */ ++net_node_list_item* Flow_network::find_node(const IP_prefix& prefix, ++ net_node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ if (list->prefix == prefix) { ++ // corresponding node - return pointer to it ++ return list; ++ } else { ++ // node with different prefix - move to the next item of node list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding node was not found ++ return NULL; ++} // end find_node() ++ ++ ++/* ++ * Private static function that looks for the corresponding neighbour node in ++ * the given list of neighbours. ++ */ ++net_neighbour_list_item* Flow_network::find_neighbour( ++ const net_node_list_item* neighbour, ++ net_neighbour_list_item* list) { ++ // traverse all neighbour nodes ++ while (list != NULL) { ++ if (list->dst_node->prefix == neighbour->prefix) { ++ // corresponding neighbour node - return pointer to it ++ return list; ++ } else { ++ // neighbour node corresponding to different prefix node - move to the ++ // next item of neighbour list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding neighbour node was not found ++ return NULL; ++} // end find_neighbour() ++ ++ ++/* ++ * Private static function that inserts a node representing the given IP prefix ++ * at the beginning of the given list of nodes. ++ */ ++void Flow_network::insert_node(const IP_prefix& prefix, ++ net_node_list_item** list) { ++ // allocate and initialize new prefix node ++ net_node_list_item* node = new net_node_list_item; ++ node->prefix = prefix; ++ node->visited = false; ++ node->neighbours = NULL; ++ ++ // insert new prefix node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_node() ++ ++ ++/* ++ * Private static function that inserts a neighbour node representing an edge ++ * between the given source and destination nodes at the beginning of the ++ * specified list of neighbour nodes. ++ */ ++void Flow_network::insert_neighbour(net_node_list_item* src_node, ++ net_node_list_item* dst_node, ++ int capacity, ++ int flow, ++ neighbour_list_item* orig_edge, ++ bool forward_edge, ++ net_neighbour_list_item** list) { ++ // allocate and initialize new neighbour node ++ net_neighbour_list_item* node = new net_neighbour_list_item; ++ node->src_node = src_node; ++ node->dst_node = dst_node; ++ node->capacity = capacity; ++ node->flow = flow; ++ node->orig_edge = orig_edge; ++ node->forward_edge = forward_edge; ++ ++ // insert new neighbour node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_neighbour() ++ ++ ++/* ++ * Private static function that prints specified node list, including all ++ * sublists. ++ */ ++void Flow_network::print_node_list(const net_node_list_item* nodes) { ++ while (nodes != NULL) { ++ // print node list items ++ cout << "+-> " << nodes->prefix.get_prefix() << "/" ++ << nodes->prefix.get_length() << endl; ++ net_neighbour_list_item* neighbours = nodes->neighbours; ++ while (neighbours != NULL) { ++ // print neighbour list items ++ cout << "| +-> "; ++ if (neighbours->forward_edge) { // forward edge ++ cout << "FORWARD: "; ++ } else { // backward edge ++ cout << "BACKWARD: "; ++ } ++ cout << neighbours->src_node->prefix.get_prefix() << "/" ++ << neighbours->src_node->prefix.get_length() ++ << " --> " ++ << neighbours->dst_node->prefix.get_prefix() << "/" ++ << neighbours->dst_node->prefix.get_length() ++ << " " ++ << "(" ++ << neighbours->flow << "/" ++ << neighbours->capacity ++ << ")" << endl; ++ // move to the next neighbour ++ neighbours = neighbours->next; ++ } ++ // move to the next node ++ nodes = nodes->next; ++ } ++} // end print_node_list() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++/* ++ * Default constructor. ++ */ ++Flow_network::Flow_network() { ++ src_nodes = NULL; ++ dst_nodes = NULL; ++ s_node = NULL; ++ t_node = NULL; ++} // end Flow_network() ++ ++ ++/* ++ * Copy constructor. ++ */ ++Flow_network::Flow_network(const Flow_network& orig) { ++ // acquire members of the original object ++ const net_node_list_item* orig_src_nodes = orig.get_src_nodes(); ++ const net_node_list_item* orig_dst_nodes = orig.get_dst_nodes(); ++ const net_node_list_item* orig_s_node = orig.get_s_node(); ++ const net_node_list_item* orig_t_node = orig.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(orig_src_nodes); ++ dst_nodes = copy_node_list(orig_dst_nodes); ++ s_node = copy_node_list(orig_s_node); ++ t_node = copy_node_list(orig_t_node); ++ ++ // set pointers to neighbour nodes ++ set_destination_nodes(orig_t_node, t_node, dst_nodes, NULL); ++ set_destination_nodes(orig_dst_nodes, dst_nodes, src_nodes, t_node); ++ set_destination_nodes(orig_src_nodes, src_nodes, s_node, dst_nodes); ++ set_destination_nodes(orig_s_node, s_node, NULL, src_nodes); ++} // end Filter_graph() ++ ++ ++/* ++ * Copy assignment. ++ */ ++Flow_network& Flow_network::operator=(const Flow_network& copy) { ++ // destruct the original object ++ remove_node_list(s_node); ++ remove_node_list(src_nodes); ++ remove_node_list(dst_nodes); ++ remove_node_list(t_node); ++ ++ // acquire members of the copied object ++ const net_node_list_item* copy_src_nodes = copy.get_src_nodes(); ++ const net_node_list_item* copy_dst_nodes = copy.get_dst_nodes(); ++ const net_node_list_item* copy_s_node = copy.get_s_node(); ++ const net_node_list_item* copy_t_node = copy.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(copy_src_nodes); ++ dst_nodes = copy_node_list(copy_dst_nodes); ++ s_node = copy_node_list(copy_s_node); ++ t_node = copy_node_list(copy_t_node); ++ ++ // set pointers to neighbour nodes ++ set_destination_nodes(copy_t_node, t_node, dst_nodes, NULL); ++ set_destination_nodes(copy_dst_nodes, dst_nodes, src_nodes, t_node); ++ set_destination_nodes(copy_src_nodes, src_nodes, s_node, dst_nodes); ++ set_destination_nodes(copy_s_node, s_node, NULL, src_nodes); ++ ++ // return the original object with new content ++ return *this; ++} // end operator=() ++ ++ ++/* ++ * Destructor. ++ */ ++Flow_network::~Flow_network() { ++ remove_node_list(s_node); ++ remove_node_list(src_nodes); ++ remove_node_list(dst_nodes); ++ remove_node_list(t_node); ++} // end ~Flow_network() ++ ++ ++/* ++ * Adds an edge to the flow network. ++ */ ++void Flow_network::add_edge(const IP_prefix& src_prefix, int src_list, ++ const IP_prefix& dst_prefix, int dst_list, ++ neighbour_list_item* orig_edge, bool forward_edge, ++ int capacity) { ++ // get pointer to correct source node list pointer ++ net_node_list_item** src_list_ptr; ++ switch (src_list) { ++ case 0 : ++ src_list_ptr = &s_node; ++ break; ++ case 1 : ++ src_list_ptr = &src_nodes; ++ break; ++ case 2 : ++ src_list_ptr = &dst_nodes; ++ break; ++ case 3 : ++ src_list_ptr = &t_node; ++ break; ++ } ++ ++ // get pointer to correct destination node list pointer ++ net_node_list_item** dst_list_ptr; ++ switch (dst_list) { ++ case 0 : ++ dst_list_ptr = &s_node; ++ break; ++ case 1 : ++ dst_list_ptr = &src_nodes; ++ break; ++ case 2 : ++ dst_list_ptr = &dst_nodes; ++ break; ++ case 3 : ++ dst_list_ptr = &t_node; ++ break; ++ } ++ ++ // find source prefix node in the specified node list and insert such node ++ // if it does not exist ++ net_node_list_item* src_node = find_node(src_prefix, *src_list_ptr); ++ if (src_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(src_prefix, src_list_ptr); ++ src_node = *src_list_ptr; ++ } ++ ++ // find destination prefix node in the specified node list and insert such node ++ // if it does not exist ++ net_node_list_item* dst_node = find_node(dst_prefix, *dst_list_ptr); ++ if (dst_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(dst_prefix, dst_list_ptr); ++ dst_node = *dst_list_ptr; ++ } ++ ++ // find neighbour node corresponding to the filter and insert such node if ++ // it does not exist ++ net_neighbour_list_item* neighbour = find_neighbour(dst_node, ++ src_node->neighbours); ++ if (neighbour == NULL) { ++ // neighbour is inserted at the beginning of the list ++ insert_neighbour(src_node, dst_node, capacity, 0, orig_edge, ++ forward_edge, &(src_node->neighbours)); ++ } ++} // end add_edge() ++ ++ ++/* ++ * Transforms the flow network into a level graph. ++ */ ++void Flow_network::to_level_graph() { ++ ++ // initialize auxiliary variables ++ queue q; ++ stack s; ++ if (s_node != NULL) { ++ s_node->visited = true; ++ q.push(s_node); ++ } ++ ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue the front element of the queue ++ net_node_list_item* node = q.front(); ++ q.pop(); ++ // iterate through the list of node's neighbours ++ net_neighbour_list_item** neighbour_ptr = &(node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ // push a pointer to a pointer to the edge on the stack ++ s.push(neighbour_ptr); ++ // if it has not been visited yet, enqueue a pointer to the target ++ // node of this edge ++ if ((*neighbour_ptr)->dst_node->visited == false) { ++ (*neighbour_ptr)->dst_node->visited = true; ++ q.push((*neighbour_ptr)->dst_node); ++ } ++ // move to the next neighbour ++ neighbour_ptr = &((*neighbour_ptr)->next); ++ } ++ } ++ ++ // initialize a set of level graph nodes with the 't' node ++ list l; ++ l.push_front(t_node); ++ ++ // do an inverse breadth-first search ++ while (!s.empty()) { ++ // pop the top element of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ s.pop(); ++ // check if the dst_node already belongs to the level graph ++ net_node_list_item* dst_node = (*neighbour_ptr)->dst_node; ++ list::iterator i; ++ for (i = l.begin(); i != l.end(); ++i) { ++ if (*i == dst_node) { ++ break; ++ } ++ } ++ if (i != l.end()) { // dst_node belongs to the level graph ++ // add also src_node to the level graph ++ l.push_front((*neighbour_ptr)->src_node); ++ } else { // dst_node does not belong to the level graph ++ // remove the edge from the flow network ++ net_neighbour_list_item* edge = (*neighbour_ptr); ++ *neighbour_ptr = (*neighbour_ptr)->next; ++ delete edge; ++ } ++ } ++} // end to_level_graph() ++ ++ ++/* ++ * Finds a blocking flow in the flow network, adds its value to the ++ * current flow in the corresponding filter graph, and also returns its ++ * value. ++ */ ++int Flow_network::find_blocking_flow() { ++ // check if the flow network exists at all ++ if (s_node == NULL) { ++ return 0; ++ } ++ ++ int blocking_flow = 0; ++ while (1) { // inifinite loop with return statement inside ++ // initialize auxiliary variables ++ stack s; ++ stack s_capacity; ++ net_node_list_item* node = s_node; ++ // do a depth-first search ++ while (node != t_node) { ++ while (node->neighbours == NULL) { // no output edges - traverse back ++ if (s.empty()) { // the stack is empty - no way to traverse back ++ return blocking_flow; ++ } ++ // traverse back along the edge on the top of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ net_neighbour_list_item* neighbour = *neighbour_ptr; ++ node = neighbour->src_node; ++ // pop the top elements of both stacks ++ s.pop(); ++ s_capacity.pop(); ++ // remove back-traversed edge ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } ++ // push the first edge of the current node and its remaining capacity on ++ // the respective stacks ++ s.push(&(node->neighbours)); ++ s_capacity.push(node->neighbours->capacity - node->neighbours->flow); ++ // move forward along the edge - update the current node ++ node = node->neighbours->dst_node; ++ } ++ ++ // determine the smallest capacity among edges of the found path ++ int min_capacity = s_capacity.top(); ++ s_capacity.pop(); ++ while (!s_capacity.empty()) { ++ // pop the top element of the capacity stack ++ int capacity = s_capacity.top(); ++ s_capacity.pop(); ++ if (capacity < min_capacity) { // update the smallest capacity ++ min_capacity = capacity; ++ } ++ } ++ ++ // update the flow through the found path according to min_capacity value ++ while (!s.empty()) { ++ // pop the top element of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ s.pop(); ++ // update the flow in both the flow network and filter graph ++ net_neighbour_list_item* neighbour = *neighbour_ptr; ++ neighbour->flow += min_capacity; ++ if (neighbour->forward_edge) { // forward edge ++ neighbour->orig_edge->flow += min_capacity; ++ } else { // backward edge ++ neighbour->orig_edge->flow -= min_capacity; ++ } ++ // remove the edge if its remaining capacity decreases to 0 ++ if (neighbour->capacity == neighbour->flow) { ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } ++ } ++ ++ // update the value of blocking flow through the flow network ++ blocking_flow += min_capacity; ++ } ++} // end find_blocking_flow() ++ ++ ++/* ++ * Prints the flow network. ++ */ ++void Flow_network::print() { ++ cout << "S_NODE:" << endl; ++ print_node_list(s_node); ++ cout << "--------------------" << endl; ++ ++ cout << "SRC_NODES:" << endl; ++ print_node_list(src_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "DST_NODES:" << endl; ++ print_node_list(dst_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "T_NODE:" << endl; ++ print_node_list(t_node); ++ cout << "--------------------" << endl; ++} +diff --git a/flow_network.h b/flow_network.h +new file mode 100644 +index 0000000..df76c3f +--- /dev/null ++++ b/flow_network.h +@@ -0,0 +1,362 @@ ++// flow_network.h: header file for Flow_network class ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef FLOW_NETWORK_H ++#define FLOW_NETWORK_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++#include "filter_graph.h" ++ ++// Library includes ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++ ++// Forward declarations (including typedef) to resolve circular dependency ++typedef struct net_node_list_item net_node_list_item; ++typedef struct net_neighbour_list_item net_neighbour_list_item; ++ ++/* ++ * A structure representing an item in a list of network nodes. ++ */ ++struct net_node_list_item { ++ // IP prefix represented by this node ++ IP_prefix prefix; ++ ++ // Flag showing whether the node was already visited during a traversal ++ bool visited; ++ ++ // List of neighbours ++ net_neighbour_list_item* neighbours; ++ ++ // Next item in list of network nodes ++ net_node_list_item* next; ++}; ++ ++/* ++ * A structure representing an item in a list of neighbours of a network node. ++ */ ++struct net_neighbour_list_item { ++ // Pointer to source node within list of network nodes ++ net_node_list_item* src_node; ++ ++ // Pointer to destination node within list of network nodes ++ net_node_list_item* dst_node; ++ ++ // Residual capacity of flow network's edge between neighbouring nodes ++ int capacity; ++ ++ // Flow through flow network's edge between neighbouring nodes ++ int flow; ++ ++ // Pointer to corresponding edge in filter graph ++ // (the pointer is the same for both forward and backward edges) ++ neighbour_list_item* orig_edge; ++ ++ // Flag showing whether this node represents a forward edge ++ bool forward_edge; ++ ++ // Next item in list of neighbours ++ net_neighbour_list_item* next; ++}; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a flow network -- i.e., weighted directed graph ++ * with special source (s) and terminate (t) nodes -- over a filter graph. ++ */ ++class Flow_network { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * Lists of source and destination nodes of the flow network. ++ */ ++ net_node_list_item* src_nodes; ++ net_node_list_item* dst_nodes; ++ ++ /* ++ * Special nodes 's' and 't' of the flow network. ++ */ ++ net_node_list_item* s_node; ++ net_node_list_item* t_node; ++ ++ /* ++ * Private static function that creates a deep copy of the original list. ++ * The function creates new instances of all items from the original list ++ * (as well as their neighbours sublists) and sets the value of their ++ * components according to this original list. The only exception is a ++ * pointer to destination node, which is initialized to NULL (it points ++ * to different list, thus it cannot be initialized to correct value ++ * during copying). ++ * @param orig Pointer to the constant original node list. ++ * @return Pointer to the copy of the original node list. ++ */ ++ static net_node_list_item* copy_node_list(const net_node_list_item* orig); ++ ++ /* ++ * Private static function that correctly deallocates the whole node ++ * list. ++ * The function traverses the given list and all its sublists and ++ * starting from lists of neighbours it deallocates all the traversed ++ * list items. ++ * @ param list Pointer to node list that is to be deallocated. ++ */ ++ static void remove_node_list(net_node_list_item* list); ++ ++ /* ++ * Private static function that sets correct values of destination node ++ * pointers, which cannot be correctly initialized during copying. ++ * The function simultaneously traverses neighbours lists in the orig and ++ * copy node lists. For each destination node from the orig list it looks ++ * for a corresponding item in either prev (backward edges) or next ++ * (forward edges) node list and stores the pointer to this node to the ++ * current item in the copy list. ++ * @param orig Pointer to the constant original node list. ++ * @param copy Pointer to the copy of the original node list ++ * (destination node pointers of this list are set). ++ * @param prev Pointer to the list of destination nodes of backward ++ * edges. ++ * @param next Pointer to the list of destination nodes of forward ++ * edges. ++ */ ++ static void set_destination_nodes(const net_node_list_item* orig, ++ net_node_list_item* copy, ++ net_node_list_item* prev, ++ net_node_list_item* next); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for a node with the given prefix in ++ * the given list of nodes. ++ * @param prefix Reference to a constant IP prefix of the node that the ++ * function looks for in the list. ++ * @param list Pointer to the list of nodes that is traversed during ++ * looking for the node with the given IP prefix. ++ * @return Pointer to the found node or NULL. ++ */ ++ static net_node_list_item* find_node(const IP_prefix& prefix, ++ net_node_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the corresponding neighbour ++ * node in the given list of neighbours. ++ * @param neighbour Pointer to a constant prefix node whose neighbour ++ * node the function looks for in the list. ++ * @param list Pointer to the list of neighbour nodes that is ++ * traversed during looking for the node corresponding ++ * to the given prefix node. ++ * @return Pointer to the found neighbour node or NULL. ++ */ ++ static net_neighbour_list_item* find_neighbour( ++ const net_node_list_item* neighbour, ++ net_neighbour_list_item* list); ++ ++ /* ++ * Private static function that inserts a node representing the given IP ++ * prefix at the beginning of the given list of nodes. ++ * @param prefix Reference to a constant IP prefix that is going to be ++ * represented by the inserted node. ++ * @param list Pointer to pointer to the list of nodes that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_node(const IP_prefix& prefix, ++ net_node_list_item** list); ++ ++ /* ++ * Private static function that inserts a neighbour node representing an ++ * edge between the given source and destination nodes at the beginning ++ * of the specified list of neighbour nodes. ++ * @param src_node Pointer to a source node of the represented ++ * edge. ++ * @param dst_node Pointer to a destination node of the represented ++ * edge. ++ * @param capacity Residual capacity of the represented edge. ++ * @param flow Flow through the represented edge. ++ * @param orig_edge Pointer to the corresponding edge in the filter ++ * graph. ++ * @param forward_edge Flag showing whether the inserted neighbour ++ * represents a forward edge. ++ * @param list Pointer to pointer to the list of neighbours ++ * that is going to be extended by the inserted ++ * node. ++ */ ++ static void insert_neighbour(net_node_list_item* src_node, ++ net_node_list_item* dst_node, ++ int capacity, ++ int flow, ++ neighbour_list_item* orig_edge, ++ bool forward_edge, ++ net_neighbour_list_item** list); ++ ++ /* ++ * Private static function that prints specified node list, including all ++ * sublists. ++ * @param nodes Pointer to the constant list of nodes that is to be ++ * printed. ++ */ ++ static void print_node_list(const net_node_list_item* nodes); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * All pointers are initialized to NULL. ++ */ ++ Flow_network(); ++ ++ /* ++ * Copy constructor. ++ * All pointers used by the filter graph are initialized to a deep copy ++ * of corresponding members of the original object. ++ * @param orig Reference to the constant original object. ++ */ ++ Flow_network(const Flow_network& orig); ++ ++ /* ++ * Copy assignment. ++ * The original object is destructed and its new content is constructed ++ * in a similar way as in the copy constructor. ++ * @param copy Reference to the constant copied object. ++ * @return Reference to the original object with new content. ++ */ ++ Flow_network& operator= (const Flow_network& copy); ++ ++ /* ++ * Destructor. ++ * Correctly deallocates all lists that are referenced by object members. ++ */ ++ ~Flow_network(); ++ ++ /* ++ * Get function for the src_nodes member. ++ * @return Pointer to the constant list of source nodes. ++ */ ++ inline const net_node_list_item* get_src_nodes() const { ++ return src_nodes; ++ } // end get_src_nodes() ++ ++ /* ++ * Get function for the dst_nodes member. ++ * @return Pointer to the constant list of destination nodes. ++ */ ++ inline const net_node_list_item* get_dst_nodes() const { ++ return dst_nodes; ++ } // end get_dst_nodes() ++ ++ /* ++ * Get function for the s_node member. ++ * @return Pointer to the constant special 's' node. ++ */ ++ inline const net_node_list_item* get_s_node() const { ++ return s_node; ++ } // end get_s_node() ++ ++ /* ++ * Get function for the t_node member. ++ * @return Pointer to the constant special 't' node. ++ */ ++ inline const net_node_list_item* get_t_node() const { ++ return t_node; ++ } // end get_t_node() ++ ++ /* ++ * Adds an edge to the flow network. ++ * First of all, if they are not already present, the function inserts ++ * nodes representing src_prefix and dst_prefix into node lists src_list ++ * and dst_list, respectively. Next, if it is not already present, the ++ * function inserts a neighbour node representing the edge into the list ++ * of neighbours of the node representing the source prefix. Flow item of ++ * the neighbour node is set to 0, while other items within its structure ++ * are set according to the function's parameters. ++ * @param src_prefix Reference to the IP_prefix object that ++ * determines a source node of the added edge. ++ * @param src_list Specification of a node list that contains the ++ * source node of the added edge. Mapping of the ++ * four allowed values to the node lists is the ++ * following: ++ * 0 ... s_node ++ * 1 ... src_node ++ * 2 ... dst_node ++ * 3 ... t_node ++ * @param dst_prefix Reference to the IP_prefix object that ++ * determines a destination node of the added edge. ++ * @param dst_list Specification of a node list that contains the ++ * destination node of the added edge. Mapping of ++ * the four allowed values to the node lists is the ++ * following: ++ * 0 ... s_node ++ * 1 ... src_node ++ * 2 ... dst_node ++ * 3 ... t_node ++ * @param orig_edge Pointer to the corresponding edge in the filter ++ * graph. ++ * @param forward_edge Flag showing whether the added edge represents a ++ * forward edge. ++ * @param capacity Residual capacity of the added edge. ++ */ ++ void add_edge(const IP_prefix& src_prefix, int src_list, ++ const IP_prefix& dst_prefix, int dst_list, ++ neighbour_list_item* orig_edge, bool forward_edge, ++ int capacity); ++ ++ /* ++ * Transforms the flow network into a level graph. ++ * During inverse BFS of the flow network, starting from a set containing ++ * the 't' node, the function incrementally extends the set by start ++ * nodes of edges ending in one of the set nodes and removes from the ++ * flow network edges that do not meet this condition. ++ */ ++ void to_level_graph(); ++ ++ /* ++ * Finds a blocking flow in the flow network, adds its value to the ++ * current flow in the corresponding filter graph, and also returns its ++ * value. ++ * The function repeatedly performs DST to find an s-t path in the flow ++ * network and the smallest capacity on this path. Once the function ++ * reaches the 't' node, it returns along the found path and increases ++ * the flow through the particular flow network edges as well as the ++ * corresponding filter graph edges. The function also updates capacities ++ * of backward-traversed flow network edges and removes them in case ++ * their capacity decreases to 0. In case of DFS ending in a node other ++ * than the 't' node, the function traverses back to the closest node ++ * with at least two output edges and removes all back-traversed edges. ++ * After each successful DFS and flow update on the found path, the ++ * function increases the value of the total flow through the flow ++ * network, which is returned at the end. ++ * The function expects that the flow network is in the form of a level ++ * graph at the time of invocation. ++ * @return The value of the blocking flow through the flow network. ++ */ ++ int find_blocking_flow(); ++ ++ /* ++ * Prints the flow network. ++ */ ++ void print(); ++}; ++ ++#endif +diff --git a/ip-address/COPYING b/ip-address/COPYING +new file mode 100644 +index 0000000..03fc9f6 +--- /dev/null ++++ b/ip-address/COPYING +@@ -0,0 +1,4 @@ ++Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++ ++Distributed under the Boost Software License, Version 1.0. (See accompanying ++file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +diff --git a/ip-address/LICENSE_1_0.txt b/ip-address/LICENSE_1_0.txt +new file mode 100644 +index 0000000..36b7cd9 +--- /dev/null ++++ b/ip-address/LICENSE_1_0.txt +@@ -0,0 +1,23 @@ ++Boost Software License - Version 1.0 - August 17th, 2003 ++ ++Permission is hereby granted, free of charge, to any person or organization ++obtaining a copy of the software and accompanying documentation covered by ++this license (the "Software") to use, reproduce, display, distribute, ++execute, and transmit the Software, and to prepare derivative works of the ++Software, and to permit third-parties to whom the Software is furnished to ++do so, all subject to the following: ++ ++The copyright notices in the Software and this entire statement, including ++the above license grant, this restriction and the following disclaimer, ++must be included in all copies of the Software, in whole or in part, and ++all derivative works of the Software, unless such copies or derivative ++works are solely in the form of machine-executable object code generated by ++a source language processor. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT ++SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ++FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ++ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++DEALINGS IN THE SOFTWARE. +diff --git a/ip-address/README.md b/ip-address/README.md +new file mode 100644 +index 0000000..08ff928 +--- /dev/null ++++ b/ip-address/README.md +@@ -0,0 +1,18 @@ ++IP Address Proposal ++=================== ++ ++Proposed IP addresses classes for the standard C++ library. ++ ++What's Included ++--------------- ++ ++* `./include` - Reference implementation. ++ ++Tested Platforms ++---------------- ++ ++* Mac OS 10.8 using g++ 4.7 (requires `-std=c++11`) ++* Mac OS 10.8 using clang++ from Xcode 4.6 (requires `-std=c++11` and `-stdlib=libc++`) ++* Linux (CentOS 6.2) using g++ 4.7 (requires `-std=c++11`) ++* Windows 7 32-bit using Visual Studio 2010 ++* Windows 7 x64 using Visual Studio 2010 +diff --git a/ip-address/include/network b/ip-address/include/network +new file mode 100644 +index 0000000..c97ea69 +--- /dev/null ++++ b/ip-address/include/network +@@ -0,0 +1,25 @@ ++// ++// network ++// ~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_NETWORK_HEADER_FILE ++#define STDNET_NETWORK_HEADER_FILE ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++#include "std/net/ip/address_cast.hpp" ++#include "std/net/literals.hpp" ++ ++#endif // STDNET_NETWORK_HEADER_FILE +diff --git a/ip-address/include/std/net/detail/config.hpp b/ip-address/include/std/net/detail/config.hpp +new file mode 100644 +index 0000000..c797490 +--- /dev/null ++++ b/ip-address/include/std/net/detail/config.hpp +@@ -0,0 +1,666 @@ ++// ++// detail/config.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_CONFIG_HPP ++#define STDNET_DETAIL_CONFIG_HPP ++ ++// Default to a header-only implementation. The user must specifically request ++// separate compilation by defining either STDNET_SEPARATE_COMPILATION or ++// STDNET_DYN_LINK (as a DLL/shared library implies separate compilation). ++#if !defined(STDNET_HEADER_ONLY) ++# if !defined(STDNET_SEPARATE_COMPILATION) ++# if !defined(STDNET_DYN_LINK) ++# define STDNET_HEADER_ONLY 1 ++# endif // !defined(STDNET_DYN_LINK) ++# endif // !defined(STDNET_SEPARATE_COMPILATION) ++#endif // !defined(STDNET_HEADER_ONLY) ++ ++#if defined(STDNET_HEADER_ONLY) ++# define STDNET_DECL inline ++#else // defined(STDNET_HEADER_ONLY) ++# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) ++// We need to import/export our code only if the user has specifically asked ++// for it by defining STDNET_DYN_LINK. ++# if defined(STDNET_DYN_LINK) ++// Export if this is our own source, otherwise import. ++# if defined(STDNET_SOURCE) ++# define STDNET_DECL __declspec(dllexport) ++# else // defined(STDNET_SOURCE) ++# define STDNET_DECL __declspec(dllimport) ++# endif // defined(STDNET_SOURCE) ++# endif // defined(STDNET_DYN_LINK) ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) ++#endif // defined(STDNET_HEADER_ONLY) ++ ++// If STDNET_DECL isn't defined yet define it now. ++#if !defined(STDNET_DECL) ++# define STDNET_DECL ++#endif // !defined(STDNET_DECL) ++ ++// Microsoft Visual C++ detection. ++#if !defined(STDNET_MSVC) ++# if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__EDG_VERSION__) ++# define STDNET_MSVC _MSC_VER ++# endif // defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__EDG_VERSION__) ++#endif // defined(STDNET_MSVC) ++ ++// Support move construction and assignment on compilers known to allow it. ++#if !defined(STDNET_HAS_MOVE) ++# if !defined(STDNET_DISABLE_MOVE) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_MOVE 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_MOVE) ++#endif // !defined(STDNET_HAS_MOVE) ++ ++// If STDNET_MOVE_CAST isn't defined, and move support is available, define ++// STDNET_MOVE_ARG and STDNET_MOVE_CAST to take advantage of rvalue ++// references and perfect forwarding. ++#if defined(STDNET_HAS_MOVE) && !defined(STDNET_MOVE_CAST) ++# define STDNET_MOVE_ARG(type) type&& ++# define STDNET_MOVE_CAST(type) static_cast ++#endif // defined(STDNET_HAS_MOVE) && !defined(STDNET_MOVE_CAST) ++ ++// If STDNET_MOVE_CAST still isn't defined, default to a C++03-compatible ++// implementation. Note that older g++ and MSVC versions don't like it when you ++// pass a non-member function through a const reference, so for most compilers ++// we'll play it safe and stick with the old approach of passing the handler by ++// value. ++#if !defined(STDNET_MOVE_CAST) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# define STDNET_MOVE_ARG(type) const type& ++# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# define STDNET_MOVE_ARG(type) type ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# elif defined(STDNET_MSVC) ++# if (_MSC_VER >= 1400) ++# define STDNET_MOVE_ARG(type) const type& ++# else // (_MSC_VER >= 1400) ++# define STDNET_MOVE_ARG(type) type ++# endif // (_MSC_VER >= 1400) ++# else ++# define STDNET_MOVE_ARG(type) type ++# endif ++# define STDNET_MOVE_CAST(type) static_cast ++#endif // !defined_STDNET_MOVE_CAST ++ ++// Support variadic templates on compilers known to allow it. ++#if !defined(STDNET_HAS_VARIADIC_TEMPLATES) ++# if !defined(STDNET_DISABLE_VARIADIC_TEMPLATES) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_VARIADIC_TEMPLATES 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_variadic_templates) ++# define STDNET_HAS_VARIADIC_TEMPLATES 1 ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# endif // !defined(STDNET_DISABLE_VARIADIC_TEMPLATES) ++#endif // !defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++// Support the noexcept specifier on compilers known to allow it. ++#if !defined(STDNET_NOEXCEPT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_NOEXCEPT noexcept ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_noexcept) ++# define STDNET_NOEXCEPT noexcept ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_NOEXCEPT) ++# define STDNET_NOEXCEPT ++# endif // !defined(STDNET_NOEXCEPT) ++#endif // !defined(STDNET_NOEXCEPT) ++ ++// Support deleted functions on compilers known to allow it. ++#if !defined(STDNET_DELETED) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_DELETED = delete ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_deleted_functions) ++# define STDNET_DELETED = delete ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_DELETED) ++# define STDNET_DELETED ++# endif // !defined(STDNET_DELETED) ++#endif // !defined(STDNET_DELETED) ++ ++// Support relaxed constexpr on compilers known to allow it. ++#if !defined(STDNET_CONSTEXPR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_CONSTEXPR 1 ++# define STDNET_CONSTEXPR constexpr ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_constexpr) ++# define STDNET_HAS_CONSTEXPR 1 ++# define STDNET_CONSTEXPR constexpr ++# endif // __has_feature(cxx_constexpr) ++# endif // defined(__clang__) ++# if !defined(STDNET_CONSTEXPR) ++# define STDNET_CONSTEXPR ++# endif // !defined(STDNET_CONSTEXPR) ++#endif // !defined(STDNET_CONSTEXPR) ++ ++// Standard library support for system errors. ++#if !defined(STDNET_HAS_STD_SYSTEM_ERROR) ++# if !defined(STDNET_DISABLE_STD_SYSTEM_ERROR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_SYSTEM_ERROR 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_SYSTEM_ERROR) ++#endif // !defined(STDNET_HAS_STD_SYSTEM_ERROR) ++ ++// Compliant C++11 compilers put noexcept specifiers on error_category members. ++#if !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_noexcept) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT ++# endif // !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++#endif // !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++ ++// Standard library support for arrays. ++#if !defined(STDNET_HAS_STD_ARRAY) ++# if !defined(STDNET_DISABLE_STD_ARRAY) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ARRAY 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(STDNET_MSVC) ++# if (_MSC_VER >= 1600) ++# define STDNET_HAS_STD_ARRAY 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(STDNET_MSVC) ++# endif // !defined(STDNET_DISABLE_STD_ARRAY) ++#endif // !defined(STDNET_HAS_STD_ARRAY) ++ ++// Standard library support for shared_ptr and weak_ptr. ++#if !defined(STDNET_HAS_STD_SHARED_PTR) ++# if !defined(STDNET_DISABLE_STD_SHARED_PTR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_SHARED_PTR 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(STDNET_MSVC) ++# if (_MSC_VER >= 1600) ++# define STDNET_HAS_STD_SHARED_PTR 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(STDNET_MSVC) ++# endif // !defined(STDNET_DISABLE_STD_SHARED_PTR) ++#endif // !defined(STDNET_HAS_STD_SHARED_PTR) ++ ++// Standard library support for atomic operations. ++#if !defined(STDNET_HAS_STD_ATOMIC) ++# if !defined(STDNET_DISABLE_STD_ATOMIC) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ATOMIC 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_ATOMIC) ++#endif // !defined(STDNET_HAS_STD_ATOMIC) ++ ++// Standard library support for chrono. Some standard libraries (such as the ++// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x ++// drafts, rather than the eventually standardised name of steady_clock. ++#if !defined(STDNET_HAS_STD_CHRONO) ++# if !defined(STDNET_DISABLE_STD_CHRONO) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_CHRONO 1 ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) ++# define STDNET_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_CHRONO) ++#endif // !defined(STDNET_HAS_STD_CHRONO) ++ ++// Standard library support for addressof. ++#if !defined(STDNET_HAS_STD_ADDRESSOF) ++# if !defined(STDNET_DISABLE_STD_ADDRESSOF) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ADDRESSOF 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_ADDRESSOF) ++#endif // !defined(STDNET_HAS_STD_ADDRESSOF) ++ ++// Standard library support for the function class. ++#if !defined(STDNET_HAS_STD_FUNCTION) ++# if !defined(STDNET_DISABLE_STD_FUNCTION) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_FUNCTION 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_FUNCTION) ++#endif // !defined(STDNET_HAS_STD_FUNCTION) ++ ++// Standard library support for type traits. ++#if !defined(STDNET_HAS_STD_TYPE_TRAITS) ++# if !defined(STDNET_DISABLE_STD_TYPE_TRAITS) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_TYPE_TRAITS 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_TYPE_TRAITS) ++#endif // !defined(STDNET_HAS_STD_TYPE_TRAITS) ++ ++// Standard library support for the cstdint header. ++#if !defined(STDNET_HAS_CSTDINT) ++# if !defined(STDNET_DISABLE_CSTDINT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_CSTDINT 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_CSTDINT) ++#endif // !defined(STDNET_HAS_CSTDINT) ++ ++// Windows target. ++#if !defined(STDNET_WINDOWS) ++# if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ++# define STDNET_WINDOWS 1 ++# endif // defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ++#endif // !defined(STDNET_WINDOWS) ++ ++// Windows: target OS version. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) ++# if defined(_MSC_VER) || defined(__BORLANDC__) ++# pragma message( \ ++ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ ++ "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ ++ "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ ++ "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") ++# else // defined(_MSC_VER) || defined(__BORLANDC__) ++# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. ++# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. ++# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) ++# define _WIN32_WINNT 0x0501 ++# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) ++# if defined(_MSC_VER) ++# if defined(_WIN32) && !defined(WIN32) ++# if !defined(_WINSOCK2API_) ++# define WIN32 // Needed for correct types in winsock2.h ++# else // !defined(_WINSOCK2API_) ++# error Please define the macro WIN32 in your compiler options ++# endif // !defined(_WINSOCK2API_) ++# endif // defined(_WIN32) && !defined(WIN32) ++# endif // defined(_MSC_VER) ++# if defined(__BORLANDC__) ++# if defined(__WIN32__) && !defined(WIN32) ++# if !defined(_WINSOCK2API_) ++# define WIN32 // Needed for correct types in winsock2.h ++# else // !defined(_WINSOCK2API_) ++# error Please define the macro WIN32 in your compiler options ++# endif // !defined(_WINSOCK2API_) ++# endif // defined(__WIN32__) && !defined(WIN32) ++# endif // defined(__BORLANDC__) ++# if defined(__CYGWIN__) ++# if !defined(__USE_W32_SOCKETS) ++# error You must add -D__USE_W32_SOCKETS to your compiler options. ++# endif // !defined(__USE_W32_SOCKETS) ++# endif // defined(__CYGWIN__) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: minimise header inclusion. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(STDNET_NO_WIN32_LEAN_AND_MEAN) ++# if !defined(WIN32_LEAN_AND_MEAN) ++# define WIN32_LEAN_AND_MEAN ++# endif // !defined(WIN32_LEAN_AND_MEAN) ++# endif // !defined(STDNET_NO_WIN32_LEAN_AND_MEAN) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: suppress definition of "min" and "max" macros. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(STDNET_NO_NOMINMAX) ++# if !defined(NOMINMAX) ++# define NOMINMAX 1 ++# endif // !defined(NOMINMAX) ++# endif // !defined(STDNET_NO_NOMINMAX) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: No ANSI API calls. ++#if !defined(STDNET_NO_ANSI_APIS) ++# if defined(STDNET_WINDOWS) && defined(UNDER_CE) ++# define STDNET_NO_ANSI_APIS 1 ++# endif // defined(STDNET_WINDOWS) && defined(UNDER_CE) ++#endif // !defined(STDNET_NO_ANSI_APIS) ++ ++// Windows: IO Completion Ports. ++#if !defined(STDNET_HAS_IOCP) ++# if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) ++# if !defined(UNDER_CE) ++# if !defined(STDNET_DISABLE_IOCP) ++# define STDNET_HAS_IOCP 1 ++# endif // !defined(STDNET_DISABLE_IOCP) ++# endif // !defined(UNDER_CE) ++# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) ++# endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++#endif // !defined(STDNET_HAS_IOCP) ++ ++// Linux: epoll, eventfd and timerfd. ++#if defined(__linux__) ++# include ++# if !defined(STDNET_HAS_EPOLL) ++# if !defined(STDNET_DISABLE_EPOLL) ++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) ++# define STDNET_HAS_EPOLL 1 ++# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) ++# endif // !defined(STDNET_DISABLE_EPOLL) ++# endif // !defined(STDNET_HAS_EPOLL) ++# if !defined(STDNET_HAS_EVENTFD) ++# if !defined(STDNET_DISABLE_EVENTFD) ++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++# define STDNET_HAS_EVENTFD 1 ++# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++# endif // !defined(STDNET_DISABLE_EVENTFD) ++# endif // !defined(STDNET_HAS_EVENTFD) ++# if !defined(STDNET_HAS_TIMERFD) ++# if defined(STDNET_HAS_EPOLL) ++# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) ++# define STDNET_HAS_TIMERFD 1 ++# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) ++# endif // defined(STDNET_HAS_EPOLL) ++# endif // !defined(STDNET_HAS_TIMERFD) ++#endif // defined(__linux__) ++ ++// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. ++#if (defined(__MACH__) && defined(__APPLE__)) \ ++ || defined(__FreeBSD__) \ ++ || defined(__NetBSD__) \ ++ || defined(__OpenBSD__) ++# if !defined(STDNET_HAS_KQUEUE) ++# if !defined(STDNET_DISABLE_KQUEUE) ++# define STDNET_HAS_KQUEUE 1 ++# endif // !defined(STDNET_DISABLE_KQUEUE) ++# endif // !defined(STDNET_HAS_KQUEUE) ++#endif // (defined(__MACH__) && defined(__APPLE__)) ++ // || defined(__FreeBSD__) ++ // || defined(__NetBSD__) ++ // || defined(__OpenBSD__) ++ ++// Solaris: /dev/poll. ++#if defined(__sun) ++# if !defined(STDNET_HAS_DEV_POLL) ++# if !defined(STDNET_DISABLE_DEV_POLL) ++# define STDNET_HAS_DEV_POLL 1 ++# endif // !defined(STDNET_DISABLE_DEV_POLL) ++# endif // !defined(STDNET_HAS_DEV_POLL) ++#endif // defined(__sun) ++ ++// Serial ports. ++#if !defined(STDNET_HAS_SERIAL_PORT) ++# if defined(STDNET_HAS_IOCP) \ ++ || !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# if !defined(__SYMBIAN32__) ++# if !defined(STDNET_DISABLE_SERIAL_PORT) ++# define STDNET_HAS_SERIAL_PORT 1 ++# endif // !defined(STDNET_DISABLE_SERIAL_PORT) ++# endif // !defined(__SYMBIAN32__) ++# endif // defined(STDNET_HAS_IOCP) ++ // || !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++#endif // !defined(STDNET_HAS_SERIAL_PORT) ++ ++// Windows: stream handles. ++#if !defined(STDNET_HAS_WINDOWS_STREAM_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_STREAM_HANDLE) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_STREAM_HANDLE 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_STREAM_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_STREAM_HANDLE) ++ ++// Windows: random access handles. ++#if !defined(STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++ ++// Windows: object handles. ++#if !defined(STDNET_HAS_WINDOWS_OBJECT_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_OBJECT_HANDLE) ++# if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(UNDER_CE) ++# define STDNET_HAS_WINDOWS_OBJECT_HANDLE 1 ++# endif // !defined(UNDER_CE) ++# endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_WINDOWS_OBJECT_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_OBJECT_HANDLE) ++ ++// Windows: OVERLAPPED wrapper. ++#if !defined(STDNET_HAS_WINDOWS_OVERLAPPED_PTR) ++# if !defined(STDNET_DISABLE_WINDOWS_OVERLAPPED_PTR) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_OVERLAPPED_PTR 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_OVERLAPPED_PTR) ++#endif // !defined(STDNET_HAS_WINDOWS_OVERLAPPED_PTR) ++ ++// POSIX: stream-oriented file descriptors. ++#if !defined(STDNET_HAS_POSIX_STREAM_DESCRIPTOR) ++# if !defined(STDNET_DISABLE_POSIX_STREAM_DESCRIPTOR) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_POSIX_STREAM_DESCRIPTOR 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_POSIX_STREAM_DESCRIPTOR) ++#endif // !defined(STDNET_HAS_POSIX_STREAM_DESCRIPTOR) ++ ++// UNIX domain sockets. ++#if !defined(STDNET_HAS_LOCAL_SOCKETS) ++# if !defined(STDNET_DISABLE_LOCAL_SOCKETS) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_LOCAL_SOCKETS 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_LOCAL_SOCKETS) ++#endif // !defined(STDNET_HAS_LOCAL_SOCKETS) ++ ++// Can use sigaction() instead of signal(). ++#if !defined(STDNET_HAS_SIGACTION) ++# if !defined(STDNET_DISABLE_SIGACTION) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_SIGACTION 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_SIGACTION) ++#endif // !defined(STDNET_HAS_SIGACTION) ++ ++// Can use signal(). ++#if !defined(STDNET_HAS_SIGNAL) ++# if !defined(STDNET_DISABLE_SIGNAL) ++# if !defined(UNDER_CE) ++# define STDNET_HAS_SIGNAL 1 ++# endif // !defined(UNDER_CE) ++# endif // !defined(STDNET_DISABLE_SIGNAL) ++#endif // !defined(STDNET_HAS_SIGNAL) ++ ++// Whether standard iostreams are disabled. ++//#if !defined(STDNET_NO_IOSTREAM) ++//# define STDNET_NO_IOSTREAM 1 ++//#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// Whether exception handling is disabled. ++//#if !defined(STDNET_NO_EXCEPTIONS) ++//# define STDNET_NO_EXCEPTIONS 1 ++//#endif // !defined(STDNET_NO_EXCEPTIONS) ++ ++// Whether the typeid operator is supported. ++//#if !defined(STDNET_NO_TYPEID) ++//# define STDNET_NO_TYPEID 1 ++//#endif // !defined(STDNET_NO_TYPEID) ++ ++// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to ++// get access to the various platform feature macros, e.g. to be able to test ++// for threads support. ++#if !defined(STDNET_HAS_UNISTD_H) ++# if defined(unix) \ ++ || defined(__unix) \ ++ || defined(_XOPEN_SOURCE) \ ++ || defined(_POSIX_SOURCE) \ ++ || (defined(__MACH__) && defined(__APPLE__)) \ ++ || defined(__FreeBSD__) \ ++ || defined(__NetBSD__) \ ++ || defined(__OpenBSD__) \ ++ || defined(__linux__) ++# define STDNET_HAS_UNISTD_H 1 ++# endif ++#endif // !defined(STDNET_HAS_UNISTD_H) ++#if defined(STDNET_HAS_UNISTD_H) ++# include ++#endif // defined(STDNET_HAS_UNISTD_H) ++ ++// Threads. ++#if !defined(STDNET_HAS_THREADS) ++# if !defined(STDNET_DISABLE_THREADS) ++# if defined(_MSC_VER) && defined(_MT) ++# define STDNET_HAS_THREADS 1 ++# elif defined(__BORLANDC__) && defined(__MT__) ++# define STDNET_HAS_THREADS 1 ++# elif defined(_POSIX_THREADS) ++# define STDNET_HAS_THREADS 1 ++# endif // defined(_MSC_VER) && defined(_MT) ++# endif // !defined(STDNET_DISABLE_THREADS) ++#endif // !defined(STDNET_HAS_THREADS) ++ ++// POSIX threads. ++#if !defined(STDNET_HAS_PTHREADS) ++# if defined(STDNET_HAS_THREADS) ++# if defined(_POSIX_THREADS) ++# define STDNET_HAS_PTHREADS 1 ++# endif // defined(_POSIX_THREADS) ++# endif // defined(STDNET_HAS_THREADS) ++#endif // !defined(STDNET_HAS_PTHREADS) ++ ++// Helper to prevent macro expansion. ++#define STDNET_PREVENT_MACRO_SUBSTITUTION ++ ++// Helper to define in-class constants. ++#if !defined(STDNET_STATIC_CONSTANT) ++# define STDNET_STATIC_CONSTANT(type, assignment) \ ++ static const type assignment ++#endif // !defined(STDNET_STATIC_CONSTANT) ++ ++// Microsoft Visual C++'s secure C runtime library. ++#if !defined(STDNET_HAS_SECURE_RTL) ++# if !defined(STDNET_DISABLE_SECURE_RTL) ++# if defined(STDNET_MSVC) \ ++ && (STDNET_MSVC >= 1400) \ ++ && !defined(UNDER_CE) ++# define STDNET_HAS_SECURE_RTL 1 ++# endif // defined(STDNET_MSVC) ++ // && (STDNET_MSVC >= 1400) ++ // && !defined(UNDER_CE) ++# endif // !defined(STDNET_DISABLE_SECURE_RTL) ++#endif // !defined(STDNET_HAS_SECURE_RTL) ++ ++// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. ++#if !defined(STDNET_HAS_HANDLER_HOOKS) ++# if !defined(STDNET_DISABLE_HANDLER_HOOKS) ++# if defined(__GNUC__) ++# if (__GNUC__ >= 3) ++# define STDNET_HAS_HANDLER_HOOKS 1 ++# endif // (__GNUC__ >= 3) ++# elif !defined(__BORLANDC__) ++# define STDNET_HAS_HANDLER_HOOKS 1 ++# endif // !defined(__BORLANDC__) ++# endif // !defined(STDNET_DISABLE_HANDLER_HOOKS) ++#endif // !defined(STDNET_HAS_HANDLER_HOOKS) ++ ++// Support for the __thread keyword extension. ++#if !defined(STDNET_DISABLE_THREAD_KEYWORD_EXTENSION) ++# if defined(__linux__) ++# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) ++# if !defined(__INTEL_COMPILER) && !defined(__ICL) ++# define STDNET_HAS_THREAD_KEYWORD_EXTENSION 1 ++# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) ++# define STDNET_HAS_THREAD_KEYWORD_EXTENSION 1 ++# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) ++# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) ++# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++# endif // defined(__linux__) ++#endif // !defined(STDNET_DISABLE_THREAD_KEYWORD_EXTENSION) ++ ++// Support for POSIX ssize_t typedef. ++#if !defined(STDNET_DISABLE_SSIZE_T) ++# if defined(__linux__) \ ++ || (defined(__MACH__) && defined(__APPLE__)) ++# define STDNET_HAS_SSIZE_T 1 ++# endif // defined(__linux__) ++ // || (defined(__MACH__) && defined(__APPLE__)) ++#endif // !defined(STDNET_DISABLE_SSIZE_T) ++ ++#endif // STDNET_DETAIL_CONFIG_HPP +diff --git a/ip-address/include/std/net/detail/impl/socket_ops.ipp b/ip-address/include/std/net/detail/impl/socket_ops.ipp +new file mode 100644 +index 0000000..13b32a3 +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/socket_ops.ipp +@@ -0,0 +1,260 @@ ++// ++// detail/impl/socket_ops.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_OPS_IPP ++#define STDNET_DETAIL_SOCKET_OPS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include ++#include ++#include ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace socket_ops { ++ ++#if defined(__hpux) ++// HP-UX doesn't declare these functions extern "C", so they are declared again ++// here to avoid linker errors about undefined symbols. ++extern "C" char* if_indextoname(unsigned int, char*); ++extern "C" unsigned int if_nametoindex(const char*); ++#endif // defined(__hpux) ++ ++inline void clear_last_error() ++{ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ WSASetLastError(0); ++#else ++ errno = 0; ++#endif ++} ++ ++template ++inline ReturnType error_wrapper(ReturnType return_value, ++ std::error_code& ec) ++{ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ec = std::error_code(WSAGetLastError(), ++ std::experimental::net::detail::syserrc::system_category()); ++#else ++ ec = std::error_code(errno, ++ std::experimental::net::detail::syserrc::system_category()); ++#endif ++ return return_value; ++} ++ ++const char* inet_ntop(int af, const void* src, char* dest, size_t length, ++ unsigned long scope_id, std::error_code& ec) ++{ ++ clear_last_error(); ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ using namespace std; // For memcpy. ++ ++ if (af != AF_INET && af != AF_INET6) ++ { ++ ec = std::experimental::net::detail::syserrc::address_family_not_supported; ++ return 0; ++ } ++ ++ union ++ { ++ socket_addr_type base; ++ sockaddr_storage_type storage; ++ sockaddr_in4_type v4; ++ sockaddr_in6_type v6; ++ } address; ++ DWORD address_length; ++ if (af == AF_INET) ++ { ++ address_length = sizeof(sockaddr_in4_type); ++ address.v4.sin_family = AF_INET; ++ address.v4.sin_port = 0; ++ memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); ++ } ++ else // AF_INET6 ++ { ++ address_length = sizeof(sockaddr_in6_type); ++ address.v6.sin6_family = AF_INET6; ++ address.v6.sin6_port = 0; ++ address.v6.sin6_flowinfo = 0; ++ address.v6.sin6_scope_id = scope_id; ++ memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); ++ } ++ ++ DWORD string_length = static_cast(length); ++#if defined(STDNET_NO_ANSI_APIS) ++ LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); ++ int result = error_wrapper(::WSAAddressToStringW(&address.base, ++ address_length, 0, string_buffer, &string_length), ec); ++ ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); ++#else ++ int result = error_wrapper(::WSAAddressToStringA( ++ &address.base, address_length, 0, dest, &string_length), ec); ++#endif ++ ++ // Windows may set error code on success. ++ if (result != socket_error_retval) ++ ec = std::error_code(); ++ ++ // Windows may not set an error code on failure. ++ else if (result == socket_error_retval && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ ++ return result == socket_error_retval ? 0 : dest; ++#else // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ const char* result = error_wrapper(::inet_ntop( ++ af, src, dest, static_cast(length)), ec); ++ if (result == 0 && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ if (result != 0 && af == AF_INET6 && scope_id != 0) ++ { ++ using namespace std; // For strcat and sprintf. ++ char if_name[IF_NAMESIZE + 1] = "%"; ++ const in6_addr_type* ipv6_address = static_cast(src); ++ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) ++ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); ++ if (!is_link_local ++ || if_indextoname(static_cast(scope_id), if_name + 1) == 0) ++ sprintf(if_name + 1, "%lu", scope_id); ++ strcat(dest, if_name); ++ } ++ return result; ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++} ++ ++int inet_pton(int af, const char* src, void* dest, ++ unsigned long* scope_id, std::error_code& ec) ++{ ++ clear_last_error(); ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ using namespace std; // For memcpy and strcmp. ++ ++ if (af != AF_INET && af != AF_INET6) ++ { ++ ec = std::experimental::net::detail::syserrc::address_family_not_supported; ++ return -1; ++ } ++ ++ union ++ { ++ socket_addr_type base; ++ sockaddr_storage_type storage; ++ sockaddr_in4_type v4; ++ sockaddr_in6_type v6; ++ } address; ++ int address_length = sizeof(sockaddr_storage_type); ++#if defined(STDNET_NO_ANSI_APIS) ++ int num_wide_chars = strlen(src) + 1; ++ LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); ++ ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); ++ int result = error_wrapper(::WSAStringToAddressW( ++ wide_buffer, af, 0, &address.base, &address_length), ec); ++#else ++ int result = error_wrapper(::WSAStringToAddressA( ++ const_cast(src), af, 0, &address.base, &address_length), ec); ++#endif ++ ++ if (af == AF_INET) ++ { ++ if (result != socket_error_retval) ++ { ++ memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); ++ ec = std::error_code(); ++ } ++ else if (strcmp(src, "255.255.255.255") == 0) ++ { ++ static_cast(dest)->s_addr = INADDR_NONE; ++ ec = std::error_code(); ++ } ++ } ++ else // AF_INET6 ++ { ++ if (result != socket_error_retval) ++ { ++ memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); ++ if (scope_id) ++ *scope_id = address.v6.sin6_scope_id; ++ ec = std::error_code(); ++ } ++ } ++ ++ // Windows may not set an error code on failure. ++ if (result == socket_error_retval && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ ++ if (result != socket_error_retval) ++ ec = std::error_code(); ++ ++ return result == socket_error_retval ? -1 : 1; ++#else // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ int result = error_wrapper(::inet_pton(af, src, dest), ec); ++ if (result <= 0 && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ if (result > 0 && af == AF_INET6 && scope_id) ++ { ++ using namespace std; // For strchr and atoi. ++ *scope_id = 0; ++ if (const char* if_name = strchr(src, '%')) ++ { ++ in6_addr_type* ipv6_address = static_cast(dest); ++ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) ++ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); ++ if (is_link_local) ++ *scope_id = if_nametoindex(if_name + 1); ++ if (*scope_id == 0) ++ *scope_id = atoi(if_name + 1); ++ } ++ } ++ return result; ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++} ++ ++u_long_type network_to_host_long(u_long_type value) ++{ ++ return ntohl(value); ++} ++ ++u_long_type host_to_network_long(u_long_type value) ++{ ++ return htonl(value); ++} ++ ++u_short_type network_to_host_short(u_short_type value) ++{ ++ return ntohs(value); ++} ++ ++u_short_type host_to_network_short(u_short_type value) ++{ ++ return htons(value); ++} ++ ++} // namespace socket_ops ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_SOCKET_OPS_IPP +diff --git a/ip-address/include/std/net/detail/impl/system_errors.ipp b/ip-address/include/std/net/detail/impl/system_errors.ipp +new file mode 100644 +index 0000000..8b01e08 +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/system_errors.ipp +@@ -0,0 +1,94 @@ ++// ++// impl/system_errors.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP ++#define STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/local_free_on_block_exit.hpp" ++#include "std/net/detail/system_errors.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++class system_category : public std::error_category ++{ ++public: ++ const char* name() const STDNET_ERROR_CATEGORY_NOEXCEPT ++ { ++ return "std.net.system"; ++ } ++ ++ std::string message(int value) const ++ { ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ char* msg = 0; ++ DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER ++ | FORMAT_MESSAGE_FROM_SYSTEM ++ | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value, ++ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0); ++ detail::local_free_on_block_exit local_free_obj(msg); ++ if (length && msg[length - 1] == '\n') ++ msg[--length] = '\0'; ++ if (length && msg[length - 1] == '\r') ++ msg[--length] = '\0'; ++ if (length) ++ return msg; ++ else ++ return "std.net.system error"; ++#else // defined(STDNET_WINDOWS) ++#if !defined(__sun) ++ if (value == ECANCELED) ++ return "Operation aborted."; ++#endif // !defined(__sun) ++#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__) ++ using namespace std; ++ return strerror(value); ++#elif defined(__MACH__) && defined(__APPLE__) \ ++ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ ++ || defined(_AIX) || defined(__hpux) || defined(__osf__) \ ++ || defined(__ANDROID__) ++ char buf[256] = ""; ++ using namespace std; ++ strerror_r(value, buf, sizeof(buf)); ++ return buf; ++#else ++ char buf[256] = ""; ++ return strerror_r(value, buf, sizeof(buf)); ++#endif ++#endif // defined(STDNET_WINDOWS) ++ } ++}; ++ ++} // namespace syserrc ++ ++const std::error_category& system_category() ++{ ++ static syserrc::system_category instance; ++ return instance; ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP +diff --git a/ip-address/include/std/net/detail/impl/throw_error.ipp b/ip-address/include/std/net/detail/impl/throw_error.ipp +new file mode 100644 +index 0000000..92baf1c +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/throw_error.ipp +@@ -0,0 +1,49 @@ ++// ++// detail/impl/throw_error.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_THROW_ERROR_IPP ++#define STDNET_DETAIL_IMPL_THROW_ERROR_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++void do_throw_error(const std::error_code& err) ++{ ++ std::system_error e(err); ++ std::experimental::net::detail::throw_exception(e); ++} ++ ++void do_throw_error(const std::error_code& err, const char* location) ++{ ++ std::system_error e(err, location); ++ std::experimental::net::detail::throw_exception(e); ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_IMPL_THROW_ERROR_IPP +diff --git a/ip-address/include/std/net/detail/impl/winsock_init.ipp b/ip-address/include/std/net/detail/impl/winsock_init.ipp +new file mode 100644 +index 0000000..7114f6a +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/winsock_init.ipp +@@ -0,0 +1,73 @@ ++// ++// detail/impl/winsock_init.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP ++#define STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/socket_types.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/winsock_init.hpp" ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++void winsock_init_base::startup(data& d, ++ unsigned char major, unsigned char minor) ++{ ++ if (::InterlockedIncrement(&d.init_count_) == 1) ++ { ++ WSADATA wsa_data; ++ long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); ++ ::InterlockedExchange(&d.result_, result); ++ } ++} ++ ++void winsock_init_base::cleanup(data& d) ++{ ++ if (::InterlockedDecrement(&d.init_count_) == 0) ++ { ++ ::WSACleanup(); ++ } ++} ++ ++void winsock_init_base::throw_on_error(data& d) ++{ ++ long result = ::InterlockedExchangeAdd(&d.result_, 0); ++ if (result != 0) ++ { ++ std::error_code ec(result, ++ std::experimental::net::detail::system_category()); ++ std::experimental::net::detail::throw_error(ec, "winsock"); ++ } ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP +diff --git a/ip-address/include/std/net/detail/local_free_on_block_exit.hpp b/ip-address/include/std/net/detail/local_free_on_block_exit.hpp +new file mode 100644 +index 0000000..64c9137 +--- /dev/null ++++ b/ip-address/include/std/net/detail/local_free_on_block_exit.hpp +@@ -0,0 +1,63 @@ ++// ++// detail/local_free_on_block_exit.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP ++#define STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/socket_types.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++class local_free_on_block_exit ++{ ++public: ++ // Constructor blocks all signals for the calling thread. ++ explicit local_free_on_block_exit(void* p) ++ : p_(p) ++ { ++ } ++ ++ // Destructor restores the previous signal mask. ++ ~local_free_on_block_exit() ++ { ++ ::LocalFree(p_); ++ } ++ ++private: ++ // Disallow copying and assignemnt. ++ local_free_on_block_exit(const local_free_on_block_exit&); ++ local_free_on_block_exit& operator=(const local_free_on_block_exit&); ++ ++ void* p_; ++}; ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP +diff --git a/ip-address/include/std/net/detail/old_win_sdk_compat.hpp b/ip-address/include/std/net/detail/old_win_sdk_compat.hpp +new file mode 100644 +index 0000000..3a3cdac +--- /dev/null ++++ b/ip-address/include/std/net/detail/old_win_sdk_compat.hpp +@@ -0,0 +1,218 @@ ++// ++// detail/old_win_sdk_compat.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP ++#define STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Guess whether we are building against on old Platform SDK. ++#if !defined(IN6ADDR_ANY_INIT) ++#define STDNET_HAS_OLD_WIN_SDK 1 ++#endif // !defined(IN6ADDR_ANY_INIT) ++ ++#if defined(STDNET_HAS_OLD_WIN_SDK) ++ ++// Emulation of types that are missing from old Platform SDKs. ++// ++// N.B. this emulation is also used if building for a Windows 2000 target with ++// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support ++// in that case. ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++enum ++{ ++ sockaddr_storage_maxsize = 128, // Maximum size. ++ sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment. ++ sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)), ++ sockaddr_storage_pad2size = (sockaddr_storage_maxsize - ++ (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize)) ++}; ++ ++struct sockaddr_storage_emulation ++{ ++ short ss_family; ++ char __ss_pad1[sockaddr_storage_pad1size]; ++ __int64 __ss_align; ++ char __ss_pad2[sockaddr_storage_pad2size]; ++}; ++ ++struct in6_addr_emulation ++{ ++ union ++ { ++ u_char Byte[16]; ++ u_short Word[8]; ++ } u; ++}; ++ ++#if !defined(s6_addr) ++# define _S6_un u ++# define _S6_u8 Byte ++# define s6_addr _S6_un._S6_u8 ++#endif // !defined(s6_addr) ++ ++struct sockaddr_in6_emulation ++{ ++ short sin6_family; ++ u_short sin6_port; ++ u_long sin6_flowinfo; ++ in6_addr_emulation sin6_addr; ++ u_long sin6_scope_id; ++}; ++ ++struct ipv6_mreq_emulation ++{ ++ in6_addr_emulation ipv6mr_multiaddr; ++ unsigned int ipv6mr_interface; ++}; ++ ++struct addrinfo_emulation ++{ ++ int ai_flags; ++ int ai_family; ++ int ai_socktype; ++ int ai_protocol; ++ size_t ai_addrlen; ++ char* ai_canonname; ++ sockaddr* ai_addr; ++ addrinfo_emulation* ai_next; ++}; ++ ++#if !defined(AI_PASSIVE) ++# define AI_PASSIVE 0x1 ++#endif ++ ++#if !defined(AI_CANONNAME) ++# define AI_CANONNAME 0x2 ++#endif ++ ++#if !defined(AI_NUMERICHOST) ++# define AI_NUMERICHOST 0x4 ++#endif ++ ++#if !defined(EAI_AGAIN) ++# define EAI_AGAIN WSATRY_AGAIN ++#endif ++ ++#if !defined(EAI_BADFLAGS) ++# define EAI_BADFLAGS WSAEINVAL ++#endif ++ ++#if !defined(EAI_FAIL) ++# define EAI_FAIL WSANO_RECOVERY ++#endif ++ ++#if !defined(EAI_FAMILY) ++# define EAI_FAMILY WSAEAFNOSUPPORT ++#endif ++ ++#if !defined(EAI_MEMORY) ++# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY ++#endif ++ ++#if !defined(EAI_NODATA) ++# define EAI_NODATA WSANO_DATA ++#endif ++ ++#if !defined(EAI_NONAME) ++# define EAI_NONAME WSAHOST_NOT_FOUND ++#endif ++ ++#if !defined(EAI_SERVICE) ++# define EAI_SERVICE WSATYPE_NOT_FOUND ++#endif ++ ++#if !defined(EAI_SOCKTYPE) ++# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT ++#endif ++ ++#if !defined(NI_NOFQDN) ++# define NI_NOFQDN 0x01 ++#endif ++ ++#if !defined(NI_NUMERICHOST) ++# define NI_NUMERICHOST 0x02 ++#endif ++ ++#if !defined(NI_NAMEREQD) ++# define NI_NAMEREQD 0x04 ++#endif ++ ++#if !defined(NI_NUMERICSERV) ++# define NI_NUMERICSERV 0x08 ++#endif ++ ++#if !defined(NI_DGRAM) ++# define NI_DGRAM 0x10 ++#endif ++ ++#if !defined(IPPROTO_IPV6) ++# define IPPROTO_IPV6 41 ++#endif ++ ++#if !defined(IPV6_UNICAST_HOPS) ++# define IPV6_UNICAST_HOPS 4 ++#endif ++ ++#if !defined(IPV6_MULTICAST_IF) ++# define IPV6_MULTICAST_IF 9 ++#endif ++ ++#if !defined(IPV6_MULTICAST_HOPS) ++# define IPV6_MULTICAST_HOPS 10 ++#endif ++ ++#if !defined(IPV6_MULTICAST_LOOP) ++# define IPV6_MULTICAST_LOOP 11 ++#endif ++ ++#if !defined(IPV6_JOIN_GROUP) ++# define IPV6_JOIN_GROUP 12 ++#endif ++ ++#if !defined(IPV6_LEAVE_GROUP) ++# define IPV6_LEAVE_GROUP 13 ++#endif ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_HAS_OLD_WIN_SDK) ++ ++// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. ++#if !defined(IPV6_V6ONLY) ++# define IPV6_V6ONLY 27 ++#endif ++ ++// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6. ++#if !defined(IPPROTO_ICMPV6) ++# define IPPROTO_ICMPV6 58 ++#endif ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP +diff --git a/ip-address/include/std/net/detail/pop_options.hpp b/ip-address/include/std/net/detail/pop_options.hpp +new file mode 100644 +index 0000000..8aa375e +--- /dev/null ++++ b/ip-address/include/std/net/detail/pop_options.hpp +@@ -0,0 +1,98 @@ ++// ++// detail/pop_options.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++// No header guard ++ ++#if defined(__COMO__) ++ ++// Comeau C++ ++ ++#elif defined(__DMC__) ++ ++// Digital Mars C++ ++ ++#elif defined(__INTEL_COMPILER) || defined(__ICL) \ ++ || defined(__ICC) || defined(__ECC) ++ ++// Intel C++ ++ ++#elif defined(__GNUC__) ++ ++// GNU C++ ++ ++# if defined(__MINGW32__) || defined(__CYGWIN__) ++# pragma pack (pop) ++# endif ++ ++# if defined(__OBJC__) ++# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) ++# if defined(STDNET_OBJC_WORKAROUND) ++# undef Protocol ++# undef id ++# undef STDNET_OBJC_WORKAROUND ++# endif ++# endif ++# endif ++ ++#elif defined(__KCC) ++ ++// Kai C++ ++ ++#elif defined(__sgi) ++ ++// SGI MIPSpro C++ ++ ++#elif defined(__DECCXX) ++ ++// Compaq Tru64 Unix cxx ++ ++#elif defined(__ghs) ++ ++// Greenhills C++ ++ ++#elif defined(__BORLANDC__) ++ ++// Borland C++ ++ ++# pragma option pop ++# pragma nopushoptwarn ++# pragma nopackwarning ++ ++#elif defined(__MWERKS__) ++ ++// Metrowerks CodeWarrior ++ ++#elif defined(__SUNPRO_CC) ++ ++// Sun Workshop Compiler C++ ++ ++#elif defined(__HP_aCC) ++ ++// HP aCC ++ ++#elif defined(__MRC__) || defined(__SC__) ++ ++// MPW MrCpp or SCpp ++ ++#elif defined(__IBMCPP__) ++ ++// IBM Visual Age ++ ++#elif defined(_MSC_VER) ++ ++// Microsoft Visual C++ ++// ++// Must remain the last #elif since some other vendors (Metrowerks, for example) ++// also #define _MSC_VER ++ ++# pragma warning (pop) ++# pragma pack (pop) ++ ++#endif +diff --git a/ip-address/include/std/net/detail/push_options.hpp b/ip-address/include/std/net/detail/push_options.hpp +new file mode 100644 +index 0000000..ec64373 +--- /dev/null ++++ b/ip-address/include/std/net/detail/push_options.hpp +@@ -0,0 +1,127 @@ ++// ++// detail/push_options.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++// No header guard ++ ++#if defined(__COMO__) ++ ++// Comeau C++ ++ ++#elif defined(__DMC__) ++ ++// Digital Mars C++ ++ ++#elif defined(__INTEL_COMPILER) || defined(__ICL) \ ++ || defined(__ICC) || defined(__ECC) ++ ++// Intel C++ ++ ++#elif defined(__GNUC__) ++ ++// GNU C++ ++ ++# if defined(__MINGW32__) || defined(__CYGWIN__) ++# pragma pack (push, 8) ++# endif ++ ++# if defined(__OBJC__) ++# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) ++# if !defined(STDNET_DISABLE_OBJC_WORKAROUND) ++# if !defined(Protocol) && !defined(id) ++# define Protocol cpp_Protocol ++# define id cpp_id ++# define STDNET_OBJC_WORKAROUND ++# endif ++# endif ++# endif ++# endif ++ ++#elif defined(__KCC) ++ ++// Kai C++ ++ ++#elif defined(__sgi) ++ ++// SGI MIPSpro C++ ++ ++#elif defined(__DECCXX) ++ ++// Compaq Tru64 Unix cxx ++ ++#elif defined(__ghs) ++ ++// Greenhills C++ ++ ++#elif defined(__BORLANDC__) ++ ++// Borland C++ ++ ++# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi- ++# pragma nopushoptwarn ++# pragma nopackwarning ++# if !defined(__MT__) ++# error Multithreaded RTL must be selected. ++# endif // !defined(__MT__) ++ ++#elif defined(__MWERKS__) ++ ++// Metrowerks CodeWarrior ++ ++#elif defined(__SUNPRO_CC) ++ ++// Sun Workshop Compiler C++ ++ ++#elif defined(__HP_aCC) ++ ++// HP aCC ++ ++#elif defined(__MRC__) || defined(__SC__) ++ ++// MPW MrCpp or SCpp ++ ++#elif defined(__IBMCPP__) ++ ++// IBM Visual Age ++ ++#elif defined(_MSC_VER) ++ ++// Microsoft Visual C++ ++// ++// Must remain the last #elif since some other vendors (Metrowerks, for example) ++// also #define _MSC_VER ++ ++# pragma warning (disable:4103) ++# pragma warning (push) ++# pragma warning (disable:4127) ++# pragma warning (disable:4180) ++# pragma warning (disable:4244) ++# pragma warning (disable:4355) ++# pragma warning (disable:4512) ++# pragma warning (disable:4675) ++# if defined(_M_IX86) && defined(_Wp64) ++// The /Wp64 option is broken. If you want to check 64 bit portability, use a ++// 64 bit compiler! ++# pragma warning (disable:4311) ++# pragma warning (disable:4312) ++# endif // defined(_M_IX86) && defined(_Wp64) ++# pragma pack (push, 8) ++// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler ++// has a tendency to incorrectly optimise away some calls to member template ++// functions, even though those functions contain code that should not be ++// optimised away! Therefore we will always disable this optimisation option ++// for the MSVC6 compiler. ++# if (_MSC_VER < 1300) ++# pragma optimize ("g", off) ++# endif ++# if !defined(_MT) ++# error Multithreaded RTL must be selected. ++# endif // !defined(_MT) ++ ++#endif +diff --git a/ip-address/include/std/net/detail/socket_ops.hpp b/ip-address/include/std/net/detail/socket_ops.hpp +new file mode 100644 +index 0000000..02cb8a4 +--- /dev/null ++++ b/ip-address/include/std/net/detail/socket_ops.hpp +@@ -0,0 +1,57 @@ ++// ++// detail/socket_ops.hpp ++// ~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_OPS_HPP ++#define STDNET_DETAIL_SOCKET_OPS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#include ++#include "std/net/detail/socket_types.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace socket_ops { ++ ++STDNET_DECL const char* inet_ntop(int af, const void* src, char* dest, ++ size_t length, unsigned long scope_id, std::error_code& ec); ++ ++STDNET_DECL int inet_pton(int af, const char* src, void* dest, ++ unsigned long* scope_id, std::error_code& ec); ++ ++STDNET_DECL u_long_type network_to_host_long(u_long_type value); ++ ++STDNET_DECL u_long_type host_to_network_long(u_long_type value); ++ ++STDNET_DECL u_short_type network_to_host_short(u_short_type value); ++ ++STDNET_DECL u_short_type host_to_network_short(u_short_type value); ++ ++} // namespace socket_ops ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/socket_ops.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_SOCKET_OPS_HPP +diff --git a/ip-address/include/std/net/detail/socket_types.hpp b/ip-address/include/std/net/detail/socket_types.hpp +new file mode 100644 +index 0000000..ee35521 +--- /dev/null ++++ b/ip-address/include/std/net/detail/socket_types.hpp +@@ -0,0 +1,186 @@ ++// ++// detail/socket_types.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_TYPES_HPP ++#define STDNET_DETAIL_SOCKET_TYPES_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) ++# error WinSock.h has already been included ++# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) ++# if defined(__BORLANDC__) ++# include // Needed for __errno ++# if !defined(_WSPIAPI_H_) ++# define _WSPIAPI_H_ ++# define STDNET_WSPIAPI_H_DEFINED ++# endif // !defined(_WSPIAPI_H_) ++# endif // defined(__BORLANDC__) ++# include ++# include ++# include ++# if defined(STDNET_WSPIAPI_H_DEFINED) ++# undef _WSPIAPI_H_ ++# undef STDNET_WSPIAPI_H_DEFINED ++# endif // defined(STDNET_WSPIAPI_H_DEFINED) ++# if !defined(STDNET_NO_DEFAULT_LINKED_LIBS) ++# if defined(UNDER_CE) ++# pragma comment(lib, "ws2.lib") ++# elif defined(_MSC_VER) || defined(__BORLANDC__) ++# pragma comment(lib, "ws2_32.lib") ++# pragma comment(lib, "mswsock.lib") ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) ++# endif // !defined(STDNET_NO_DEFAULT_LINKED_LIBS) ++# include "std/net/detail/old_win_sdk_compat.hpp" ++#else ++# include ++# if !defined(__SYMBIAN32__) ++# include ++# endif ++# include ++# include ++# include ++# if defined(__hpux) ++# include ++# endif ++# if !defined(__hpux) || defined(__SELECT) ++# include ++# endif ++# include ++# include ++# include ++# include ++# if !defined(__SYMBIAN32__) ++# include ++# endif ++# include ++# include ++# include ++# include ++# if defined(__sun) ++# include ++# include ++# endif ++#endif ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++typedef SOCKET socket_type; ++const SOCKET invalid_socket = INVALID_SOCKET; ++const int socket_error_retval = SOCKET_ERROR; ++const int max_addr_v4_str_len = 256; ++const int max_addr_v6_str_len = 256; ++typedef sockaddr socket_addr_type; ++typedef in_addr in4_addr_type; ++typedef ip_mreq in4_mreq_type; ++typedef sockaddr_in sockaddr_in4_type; ++# if defined(STDNET_HAS_OLD_WIN_SDK) ++typedef in6_addr_emulation in6_addr_type; ++typedef ipv6_mreq_emulation in6_mreq_type; ++typedef sockaddr_in6_emulation sockaddr_in6_type; ++typedef sockaddr_storage_emulation sockaddr_storage_type; ++typedef addrinfo_emulation addrinfo_type; ++# else ++typedef in6_addr in6_addr_type; ++typedef ipv6_mreq in6_mreq_type; ++typedef sockaddr_in6 sockaddr_in6_type; ++typedef sockaddr_storage sockaddr_storage_type; ++typedef addrinfo addrinfo_type; ++# endif ++typedef unsigned long ioctl_arg_type; ++typedef u_long u_long_type; ++typedef u_short u_short_type; ++typedef int signed_size_type; ++const int shutdown_receive = SD_RECEIVE; ++const int shutdown_send = SD_SEND; ++const int shutdown_both = SD_BOTH; ++const int message_peek = MSG_PEEK; ++const int message_out_of_band = MSG_OOB; ++const int message_do_not_route = MSG_DONTROUTE; ++const int message_end_of_record = 0; // Not supported on Windows. ++# if defined (_WIN32_WINNT) ++const int max_iov_len = 64; ++# else ++const int max_iov_len = 16; ++# endif ++#else ++typedef int socket_type; ++const int invalid_socket = -1; ++const int socket_error_retval = -1; ++const int max_addr_v4_str_len = INET_ADDRSTRLEN; ++#if defined(INET6_ADDRSTRLEN) ++const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; ++#else // defined(INET6_ADDRSTRLEN) ++const int max_addr_v6_str_len = 256; ++#endif // defined(INET6_ADDRSTRLEN) ++typedef sockaddr socket_addr_type; ++typedef in_addr in4_addr_type; ++# if defined(__hpux) ++// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined. ++struct in4_mreq_type ++{ ++ struct in_addr imr_multiaddr; ++ struct in_addr imr_interface; ++}; ++# else ++typedef ip_mreq in4_mreq_type; ++# endif ++typedef sockaddr_in sockaddr_in4_type; ++typedef in6_addr in6_addr_type; ++typedef ipv6_mreq in6_mreq_type; ++typedef sockaddr_in6 sockaddr_in6_type; ++typedef sockaddr_storage sockaddr_storage_type; ++typedef sockaddr_un sockaddr_un_type; ++typedef addrinfo addrinfo_type; ++typedef int ioctl_arg_type; ++typedef uint32_t u_long_type; ++typedef uint16_t u_short_type; ++#if defined(STDNET_HAS_SSIZE_T) ++typedef ssize_t signed_size_type; ++#else // defined(STDNET_HAS_SSIZE_T) ++typedef int signed_size_type; ++#endif // defined(STDNET_HAS_SSIZE_T) ++const int shutdown_receive = SHUT_RD; ++const int shutdown_send = SHUT_WR; ++const int shutdown_both = SHUT_RDWR; ++const int message_peek = MSG_PEEK; ++const int message_out_of_band = MSG_OOB; ++const int message_do_not_route = MSG_DONTROUTE; ++const int message_end_of_record = MSG_EOR; ++# if defined(IOV_MAX) ++const int max_iov_len = IOV_MAX; ++# else ++// POSIX platforms are not required to define IOV_MAX. ++const int max_iov_len = 16; ++# endif ++#endif ++const int custom_socket_option_level = 0xA5100000; ++const int enable_connection_aborted_option = 1; ++const int always_fail_option = 2; ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_SOCKET_TYPES_HPP +diff --git a/ip-address/include/std/net/detail/system_errors.hpp b/ip-address/include/std/net/detail/system_errors.hpp +new file mode 100644 +index 0000000..4aa5c44 +--- /dev/null ++++ b/ip-address/include/std/net/detail/system_errors.hpp +@@ -0,0 +1,221 @@ ++// ++// system_errors.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SYSTEM_ERRORS_HPP ++#define STDNET_DETAIL_SYSTEM_ERRORS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# include ++#else ++# include ++#endif ++ ++#if defined(GENERATING_DOCUMENTATION) ++/// INTERNAL ONLY. ++# define STDNET_NATIVE_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_SOCKET_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_NETDB_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_GETADDRINFO_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) implementation_defined ++#elif defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# define STDNET_NATIVE_ERROR(e) e ++# define STDNET_SOCKET_ERROR(e) WSA ## e ++# define STDNET_NETDB_ERROR(e) WSA ## e ++# define STDNET_GETADDRINFO_ERROR(e) WSA ## e ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) e_win ++#else ++# define STDNET_NATIVE_ERROR(e) e ++# define STDNET_SOCKET_ERROR(e) e ++# define STDNET_NETDB_ERROR(e) e ++# define STDNET_GETADDRINFO_ERROR(e) e ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) e_posix ++#endif ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++enum system_errors ++{ ++ /// Permission denied. ++ access_denied = STDNET_SOCKET_ERROR(EACCES), ++ ++ /// Address family not supported by protocol. ++ address_family_not_supported = STDNET_SOCKET_ERROR(EAFNOSUPPORT), ++ ++ /// Address already in use. ++ address_in_use = STDNET_SOCKET_ERROR(EADDRINUSE), ++ ++ /// Transport endpoint is already connected. ++ already_connected = STDNET_SOCKET_ERROR(EISCONN), ++ ++ /// Operation already in progress. ++ already_started = STDNET_SOCKET_ERROR(EALREADY), ++ ++ /// Broken pipe. ++ broken_pipe = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_BROKEN_PIPE), ++ STDNET_NATIVE_ERROR(EPIPE)), ++ ++ /// A connection has been aborted. ++ connection_aborted = STDNET_SOCKET_ERROR(ECONNABORTED), ++ ++ /// Connection refused. ++ connection_refused = STDNET_SOCKET_ERROR(ECONNREFUSED), ++ ++ /// Connection reset by peer. ++ connection_reset = STDNET_SOCKET_ERROR(ECONNRESET), ++ ++ /// Bad file descriptor. ++ bad_descriptor = STDNET_SOCKET_ERROR(EBADF), ++ ++ /// Bad address. ++ fault = STDNET_SOCKET_ERROR(EFAULT), ++ ++ /// No route to host. ++ host_unreachable = STDNET_SOCKET_ERROR(EHOSTUNREACH), ++ ++ /// Operation now in progress. ++ in_progress = STDNET_SOCKET_ERROR(EINPROGRESS), ++ ++ /// Interrupted system call. ++ interrupted = STDNET_SOCKET_ERROR(EINTR), ++ ++ /// Invalid argument. ++ invalid_argument = STDNET_SOCKET_ERROR(EINVAL), ++ ++ /// Message too long. ++ message_size = STDNET_SOCKET_ERROR(EMSGSIZE), ++ ++ /// The name was too long. ++ name_too_long = STDNET_SOCKET_ERROR(ENAMETOOLONG), ++ ++ /// Network is down. ++ network_down = STDNET_SOCKET_ERROR(ENETDOWN), ++ ++ /// Network dropped connection on reset. ++ network_reset = STDNET_SOCKET_ERROR(ENETRESET), ++ ++ /// Network is unreachable. ++ network_unreachable = STDNET_SOCKET_ERROR(ENETUNREACH), ++ ++ /// Too many open files. ++ no_descriptors = STDNET_SOCKET_ERROR(EMFILE), ++ ++ /// No buffer space available. ++ no_buffer_space = STDNET_SOCKET_ERROR(ENOBUFS), ++ ++ /// Cannot allocate memory. ++ no_memory = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_OUTOFMEMORY), ++ STDNET_NATIVE_ERROR(ENOMEM)), ++ ++ /// Operation not permitted. ++ no_permission = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_ACCESS_DENIED), ++ STDNET_NATIVE_ERROR(EPERM)), ++ ++ /// Protocol not available. ++ no_protocol_option = STDNET_SOCKET_ERROR(ENOPROTOOPT), ++ ++ /// Transport endpoint is not connected. ++ not_connected = STDNET_SOCKET_ERROR(ENOTCONN), ++ ++ /// Socket operation on non-socket. ++ not_socket = STDNET_SOCKET_ERROR(ENOTSOCK), ++ ++ /// Operation cancelled. ++ operation_aborted = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_OPERATION_ABORTED), ++ STDNET_NATIVE_ERROR(ECANCELED)), ++ ++ /// Operation not supported. ++ operation_not_supported = STDNET_SOCKET_ERROR(EOPNOTSUPP), ++ ++ /// Cannot send after transport endpoint shutdown. ++ shut_down = STDNET_SOCKET_ERROR(ESHUTDOWN), ++ ++ /// Connection timed out. ++ timed_out = STDNET_SOCKET_ERROR(ETIMEDOUT), ++ ++ /// Resource temporarily unavailable. ++ try_again = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_RETRY), ++ STDNET_NATIVE_ERROR(EAGAIN)), ++ ++ /// The socket is marked non-blocking and the requested operation would block. ++ would_block = STDNET_SOCKET_ERROR(EWOULDBLOCK) ++}; ++ ++} // namespace syserrc ++ ++/// Returns the error category used for the system errors. ++extern STDNET_DECL const std::error_category& system_category(); ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++namespace std { ++ ++template<> struct is_error_code_enum< ++ std::experimental::net::detail::syserrc::system_errors> ++{ ++ static const bool value = true; ++}; ++ ++} // namespace std ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++inline std::error_code make_error_code(system_errors e) ++{ ++ return std::error_code(static_cast(e), ++ std::experimental::net::detail::system_category()); ++} ++ ++} // namespace syserrc ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#undef STDNET_NATIVE_ERROR ++#undef STDNET_SOCKET_ERROR ++#undef STDNET_NETDB_ERROR ++#undef STDNET_GETADDRINFO_ERROR ++#undef STDNET_WIN_OR_POSIX ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/system_errors.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_SYSTEM_ERRORS_HPP +diff --git a/ip-address/include/std/net/detail/throw_error.hpp b/ip-address/include/std/net/detail/throw_error.hpp +new file mode 100644 +index 0000000..4067cb7 +--- /dev/null ++++ b/ip-address/include/std/net/detail/throw_error.hpp +@@ -0,0 +1,57 @@ ++// ++// detail/throw_error.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_THROW_ERROR_HPP ++#define STDNET_DETAIL_THROW_ERROR_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++STDNET_DECL void do_throw_error(const std::error_code& err); ++ ++STDNET_DECL void do_throw_error(const std::error_code& err, ++ const char* location); ++ ++inline void throw_error(const std::error_code& err) ++{ ++ if (err) ++ do_throw_error(err); ++} ++ ++inline void throw_error(const std::error_code& err, ++ const char* location) ++{ ++ if (err) ++ do_throw_error(err, location); ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/throw_error.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_THROW_ERROR_HPP +diff --git a/ip-address/include/std/net/detail/throw_exception.hpp b/ip-address/include/std/net/detail/throw_exception.hpp +new file mode 100644 +index 0000000..0903df1 +--- /dev/null ++++ b/ip-address/include/std/net/detail/throw_exception.hpp +@@ -0,0 +1,45 @@ ++// ++// detail/throw_exception.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_THROW_EXCEPTION_HPP ++#define STDNET_DETAIL_THROW_EXCEPTION_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++// Declare the throw_exception function for all targets. ++template ++void throw_exception(const Exception& e); ++ ++// Only define the throw_exception function when exceptions are enabled. ++// Otherwise, it is up to the application to provide a definition of this ++// function. ++# if !defined(STDNET_NO_EXCEPTIONS) ++template ++void throw_exception(const Exception& e) ++{ ++ throw e; ++} ++# endif // !defined(STDNET_NO_EXCEPTIONS) ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#endif // STDNET_DETAIL_THROW_EXCEPTION_HPP +diff --git a/ip-address/include/std/net/detail/winsock_init.hpp b/ip-address/include/std/net/detail/winsock_init.hpp +new file mode 100644 +index 0000000..fc008de +--- /dev/null ++++ b/ip-address/include/std/net/detail/winsock_init.hpp +@@ -0,0 +1,94 @@ ++// ++// detail/winsock_init.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_WINSOCK_INIT_HPP ++#define STDNET_DETAIL_WINSOCK_INIT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++class winsock_init_base ++{ ++protected: ++ // Structure to track result of initialisation and number of uses. POD is used ++ // to ensure that the values are zero-initialised prior to any code being run. ++ struct data ++ { ++ long init_count_; ++ long result_; ++ }; ++ ++ STDNET_DECL static void startup(data& d, ++ unsigned char major, unsigned char minor); ++ ++ STDNET_DECL static void cleanup(data& d); ++ ++ STDNET_DECL static void throw_on_error(data& d); ++}; ++ ++template ++class winsock_init : private winsock_init_base ++{ ++public: ++ winsock_init(bool allow_throw = true) ++ { ++ startup(data_, Major, Minor); ++ if (allow_throw) ++ throw_on_error(data_); ++ } ++ ++ winsock_init(const winsock_init&) ++ { ++ startup(data_, Major, Minor); ++ throw_on_error(data_); ++ } ++ ++ ~winsock_init() ++ { ++ cleanup(data_); ++ } ++ ++private: ++ static data data_; ++}; ++ ++template ++winsock_init_base::data winsock_init::data_; ++ ++// Static variable to ensure that winsock is initialised before main, and ++// therefore before any other threads can get started. ++static const winsock_init<>& winsock_init_instance = winsock_init<>(false); ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/winsock_init.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_WINSOCK_INIT_HPP +diff --git a/ip-address/include/std/net/ip/address.hpp b/ip-address/include/std/net/ip/address.hpp +new file mode 100644 +index 0000000..8a5e75a +--- /dev/null ++++ b/ip-address/include/std/net/ip/address.hpp +@@ -0,0 +1,328 @@ ++// ++// ip/address.hpp ++// ~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_HPP ++#define STDNET_IP_ADDRESS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++namespace detail { ++ ++template ++struct is_convertible_to_address_1 : false_type {}; ++ ++template ++struct is_convertible_to_address_1(declval()))>::value>::type> : true_type {}; ++ ++template ++struct is_convertible_to_address : is_convertible_to_address_1 {}; ++ ++template <> ++struct is_convertible_to_address
: false_type {}; ++ ++} // namespace detail ++ ++//template <> struct is_convertible_to_address
: false_type {}; ++ ++/// Implements version-independent IP addresses. ++/** ++ * The ip::address class provides the ability to use either IP version 4 or ++ * version 6 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address ++{ ++public: ++ /// Default constructor. ++ STDNET_CONSTEXPR address() STDNET_NOEXCEPT ++ : type_(invalid), ++ ipv4_address_(), ++ ipv6_address_() ++ { ++ } ++ ++ /// Construct from another address type. ++ template ::value>::type> ++ STDNET_CONSTEXPR address(const T& t) STDNET_NOEXCEPT; ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address(T&&... t); ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit address(T1& t1, typename enable_if()))>::value>::type* = 0) ++ { *this = make_address(t1); } ++ template ++ explicit address(const T1& t1, typename enable_if()))>::value>::type* = 0) ++ { *this = make_address(t1); } ++ template ++ address(T1& t1, T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(T1& t1, const T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(const T1& t1, T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(const T1& t1, const T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address(const address& other) STDNET_NOEXCEPT ++ : type_(other.type_), ++ ipv4_address_(other.ipv4_address_), ++ ipv6_address_(other.ipv6_address_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address(address&& other) STDNET_NOEXCEPT ++ : type_(other.type_), ++ ipv4_address_(other.ipv4_address_), ++ ipv6_address_(other.ipv6_address_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address& operator=(const address& other) STDNET_NOEXCEPT ++ { ++ type_ = other.type_; ++ ipv4_address_ = other.ipv4_address_; ++ ipv6_address_ = other.ipv6_address_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address& operator=(address&& other) STDNET_NOEXCEPT ++ { ++ type_ = other.type_; ++ ipv4_address_ = other.ipv4_address_; ++ ipv6_address_ = other.ipv6_address_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Get whether the address is an IP version 4 address. ++ STDNET_CONSTEXPR bool is_v4() const STDNET_NOEXCEPT ++ { ++ return type_ == ipv4; ++ } ++ ++ /// Get whether the address is an IP version 6 address. ++ STDNET_CONSTEXPR bool is_v6() const STDNET_NOEXCEPT ++ { ++ return type_ == ipv6; ++ } ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_loopback() : ++ (type_ == ipv6) ? ipv6_address_.is_loopback() : false; ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_unspecified() : ++ (type_ == ipv6) ? ipv6_address_.is_unspecified() : false; ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_multicast() : ++ (type_ == ipv6) ? ipv6_address_.is_multicast() : false; ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address& a1, ++ const address& a2) STDNET_NOEXCEPT ++ { ++ if (a1.type_ != a2.type_) ++ return false; ++ if (a1.type_ == address::ipv4) ++ return a1.ipv4_address_ == a2.ipv4_address_; ++ if (a1.type_ == address::ipv6) ++ return a1.ipv4_address_ == a2.ipv4_address_; ++ return true; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 == a2); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address& a1, ++ const address& a2) STDNET_NOEXCEPT ++ { ++ if (a1.type_ < a2.type_) ++ return true; ++ if (a1.type_ > a2.type_) ++ return false; ++ if (a1.type_ == address::ipv4) ++ return a1.ipv4_address_ < a2.ipv4_address_; ++ if (a1.type_ == address::ipv6) ++ return a1.ipv6_address_ < a2.ipv6_address_; ++ return false; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return a2 < a1; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a2 < a1); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 < a2); ++ } ++ ++private: ++ friend class address_v4; ++ friend class address_v6; ++ ++ // The type of the address. ++ enum address_type { invalid, ipv4, ipv6 } type_; ++ ++ // The underlying IPv4 address. ++ address_v4 ipv4_address_; ++ ++ // The underlying IPv6 address. ++ address_v6 ipv6_address_; ++ ++ // Helper constructor for address_cast. ++ STDNET_CONSTEXPR address(address_type type, ++ const address_v4& v4, const address_v6& v6) ++ : type_(type), ++ ipv4_address_(v4), ++ ipv6_address_(v6) ++ { ++ } ++ ++ template friend STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type*); ++ template friend STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type*); ++ template friend STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT; ++ template friend STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT; ++}; ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const char* str); ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const std::string& str); ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#include "std/net/ip/address_cast.hpp" ++ ++#endif // STDNET_IP_ADDRESS_HPP +diff --git a/ip-address/include/std/net/ip/address_cast.hpp b/ip-address/include/std/net/ip/address_cast.hpp +new file mode 100644 +index 0000000..dae3d02 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_cast.hpp +@@ -0,0 +1,106 @@ ++// ++// ip/address_cast.hpp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_CAST_HPP ++#define STDNET_IP_ADDRESS_CAST_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++#include "std/net/ip/bad_address_cast.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++/// Cast a version-independent address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++/// Cast a version-independent address to an IPv4 address. ++/** ++ * @throws bad_address_cast if @c a does not represent an IPv4 address. ++ */ ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) ++{ ++ return (addr.type_ != address::ipv4) ++ ? throw bad_address_cast() ++ : addr.ipv4_address_; ++} ++ ++/// Cast a version-independent address to an IPv6 address. ++/** ++ * @throws bad_address_cast if @c a does not represent an IPv6 address. ++ */ ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) ++{ ++ return (addr.type_ != address::ipv6) ++ ? throw bad_address_cast() ++ : addr.ipv6_address_; ++} ++ ++/// Cast an IPv4 address to a version-independent address. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v4& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return address(address::ipv4, addr, address_v6()); ++} ++ ++/// Cast an IPv4 address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v4& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++/// Cast an IPv6 address to a version-independent address. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v6& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return address(address::ipv6, address_v4(), addr); ++} ++ ++/// Cast an IPv6 address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v6& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_ADDRESS_CAST_HPP +diff --git a/ip-address/include/std/net/ip/address_v4.hpp b/ip-address/include/std/net/ip/address_v4.hpp +new file mode 100644 +index 0000000..a7b9234 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_v4.hpp +@@ -0,0 +1,376 @@ ++// ++// ip/address_v4.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_V4_HPP ++#define STDNET_IP_ADDRESS_V4_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/detail/winsock_init.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++class address; ++ ++/// Implements IP version 4 style addresses. ++/** ++ * The ip::address_v4 class provides the ability to use and manipulate IP ++ * version 4 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address_v4 ++{ ++public: ++ /// A standard-layout type used to represent an address as an array of bytes. ++ struct bytes_type : std::array ++ { ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR bytes_type(T... t) ++ : std::array{{static_cast(t)...}} ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ explicit STDNET_CONSTEXPR bytes_type(unsigned char a = 0, ++ unsigned char b = 0, unsigned char c = 0, unsigned char d = 0) ++# if defined(STDNET_HAS_CONSTEXPR) ++ : std::array{{a, b, c, d}} ++ { ++ } ++# else // defined(STDNET_HAS_CONSTEXPR) ++ { ++ (*this)[0] = a, (*this)[1] = b, (*this)[2] = c, (*this)[3] = d; ++ } ++# endif // defined(STDNET_HAS_CONSTEXPR) ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ }; ++ ++ /// Default constructor. ++ STDNET_CONSTEXPR address_v4() STDNET_NOEXCEPT ++ : bytes_(0, 0, 0, 0) ++ { ++ } ++ ++ /// Implicit construction from bytes, in network byte order. ++ STDNET_CONSTEXPR address_v4(const bytes_type& bytes) ++ : bytes_( ++#if UCHAR_MAX > 0xFF ++ (bytes[0] > 0xFF || bytes[1] > 0xFF || bytes[2] > 0xFF || bytes[3] > 0xFF) ++ ? throw std::out_of_range("address_v4 from bytes_type") : ++#endif // UCHAR_MAX > 0xFF ++ bytes) ++ { ++ } ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address_v4(T&&... t) ++ : address_v4(make_address_v4(static_cast(t)...)) ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR address_v4(T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1).to_bytes()) {} ++ template ++ explicit STDNET_CONSTEXPR address_v4(const T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(const T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(const T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address_v4(const address_v4& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address_v4(address_v4&& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address_v4& operator=(const address_v4& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address_v4& operator=(address_v4&& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Get the address in bytes, in network byte order. ++ STDNET_CONSTEXPR bytes_type to_bytes() const STDNET_NOEXCEPT ++ { ++ return bytes_; ++ } ++ ++ /// Get the address as an unsigned long in host byte order ++ STDNET_CONSTEXPR unsigned long to_ulong() const STDNET_NOEXCEPT ++ { ++ return (static_cast(bytes_[0]) << 24) ++ | (static_cast(bytes_[1]) << 16) ++ | (static_cast(bytes_[2]) << 8) ++ | static_cast(bytes_[3]); ++ } ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xFF000000) == 0x7F000000; ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return to_ulong() == 0; ++ } ++ ++ /// Determine whether the address is a class A address. ++ STDNET_CONSTEXPR bool is_class_a() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0x80000000) == 0; ++ } ++ ++ /// Determine whether the address is a class B address. ++ STDNET_CONSTEXPR bool is_class_b() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xC0000000) == 0x80000000; ++ } ++ ++ /// Determine whether the address is a class C address. ++ STDNET_CONSTEXPR bool is_class_c() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xE0000000) == 0xC0000000; ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xF0000000) == 0xE0000000; ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() < a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() > a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() <= a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() >= a2.to_ulong(); ++ } ++ ++ /// Obtain an address object that represents any address. ++ static STDNET_CONSTEXPR address_v4 any() STDNET_NOEXCEPT ++ { ++ return address_v4(); ++ } ++ ++ /// Obtain an address object that represents the loopback address. ++ static STDNET_CONSTEXPR address_v4 loopback() STDNET_NOEXCEPT ++ { ++ return address_v4(0x7F000001); ++ } ++ ++ /// Obtain an address object that represents the broadcast address. ++ static STDNET_CONSTEXPR address_v4 broadcast() STDNET_NOEXCEPT ++ { ++ return address_v4(0xFFFFFFFF); ++ } ++ ++ /// Obtain an address object that represents the broadcast address that ++ /// corresponds to the specified address and netmask. ++ static STDNET_CONSTEXPR address_v4 broadcast(const address_v4& addr, ++ const address_v4& mask) STDNET_NOEXCEPT ++ { ++ return address_v4(addr.to_ulong() | (mask.to_ulong() ^ 0xFFFFFFFF)); ++ } ++ ++private: ++ // The underlying IPv4 address. ++ bytes_type bytes_; ++}; ++ ++/// Construct an address_v4 from raw bytes. ++inline STDNET_CONSTEXPR address_v4 make_address_v4(const address_v4::bytes_type& bytes) ++{ ++ return bytes; ++} ++ ++/// Construct an address_v4 from a unsigned long in host byte order. ++inline STDNET_CONSTEXPR address_v4 make_address_v4(unsigned long addr) ++{ ++ return ++#if ULONG_MAX > 0xFFFFFFFF ++ (addr > 0xFFFFFFFF) ++ ? throw std::out_of_range("address_v4 from unsigned long") : ++#endif // ULONG_MAX > 0xFFFFFFFF ++ address_v4::bytes_type((addr >> 24) & 0xFF, ++ (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF); ++} ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const char* str); ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const std::string& str); ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++#if defined(STDNET_HAS_CONSTEXPR) ++ ++/// The IPv4 unspecified address. ++STDNET_CONSTEXPR address_v4 any_v4(0); ++ ++/// The IPv4 loopback address. ++STDNET_CONSTEXPR address_v4 loopback_v4(0x7F000001); ++ ++/// The IPv4 broadcast address. ++STDNET_CONSTEXPR address_v4 broadcast_v4(0xFFFFFFFF); ++ ++#else // defined(STDNET_HAS_CONSTEXPR) ++ ++static const address_v4 any_v4(0); ++static const address_v4 loopback_v4(0x7F000001); ++static const address_v4 broadcast_v4(0xFFFFFFFF); ++ ++#endif // defined(STDNET_HAS_CONSTEXPR) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address_v4 ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v4& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address_v4.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address_v4.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_IP_ADDRESS_V4_HPP +diff --git a/ip-address/include/std/net/ip/address_v6.hpp b/ip-address/include/std/net/ip/address_v6.hpp +new file mode 100644 +index 0000000..3c4f440 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_v6.hpp +@@ -0,0 +1,440 @@ ++// ++// ip/address_v6.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_V6_HPP ++#define STDNET_IP_ADDRESS_V6_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/bad_address_cast.hpp" ++#include "std/net/detail/winsock_init.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++class address; ++class address_v4; ++ ++/// Implements IP version 6 style addresses. ++/** ++ * The ip::address_v6 class provides the ability to use and manipulate IP ++ * version 6 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address_v6 ++{ ++public: ++ /// A standard-layout type used to represent an address as an array of bytes. ++ struct bytes_type : std::array ++ { ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR bytes_type(T... t) ++ : std::array{{static_cast(t)...}} ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ explicit STDNET_CONSTEXPR bytes_type( ++ unsigned char a = 0, unsigned char b = 0, ++ unsigned char c = 0, unsigned char d = 0, ++ unsigned char e = 0, unsigned char f = 0, ++ unsigned char g = 0, unsigned char h = 0, ++ unsigned char i = 0, unsigned char j = 0, ++ unsigned char k = 0, unsigned char l = 0, ++ unsigned char m = 0, unsigned char n = 0, ++ unsigned char o = 0, unsigned char p = 0) ++# if defined(STDNET_HAS_CONSTEXPR) ++ : std::array{{a, b, c, d, e, f, g, h, i, h, k, l, m, n, o, p}} ++ { ++ } ++# else // defined(STDNET_HAS_CONSTEXPR) ++ { ++ (*this)[0] = a, (*this)[1] = b, (*this)[2] = c, (*this)[3] = d; ++ (*this)[4] = e, (*this)[5] = f, (*this)[6] = g, (*this)[7] = h; ++ (*this)[8] = i, (*this)[9] = j, (*this)[10] = k, (*this)[11] = l; ++ (*this)[12] = m, (*this)[13] = n, (*this)[14] = o, (*this)[15] = p; ++ } ++# endif // defined(STDNET_HAS_CONSTEXPR) ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ }; ++ ++ /// Default constructor. ++ STDNET_CONSTEXPR address_v6() STDNET_NOEXCEPT ++ : bytes_(0), ++ scope_id_(0) ++ { ++ } ++ ++ /// Implicit construction from bytes, in network byte order. ++ STDNET_CONSTEXPR address_v6(const bytes_type& bytes, unsigned long scope = 0) ++ : bytes_( ++#if UCHAR_MAX > 0xFF ++ (bytes[0] > 0xFF || bytes[1] > 0xFF || bytes[2] > 0xFF || bytes[3] > 0xFF ++ || bytes[4] > 0xFF || bytes[5] > 0xFF || bytes[6] > 0xFF || bytes[7] > 0xFF ++ || bytes[8] > 0xFF || bytes[9] > 0xFF || bytes[10] > 0xFF || bytes[11] > 0xFF ++ || bytes[12] > 0xFF || bytes[13] > 0xFF || bytes[14] > 0xFF || bytes[15] > 0xFF) ++ ? throw std::out_of_range("address_v6 from bytes_type") : ++#endif // UCHAR_MAX > 0xFF ++ bytes), ++ scope_id_(scope) ++ { ++ } ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address_v6(T&&... t) ++ : address_v6(make_address_v6(static_cast(t)...)) ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR address_v6(T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1).to_bytes()) {} ++ template ++ explicit STDNET_CONSTEXPR address_v6(const T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(const T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(const T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address_v6(const address_v6& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_), scope_id_(other.scope_id_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address_v6(address_v6&& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_), scope_id_(other.scope_id_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address_v6& operator=(const address_v6& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ scope_id_ = other.scope_id_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address_v6& operator=(address_v6&& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ scope_id_ = other.scope_id_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// The scope ID of the address. ++ /** ++ * Returns the scope ID associated with the IPv6 address. ++ */ ++ STDNET_CONSTEXPR unsigned long scope_id() const STDNET_NOEXCEPT ++ { ++ return scope_id_; ++ } ++ ++ /// The scope ID of the address. ++ /** ++ * Modifies the scope ID associated with the IPv6 address. ++ */ ++ void scope_id(unsigned long id) STDNET_NOEXCEPT ++ { ++ scope_id_ = id; ++ } ++ ++ /// Get the address in bytes, in network byte order. ++ STDNET_CONSTEXPR bytes_type to_bytes() const STDNET_NOEXCEPT ++ { ++ return bytes_; ++ } ++ ++ /// Get the address as a string. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0) && (bytes_[11] == 0) ++ && (bytes_[12] == 0) && (bytes_[13] == 0) ++ && (bytes_[14] == 0) && (bytes_[15] == 1)); ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0) && (bytes_[11] == 0) ++ && (bytes_[12] == 0) && (bytes_[13] == 0) ++ && (bytes_[14] == 0) && (bytes_[15] == 0)); ++ } ++ ++ /// Determine whether the address is link local. ++ STDNET_CONSTEXPR bool is_link_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xfe) && ((bytes_[1] & 0xc0) == 0x80)); ++ } ++ ++ /// Determine whether the address is site local. ++ STDNET_CONSTEXPR bool is_site_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xfe) && ((bytes_[1] & 0xc0) == 0xc0)); ++ } ++ ++ /// Determine whether the address is a mapped IPv4 address. ++ STDNET_CONSTEXPR bool is_v4_mapped() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0xff) && (bytes_[11] == 0xff)); ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (bytes_[0] == 0xff); ++ } ++ ++ /// Determine whether the address is a global multicast address. ++ STDNET_CONSTEXPR bool is_multicast_global() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x0e)); ++ } ++ ++ /// Determine whether the address is a link-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_link_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x02)); ++ } ++ ++ /// Determine whether the address is a node-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_node_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x01)); ++ } ++ ++ /// Determine whether the address is a org-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_org_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x08)); ++ } ++ ++ /// Determine whether the address is a site-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_site_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x05)); ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_ && a1.scope_id_ == a2.scope_id_; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 == a2); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ if (a1.bytes_ < a2.bytes_) ++ return true; ++ if (a1.bytes_ > a2.bytes_) ++ return false; ++ return a1.scope_id_ < a2.scope_id_; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return a2 < a1; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a2 < a1); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 < a2); ++ } ++ ++ /// Obtain an address object that represents any address. ++ static STDNET_CONSTEXPR address_v6 any() STDNET_NOEXCEPT ++ { ++ return address_v6(); ++ } ++ ++ /// Obtain an address object that represents the loopback address. ++ static STDNET_CONSTEXPR address_v6 loopback() STDNET_NOEXCEPT ++ { ++ return bytes_type(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); ++ } ++ ++private: ++ friend STDNET_CONSTEXPR address_v4 make_address_v4( ++ v4_mapped_t, const address_v6&); ++ ++ // The underlying IPv6 address. ++ bytes_type bytes_; ++ ++ // The scope ID associated with the address. ++ unsigned long scope_id_; ++}; ++ ++/// Construct an address_v6 from raw bytes. ++inline STDNET_CONSTEXPR address_v6 make_address_v6( ++ const address_v6::bytes_type& bytes, unsigned long scope_id = 0) ++{ ++ return address_v6(bytes, scope_id); ++} ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const char* str); ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const std::string& str); ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an IPv4-mapped address_v6 from an IPv4 address. ++inline STDNET_CONSTEXPR address_v6 make_address_v6( ++ v4_mapped_t, const address_v4& addr) STDNET_NOEXCEPT ++{ ++ return address_v6::bytes_type(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, ++ static_cast(addr.to_bytes())[0], ++ static_cast(addr.to_bytes())[1], ++ static_cast(addr.to_bytes())[2], ++ static_cast(addr.to_bytes())[3]); ++} ++ ++/// Create an address_v4 from an IPv4-mapped address_v6. ++inline STDNET_CONSTEXPR address_v4 make_address_v4( ++ v4_mapped_t, const address_v6& addr) ++{ ++ return !addr.is_v4_mapped() ? throw bad_address_cast() : ++ address_v4::bytes_type(addr.bytes_[12], addr.bytes_[13], ++ addr.bytes_[14], addr.bytes_[15]); ++} ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address_v6 ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v6& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address_v6.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address_v6.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_IP_ADDRESS_V6_HPP +diff --git a/ip-address/include/std/net/ip/bad_address_cast.hpp b/ip-address/include/std/net/ip/bad_address_cast.hpp +new file mode 100644 +index 0000000..bc330c2 +--- /dev/null ++++ b/ip-address/include/std/net/ip/bad_address_cast.hpp +@@ -0,0 +1,46 @@ ++// ++// ip/bad_address_cast.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_BAD_ADDRESS_CAST_HPP ++#define STDNET_IP_BAD_ADDRESS_CAST_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++/// Exception thrown on a failed address_cast. ++class bad_address_cast ++ : public bad_cast ++{ ++public: ++ virtual const char* what() const STDNET_NOEXCEPT ++ { ++ return "bad address cast"; ++ } ++}; ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_BAD_ADDRESS_CAST_HPP +diff --git a/ip-address/include/std/net/ip/fwd.hpp b/ip-address/include/std/net/ip/fwd.hpp +new file mode 100644 +index 0000000..2c8f929 +--- /dev/null ++++ b/ip-address/include/std/net/ip/fwd.hpp +@@ -0,0 +1,149 @@ ++// ++// ip/fwd.hpp ++// ~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_FWD_HPP ++#define STDNET_IP_FWD_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++#if defined(STDNET_HAS_CONSTEXPR) ++struct v4_mapped_t { STDNET_CONSTEXPR v4_mapped_t() {} }; ++STDNET_CONSTEXPR v4_mapped_t v4_mapped; ++#else // !defined(STDNET_HAS_CONSTEXPR) ++enum v4_mapped_t { v4_mapped }; ++#endif // !defined(STDNET_HAS_CONSTEXPR) ++ ++class address; ++class address_v4; ++class address_v6; ++ ++// address comparisons: ++bool operator==(const address&, const address&) STDNET_NOEXCEPT; ++bool operator!=(const address&, const address&) STDNET_NOEXCEPT; ++bool operator< (const address&, const address&) STDNET_NOEXCEPT; ++bool operator> (const address&, const address&) STDNET_NOEXCEPT; ++bool operator<=(const address&, const address&) STDNET_NOEXCEPT; ++bool operator>=(const address&, const address&) STDNET_NOEXCEPT; ++ ++// address creation: ++address make_address(const char*); ++address make_address(const char*, std::error_code&) STDNET_NOEXCEPT; ++address make_address(const std::string&); ++address make_address(const std::string&, std::error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// address_v4 comparisons: ++bool operator==(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator!=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator< (const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator> (const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator<=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator>=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++ ++// address_v4 creation: ++//STDNET_CONSTEXPR address_v4 make_address_v4(const address_v4::octets&); ++STDNET_CONSTEXPR address_v4 make_address_v4(unsigned long); ++STDNET_CONSTEXPR address_v4 make_address_v4(v4_mapped_t, const address_v6&); ++address_v4 make_address_v4(const char*); ++address_v4 make_address_v4(const char*, error_code&) STDNET_NOEXCEPT; ++address_v4 make_address_v4(const std::string&); ++address_v4 make_address_v4(const std::string&, std::error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address_v4 I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address_v4&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// address_v6 comparisons: ++bool operator==(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator!=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator< (const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator> (const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator<=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator>=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++ ++// address_v6 creation: ++//STDNET_CONSTEXPR address_v6 make_address_v6(const address_v6::octets&, unsigned long = 0); ++STDNET_CONSTEXPR address_v6 make_address_v6(v4_mapped_t, const address_v4&) STDNET_NOEXCEPT; ++address_v6 make_address_v6(const char*); ++address_v6 make_address_v6(const char*, error_code&) STDNET_NOEXCEPT; ++address_v6 make_address_v6(const std::string&); ++address_v6 make_address_v6(const std::string&, error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address_v6 I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address_v6&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++class bad_address_cast; ++ ++// address conversion: ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0); ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0); ++template STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_DELETED; ++template STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_DELETED; ++template STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_FWD_HPP +diff --git a/ip-address/include/std/net/ip/impl/address.hpp b/ip-address/include/std/net/ip/impl/address.hpp +new file mode 100644 +index 0000000..82dc09c +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address.hpp +@@ -0,0 +1,74 @@ ++// ++// ip/impl/address.hpp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_HPP ++#define STDNET_IP_IMPL_ADDRESS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/ip/address_cast.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++inline STDNET_CONSTEXPR address::address(const T& t) STDNET_NOEXCEPT ++ : address(address_cast
(t)) ++{ ++} ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++template ++inline STDNET_CONSTEXPR address::address(T&&... t) ++ : address(make_address(static_cast(t)...)) ++{ ++} ++ ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_HPP +diff --git a/ip-address/include/std/net/ip/impl/address.ipp b/ip-address/include/std/net/ip/impl/address.ipp +new file mode 100644 +index 0000000..b74189c +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address.ipp +@@ -0,0 +1,91 @@ ++// ++// ip/impl/address.ipp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_IPP ++#define STDNET_IP_IMPL_ADDRESS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/ip/address.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address::to_string() const ++{ ++ if (type_ == ipv4) ++ return ipv4_address_.to_string(); ++ if (type_ == ipv6) ++ return ipv6_address_.to_string(); ++ throw bad_address_cast(); ++} ++ ++std::string address::to_string(std::error_code& ec) const ++{ ++ if (type_ == ipv4) ++ return ipv4_address_.to_string(ec); ++ if (type_ == ipv6) ++ return ipv6_address_.to_string(ec); ++ throw bad_address_cast(); ++} ++ ++address make_address(const char* str) ++{ ++ std::error_code ec; ++ address addr = make_address(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address make_address(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v6 ipv6_address = make_address_v6(str, ec); ++ if (!ec) ++ return ipv6_address; ++ ++ address_v4 ipv4_address = make_address_v4(str, ec); ++ if (!ec) ++ return ipv4_address; ++ ++ return address(); ++} ++ ++address make_address(const std::string& str) ++{ ++ return make_address(str.c_str()); ++} ++ ++address make_address(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_IPP +diff --git a/ip-address/include/std/net/ip/impl/address_v4.hpp b/ip-address/include/std/net/ip/impl/address_v4.hpp +new file mode 100644 +index 0000000..8544419 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v4.hpp +@@ -0,0 +1,57 @@ ++// ++// ip/impl/address_v4.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V4_HPP ++#define STDNET_IP_IMPL_ADDRESS_V4_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v4& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V4_HPP +diff --git a/ip-address/include/std/net/ip/impl/address_v4.ipp b/ip-address/include/std/net/ip/impl/address_v4.ipp +new file mode 100644 +index 0000000..1ed99f7 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v4.ipp +@@ -0,0 +1,90 @@ ++// ++// ip/impl/address_v4.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V4_IPP ++#define STDNET_IP_IMPL_ADDRESS_V4_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/address_v4.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address_v4::to_string() const ++{ ++ std::error_code ec; ++ std::string addr = to_string(ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++std::string address_v4::to_string(std::error_code& ec) const ++{ ++ char addr_str[std::experimental::net::detail::max_addr_v4_str_len]; ++ const char* addr = ++ std::experimental::net::detail::socket_ops::inet_ntop( ++ AF_INET, bytes_.data(), addr_str, ++ std::experimental::net::detail::max_addr_v4_str_len, 0, ec); ++ if (addr == 0) ++ return std::string(); ++ return addr; ++} ++ ++address_v4 make_address_v4(const char* str) ++{ ++ std::error_code ec; ++ address_v4 addr = make_address_v4(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address_v4 make_address_v4(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v4::bytes_type bytes; ++ if (std::experimental::net::detail::socket_ops::inet_pton( ++ AF_INET, str, bytes.data(), 0, ec) <= 0) ++ return address_v4(); ++ return address_v4(bytes); ++} ++ ++address_v4 make_address_v4(const std::string& str) ++{ ++ return make_address_v4(str.c_str()); ++} ++ ++address_v4 make_address_v4(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address_v4(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V4_IPP +diff --git a/ip-address/include/std/net/ip/impl/address_v6.hpp b/ip-address/include/std/net/ip/impl/address_v6.hpp +new file mode 100644 +index 0000000..1b3fd23 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v6.hpp +@@ -0,0 +1,57 @@ ++// ++// ip/impl/address_v6.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V6_HPP ++#define STDNET_IP_IMPL_ADDRESS_V6_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v6& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V6_HPP +diff --git a/ip-address/include/std/net/ip/impl/address_v6.ipp b/ip-address/include/std/net/ip/impl/address_v6.ipp +new file mode 100644 +index 0000000..682160b +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v6.ipp +@@ -0,0 +1,90 @@ ++// ++// ip/impl/address_v6.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V6_IPP ++#define STDNET_IP_IMPL_ADDRESS_V6_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address_v6::to_string() const ++{ ++ std::error_code ec; ++ std::string addr = to_string(ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++std::string address_v6::to_string(std::error_code& ec) const ++{ ++ char addr_str[std::experimental::net::detail::max_addr_v6_str_len]; ++ const char* addr = ++ std::experimental::net::detail::socket_ops::inet_ntop( ++ AF_INET6, bytes_.data(), addr_str, ++ std::experimental::net::detail::max_addr_v6_str_len, ++ scope_id_, ec); ++ if (addr == 0) ++ return std::string(); ++ return addr; ++} ++ ++address_v6 make_address_v6(const char* str) ++{ ++ std::error_code ec; ++ address_v6 addr = make_address_v6(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address_v6 make_address_v6(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v6::bytes_type bytes; ++ unsigned long scope_id = 0; ++ if (std::experimental::net::detail::socket_ops::inet_pton( ++ AF_INET6, str, bytes.data(), &scope_id, ec) <= 0) ++ return address_v6(); ++ return address_v6(bytes, scope_id); ++} ++ ++address_v6 make_address_v6(const std::string& str) ++{ ++ return make_address_v6(str.c_str()); ++} ++ ++address_v6 make_address_v6(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address_v6(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V6_IPP +diff --git a/ip-address/include/std/net/literals.hpp b/ip-address/include/std/net/literals.hpp +new file mode 100644 +index 0000000..2f10279 +--- /dev/null ++++ b/ip-address/include/std/net/literals.hpp +@@ -0,0 +1,51 @@ ++// ++// literals.hpp ++// ~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_LITERALS_HPP ++#define STDNET_LITERALS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++inline namespace literals { ++inline namespace net_literals { ++ ++inline net::ip::address operator"" _ip(const char* str, std::size_t) ++{ ++ return net::ip::make_address(str); ++} ++ ++inline net::ip::address_v4 operator"" _ipv4(const char* str, std::size_t) ++{ ++ return net::ip::make_address_v4(str); ++} ++ ++inline net::ip::address_v6 operator"" _ipv6(const char* str, std::size_t) ++{ ++ return net::ip::make_address_v6(str); ++} ++ ++} // inline namespace net_literals ++} // inline namespace literals ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_LITERALS_HPP +diff --git a/ip_prefix.cc b/ip_prefix.cc +new file mode 100644 +index 0000000..871ee73 +--- /dev/null ++++ b/ip_prefix.cc +@@ -0,0 +1,124 @@ ++// ip_prefix.cc: IP_prefix class definition ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++#include ++#include ++#include ++ ++ ++// Namespace aliases ++namespace ip = std::experimental::net::ip; ++ ++// Deafult namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++string IP_prefix::to_bitstring(unsigned short int byte) { ++ string result = "00000000"; ++ for (int i = 7; i >= 0; i--) { ++ if (byte > 0) { ++ if (byte % 2 == 0) { ++ result[i] = '0'; ++ } else { ++ result[i] = '1'; ++ } ++ byte /= 2; ++ } ++ } ++ return result; ++} // end to_bitstring() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++IP_prefix::IP_prefix(const string& str, bool bitstring) { ++ if (bitstring) { // str represents bits of an IPv4/IPv6 prefix ++ prefix = str; ++ } else { // str represents a valid IPv4/IPv6 prefix in the standard notation ++ // extract prefix ++ string pref = str.substr(0, str.find('/')); ++ // extract prefix length ++ int len = atoi(str.substr(str.find('/')+1).c_str()); ++ ++ // transform address part of the prefix into generic format ++ ip::address addr(pref); ++ ++ // transform generic format into bitstring format ++ string addr_bitstring; ++ if (addr.is_v4()) { // IPv4 ++ ip::address_v4 addr_v4(pref); ++ ip::address_v4::bytes_type addr_v4_bytes = addr_v4.to_bytes(); ++ for (ip::address_v4::bytes_type::iterator it = addr_v4_bytes.begin(); it != addr_v4_bytes.end(); ++it) { ++ addr_bitstring.append(to_bitstring(*it)); ++ } ++ } else if (addr.is_v6()){ // IPv6 ++ ip::address_v6 addr_v6(pref); ++ ip::address_v6::bytes_type addr_v6_bytes = addr_v6.to_bytes(); ++ for (ip::address_v6::bytes_type::iterator it = addr_v6_bytes.begin(); it != addr_v6_bytes.end(); ++it) { ++ addr_bitstring.append(to_bitstring(*it)); ++ } ++ } ++ ++ // store only bits actually involved in IP prefix ++ prefix = addr_bitstring.substr(0, len); ++ } ++} // end IP_prefix() ++ ++ ++IP_prefix::IP_prefix(unsigned addr, int len) { ++ // bitstring representation of addr ++ string addr_bitstring; ++ ++ // convert addr into bitstring representation ++ addr_bitstring.append(to_bitstring(addr >> 24)); ++ addr_bitstring.append(to_bitstring(addr >> 16)); ++ addr_bitstring.append(to_bitstring(addr >> 8)); ++ addr_bitstring.append(to_bitstring(addr)); ++ ++ // store only bits actually involved in IP prefix ++ prefix = addr_bitstring.substr(0, len); ++} // end IP_prefix() ++ ++ ++IP_prefix& IP_prefix::operator= (const IP_prefix& orig) { ++ // create a copy of class members ++ prefix = orig.get_prefix(); ++ // return the created object ++ return *this; ++} // end operator= () ++ ++ ++unsigned IP_prefix::get_prefix_unsigned() const { ++ // initialize auxiliary variables ++ unsigned prefix_uns = 0; ++ unsigned pow = 1; ++ ++ // iterate over all bits of an unsigned integer from right to left ++ for (int i = 31; i >= 0; i--) { ++ if (i < (int)prefix.length()) { ++ if (prefix[i] == '1') { ++ prefix_uns += pow; ++ } ++ } ++ pow += pow; ++ } ++ ++ // return the prefix value ++ return prefix_uns; ++} // end get_prefix_unsigned(); +diff --git a/ip_prefix.h b/ip_prefix.h +new file mode 100644 +index 0000000..f21616f +--- /dev/null ++++ b/ip_prefix.h +@@ -0,0 +1,128 @@ ++// ip_prefix.h: header file for IP_prefix class ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef IP_PREFIX_H ++#define IP_PREFIX_H ++ ++ ++#include ++ ++// Deafult namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of IPv4/IPv6 prefixes. ++ * ++ * IP prefixes are represented as bitstrings where the first character ++ * represents the MSB of an IP address. Prefix length is determined by the ++ * length of the bitstring. ++ */ ++class IP_prefix { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * String of bits representing the prefix. ++ * The first character represents the MSB of the prefix and the prefix ++ * length is given by the length of this string. ++ */ ++ string prefix; ++ ++ /* ++ * Static function for conversion of a single byte into a bitstring. ++ * @param byte Byte to be converted. ++ * @return Byte converted into bitstring. ++ */ ++ static string to_bitstring(unsigned short int byte); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * Constructs an empty object of the IP_prefix class ++ */ ++ inline IP_prefix() {}; ++ ++ /* ++ * Constructor. ++ * Constructs an object of the IP_prefix class from a given string ++ * representing either bits of an IPv4/IPv6 prefix (the length of the ++ * string being the lenght of the prefix) or a valid IPv4/IPv6 prefix in ++ * the standard notation. ++ * @param str String representing an IPv4/IPv6 prefix in a format ++ * determined by the bitsring parameter. ++ * @param bitstring str represents bits of an IPv4/IPv6 prefix (TRUE) ++ * or a valid IPv4/IPv6 prefix in the standard ++ * notation (FALSE). ++ */ ++ IP_prefix(const string& str, bool bitsring); ++ ++ /* ++ * Constructor. ++ * Constructs an object of the IP_prefix class from a given IPv4 prefix ++ * represented by its address part (unsigned integer) and length ++ * (integer). ++ * @param addr Address part of the IPv4 prefix. ++ * @param len Prefix length. ++ */ ++ IP_prefix(unsigned addr, int len); ++ ++ /* ++ * Copy assignment. ++ * Constructs a new IP prefix object by asigning a copy of the original ++ * IP prefix object. ++ * @param orig Reference to the original IP prefix object. ++ * @return Reference to the new IP prefix object. ++ */ ++ IP_prefix& operator= (const IP_prefix& orig); ++ ++ /* ++ * Comparison operator. ++ * Compares the current IP prefix object with the given IP prefix object. ++ * @param rhs_prefix IP prefix object to be compared with the current ++ * IP prefix object. ++ * @return TRUE if IP prefixes are equal, ++ * FALSE otherwise. ++ */ ++ inline bool operator== (const IP_prefix& rhs_prefix) const { ++ return (prefix == rhs_prefix.get_prefix()); ++ } ++ ++ /* ++ * Get function for the prefix bitstring. ++ * @return Bitstring representing IPv4/IPv6 prefix. ++ */ ++ inline string get_prefix() const { ++ return prefix; ++ } // end get_prefix() ++ ++ /* ++ * Get function for the prefix in the form of an unsigned number. ++ * @return Unsingned numbre representing IPv4/IPv6 prefix. ++ */ ++ unsigned get_prefix_unsigned() const; ++ ++ /* ++ * Get function for the prefix length. ++ * @return Prefix length. ++ */ ++ inline int get_length() const { ++ return prefix.length(); ++ } // end get_prefix() ++}; ++ ++#endif +diff --git a/makefile b/makefile +old mode 100755 +new mode 100644 +index 773f4c1..2750d37 +--- a/makefile ++++ b/makefile +@@ -9,15 +9,16 @@ + ## See README file for details + + CC = g++ ++LIB = -I./ip-address/include + ##CFLAGS = -g -pg +-CFLAGS = -O2 ++CFLAGS = -O2 -std=c++11 $(LIB) + .cc.o: + ${CC} ${CFLAGS} -c $*.cc + + sbintree.o : stdinc.h dlist.h sbintree.h + dbintree.o : stdinc.h dlist.h dbintree.h + random_db.o : stdinc.h FilterList.h random_db.h +-custom_db.o : stdinc.h FilterList.h ProtList.h FlagList.h ExtraList.h PortList.h PrefixList.h dlist.h sbintree.h dbintree.h redundant_filter_check.h TupleBST.h custom_db.h ++custom_db.o : stdinc.h FilterList.h ProtList.h FlagList.h ExtraList.h PortList.h PrefixList.h dlist.h sbintree.h dbintree.h redundant_filter_check.h TupleBST.h custom_db.h ip_prefix.h trie.h filter_graph.h + dlist.o : stdinc.h dlist.h + redundant_filter_check.o : stdinc.h redundant_filter_check.h + ## nesting_filter_check.o : stdinc.h nesting_filter_check.h +@@ -29,8 +30,15 @@ PrefixList.o : stdinc.h PrefixList.h + FilterList.o : stdinc.h FilterList.h + TupleBST.o : stdinc.h dlist.h TupleBST.h + db_generator.o : stdinc.h random_db.h PortList.h FilterList.h custom_db.h ++ip_prefix.o : ip_prefix.h ++trie.o : trie.h ++flow_network.o : flow_network.h ++filter_graph.o : stdinc.h filter_graph.h + +-db_generator: db_generator.o random_db.o dlist.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o sbintree.o dbintree.o redundant_filter_check.o FilterList.o TupleBST.o custom_db.o +- ${CC} ${CFLAGS} db_generator.o random_db.o dlist.o sbintree.o dbintree.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o FilterList.o redundant_filter_check.o TupleBST.o custom_db.o -o db_generator ++db_generator: db_generator.o random_db.o dlist.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o sbintree.o dbintree.o redundant_filter_check.o FilterList.o TupleBST.o custom_db.o ip_prefix.o trie.o flow_network.o filter_graph.o ++ ${CC} ${CFLAGS} db_generator.o random_db.o dlist.o sbintree.o dbintree.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o FilterList.o redundant_filter_check.o TupleBST.o custom_db.o ip_prefix.o trie.o flow_network.o filter_graph.o -o db_generator + + all: db_generator ++ ++clean: ++ rm -rf *.o db_generator +diff --git a/sbintree.cc b/sbintree.cc +index d755099..cbd4410 100644 +--- a/sbintree.cc ++++ b/sbintree.cc +@@ -26,9 +26,9 @@ sbintree::sbintree() { + } + + sbintree::~sbintree() { +- delete(skew); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } +@@ -291,6 +291,10 @@ void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr + add_node(me, lev1, 1, addr1, other_list, filters, MyNest); + } + } ++ ++ // Deallocate nest_list ++ delete(nest_list); ++ delete(other_list); + } + else { + // Othewise, branch based on branching probability and skew +diff --git a/sbintree.h b/sbintree.h +index b085696..9deca63 100644 +--- a/sbintree.h ++++ b/sbintree.h +@@ -43,6 +43,17 @@ class sbintree { + void scale_skew(float scale_factor); // scale branching and skew according to scaling factor + void print_skew(FILE*); // print average skew per level + void build_tree(dlist* Flist, struct filter filters[]); ++ ++ // get methods for selected private members ++ inline float* get_skew() { ++ return skew; ++ }; ++ inline float* get_p1child() { ++ return p1child; ++ }; ++ inline float* get_p2child() { ++ return p2child; ++ }; + }; + + #endif +diff --git a/stdinc.h b/stdinc.h +index f566e0f..a66dfd7 100644 +--- a/stdinc.h ++++ b/stdinc.h +@@ -24,7 +24,7 @@ inline double max(double x, double y) { return x > y ? x : y; } + inline int min(int x, int y) { return x < y ? x : y; } + inline double min(double x, double y) { return x < y ? x : y; } + inline int abs(int x) { return x < 0 ? -x : x; } +-inline bit isdigit(int c) { return (c >= '0') && (c <= '9'); } ++// inline bit isdigit(int c) { return (c >= '0') && (c <= '9'); } + + inline void warning(char* p) { fprintf(stderr,"Warning:%s \n",p); } + inline void fatal(char* string) {fprintf(stderr,"Fatal:%s\n",string); exit(1); } +@@ -69,6 +69,30 @@ struct filter { + int *ext_field; // Pointer to array of extra header fields + }; + ++// Do a deep copy of orig filter ++inline void copy_filter(struct filter& copy, struct filter orig) { ++ copy.sa = orig.sa; ++ copy.da = orig.da; ++ copy.sa_len = orig.sa_len; ++ copy.da_len = orig.da_len; ++ copy.sp[0] = orig.sp[0]; ++ copy.sp[1] = orig.sp[1]; ++ copy.dp[0] = orig.dp[0]; ++ copy.dp[1] = orig.dp[1]; ++ copy.prot_num = orig.prot_num; ++ copy.flags = orig.flags; ++ copy.flags_mask = orig.flags_mask; ++ copy.num_ext_field = orig.num_ext_field; ++ if (copy.num_ext_field > 0) { ++ copy.ext_field = new int[copy.num_ext_field]; ++ for (int i = 0; i < copy.num_ext_field; i++) { ++ copy.ext_field[i] = orig.ext_field[i]; ++ } ++ } else { ++ copy.ext_field = NULL; ++ } ++} ++ + struct range { + int low; + int high; +diff --git a/trie.cc b/trie.cc +new file mode 100644 +index 0000000..12f15de +--- /dev/null ++++ b/trie.cc +@@ -0,0 +1,1190 @@ ++// trie.cc: trie class definition ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "trie.h" ++ ++// Library includes ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Auxiliary class definitions ++// **************************************************************************** ++ ++class trie_nodes_greater_than_prefixes { ++public: ++ // implements operation "node1 is GREATER THAN node2" ++ // according to the number of prefixes ++ bool operator()(trie_node* node1, trie_node* node2) ++ { ++ if (node2->prefixes < node1->prefixes) { ++ return true; ++ } else { ++ return false; ++ } ++ } ++}; ++ ++class trie_nodes_greater_than_weight { ++public: ++ // implements operation "node1 is GREATER THAN node2" ++ // according to the total weight of nodes' subtrees ++ bool operator()(trie_node* node1, trie_node* node2) ++ { ++ if ((node2->zero_weight + node2->one_weight) < ++ (node1->zero_weight + node1->one_weight)) { ++ return true; ++ } else { ++ return false; ++ } ++ } ++}; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++trie_node* Trie::copy(const trie_node* node, int level) { ++ // create a pointer to the root of a new trie ++ trie_node* copy_root; ++ // copy the given subtree ++ if (node != NULL) { // non-empty subtree ++ copy_root = new trie_node; ++ copy_root->level = level; ++ copy_root->prefixes = node->prefixes; ++ copy_root->prefix_nesting_branches = node->prefix_nesting_branches; ++ copy_root->zero = copy(node->zero, level+1); ++ copy_root->zero_weight = node->zero_weight; ++ copy_root->one = copy(node->one, level+1); ++ copy_root->one_weight = node->one_weight; ++ } else { // empty subtree ++ copy_root = NULL; ++ } ++ // return the pointer to the root node of the copy ++ return copy_root; ++} // end copy() ++ ++ ++void Trie::destruct(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ destruct(node->zero); ++ destruct(node->one); ++ delete node; ++ } ++ return; ++} // end destruct() ++ ++ ++int Trie::compute_weights(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ node->zero_weight = compute_weights(node->zero); ++ node->one_weight = compute_weights(node->one); ++ return node->zero_weight + node->one_weight + node->prefixes; ++ } else { // empty subtree ++ return 0; ++ } ++} // end compute_weights() ++ ++ ++float Trie::compute_skew(trie_node* node) { ++ if (node->zero_weight > node->one_weight) { // lighter 1-subtree ++ return 1 - ((float)node->one_weight / (float)node->zero_weight); ++ } else { // lighter 0-subtree ++ return 1 - ((float)node->zero_weight / (float)node->one_weight); ++ } ++} // end compute_skew() ++ ++ ++int Trie::get_prefix_nesting(const trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ // get prefix nesting from successor nodes ++ int zero_nesting = get_prefix_nesting(node->zero); ++ int one_nesting = get_prefix_nesting(node->one); ++ // will this node increase prefix nesting? ++ int is_prefix; ++ if (node->prefixes > 0) { // this is a prefix node ++ is_prefix = 1; ++ } else { ++ is_prefix = 0; ++ } ++ // return maximum of successors' nesting, possibly incremented ++ if (zero_nesting > one_nesting) { ++ return zero_nesting + is_prefix; ++ } else { ++ return one_nesting + is_prefix; ++ } ++ } else { // empty subtree ++ return 0; ++ } ++} // end get_prefix_nesting() ++ ++ ++void Trie::remove_lightest_subtree(queue q, bool one_child, ++ int prefix_nesting_branches) { ++ trie_node** lightest_subtree_ptr = NULL; ++ int* lightest_weight_ptr = NULL; ++ // find the lightest subtree of nodes stored in the queue ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // auxiliary variables ++ trie_node** subtree_ptr = NULL; ++ int* weight_ptr = NULL; ++ if (one_child) { // consider only nodes with one child ++ // consider only nodes that can become a valid leaf node ++ if (node->prefixes > 0) { ++ // one-subtree only ++ if ((node->zero == NULL) && (node->one != NULL)) { ++ // the last maximum prefix nesting branch is not going through ++ // the one-subtree ++ if (node->one->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->one); ++ weight_ptr = &(node->one_weight); ++ } ++ // zero-subtree only ++ } else if ((node->zero != NULL) && (node->one == NULL)) { ++ // the last maximum prefix nesting branch is not going through ++ // the zero-subtree ++ if (node->zero->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->zero); ++ weight_ptr = &(node->zero_weight); ++ } ++ } ++ } ++ } else { // consider only nodes with two children ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // determine lighter subtree ++ if (node->zero_weight <= node->one_weight) { ++ // the last maximum prefix nesting branch is not going through ++ // the zero-subtree ++ if (node->zero->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->zero); ++ weight_ptr = &(node->zero_weight); ++ } ++ } else { ++ // the last maximum prefix nesting branch is not going through ++ // the one-subtree ++ if (node->one->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->one); ++ weight_ptr = &(node->one_weight); ++ } ++ } ++ } ++ } ++ // no lightest subtree has been found so far ++ if (lightest_weight_ptr == NULL) { ++ if (weight_ptr != NULL) { // new candidate for the lightest subtree ++ lightest_subtree_ptr = subtree_ptr; ++ lightest_weight_ptr = weight_ptr; ++ } ++ } else { // a candidate for the lightest subtree has already been found ++ if (weight_ptr != NULL) { // new candidate for the lightest subtree ++ // new lightest subtree ++ if ((*weight_ptr) < (*lightest_weight_ptr)) { ++ lightest_subtree_ptr = subtree_ptr; ++ lightest_weight_ptr = weight_ptr; ++ } ++ } ++ } ++ } // end of while (!q.empty()) ++ // if lightest subtree, which can be removed, has been found ++ if (lightest_subtree_ptr != NULL) { ++ destruct(*lightest_subtree_ptr); ++ *lightest_subtree_ptr = NULL; ++ *lightest_weight_ptr = 0; ++ } ++ return; ++} // end remove_lightest_subtree() ++ ++ ++int Trie::mark_prefix_nesting_branches(trie_node* node, int prefix_nesting, ++ int seen_prefixes) { ++ if (node == NULL) { // empty subtree ++ return 0; ++ } ++ if (node->prefixes > 0) { // the current root node is a prefix node ++ seen_prefixes++; ++ } ++ // when a prefix nesting branch has been found ++ if (seen_prefixes == prefix_nesting) { ++ node->prefix_nesting_branches = 1; ++ } else { // look for maximum prefix nesting branches in subtrees ++ int branches_zero = mark_prefix_nesting_branches(node->zero, ++ prefix_nesting, ++ seen_prefixes); ++ int branches_one = mark_prefix_nesting_branches(node->one, ++ prefix_nesting, ++ seen_prefixes); ++ node->prefix_nesting_branches = branches_zero + branches_one; ++ } ++ return node->prefix_nesting_branches; ++} // end mark_refix_nesting_branches() ++ ++ ++int Trie::get_removable_prefixes(trie_node* node) { ++ if (node == NULL) { ++ return 0; ++ } ++ int removable_prefixes_zero = get_removable_prefixes(node->zero); ++ int removable_prefixes_one = get_removable_prefixes(node->one); ++ int removable_prefixes_this = node->prefixes; ++ // keep at least one prefix in a leaf node ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_this--; ++ } ++ // different handling for 2-children node ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // allow removing prefixes from subtrees only if both subtrees contain ++ // removable prefixes ++ if ((removable_prefixes_zero > 0) && (removable_prefixes_one > 0)) { ++ // initialize auxiliar variables ++ int zero_weight = node->zero_weight; ++ int one_weight = node->one_weight; ++ int d = 1; // divisor of zero_weight and one_weight ++ int x = 0; // to be removed prefixes from zero subtree ++ int y = 0; // to be removed prefixes from one subtree ++ // find x and y such that ++ // a) x <= removable_prefixes_zero ++ // b) y <= removable_prefixes_one ++ // where ++ // x = zero_weight - (zero_weight / gcd) ++ // y = one_weight - (one_weight / gcd) ++ // and gcd is the gratest common divisor of zero_weight and one_weight ++ while ((d <= zero_weight) && (d <= one_weight)) { ++ // if d is the gcd ++ if (((zero_weight % d) == 0) && ((one_weight % d) == 0)) { ++ // if to be removed prefixes from both zero and one subtrees is ++ // smaller than removable prefixes from these subtrees ++ if ((zero_weight - zero_weight / d <= removable_prefixes_zero) ++ && ++ (one_weight - one_weight / d <= removable_prefixes_one)) { ++ x = zero_weight - (zero_weight / d); ++ y = one_weight - (one_weight / d); ++ } else { ++ break; ++ } ++ } ++ d++; ++ } ++ // return the total number of prefixes that can be removed without ++ // altering the skew ++ return removable_prefixes_this + ++ x + ++ y; ++ } else { ++ return removable_prefixes_this; ++ } ++ } else { ++ return removable_prefixes_this + ++ removable_prefixes_zero + ++ removable_prefixes_one; ++ } ++} // end get_removable_prefixes ++ ++ ++void Trie::adjust_node_skew(trie_node* node, float target_skew) { ++ // initialize lighter_* and heavier_* variables ++ int lighter_weight; ++ int heavier_weight; ++ trie_node* lighter_subtree; ++ trie_node* heavier_subtree; ++ // initialize auxiliary variables for skew computation ++ float skew; ++ int zero_weight = node->zero_weight; ++ int one_weight = node->one_weight; ++ // compute skew of the given node and set lighter_* and heavier_* variables ++ if (zero_weight > one_weight) { // zero subtree is heavier ++ skew = 1 - ((float)one_weight / (float)zero_weight); ++ lighter_weight = one_weight; ++ heavier_weight = zero_weight; ++ lighter_subtree = node->one; ++ heavier_subtree = node->zero; ++ } else { // one subtree is heavier ++ skew = 1 - ((float)zero_weight / (float)one_weight); ++ lighter_weight = zero_weight; ++ heavier_weight = one_weight; ++ lighter_subtree = node->zero; ++ heavier_subtree = node->one; ++ } ++ // initialize auxiliary variables ++ double new_weight_real; ++ int weight; ++ trie_node* subtree; ++ // decrease working skew - remove prefixes from heavier subtree ++ if ((skew - target_skew) > 0) { ++ new_weight_real = lighter_weight / (1 - target_skew); ++ weight = heavier_weight; ++ subtree = heavier_subtree; ++ // increase working skew - remove prefixes from lighter subtree ++ } else { ++ new_weight_real = heavier_weight * (1 - target_skew); ++ weight = lighter_weight; ++ subtree = lighter_subtree; ++ } ++ // determine new integer weight of a selected subtree ++ int new_weight = round(new_weight_real); ++ // determine number of prefixes that will be removed ++ int remove_prefixes = weight - new_weight; ++ int removable_prefixes = get_removable_prefixes(subtree); ++ if (remove_prefixes > removable_prefixes) { ++ // decrease the number of removed prefixes to the maximum number of ++ // prefixes that can be removed ++ remove_prefixes = removable_prefixes; ++ } ++ // make the selected subtree lighter by removing the given number of ++ //prefixes ++ make_subtree_lighter(subtree, remove_prefixes); ++ compute_weights(node); ++ return; ++} // end adjust_node_skew() ++ ++ ++void Trie::make_subtree_lighter(trie_node* root, int remove_prefixes) { ++ // nothing to do when the subtree is empty or 0 prefixes are to be removed ++ if ((root == NULL) || (remove_prefixes == 0)) { ++ return; ++ } ++ // auxiliary variables for counting statistics ++ trie_node* node = root; ++ int removable_prefixes_node = 0; ++ int removable_prefixes_branch = 0; ++ // in priority queue, nodes with less prefixes have higher priority ++ priority_queue, ++ trie_nodes_greater_than_prefixes> pq; ++ // initialize auxiliary variables (keep at least one prefix in a leaf node) ++ removable_prefixes_node = node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ if (removable_prefixes_node > 0) { ++ removable_prefixes_branch = removable_prefixes_node; ++ pq.push(node); ++ } ++ // traverse a non-branching part of the subtree (i.e. up to the closest ++ // 2-children node or a leaf node) and compute basic statistics about it ++ while (((node->zero == NULL) && (node->one != NULL)) || ++ ((node->zero != NULL) && (node->one == NULL))) { ++ // determine the next step ++ if (node->zero == NULL) { ++ node = node->one; ++ } else { ++ node = node->zero; ++ } ++ // compute statistics (keep at least one prefix in a leaf node) ++ removable_prefixes_node = node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ if (removable_prefixes_node > 0) { ++ removable_prefixes_branch += removable_prefixes_node; ++ pq.push(node); ++ } ++ } ++ // get the number of removable prefixes in the remaining subtree ++ int removable_prefixes_subtree = get_removable_prefixes(node); ++ int removable_prefixes_zero = 0; ++ // adjust it to not contain removable prefixes of the subtree's root node ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_subtree = 0; ++ } else { ++ removable_prefixes_subtree -= node->prefixes; ++ } ++ // get the number of removable prefixes in branches of the remaining subtree ++ if (removable_prefixes_subtree > 0) { ++ int subtree_weight = node->zero_weight + node->one_weight; ++ removable_prefixes_zero = ++ round(((float)node->zero_weight / (float)subtree_weight) * ++ removable_prefixes_subtree); ++ } ++ // do not continue when no removable prefixes in the branch nor the subtree ++ if ((removable_prefixes_branch + removable_prefixes_subtree) == 0) { ++ return; ++ } ++ // distribute prefixes that are to be removed between the branch and the ++ // subtree ++ int remove_prefixes_branch = round(((float)removable_prefixes_branch / ++ (float)(removable_prefixes_subtree + ++ removable_prefixes_branch)) * ++ remove_prefixes); ++ int remove_prefixes_subtree = remove_prefixes - remove_prefixes_branch; ++ // initialize auxiliary variable for test purposes ++ int removed_prefixes_branch = 0; ++ // while there are some prefix nodes in the branch, remove prefixes ++ // proportionally from all these nodes ++ while (!pq.empty()) { ++ // deque the front element from the priority queue ++ trie_node* working_node = pq.top(); ++ pq.pop(); ++ // determine the number of prefixes that are to be removed from this node ++ int remove_prefixes_node; ++ if (!pq.empty()) { // not the last node of the branch ++ // keep at least one prefix in a leaf node ++ removable_prefixes_node = working_node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ // the nuber of prefixes to be removed is computed proportionally ++ remove_prefixes_node = round(((float)removable_prefixes_node / ++ (float)removable_prefixes_branch) * ++ remove_prefixes_branch); ++ } else { // the last node of the branch ++ // the number of prefixes to be removed ensures removing all the remaining prefixes ++ remove_prefixes_node = remove_prefixes_branch - removed_prefixes_branch; ++ } ++ // remove the given number of prefixes ++ working_node->prefixes -= remove_prefixes_node; ++ // adjust the test variable ++ removed_prefixes_branch += remove_prefixes_node; ++ } ++ // the last node in the non-branching part of the subtree is a 2-children ++ // node ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // there are some prefixes to be removed from the subtree rooted at node ++ if (remove_prefixes_subtree > 0) { ++ // distribute prefixes that are to be removed from from the subtree ++ // between its zero and one subtrees ++ int remove_prefixes_zero = round(((float)removable_prefixes_zero / ++ (float)removable_prefixes_subtree) * ++ remove_prefixes_subtree); ++ int remove_prefixes_one = remove_prefixes_subtree - ++ remove_prefixes_zero; ++ // remove prefixes from subtrees of the 2-children node ++ compute_weights(node); ++ make_subtree_lighter(node->zero, remove_prefixes_zero); ++ make_subtree_lighter(node->one, remove_prefixes_one); ++ compute_weights(node); ++ } ++ } ++ return; ++} // end make_subtree_lighter() ++ ++ ++trie_node* Trie::remove_nonprefix_branches(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ node->zero = remove_nonprefix_branches(node->zero); ++ node->one = remove_nonprefix_branches(node->one); ++ if ((node->zero == NULL) && (node->one == NULL) && ++ (node->prefixes == 0)) { ++ delete node; ++ return NULL; ++ } ++ } ++ return node; ++} //end remove_nonprefix_branches() ++ ++ ++void Trie::adjust_branching(vector branching_one_child, ++ vector branching_two_children) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // recursively compute weight of all subtrees ++ compute_weights(root); ++ // recursively compute maximum prefix nesting ++ int prefix_nesting = get_prefix_nesting(root); ++ // mark branches with maximum prefix nesting ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ // initialize auxiliary variables ++ queue q; ++ q.push(root); ++ int level = -1; ++ // do a breadth-first search ++ while (!q.empty()) { ++ // get pointer to the front element ++ trie_node* node = q.front(); ++ // first node at this level - perform branching adjustment ++ // (all nodes from the current level are enqueued) ++ if (node->level != level) { ++ level = node->level; ++ // compute branching statistics for this level ++ queue q_copy (q); ++ int one_child = 0; ++ int two_children = 0; ++ int sum = 0; ++ while (!q_copy.empty()) { ++ // dequeue front element from the auxiliary queue ++ trie_node* node_copy = q_copy.front(); ++ q_copy.pop(); ++ // increment correct counter ++ if ((node_copy->zero != NULL) && (node_copy->one != NULL)) { ++ two_children++; ++ } else if ((node_copy->zero != NULL) || (node_copy->one != NULL)) { ++ one_child++; ++ } ++ } ++ sum = one_child + two_children; ++ // branching probabilities are defined at this level ++ if (sum != 0) { // there is some branching at this level ++ float current_branching_two = (float) two_children / (float) (sum); ++ // adjust branching by reducing the number of two-children nodes ++ if (current_branching_two > branching_two_children[level]) { ++ // determine the ideal number of subtree removing steps ++ float remove_subtrees = two_children - ++ (branching_two_children[level] * sum); ++ // diff from ideal branching when remove min./max. subtrees ++ float diff_min = ((two_children - floor(remove_subtrees)) / sum) ++ - branching_two_children[level]; ++ float diff_max = branching_two_children[level] - ++ ((two_children - ceil(remove_subtrees)) / sum); ++ // determine the number of subtree removing steps ++ int remove_steps = 0; ++ if (diff_min <= diff_max) { ++ remove_steps = (int) floor(remove_subtrees); ++ } else { ++ remove_steps = (int) ceil(remove_subtrees); ++ } ++ // remove the given number of "lightest" subtrees + ++ // actualize markers of maximum prefix nesting branches ++ for (int i = 0; i < remove_steps; i++) { ++ remove_lightest_subtree(q, false, ++ root->prefix_nesting_branches); ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ } ++ // adjust branching nodes count variables ++ one_child += remove_steps; ++ two_children -= remove_steps; ++ } ++ // removing subtree of one-child nodes can change branching ++ // probabilities ++ if (two_children != 0) { ++ float current_branching_one = (float) one_child / (float) (sum); ++ // adjust branching by reducing the number of one-child nodes ++ if (current_branching_one > branching_one_child[level]) { ++ // determine the ideal number of subtree removing steps ++ float remove_subtrees = ++ ((branching_one_child[level] * sum) - one_child) / ++ (branching_one_child[level] - 1); ++ // diff from ideal branching when remove min./max. subtrees ++ float diff_min = ((one_child - floor(remove_subtrees)) / ++ (sum - floor(remove_subtrees))) - ++ branching_one_child[level]; ++ float diff_max = branching_one_child[level] - ++ ((one_child - ceil(remove_subtrees)) / ++ (sum - ceil(remove_subtrees))); ++ // determine the number of subtree removing steps ++ int remove_steps = 0; ++ if (diff_min <= diff_max) { ++ remove_steps = (int) floor(remove_subtrees); ++ } else { ++ remove_steps = (int) ceil(remove_subtrees); ++ } ++ // remove the given number of "lightest" subtrees + ++ // actualize markers of maximum prefix nesting branches ++ for (int i = 0; i < remove_steps; i++) { ++ remove_lightest_subtree(q, true, ++ root->prefix_nesting_branches); ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ } ++ one_child -= remove_steps; ++ sum -= remove_steps; ++ } ++ } ++ } // end of if (sum != 0) ++ } // end of if (node->level != level) ++ // enqueue possible successors of the current node ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // remove the front element from the queue ++ q.pop(); ++ } // end of while (!q.empty()) ++ return; ++} // end adjust_branching() ++ ++ ++void Trie::adjust_skew(vector skew, float skew_epsilon) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // initialize auxiliary variables ++ queue q; ++ stack s; ++ q.push(root); ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue front element from the queue ++ trie_node* node = q.front(); ++ q.pop(); ++ // store nodes with 2 children into a stack ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ s.push(node); ++ } ++ // enqueue possible successors of the current node ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ } ++ // initialize auxiliary variables ++ // in priority queue, lighter nodes have higher priority ++ priority_queue, ++ trie_nodes_greater_than_weight> pq; ++ float total_skew = 0.0; ++ int level; ++ if (!s.empty()) { ++ level = s.top()->level; ++ } ++ // do inverse breadth-first search on two-children nodes ++ while (!s.empty()) { ++ // pop top element from the stack ++ trie_node* node = s.top(); ++ s.pop(); ++ // next level - adjust total skew of the current level ++ if (level != node->level) { ++ // store the number of 2-children nodes at current level ++ int two_children_nodes = pq.size(); ++ // compute target total skew ("sum of all skew values at this level") ++ float target_total_skew = skew[level] * two_children_nodes; ++ // compute skew that is going to be added/removed ++ float skew_change = target_total_skew - total_skew; ++ // compute average skew that is going to be added/removed ++ float average_skew_change; ++ if (two_children_nodes > 0) { ++ average_skew_change = skew_change / (float)two_children_nodes; ++ } else { ++ average_skew_change = skew_change; ++ } ++ // iteratively adjust total skew at this level ++ while (!pq.empty()) { ++ // skip further skew adjustment when average_skew_change is less ++ // than the given skew_epsilon ++ if (abs(average_skew_change) < skew_epsilon) { ++ // remove remaining nodes from the priority queue ++ while (!pq.empty()) { ++ pq.pop(); ++ } ++ // end the outer "while (!pq.empty())" loop ++ break; ++ } ++ // pop the top element from the priority queue ++ trie_node* working_node = pq.top(); ++ pq.pop(); ++ // compute original skew of the working node ++ float original_skew = compute_skew(working_node); ++ float target_skew = original_skew + skew_change; ++ // adjust skew of the working node ++ if (target_skew < 0.0) { ++ target_skew = 0.0; ++ } else if (target_skew > 1.0) { ++ target_skew = 1.0; ++ } ++ adjust_node_skew(working_node, target_skew); ++ // recursively compute weight of node's subtrees ++ compute_weights(working_node); ++ // compute adjusted skew of the working node ++ float adjusted_skew = compute_skew(working_node); ++ // update total skew, skew that is going to be added/removed, and ++ // its average value ++ total_skew = total_skew - original_skew + adjusted_skew; ++ skew_change = target_total_skew - total_skew; ++ two_children_nodes = pq.size(); ++ if (two_children_nodes > 0) { ++ average_skew_change = skew_change / (float)two_children_nodes; ++ } else { ++ average_skew_change = skew_change; ++ } ++ } ++ level = node->level; ++ total_skew = 0.0; ++ } ++ // recursively compute weight of node's subtrees ++ compute_weights(node); ++ // insert the node into the priority queue ++ pq.push(node); ++ // actualize total skew value ++ total_skew += compute_skew(node); ++ } ++ return; ++} // end adjust_skew() ++ ++ ++void Trie::adjust_prefixes(vector prefixes_proportion, ++ const int target_size) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // compute the total number of prefixes at each level ++ vector all_prefixes(129,0); ++ queue q; ++ q.push(root); ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // enqueue its possible successors ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // update the total number of prefixes at current level ++ all_prefixes[node->level] += node->prefixes; ++ } ++ // compute the number of target and to be removed prefixes at each level ++ vector target_prefixes(129,0); ++ vector remove_prefixes(129,0); ++ int target_prefixes_total = 0; ++ int leaf_level = 0; ++ for (int i = 0; i < (int) prefixes_proportion.size(); i++) { ++ target_prefixes[i] = round(prefixes_proportion[i]*target_size); ++ target_prefixes_total += target_prefixes[i]; ++ remove_prefixes[i] = all_prefixes[i] - target_prefixes[i]; ++ if (target_prefixes[i] != 0) { ++ leaf_level = i; ++ } ++ } ++ // final correction to given target_size ++ if (target_prefixes_total != target_size) { ++ int diff = target_size - target_prefixes_total; ++ target_prefixes[leaf_level] += diff; ++ target_prefixes_total += diff; ++ remove_prefixes[leaf_level] -= diff; ++ } ++ // compute the number of prefixes to be removed at remaining levels ++ vector remove_prefixes_remaining(129,0); ++ for (int i = 127; i >= 0; i--) { ++ remove_prefixes_remaining[i] = remove_prefixes_remaining[i+1] + ++ remove_prefixes[i+1]; ++ } ++ // starting from the root, adjust prefixes distribution ++ queue nodes; ++ nodes.push(root); ++ queue remove_prefixes_subtrees; ++ remove_prefixes_subtrees.push(remove_prefixes[0] + remove_prefixes_remaining[0]); ++ int level = -1; ++ while (!nodes.empty()) { ++ // get the front element ++ // (from both nodes and remove_prefixes_subtrees queues) ++ trie_node* node = nodes.front(); ++ // next level - adjust prefixes at this level ++ // (all nodes of this level are stored in nodes queue) ++ if (node->level != level) { ++ level = node->level; ++ // actualize subtrees' weight information in nodes ++ compute_weights(root); ++ // initialize vectors to contain all current elements of queues ++ queue nodes_copy (nodes); ++ vector nodes_vect; ++ queue remove_prefixes_subtrees_copy (remove_prefixes_subtrees); ++ vector remove_prefixes_subtrees_vect; ++ while (!nodes_copy.empty()) { ++ nodes_vect.push_back(nodes_copy.front()); ++ nodes_copy.pop(); ++ remove_prefixes_subtrees_vect.push_back(remove_prefixes_subtrees_copy.front()); ++ remove_prefixes_subtrees_copy.pop(); ++ } ++ // from all leaf nodes at this level ++ // remove prefixes that have to be removed ++ int i = 0; ++ while (i < (int) nodes_vect.size()) { ++ if ((nodes_vect[i]->zero == NULL) && ++ (nodes_vect[i]->one == NULL)) { ++ // determine the real number of prefixes to be removed ++ // (do not remove the last prefix from a leaf node) ++ int remove_prefixes_node; ++ if (nodes_vect[i]->prefixes > remove_prefixes_subtrees_vect[i]) { ++ remove_prefixes_node = remove_prefixes_subtrees_vect[i]; ++ } else { ++ remove_prefixes_node = nodes_vect[i]->prefixes - 1; ++ } ++ // consider all prefixes of this node and this subtree to be ++ // removed, regardless they are really removed or not ++ // (in any case, there are no other prefixes that could be ++ // removed) ++ all_prefixes[level] -= nodes_vect[i]->prefixes; ++ remove_prefixes_subtrees_vect[i] = 0; ++ // remove the prefixes ++ nodes_vect[i]->prefixes -= remove_prefixes_node; ++ remove_prefixes[level] -= remove_prefixes_node; ++ // remove this node from both vectors ++ nodes_vect.erase(nodes_vect.begin()+i); ++ remove_prefixes_subtrees_vect.erase(remove_prefixes_subtrees_vect.begin()+i); ++ } else { ++ // the node has not been removed, thus increase the index ++ i++; ++ } ++ } ++ // if there are some nodes with prefixes that could be removed AND ++ // the number of prefixes to be removed is not negative ++ if ((all_prefixes[level] > 0) && (remove_prefixes[level] >= 0)) { ++ // initialize auxiliary constant (for this level) ++ float remove_all_ratio = (float)(remove_prefixes[level]) / ++ (float)(all_prefixes[level]); ++ // from all non-leaf nodes at this level ++ // remove prefixes that are to be removed at this level ++ for (int i = 0; i < (int) nodes_vect.size(); i++) { ++ int remove_prefixes_node = round((float)(nodes_vect[i]->prefixes) * ++ remove_all_ratio); ++ // do not remove more than all prefixes to be removed from this subtree ++ if (remove_prefixes_node > remove_prefixes_subtrees_vect[i]) { ++ remove_prefixes_node = remove_prefixes_subtrees_vect[i]; ++ } ++ // do not remove more than all prefixes of this node ++ if (remove_prefixes_node > nodes_vect[i]->prefixes) { ++ remove_prefixes_node = nodes_vect[i]->prefixes; ++ } ++ // remove the prefixes and adjust other variables ++ nodes_vect[i]->prefixes -= remove_prefixes_node; ++ all_prefixes[level] -= remove_prefixes_node; ++ remove_prefixes[level] -= remove_prefixes_node; ++ remove_prefixes_subtrees_vect[i] -= remove_prefixes_node; ++ } ++ } ++ // for all nodes at this level ++ // distribute prefixes to be removed in a subtree rooted at this node ++ // into node's subtrees ++ for (int i = 0; i < (int) nodes_vect.size(); i++) { ++ // distribution for 2-children nodes ++ if ((nodes_vect[i]->zero != NULL) && (nodes_vect[i]->one != NULL)) { ++ // determine the distribution ++ int total_weight = nodes_vect[i]->zero_weight + ++ nodes_vect[i]->one_weight; ++ int remove_prefixes_zero = round(((float)(nodes_vect[i]->zero_weight) / ++ (float)total_weight) * ++ (float)(remove_prefixes_subtrees_vect[i])); ++ int remove_prefixes_one = remove_prefixes_subtrees_vect[i] - ++ remove_prefixes_zero; ++ // do not remove more than all prefixes from zero subtree ++ if (remove_prefixes_zero > nodes_vect[i]->zero_weight) { ++ remove_prefixes_zero = nodes_vect[i]->zero_weight; ++ } ++ // do not remove more than all prefixes from one subtree ++ if (remove_prefixes_one > nodes_vect[i]->one_weight) { ++ remove_prefixes_one = nodes_vect[i]->one_weight; ++ } ++ // store the distribution into main queues ++ nodes.push(nodes_vect[i]->zero); ++ remove_prefixes_subtrees.push(remove_prefixes_zero); ++ nodes.push(nodes_vect[i]->one); ++ remove_prefixes_subtrees.push(remove_prefixes_one); ++ } else { ++ // distribution for 1-child nodes ++ if (nodes_vect[i]->zero != NULL) { ++ nodes.push(nodes_vect[i]->zero); ++ } else if (nodes_vect[i]->one != NULL) { ++ nodes.push(nodes_vect[i]->one); ++ } ++ remove_prefixes_subtrees.push(remove_prefixes_subtrees_vect[i]); ++ } ++ } ++ } ++ // remove the front elements from the main queues ++ nodes.pop(); ++ remove_prefixes_subtrees.pop(); ++ } ++ return; ++} // end adjust_prefixes() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++// Default constructor ++Trie::Trie() { ++ root = NULL; ++} // end Trie() ++ ++ ++// Copy constructor ++Trie::Trie(const Trie& orig) { ++ root = copy(orig.get_root(), 0); ++} // end Trie() ++ ++ ++// Destructor ++Trie::~Trie() { ++ destruct(root); ++} // end ~Trie() ++ ++ ++// Copy assignment ++Trie& Trie::operator= (const Trie& orig) { ++ // replace the original trie by a copy of the assigned trie ++ destruct(root); ++ root = copy(orig.get_root(), 0); ++ // return created object ++ return *this; ++} // end operator= () ++ ++ ++void Trie::insert(const IP_prefix& pref) { ++ // insert at least a root node when the trie is empty ++ if (root == NULL) { ++ root = new trie_node; ++ root->level = 0; ++ root->prefixes = 0; ++ root->prefix_nesting_branches = 0; ++ root->zero = NULL; ++ root->zero_weight = 0; ++ root->one = NULL; ++ root->one_weight = 0; ++ } ++ // insert the given prefix into the trie ++ if (pref.get_length() == 0) { // prefix of length 0 ++ (root->prefixes)++; ++ } else { // prefix of length > 0 ++ // auxiliary variables ++ trie_node* node = root; ++ trie_node** next_node_ptr; ++ string prefix = pref.get_prefix(); ++ // trie traversal ++ for (int i = 0; i < pref.get_length(); i++) { ++ // determine the next node and store the pointer to it ++ if (prefix[i] == '0') { ++ next_node_ptr = &(node->zero); ++ } else { // (prefix[i] == '1') ++ next_node_ptr = &(node->one); ++ } ++ // insert the next node if it does not exist ++ if ((*next_node_ptr) == NULL) { ++ (*next_node_ptr) = new trie_node; ++ (*next_node_ptr)->level = i+1; ++ (*next_node_ptr)->prefixes = 0; ++ (*next_node_ptr)->prefix_nesting_branches = 0; ++ (*next_node_ptr)->zero = NULL; ++ (*next_node_ptr)->zero_weight = 0; ++ (*next_node_ptr)->one = NULL; ++ (*next_node_ptr)->one_weight = 0; ++ } ++ // move to the next node; ++ node = (*next_node_ptr); ++ } ++ // prefix insertion ++ (node->prefixes)++; ++ } ++ return; ++} // end insert() ++ ++ ++bool Trie::erase(const IP_prefix& pref) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return root; ++ } ++ // search for the given prefix ++ if (pref.get_length() == 0) { // prefix of length 0 ++ if (root->prefixes > 0) { // we have found the prefix node ++ (root->prefixes)--; ++ if ((root->prefixes == 0) && ++ (root->zero == NULL) && ++ (root->one == NULL)) { ++ // all the conditions for removing the node were met ++ destruct(root); ++ root = NULL; ++ } ++ return true; ++ } else { // the corresponding node is a non-prefix node ++ return false; ++ } ++ } else { // prefix of length > 0 ++ // auxiliary variables ++ trie_node* node = root; ++ trie_node** destruct_root = &(root); ++ string prefix = pref.get_prefix(); ++ for (int i = 0; i < pref.get_length(); i++) { ++ // determine the next node ++ if (prefix[i] == '0') { ++ // adjust desctruct_root ++ if ((node->prefixes != 0) || ++ (node->one != NULL)) { // this node cannot be removed ++ destruct_root = &(node->zero); ++ } ++ // move to the next node ++ node = node->zero; ++ } else { // (prefix[i] == '1') ++ // adjust desctruct_root ++ if ((node->prefixes != 0) || ++ (node->zero != NULL)) { // this node cannot be removed ++ destruct_root = &(node->one); ++ } ++ // move to the next node ++ node = node->one; ++ } ++ // chceck whether the next node exists (terminate search if not) ++ if (node == NULL) { ++ return false; ++ } ++ } ++ if (node->prefixes > 0) { // we have found the prefix node ++ (node->prefixes)--; ++ if ((node->prefixes == 0) && ++ (node->zero == NULL) && ++ (node->one == NULL)) { ++ // all the conditions for removing the node were met ++ destruct(*destruct_root); ++ *destruct_root = NULL; ++ } ++ return true; ++ } else { // the corresponding node is a non-prefix node ++ return false; ++ } ++ } ++} // end erase() ++ ++ ++void Trie::prune(const int target_size, ++ const vector& prefixes, ++ const vector& one_child, ++ const vector& two_children, ++ const vector& skew, ++ const int iterations) { ++ // get original prefix set size ++ trie_stats s; ++ this->get_stats(s); ++ int orig_size = s.classbench.prefixes; ++ ++ // adjust branching (1st step of trie pruning) ++ this->adjust_branching(one_child, two_children); ++ ++ // iteratively adjust skew and prefixes proportion ++ // (multiple iterations help to reduce the negative effect of ++ // adjust_prefixes function on skew) ++ for (int i = 1; i <= iterations; i++) { ++ // adjust skew (2nd step of trie pruning) ++ this->adjust_skew(skew); ++ // adjust prefixes proportion (3rd step of trie pruning) ++ if (i == iterations) { ++ this->adjust_prefixes(prefixes, target_size); ++ } else { ++ this->adjust_prefixes(prefixes, round((1-(float)i/4)*orig_size)); ++ } ++ } ++} // end prune() ++ ++ ++void Trie::get_stats(trie_stats& stats) { ++ // initialize classbench statistics ++ stats.classbench.prefixes = 0; ++ stats.classbench.prefix_lengths = vector(129,0); ++ stats.classbench.branching_one_child = vector(129,0.0); ++ stats.classbench.branching_two_children = vector(129,0.0); ++ stats.classbench.skew = vector(129,0.0); ++ stats.classbench.prefix_nesting = 0; ++ // initialize nodes statistics ++ stats.nodes.leaf = vector(129,0); ++ stats.nodes.one_child = vector(129,0); ++ stats.nodes.two_children = vector(129,0); ++ stats.nodes.prefix = vector(129,0); ++ stats.nodes.non_prefix = vector(129,0); ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // compute zero_weight and one_weight in each node of the trie ++ compute_weights(root); ++ // initialize auxiliary variables ++ queue q; ++ q.push(root); ++ int level = root->level; ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // enqueue its possible successors ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // level change - finish statistics computation for the previous level ++ if (node->level != level) { ++ // auxiliary variables ++ int one_child = stats.nodes.one_child[level]; ++ int two_children = stats.nodes.two_children[level]; ++ int sum = one_child + two_children; ++ // branching_one_child and branching_two_children ++ if (sum != 0) { ++ stats.classbench.branching_one_child[level] = ++ (float)one_child / (float)sum; ++ stats.classbench.branching_two_children[level] = ++ (float)two_children / (float)sum; ++ } ++ // skew ++ if (two_children != 0) { ++ stats.classbench.skew[level] /= (float)two_children; ++ } ++ // increment the level counter ++ level++; ++ } ++ // trie node visit - classbench statistics ++ stats.classbench.prefixes += node->prefixes; ++ stats.classbench.prefix_lengths[level] += node->prefixes; ++ if ((node->zero != NULL) && (node->one != NULL)) { // skew is defined ++ stats.classbench.skew[level] += compute_skew(node); ++ } ++ // trie node visit - nodes statistics ++ if (node->zero == NULL) { ++ if (node->one == NULL) { // leaf node ++ (stats.nodes.leaf[level])++; ++ } else { // one child node ++ (stats.nodes.one_child[level])++; ++ } ++ } else { // node->zero != NULL ++ if (node->one != NULL) { // two child node ++ (stats.nodes.two_children[level])++; ++ } else { // one child node ++ (stats.nodes.one_child[level])++; ++ } ++ } ++ if (node->prefixes > 0) { // prefix node ++ (stats.nodes.prefix[level])++; ++ } else { // non-prefix node ++ (stats.nodes.non_prefix[level])++; ++ } ++ } // end of while (!q.empty()) ++ // finish statistics computation for the last level ++ // auxiliary variables ++ int one_child = stats.nodes.one_child[level]; ++ int two_children = stats.nodes.two_children[level]; ++ int sum = one_child + two_children; ++ // branching_one_child and branching_two_children ++ if (sum != 0) { ++ stats.classbench.branching_one_child[level] = ++ (float)one_child / (float)sum; ++ stats.classbench.branching_two_children[level] = ++ (float)two_children / (float)sum; ++ } ++ // skew ++ if (two_children != 0) { ++ stats.classbench.skew[level] /= (float)two_children; ++ } ++ // compute prefix nesting ++ stats.classbench.prefix_nesting = get_prefix_nesting(root); ++ return; ++} // end get_stats() +diff --git a/trie.h b/trie.h +new file mode 100644 +index 0000000..4cbe414 +--- /dev/null ++++ b/trie.h +@@ -0,0 +1,477 @@ ++// trie.h: header file for trie class ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef TRIE_H ++#define TRIE_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++/* ++ * Structure representing a node of a trie. ++ * ++ * Each node can be a prefix node (prefixes > 0) or a non-prefix node ++ * (prefixes = 0) and it can have at most two successors accessible using ++ * pointers zero (when the next bit of the prefix is 0) or one (when the next ++ * bit of the prefix is 1). ++ * Except these basic members, each trie node stores some other values that ++ * make the computation of trie characteristics easier. These values are ++ * further described directly in the trie node structure declaration. ++ */ ++ ++struct trie_node { ++ // trie level (i.e. distance from the root) at which the node resides ++ int level; ++ ++ // number of occurences of the prefix ++ int prefixes; ++ ++ // counter of branches with maximum prefix nesting that this node is part of ++ int prefix_nesting_branches; ++ ++ // 0-subtree-related members ++ trie_node* zero; // pointer to the subtree root ++ int zero_weight; // number of prefixes in the subtree ++ ++ // 1-subtree-related members ++ trie_node* one; // pointer to the subtree root ++ int one_weight; // number of prefixes in the subtree ++}; ++ ++/* ++ * Structure representing trie statistics proposed in the ClassBench tool. ++ * ++ * Vector members store statistics defined separately for each level of the ++ * trie. Prefix nesting is defined for the whole trie. ++ */ ++struct classbench_stats { ++ // total number of prefixes ++ int prefixes; ++ ++ // number of prefixes (not prefix nodes) with given length ++ vector prefix_lengths; ++ ++ // probability of node with only one child (from all non-leaf nodes) ++ vector branching_one_child; ++ // probability of node with two children (from all non-leaf nodes) ++ vector branching_two_children; ++ ++ // average relative weight ratio of lighter vs heavier subtree ++ // (nodes with two children only) ++ vector skew; ++ ++ // maximum number of prefix nodes on an arbitrary path in the trie ++ int prefix_nesting; ++}; ++ ++/* ++ * Structure representing statistics related to trie nodes. ++ * ++ * All the statistics are stored separately for each level of the trie. ++ */ ++struct node_stats { ++ vector leaf; // number of leaf nodes ++ vector one_child; // number of nodes with one child only ++ vector two_children; // number of nodes with both children ++ vector prefix; // number of prefix nodes (not prefixes) ++ vector non_prefix; // number of non-prefix nodes ++}; ++ ++/* ++ * Structure representing statistics related to the trie. ++ * ++ * Statistics are divided into two groups: ++ * 1) statistics proposed in ClassBench tool and ++ * 2) statistics related to trie nodes. ++ */ ++struct trie_stats { ++ classbench_stats classbench; // ClassBench statistics ++ node_stats nodes; // nodes statistics ++}; ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a binary prefix tree - trie. ++ * ++ * Class functions do not adjust zero_weight and one_weight counters in a trie ++ * node by default. These feilds are viewed as place holders and they can be ++ * set to the correct value by calling the compute_weights(). ++ */ ++class Trie { ++ private: ++ /* ++ * Pointer to the root node of the trie. ++ */ ++ trie_node* root; ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++// (MAYBE JUST ONE REASON -- BY COPYING ONLY A SUBTREE YOU LOOSE THE ++// INFORMATION ABOUT THE COMMON PREFIX, I.E. PATH IN TRIE PRECEDING THIS ++// SUBTREE) ++ /* ++ * Private static function for copying a subtree of the trie, where the ++ * subtree is specified by a pointer to its root node. ++ * Trie node members prefixes, zero_weight, and one_weight are copied ++ * without any change, while the level member is set to the given value. ++ * This approach allows e.g. to create a new valid trie by copying the ++ * given subtree. (In such a case the level parameter have to be set to ++ * 0 during the initial function call.) ++ * Trie node members zero and one are set to the values returned by the ++ * recursive call of the copy() onto the 0-subtree and 1-subtree, ++ * respectively. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of a subtree that is to be ++ * copied. ++ * @param level Value for the level member of the copied trie node. ++ * @return Pointer to the root node of the copy. ++ */ ++ static trie_node* copy(const trie_node* node, int level); ++ ++ /* ++ * Private static function for destruction of a trie's subtree. The ++ * subtree is given by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of a subtree that is to be ++ * destructed. ++ */ ++ static void destruct(trie_node* node); ++ ++ /* ++ * Private static function for computation of zero_weight and one_weight ++ * values of all the trie nodes in a given subtree. The subtree is given ++ * by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which the ++ * weights are to be computed. ++ * @return Weights of the given subtree. ++ */ ++ static int compute_weights(trie_node* node); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function for computation of node's skew as defined in ++ * the ClassBench paper. This function expects that the pointed node is ++ * a 2-children node and that its fields zero_weight and one_weight ++ * contain valid values. ++ * @param node Pointer to the node of which the skew is going to be ++ * computed. ++ * @return Skew of the given node. ++ */ ++ static float compute_skew(trie_node* node); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that determines the maximum prefix nesting in ++ * a given subtree, i.e. the maximum number of prefixes on any path from ++ * the root to the leaves in the subtree. The subtree is given by a ++ * pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which the ++ * prefix nesting is to be computed. ++ * @return Maximum prefix nesting in the given subtree. ++ */ ++ static int get_prefix_nesting(const trie_node* node); ++ ++ /* ++ * Private static function that removes the lightest subtree among trie ++ * nodes passed in a queue. The lightest subtree can be selected ++ * either among one-child nodes or two-children nodes. The selection is ++ * done in such a way that when the lightest subtree is removed, there ++ * is still at least one branch with maximum prefix nesting in the trie. ++ * After removing the lightest subtree, corresponding subtree weight is ++ * set to 0. ++ * @param q Queue with trie nodes that are to be ++ * inspected. ++ * @param one_child Select lightest subtree either among ++ * one-child nodes (TRUE) or ++ * two-children nodes (FALSE). ++ * @param prefix_nesting_branches The number of branches in the trie ++ * with maximum prefix nesting. ++ */ ++ static void remove_lightest_subtree(queue q, bool one_child, ++ int prefix_nesting_branches); ++ ++ /* ++ * Private static function for marking branches with maximum prefix ++ * nesting in a given subtree. The subtree is given by a pointer to its ++ * root node. Maximum prefix nesting is specified as a parameter of the ++ * function (therefore, it has to be computed outside the function). ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in ++ * which prefix nesting branches are to be ++ marked. ++ * @param prefix_nesting Maximum prefix nesting in the given subtree. ++ * @param seen_prefixes Number of prefixes that has been seen so far. ++ * @return Weights of the given subtree. ++ */ ++ static int mark_prefix_nesting_branches(trie_node* node, ++ int prefix_nesting, ++ int seen_prefixes); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function for computation of the maximum number of ++ * prefixes that can be removed from a given subtree. When computing the ++ * result of this function, the following contraints are taken into ++ * account: ++ * * no prefix node within the subtree must not become a non-prefix ++ * node after removing the prefixes; ++ * * removing the prefixes from subtrees of 2-children node should not ++ * alter the skew of this node. ++ * The subtree is given by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node A Pointer to the root node of the subtree in which the ++ number of removable prefixes is going to be computed. ++ * @return The number of removable prefixes in the given subtree. ++ */ ++ static int get_removable_prefixes(trie_node* node); ++ ++ /* ++ * Private static function for adjusting skew of a specified node to the ++ * given value. The node is specified by it's pointer and the target ++ * skew is given as a float number. ++ * @param node Pointer to the node whose skew is going to be ++ * adjusted. ++ * @param target_skew The value to which the node's skew should be ++ * adjusted. ++ */ ++ static void adjust_node_skew(trie_node* node, float target_skew); ++ ++ /* ++ * Private static function that removes the given number of prefixes from ++ * a subtree specified by the pointer to its root node. Prefixes are ++ * removed as equally as possible while following a rule that no prefix ++ * node can be turned to a non-prefix node. Removing of prefixes is ++ * performed over all prefix nodes from the root node up to the closest ++ * 2-children node or a leaf node... ++ * @param root Pointer to the root node of the subtree in which ++ * prefixes are going to be removed. ++ * @remove_prefixes The number of prefixes that should be removed from ++ * the specified subtree. ++ */ ++ static void make_subtree_lighter(trie_node* root, int remove_prefixes); ++ ++ /* ++ * Private static function for removing branches without a prefix node ++ * from a given subtree. The subtree is given by a pointer to its root ++ * node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which ++ * nonprefix are to be removed. ++ * @return actualized pointer to the subtree's root node ++ * (NULL when the whole subtree was removed) ++ */ ++ static trie_node* remove_nonprefix_branches(trie_node* node); ++ ++ /* ++ * Private function that removes some subtrees in order to achieve ++ * branching probabilities that are as close as possible to the given ++ * values. ++ * Modifications are done on a per level basis, starting from the root ++ * node. Changes at each level are done in two steps: ++ * 1) lightest subtrees of two-children nodes are removed to achieve ++ * given branching_two_children probability ++ * 2) lightest subtrees of one-child nodes are removed to achieve ++ * given branching_one_child probability ++ * @param branching_one_child Vector specifying probability of ++ * occurence of a trie node with one ++ * child at the given level of the trie. ++ * @param branching_two_children Vector specifying probability of ++ * occurence of a trie node with two ++ * children at the given level of the ++ * trie. ++ */ ++ void adjust_branching(vector branching_one_child, ++ vector branching_two_children); ++ ++ /* ++ * Private function that removes some prefixes in order to achieve an ++ * average skew that is as close as possible to the given values for ++ * particular levels. ++ * Prefixes are removed on a per level basis, starting from the lowest ++ * level. At each level, an average skew is increased/decreased by ++ * removing prefixes from lighter/heavier subtree of the level's nodes. ++ * This adjustment starts from nodes with the lightest subtrees ++ * (adjusting their skew requires removing of the lowest number of ++ * prefixes) and it is implemented such that it (almost) does not change ++ * a skew of nodes at lower levels. ++ * @param skew Vector specifying an average skew at all levels of ++ * the trie. ++ * @ skew_epsilon Threshold value for average skew change at not yet ++ * adjusted nodes (skew adjustment stops when average ++ * skew change is less than the given skew_epsilon). ++ */ ++ void adjust_skew(vector skew, float skew_epsilon = 0.01); ++ ++ /* ++ * Private function that removes some prefixes in order to achieve ++ * prefixes distribution that is as close as possible to the given values ++ * for particular levels. ++ * Prefixes are removed on a per level basis, starting from the root ++ * node. Removing the prefixes consists of three steps: ++ * 1) removing the prefixes from leaf nodes (the last prefix ++ * represented by a leaf node is never removed) ++ * 2) removing the prefixes from non-leaf nodes, proportionally to ++ * their weight ++ * 3) distributing prefixes that are to be removed at lower levels to ++ * subtrees of non-leaf nodes (this distribution is driven by skew) ++ * @param prefixes_proportion Vector that for all trie levels specifies ++ * proportion of prefixes at the given level ++ * to all prefixes in the trie. ++ * @param target_size Target total number of prefixes in the ++ * trie. ++ */ ++ void adjust_prefixes(vector prefixes_proportion, ++ const int target_size); ++ ++ public: ++ /* ++ * Default constructor. ++ * Pointer to the root node is initialized to NULL. ++ */ ++ Trie(); ++ ++ /* ++ * Copy constructor. ++ * Pointer to the root node is initialized by the result of the private ++ * copy(). ++ * @param orig Reference to the original trie object. ++ */ ++ Trie(const Trie& orig); ++ ++ /* ++ * Destructor. ++ * Trie specified by the root pointer is destructed by the private ++ * destruct(). ++ */ ++ ~Trie(); ++ ++ /* ++ * Copy assignment. ++ * Original trie is destructed by the private destruct() and the new trie ++ * is created by the private copy(). ++ * @param orig Reference to the original trie object. ++ * @return Reference to the new trie object. ++ */ ++ Trie& operator= (const Trie& orig); ++ ++ /* ++ * Get function for the root pointer. ++ * @return Pointer to the root node of the trie. ++ */ ++ inline const trie_node* get_root() const { ++ return root; ++ } // end get_root() ++ ++ /* ++ * Inserts the specified prefix into the trie. ++ * The trie is non-recursively traversed to the corresponding trie node, ++ * where the prefix is newly inserted or at least the counter of its ++ * occurences is incremented. ++ * All the missing nodes on a way to the prefix node are newly created ++ * and inserted into the trie as non-prefix nodes. ++ * @param pref Reference to the IP_prefix object representing the ++ * prefix that is to be inserted. ++ */ ++ void insert(const IP_prefix& pref); ++ ++ /* ++ * Erases the specified prefix from the trie. ++ * The prefix is searched by non-recursively traversing the trie. If the ++ * erase() finds the prefix, the counter of its occurences is decremented ++ * and return value is set to TRUE. ++ * If the erased prefix was the last one (i.e. prefix node has changed to ++ * non-prefix node) and there is not more specific prefix (i.e. prefix ++ * node is a leaf node of the trie), its corresponding node and all its ++ * non-prefix predecessors (up to the closest node with two children) are ++ * removed from the trie using private destruct(). ++ * If the erase() does not find the prefix, it silently ends without any ++ * further action and with return value set to FALSE. ++ * @param pref Reference to the IP_prefix object representing the ++ * prefix that is to be removed. ++ * @return TRUE if the prefix was removed, ++ * FALSE otherwise. ++ */ ++ bool erase(const IP_prefix& pref); ++ ++ /* ++ * Prunes the trie in order to achieve the given characteristics. ++ * The function first adjusts branching probability distributions at all ++ * trie levels. Next, average skew and prefix length distributions are ++ * adjusted while the number of prefixes in the trie is iteratively ++ * decreased towards the given target size. ++ * @param target_size Target number of prefixes in the trie. The ++ * final number of prefixes in the pruned trie can ++ * be slightly different. ++ * @param prefixes The vector of target prefix length distribution ++ * over the trie levels. ++ * @param one_child The vector of target one-child branching ++ * probability distribution over the trie levels. ++ * @param two_children The vector of target two-children branching ++ * probability distribution over the trie levels. ++ * @param skew The vector of target average skew distribution ++ * over the trie levels. ++ * @param iterations The number of iterations of average skew and ++ * prefix length distribution adjustment. ++ */ ++ void prune(const int target_size, ++ const vector& prefixes, ++ const vector& one_child, ++ const vector& two_children, ++ const vector& skew, ++ const int iterations = 4); ++ ++ /* ++ * Computes all defined trie statistics and stores them into a given ++ * structure. ++ * Except prefix nesting, which is computed during separate recursive ++ * traversal, all the other statistics are computed during single ++ * breadth-first search. Following statistics are actualized when ++ * visiting the nodes: ++ * * classbench.prefix_lengths ++ * * classbench.skew ++ * * nodes.leaf ++ * * nodes.one_child ++ * * nodes.two_children ++ * * nodes.prefix ++ * * nodes.non_prefix ++ * The value classbech.skew is also adjusted (divided by ++ * nodes.two_children) after visiting all the nodes at the current trie ++ * level. ++ * There are also two statistics (classbench.branching_one_child and ++ * classbench.branching_two_children) that are fully computed after ++ * visiting all the nodes at the current trie level. Their computation is ++ * based on values nodes.one_child and nodes.two_children. ++ * @param stats Reference to a data structure for computed trie ++ * statistics. ++ */ ++ void get_stats(trie_stats& stats); ++}; ++ ++#endif diff --git a/patches/improvements_ipv6.patch b/patches/improvements_ipv6.patch new file mode 100644 index 0000000..5a8f61f --- /dev/null +++ b/patches/improvements_ipv6.patch @@ -0,0 +1,11178 @@ +diff --git a/ExtraList.cc b/ExtraList.cc +index d09f0aa..4b309fe 100644 +--- a/ExtraList.cc ++++ b/ExtraList.cc +@@ -17,6 +17,7 @@ ExtraList::ExtraList(int P1) { + for (int i = 1; i <= P; i++){ + // Create header list + struct ExtraListHeader *temp = new struct ExtraListHeader; ++ temp->field = NULL; + temp->next = NULL; + temp->prev = last; + if (i == 1) { +@@ -39,11 +40,12 @@ ExtraList::~ExtraList() { + for (int j = 0; j < N; j++){ + tempI = temp->field[j]; + // Delete list of values +- delete(tempI->value); +- delete(tempI->prob); ++ delete[] (tempI->value); ++ delete[] (tempI->prob); ++ delete(tempI); + } + first = first->next; +- delete(temp->field); ++ delete[] (temp->field); + delete(temp); + } + } +diff --git a/FilterList.cc b/FilterList.cc +index c123529..4677276 100644 +--- a/FilterList.cc ++++ b/FilterList.cc +@@ -11,6 +11,9 @@ + + #include "stdinc.h" + #include "FilterList.h" ++#include ++ ++namespace ip = std::experimental::net::ip; + + FilterList::FilterList() { + first = last = NULL; +@@ -20,6 +23,9 @@ FilterList::FilterList() { + FilterList::~FilterList() { + struct FilterList_item *temp; + while (first != NULL) { ++ if (first->filt.num_ext_field > 0) { ++ delete[] (first->filt.ext_field); ++ } + temp = first->next; + delete(first); + first = temp; +@@ -57,7 +63,7 @@ struct FilterList_item* FilterList::operator()(int i) { + void FilterList::insert(struct FilterList_item *item, struct filter filt) { + struct FilterList_item *newitem; + newitem = new struct FilterList_item; +- newitem->filt = filt; ++ copy_filter(newitem->filt, filt); + newitem->prev = item->prev; + newitem->next = item; + if (first == item) first = newitem; +@@ -72,7 +78,7 @@ void FilterList::insert(struct FilterList_item *item, struct filter filt) { + void FilterList::operator&=(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->prev = last; + temp->next = NULL; + if (num == 0){ +@@ -110,7 +116,7 @@ void FilterList::operator=(FilterList* L) { + void FilterList::push(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->next = first; + temp->prev = NULL; + if (num == 0){ +@@ -125,35 +131,66 @@ void FilterList::push(struct filter filt) { + + // Print the contents of the FilterList. + void FilterList::print(FILE* fp) { +- int addr[4]; +- unsigned temp; ++ uint128_t temp; + struct FilterList_item *tempfilt; + + for (tempfilt = first; tempfilt != NULL; tempfilt = tempfilt->next){ + // Print new filter character + fprintf(fp,"@"); +- // Print source address +- addr[0] = addr[1] = addr[2] = addr[3] = 0; +- temp = 0; +- temp = tempfilt->filt.sa; +- addr[0] = (temp >> 24); +- addr[1] = ((temp << 8) >> 24); +- addr[2] = ((temp << 16) >> 24); +- addr[3] = ((temp << 24) >> 24); +- fprintf(fp, "%d.%d.%d.%d/%d\t", +- addr[0], addr[1], addr[2], addr[3], +- tempfilt->filt.sa_len); +- // Print destination address +- addr[0] = addr[1] = addr[2] = addr[3] = 0; +- temp = 0; +- temp = tempfilt->filt.da; +- addr[0] = (temp >> 24); +- addr[1] = ((temp << 8) >> 24); +- addr[2] = ((temp << 16) >> 24); +- addr[3] = ((temp << 24) >> 24); +- fprintf(fp, "%d.%d.%d.%d/%d\t", +- addr[0], addr[1], addr[2], addr[3], +- tempfilt->filt.da_len); ++ // Print source/destination addresses ++ if (ADDRLEN == 32) { // IPv4 ++ // Source address ++ temp = tempfilt->filt.sa >> 96; ++ ip::address_v4 src_addr(temp); ++ fprintf(fp, "%s/%d\t", src_addr.to_string().c_str(), (tempfilt->filt.sa_len < 32) ? tempfilt->filt.sa_len : 32); ++ // Destination address ++ temp = tempfilt->filt.da >> 96; ++ ip::address_v4 dst_addr(temp); ++ fprintf(fp, "%s/%d\t", dst_addr.to_string().c_str(), (tempfilt->filt.da_len < 32) ? tempfilt->filt.da_len : 32); ++ } else { // IPv6 ++ // Source address ++ temp = tempfilt->filt.sa; ++ const ip::address_v6::bytes_type src_temp_bytes_type( ++ (unsigned char) (temp.upper() >> 56), ++ (unsigned char) (temp.upper() >> 48), ++ (unsigned char) (temp.upper() >> 40), ++ (unsigned char) (temp.upper() >> 32), ++ (unsigned char) (temp.upper() >> 24), ++ (unsigned char) (temp.upper() >> 16), ++ (unsigned char) (temp.upper() >> 8), ++ (unsigned char) temp.upper(), ++ (unsigned char) (temp.lower() >> 56), ++ (unsigned char) (temp.lower() >> 48), ++ (unsigned char) (temp.lower() >> 40), ++ (unsigned char) (temp.lower() >> 32), ++ (unsigned char) (temp.lower() >> 24), ++ (unsigned char) (temp.lower() >> 16), ++ (unsigned char) (temp.lower() >> 8), ++ (unsigned char) temp.lower()); ++ ip::address_v6 src_addr(src_temp_bytes_type); ++ fprintf(fp, "%s/%d\t", src_addr.to_string().c_str(), tempfilt->filt.sa_len); ++ // Destination address ++ temp = tempfilt->filt.da; ++ const ip::address_v6::bytes_type dst_temp_bytes_type( ++ (unsigned char) (temp.upper() >> 56), ++ (unsigned char) (temp.upper() >> 48), ++ (unsigned char) (temp.upper() >> 40), ++ (unsigned char) (temp.upper() >> 32), ++ (unsigned char) (temp.upper() >> 24), ++ (unsigned char) (temp.upper() >> 16), ++ (unsigned char) (temp.upper() >> 8), ++ (unsigned char) temp.upper(), ++ (unsigned char) (temp.lower() >> 56), ++ (unsigned char) (temp.lower() >> 48), ++ (unsigned char) (temp.lower() >> 40), ++ (unsigned char) (temp.lower() >> 32), ++ (unsigned char) (temp.lower() >> 24), ++ (unsigned char) (temp.lower() >> 16), ++ (unsigned char) (temp.lower() >> 8), ++ (unsigned char) temp.lower()); ++ ip::address_v6 dst_addr(dst_temp_bytes_type); ++ fprintf(fp, "%s/%d\t", dst_addr.to_string().c_str(), tempfilt->filt.da_len); ++ } + // Print source port + fprintf(fp, "%d : %d\t", + tempfilt->filt.sp[0], tempfilt->filt.sp[1]); +diff --git a/FlagList.cc b/FlagList.cc +index 074c4e7..9a214cf 100644 +--- a/FlagList.cc ++++ b/FlagList.cc +@@ -27,8 +27,8 @@ FlagList::~FlagList() { + first[i] = temp; + } + } +- delete(first); +- delete(last); ++ delete[] (first); ++ delete[] (last); + } + + void FlagList::choose(float p, int prot, unsigned *flags, unsigned *flags_mask){ +diff --git a/PortList.cc b/PortList.cc +index 34ad3c2..4b26d15 100644 +--- a/PortList.cc ++++ b/PortList.cc +@@ -22,7 +22,7 @@ PortList::PortList(int N1) { + } + } + +-PortList::~PortList() { delete ports; } ++PortList::~PortList() { delete[] ports; } + + void PortList::read(int t, FILE *fp) { + int done = 0; +diff --git a/PrefixList.cc b/PrefixList.cc +index a3df1dc..c3e23e5 100644 +--- a/PrefixList.cc ++++ b/PrefixList.cc +@@ -11,21 +11,21 @@ + #include "PrefixList.h" + + PrefixList::PrefixList() { +- N = 65; ++ N = 257; + cdist = 0; + prefixes = new struct prefix*[25]; + for (int type = 0; type < 25; type++){ + prefixes[type] = new struct prefix[N]; + for (int i = 0; i < N; i++) { + prefixes[type][i].prob = 0; +- for (int j = 0; j < 33; j++) prefixes[type][i].sprob[j] = 0; ++ for (int j = 0; j < 129; j++) prefixes[type][i].sprob[j] = 0; + } + } + } + + PrefixList::~PrefixList() { +- for (int type = 0; type < 25; type++) delete prefixes[type]; +- delete prefixes; ++ for (int type = 0; type < 25; type++) delete[] prefixes[type]; ++ delete[] prefixes; + } + + void PrefixList::read(FILE* fp){ +@@ -102,14 +102,14 @@ void PrefixList::read_type(int type, FILE *fp) { + int tlen = 0; + int slen = 0; + float prob = 0; +- int lens[34]; +- float probs[34]; +- char scomm[500]; +- int scomm_len = 500; ++ int lens[130]; ++ float probs[130]; ++ char scomm[2000]; ++ int scomm_len = 2000; + while (done == 0) { + fgets(scomm,scomm_len,fp); + // Read a line of the input +- matches = sscanf(scomm,"%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f",&lens[0],&probs[0],&lens[1],&probs[1],&lens[2],&probs[2],&lens[3],&probs[3],&lens[4],&probs[4],&lens[5],&probs[5],&lens[6],&probs[6],&lens[7],&probs[7],&lens[8],&probs[8],&lens[9],&probs[9],&lens[10],&probs[10],&lens[11],&probs[11],&lens[12],&probs[12],&lens[13],&probs[13],&lens[14],&probs[14],&lens[15],&probs[15],&lens[16],&probs[16],&lens[17],&probs[17],&lens[18],&probs[18],&lens[19],&probs[19],&lens[20],&probs[20],&lens[21],&probs[21],&lens[22],&probs[22],&lens[23],&probs[23],&lens[24],&probs[24],&lens[25],&probs[25],&lens[26],&probs[26],&lens[27],&probs[27],&lens[28],&probs[28],&lens[29],&probs[29],&lens[30],&probs[30],&lens[31],&probs[31],&lens[32],&probs[32],&lens[33],&probs[33]); ++ matches = sscanf(scomm,"%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f",&lens[0],&probs[0],&lens[1],&probs[1],&lens[2],&probs[2],&lens[3],&probs[3],&lens[4],&probs[4],&lens[5],&probs[5],&lens[6],&probs[6],&lens[7],&probs[7],&lens[8],&probs[8],&lens[9],&probs[9],&lens[10],&probs[10],&lens[11],&probs[11],&lens[12],&probs[12],&lens[13],&probs[13],&lens[14],&probs[14],&lens[15],&probs[15],&lens[16],&probs[16],&lens[17],&probs[17],&lens[18],&probs[18],&lens[19],&probs[19],&lens[20],&probs[20],&lens[21],&probs[21],&lens[22],&probs[22],&lens[23],&probs[23],&lens[24],&probs[24],&lens[25],&probs[25],&lens[26],&probs[26],&lens[27],&probs[27],&lens[28],&probs[28],&lens[29],&probs[29],&lens[30],&probs[30],&lens[31],&probs[31],&lens[32],&probs[32],&lens[33],&probs[33],&lens[34],&probs[34],&lens[35],&probs[35],&lens[36],&probs[36],&lens[37],&probs[37],&lens[38],&probs[38],&lens[39],&probs[39],&lens[40],&probs[40],&lens[41],&probs[41],&lens[42],&probs[42],&lens[43],&probs[43],&lens[44],&probs[44],&lens[45],&probs[45],&lens[46],&probs[46],&lens[47],&probs[47],&lens[48],&probs[48],&lens[49],&probs[49],&lens[50],&probs[50],&lens[51],&probs[51],&lens[52],&probs[52],&lens[53],&probs[53],&lens[54],&probs[54],&lens[55],&probs[55],&lens[56],&probs[56],&lens[57],&probs[57],&lens[58],&probs[58],&lens[59],&probs[59],&lens[60],&probs[60],&lens[61],&probs[61],&lens[62],&probs[62],&lens[63],&probs[63],&lens[64],&probs[64],&lens[65],&probs[65],&lens[66],&probs[66],&lens[67],&probs[67],&lens[68],&probs[68],&lens[69],&probs[69],&lens[70],&probs[70],&lens[71],&probs[71],&lens[72],&probs[72],&lens[73],&probs[73],&lens[74],&probs[74],&lens[75],&probs[75],&lens[76],&probs[76],&lens[77],&probs[77],&lens[78],&probs[78],&lens[79],&probs[79],&lens[80],&probs[80],&lens[81],&probs[81],&lens[82],&probs[82],&lens[83],&probs[83],&lens[84],&probs[84],&lens[85],&probs[85],&lens[86],&probs[86],&lens[87],&probs[87],&lens[88],&probs[88],&lens[89],&probs[89],&lens[90],&probs[90],&lens[91],&probs[91],&lens[92],&probs[92],&lens[93],&probs[93],&lens[94],&probs[94],&lens[95],&probs[95],&lens[96],&probs[96],&lens[97],&probs[97],&lens[98],&probs[98],&lens[99],&probs[99],&lens[100],&probs[100],&lens[101],&probs[101],&lens[102],&probs[102],&lens[103],&probs[103],&lens[104],&probs[104],&lens[105],&probs[105],&lens[106],&probs[106],&lens[107],&probs[107],&lens[108],&probs[108],&lens[109],&probs[109],&lens[110],&probs[110],&lens[111],&probs[111],&lens[112],&probs[112],&lens[113],&probs[113],&lens[114],&probs[114],&lens[115],&probs[115],&lens[116],&probs[116],&lens[117],&probs[117],&lens[118],&probs[118],&lens[119],&probs[119],&lens[120],&probs[120],&lens[121],&probs[121],&lens[122],&probs[122],&lens[123],&probs[123],&lens[124],&probs[124],&lens[125],&probs[125],&lens[126],&probs[126],&lens[127],&probs[127],&lens[128],&probs[128],&lens[129],&probs[129]); + // printf("matches = %d, tlen = %d, prob = %.4f\n",matches,lens[0],probs[0]); + if (matches >= 4) { + // Assign total probability +@@ -155,16 +155,16 @@ void PrefixList::smooth_type(int type, int s){ + double tp[129]; + double sp[129]; + double spj[129]; +- struct prefix temps[65]; ++ struct prefix temps[N]; + int tlen, slen; + int r, start, end; + int delta; + + // printf("this = 0x%08x\n",this); + +- for (int i=0; i<65; i++) { ++ for (int i=0; i 64){ ++ if (tlen < 0 || tlen > 256){ + printf("Error 1 : tlen is out of range, tlen = %d\n",tlen); + exit(1); + } +@@ -208,7 +208,7 @@ void PrefixList::smooth_type(int type, int s){ + // Spread spike in source distribution for total distribution i + skj = ((int)floor((double)s/(double)2)) * 2; + binomial(skj,spj); +- for (int j = 0; j <= 32; j++){ ++ for (int j = 0; j <= 128; j++){ + // j = source length + // Find source spike + if (prefixes[type][i].sprob[j] > 0){ +@@ -221,9 +221,9 @@ void PrefixList::smooth_type(int type, int s){ + slen = j - skj/2; bdist = 0; + } + // printf("slen = %d, bdist = %d\n",slen,bdist); +- while (slen <= 32 && bdist <= skj) { ++ while (slen <= 128 && bdist <= skj) { + +- if (i < 0 || i > 64 || slen < 0 || slen > 32){ ++ if (i < 0 || i > 256 || slen < 0 || slen > 128){ + printf("Error 2: i or slen is out of range, i = %d, slen = %d\n",i,slen); + exit(1); + } +@@ -242,7 +242,7 @@ void PrefixList::smooth_type(int type, int s){ + for (int m = 1; m <= s; m++) { + // compute total length point + r = i - m; +- if (0 <= r && r <= 64) { ++ if (0 <= r && r <= 256) { + // set start, end points for source distribution + start = j - m; + end = j; +@@ -268,9 +268,9 @@ void PrefixList::smooth_type(int type, int s){ + bdist = 0; + } + // printf("start = %d, bdist = %d\n",start,bdist); +- while (start <= 32 && bdist <= sk) { ++ while (start <= 128 && bdist <= sk) { + +- if (r < 0 || r > 64 || start < 0 || start > 32){ ++ if (r < 0 || r > 256 || start < 0 || start > 128){ + printf("Error 3: r or start is out of range, r = %d, start = %d\n",r,start); + exit(1); + } +@@ -290,7 +290,7 @@ void PrefixList::smooth_type(int type, int s){ + for (int m = 1; m <= s; m++) { + // compute total length point + r = i + m; +- if (0 <= r && r <= 64) { ++ if (0 <= r && r <= 256) { + // set start, end points for source distribution + start = j; + end = j + m; +@@ -315,9 +315,9 @@ void PrefixList::smooth_type(int type, int s){ + bdist = 0; + } + // printf("start = %d, bdist = %d\n",start,bdist); +- while (start <= 32 && bdist <= sk) { ++ while (start <= 128 && bdist <= sk) { + +- if (r < 0 || r > 64 || start < 0 || start > 32){ ++ if (r < 0 || r > 256 || start < 0 || start > 128){ + printf("Error 4: r or start is out of range, start = %d, q = %d\n",r,start); + exit(1); + } +@@ -345,25 +345,25 @@ void PrefixList::smooth_type(int type, int s){ + temps[i].prob = temps[i].prob / totw; + if (temps[i].prob > 0) { + // Truncate source distribution +- if (i < 32) { +- for (int j = i + 1; j <= 32; j++) temps[i].sprob[j] = 0; ++ if (i < 128) { ++ for (int j = i + 1; j <= 128; j++) temps[i].sprob[j] = 0; + } +- else if (i > 32) { +- for (int j = 0; j < i - 32; j++) temps[i].sprob[j] = 0; ++ else if (i > 128) { ++ for (int j = 0; j < i - 128; j++) temps[i].sprob[j] = 0; + } + // Normalize source distribution + tots = 0; +- for (int j = 0; j <= 32; j++) tots += temps[i].sprob[j]; +- for (int j = 0; j <= 32; j++) temps[i].sprob[j] = temps[i].sprob[j] / tots; ++ for (int j = 0; j <= 128; j++) tots += temps[i].sprob[j]; ++ for (int j = 0; j <= 128; j++) temps[i].sprob[j] = temps[i].sprob[j] / tots; + } + } + // Apply adjustments to prefixes data structure + for (int i = 0; i < N; i++) { + prefixes[type][i].prob = temps[i].prob; + if (i == N-1) prefixes[type][i].prob = 1; +- for (int j = 0; j < 33; j++) { ++ for (int j = 0; j < 129; j++) { + prefixes[type][i].sprob[j] = temps[i].sprob[j]; +- if (j == 32) prefixes[type][i].sprob[j] = 1; ++ if (j == 128) prefixes[type][i].sprob[j] = 1; + } + } + } +@@ -382,7 +382,7 @@ struct ppair PrefixList::choose_prefix(int type, float rs, float rt) { + for (int i = 0; (i < N && done == 0); i++) { + // printf("rt = %.6f, prefixes[type][%d].prob = %.6f\n",rt,i,prefixes[type][i].prob); + if (rt <= prefixes[type][i].prob) { +- for (int j = 0; (j < 33 && done == 0); j++) { ++ for (int j = 0; (j < 129 && done == 0); j++) { + // printf("rs = %.6f, prefixes[type][%d].sprob[%d] = %.6f\n",rs,i,j,prefixes[type][i].sprob[j]); + if (rs <= prefixes[type][i].sprob[j]){ + pair.slen = j; +@@ -407,7 +407,7 @@ void PrefixList::build_cdist() { + tp = prefixes[type][i].prob; + // Cummulative source distribution + sp = 0; +- for (int j = 0; j < 33; j++){ ++ for (int j = 0; j < 129; j++){ + prefixes[type][i].sprob[j] += sp; + sp = prefixes[type][i].sprob[j]; + } +@@ -421,7 +421,7 @@ void PrefixList::print(int type, FILE *fp) { + for (int i = 0; i < N; i++){ + if (prefixes[type][i].prob != 0) { + fprintf(fp,"%d,%.8f",i,prefixes[type][i].prob); +- for (int j = 0; j <= 32; j++) { ++ for (int j = 0; j <= 128; j++) { + if (prefixes[type][i].sprob[j] != 0) { + fprintf(fp,"\t%d,%.8f",j,prefixes[type][i].sprob[j]); + } +diff --git a/PrefixList.h b/PrefixList.h +index 2d39529..1df63a2 100644 +--- a/PrefixList.h ++++ b/PrefixList.h +@@ -15,7 +15,7 @@ + + struct prefix { + float prob; +- float sprob[33]; ++ float sprob[129]; + }; + + class PrefixList { +diff --git a/ProtList.cc b/ProtList.cc +index a4bc451..b9bd739 100644 +--- a/ProtList.cc ++++ b/ProtList.cc +@@ -24,8 +24,8 @@ ProtList::ProtList() { + } + + ProtList::~ProtList() { +- for (int i = 0; i < 25; i++) delete protocols[i].pt_prob; +- delete protocols; ++ for (int i = 0; i < 25; i++) delete[] protocols[i].pt_prob; ++ delete[] protocols; + } + + void ProtList::read(FILE *fp) { +diff --git a/README b/README +index 116aac2..f104e85 100644 +--- a/README ++++ b/README +@@ -75,17 +75,17 @@ PPC + 10 AR/WC source port arbitrary range, destination port wildcard + 11 HI/AR source port [1024:65535], destination port arbitrary range + 12 AR/HI source port arbitrary range, destination port [1024:65535] +-13 LO/AR source port [0:1023], destination port arbitrary range +-14 AR/LO source port arbitrary range, destination port [0:1023] +-15 AR/AR source port arbitrary range, destination port arbitrary range +-16 WC/EM source port wildcard, destination port exact match +-17 EM/WC source port exact match, destination port wildcard +-18 HI/EM source port [1024:65535], destination port exact match +-19 EM/HI source port exact match, destination port [1024:65535] +-20 LO/EM source port [0:1023], destination port exact match +-21 EM/LO source port exact match, destination port [0:1023] ++13 WC/EM source port wildcard, destination port exact match ++14 EM/WC source port exact match, destination port wildcard ++15 HI/EM source port [1024:65535], destination port exact match ++16 EM/HI source port exact match, destination port [1024:65535] ++17 LO/AR source port [0:1023], destination port arbitrary range ++18 AR/LO source port arbitraty range, destination port [0:1023] ++19 LO/EM source port [0:1023], destination port exact match ++20 EM/LO source port exact match, destination port [0:1023] ++21 AR/AR source port arbitraty range, destination port arbitrary range + 22 AR/EM source port arbitrary range, destination port exact match +-23 EM/AR source port exact match, destination port exact match arbitrary range ++23 EM/AR source port exact match, destination port arbitrary range + 24 EM/EM source port exact match, destination port exact match + + -flags +diff --git a/TupleBST.cc b/TupleBST.cc +index 9163d9b..911f1d5 100644 +--- a/TupleBST.cc ++++ b/TupleBST.cc +@@ -17,7 +17,7 @@ TupleBST::TupleBST() { + + TupleBST::~TupleBST() { + if (root != NULL) cleanup(root); +- delete(ListOfFilterIndexPtrs); ++ delete[] (ListOfFilterIndexPtrs); + } + + void TupleBST::cleanup(TupleBST_item* node){ +@@ -34,7 +34,7 @@ void TupleBST::cleanup(TupleBST_item* node){ + + int TupleBST::scope(FiveTuple* ftuple){ + double scope5d; +- scope5d = (32 - ftuple->sa_len) + (32 - ftuple->da_len) + (log(ftuple->sp_wid)/log(2)) + (log(ftuple->dp_wid)/log(2)) + (8*(1 - ftuple->prot)) + (1 - ftuple->flag); ++ scope5d = (128 - ftuple->sa_len) + (128 - ftuple->da_len) + (log(ftuple->sp_wid)/log(2)) + (log(ftuple->dp_wid)/log(2)) + (8*(1 - ftuple->prot)) + (1 - ftuple->flag); + return (int)scope5d; + } + +diff --git a/custom_db.cc b/custom_db.cc +index 6f8d193..7515336 100644 +--- a/custom_db.cc ++++ b/custom_db.cc +@@ -20,15 +20,61 @@ + #include "redundant_filter_check.h" + #include "TupleBST.h" + #include "custom_db.h" ++#include ++#include "ip_prefix.h" ++#include "trie.h" ++#include "filter_graph.h" ++ ++namespace ip = std::experimental::net::ip; ++ ++ ++/* ++ * Transforms a pruned source/destination trie into a set of edges from/to the ++ * 's'/'t' node in the filter graph. ++ * The given trie is recursively traversed. When the traversed node is a prefix ++ * node, adding of the corresponding edge from/to the 's'/'t' node of the ++ * filter graph is triggered. Weight of the added edge is set according to the ++ * number of prefixes represented by the current prefix node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node A pointer to the current trie node. ++ * @param src_trie The trie node referenced by parameter node belongs to ++ * the source trie (TRUE) or the destination trie (FALSE). ++ * @param prefix_str The prefix represented by the current node encoded as a ++ * string of bit values. ++ * @param graph A pointer to the filter graph object. ++ */ ++void trie_to_graph(const trie_node* node, bool src_trie, string prefix_str, Filter_graph* graph) { ++ if (node != NULL) { // non-empty subtree ++ int prefix_count = node->prefixes; ++ if (prefix_count > 0) { // prefix node ++ // add current prefix to the filter graph, either as "s_prefix" or as "t_prefix" ++ IP_prefix prefix(prefix_str, true); ++ if (src_trie) { ++ graph->add_s_prefix(prefix, prefix_count); ++ } else { ++ graph->add_t_prefix(prefix, prefix_count); ++ } ++ } ++ // call this function on both zero and one subtrees ++ trie_to_graph(node->zero, src_trie, prefix_str + "0", graph); ++ trie_to_graph(node->one, src_trie, prefix_str + "1", graph); ++ } else { // empty subtree ++ return; ++ } ++} // end trie_to_graph() + + + int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothness, float addr_scope, float port_scope, int branch){ + ++ // generate 100 times more filters (because of successive trie pruning) ++ int temp_num_filters = num_filters * 100; ++ + printf("Initializing data structures...\n"); + // Read in scale + int scale = read_scale(fp_in); + // printf("scale = %d\n",scale); +- float scale_factor = (float)num_filters/(float)scale; ++ float scale_factor = (float)temp_num_filters/(float)scale; + // printf("scale_factor = %.4f\n",scale); + + // Read protocol parameters, initialize data structure +@@ -80,7 +126,10 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + + // Temporary filter + // struct filter temp_filter; +- struct filter *temp_filters = new struct filter[num_filters+1]; ++ struct filter *temp_filters = new struct filter[temp_num_filters+1]; ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ temp_filters[i].num_ext_field = 0; ++ } + dlist *Flist = new dlist; + struct range temp_range; + struct ppair temp_ppair; +@@ -89,7 +138,7 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + printf("Creating application specifications...\n"); + + // For all filters: +- for (int i = 1; i <= num_filters; i++){ ++ for (int i = 1; i <= temp_num_filters; i++){ + // Select a protocol via random number + p = drand48(); + temp_filters[i].prot_num = protL->choose_prot((float)p); +@@ -143,6 +192,8 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + printf(" \tdone\n"); + // Free up memory + delete(protL); ++ delete(flagL); ++ delete(extraL); + delete(sparL); + delete(spemL); + delete(dparL); +@@ -180,10 +231,9 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + } + // printf("Flist = "); (*Flist).print(stdout); printf("\n"); + (*Stree).build_tree(Flist,temp_filters); +- delete(Stree); + /* + printf("Flist = "); (*Flist).print(stdout); printf("\n"); +- for (int i = 1; i <= num_filters; i++) ++ for (int i = 1; i <= temp_num_filters; i++) + printf("filter[%d].sa = %u/%d\n",i,temp_filters[i].sa,temp_filters[i].sa_len); + */ + printf(" \tdone\n"); +@@ -203,13 +253,245 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + + (*Dtree).build_tree(Flist,temp_filters); + // printf("Flist = "); (*Flist).print(stdout); printf("\n"); +- delete(Dtree); + printf(" \tdone\n"); + + delete(Flist); + ++ ++// **************************************************************************** ++// START of IMPROVEMENTS implemented in ClassBench-ng ++// **************************************************************************** ++ ++ // transform filter set into filter graph and insert source/destination ++ // prefixes of filters into corresponding tries ++ Filter_graph graph; ++ Trie src_trie; ++ Trie dst_trie; ++ for (int i = 1; i <= temp_num_filters; i++) { ++ graph.add_filter(&(temp_filters[i])); ++ src_trie.insert(IP_prefix(temp_filters[i].sa, temp_filters[i].sa_len)); ++ dst_trie.insert(IP_prefix(temp_filters[i].da, temp_filters[i].da_len)); ++ } ++ ++ // get statistics of source and destination tries ++ trie_stats src_trie_stats, dst_trie_stats; ++ src_trie.get_stats(src_trie_stats); ++ dst_trie.get_stats(dst_trie_stats); ++ ++ // initialize data structures for trie-related distributions ++ vector src_prefixes(129,0); ++ vector src_one_child(129,0); ++ vector src_two_children(129,0); ++ vector src_skew(129,0); ++ vector dst_prefixes(129,0); ++ vector dst_one_child(129,0); ++ vector dst_two_children(129,0); ++ vector dst_skew(129,0); ++ ++ // get source and destination prefix length distributions ++ // Use prefix length distributions from already generated source and ++ // destination prefix sets as ClassBench-generated rule sets follow them ++ // quite precisely. ++ for (int i = 0; i < 129; i++) { ++ src_prefixes[i] = (float)src_trie_stats.classbench.prefix_lengths[i] / ++ (float)src_trie_stats.classbench.prefixes; ++ dst_prefixes[i] = (float)dst_trie_stats.classbench.prefix_lengths[i] / ++ (float)dst_trie_stats.classbench.prefixes; ++ } ++ ++ // get other src distributions ++ // Copy the values that were already read from the parameter file into Stree. ++ for (int i = 0; i < 129; i++) { ++ src_one_child[i] = Stree->get_p1child()[i]; ++ src_two_children[i] = Stree->get_p2child()[i]; ++ src_skew[i] = Stree->get_skew()[i]; ++ } ++ delete(Stree); ++ ++ // get other dst distributions ++ // Copy the values that were already read from the parameter file into Dtree. ++ for (int i = 0; i < 129; i++) { ++ dst_one_child[i] = Dtree->get_p1child()[i]; ++ dst_two_children[i] = Dtree->get_p2child()[i]; ++ dst_skew[i] = Dtree->get_skew()[i]; ++ } ++ delete(Dtree); ++ ++ // prune source and destination tries to 1/100 of the original prefix sets ++ src_trie.prune(num_filters, src_prefixes, src_one_child, ++ src_two_children, src_skew); ++ dst_trie.prune(num_filters, dst_prefixes, dst_one_child, ++ dst_two_children, dst_skew); ++ ++ // extend filter graph according to pruned tries ++ trie_to_graph(src_trie.get_root(), true, "", &graph); ++ trie_to_graph(dst_trie.get_root(), false, "", &graph); ++ ++ // modify the filter graph to conform with the flow network specification ++ graph.to_flow_network(); ++ ++ // compute maximum flow for the current flow network ++ int max_flow = graph.max_flow(); ++ ++ // auxiliary variables for construction of the set of pruned filters ++ struct filter* pruned_filters = new struct filter[temp_num_filters+1]; ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ pruned_filters[i].num_ext_field = 0; ++ } ++ int pruned_filters_i = 1; ++ ++ /* ++ * 1st phase of construction of the set of pruned filters ++ */ ++ // iterate over all filters ++ const node_list_item* node; ++ node = graph.get_src_nodes(); ++ while (node != NULL) { ++ neighbour_list_item* neighbour = node->neighbours; ++ while (neighbour != NULL) { ++ filter_list_item* filter = neighbour->filters; ++ for (int i = 0; i < neighbour->flow; i++) { ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ // copy filters from the maximum flow to the pruned_filters array ++ copy_filter(pruned_filters[pruned_filters_i], *(filter->filter)); ++ pruned_filters_i++; ++ filter = filter->next; ++ } ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ neighbour = neighbour->next; ++ } ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ node = node->next; ++ } ++ ++ /* ++ * 2nd phase of construction of the set of pruned filters ++ */ ++ // auxiliary variables for looking for not fully utilized source prefixes ++ neighbour_list_item* s_neighbour = (graph.get_s_node() != NULL) ? ++ graph.get_s_node()->neighbours : NULL; ++ // iterate over all destination prefixes ++ node = graph.get_dst_nodes(); ++ while (node != NULL) { ++ neighbour_list_item* neighbour = node->neighbours; ++ if (neighbour != NULL) { ++ int free_weight = neighbour->weight - neighbour->flow; ++ // auxiliary variables for looking for not fully utilized filters with ++ // current destination prefix ++ const node_list_item* src_node = graph.get_src_nodes(); ++ neighbour_list_item* src_neighbour; ++ filter_list_item* src_filter; ++ int src_filter_index = 0; ++ // for each not fully utilized destination prefix ++ for (int i = 0; i < free_weight; i++) { ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ ++// FILTERS start -------------------------------------------------------------- ++ ++ // iterate over all filters with current destination prefix ++ while (src_node != NULL) { ++ src_neighbour = src_node->neighbours; ++ while (src_neighbour != NULL) { ++ if (src_neighbour->node->prefix == node->prefix) { ++ src_filter = src_neighbour->filters; ++ // skip over all filters from the maximum flow ++ for (; ++ src_filter_index < src_neighbour->flow; ++ src_filter_index++) { ++ src_filter = src_filter->next; ++ } ++ if (src_filter != NULL) {// this filter is not fully ++ // utilized ++ ++// SOURCE PREFIXES start ------------------------------------------------------ ++ ++ // find the first not fully utilized source prefix ++ while (s_neighbour != NULL) { ++ // if this source prefix is not fully utilized ++ if (s_neighbour->flow < s_neighbour->weight) { ++ // create local copy of the selected filter and ++ // modify its source prefix ++ struct filter pruned_filter; ++ copy_filter(pruned_filter, *(src_filter->filter)); ++ pruned_filter.sa = ++ s_neighbour->node->prefix.get_prefix_uint128_t(); ++ pruned_filter.sa_len = ++ s_neighbour->node->prefix.get_length(); ++ // inset the filter into the pruned_filters array ++ pruned_filters[pruned_filters_i++] = ++ pruned_filter; ++ // increment flow value through used edges ++ s_neighbour->flow++; ++ src_neighbour->flow++; ++ neighbour->flow++; ++ // terminate looking for the next not fully ++ // utilized source prefix ++ break; ++ } ++ s_neighbour = s_neighbour->next; ++ } ++ // always terminate looking for not fully utilized ++ // filters because of the following reasons: ++ // * if not fully utilized source prefix was found, ++ // move to the next not fully utilized destination ++ // prefix ++ // * if not fully utilized source prefix was not ++ // found, terminate inserting filters into the ++ // pruned_filters array at all ++ break; ++ ++// SOURCE PREFIES end --------------------------------------------------------- ++ ++ } else { // this filter is fully utilized ++ src_filter_index = 0; ++ } ++ } ++ src_neighbour = src_neighbour->next; ++ } ++ // if the previous cycle was broken, break also this cycle ++ // (because of the same reasons) ++ if (src_neighbour != NULL) { ++ break; ++ } ++ src_node = src_node->next; ++ } ++ // if either all filters or prefixes are fully utilized, terminate ++ // looking for not fully utilized filters ++ if ((src_node == NULL) || (s_neighbour == NULL)) { ++ break; ++ } ++ ++// FILTERS end ---------------------------------------------------------------- ++ ++ } ++ } ++ // if all source prefixes are fully utilized or enough filters have been ++ // selected, terminate looking for not fully utilized destination prefixes ++ if ((s_neighbour == NULL) || (pruned_filters_i == num_filters+1)) { ++ break; ++ } ++ node = node->next; ++ } ++ ++// **************************************************************************** ++// END of IMPROVEMENTS implemented in ClassBench-ng ++// **************************************************************************** ++ ++ + printf("Removing redundant filters and ordering nested filters...\n"); +- int filter_cnt = remove_redundant_filters(num_filters,filters,temp_filters); ++ int filter_cnt = remove_redundant_filters(pruned_filters_i-1,filters,pruned_filters); + printf(" \tdone\n"); + + // Resolve conflicts, throw away filters if necessary +@@ -219,7 +501,16 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + // printf(" \tdone\n"); + + // Delete data structures +- delete(temp_filters); ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ if (temp_filters[i].num_ext_field > 0) { ++ delete[] (temp_filters[i].ext_field); ++ } ++ if (pruned_filters[i].num_ext_field > 0) { ++ delete[] (pruned_filters[i].ext_field); ++ } ++ } ++ delete[] (temp_filters); ++ delete[] (pruned_filters); + // printf("Done with custom_db\n"); + + return filter_cnt; +@@ -464,33 +755,64 @@ void select_ports(int port_type, struct filter *temp_filter, PortList *sparL, Po + } + + void fprint_filter(FILE *fp, struct filter *filt){ +- int addr[4]; +- unsigned temp; ++ uint128_t temp; + + // Print new filter character + fprintf(fp,"@"); +- // Print source address +- addr[0] = addr[1] = addr[2] = addr[3] = 0; +- temp = 0; +- temp = filt->sa; +- addr[0] = (temp >> 24); +- addr[1] = ((temp << 8) >> 24); +- addr[2] = ((temp << 16) >> 24); +- addr[3] = ((temp << 24) >> 24); +- fprintf(fp, "%d.%d.%d.%d/%d\t", +- addr[0], addr[1], addr[2], addr[3], +- filt->sa_len); +- // Print destination address +- addr[0] = addr[1] = addr[2] = addr[3] = 0; +- temp = 0; +- temp = filt->da; +- addr[0] = (temp >> 24); +- addr[1] = ((temp << 8) >> 24); +- addr[2] = ((temp << 16) >> 24); +- addr[3] = ((temp << 24) >> 24); +- fprintf(fp, "%d.%d.%d.%d/%d\t", +- addr[0], addr[1], addr[2], addr[3], +- filt->da_len); ++ // Print source/destination address ++ if (ADDRLEN == 32) { // IPv4 ++ // Source address ++ temp = filt->sa >> 96; ++ ip::address_v4 src_addr(temp); ++ fprintf(fp, "%s/%d\t", src_addr.to_string().c_str(), (filt->sa_len < 32) ? filt->sa_len : 32); ++ // Destination address ++ temp = filt->da >> 96; ++ ip::address_v4 dst_addr(temp); ++ fprintf(fp, "%s/%d\t", dst_addr.to_string().c_str(), (filt->da_len < 32) ? filt->da_len : 32); ++ } else { // IPv6 ++ // Source address ++ temp = filt->sa; ++ const ip::address_v6::bytes_type src_temp_bytes_type( ++ (unsigned char) (temp.upper() >> 56), ++ (unsigned char) (temp.upper() >> 48), ++ (unsigned char) (temp.upper() >> 40), ++ (unsigned char) (temp.upper() >> 32), ++ (unsigned char) (temp.upper() >> 24), ++ (unsigned char) (temp.upper() >> 16), ++ (unsigned char) (temp.upper() >> 8), ++ (unsigned char) temp.upper(), ++ (unsigned char) (temp.lower() >> 56), ++ (unsigned char) (temp.lower() >> 48), ++ (unsigned char) (temp.lower() >> 40), ++ (unsigned char) (temp.lower() >> 32), ++ (unsigned char) (temp.lower() >> 24), ++ (unsigned char) (temp.lower() >> 16), ++ (unsigned char) (temp.lower() >> 8), ++ (unsigned char) temp.lower()); ++ ip::address_v6 src_addr(src_temp_bytes_type); ++ fprintf(fp, "%s/%d\t", src_addr.to_string().c_str(), filt->sa_len); ++ // Destination address ++ temp = filt->da; ++ const ip::address_v6::bytes_type dst_temp_bytes_type( ++ (unsigned char) (temp.upper() >> 56), ++ (unsigned char) (temp.upper() >> 48), ++ (unsigned char) (temp.upper() >> 40), ++ (unsigned char) (temp.upper() >> 32), ++ (unsigned char) (temp.upper() >> 24), ++ (unsigned char) (temp.upper() >> 16), ++ (unsigned char) (temp.upper() >> 8), ++ (unsigned char) temp.upper(), ++ (unsigned char) (temp.lower() >> 56), ++ (unsigned char) (temp.lower() >> 48), ++ (unsigned char) (temp.lower() >> 40), ++ (unsigned char) (temp.lower() >> 32), ++ (unsigned char) (temp.lower() >> 24), ++ (unsigned char) (temp.lower() >> 16), ++ (unsigned char) (temp.lower() >> 8), ++ (unsigned char) temp.lower()); ++ ip::address_v6 dst_addr(dst_temp_bytes_type); ++ fprintf(fp, "%s/%d\t", dst_addr.to_string().c_str(), filt->da_len); ++ } + // Print source port + fprintf(fp, "%d : %d\t", + filt->sp[0], filt->sp[1]); +diff --git a/db_generator.cc b/db_generator.cc +index 3344759..afa53fb 100644 +--- a/db_generator.cc ++++ b/db_generator.cc +@@ -15,6 +15,9 @@ + #include "custom_db.h" + #include "sys/time.h" + ++// IP address length in bits (global variable) ++int ADDRLEN = 32; ++ + main(int argc, char *argv[]) + { + char filename[1024]; +@@ -24,19 +27,20 @@ main(int argc, char *argv[]) + FILE *fp_std; // output file pointer for standard form filter file + + int num_filters = 0; // number of filters +- ++ + int smoothness = 0; // precision of database replication + float addr_scope = 0; // adjustment to average address scope + float port_scope = 0; // adjustment to average port scope + + // Check for correct number of input arguments + if (argc > 8 || argc <= 1){ +- fprintf(stderr,"Usage: db_generator -hrb (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + fprintf(stderr,"db_generator is a synthetic filter database generator.\n"); +- fprintf(stderr,"Usage: db_generator -hrb (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + fprintf(stderr,"\t -h displays help menu\n"); + fprintf(stderr,"\t -r generates a random database\n"); + fprintf(stderr,"\t -b turns on address prefix scaling with database size; note that this alters the skew distribution in the parameter file\n"); ++ fprintf(stderr,"\t -6 generates a database with IPv6 5-tuples\n"); + fprintf(stderr,"\t -c generates a custom database using an input parameter file\n"); + fprintf(stderr,"\t is a parameter [0:64] that injects structured randomness\n"); + fprintf(stderr,"\t
is a parameter [-1.0:1.0] that adjusts the average scope of the address prefix pairs\n"); +@@ -65,12 +69,16 @@ main(int argc, char *argv[]) + case 'b': + branch = 1; + break; ++ case '6': ++ ADDRLEN = 128; ++ break; + case 'h': + fprintf(stderr,"db_generator is a synthetic filter database generator.\n"); +- fprintf(stderr,"Usage: db_generator -hrb (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + fprintf(stderr,"\t -h displays help menu\n"); + fprintf(stderr,"\t -r generates a random database\n"); + fprintf(stderr,"\t -b turns on address prefix scaling with database size; note that this alters the skew distribution in the parameter file\n"); ++ fprintf(stderr,"\t -6 generates a database with IPv6 5-tuples\n"); + fprintf(stderr,"\t -c generates a custom database using an input parameter file\n"); + fprintf(stderr,"\t is a parameter [0:64] that injects structured randomness\n"); + fprintf(stderr,"\t
is a parameter [-1.0:1.0] that adjusts the average scope of the address prefixe pairs\n"); +@@ -87,7 +95,7 @@ main(int argc, char *argv[]) + } + } + } +- ++ + if (random == 1 && argc == 2){ + num_filters = atoi(argv[0]); + strcpy(filename,argv[1]); +@@ -99,21 +107,21 @@ main(int argc, char *argv[]) + // printf("smoothness = %d\n",smoothness); + if (smoothness < 0 || smoothness > 64) { + fprintf(stderr,"Error smoothness must be a value in the range [0:64]\n"); +- fprintf(stderr,"Usage: db_generator -hr (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + exit(1); + } + sscanf(argv[3],"%f",&addr_scope); + // printf("addr_scope = %.4f\n",addr_scope); + if (addr_scope < -1 || addr_scope > 1) { + fprintf(stderr,"Error address scope must be a value in the range [-1:1]\n"); +- fprintf(stderr,"Usage: db_generator -hr (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + exit(1); + } + sscanf(argv[4],"%f",&port_scope); + // printf("addr_scope = %.4f\n",port_scope); + if (port_scope < -1 || port_scope > 1) { + fprintf(stderr,"Error port scope must be a value in the range [-1:1]\n"); +- fprintf(stderr,"Usage: db_generator -hr (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + exit(1); + } + strcpy(filename,argv[5]); +@@ -121,7 +129,7 @@ main(int argc, char *argv[]) + fp_in = fopen(in_filename,"r"); + if (fp_in == NULL) {fprintf(stderr,"ERROR: cannot open seed file %s\n",in_filename); exit(1);} + } else { +- fprintf(stderr,"Usage: db_generator -hr (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + exit(1); + } + +diff --git a/dbintree.cc b/dbintree.cc +index 9274710..9a53299 100644 +--- a/dbintree.cc ++++ b/dbintree.cc +@@ -13,13 +13,13 @@ + + dbintree::dbintree() { + // Initialize to graph with N vertices and no edges. +- skew = new float[33]; +- corr = new float[33]; +- p1child = new float[33]; +- p2child = new float[33]; ++ skew = new float[129]; ++ corr = new float[129]; ++ p1child = new float[129]; ++ p2child = new float[129]; + num_tnodes = 0; + root = NULL; +- for (int u = 0; u < 33; u++) { ++ for (int u = 0; u < 129; u++) { + skew[u] = 0; + corr[u] = 0; + p1child[u] = 0; +@@ -28,10 +28,10 @@ dbintree::dbintree() { + } + + dbintree::~dbintree() { +- delete(skew); +- delete(corr); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (corr); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } +@@ -39,6 +39,7 @@ dbintree::~dbintree() { + void dbintree::delete_node(struct tnode *me){ + if (me->child0 != NULL) delete_node(me->child0); + if (me->child1 != NULL) delete_node(me->child1); ++ delete(me->stubList); + delete(me); + return; + } +@@ -99,13 +100,13 @@ void dbintree::read_skew(FILE* fp_in){ + // printf("matches = %d\n",matches); + // printf("level = %d, skew = %.4f\n",level,skew); + if (matches == 4) { +- if (level <= 32) { ++ if (level <= 128) { + p1child[level] = p1_t; + p2child[level] = p2_t; + skew[level] = f_skew; + } + else { +- fprintf(stderr,"Level for destination address skew is greater than 32.\n"); ++ fprintf(stderr,"Level for destination address skew is greater than 128.\n"); + exit(1); + } + // printf("Read line: %d\t%.4f\t%.4f\t%.4f\n",level,p1_t,p2_t,f_skew); +@@ -147,7 +148,7 @@ void dbintree::read_corr(FILE* fp_in){ + void dbintree::print_skew(FILE *fp) { + + fprintf(fp,"Level\tp1\tp2\tSkew\n"); +- for (int i = 0; i < 33; i++) { ++ for (int i = 0; i < 129; i++) { + fprintf(fp,"%d\t%.4f\t%.4f\t%.4f\n", + i,p1child[i],p2child[i],skew[i]); + } +@@ -157,14 +158,14 @@ void dbintree::print_skew(FILE *fp) { + void dbintree::print_corr(FILE *fp) { + + fprintf(fp,"Level\tCorr\n"); +- for (int i = 0; i < 33; i++) { ++ for (int i = 0; i < 129; i++) { + fprintf(fp,"%d\t%.4f\n",i,corr[i]); + } + return; + } + + void dbintree::build_tree(dlist* Flist, struct filter filters[]){ +- unsigned int addr = 0; ++ uint128_t addr = 0; + // Create copy of list + dlist *temp_list = new dlist(); + (*temp_list)=(Flist); +@@ -221,7 +222,7 @@ void dbintree::add2child_stublist(struct tnode *node, int dir, int filt){ + return; + } + +-void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, struct filter filters[], int CurrNest){ ++void dbintree::add_stub(struct tnode *node, uint128_t addr, dlist* Flist, struct filter filters[], int CurrNest){ + int Flist_size = 0; + int lev = node->lvl; + +@@ -237,21 +238,21 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str + // printf("Flist_size = %d\n",Flist_size); + + double temp; +- unsigned int sa; ++ uint128_t sa; + +- unsigned int addr0, addr1; ++ uint128_t addr0, addr1; + // Adjust addresses + if (lev == 0) { + addr0 = 0; + addr1 = 1; +- addr1 = addr1 << 31; ++ addr1 = addr1 << 127; + } else { +- addr0 = addr >> (32 - lev); +- addr0 = addr0 << (32 - lev); +- addr1 = addr >> (32 - lev); ++ addr0 = addr >> (128 - lev); ++ addr0 = addr0 << (128 - lev); ++ addr1 = addr >> (128 - lev); + addr1 = addr1 << 1; + addr1 += 1; +- addr1 = addr1 << (31 - lev); ++ addr1 = addr1 << (127 - lev); + } + + // Allocate temp_list's +@@ -297,7 +298,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str + // printf("Flist_size = %d, tempList: ",Flist_size); tempList->print(stdout); printf("\n"); + // if lev1_flag == 1, dump all lev1 filters to one side + // printf("lev = %d, MyNest = %d, Nest = %d, lev1_flag = %d\n",lev,MyNest,Nest,lev1_flag); +- if ((Flist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 31)){ ++ if ((Flist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 127)){ + // printf("add_stub: Enforcing nesting limit\n"); + // Add all filters to stublist and let the finish_node process distribute them + int fptr; +@@ -331,7 +332,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str + // sa_len > lvl + // Prevent prefix nesting + sa = sa << lev; +- sa = sa >> 31; ++ sa = sa >> 127; + // sa now equals next "bit" of source address + if (filters[fptr].sa_len == (lev+1)) { + // Source prefix will be exhausted at next level +@@ -407,7 +408,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str + return; + } + +-void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, struct filter filters[], int CurrNest){ ++void dbintree::finish_node(struct tnode *node, uint128_t addr, dlist* Flist, struct filter filters[], int CurrNest){ + int Flist_size = 0; + int stubList_size = 0; + int lev = node->lvl; +@@ -479,20 +480,20 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, + + double temp; + int path; +- unsigned int addr0, addr1; ++ uint128_t addr0, addr1; + + // Adjust addresses + if (lev == 0) { + addr0 = 0; + addr1 = 1; +- addr1 = addr1 << 31; ++ addr1 = addr1 << 127; + } else { +- addr0 = addr >> (32 - lev); +- addr0 = addr0 << (32 - lev); +- addr1 = addr >> (32 - lev); ++ addr0 = addr >> (128 - lev); ++ addr0 = addr0 << (128 - lev); ++ addr1 = addr >> (128 - lev); + addr1 = addr1 << 1; + addr1 += 1; +- addr1 = addr1 << (31 - lev); ++ addr1 = addr1 << (127 - lev); + } + + // Create an empty list +@@ -519,7 +520,7 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, + // If at the nesting threshold and list has more than one child, + // then split list (allocate all nodes with level == lev1 to one path) + // printf("lev = %d, MyNest = %d, Nest = %d, lev1_flag = %d\n",lev,MyNest,Nest,lev1_flag); +- if ((templist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 31)){ ++ if ((templist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 127)){ + // Allocate nest_list + dlist *nest_list = new dlist(); + dlist *other_list = new dlist(); +diff --git a/dbintree.h b/dbintree.h +index 5509fc3..d9311b6 100644 +--- a/dbintree.h ++++ b/dbintree.h +@@ -33,10 +33,10 @@ class dbintree { + float *p1child; // probability that a node at a given level has one child + float *p2child; // probability that a node at a given level has two children + int num_tnodes; // number of tree nodes +- void add_stub(struct tnode *node, unsigned int addr, dlist* Flist, struct filter filters[],int CurrNest); ++ void add_stub(struct tnode *node, uint128_t addr, dlist* Flist, struct filter filters[],int CurrNest); + void add2child_stublist(struct tnode *node, int dir, int filt); + void add_node(struct tnode *prnt, int lev, int dir); +- void finish_node(struct tnode *node, unsigned int addr, dlist* Flist, struct filter filters[],int CurrNest); ++ void finish_node(struct tnode *node, uint128_t addr, dlist* Flist, struct filter filters[],int CurrNest); + int Nest; // Maximum allowed nesting + + public: dbintree(); +@@ -51,4 +51,15 @@ class dbintree { + void print_corr(FILE*); // print correlation per level + void build_tree(dlist* Flist, struct filter filters[]); + void lsort(); // sort nodes by level ++ ++ // get methods for selected private members ++ inline float* get_skew() { ++ return skew; ++ }; ++ inline float* get_p1child() { ++ return p1child; ++ }; ++ inline float* get_p2child() { ++ return p2child; ++ }; + }; +diff --git a/filter_graph.cc b/filter_graph.cc +new file mode 100644 +index 0000000..726869a +--- /dev/null ++++ b/filter_graph.cc +@@ -0,0 +1,785 @@ ++// filter_graph.cc: Filter_graph class definition ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "stdinc.h" ++#include "flow_network.h" ++#include "filter_graph.h" ++ ++// Library includes ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Auxiliary (non-member) functions ************************************* ++ ++ ++/* ++ * Private function that builds a flow network corresponding to the filter ++ * graph. ++ * In three iterations the function traverses all edges of the filter graph ++ * (i.e., s_node->src_nodes, src_nodes->dst_nodes, and dst_nodes->t_node edges) ++ * and constructs the flow network corresponding to this graph. Each edge of ++ * the filter graph can be represented by at most two edges of the flow ++ * network -- a forward and backward edge. Note that they are included into the ++ * flow network only if their residual capacity is greater than zero. ++ * The function expects that the input graph is already a valid flow network, ++ * i.e., it contains only one node without input edges (the 's' node) and only ++ * one node without output edges (the 't' node). ++ * @param network Reference to the (most probably empty) flow network object. ++ * @param graph Pointer to the constant filter graph object. ++ */ ++void build_flow_network(Flow_network& network, const Filter_graph* graph) { ++ // declatarion of "phase" variables ++ const node_list_item* list; ++ int src_list; ++ int dst_list; ++ ++ // iteration through three phases ++ for (int i = 0; i < 3; i++) { ++ // setting of phase variables ++ switch (i) { ++ case 0: // edges from the 's' node to destination nodes ++ list = graph->get_s_node(); ++ src_list = 0; ++ dst_list = 1; ++ break; ++ case 1: // edges from source nodes to destination nodes ++ list = graph->get_src_nodes(); ++ src_list = 1; ++ dst_list = 2; ++ break; ++ case 2: // edges from destination nodes to the 'd' node ++ list = graph->get_dst_nodes(); ++ src_list = 2; ++ dst_list = 3; ++ break; ++ } ++ ++ // iteration over all nodes in the list ++ while (list != NULL) { ++ neighbour_list_item* neighbour = list->neighbours; ++ // iteration over all neighbours (i.e., edges of the filter graph) ++ while (neighbour != NULL) { ++ // compute residual capacity of forward and backward edges ++ int capacity_forward = neighbour->weight - neighbour->flow; ++ int capacity_backward = neighbour->flow; ++ // insert the forward edge, if it has capacity > 0 ++ if (capacity_forward > 0) { ++ network.add_edge(list->prefix, src_list, ++ neighbour->node->prefix, dst_list, ++ neighbour, true, capacity_forward); ++ } ++ // insert the backward edge, if it has capacity > 0 ++ if (capacity_backward > 0) { ++ network.add_edge(neighbour->node->prefix, dst_list, ++ list->prefix, src_list, ++ neighbour, false, capacity_backward); ++ } ++ // move to the next edge ++ neighbour = neighbour->next; ++ } ++ // move to the next node ++ list = list->next; ++ } ++ } ++} // end build_flow_network() ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++/* ++ * Private static function that creates deep copy of the original list. ++ */ ++node_list_item* Filter_graph::copy_node_list(const node_list_item* orig) { ++ // initialize pointer to copied node list ++ node_list_item* result = (orig == NULL) ? ++ NULL : ++ new node_list_item; ++ ++ // node list level of copying ++ node_list_item* copy = result; ++ while (orig != NULL) { ++ // list item members initialization ++ copy->prefix = orig->prefix; ++ copy->pruned = orig->pruned; ++ copy->neighbours = (orig->neighbours == NULL) ? ++ NULL : ++ new neighbour_list_item; ++ copy->next = (orig->next == NULL) ? ++ NULL : ++ new node_list_item; ++ ++ // neighbour list level of copying ++ neighbour_list_item* orig_neighbours = orig->neighbours; ++ neighbour_list_item* copy_neighbours = copy->neighbours; ++ while (orig_neighbours != NULL) { ++ // list item members initialization ++ copy_neighbours->node = NULL; // cannot be initialized directly ++ // (points to different node list) ++ copy_neighbours->weight = orig_neighbours->weight; ++ copy_neighbours->flow = orig_neighbours->flow; ++ copy_neighbours->filters = (orig_neighbours->filters == NULL) ? ++ NULL : ++ new filter_list_item; ++ copy_neighbours->next = (orig_neighbours->next == NULL) ? ++ NULL : ++ new neighbour_list_item; ++ ++ // filter list level of copying ++ filter_list_item* orig_filters = orig_neighbours->filters; ++ filter_list_item* copy_filters = copy_neighbours->filters; ++ while (orig_filters != NULL) { ++ // list item members initialization ++ copy_filters->filter = orig_filters->filter; ++ copy_filters->next = (orig_filters->next == NULL) ? ++ NULL : ++ new filter_list_item; ++ // move to the next item of filter list ++ copy_filters = copy_filters->next; ++ orig_filters = orig_filters->next; ++ } ++ ++ // move to the next item of neighbour list ++ copy_neighbours = copy_neighbours->next; ++ orig_neighbours = orig_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ copy = copy->next; ++ orig = orig->next; ++ } ++ ++ return result; ++} // end copy_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole node list. ++ */ ++void Filter_graph::remove_node_list(node_list_item** list) { ++ // traverse all nodes ++ while ((*list) != NULL) { ++ // get pointer to the first node ++ node_list_item* first_node = *list; ++ ++ // correctly deallocate its whole neighbour list ++ remove_neighbour_list(&(first_node->neighbours)); ++ ++ // move to the next node list item and deallocate the current one ++ node_list_item* next_node = first_node->next; ++ delete first_node; ++ *list = next_node; ++ } ++} // end remove_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole neighbour ++ * list. ++ */ ++void Filter_graph::remove_neighbour_list(neighbour_list_item** list) { ++ // traverse all neighbours ++ while ((*list) != NULL) { ++ // get pointer to the first neighbour ++ neighbour_list_item* first_neighbour = *list; ++ ++ // correctly deallocate it whole filter list ++ remove_filter_list(&(first_neighbour->filters)); ++ ++ // move to the next neighbour list item and deallocate the current one ++ neighbour_list_item* next_neighbour = first_neighbour->next; ++ delete first_neighbour; ++ *list = next_neighbour; ++ } ++} // end remove_neighbour_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole filter list. ++ */ ++void Filter_graph::remove_filter_list(filter_list_item** list) { ++ // traverse all filters ++ while ((*list) != NULL) { ++ // get pointer to the first filter ++ filter_list_item* first_filter = *list; ++ ++ // move to the next filter list item and deallocate the current one ++ filter_list_item* next_filter = first_filter->next; ++ delete first_filter; ++ *list = next_filter; ++ } ++} // end remove_filter_list() ++ ++ ++/* ++ * Private static function that sets correct values of neighbour node pointers, ++ * which cannot be correctly initialized during copying. ++ */ ++void Filter_graph::set_neighbour_nodes(const node_list_item* orig, ++ node_list_item* src, ++ node_list_item* dst) { ++ // traverse all nodes ++ while (orig != NULL) { ++ neighbour_list_item* orig_neighbours = orig->neighbours; ++ neighbour_list_item* src_neighbours = src->neighbours; ++ ++ // traverse all neighbours ++ while (orig_neighbours != NULL) { ++ // set correct neighbour node pointer ++ src_neighbours->node = find_node(orig_neighbours->node->prefix, dst); ++ ++ // move to the next item of neighbour list ++ orig_neighbours = orig_neighbours->next; ++ src_neighbours = src_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ orig = orig->next; ++ src = src->next; ++ } ++ ++ return; ++} // end set_neighbour_nodes() ++ ++ ++/* ++ * Private static function that looks for node with the given prefix in the ++ * given list of nodes. ++ */ ++node_list_item* Filter_graph::find_node(const IP_prefix& prefix, ++ node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ if (list->prefix == prefix) { ++ // corresponding node - return pointer to it ++ return list; ++ } else { ++ // node with different prefix - move to the next item of node list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding node was not found ++ return NULL; ++} // end find_node() ++ ++ ++/* ++ * Private static function that looks for the corresponding neighbour node in ++ * the given list of neighbours. ++ */ ++neighbour_list_item* Filter_graph::find_neighbour( ++ const node_list_item* neighbour, ++ neighbour_list_item* list) { ++ // traverse all neighbour nodes ++ while (list != NULL) { ++ if (list->node->prefix == neighbour->prefix) { ++ // corresponding neighbour node - return pointer to it ++ return list; ++ } else { ++ // neighbour node corresponding to different prefix node - move to the ++ // next item of neighbour list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding neighbour node was not found ++ return NULL; ++} // end find_neighbour() ++ ++ ++/* ++ * Private static function that looks for the filter node pointing to the ++ * specified filter in the given list of filters. ++ */ ++filter_list_item* Filter_graph::find_filter(const struct filter* filter, ++ filter_list_item* list) { ++ // traverse all filter nodes ++ while (list != NULL) { ++ if (list->filter == filter) { ++ // corresponding filter node - return pointer to it ++ return list; ++ } else { ++ // filter node pointing to different filter - move to the next item of ++ // filter list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding filter node was not found ++ return NULL; ++} // end find_filter() ++ ++ ++/* ++ * Private static function that inserts a node representing the given IP prefix ++ * at the beginning of the given list of nodes. ++ */ ++void Filter_graph::insert_node(const IP_prefix& prefix, ++ node_list_item** list) { ++ // allocate and initialize new prefix node ++ node_list_item* node = new node_list_item; ++ node->prefix = prefix; ++ node->pruned = false; ++ node->neighbours = NULL; ++ ++ // insert new prefix node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_node() ++ ++ ++/* ++ * Private static function that inserts a neighbour node corresponding to the ++ * given prefix node at the beginning of the given list of neighbour nodes. ++ */ ++void Filter_graph::insert_neighbour(node_list_item* neighbour, ++ neighbour_list_item** list) { ++ // allocate and initialize new neighbour node ++ neighbour_list_item* node = new neighbour_list_item; ++ node->node = neighbour; ++ node->weight = 0; ++ node->flow = 0; ++ node->filters = NULL; ++ ++ // insert new neighbour node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_neighbour() ++ ++ ++/* ++ * Private static function that inserts a filter node pointing to the given ++ * filter at the beginning of the given list of filter nodes. ++ */ ++void Filter_graph::insert_filter(const struct filter* filter, ++ filter_list_item** list) { ++ // allocate and initialize new filter node ++ filter_list_item* node = new filter_list_item; ++ node->filter = filter; ++ ++ // insert new filter node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_filter() ++ ++ ++/* ++ * Private static function that prints specified node list, including all ++ * sublists (i.e., neighbour lists and filter lists). ++ */ ++void Filter_graph::print_node_list(const node_list_item* nodes) { ++ while (nodes != NULL) { ++ // print node list items ++ cout << "+-> " << nodes->prefix.get_prefix() << "/" ++ << nodes->prefix.get_length() << endl; ++ neighbour_list_item* neighbours = nodes->neighbours; ++ while (neighbours != NULL) { ++ // print neighbour list items ++ cout << "| +-> " << neighbours->node->prefix.get_prefix() << "/" ++ << neighbours->node->prefix.get_length() << " " ++ << "(" ++ << neighbours->flow << "/" ++ << neighbours->weight ++ << ")" << endl; ++ filter_list_item* filters = neighbours->filters; ++ while (filters != NULL) { ++ // print filter list items ++ cout << "| | +-> " << filters->filter->sp[0] << ":" ++ << filters->filter->sp[1] << " " ++ << filters->filter->dp[0] << ":" ++ << filters->filter->dp[1] << " " ++ << filters->filter->prot_num << endl; ++ // move to the next filter ++ filters = filters->next; ++ } ++ // moce tothe next neighbour ++ neighbours = neighbours->next; ++ } ++ // move to the next node ++ nodes = nodes->next; ++ } ++} // end print_node_list() ++ ++ ++/* ++ * Private function that removes non-pruned nodes and resets the "pruned" ++ * flag of pruned nodes of the filter graph. ++ */ ++void Filter_graph::remove_and_reset() { ++ for (int i = 0; i < 4; i++) { ++ // select the correct node list for iteration ++ node_list_item** node_ptr; ++ switch (i) { ++ case 0: ++ node_ptr = &s_node; ++ break; ++ case 1: ++ node_ptr = &src_nodes; ++ break; ++ case 2: ++ node_ptr = &dst_nodes; ++ break; ++ case 3: ++ node_ptr = &t_node; ++ break; ++ } ++ ++ // iterate over all nodes in the list ++ while ((*node_ptr) != NULL) { ++ node_list_item* node = *node_ptr; ++ if (node->pruned == false) { // remove the non-pruned node ++ (*node_ptr) = node->next; ++ delete node; ++ } else { // reset the "pruned" flag of the pruned node ++ node->pruned = false; ++ node_ptr = &(node->next); ++ } ++ } ++ } ++} // end remove_and_reset() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++/* ++ * Default constructor. ++ */ ++Filter_graph::Filter_graph() { ++ src_nodes = NULL; ++ dst_nodes = NULL; ++ s_node = NULL; ++ t_node = NULL; ++} // end Filter_graph() ++ ++ ++/* ++ * Copy constructor. ++ */ ++Filter_graph::Filter_graph(const Filter_graph& orig) { ++ // acquire members of the original object ++ const node_list_item* orig_src_nodes = orig.get_src_nodes(); ++ const node_list_item* orig_dst_nodes = orig.get_dst_nodes(); ++ const node_list_item* orig_s_node = orig.get_s_node(); ++ const node_list_item* orig_t_node = orig.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(orig_src_nodes); ++ dst_nodes = copy_node_list(orig_dst_nodes); ++ s_node = copy_node_list(orig_s_node); ++ t_node = copy_node_list(orig_t_node); ++ ++ // set pointers to neighbour nodes ++ set_neighbour_nodes(orig_t_node, t_node, NULL); ++ set_neighbour_nodes(orig_dst_nodes, dst_nodes, t_node); ++ set_neighbour_nodes(orig_src_nodes, src_nodes, dst_nodes); ++ set_neighbour_nodes(orig_s_node, s_node, src_nodes); ++} // end Filter_graph() ++ ++ ++/* ++ * Destructor. ++ */ ++Filter_graph::~Filter_graph() { ++ remove_node_list(&s_node); ++ remove_node_list(&src_nodes); ++ remove_node_list(&dst_nodes); ++ remove_node_list(&t_node); ++} // end ~Filter_graph() ++ ++ ++/* ++ * Copy assignment. ++ */ ++Filter_graph& Filter_graph::operator=(const Filter_graph& copy) { ++ // destruct the original object ++ remove_node_list(&s_node); ++ remove_node_list(&src_nodes); ++ remove_node_list(&dst_nodes); ++ remove_node_list(&t_node); ++ ++ // acquire members of the copied object ++ const node_list_item* copy_src_nodes = copy.get_src_nodes(); ++ const node_list_item* copy_dst_nodes = copy.get_dst_nodes(); ++ const node_list_item* copy_s_node = copy.get_s_node(); ++ const node_list_item* copy_t_node = copy.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(copy_src_nodes); ++ dst_nodes = copy_node_list(copy_dst_nodes); ++ s_node = copy_node_list(copy_s_node); ++ t_node = copy_node_list(copy_t_node); ++ ++ // set pointers to neighbour nodes ++ set_neighbour_nodes(copy_t_node, t_node, NULL); ++ set_neighbour_nodes(copy_dst_nodes, dst_nodes, t_node); ++ set_neighbour_nodes(copy_src_nodes, src_nodes, dst_nodes); ++ set_neighbour_nodes(copy_s_node, s_node, src_nodes); ++ ++ // return the original object with new content ++ return *this; ++} // end operator=() ++ ++ ++/* ++ * Modifies filter graph to add the specified filter into the set of filters ++ * represented by the graph. ++ */ ++void Filter_graph::add_filter(const struct filter* filter) { ++ // acquire source and destination prefixes ++ IP_prefix src_pref(filter->sa, filter->sa_len); ++ IP_prefix dst_pref(filter->da, filter->da_len); ++ ++ // find source prefix node and insert such node if it does not exist ++ node_list_item* src_node = find_node(src_pref, src_nodes); ++ if (src_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(src_pref, &src_nodes); ++ src_node = src_nodes; ++ } ++ ++ // find destination prefix node and insert such node if it does not exist ++ node_list_item* dst_node = find_node(dst_pref, dst_nodes); ++ if (dst_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(dst_pref, &dst_nodes); ++ dst_node = dst_nodes; ++ } ++ ++ // find neighbour node corresponding to the filter and insert such node if ++ // it does not exist ++ neighbour_list_item* neighbour = find_neighbour(dst_node, ++ src_node->neighbours); ++ if (neighbour == NULL) { ++ // neighbour is inserted at the beginning of the list ++ insert_neighbour(dst_node, &(src_node->neighbours)); ++ neighbour = src_node->neighbours; ++ } ++ ++ // find filter node pointing to the specified filter and insert such node if ++ // it does not exist ++ filter_list_item* filter_node = find_filter(filter, neighbour->filters); ++ if (filter_node == NULL) { ++ insert_filter(filter, &(neighbour->filters)); ++ neighbour->weight += 1; ++ } ++} // end add_filter() ++ ++ ++/* ++ * Adds an edge from the 's' node to a node representing the given prefix ++ * within the source nodes list and sets its weight to the given value. ++ */ ++void Filter_graph::add_s_prefix(const IP_prefix& prefix, const int weight) { ++ // check existence of the 's' node and allocate it if it does not exist ++ if (s_node == NULL) { ++ insert_node(IP_prefix(), &s_node); ++ s_node->pruned = true; ++ } ++ ++ // find a node representing the given prefix within the source nodes list ++ // (existence of such node is not checked since it should always exist) ++ node_list_item* src_node = find_node(prefix, src_nodes); ++ ++ // find a neighbour node corresponding to the given prefix ++ neighbour_list_item* neighbour = find_neighbour(src_node, ++ s_node->neighbours); ++ if (neighbour == NULL) { // the neighbour node does not exist ++ // insert the node at the beginning of the list ++ insert_neighbour(src_node, &(s_node->neighbours)); ++ neighbour = s_node->neighbours; ++ // set neighbour node's weight member ++ neighbour->weight = weight; ++ } else { // the neighbour node exists ++ // adjust neighbour node's weight member accordingly ++ neighbour->weight += weight; ++ } ++ ++ // set source node's pruned flag to true ++ src_node->pruned = true; ++} // end add_s_prefix() ++ ++ ++/* ++ * Adds an edge from a node representing the given prefix within the ++ * destination nodes list to the 't' node and sets its weight to the given ++ * value. ++ */ ++void Filter_graph::add_t_prefix(const IP_prefix& prefix, const int weight) { ++ // check existence of the 't' node and allocate it if it does not exist ++ if (t_node == NULL) { ++ insert_node(IP_prefix(), &t_node); ++ t_node->pruned = true; ++ } ++ ++ // find a node representing the given prefix within the destination nodes ++ // list ++ // (existence of such node is not checked since it should always exist) ++ node_list_item* dst_node = find_node(prefix, dst_nodes); ++ ++ // find a neighbour node corresponding to the 't' node ++ neighbour_list_item* neighbour = find_neighbour(t_node, ++ dst_node->neighbours); ++ if (neighbour == NULL) { // the neighbour node does not exist ++ // insert the node at the beginning of the list ++ insert_neighbour(t_node, &(dst_node->neighbours)); ++ neighbour = dst_node->neighbours; ++ // set neighbour node's weight member ++ neighbour->weight = weight; ++ } else { // the neighbour node exists ++ // adjust neighbour node's weight member accordingly ++ neighbour->weight += weight; ++ } ++ ++ // set destination node's pruned flag to true ++ dst_node->pruned = true; ++} // end add_t_prefix() ++ ++ ++/* ++ * Modifies the filter graph such that it conforms with the flow network ++ * specification -- i.e., it has only one node without input edges (the ++ * 's' node) and only one node without output edges (the 't' node). ++ */ ++void Filter_graph::to_flow_network() { ++ // 1) remove filters containing at least one non-pruned prefix ++ node_list_item* node = src_nodes; ++ while (node != NULL) { ++ if (node->pruned == false) { // remove all neighbours of this node ++ remove_neighbour_list(&(node->neighbours)); ++ } else { // remove only neighbours pointing to a non-pruned node ++ neighbour_list_item** neighbour_ptr = &(node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ neighbour_list_item* neighbour = *neighbour_ptr; ++ if (neighbour->node->pruned == false) { // remove this neighbour ++ remove_filter_list(&(neighbour->filters)); ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } else { // just move to the next neighbour ++ neighbour_ptr = &(neighbour->next); ++ } ++ } ++ } ++ node = node->next; ++ } ++ ++ // 2) remove non-pruned nodes and reset the "pruned" flag of other nodes ++ remove_and_reset(); ++ ++ // 3) BFS to set the "pruned" flag of visited nodes with at least one ++ // neighbour and the 's' and 't' nodes ++ queue q; ++ q.push(s_node); ++ // do the BFS ++ while (!q.empty()) { ++ // dequeue the front element of the queue ++ node_list_item* node = q.front(); ++ q.pop(); ++ // set the "pruned" flag if the list of neighbours is non-empty ++ if (node->neighbours != NULL) { ++ node->pruned = true; ++ } ++ // insert neighbours into the queue ++ neighbour_list_item* neighbour = node->neighbours; ++ while (neighbour != NULL) { ++ q.push(neighbour->node); ++ neighbour = neighbour->next; ++ } ++ } ++ // set the "pruned" flag of the 's' and 't' nodes ++ s_node->pruned = true; ++ t_node->pruned = true; ++ ++ // 4) remove edges from the 's' node going to non-pruned nodes ++ neighbour_list_item** neighbour_ptr = &(s_node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ neighbour_list_item* neighbour = *neighbour_ptr; ++ if (neighbour->node->pruned == false) { // remove this edge ++ // there are no filters represented by edges from the 's' node ++ (*neighbour_ptr) = neighbour->next; ++ delete neighbour; ++ } else { // move to the next edge ++ neighbour_ptr = &(neighbour->next); ++ } ++ } ++ ++ // 5) remove edges to the 't' node going from non-pruned nodes ++ node = dst_nodes; ++ while (node != NULL) { ++ if (node->pruned == false) { // remove all edges going from this node ++ remove_neighbour_list(&(node->neighbours)); ++ } ++ // move to the next node ++ node = node->next; ++ } ++ ++ // 6) remove non-pruned nodes (and reset the "pruned" flag of other nodes) ++ remove_and_reset(); ++} // end to_flow_network() ++ ++ ++/* ++ * Computes maximum flow using Dinic's algorithm. ++ */ ++int Filter_graph::max_flow() { ++ int max_flow = 0; ++ int flow_inc; ++ ++ do { // iterate until the flow cannot be improved ++ // build flow network corresponding to the filter graph ++ Flow_network network; ++ build_flow_network(network, this); ++ ++ // transform the flow network into the level graph ++ network.to_level_graph(); ++ ++ // compute a blocking flow in the flow network and update the flow in the ++ // filter graph accordingly ++ flow_inc = network.find_blocking_flow(); ++ max_flow += flow_inc; ++ } while (flow_inc != 0); ++ ++ return max_flow; ++} // end max_flow() ++ ++ ++/* ++ * Prints the filter graph. ++ */ ++void Filter_graph::print() { ++ cout << "S_NODE:" << endl; ++ print_node_list(s_node); ++ cout << "--------------------" << endl; ++ ++ cout << "SRC_NODES:" << endl; ++ print_node_list(src_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "DST_NODES:" << endl; ++ print_node_list(dst_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "T_NODE:" << endl; ++ print_node_list(t_node); ++ cout << "--------------------" << endl; ++} +diff --git a/filter_graph.h b/filter_graph.h +new file mode 100644 +index 0000000..601f2cd +--- /dev/null ++++ b/filter_graph.h +@@ -0,0 +1,437 @@ ++// filter_graph.h: header file for Filter_graph class ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef FILTER_GRAPH_H ++#define FILTER_GRAPH_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++ ++// Forward declarations (including typedef) to resolve circular dependency ++typedef struct node_list_item node_list_item; ++typedef struct neighbour_list_item neighbour_list_item; ++typedef struct filter_list_item filter_list_item; ++ ++/* ++ * A structure representing an item in a list of graph nodes. ++ */ ++struct node_list_item { ++ // IP prefix represented by this node ++ IP_prefix prefix; ++ ++ // Flag that is utilized for "pruning" filters once the complete filter ++ // graph is constructed ++ bool pruned; ++ ++ // List of neighbours ++ neighbour_list_item* neighbours; ++ ++ // Next item in list of graph nodes ++ node_list_item* next; ++}; ++ ++/* ++ * A structure representing an item in a list of neighbours of a graph node. ++ */ ++struct neighbour_list_item { ++ // Pointer to neighbour node within list of graph nodes ++ node_list_item* node; ++ ++ // Weight of filter graph's edge between neighbouring nodes ++ int weight; ++ ++ // Flow through filter graph's edge between neighbouring nodes ++ int flow; ++ ++ // List of filters that specify prefixes of neighbouring nodes ++ filter_list_item* filters; ++ ++ // Next item in list of neighbours ++ neighbour_list_item* next; ++}; ++ ++/* ++ * A Structure representing an item in a list of filters that specify prefixes ++ * of neighbouring graph nodes. ++ */ ++struct filter_list_item { ++ // Pointer to representation of filter ++ // (struct filter is defined in stdinc.h included in custom_db.cc) ++ const struct filter* filter; ++ ++ // Next item in list of filters ++ filter_list_item* next; ++}; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a set of filters as a filter graph -- i.e., ++ * weighted directed bipartite graph with special source (s) and terminate (t) ++ * nodes -- that is constructed according to filters' source and destination ++ * prefixes and pruned source and destination prefix tries. ++ */ ++class Filter_graph { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * Lists of source and destination nodes of the filter graph. ++ */ ++ node_list_item* src_nodes; ++ node_list_item* dst_nodes; ++ ++ /* ++ * Special nodes 's' and 't' of the filter graph. ++ */ ++ node_list_item* s_node; ++ node_list_item* t_node; ++ ++ /* ++ * Private static function that creates deep copy of the original list. ++ * The function creates new instances of all items from the original list ++ * (as well as all sublists) and sets the value of their components ++ * according to this original list. The only exception is pointer to ++ * neighbour node, which is initialized to NULL (it points to different ++ * list, thus it cannot be initialized to correct value during copying). ++ * @param orig Pointer to the constant original node list. ++ * @return Pointer to the copy of the original node list. ++ */ ++ static node_list_item* copy_node_list(const node_list_item* orig); ++ ++ /* ++ * Private static function that correctly deallocates the whole node ++ * list. ++ * The function traverses the given node list and all its sublists and ++ * starting from the inner-most list it deallocates all the traversed ++ * list items. ++ * @ param list Pointer to pointer to node list that is to be ++ * deallocated. ++ */ ++ static void remove_node_list(node_list_item** list); ++ ++ /* ++ * Private static function that correctly deallocates the whole neighbour ++ * list. ++ * The function traverses the given neighbour list and all its sublists ++ * and starting from the inner-most list it deallocates all the traversed ++ * list items. ++ * @param Pointer to pointer to the neighbour list that is to be ++ * deallocated. ++ */ ++ static void remove_neighbour_list(neighbour_list_item** list); ++ ++ /* ++ * Private static function that correctly deallocates the whole filter ++ * list. ++ * The function traverses the given filter list and deallocates all the ++ * traversed list items. ++ * @param Pointer to pointer to the filter list that is to be ++ * deallocated. ++ */ ++ static void remove_filter_list(filter_list_item** list); ++ ++ /* ++ * Private static function that sets correct values of neighbour node ++ * pointers, which cannot be correctly initialized during copying. ++ * The function simultaneously traverses neighbours lists in orig and src ++ * node lists. For each neighbour node from orig list it looks for ++ * corresponding item in dst node list and stores pointer to this node to ++ * current item in src list. ++ * @param orig Pointer to the constant original node list. ++ * @param src Pointer to the list of source nodes (neighbour node ++ * pointers of this list are set). ++ * @param dst Pointer to the list of destination nodes (nodes of this ++ * list act as targets of neighbour node pointers within ++ * src node list). ++ */ ++ static void set_neighbour_nodes(const node_list_item* orig, ++ node_list_item* src, ++ node_list_item* dst); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for node with the given prefix in ++ * the given list of nodes. ++ * @param prefix Reference to a constant IP prefix of node that the ++ * function looks for in the list. ++ * @param list Pointer to list of nodes that is traversed during ++ * looking for node with the given IP prefix. ++ * @return Pointer to found node or NULL. ++ */ ++ static node_list_item* find_node(const IP_prefix& prefix, ++ node_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the corresponding neighbour ++ * node in the given list of neighbours. ++ * @param neighbour Pointer to a constant prefix node whose neighbour ++ * node the function looks for in the list. ++ * @param list Pointer to the list of neighbour nodes that is ++ * traversed during looking for the node corresponding ++ * to the given prefix node. ++ * @return Pointer to the found neighbour node or NULL. ++ */ ++ static neighbour_list_item* find_neighbour( ++ const node_list_item* neighbour, ++ neighbour_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the filter node pointing to the ++ * specified filter in the given list of filters. ++ * @param filter Pointer to the constant filter that is referenced by ++ * the filter node the function looks for in the list. ++ * @param list Pointer to the list of filter nodes that is traversed ++ * during looking for a node pointing to the given ++ * filter. ++ * @return Pointer to the found filter node or NULL. ++ */ ++ static filter_list_item* find_filter(const struct filter* filter, ++ filter_list_item* list); ++ ++ /* ++ * Private static function that inserts a node representing the given IP ++ * prefix at the beginning of the given list of nodes. ++ * @param prefix Reference to a constant IP prefix that is going to be ++ * represented by the inserted node. ++ * @param list Pointer to pointer to the list of nodes that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_node(const IP_prefix& prefix, ++ node_list_item** list); ++ ++ /* ++ * Private static function that inserts a neighbour node corresponding to ++ * the given prefix node at the beginning of the given list of ++ * neighbour nodes. ++ * @param neighbour Pointer to a prefix node whose neighbour node is ++ * going to be inserted. ++ * @param list Pointer to pointer to the list of neighbours that ++ * is going to be extended by the inserted node. ++ */ ++ static void insert_neighbour(node_list_item* neighbour, ++ neighbour_list_item** list); ++ ++ /* ++ * Private static function that inserts a filter node pointing to the ++ * given filter at the beginning of the given list of filter nodes. ++ * @param node Pointer to the constant filter that is going to be ++ * referenced by the inserted filter node. ++ * @param list Pointer to pointer to the list of filters that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_filter(const struct filter* filter, ++ filter_list_item** list); ++ ++ /* ++ * Private static function that prints specified node list, including all ++ * sublists (i.e., neighbour lists and filter lists). ++ * @param nodes Pointer to the constant list of nodes that is to be ++ * printed. ++ */ ++ static void print_node_list(const node_list_item* nodes); ++ ++ /* ++ * Private function that removes non-pruned nodes and resets the "pruned" ++ * flag of pruned nodes of the filter graph. ++ * The function performs the specified function on all nodes of the ++ * filter graph (i.e., source and destination nodes as well as the 's' ++ * and 't' nodes). ++ * The function expects that neighbours list referenced from the ++ * non-pruned nodes have been correctly deallocated before calling this ++ * function. ++ */ ++ void remove_and_reset(); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * All pointers are initialized to NULL. ++ */ ++ Filter_graph(); ++ ++ /* ++ * Copy constructor. ++ * All pointers are initialized to a deep copy of corresponding members ++ * of the original object. ++ * @param orig Reference to the constant original object. ++ */ ++ Filter_graph(const Filter_graph& orig); ++ ++ /* ++ * Destructor. ++ * Correctly deallocates all lists that are referenced by object members. ++ */ ++ ~Filter_graph(); ++ ++ /* ++ * Copy assignment. ++ * The original object is destructed and its new content is constructed ++ * in similar way as in the copy constructor. ++ * @param copy Reference to the constant copied object. ++ * @return Reference to the original object with new content. ++ */ ++ Filter_graph& operator= (const Filter_graph& copy); ++ ++ /* ++ * Get function for the src_nodes member. ++ * @return Pointer to the constant list of source nodes. ++ */ ++ inline const node_list_item* get_src_nodes() const { ++ return src_nodes; ++ } // end get_src_nodes() ++ ++ /* ++ * Get function for the dst_nodes member. ++ * @return Pointer to the constant list of destination nodes. ++ */ ++ inline const node_list_item* get_dst_nodes() const { ++ return dst_nodes; ++ } // end get_dst_nodes() ++ ++ /* ++ * Get function for the s_node member. ++ * @return Pointer to the constant special 's' node. ++ */ ++ inline const node_list_item* get_s_node() const { ++ return s_node; ++ } // end get_s_node() ++ ++ /* ++ * Get function for the t_node member. ++ * @return Pointer to the constant special 't' node. ++ */ ++ inline const node_list_item* get_t_node() const { ++ return t_node; ++ } // end get_t_node() ++ ++ /* ++ * Modifies filter graph to add the specified filter into the set of ++ * filters represented by the graph. ++ * The function searches src_nodes and dst_nodes lists for nodes ++ * representing source and destination prefixes of the given filter and ++ * inserts such nodes into these lists if they are not found. Next, the ++ * function seraches neighbours list of source prefix node for neighbour ++ * node representing destination prefix of the given filter and inserts ++ * such neighbour node into the list if it is not found. Finally, the ++ * function searches filters list of neighbouring node for pointer to the ++ * given filter and inserts such pointer into the list if it is not ++ * found. Along with inserting new filter pointer to the list, the ++ * function increments weight item of neighbouring node representation. ++ * @param filter Pointer to a constant structure representing inserted ++ * filter. ++ */ ++ void add_filter(const struct filter* filter); ++ ++ /* ++ * Adds an edge from the 's' node to a node representing the given prefix ++ * within the source nodes list and sets its weight to the given value. ++ * First of all, the function checks whether the 's' node has already ++ * been allocated and allocates this node in case it does not yet exist. ++ * Next, the function searches the neighbours list of the 's' node for a ++ * neighbour node representing the given prefix. If such neighbour node ++ * exists, the function just adds the given weight to the current value ++ * of its weight counter. If such neighbour node does not exist, the ++ * function inserts the node into the list and sets its weight counter to ++ * the given value. The function also sets the "pruned" flag of the node ++ * representing the given prefix to true. ++ * The implementation expects that all filters have already been added to ++ * the filter graph and that only prefixes of a pruned source trie are ++ * added using this function. In such a case the source nodes list always ++ * contains a node representing the given prefix. ++ * @param prefix Reference to the IP_prefix object that determines a ++ * target node of the edge from the 's' node. ++ * @param weight Weight of the newly created edge. ++ */ ++ void add_s_prefix(const IP_prefix& prefix, const int weight); ++ ++ /* ++ * Adds an edge from a node representing the given prefix within the ++ * destination nodes list to the 't' node and sets its weight to the ++ * given value. ++ * First of all, the function checks whether the 't' node has already ++ * been allocated and allocates this node in case it does not yet exist. ++ * Next, the function searches the neighbours list of the node ++ * representing the given prefix within the destination nodes list for a ++ * neighbour node representing the 't' node. If such neighbour node ++ * exists, the function just adds the given weight to the current value ++ * of its weight counter. If such neighbour node does not exist, the ++ * function inserts the node into the list and sets its weight counter to ++ * the given value. The function also sets the "pruned" flag of the node ++ * representing the given prefix to true. ++ * The implementation expects that all filters have already been added to ++ * the filter graph and that only prefixes of a pruned destination trie ++ * are added using this function. In such a case the destination nodes ++ * list always contains a node representing the given prefix. ++ * @param prefix Reference to the IP_prefix object that determines a ++ * source node of the edge towards the 't' node. ++ * @param weight Weight of the newly created edge. ++ */ ++ void add_t_prefix(const IP_prefix& prefix, const int weight); ++ ++ /* ++ * Modifies the filter graph such that it conforms with the flow network ++ * specification -- i.e., it has only one node without input edges (the ++ * 's' node) and only one node without output edges (the 't' node). ++ * First of all, the function removes all edges representing filters with ++ * at least one non-pruned prefix and all nodes representing non-pruned ++ * prefixes. During this step, the "pruned" flag of the remaining nodes ++ * is also set to false. Next, the filter graph is traversed in a BFS ++ * manner and the "pruned" flag is set to true for all visited nodes with ++ * at least one input edge and one output edge. Finally, the function ++ * removes all edges going from the 's' node/to the 't' node that do not ++ * end/start in a node with the set "pruned" flag. These non-pruned nodes ++ * are also removed from the graph in this final step. ++ * The function expects that all steps of the filter graph construction ++ * (i.e., adding filters, s-prefixes, and t-prefixes) have already been ++ * performed before its invocation. ++ */ ++ void to_flow_network(); ++ ++ /* ++ * Computes maximum flow using Dinic's algorithm. ++ * The function builds a flow network corresponding to the filter graph, ++ * transforms it to a level graph and updates the flow through the filter ++ * graph according to a blocking flow through the level graph. This way ++ * the flow through the filter graph is iteratively updated until there ++ * are paths from the 's' node to the 't' node in the level graph. ++ * The flow network is represented by an object of the Flow_network, ++ * which also allows transformation into the corresponding level graph. ++ * @return The value of the maximum flow through the filter graph. ++ */ ++ int max_flow(); ++ ++ /* ++ * Prints the filter graph. ++ */ ++ void print(); ++}; ++ ++#endif +diff --git a/flow_network.cc b/flow_network.cc +new file mode 100644 +index 0000000..b5523da +--- /dev/null ++++ b/flow_network.cc +@@ -0,0 +1,592 @@ ++// flow_network.cc: Flow_network class definition ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "flow_network.h" ++ ++// Library includes ++#include ++#include ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions (related to filter graph) ************************** ++ ++ ++/* ++ * Private static function that creates deep copy of the original list. ++ */ ++net_node_list_item* Flow_network::copy_node_list(const net_node_list_item* orig) { ++ // initialize pointer to copied node list ++ net_node_list_item* result = (orig == NULL) ? ++ NULL : ++ new net_node_list_item; ++ ++ // node list level of copying ++ net_node_list_item* copy = result; ++ while (orig != NULL) { ++ // list item members initialization ++ copy->prefix = orig->prefix; ++ copy->visited = orig->visited; ++ copy->neighbours = (orig->neighbours == NULL) ? ++ NULL : ++ new net_neighbour_list_item; ++ copy->next = (orig->next == NULL) ? ++ NULL : ++ new net_node_list_item; ++ ++ // neighbour list level of copying ++ net_neighbour_list_item* orig_neighbours = orig->neighbours; ++ net_neighbour_list_item* copy_neighbours = copy->neighbours; ++ while (orig_neighbours != NULL) { ++ // list item members initialization ++ copy_neighbours->src_node = copy; ++ copy_neighbours->dst_node = NULL; // cannot be initialized directly ++ // (points to different node list) ++ copy_neighbours->capacity = orig_neighbours->capacity; ++ copy_neighbours->flow = orig_neighbours->flow; ++ copy_neighbours->orig_edge = orig_neighbours->orig_edge; ++ copy_neighbours->forward_edge = orig_neighbours->forward_edge; ++ copy_neighbours->next = (orig_neighbours->next == NULL) ? ++ NULL : ++ new net_neighbour_list_item; ++ ++ // move to the next item of neighbour list ++ copy_neighbours = copy_neighbours->next; ++ orig_neighbours = orig_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ copy = copy->next; ++ orig = orig->next; ++ } ++ ++ return result; ++} // end copy_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole node list. ++ */ ++void Flow_network::remove_node_list(net_node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ net_neighbour_list_item* neighbours = list->neighbours; ++ ++ // traverse all neighbours ++ while (neighbours != NULL) { ++ // move to the next neighbour list item and deallocate the current one ++ net_neighbour_list_item* current_neighbour = neighbours; ++ neighbours = neighbours->next; ++ delete current_neighbour; ++ } ++ ++ // move to the next node list item and deallocate the current one ++ net_node_list_item* current_node = list; ++ list = list->next; ++ delete current_node; ++ } ++ ++ return; ++} // end remove_node_list() ++ ++ ++/* ++ * Private static function that sets correct values of destination node ++ * pointers, which cannot be correctly initialized during copying. ++ */ ++void Flow_network::set_destination_nodes(const net_node_list_item* orig, ++ net_node_list_item* copy, ++ net_node_list_item* prev, ++ net_node_list_item* next) { ++ // traverse all nodes ++ while (orig != NULL) { ++ net_neighbour_list_item* orig_neighbours = orig->neighbours; ++ net_neighbour_list_item* copy_neighbours = copy->neighbours; ++ ++ // traverse all neighbours ++ while (orig_neighbours != NULL) { ++ // set correct destination node pointer ++ if (orig_neighbours->forward_edge) { // forward edge ++ copy_neighbours->dst_node = ++ find_node(orig_neighbours->dst_node->prefix, next); ++ } else { // backward edge ++ copy_neighbours->dst_node = ++ find_node(orig_neighbours->dst_node->prefix, prev); ++ } ++ ++ // move to the next item of neighbour list ++ orig_neighbours = orig_neighbours->next; ++ copy_neighbours = copy_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ orig = orig->next; ++ copy = copy->next; ++ } ++ ++ return; ++} // end set_destination_nodes() ++ ++ ++/* ++ * Private static function that looks for node with the given prefix in the ++ * given list of nodes. ++ */ ++net_node_list_item* Flow_network::find_node(const IP_prefix& prefix, ++ net_node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ if (list->prefix == prefix) { ++ // corresponding node - return pointer to it ++ return list; ++ } else { ++ // node with different prefix - move to the next item of node list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding node was not found ++ return NULL; ++} // end find_node() ++ ++ ++/* ++ * Private static function that looks for the corresponding neighbour node in ++ * the given list of neighbours. ++ */ ++net_neighbour_list_item* Flow_network::find_neighbour( ++ const net_node_list_item* neighbour, ++ net_neighbour_list_item* list) { ++ // traverse all neighbour nodes ++ while (list != NULL) { ++ if (list->dst_node->prefix == neighbour->prefix) { ++ // corresponding neighbour node - return pointer to it ++ return list; ++ } else { ++ // neighbour node corresponding to different prefix node - move to the ++ // next item of neighbour list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding neighbour node was not found ++ return NULL; ++} // end find_neighbour() ++ ++ ++/* ++ * Private static function that inserts a node representing the given IP prefix ++ * at the beginning of the given list of nodes. ++ */ ++void Flow_network::insert_node(const IP_prefix& prefix, ++ net_node_list_item** list) { ++ // allocate and initialize new prefix node ++ net_node_list_item* node = new net_node_list_item; ++ node->prefix = prefix; ++ node->visited = false; ++ node->neighbours = NULL; ++ ++ // insert new prefix node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_node() ++ ++ ++/* ++ * Private static function that inserts a neighbour node representing an edge ++ * between the given source and destination nodes at the beginning of the ++ * specified list of neighbour nodes. ++ */ ++void Flow_network::insert_neighbour(net_node_list_item* src_node, ++ net_node_list_item* dst_node, ++ int capacity, ++ int flow, ++ neighbour_list_item* orig_edge, ++ bool forward_edge, ++ net_neighbour_list_item** list) { ++ // allocate and initialize new neighbour node ++ net_neighbour_list_item* node = new net_neighbour_list_item; ++ node->src_node = src_node; ++ node->dst_node = dst_node; ++ node->capacity = capacity; ++ node->flow = flow; ++ node->orig_edge = orig_edge; ++ node->forward_edge = forward_edge; ++ ++ // insert new neighbour node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_neighbour() ++ ++ ++/* ++ * Private static function that prints specified node list, including all ++ * sublists. ++ */ ++void Flow_network::print_node_list(const net_node_list_item* nodes) { ++ while (nodes != NULL) { ++ // print node list items ++ cout << "+-> " << nodes->prefix.get_prefix() << "/" ++ << nodes->prefix.get_length() << endl; ++ net_neighbour_list_item* neighbours = nodes->neighbours; ++ while (neighbours != NULL) { ++ // print neighbour list items ++ cout << "| +-> "; ++ if (neighbours->forward_edge) { // forward edge ++ cout << "FORWARD: "; ++ } else { // backward edge ++ cout << "BACKWARD: "; ++ } ++ cout << neighbours->src_node->prefix.get_prefix() << "/" ++ << neighbours->src_node->prefix.get_length() ++ << " --> " ++ << neighbours->dst_node->prefix.get_prefix() << "/" ++ << neighbours->dst_node->prefix.get_length() ++ << " " ++ << "(" ++ << neighbours->flow << "/" ++ << neighbours->capacity ++ << ")" << endl; ++ // move to the next neighbour ++ neighbours = neighbours->next; ++ } ++ // move to the next node ++ nodes = nodes->next; ++ } ++} // end print_node_list() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++/* ++ * Default constructor. ++ */ ++Flow_network::Flow_network() { ++ src_nodes = NULL; ++ dst_nodes = NULL; ++ s_node = NULL; ++ t_node = NULL; ++} // end Flow_network() ++ ++ ++/* ++ * Copy constructor. ++ */ ++Flow_network::Flow_network(const Flow_network& orig) { ++ // acquire members of the original object ++ const net_node_list_item* orig_src_nodes = orig.get_src_nodes(); ++ const net_node_list_item* orig_dst_nodes = orig.get_dst_nodes(); ++ const net_node_list_item* orig_s_node = orig.get_s_node(); ++ const net_node_list_item* orig_t_node = orig.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(orig_src_nodes); ++ dst_nodes = copy_node_list(orig_dst_nodes); ++ s_node = copy_node_list(orig_s_node); ++ t_node = copy_node_list(orig_t_node); ++ ++ // set pointers to neighbour nodes ++ set_destination_nodes(orig_t_node, t_node, dst_nodes, NULL); ++ set_destination_nodes(orig_dst_nodes, dst_nodes, src_nodes, t_node); ++ set_destination_nodes(orig_src_nodes, src_nodes, s_node, dst_nodes); ++ set_destination_nodes(orig_s_node, s_node, NULL, src_nodes); ++} // end Filter_graph() ++ ++ ++/* ++ * Copy assignment. ++ */ ++Flow_network& Flow_network::operator=(const Flow_network& copy) { ++ // destruct the original object ++ remove_node_list(s_node); ++ remove_node_list(src_nodes); ++ remove_node_list(dst_nodes); ++ remove_node_list(t_node); ++ ++ // acquire members of the copied object ++ const net_node_list_item* copy_src_nodes = copy.get_src_nodes(); ++ const net_node_list_item* copy_dst_nodes = copy.get_dst_nodes(); ++ const net_node_list_item* copy_s_node = copy.get_s_node(); ++ const net_node_list_item* copy_t_node = copy.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(copy_src_nodes); ++ dst_nodes = copy_node_list(copy_dst_nodes); ++ s_node = copy_node_list(copy_s_node); ++ t_node = copy_node_list(copy_t_node); ++ ++ // set pointers to neighbour nodes ++ set_destination_nodes(copy_t_node, t_node, dst_nodes, NULL); ++ set_destination_nodes(copy_dst_nodes, dst_nodes, src_nodes, t_node); ++ set_destination_nodes(copy_src_nodes, src_nodes, s_node, dst_nodes); ++ set_destination_nodes(copy_s_node, s_node, NULL, src_nodes); ++ ++ // return the original object with new content ++ return *this; ++} // end operator=() ++ ++ ++/* ++ * Destructor. ++ */ ++Flow_network::~Flow_network() { ++ remove_node_list(s_node); ++ remove_node_list(src_nodes); ++ remove_node_list(dst_nodes); ++ remove_node_list(t_node); ++} // end ~Flow_network() ++ ++ ++/* ++ * Adds an edge to the flow network. ++ */ ++void Flow_network::add_edge(const IP_prefix& src_prefix, int src_list, ++ const IP_prefix& dst_prefix, int dst_list, ++ neighbour_list_item* orig_edge, bool forward_edge, ++ int capacity) { ++ // get pointer to correct source node list pointer ++ net_node_list_item** src_list_ptr; ++ switch (src_list) { ++ case 0 : ++ src_list_ptr = &s_node; ++ break; ++ case 1 : ++ src_list_ptr = &src_nodes; ++ break; ++ case 2 : ++ src_list_ptr = &dst_nodes; ++ break; ++ case 3 : ++ src_list_ptr = &t_node; ++ break; ++ } ++ ++ // get pointer to correct destination node list pointer ++ net_node_list_item** dst_list_ptr; ++ switch (dst_list) { ++ case 0 : ++ dst_list_ptr = &s_node; ++ break; ++ case 1 : ++ dst_list_ptr = &src_nodes; ++ break; ++ case 2 : ++ dst_list_ptr = &dst_nodes; ++ break; ++ case 3 : ++ dst_list_ptr = &t_node; ++ break; ++ } ++ ++ // find source prefix node in the specified node list and insert such node ++ // if it does not exist ++ net_node_list_item* src_node = find_node(src_prefix, *src_list_ptr); ++ if (src_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(src_prefix, src_list_ptr); ++ src_node = *src_list_ptr; ++ } ++ ++ // find destination prefix node in the specified node list and insert such node ++ // if it does not exist ++ net_node_list_item* dst_node = find_node(dst_prefix, *dst_list_ptr); ++ if (dst_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(dst_prefix, dst_list_ptr); ++ dst_node = *dst_list_ptr; ++ } ++ ++ // find neighbour node corresponding to the filter and insert such node if ++ // it does not exist ++ net_neighbour_list_item* neighbour = find_neighbour(dst_node, ++ src_node->neighbours); ++ if (neighbour == NULL) { ++ // neighbour is inserted at the beginning of the list ++ insert_neighbour(src_node, dst_node, capacity, 0, orig_edge, ++ forward_edge, &(src_node->neighbours)); ++ } ++} // end add_edge() ++ ++ ++/* ++ * Transforms the flow network into a level graph. ++ */ ++void Flow_network::to_level_graph() { ++ ++ // initialize auxiliary variables ++ queue q; ++ stack s; ++ if (s_node != NULL) { ++ s_node->visited = true; ++ q.push(s_node); ++ } ++ ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue the front element of the queue ++ net_node_list_item* node = q.front(); ++ q.pop(); ++ // iterate through the list of node's neighbours ++ net_neighbour_list_item** neighbour_ptr = &(node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ // push a pointer to a pointer to the edge on the stack ++ s.push(neighbour_ptr); ++ // if it has not been visited yet, enqueue a pointer to the target ++ // node of this edge ++ if ((*neighbour_ptr)->dst_node->visited == false) { ++ (*neighbour_ptr)->dst_node->visited = true; ++ q.push((*neighbour_ptr)->dst_node); ++ } ++ // move to the next neighbour ++ neighbour_ptr = &((*neighbour_ptr)->next); ++ } ++ } ++ ++ // initialize a set of level graph nodes with the 't' node ++ list l; ++ l.push_front(t_node); ++ ++ // do an inverse breadth-first search ++ while (!s.empty()) { ++ // pop the top element of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ s.pop(); ++ // check if the dst_node already belongs to the level graph ++ net_node_list_item* dst_node = (*neighbour_ptr)->dst_node; ++ list::iterator i; ++ for (i = l.begin(); i != l.end(); ++i) { ++ if (*i == dst_node) { ++ break; ++ } ++ } ++ if (i != l.end()) { // dst_node belongs to the level graph ++ // add also src_node to the level graph ++ l.push_front((*neighbour_ptr)->src_node); ++ } else { // dst_node does not belong to the level graph ++ // remove the edge from the flow network ++ net_neighbour_list_item* edge = (*neighbour_ptr); ++ *neighbour_ptr = (*neighbour_ptr)->next; ++ delete edge; ++ } ++ } ++} // end to_level_graph() ++ ++ ++/* ++ * Finds a blocking flow in the flow network, adds its value to the ++ * current flow in the corresponding filter graph, and also returns its ++ * value. ++ */ ++int Flow_network::find_blocking_flow() { ++ // check if the flow network exists at all ++ if (s_node == NULL) { ++ return 0; ++ } ++ ++ int blocking_flow = 0; ++ while (1) { // inifinite loop with return statement inside ++ // initialize auxiliary variables ++ stack s; ++ stack s_capacity; ++ net_node_list_item* node = s_node; ++ // do a depth-first search ++ while (node != t_node) { ++ while (node->neighbours == NULL) { // no output edges - traverse back ++ if (s.empty()) { // the stack is empty - no way to traverse back ++ return blocking_flow; ++ } ++ // traverse back along the edge on the top of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ net_neighbour_list_item* neighbour = *neighbour_ptr; ++ node = neighbour->src_node; ++ // pop the top elements of both stacks ++ s.pop(); ++ s_capacity.pop(); ++ // remove back-traversed edge ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } ++ // push the first edge of the current node and its remaining capacity on ++ // the respective stacks ++ s.push(&(node->neighbours)); ++ s_capacity.push(node->neighbours->capacity - node->neighbours->flow); ++ // move forward along the edge - update the current node ++ node = node->neighbours->dst_node; ++ } ++ ++ // determine the smallest capacity among edges of the found path ++ int min_capacity = s_capacity.top(); ++ s_capacity.pop(); ++ while (!s_capacity.empty()) { ++ // pop the top element of the capacity stack ++ int capacity = s_capacity.top(); ++ s_capacity.pop(); ++ if (capacity < min_capacity) { // update the smallest capacity ++ min_capacity = capacity; ++ } ++ } ++ ++ // update the flow through the found path according to min_capacity value ++ while (!s.empty()) { ++ // pop the top element of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ s.pop(); ++ // update the flow in both the flow network and filter graph ++ net_neighbour_list_item* neighbour = *neighbour_ptr; ++ neighbour->flow += min_capacity; ++ if (neighbour->forward_edge) { // forward edge ++ neighbour->orig_edge->flow += min_capacity; ++ } else { // backward edge ++ neighbour->orig_edge->flow -= min_capacity; ++ } ++ // remove the edge if its remaining capacity decreases to 0 ++ if (neighbour->capacity == neighbour->flow) { ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } ++ } ++ ++ // update the value of blocking flow through the flow network ++ blocking_flow += min_capacity; ++ } ++} // end find_blocking_flow() ++ ++ ++/* ++ * Prints the flow network. ++ */ ++void Flow_network::print() { ++ cout << "S_NODE:" << endl; ++ print_node_list(s_node); ++ cout << "--------------------" << endl; ++ ++ cout << "SRC_NODES:" << endl; ++ print_node_list(src_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "DST_NODES:" << endl; ++ print_node_list(dst_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "T_NODE:" << endl; ++ print_node_list(t_node); ++ cout << "--------------------" << endl; ++} +diff --git a/flow_network.h b/flow_network.h +new file mode 100644 +index 0000000..df76c3f +--- /dev/null ++++ b/flow_network.h +@@ -0,0 +1,362 @@ ++// flow_network.h: header file for Flow_network class ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef FLOW_NETWORK_H ++#define FLOW_NETWORK_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++#include "filter_graph.h" ++ ++// Library includes ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++ ++// Forward declarations (including typedef) to resolve circular dependency ++typedef struct net_node_list_item net_node_list_item; ++typedef struct net_neighbour_list_item net_neighbour_list_item; ++ ++/* ++ * A structure representing an item in a list of network nodes. ++ */ ++struct net_node_list_item { ++ // IP prefix represented by this node ++ IP_prefix prefix; ++ ++ // Flag showing whether the node was already visited during a traversal ++ bool visited; ++ ++ // List of neighbours ++ net_neighbour_list_item* neighbours; ++ ++ // Next item in list of network nodes ++ net_node_list_item* next; ++}; ++ ++/* ++ * A structure representing an item in a list of neighbours of a network node. ++ */ ++struct net_neighbour_list_item { ++ // Pointer to source node within list of network nodes ++ net_node_list_item* src_node; ++ ++ // Pointer to destination node within list of network nodes ++ net_node_list_item* dst_node; ++ ++ // Residual capacity of flow network's edge between neighbouring nodes ++ int capacity; ++ ++ // Flow through flow network's edge between neighbouring nodes ++ int flow; ++ ++ // Pointer to corresponding edge in filter graph ++ // (the pointer is the same for both forward and backward edges) ++ neighbour_list_item* orig_edge; ++ ++ // Flag showing whether this node represents a forward edge ++ bool forward_edge; ++ ++ // Next item in list of neighbours ++ net_neighbour_list_item* next; ++}; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a flow network -- i.e., weighted directed graph ++ * with special source (s) and terminate (t) nodes -- over a filter graph. ++ */ ++class Flow_network { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * Lists of source and destination nodes of the flow network. ++ */ ++ net_node_list_item* src_nodes; ++ net_node_list_item* dst_nodes; ++ ++ /* ++ * Special nodes 's' and 't' of the flow network. ++ */ ++ net_node_list_item* s_node; ++ net_node_list_item* t_node; ++ ++ /* ++ * Private static function that creates a deep copy of the original list. ++ * The function creates new instances of all items from the original list ++ * (as well as their neighbours sublists) and sets the value of their ++ * components according to this original list. The only exception is a ++ * pointer to destination node, which is initialized to NULL (it points ++ * to different list, thus it cannot be initialized to correct value ++ * during copying). ++ * @param orig Pointer to the constant original node list. ++ * @return Pointer to the copy of the original node list. ++ */ ++ static net_node_list_item* copy_node_list(const net_node_list_item* orig); ++ ++ /* ++ * Private static function that correctly deallocates the whole node ++ * list. ++ * The function traverses the given list and all its sublists and ++ * starting from lists of neighbours it deallocates all the traversed ++ * list items. ++ * @ param list Pointer to node list that is to be deallocated. ++ */ ++ static void remove_node_list(net_node_list_item* list); ++ ++ /* ++ * Private static function that sets correct values of destination node ++ * pointers, which cannot be correctly initialized during copying. ++ * The function simultaneously traverses neighbours lists in the orig and ++ * copy node lists. For each destination node from the orig list it looks ++ * for a corresponding item in either prev (backward edges) or next ++ * (forward edges) node list and stores the pointer to this node to the ++ * current item in the copy list. ++ * @param orig Pointer to the constant original node list. ++ * @param copy Pointer to the copy of the original node list ++ * (destination node pointers of this list are set). ++ * @param prev Pointer to the list of destination nodes of backward ++ * edges. ++ * @param next Pointer to the list of destination nodes of forward ++ * edges. ++ */ ++ static void set_destination_nodes(const net_node_list_item* orig, ++ net_node_list_item* copy, ++ net_node_list_item* prev, ++ net_node_list_item* next); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for a node with the given prefix in ++ * the given list of nodes. ++ * @param prefix Reference to a constant IP prefix of the node that the ++ * function looks for in the list. ++ * @param list Pointer to the list of nodes that is traversed during ++ * looking for the node with the given IP prefix. ++ * @return Pointer to the found node or NULL. ++ */ ++ static net_node_list_item* find_node(const IP_prefix& prefix, ++ net_node_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the corresponding neighbour ++ * node in the given list of neighbours. ++ * @param neighbour Pointer to a constant prefix node whose neighbour ++ * node the function looks for in the list. ++ * @param list Pointer to the list of neighbour nodes that is ++ * traversed during looking for the node corresponding ++ * to the given prefix node. ++ * @return Pointer to the found neighbour node or NULL. ++ */ ++ static net_neighbour_list_item* find_neighbour( ++ const net_node_list_item* neighbour, ++ net_neighbour_list_item* list); ++ ++ /* ++ * Private static function that inserts a node representing the given IP ++ * prefix at the beginning of the given list of nodes. ++ * @param prefix Reference to a constant IP prefix that is going to be ++ * represented by the inserted node. ++ * @param list Pointer to pointer to the list of nodes that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_node(const IP_prefix& prefix, ++ net_node_list_item** list); ++ ++ /* ++ * Private static function that inserts a neighbour node representing an ++ * edge between the given source and destination nodes at the beginning ++ * of the specified list of neighbour nodes. ++ * @param src_node Pointer to a source node of the represented ++ * edge. ++ * @param dst_node Pointer to a destination node of the represented ++ * edge. ++ * @param capacity Residual capacity of the represented edge. ++ * @param flow Flow through the represented edge. ++ * @param orig_edge Pointer to the corresponding edge in the filter ++ * graph. ++ * @param forward_edge Flag showing whether the inserted neighbour ++ * represents a forward edge. ++ * @param list Pointer to pointer to the list of neighbours ++ * that is going to be extended by the inserted ++ * node. ++ */ ++ static void insert_neighbour(net_node_list_item* src_node, ++ net_node_list_item* dst_node, ++ int capacity, ++ int flow, ++ neighbour_list_item* orig_edge, ++ bool forward_edge, ++ net_neighbour_list_item** list); ++ ++ /* ++ * Private static function that prints specified node list, including all ++ * sublists. ++ * @param nodes Pointer to the constant list of nodes that is to be ++ * printed. ++ */ ++ static void print_node_list(const net_node_list_item* nodes); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * All pointers are initialized to NULL. ++ */ ++ Flow_network(); ++ ++ /* ++ * Copy constructor. ++ * All pointers used by the filter graph are initialized to a deep copy ++ * of corresponding members of the original object. ++ * @param orig Reference to the constant original object. ++ */ ++ Flow_network(const Flow_network& orig); ++ ++ /* ++ * Copy assignment. ++ * The original object is destructed and its new content is constructed ++ * in a similar way as in the copy constructor. ++ * @param copy Reference to the constant copied object. ++ * @return Reference to the original object with new content. ++ */ ++ Flow_network& operator= (const Flow_network& copy); ++ ++ /* ++ * Destructor. ++ * Correctly deallocates all lists that are referenced by object members. ++ */ ++ ~Flow_network(); ++ ++ /* ++ * Get function for the src_nodes member. ++ * @return Pointer to the constant list of source nodes. ++ */ ++ inline const net_node_list_item* get_src_nodes() const { ++ return src_nodes; ++ } // end get_src_nodes() ++ ++ /* ++ * Get function for the dst_nodes member. ++ * @return Pointer to the constant list of destination nodes. ++ */ ++ inline const net_node_list_item* get_dst_nodes() const { ++ return dst_nodes; ++ } // end get_dst_nodes() ++ ++ /* ++ * Get function for the s_node member. ++ * @return Pointer to the constant special 's' node. ++ */ ++ inline const net_node_list_item* get_s_node() const { ++ return s_node; ++ } // end get_s_node() ++ ++ /* ++ * Get function for the t_node member. ++ * @return Pointer to the constant special 't' node. ++ */ ++ inline const net_node_list_item* get_t_node() const { ++ return t_node; ++ } // end get_t_node() ++ ++ /* ++ * Adds an edge to the flow network. ++ * First of all, if they are not already present, the function inserts ++ * nodes representing src_prefix and dst_prefix into node lists src_list ++ * and dst_list, respectively. Next, if it is not already present, the ++ * function inserts a neighbour node representing the edge into the list ++ * of neighbours of the node representing the source prefix. Flow item of ++ * the neighbour node is set to 0, while other items within its structure ++ * are set according to the function's parameters. ++ * @param src_prefix Reference to the IP_prefix object that ++ * determines a source node of the added edge. ++ * @param src_list Specification of a node list that contains the ++ * source node of the added edge. Mapping of the ++ * four allowed values to the node lists is the ++ * following: ++ * 0 ... s_node ++ * 1 ... src_node ++ * 2 ... dst_node ++ * 3 ... t_node ++ * @param dst_prefix Reference to the IP_prefix object that ++ * determines a destination node of the added edge. ++ * @param dst_list Specification of a node list that contains the ++ * destination node of the added edge. Mapping of ++ * the four allowed values to the node lists is the ++ * following: ++ * 0 ... s_node ++ * 1 ... src_node ++ * 2 ... dst_node ++ * 3 ... t_node ++ * @param orig_edge Pointer to the corresponding edge in the filter ++ * graph. ++ * @param forward_edge Flag showing whether the added edge represents a ++ * forward edge. ++ * @param capacity Residual capacity of the added edge. ++ */ ++ void add_edge(const IP_prefix& src_prefix, int src_list, ++ const IP_prefix& dst_prefix, int dst_list, ++ neighbour_list_item* orig_edge, bool forward_edge, ++ int capacity); ++ ++ /* ++ * Transforms the flow network into a level graph. ++ * During inverse BFS of the flow network, starting from a set containing ++ * the 't' node, the function incrementally extends the set by start ++ * nodes of edges ending in one of the set nodes and removes from the ++ * flow network edges that do not meet this condition. ++ */ ++ void to_level_graph(); ++ ++ /* ++ * Finds a blocking flow in the flow network, adds its value to the ++ * current flow in the corresponding filter graph, and also returns its ++ * value. ++ * The function repeatedly performs DST to find an s-t path in the flow ++ * network and the smallest capacity on this path. Once the function ++ * reaches the 't' node, it returns along the found path and increases ++ * the flow through the particular flow network edges as well as the ++ * corresponding filter graph edges. The function also updates capacities ++ * of backward-traversed flow network edges and removes them in case ++ * their capacity decreases to 0. In case of DFS ending in a node other ++ * than the 't' node, the function traverses back to the closest node ++ * with at least two output edges and removes all back-traversed edges. ++ * After each successful DFS and flow update on the found path, the ++ * function increases the value of the total flow through the flow ++ * network, which is returned at the end. ++ * The function expects that the flow network is in the form of a level ++ * graph at the time of invocation. ++ * @return The value of the blocking flow through the flow network. ++ */ ++ int find_blocking_flow(); ++ ++ /* ++ * Prints the flow network. ++ */ ++ void print(); ++}; ++ ++#endif +diff --git a/ip-address/COPYING b/ip-address/COPYING +new file mode 100644 +index 0000000..03fc9f6 +--- /dev/null ++++ b/ip-address/COPYING +@@ -0,0 +1,4 @@ ++Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++ ++Distributed under the Boost Software License, Version 1.0. (See accompanying ++file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +diff --git a/ip-address/LICENSE_1_0.txt b/ip-address/LICENSE_1_0.txt +new file mode 100644 +index 0000000..36b7cd9 +--- /dev/null ++++ b/ip-address/LICENSE_1_0.txt +@@ -0,0 +1,23 @@ ++Boost Software License - Version 1.0 - August 17th, 2003 ++ ++Permission is hereby granted, free of charge, to any person or organization ++obtaining a copy of the software and accompanying documentation covered by ++this license (the "Software") to use, reproduce, display, distribute, ++execute, and transmit the Software, and to prepare derivative works of the ++Software, and to permit third-parties to whom the Software is furnished to ++do so, all subject to the following: ++ ++The copyright notices in the Software and this entire statement, including ++the above license grant, this restriction and the following disclaimer, ++must be included in all copies of the Software, in whole or in part, and ++all derivative works of the Software, unless such copies or derivative ++works are solely in the form of machine-executable object code generated by ++a source language processor. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT ++SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ++FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ++ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++DEALINGS IN THE SOFTWARE. +diff --git a/ip-address/README.md b/ip-address/README.md +new file mode 100644 +index 0000000..08ff928 +--- /dev/null ++++ b/ip-address/README.md +@@ -0,0 +1,18 @@ ++IP Address Proposal ++=================== ++ ++Proposed IP addresses classes for the standard C++ library. ++ ++What's Included ++--------------- ++ ++* `./include` - Reference implementation. ++ ++Tested Platforms ++---------------- ++ ++* Mac OS 10.8 using g++ 4.7 (requires `-std=c++11`) ++* Mac OS 10.8 using clang++ from Xcode 4.6 (requires `-std=c++11` and `-stdlib=libc++`) ++* Linux (CentOS 6.2) using g++ 4.7 (requires `-std=c++11`) ++* Windows 7 32-bit using Visual Studio 2010 ++* Windows 7 x64 using Visual Studio 2010 +diff --git a/ip-address/include/network b/ip-address/include/network +new file mode 100644 +index 0000000..c97ea69 +--- /dev/null ++++ b/ip-address/include/network +@@ -0,0 +1,25 @@ ++// ++// network ++// ~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_NETWORK_HEADER_FILE ++#define STDNET_NETWORK_HEADER_FILE ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++#include "std/net/ip/address_cast.hpp" ++#include "std/net/literals.hpp" ++ ++#endif // STDNET_NETWORK_HEADER_FILE +diff --git a/ip-address/include/std/net/detail/config.hpp b/ip-address/include/std/net/detail/config.hpp +new file mode 100644 +index 0000000..c797490 +--- /dev/null ++++ b/ip-address/include/std/net/detail/config.hpp +@@ -0,0 +1,666 @@ ++// ++// detail/config.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_CONFIG_HPP ++#define STDNET_DETAIL_CONFIG_HPP ++ ++// Default to a header-only implementation. The user must specifically request ++// separate compilation by defining either STDNET_SEPARATE_COMPILATION or ++// STDNET_DYN_LINK (as a DLL/shared library implies separate compilation). ++#if !defined(STDNET_HEADER_ONLY) ++# if !defined(STDNET_SEPARATE_COMPILATION) ++# if !defined(STDNET_DYN_LINK) ++# define STDNET_HEADER_ONLY 1 ++# endif // !defined(STDNET_DYN_LINK) ++# endif // !defined(STDNET_SEPARATE_COMPILATION) ++#endif // !defined(STDNET_HEADER_ONLY) ++ ++#if defined(STDNET_HEADER_ONLY) ++# define STDNET_DECL inline ++#else // defined(STDNET_HEADER_ONLY) ++# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) ++// We need to import/export our code only if the user has specifically asked ++// for it by defining STDNET_DYN_LINK. ++# if defined(STDNET_DYN_LINK) ++// Export if this is our own source, otherwise import. ++# if defined(STDNET_SOURCE) ++# define STDNET_DECL __declspec(dllexport) ++# else // defined(STDNET_SOURCE) ++# define STDNET_DECL __declspec(dllimport) ++# endif // defined(STDNET_SOURCE) ++# endif // defined(STDNET_DYN_LINK) ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) ++#endif // defined(STDNET_HEADER_ONLY) ++ ++// If STDNET_DECL isn't defined yet define it now. ++#if !defined(STDNET_DECL) ++# define STDNET_DECL ++#endif // !defined(STDNET_DECL) ++ ++// Microsoft Visual C++ detection. ++#if !defined(STDNET_MSVC) ++# if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__EDG_VERSION__) ++# define STDNET_MSVC _MSC_VER ++# endif // defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__EDG_VERSION__) ++#endif // defined(STDNET_MSVC) ++ ++// Support move construction and assignment on compilers known to allow it. ++#if !defined(STDNET_HAS_MOVE) ++# if !defined(STDNET_DISABLE_MOVE) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_MOVE 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_MOVE) ++#endif // !defined(STDNET_HAS_MOVE) ++ ++// If STDNET_MOVE_CAST isn't defined, and move support is available, define ++// STDNET_MOVE_ARG and STDNET_MOVE_CAST to take advantage of rvalue ++// references and perfect forwarding. ++#if defined(STDNET_HAS_MOVE) && !defined(STDNET_MOVE_CAST) ++# define STDNET_MOVE_ARG(type) type&& ++# define STDNET_MOVE_CAST(type) static_cast ++#endif // defined(STDNET_HAS_MOVE) && !defined(STDNET_MOVE_CAST) ++ ++// If STDNET_MOVE_CAST still isn't defined, default to a C++03-compatible ++// implementation. Note that older g++ and MSVC versions don't like it when you ++// pass a non-member function through a const reference, so for most compilers ++// we'll play it safe and stick with the old approach of passing the handler by ++// value. ++#if !defined(STDNET_MOVE_CAST) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# define STDNET_MOVE_ARG(type) const type& ++# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# define STDNET_MOVE_ARG(type) type ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# elif defined(STDNET_MSVC) ++# if (_MSC_VER >= 1400) ++# define STDNET_MOVE_ARG(type) const type& ++# else // (_MSC_VER >= 1400) ++# define STDNET_MOVE_ARG(type) type ++# endif // (_MSC_VER >= 1400) ++# else ++# define STDNET_MOVE_ARG(type) type ++# endif ++# define STDNET_MOVE_CAST(type) static_cast ++#endif // !defined_STDNET_MOVE_CAST ++ ++// Support variadic templates on compilers known to allow it. ++#if !defined(STDNET_HAS_VARIADIC_TEMPLATES) ++# if !defined(STDNET_DISABLE_VARIADIC_TEMPLATES) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_VARIADIC_TEMPLATES 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_variadic_templates) ++# define STDNET_HAS_VARIADIC_TEMPLATES 1 ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# endif // !defined(STDNET_DISABLE_VARIADIC_TEMPLATES) ++#endif // !defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++// Support the noexcept specifier on compilers known to allow it. ++#if !defined(STDNET_NOEXCEPT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_NOEXCEPT noexcept ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_noexcept) ++# define STDNET_NOEXCEPT noexcept ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_NOEXCEPT) ++# define STDNET_NOEXCEPT ++# endif // !defined(STDNET_NOEXCEPT) ++#endif // !defined(STDNET_NOEXCEPT) ++ ++// Support deleted functions on compilers known to allow it. ++#if !defined(STDNET_DELETED) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_DELETED = delete ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_deleted_functions) ++# define STDNET_DELETED = delete ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_DELETED) ++# define STDNET_DELETED ++# endif // !defined(STDNET_DELETED) ++#endif // !defined(STDNET_DELETED) ++ ++// Support relaxed constexpr on compilers known to allow it. ++#if !defined(STDNET_CONSTEXPR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_CONSTEXPR 1 ++# define STDNET_CONSTEXPR constexpr ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_constexpr) ++# define STDNET_HAS_CONSTEXPR 1 ++# define STDNET_CONSTEXPR constexpr ++# endif // __has_feature(cxx_constexpr) ++# endif // defined(__clang__) ++# if !defined(STDNET_CONSTEXPR) ++# define STDNET_CONSTEXPR ++# endif // !defined(STDNET_CONSTEXPR) ++#endif // !defined(STDNET_CONSTEXPR) ++ ++// Standard library support for system errors. ++#if !defined(STDNET_HAS_STD_SYSTEM_ERROR) ++# if !defined(STDNET_DISABLE_STD_SYSTEM_ERROR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_SYSTEM_ERROR 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_SYSTEM_ERROR) ++#endif // !defined(STDNET_HAS_STD_SYSTEM_ERROR) ++ ++// Compliant C++11 compilers put noexcept specifiers on error_category members. ++#if !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_noexcept) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT ++# endif // !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++#endif // !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++ ++// Standard library support for arrays. ++#if !defined(STDNET_HAS_STD_ARRAY) ++# if !defined(STDNET_DISABLE_STD_ARRAY) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ARRAY 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(STDNET_MSVC) ++# if (_MSC_VER >= 1600) ++# define STDNET_HAS_STD_ARRAY 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(STDNET_MSVC) ++# endif // !defined(STDNET_DISABLE_STD_ARRAY) ++#endif // !defined(STDNET_HAS_STD_ARRAY) ++ ++// Standard library support for shared_ptr and weak_ptr. ++#if !defined(STDNET_HAS_STD_SHARED_PTR) ++# if !defined(STDNET_DISABLE_STD_SHARED_PTR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_SHARED_PTR 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(STDNET_MSVC) ++# if (_MSC_VER >= 1600) ++# define STDNET_HAS_STD_SHARED_PTR 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(STDNET_MSVC) ++# endif // !defined(STDNET_DISABLE_STD_SHARED_PTR) ++#endif // !defined(STDNET_HAS_STD_SHARED_PTR) ++ ++// Standard library support for atomic operations. ++#if !defined(STDNET_HAS_STD_ATOMIC) ++# if !defined(STDNET_DISABLE_STD_ATOMIC) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ATOMIC 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_ATOMIC) ++#endif // !defined(STDNET_HAS_STD_ATOMIC) ++ ++// Standard library support for chrono. Some standard libraries (such as the ++// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x ++// drafts, rather than the eventually standardised name of steady_clock. ++#if !defined(STDNET_HAS_STD_CHRONO) ++# if !defined(STDNET_DISABLE_STD_CHRONO) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_CHRONO 1 ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) ++# define STDNET_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_CHRONO) ++#endif // !defined(STDNET_HAS_STD_CHRONO) ++ ++// Standard library support for addressof. ++#if !defined(STDNET_HAS_STD_ADDRESSOF) ++# if !defined(STDNET_DISABLE_STD_ADDRESSOF) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ADDRESSOF 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_ADDRESSOF) ++#endif // !defined(STDNET_HAS_STD_ADDRESSOF) ++ ++// Standard library support for the function class. ++#if !defined(STDNET_HAS_STD_FUNCTION) ++# if !defined(STDNET_DISABLE_STD_FUNCTION) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_FUNCTION 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_FUNCTION) ++#endif // !defined(STDNET_HAS_STD_FUNCTION) ++ ++// Standard library support for type traits. ++#if !defined(STDNET_HAS_STD_TYPE_TRAITS) ++# if !defined(STDNET_DISABLE_STD_TYPE_TRAITS) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_TYPE_TRAITS 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_TYPE_TRAITS) ++#endif // !defined(STDNET_HAS_STD_TYPE_TRAITS) ++ ++// Standard library support for the cstdint header. ++#if !defined(STDNET_HAS_CSTDINT) ++# if !defined(STDNET_DISABLE_CSTDINT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_CSTDINT 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_CSTDINT) ++#endif // !defined(STDNET_HAS_CSTDINT) ++ ++// Windows target. ++#if !defined(STDNET_WINDOWS) ++# if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ++# define STDNET_WINDOWS 1 ++# endif // defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ++#endif // !defined(STDNET_WINDOWS) ++ ++// Windows: target OS version. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) ++# if defined(_MSC_VER) || defined(__BORLANDC__) ++# pragma message( \ ++ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ ++ "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ ++ "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ ++ "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") ++# else // defined(_MSC_VER) || defined(__BORLANDC__) ++# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. ++# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. ++# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) ++# define _WIN32_WINNT 0x0501 ++# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) ++# if defined(_MSC_VER) ++# if defined(_WIN32) && !defined(WIN32) ++# if !defined(_WINSOCK2API_) ++# define WIN32 // Needed for correct types in winsock2.h ++# else // !defined(_WINSOCK2API_) ++# error Please define the macro WIN32 in your compiler options ++# endif // !defined(_WINSOCK2API_) ++# endif // defined(_WIN32) && !defined(WIN32) ++# endif // defined(_MSC_VER) ++# if defined(__BORLANDC__) ++# if defined(__WIN32__) && !defined(WIN32) ++# if !defined(_WINSOCK2API_) ++# define WIN32 // Needed for correct types in winsock2.h ++# else // !defined(_WINSOCK2API_) ++# error Please define the macro WIN32 in your compiler options ++# endif // !defined(_WINSOCK2API_) ++# endif // defined(__WIN32__) && !defined(WIN32) ++# endif // defined(__BORLANDC__) ++# if defined(__CYGWIN__) ++# if !defined(__USE_W32_SOCKETS) ++# error You must add -D__USE_W32_SOCKETS to your compiler options. ++# endif // !defined(__USE_W32_SOCKETS) ++# endif // defined(__CYGWIN__) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: minimise header inclusion. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(STDNET_NO_WIN32_LEAN_AND_MEAN) ++# if !defined(WIN32_LEAN_AND_MEAN) ++# define WIN32_LEAN_AND_MEAN ++# endif // !defined(WIN32_LEAN_AND_MEAN) ++# endif // !defined(STDNET_NO_WIN32_LEAN_AND_MEAN) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: suppress definition of "min" and "max" macros. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(STDNET_NO_NOMINMAX) ++# if !defined(NOMINMAX) ++# define NOMINMAX 1 ++# endif // !defined(NOMINMAX) ++# endif // !defined(STDNET_NO_NOMINMAX) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: No ANSI API calls. ++#if !defined(STDNET_NO_ANSI_APIS) ++# if defined(STDNET_WINDOWS) && defined(UNDER_CE) ++# define STDNET_NO_ANSI_APIS 1 ++# endif // defined(STDNET_WINDOWS) && defined(UNDER_CE) ++#endif // !defined(STDNET_NO_ANSI_APIS) ++ ++// Windows: IO Completion Ports. ++#if !defined(STDNET_HAS_IOCP) ++# if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) ++# if !defined(UNDER_CE) ++# if !defined(STDNET_DISABLE_IOCP) ++# define STDNET_HAS_IOCP 1 ++# endif // !defined(STDNET_DISABLE_IOCP) ++# endif // !defined(UNDER_CE) ++# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) ++# endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++#endif // !defined(STDNET_HAS_IOCP) ++ ++// Linux: epoll, eventfd and timerfd. ++#if defined(__linux__) ++# include ++# if !defined(STDNET_HAS_EPOLL) ++# if !defined(STDNET_DISABLE_EPOLL) ++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) ++# define STDNET_HAS_EPOLL 1 ++# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) ++# endif // !defined(STDNET_DISABLE_EPOLL) ++# endif // !defined(STDNET_HAS_EPOLL) ++# if !defined(STDNET_HAS_EVENTFD) ++# if !defined(STDNET_DISABLE_EVENTFD) ++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++# define STDNET_HAS_EVENTFD 1 ++# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++# endif // !defined(STDNET_DISABLE_EVENTFD) ++# endif // !defined(STDNET_HAS_EVENTFD) ++# if !defined(STDNET_HAS_TIMERFD) ++# if defined(STDNET_HAS_EPOLL) ++# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) ++# define STDNET_HAS_TIMERFD 1 ++# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) ++# endif // defined(STDNET_HAS_EPOLL) ++# endif // !defined(STDNET_HAS_TIMERFD) ++#endif // defined(__linux__) ++ ++// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. ++#if (defined(__MACH__) && defined(__APPLE__)) \ ++ || defined(__FreeBSD__) \ ++ || defined(__NetBSD__) \ ++ || defined(__OpenBSD__) ++# if !defined(STDNET_HAS_KQUEUE) ++# if !defined(STDNET_DISABLE_KQUEUE) ++# define STDNET_HAS_KQUEUE 1 ++# endif // !defined(STDNET_DISABLE_KQUEUE) ++# endif // !defined(STDNET_HAS_KQUEUE) ++#endif // (defined(__MACH__) && defined(__APPLE__)) ++ // || defined(__FreeBSD__) ++ // || defined(__NetBSD__) ++ // || defined(__OpenBSD__) ++ ++// Solaris: /dev/poll. ++#if defined(__sun) ++# if !defined(STDNET_HAS_DEV_POLL) ++# if !defined(STDNET_DISABLE_DEV_POLL) ++# define STDNET_HAS_DEV_POLL 1 ++# endif // !defined(STDNET_DISABLE_DEV_POLL) ++# endif // !defined(STDNET_HAS_DEV_POLL) ++#endif // defined(__sun) ++ ++// Serial ports. ++#if !defined(STDNET_HAS_SERIAL_PORT) ++# if defined(STDNET_HAS_IOCP) \ ++ || !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# if !defined(__SYMBIAN32__) ++# if !defined(STDNET_DISABLE_SERIAL_PORT) ++# define STDNET_HAS_SERIAL_PORT 1 ++# endif // !defined(STDNET_DISABLE_SERIAL_PORT) ++# endif // !defined(__SYMBIAN32__) ++# endif // defined(STDNET_HAS_IOCP) ++ // || !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++#endif // !defined(STDNET_HAS_SERIAL_PORT) ++ ++// Windows: stream handles. ++#if !defined(STDNET_HAS_WINDOWS_STREAM_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_STREAM_HANDLE) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_STREAM_HANDLE 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_STREAM_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_STREAM_HANDLE) ++ ++// Windows: random access handles. ++#if !defined(STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++ ++// Windows: object handles. ++#if !defined(STDNET_HAS_WINDOWS_OBJECT_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_OBJECT_HANDLE) ++# if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(UNDER_CE) ++# define STDNET_HAS_WINDOWS_OBJECT_HANDLE 1 ++# endif // !defined(UNDER_CE) ++# endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_WINDOWS_OBJECT_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_OBJECT_HANDLE) ++ ++// Windows: OVERLAPPED wrapper. ++#if !defined(STDNET_HAS_WINDOWS_OVERLAPPED_PTR) ++# if !defined(STDNET_DISABLE_WINDOWS_OVERLAPPED_PTR) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_OVERLAPPED_PTR 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_OVERLAPPED_PTR) ++#endif // !defined(STDNET_HAS_WINDOWS_OVERLAPPED_PTR) ++ ++// POSIX: stream-oriented file descriptors. ++#if !defined(STDNET_HAS_POSIX_STREAM_DESCRIPTOR) ++# if !defined(STDNET_DISABLE_POSIX_STREAM_DESCRIPTOR) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_POSIX_STREAM_DESCRIPTOR 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_POSIX_STREAM_DESCRIPTOR) ++#endif // !defined(STDNET_HAS_POSIX_STREAM_DESCRIPTOR) ++ ++// UNIX domain sockets. ++#if !defined(STDNET_HAS_LOCAL_SOCKETS) ++# if !defined(STDNET_DISABLE_LOCAL_SOCKETS) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_LOCAL_SOCKETS 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_LOCAL_SOCKETS) ++#endif // !defined(STDNET_HAS_LOCAL_SOCKETS) ++ ++// Can use sigaction() instead of signal(). ++#if !defined(STDNET_HAS_SIGACTION) ++# if !defined(STDNET_DISABLE_SIGACTION) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_SIGACTION 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_SIGACTION) ++#endif // !defined(STDNET_HAS_SIGACTION) ++ ++// Can use signal(). ++#if !defined(STDNET_HAS_SIGNAL) ++# if !defined(STDNET_DISABLE_SIGNAL) ++# if !defined(UNDER_CE) ++# define STDNET_HAS_SIGNAL 1 ++# endif // !defined(UNDER_CE) ++# endif // !defined(STDNET_DISABLE_SIGNAL) ++#endif // !defined(STDNET_HAS_SIGNAL) ++ ++// Whether standard iostreams are disabled. ++//#if !defined(STDNET_NO_IOSTREAM) ++//# define STDNET_NO_IOSTREAM 1 ++//#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// Whether exception handling is disabled. ++//#if !defined(STDNET_NO_EXCEPTIONS) ++//# define STDNET_NO_EXCEPTIONS 1 ++//#endif // !defined(STDNET_NO_EXCEPTIONS) ++ ++// Whether the typeid operator is supported. ++//#if !defined(STDNET_NO_TYPEID) ++//# define STDNET_NO_TYPEID 1 ++//#endif // !defined(STDNET_NO_TYPEID) ++ ++// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to ++// get access to the various platform feature macros, e.g. to be able to test ++// for threads support. ++#if !defined(STDNET_HAS_UNISTD_H) ++# if defined(unix) \ ++ || defined(__unix) \ ++ || defined(_XOPEN_SOURCE) \ ++ || defined(_POSIX_SOURCE) \ ++ || (defined(__MACH__) && defined(__APPLE__)) \ ++ || defined(__FreeBSD__) \ ++ || defined(__NetBSD__) \ ++ || defined(__OpenBSD__) \ ++ || defined(__linux__) ++# define STDNET_HAS_UNISTD_H 1 ++# endif ++#endif // !defined(STDNET_HAS_UNISTD_H) ++#if defined(STDNET_HAS_UNISTD_H) ++# include ++#endif // defined(STDNET_HAS_UNISTD_H) ++ ++// Threads. ++#if !defined(STDNET_HAS_THREADS) ++# if !defined(STDNET_DISABLE_THREADS) ++# if defined(_MSC_VER) && defined(_MT) ++# define STDNET_HAS_THREADS 1 ++# elif defined(__BORLANDC__) && defined(__MT__) ++# define STDNET_HAS_THREADS 1 ++# elif defined(_POSIX_THREADS) ++# define STDNET_HAS_THREADS 1 ++# endif // defined(_MSC_VER) && defined(_MT) ++# endif // !defined(STDNET_DISABLE_THREADS) ++#endif // !defined(STDNET_HAS_THREADS) ++ ++// POSIX threads. ++#if !defined(STDNET_HAS_PTHREADS) ++# if defined(STDNET_HAS_THREADS) ++# if defined(_POSIX_THREADS) ++# define STDNET_HAS_PTHREADS 1 ++# endif // defined(_POSIX_THREADS) ++# endif // defined(STDNET_HAS_THREADS) ++#endif // !defined(STDNET_HAS_PTHREADS) ++ ++// Helper to prevent macro expansion. ++#define STDNET_PREVENT_MACRO_SUBSTITUTION ++ ++// Helper to define in-class constants. ++#if !defined(STDNET_STATIC_CONSTANT) ++# define STDNET_STATIC_CONSTANT(type, assignment) \ ++ static const type assignment ++#endif // !defined(STDNET_STATIC_CONSTANT) ++ ++// Microsoft Visual C++'s secure C runtime library. ++#if !defined(STDNET_HAS_SECURE_RTL) ++# if !defined(STDNET_DISABLE_SECURE_RTL) ++# if defined(STDNET_MSVC) \ ++ && (STDNET_MSVC >= 1400) \ ++ && !defined(UNDER_CE) ++# define STDNET_HAS_SECURE_RTL 1 ++# endif // defined(STDNET_MSVC) ++ // && (STDNET_MSVC >= 1400) ++ // && !defined(UNDER_CE) ++# endif // !defined(STDNET_DISABLE_SECURE_RTL) ++#endif // !defined(STDNET_HAS_SECURE_RTL) ++ ++// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. ++#if !defined(STDNET_HAS_HANDLER_HOOKS) ++# if !defined(STDNET_DISABLE_HANDLER_HOOKS) ++# if defined(__GNUC__) ++# if (__GNUC__ >= 3) ++# define STDNET_HAS_HANDLER_HOOKS 1 ++# endif // (__GNUC__ >= 3) ++# elif !defined(__BORLANDC__) ++# define STDNET_HAS_HANDLER_HOOKS 1 ++# endif // !defined(__BORLANDC__) ++# endif // !defined(STDNET_DISABLE_HANDLER_HOOKS) ++#endif // !defined(STDNET_HAS_HANDLER_HOOKS) ++ ++// Support for the __thread keyword extension. ++#if !defined(STDNET_DISABLE_THREAD_KEYWORD_EXTENSION) ++# if defined(__linux__) ++# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) ++# if !defined(__INTEL_COMPILER) && !defined(__ICL) ++# define STDNET_HAS_THREAD_KEYWORD_EXTENSION 1 ++# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) ++# define STDNET_HAS_THREAD_KEYWORD_EXTENSION 1 ++# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) ++# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) ++# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++# endif // defined(__linux__) ++#endif // !defined(STDNET_DISABLE_THREAD_KEYWORD_EXTENSION) ++ ++// Support for POSIX ssize_t typedef. ++#if !defined(STDNET_DISABLE_SSIZE_T) ++# if defined(__linux__) \ ++ || (defined(__MACH__) && defined(__APPLE__)) ++# define STDNET_HAS_SSIZE_T 1 ++# endif // defined(__linux__) ++ // || (defined(__MACH__) && defined(__APPLE__)) ++#endif // !defined(STDNET_DISABLE_SSIZE_T) ++ ++#endif // STDNET_DETAIL_CONFIG_HPP +diff --git a/ip-address/include/std/net/detail/impl/socket_ops.ipp b/ip-address/include/std/net/detail/impl/socket_ops.ipp +new file mode 100644 +index 0000000..13b32a3 +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/socket_ops.ipp +@@ -0,0 +1,260 @@ ++// ++// detail/impl/socket_ops.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_OPS_IPP ++#define STDNET_DETAIL_SOCKET_OPS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include ++#include ++#include ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace socket_ops { ++ ++#if defined(__hpux) ++// HP-UX doesn't declare these functions extern "C", so they are declared again ++// here to avoid linker errors about undefined symbols. ++extern "C" char* if_indextoname(unsigned int, char*); ++extern "C" unsigned int if_nametoindex(const char*); ++#endif // defined(__hpux) ++ ++inline void clear_last_error() ++{ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ WSASetLastError(0); ++#else ++ errno = 0; ++#endif ++} ++ ++template ++inline ReturnType error_wrapper(ReturnType return_value, ++ std::error_code& ec) ++{ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ec = std::error_code(WSAGetLastError(), ++ std::experimental::net::detail::syserrc::system_category()); ++#else ++ ec = std::error_code(errno, ++ std::experimental::net::detail::syserrc::system_category()); ++#endif ++ return return_value; ++} ++ ++const char* inet_ntop(int af, const void* src, char* dest, size_t length, ++ unsigned long scope_id, std::error_code& ec) ++{ ++ clear_last_error(); ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ using namespace std; // For memcpy. ++ ++ if (af != AF_INET && af != AF_INET6) ++ { ++ ec = std::experimental::net::detail::syserrc::address_family_not_supported; ++ return 0; ++ } ++ ++ union ++ { ++ socket_addr_type base; ++ sockaddr_storage_type storage; ++ sockaddr_in4_type v4; ++ sockaddr_in6_type v6; ++ } address; ++ DWORD address_length; ++ if (af == AF_INET) ++ { ++ address_length = sizeof(sockaddr_in4_type); ++ address.v4.sin_family = AF_INET; ++ address.v4.sin_port = 0; ++ memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); ++ } ++ else // AF_INET6 ++ { ++ address_length = sizeof(sockaddr_in6_type); ++ address.v6.sin6_family = AF_INET6; ++ address.v6.sin6_port = 0; ++ address.v6.sin6_flowinfo = 0; ++ address.v6.sin6_scope_id = scope_id; ++ memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); ++ } ++ ++ DWORD string_length = static_cast(length); ++#if defined(STDNET_NO_ANSI_APIS) ++ LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); ++ int result = error_wrapper(::WSAAddressToStringW(&address.base, ++ address_length, 0, string_buffer, &string_length), ec); ++ ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); ++#else ++ int result = error_wrapper(::WSAAddressToStringA( ++ &address.base, address_length, 0, dest, &string_length), ec); ++#endif ++ ++ // Windows may set error code on success. ++ if (result != socket_error_retval) ++ ec = std::error_code(); ++ ++ // Windows may not set an error code on failure. ++ else if (result == socket_error_retval && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ ++ return result == socket_error_retval ? 0 : dest; ++#else // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ const char* result = error_wrapper(::inet_ntop( ++ af, src, dest, static_cast(length)), ec); ++ if (result == 0 && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ if (result != 0 && af == AF_INET6 && scope_id != 0) ++ { ++ using namespace std; // For strcat and sprintf. ++ char if_name[IF_NAMESIZE + 1] = "%"; ++ const in6_addr_type* ipv6_address = static_cast(src); ++ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) ++ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); ++ if (!is_link_local ++ || if_indextoname(static_cast(scope_id), if_name + 1) == 0) ++ sprintf(if_name + 1, "%lu", scope_id); ++ strcat(dest, if_name); ++ } ++ return result; ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++} ++ ++int inet_pton(int af, const char* src, void* dest, ++ unsigned long* scope_id, std::error_code& ec) ++{ ++ clear_last_error(); ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ using namespace std; // For memcpy and strcmp. ++ ++ if (af != AF_INET && af != AF_INET6) ++ { ++ ec = std::experimental::net::detail::syserrc::address_family_not_supported; ++ return -1; ++ } ++ ++ union ++ { ++ socket_addr_type base; ++ sockaddr_storage_type storage; ++ sockaddr_in4_type v4; ++ sockaddr_in6_type v6; ++ } address; ++ int address_length = sizeof(sockaddr_storage_type); ++#if defined(STDNET_NO_ANSI_APIS) ++ int num_wide_chars = strlen(src) + 1; ++ LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); ++ ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); ++ int result = error_wrapper(::WSAStringToAddressW( ++ wide_buffer, af, 0, &address.base, &address_length), ec); ++#else ++ int result = error_wrapper(::WSAStringToAddressA( ++ const_cast(src), af, 0, &address.base, &address_length), ec); ++#endif ++ ++ if (af == AF_INET) ++ { ++ if (result != socket_error_retval) ++ { ++ memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); ++ ec = std::error_code(); ++ } ++ else if (strcmp(src, "255.255.255.255") == 0) ++ { ++ static_cast(dest)->s_addr = INADDR_NONE; ++ ec = std::error_code(); ++ } ++ } ++ else // AF_INET6 ++ { ++ if (result != socket_error_retval) ++ { ++ memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); ++ if (scope_id) ++ *scope_id = address.v6.sin6_scope_id; ++ ec = std::error_code(); ++ } ++ } ++ ++ // Windows may not set an error code on failure. ++ if (result == socket_error_retval && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ ++ if (result != socket_error_retval) ++ ec = std::error_code(); ++ ++ return result == socket_error_retval ? -1 : 1; ++#else // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ int result = error_wrapper(::inet_pton(af, src, dest), ec); ++ if (result <= 0 && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ if (result > 0 && af == AF_INET6 && scope_id) ++ { ++ using namespace std; // For strchr and atoi. ++ *scope_id = 0; ++ if (const char* if_name = strchr(src, '%')) ++ { ++ in6_addr_type* ipv6_address = static_cast(dest); ++ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) ++ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); ++ if (is_link_local) ++ *scope_id = if_nametoindex(if_name + 1); ++ if (*scope_id == 0) ++ *scope_id = atoi(if_name + 1); ++ } ++ } ++ return result; ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++} ++ ++u_long_type network_to_host_long(u_long_type value) ++{ ++ return ntohl(value); ++} ++ ++u_long_type host_to_network_long(u_long_type value) ++{ ++ return htonl(value); ++} ++ ++u_short_type network_to_host_short(u_short_type value) ++{ ++ return ntohs(value); ++} ++ ++u_short_type host_to_network_short(u_short_type value) ++{ ++ return htons(value); ++} ++ ++} // namespace socket_ops ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_SOCKET_OPS_IPP +diff --git a/ip-address/include/std/net/detail/impl/system_errors.ipp b/ip-address/include/std/net/detail/impl/system_errors.ipp +new file mode 100644 +index 0000000..8b01e08 +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/system_errors.ipp +@@ -0,0 +1,94 @@ ++// ++// impl/system_errors.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP ++#define STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/local_free_on_block_exit.hpp" ++#include "std/net/detail/system_errors.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++class system_category : public std::error_category ++{ ++public: ++ const char* name() const STDNET_ERROR_CATEGORY_NOEXCEPT ++ { ++ return "std.net.system"; ++ } ++ ++ std::string message(int value) const ++ { ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ char* msg = 0; ++ DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER ++ | FORMAT_MESSAGE_FROM_SYSTEM ++ | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value, ++ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0); ++ detail::local_free_on_block_exit local_free_obj(msg); ++ if (length && msg[length - 1] == '\n') ++ msg[--length] = '\0'; ++ if (length && msg[length - 1] == '\r') ++ msg[--length] = '\0'; ++ if (length) ++ return msg; ++ else ++ return "std.net.system error"; ++#else // defined(STDNET_WINDOWS) ++#if !defined(__sun) ++ if (value == ECANCELED) ++ return "Operation aborted."; ++#endif // !defined(__sun) ++#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__) ++ using namespace std; ++ return strerror(value); ++#elif defined(__MACH__) && defined(__APPLE__) \ ++ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ ++ || defined(_AIX) || defined(__hpux) || defined(__osf__) \ ++ || defined(__ANDROID__) ++ char buf[256] = ""; ++ using namespace std; ++ strerror_r(value, buf, sizeof(buf)); ++ return buf; ++#else ++ char buf[256] = ""; ++ return strerror_r(value, buf, sizeof(buf)); ++#endif ++#endif // defined(STDNET_WINDOWS) ++ } ++}; ++ ++} // namespace syserrc ++ ++const std::error_category& system_category() ++{ ++ static syserrc::system_category instance; ++ return instance; ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP +diff --git a/ip-address/include/std/net/detail/impl/throw_error.ipp b/ip-address/include/std/net/detail/impl/throw_error.ipp +new file mode 100644 +index 0000000..92baf1c +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/throw_error.ipp +@@ -0,0 +1,49 @@ ++// ++// detail/impl/throw_error.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_THROW_ERROR_IPP ++#define STDNET_DETAIL_IMPL_THROW_ERROR_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++void do_throw_error(const std::error_code& err) ++{ ++ std::system_error e(err); ++ std::experimental::net::detail::throw_exception(e); ++} ++ ++void do_throw_error(const std::error_code& err, const char* location) ++{ ++ std::system_error e(err, location); ++ std::experimental::net::detail::throw_exception(e); ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_IMPL_THROW_ERROR_IPP +diff --git a/ip-address/include/std/net/detail/impl/winsock_init.ipp b/ip-address/include/std/net/detail/impl/winsock_init.ipp +new file mode 100644 +index 0000000..7114f6a +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/winsock_init.ipp +@@ -0,0 +1,73 @@ ++// ++// detail/impl/winsock_init.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP ++#define STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/socket_types.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/winsock_init.hpp" ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++void winsock_init_base::startup(data& d, ++ unsigned char major, unsigned char minor) ++{ ++ if (::InterlockedIncrement(&d.init_count_) == 1) ++ { ++ WSADATA wsa_data; ++ long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); ++ ::InterlockedExchange(&d.result_, result); ++ } ++} ++ ++void winsock_init_base::cleanup(data& d) ++{ ++ if (::InterlockedDecrement(&d.init_count_) == 0) ++ { ++ ::WSACleanup(); ++ } ++} ++ ++void winsock_init_base::throw_on_error(data& d) ++{ ++ long result = ::InterlockedExchangeAdd(&d.result_, 0); ++ if (result != 0) ++ { ++ std::error_code ec(result, ++ std::experimental::net::detail::system_category()); ++ std::experimental::net::detail::throw_error(ec, "winsock"); ++ } ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP +diff --git a/ip-address/include/std/net/detail/local_free_on_block_exit.hpp b/ip-address/include/std/net/detail/local_free_on_block_exit.hpp +new file mode 100644 +index 0000000..64c9137 +--- /dev/null ++++ b/ip-address/include/std/net/detail/local_free_on_block_exit.hpp +@@ -0,0 +1,63 @@ ++// ++// detail/local_free_on_block_exit.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP ++#define STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/socket_types.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++class local_free_on_block_exit ++{ ++public: ++ // Constructor blocks all signals for the calling thread. ++ explicit local_free_on_block_exit(void* p) ++ : p_(p) ++ { ++ } ++ ++ // Destructor restores the previous signal mask. ++ ~local_free_on_block_exit() ++ { ++ ::LocalFree(p_); ++ } ++ ++private: ++ // Disallow copying and assignemnt. ++ local_free_on_block_exit(const local_free_on_block_exit&); ++ local_free_on_block_exit& operator=(const local_free_on_block_exit&); ++ ++ void* p_; ++}; ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP +diff --git a/ip-address/include/std/net/detail/old_win_sdk_compat.hpp b/ip-address/include/std/net/detail/old_win_sdk_compat.hpp +new file mode 100644 +index 0000000..3a3cdac +--- /dev/null ++++ b/ip-address/include/std/net/detail/old_win_sdk_compat.hpp +@@ -0,0 +1,218 @@ ++// ++// detail/old_win_sdk_compat.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP ++#define STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Guess whether we are building against on old Platform SDK. ++#if !defined(IN6ADDR_ANY_INIT) ++#define STDNET_HAS_OLD_WIN_SDK 1 ++#endif // !defined(IN6ADDR_ANY_INIT) ++ ++#if defined(STDNET_HAS_OLD_WIN_SDK) ++ ++// Emulation of types that are missing from old Platform SDKs. ++// ++// N.B. this emulation is also used if building for a Windows 2000 target with ++// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support ++// in that case. ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++enum ++{ ++ sockaddr_storage_maxsize = 128, // Maximum size. ++ sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment. ++ sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)), ++ sockaddr_storage_pad2size = (sockaddr_storage_maxsize - ++ (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize)) ++}; ++ ++struct sockaddr_storage_emulation ++{ ++ short ss_family; ++ char __ss_pad1[sockaddr_storage_pad1size]; ++ __int64 __ss_align; ++ char __ss_pad2[sockaddr_storage_pad2size]; ++}; ++ ++struct in6_addr_emulation ++{ ++ union ++ { ++ u_char Byte[16]; ++ u_short Word[8]; ++ } u; ++}; ++ ++#if !defined(s6_addr) ++# define _S6_un u ++# define _S6_u8 Byte ++# define s6_addr _S6_un._S6_u8 ++#endif // !defined(s6_addr) ++ ++struct sockaddr_in6_emulation ++{ ++ short sin6_family; ++ u_short sin6_port; ++ u_long sin6_flowinfo; ++ in6_addr_emulation sin6_addr; ++ u_long sin6_scope_id; ++}; ++ ++struct ipv6_mreq_emulation ++{ ++ in6_addr_emulation ipv6mr_multiaddr; ++ unsigned int ipv6mr_interface; ++}; ++ ++struct addrinfo_emulation ++{ ++ int ai_flags; ++ int ai_family; ++ int ai_socktype; ++ int ai_protocol; ++ size_t ai_addrlen; ++ char* ai_canonname; ++ sockaddr* ai_addr; ++ addrinfo_emulation* ai_next; ++}; ++ ++#if !defined(AI_PASSIVE) ++# define AI_PASSIVE 0x1 ++#endif ++ ++#if !defined(AI_CANONNAME) ++# define AI_CANONNAME 0x2 ++#endif ++ ++#if !defined(AI_NUMERICHOST) ++# define AI_NUMERICHOST 0x4 ++#endif ++ ++#if !defined(EAI_AGAIN) ++# define EAI_AGAIN WSATRY_AGAIN ++#endif ++ ++#if !defined(EAI_BADFLAGS) ++# define EAI_BADFLAGS WSAEINVAL ++#endif ++ ++#if !defined(EAI_FAIL) ++# define EAI_FAIL WSANO_RECOVERY ++#endif ++ ++#if !defined(EAI_FAMILY) ++# define EAI_FAMILY WSAEAFNOSUPPORT ++#endif ++ ++#if !defined(EAI_MEMORY) ++# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY ++#endif ++ ++#if !defined(EAI_NODATA) ++# define EAI_NODATA WSANO_DATA ++#endif ++ ++#if !defined(EAI_NONAME) ++# define EAI_NONAME WSAHOST_NOT_FOUND ++#endif ++ ++#if !defined(EAI_SERVICE) ++# define EAI_SERVICE WSATYPE_NOT_FOUND ++#endif ++ ++#if !defined(EAI_SOCKTYPE) ++# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT ++#endif ++ ++#if !defined(NI_NOFQDN) ++# define NI_NOFQDN 0x01 ++#endif ++ ++#if !defined(NI_NUMERICHOST) ++# define NI_NUMERICHOST 0x02 ++#endif ++ ++#if !defined(NI_NAMEREQD) ++# define NI_NAMEREQD 0x04 ++#endif ++ ++#if !defined(NI_NUMERICSERV) ++# define NI_NUMERICSERV 0x08 ++#endif ++ ++#if !defined(NI_DGRAM) ++# define NI_DGRAM 0x10 ++#endif ++ ++#if !defined(IPPROTO_IPV6) ++# define IPPROTO_IPV6 41 ++#endif ++ ++#if !defined(IPV6_UNICAST_HOPS) ++# define IPV6_UNICAST_HOPS 4 ++#endif ++ ++#if !defined(IPV6_MULTICAST_IF) ++# define IPV6_MULTICAST_IF 9 ++#endif ++ ++#if !defined(IPV6_MULTICAST_HOPS) ++# define IPV6_MULTICAST_HOPS 10 ++#endif ++ ++#if !defined(IPV6_MULTICAST_LOOP) ++# define IPV6_MULTICAST_LOOP 11 ++#endif ++ ++#if !defined(IPV6_JOIN_GROUP) ++# define IPV6_JOIN_GROUP 12 ++#endif ++ ++#if !defined(IPV6_LEAVE_GROUP) ++# define IPV6_LEAVE_GROUP 13 ++#endif ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_HAS_OLD_WIN_SDK) ++ ++// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. ++#if !defined(IPV6_V6ONLY) ++# define IPV6_V6ONLY 27 ++#endif ++ ++// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6. ++#if !defined(IPPROTO_ICMPV6) ++# define IPPROTO_ICMPV6 58 ++#endif ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP +diff --git a/ip-address/include/std/net/detail/pop_options.hpp b/ip-address/include/std/net/detail/pop_options.hpp +new file mode 100644 +index 0000000..8aa375e +--- /dev/null ++++ b/ip-address/include/std/net/detail/pop_options.hpp +@@ -0,0 +1,98 @@ ++// ++// detail/pop_options.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++// No header guard ++ ++#if defined(__COMO__) ++ ++// Comeau C++ ++ ++#elif defined(__DMC__) ++ ++// Digital Mars C++ ++ ++#elif defined(__INTEL_COMPILER) || defined(__ICL) \ ++ || defined(__ICC) || defined(__ECC) ++ ++// Intel C++ ++ ++#elif defined(__GNUC__) ++ ++// GNU C++ ++ ++# if defined(__MINGW32__) || defined(__CYGWIN__) ++# pragma pack (pop) ++# endif ++ ++# if defined(__OBJC__) ++# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) ++# if defined(STDNET_OBJC_WORKAROUND) ++# undef Protocol ++# undef id ++# undef STDNET_OBJC_WORKAROUND ++# endif ++# endif ++# endif ++ ++#elif defined(__KCC) ++ ++// Kai C++ ++ ++#elif defined(__sgi) ++ ++// SGI MIPSpro C++ ++ ++#elif defined(__DECCXX) ++ ++// Compaq Tru64 Unix cxx ++ ++#elif defined(__ghs) ++ ++// Greenhills C++ ++ ++#elif defined(__BORLANDC__) ++ ++// Borland C++ ++ ++# pragma option pop ++# pragma nopushoptwarn ++# pragma nopackwarning ++ ++#elif defined(__MWERKS__) ++ ++// Metrowerks CodeWarrior ++ ++#elif defined(__SUNPRO_CC) ++ ++// Sun Workshop Compiler C++ ++ ++#elif defined(__HP_aCC) ++ ++// HP aCC ++ ++#elif defined(__MRC__) || defined(__SC__) ++ ++// MPW MrCpp or SCpp ++ ++#elif defined(__IBMCPP__) ++ ++// IBM Visual Age ++ ++#elif defined(_MSC_VER) ++ ++// Microsoft Visual C++ ++// ++// Must remain the last #elif since some other vendors (Metrowerks, for example) ++// also #define _MSC_VER ++ ++# pragma warning (pop) ++# pragma pack (pop) ++ ++#endif +diff --git a/ip-address/include/std/net/detail/push_options.hpp b/ip-address/include/std/net/detail/push_options.hpp +new file mode 100644 +index 0000000..ec64373 +--- /dev/null ++++ b/ip-address/include/std/net/detail/push_options.hpp +@@ -0,0 +1,127 @@ ++// ++// detail/push_options.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++// No header guard ++ ++#if defined(__COMO__) ++ ++// Comeau C++ ++ ++#elif defined(__DMC__) ++ ++// Digital Mars C++ ++ ++#elif defined(__INTEL_COMPILER) || defined(__ICL) \ ++ || defined(__ICC) || defined(__ECC) ++ ++// Intel C++ ++ ++#elif defined(__GNUC__) ++ ++// GNU C++ ++ ++# if defined(__MINGW32__) || defined(__CYGWIN__) ++# pragma pack (push, 8) ++# endif ++ ++# if defined(__OBJC__) ++# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) ++# if !defined(STDNET_DISABLE_OBJC_WORKAROUND) ++# if !defined(Protocol) && !defined(id) ++# define Protocol cpp_Protocol ++# define id cpp_id ++# define STDNET_OBJC_WORKAROUND ++# endif ++# endif ++# endif ++# endif ++ ++#elif defined(__KCC) ++ ++// Kai C++ ++ ++#elif defined(__sgi) ++ ++// SGI MIPSpro C++ ++ ++#elif defined(__DECCXX) ++ ++// Compaq Tru64 Unix cxx ++ ++#elif defined(__ghs) ++ ++// Greenhills C++ ++ ++#elif defined(__BORLANDC__) ++ ++// Borland C++ ++ ++# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi- ++# pragma nopushoptwarn ++# pragma nopackwarning ++# if !defined(__MT__) ++# error Multithreaded RTL must be selected. ++# endif // !defined(__MT__) ++ ++#elif defined(__MWERKS__) ++ ++// Metrowerks CodeWarrior ++ ++#elif defined(__SUNPRO_CC) ++ ++// Sun Workshop Compiler C++ ++ ++#elif defined(__HP_aCC) ++ ++// HP aCC ++ ++#elif defined(__MRC__) || defined(__SC__) ++ ++// MPW MrCpp or SCpp ++ ++#elif defined(__IBMCPP__) ++ ++// IBM Visual Age ++ ++#elif defined(_MSC_VER) ++ ++// Microsoft Visual C++ ++// ++// Must remain the last #elif since some other vendors (Metrowerks, for example) ++// also #define _MSC_VER ++ ++# pragma warning (disable:4103) ++# pragma warning (push) ++# pragma warning (disable:4127) ++# pragma warning (disable:4180) ++# pragma warning (disable:4244) ++# pragma warning (disable:4355) ++# pragma warning (disable:4512) ++# pragma warning (disable:4675) ++# if defined(_M_IX86) && defined(_Wp64) ++// The /Wp64 option is broken. If you want to check 64 bit portability, use a ++// 64 bit compiler! ++# pragma warning (disable:4311) ++# pragma warning (disable:4312) ++# endif // defined(_M_IX86) && defined(_Wp64) ++# pragma pack (push, 8) ++// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler ++// has a tendency to incorrectly optimise away some calls to member template ++// functions, even though those functions contain code that should not be ++// optimised away! Therefore we will always disable this optimisation option ++// for the MSVC6 compiler. ++# if (_MSC_VER < 1300) ++# pragma optimize ("g", off) ++# endif ++# if !defined(_MT) ++# error Multithreaded RTL must be selected. ++# endif // !defined(_MT) ++ ++#endif +diff --git a/ip-address/include/std/net/detail/socket_ops.hpp b/ip-address/include/std/net/detail/socket_ops.hpp +new file mode 100644 +index 0000000..02cb8a4 +--- /dev/null ++++ b/ip-address/include/std/net/detail/socket_ops.hpp +@@ -0,0 +1,57 @@ ++// ++// detail/socket_ops.hpp ++// ~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_OPS_HPP ++#define STDNET_DETAIL_SOCKET_OPS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#include ++#include "std/net/detail/socket_types.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace socket_ops { ++ ++STDNET_DECL const char* inet_ntop(int af, const void* src, char* dest, ++ size_t length, unsigned long scope_id, std::error_code& ec); ++ ++STDNET_DECL int inet_pton(int af, const char* src, void* dest, ++ unsigned long* scope_id, std::error_code& ec); ++ ++STDNET_DECL u_long_type network_to_host_long(u_long_type value); ++ ++STDNET_DECL u_long_type host_to_network_long(u_long_type value); ++ ++STDNET_DECL u_short_type network_to_host_short(u_short_type value); ++ ++STDNET_DECL u_short_type host_to_network_short(u_short_type value); ++ ++} // namespace socket_ops ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/socket_ops.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_SOCKET_OPS_HPP +diff --git a/ip-address/include/std/net/detail/socket_types.hpp b/ip-address/include/std/net/detail/socket_types.hpp +new file mode 100644 +index 0000000..ee35521 +--- /dev/null ++++ b/ip-address/include/std/net/detail/socket_types.hpp +@@ -0,0 +1,186 @@ ++// ++// detail/socket_types.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_TYPES_HPP ++#define STDNET_DETAIL_SOCKET_TYPES_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) ++# error WinSock.h has already been included ++# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) ++# if defined(__BORLANDC__) ++# include // Needed for __errno ++# if !defined(_WSPIAPI_H_) ++# define _WSPIAPI_H_ ++# define STDNET_WSPIAPI_H_DEFINED ++# endif // !defined(_WSPIAPI_H_) ++# endif // defined(__BORLANDC__) ++# include ++# include ++# include ++# if defined(STDNET_WSPIAPI_H_DEFINED) ++# undef _WSPIAPI_H_ ++# undef STDNET_WSPIAPI_H_DEFINED ++# endif // defined(STDNET_WSPIAPI_H_DEFINED) ++# if !defined(STDNET_NO_DEFAULT_LINKED_LIBS) ++# if defined(UNDER_CE) ++# pragma comment(lib, "ws2.lib") ++# elif defined(_MSC_VER) || defined(__BORLANDC__) ++# pragma comment(lib, "ws2_32.lib") ++# pragma comment(lib, "mswsock.lib") ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) ++# endif // !defined(STDNET_NO_DEFAULT_LINKED_LIBS) ++# include "std/net/detail/old_win_sdk_compat.hpp" ++#else ++# include ++# if !defined(__SYMBIAN32__) ++# include ++# endif ++# include ++# include ++# include ++# if defined(__hpux) ++# include ++# endif ++# if !defined(__hpux) || defined(__SELECT) ++# include ++# endif ++# include ++# include ++# include ++# include ++# if !defined(__SYMBIAN32__) ++# include ++# endif ++# include ++# include ++# include ++# include ++# if defined(__sun) ++# include ++# include ++# endif ++#endif ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++typedef SOCKET socket_type; ++const SOCKET invalid_socket = INVALID_SOCKET; ++const int socket_error_retval = SOCKET_ERROR; ++const int max_addr_v4_str_len = 256; ++const int max_addr_v6_str_len = 256; ++typedef sockaddr socket_addr_type; ++typedef in_addr in4_addr_type; ++typedef ip_mreq in4_mreq_type; ++typedef sockaddr_in sockaddr_in4_type; ++# if defined(STDNET_HAS_OLD_WIN_SDK) ++typedef in6_addr_emulation in6_addr_type; ++typedef ipv6_mreq_emulation in6_mreq_type; ++typedef sockaddr_in6_emulation sockaddr_in6_type; ++typedef sockaddr_storage_emulation sockaddr_storage_type; ++typedef addrinfo_emulation addrinfo_type; ++# else ++typedef in6_addr in6_addr_type; ++typedef ipv6_mreq in6_mreq_type; ++typedef sockaddr_in6 sockaddr_in6_type; ++typedef sockaddr_storage sockaddr_storage_type; ++typedef addrinfo addrinfo_type; ++# endif ++typedef unsigned long ioctl_arg_type; ++typedef u_long u_long_type; ++typedef u_short u_short_type; ++typedef int signed_size_type; ++const int shutdown_receive = SD_RECEIVE; ++const int shutdown_send = SD_SEND; ++const int shutdown_both = SD_BOTH; ++const int message_peek = MSG_PEEK; ++const int message_out_of_band = MSG_OOB; ++const int message_do_not_route = MSG_DONTROUTE; ++const int message_end_of_record = 0; // Not supported on Windows. ++# if defined (_WIN32_WINNT) ++const int max_iov_len = 64; ++# else ++const int max_iov_len = 16; ++# endif ++#else ++typedef int socket_type; ++const int invalid_socket = -1; ++const int socket_error_retval = -1; ++const int max_addr_v4_str_len = INET_ADDRSTRLEN; ++#if defined(INET6_ADDRSTRLEN) ++const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; ++#else // defined(INET6_ADDRSTRLEN) ++const int max_addr_v6_str_len = 256; ++#endif // defined(INET6_ADDRSTRLEN) ++typedef sockaddr socket_addr_type; ++typedef in_addr in4_addr_type; ++# if defined(__hpux) ++// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined. ++struct in4_mreq_type ++{ ++ struct in_addr imr_multiaddr; ++ struct in_addr imr_interface; ++}; ++# else ++typedef ip_mreq in4_mreq_type; ++# endif ++typedef sockaddr_in sockaddr_in4_type; ++typedef in6_addr in6_addr_type; ++typedef ipv6_mreq in6_mreq_type; ++typedef sockaddr_in6 sockaddr_in6_type; ++typedef sockaddr_storage sockaddr_storage_type; ++typedef sockaddr_un sockaddr_un_type; ++typedef addrinfo addrinfo_type; ++typedef int ioctl_arg_type; ++typedef uint32_t u_long_type; ++typedef uint16_t u_short_type; ++#if defined(STDNET_HAS_SSIZE_T) ++typedef ssize_t signed_size_type; ++#else // defined(STDNET_HAS_SSIZE_T) ++typedef int signed_size_type; ++#endif // defined(STDNET_HAS_SSIZE_T) ++const int shutdown_receive = SHUT_RD; ++const int shutdown_send = SHUT_WR; ++const int shutdown_both = SHUT_RDWR; ++const int message_peek = MSG_PEEK; ++const int message_out_of_band = MSG_OOB; ++const int message_do_not_route = MSG_DONTROUTE; ++const int message_end_of_record = MSG_EOR; ++# if defined(IOV_MAX) ++const int max_iov_len = IOV_MAX; ++# else ++// POSIX platforms are not required to define IOV_MAX. ++const int max_iov_len = 16; ++# endif ++#endif ++const int custom_socket_option_level = 0xA5100000; ++const int enable_connection_aborted_option = 1; ++const int always_fail_option = 2; ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_SOCKET_TYPES_HPP +diff --git a/ip-address/include/std/net/detail/system_errors.hpp b/ip-address/include/std/net/detail/system_errors.hpp +new file mode 100644 +index 0000000..4aa5c44 +--- /dev/null ++++ b/ip-address/include/std/net/detail/system_errors.hpp +@@ -0,0 +1,221 @@ ++// ++// system_errors.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SYSTEM_ERRORS_HPP ++#define STDNET_DETAIL_SYSTEM_ERRORS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# include ++#else ++# include ++#endif ++ ++#if defined(GENERATING_DOCUMENTATION) ++/// INTERNAL ONLY. ++# define STDNET_NATIVE_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_SOCKET_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_NETDB_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_GETADDRINFO_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) implementation_defined ++#elif defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# define STDNET_NATIVE_ERROR(e) e ++# define STDNET_SOCKET_ERROR(e) WSA ## e ++# define STDNET_NETDB_ERROR(e) WSA ## e ++# define STDNET_GETADDRINFO_ERROR(e) WSA ## e ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) e_win ++#else ++# define STDNET_NATIVE_ERROR(e) e ++# define STDNET_SOCKET_ERROR(e) e ++# define STDNET_NETDB_ERROR(e) e ++# define STDNET_GETADDRINFO_ERROR(e) e ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) e_posix ++#endif ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++enum system_errors ++{ ++ /// Permission denied. ++ access_denied = STDNET_SOCKET_ERROR(EACCES), ++ ++ /// Address family not supported by protocol. ++ address_family_not_supported = STDNET_SOCKET_ERROR(EAFNOSUPPORT), ++ ++ /// Address already in use. ++ address_in_use = STDNET_SOCKET_ERROR(EADDRINUSE), ++ ++ /// Transport endpoint is already connected. ++ already_connected = STDNET_SOCKET_ERROR(EISCONN), ++ ++ /// Operation already in progress. ++ already_started = STDNET_SOCKET_ERROR(EALREADY), ++ ++ /// Broken pipe. ++ broken_pipe = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_BROKEN_PIPE), ++ STDNET_NATIVE_ERROR(EPIPE)), ++ ++ /// A connection has been aborted. ++ connection_aborted = STDNET_SOCKET_ERROR(ECONNABORTED), ++ ++ /// Connection refused. ++ connection_refused = STDNET_SOCKET_ERROR(ECONNREFUSED), ++ ++ /// Connection reset by peer. ++ connection_reset = STDNET_SOCKET_ERROR(ECONNRESET), ++ ++ /// Bad file descriptor. ++ bad_descriptor = STDNET_SOCKET_ERROR(EBADF), ++ ++ /// Bad address. ++ fault = STDNET_SOCKET_ERROR(EFAULT), ++ ++ /// No route to host. ++ host_unreachable = STDNET_SOCKET_ERROR(EHOSTUNREACH), ++ ++ /// Operation now in progress. ++ in_progress = STDNET_SOCKET_ERROR(EINPROGRESS), ++ ++ /// Interrupted system call. ++ interrupted = STDNET_SOCKET_ERROR(EINTR), ++ ++ /// Invalid argument. ++ invalid_argument = STDNET_SOCKET_ERROR(EINVAL), ++ ++ /// Message too long. ++ message_size = STDNET_SOCKET_ERROR(EMSGSIZE), ++ ++ /// The name was too long. ++ name_too_long = STDNET_SOCKET_ERROR(ENAMETOOLONG), ++ ++ /// Network is down. ++ network_down = STDNET_SOCKET_ERROR(ENETDOWN), ++ ++ /// Network dropped connection on reset. ++ network_reset = STDNET_SOCKET_ERROR(ENETRESET), ++ ++ /// Network is unreachable. ++ network_unreachable = STDNET_SOCKET_ERROR(ENETUNREACH), ++ ++ /// Too many open files. ++ no_descriptors = STDNET_SOCKET_ERROR(EMFILE), ++ ++ /// No buffer space available. ++ no_buffer_space = STDNET_SOCKET_ERROR(ENOBUFS), ++ ++ /// Cannot allocate memory. ++ no_memory = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_OUTOFMEMORY), ++ STDNET_NATIVE_ERROR(ENOMEM)), ++ ++ /// Operation not permitted. ++ no_permission = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_ACCESS_DENIED), ++ STDNET_NATIVE_ERROR(EPERM)), ++ ++ /// Protocol not available. ++ no_protocol_option = STDNET_SOCKET_ERROR(ENOPROTOOPT), ++ ++ /// Transport endpoint is not connected. ++ not_connected = STDNET_SOCKET_ERROR(ENOTCONN), ++ ++ /// Socket operation on non-socket. ++ not_socket = STDNET_SOCKET_ERROR(ENOTSOCK), ++ ++ /// Operation cancelled. ++ operation_aborted = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_OPERATION_ABORTED), ++ STDNET_NATIVE_ERROR(ECANCELED)), ++ ++ /// Operation not supported. ++ operation_not_supported = STDNET_SOCKET_ERROR(EOPNOTSUPP), ++ ++ /// Cannot send after transport endpoint shutdown. ++ shut_down = STDNET_SOCKET_ERROR(ESHUTDOWN), ++ ++ /// Connection timed out. ++ timed_out = STDNET_SOCKET_ERROR(ETIMEDOUT), ++ ++ /// Resource temporarily unavailable. ++ try_again = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_RETRY), ++ STDNET_NATIVE_ERROR(EAGAIN)), ++ ++ /// The socket is marked non-blocking and the requested operation would block. ++ would_block = STDNET_SOCKET_ERROR(EWOULDBLOCK) ++}; ++ ++} // namespace syserrc ++ ++/// Returns the error category used for the system errors. ++extern STDNET_DECL const std::error_category& system_category(); ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++namespace std { ++ ++template<> struct is_error_code_enum< ++ std::experimental::net::detail::syserrc::system_errors> ++{ ++ static const bool value = true; ++}; ++ ++} // namespace std ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++inline std::error_code make_error_code(system_errors e) ++{ ++ return std::error_code(static_cast(e), ++ std::experimental::net::detail::system_category()); ++} ++ ++} // namespace syserrc ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#undef STDNET_NATIVE_ERROR ++#undef STDNET_SOCKET_ERROR ++#undef STDNET_NETDB_ERROR ++#undef STDNET_GETADDRINFO_ERROR ++#undef STDNET_WIN_OR_POSIX ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/system_errors.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_SYSTEM_ERRORS_HPP +diff --git a/ip-address/include/std/net/detail/throw_error.hpp b/ip-address/include/std/net/detail/throw_error.hpp +new file mode 100644 +index 0000000..4067cb7 +--- /dev/null ++++ b/ip-address/include/std/net/detail/throw_error.hpp +@@ -0,0 +1,57 @@ ++// ++// detail/throw_error.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_THROW_ERROR_HPP ++#define STDNET_DETAIL_THROW_ERROR_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++STDNET_DECL void do_throw_error(const std::error_code& err); ++ ++STDNET_DECL void do_throw_error(const std::error_code& err, ++ const char* location); ++ ++inline void throw_error(const std::error_code& err) ++{ ++ if (err) ++ do_throw_error(err); ++} ++ ++inline void throw_error(const std::error_code& err, ++ const char* location) ++{ ++ if (err) ++ do_throw_error(err, location); ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/throw_error.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_THROW_ERROR_HPP +diff --git a/ip-address/include/std/net/detail/throw_exception.hpp b/ip-address/include/std/net/detail/throw_exception.hpp +new file mode 100644 +index 0000000..0903df1 +--- /dev/null ++++ b/ip-address/include/std/net/detail/throw_exception.hpp +@@ -0,0 +1,45 @@ ++// ++// detail/throw_exception.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_THROW_EXCEPTION_HPP ++#define STDNET_DETAIL_THROW_EXCEPTION_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++// Declare the throw_exception function for all targets. ++template ++void throw_exception(const Exception& e); ++ ++// Only define the throw_exception function when exceptions are enabled. ++// Otherwise, it is up to the application to provide a definition of this ++// function. ++# if !defined(STDNET_NO_EXCEPTIONS) ++template ++void throw_exception(const Exception& e) ++{ ++ throw e; ++} ++# endif // !defined(STDNET_NO_EXCEPTIONS) ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#endif // STDNET_DETAIL_THROW_EXCEPTION_HPP +diff --git a/ip-address/include/std/net/detail/winsock_init.hpp b/ip-address/include/std/net/detail/winsock_init.hpp +new file mode 100644 +index 0000000..fc008de +--- /dev/null ++++ b/ip-address/include/std/net/detail/winsock_init.hpp +@@ -0,0 +1,94 @@ ++// ++// detail/winsock_init.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_WINSOCK_INIT_HPP ++#define STDNET_DETAIL_WINSOCK_INIT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++class winsock_init_base ++{ ++protected: ++ // Structure to track result of initialisation and number of uses. POD is used ++ // to ensure that the values are zero-initialised prior to any code being run. ++ struct data ++ { ++ long init_count_; ++ long result_; ++ }; ++ ++ STDNET_DECL static void startup(data& d, ++ unsigned char major, unsigned char minor); ++ ++ STDNET_DECL static void cleanup(data& d); ++ ++ STDNET_DECL static void throw_on_error(data& d); ++}; ++ ++template ++class winsock_init : private winsock_init_base ++{ ++public: ++ winsock_init(bool allow_throw = true) ++ { ++ startup(data_, Major, Minor); ++ if (allow_throw) ++ throw_on_error(data_); ++ } ++ ++ winsock_init(const winsock_init&) ++ { ++ startup(data_, Major, Minor); ++ throw_on_error(data_); ++ } ++ ++ ~winsock_init() ++ { ++ cleanup(data_); ++ } ++ ++private: ++ static data data_; ++}; ++ ++template ++winsock_init_base::data winsock_init::data_; ++ ++// Static variable to ensure that winsock is initialised before main, and ++// therefore before any other threads can get started. ++static const winsock_init<>& winsock_init_instance = winsock_init<>(false); ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/winsock_init.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_WINSOCK_INIT_HPP +diff --git a/ip-address/include/std/net/ip/address.hpp b/ip-address/include/std/net/ip/address.hpp +new file mode 100644 +index 0000000..8a5e75a +--- /dev/null ++++ b/ip-address/include/std/net/ip/address.hpp +@@ -0,0 +1,328 @@ ++// ++// ip/address.hpp ++// ~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_HPP ++#define STDNET_IP_ADDRESS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++namespace detail { ++ ++template ++struct is_convertible_to_address_1 : false_type {}; ++ ++template ++struct is_convertible_to_address_1(declval()))>::value>::type> : true_type {}; ++ ++template ++struct is_convertible_to_address : is_convertible_to_address_1 {}; ++ ++template <> ++struct is_convertible_to_address
: false_type {}; ++ ++} // namespace detail ++ ++//template <> struct is_convertible_to_address
: false_type {}; ++ ++/// Implements version-independent IP addresses. ++/** ++ * The ip::address class provides the ability to use either IP version 4 or ++ * version 6 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address ++{ ++public: ++ /// Default constructor. ++ STDNET_CONSTEXPR address() STDNET_NOEXCEPT ++ : type_(invalid), ++ ipv4_address_(), ++ ipv6_address_() ++ { ++ } ++ ++ /// Construct from another address type. ++ template ::value>::type> ++ STDNET_CONSTEXPR address(const T& t) STDNET_NOEXCEPT; ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address(T&&... t); ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit address(T1& t1, typename enable_if()))>::value>::type* = 0) ++ { *this = make_address(t1); } ++ template ++ explicit address(const T1& t1, typename enable_if()))>::value>::type* = 0) ++ { *this = make_address(t1); } ++ template ++ address(T1& t1, T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(T1& t1, const T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(const T1& t1, T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(const T1& t1, const T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address(const address& other) STDNET_NOEXCEPT ++ : type_(other.type_), ++ ipv4_address_(other.ipv4_address_), ++ ipv6_address_(other.ipv6_address_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address(address&& other) STDNET_NOEXCEPT ++ : type_(other.type_), ++ ipv4_address_(other.ipv4_address_), ++ ipv6_address_(other.ipv6_address_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address& operator=(const address& other) STDNET_NOEXCEPT ++ { ++ type_ = other.type_; ++ ipv4_address_ = other.ipv4_address_; ++ ipv6_address_ = other.ipv6_address_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address& operator=(address&& other) STDNET_NOEXCEPT ++ { ++ type_ = other.type_; ++ ipv4_address_ = other.ipv4_address_; ++ ipv6_address_ = other.ipv6_address_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Get whether the address is an IP version 4 address. ++ STDNET_CONSTEXPR bool is_v4() const STDNET_NOEXCEPT ++ { ++ return type_ == ipv4; ++ } ++ ++ /// Get whether the address is an IP version 6 address. ++ STDNET_CONSTEXPR bool is_v6() const STDNET_NOEXCEPT ++ { ++ return type_ == ipv6; ++ } ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_loopback() : ++ (type_ == ipv6) ? ipv6_address_.is_loopback() : false; ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_unspecified() : ++ (type_ == ipv6) ? ipv6_address_.is_unspecified() : false; ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_multicast() : ++ (type_ == ipv6) ? ipv6_address_.is_multicast() : false; ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address& a1, ++ const address& a2) STDNET_NOEXCEPT ++ { ++ if (a1.type_ != a2.type_) ++ return false; ++ if (a1.type_ == address::ipv4) ++ return a1.ipv4_address_ == a2.ipv4_address_; ++ if (a1.type_ == address::ipv6) ++ return a1.ipv4_address_ == a2.ipv4_address_; ++ return true; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 == a2); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address& a1, ++ const address& a2) STDNET_NOEXCEPT ++ { ++ if (a1.type_ < a2.type_) ++ return true; ++ if (a1.type_ > a2.type_) ++ return false; ++ if (a1.type_ == address::ipv4) ++ return a1.ipv4_address_ < a2.ipv4_address_; ++ if (a1.type_ == address::ipv6) ++ return a1.ipv6_address_ < a2.ipv6_address_; ++ return false; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return a2 < a1; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a2 < a1); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 < a2); ++ } ++ ++private: ++ friend class address_v4; ++ friend class address_v6; ++ ++ // The type of the address. ++ enum address_type { invalid, ipv4, ipv6 } type_; ++ ++ // The underlying IPv4 address. ++ address_v4 ipv4_address_; ++ ++ // The underlying IPv6 address. ++ address_v6 ipv6_address_; ++ ++ // Helper constructor for address_cast. ++ STDNET_CONSTEXPR address(address_type type, ++ const address_v4& v4, const address_v6& v6) ++ : type_(type), ++ ipv4_address_(v4), ++ ipv6_address_(v6) ++ { ++ } ++ ++ template friend STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type*); ++ template friend STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type*); ++ template friend STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT; ++ template friend STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT; ++}; ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const char* str); ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const std::string& str); ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#include "std/net/ip/address_cast.hpp" ++ ++#endif // STDNET_IP_ADDRESS_HPP +diff --git a/ip-address/include/std/net/ip/address_cast.hpp b/ip-address/include/std/net/ip/address_cast.hpp +new file mode 100644 +index 0000000..dae3d02 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_cast.hpp +@@ -0,0 +1,106 @@ ++// ++// ip/address_cast.hpp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_CAST_HPP ++#define STDNET_IP_ADDRESS_CAST_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++#include "std/net/ip/bad_address_cast.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++/// Cast a version-independent address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++/// Cast a version-independent address to an IPv4 address. ++/** ++ * @throws bad_address_cast if @c a does not represent an IPv4 address. ++ */ ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) ++{ ++ return (addr.type_ != address::ipv4) ++ ? throw bad_address_cast() ++ : addr.ipv4_address_; ++} ++ ++/// Cast a version-independent address to an IPv6 address. ++/** ++ * @throws bad_address_cast if @c a does not represent an IPv6 address. ++ */ ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) ++{ ++ return (addr.type_ != address::ipv6) ++ ? throw bad_address_cast() ++ : addr.ipv6_address_; ++} ++ ++/// Cast an IPv4 address to a version-independent address. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v4& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return address(address::ipv4, addr, address_v6()); ++} ++ ++/// Cast an IPv4 address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v4& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++/// Cast an IPv6 address to a version-independent address. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v6& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return address(address::ipv6, address_v4(), addr); ++} ++ ++/// Cast an IPv6 address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v6& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_ADDRESS_CAST_HPP +diff --git a/ip-address/include/std/net/ip/address_v4.hpp b/ip-address/include/std/net/ip/address_v4.hpp +new file mode 100644 +index 0000000..a7b9234 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_v4.hpp +@@ -0,0 +1,376 @@ ++// ++// ip/address_v4.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_V4_HPP ++#define STDNET_IP_ADDRESS_V4_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/detail/winsock_init.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++class address; ++ ++/// Implements IP version 4 style addresses. ++/** ++ * The ip::address_v4 class provides the ability to use and manipulate IP ++ * version 4 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address_v4 ++{ ++public: ++ /// A standard-layout type used to represent an address as an array of bytes. ++ struct bytes_type : std::array ++ { ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR bytes_type(T... t) ++ : std::array{{static_cast(t)...}} ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ explicit STDNET_CONSTEXPR bytes_type(unsigned char a = 0, ++ unsigned char b = 0, unsigned char c = 0, unsigned char d = 0) ++# if defined(STDNET_HAS_CONSTEXPR) ++ : std::array{{a, b, c, d}} ++ { ++ } ++# else // defined(STDNET_HAS_CONSTEXPR) ++ { ++ (*this)[0] = a, (*this)[1] = b, (*this)[2] = c, (*this)[3] = d; ++ } ++# endif // defined(STDNET_HAS_CONSTEXPR) ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ }; ++ ++ /// Default constructor. ++ STDNET_CONSTEXPR address_v4() STDNET_NOEXCEPT ++ : bytes_(0, 0, 0, 0) ++ { ++ } ++ ++ /// Implicit construction from bytes, in network byte order. ++ STDNET_CONSTEXPR address_v4(const bytes_type& bytes) ++ : bytes_( ++#if UCHAR_MAX > 0xFF ++ (bytes[0] > 0xFF || bytes[1] > 0xFF || bytes[2] > 0xFF || bytes[3] > 0xFF) ++ ? throw std::out_of_range("address_v4 from bytes_type") : ++#endif // UCHAR_MAX > 0xFF ++ bytes) ++ { ++ } ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address_v4(T&&... t) ++ : address_v4(make_address_v4(static_cast(t)...)) ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR address_v4(T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1).to_bytes()) {} ++ template ++ explicit STDNET_CONSTEXPR address_v4(const T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(const T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(const T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address_v4(const address_v4& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address_v4(address_v4&& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address_v4& operator=(const address_v4& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address_v4& operator=(address_v4&& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Get the address in bytes, in network byte order. ++ STDNET_CONSTEXPR bytes_type to_bytes() const STDNET_NOEXCEPT ++ { ++ return bytes_; ++ } ++ ++ /// Get the address as an unsigned long in host byte order ++ STDNET_CONSTEXPR unsigned long to_ulong() const STDNET_NOEXCEPT ++ { ++ return (static_cast(bytes_[0]) << 24) ++ | (static_cast(bytes_[1]) << 16) ++ | (static_cast(bytes_[2]) << 8) ++ | static_cast(bytes_[3]); ++ } ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xFF000000) == 0x7F000000; ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return to_ulong() == 0; ++ } ++ ++ /// Determine whether the address is a class A address. ++ STDNET_CONSTEXPR bool is_class_a() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0x80000000) == 0; ++ } ++ ++ /// Determine whether the address is a class B address. ++ STDNET_CONSTEXPR bool is_class_b() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xC0000000) == 0x80000000; ++ } ++ ++ /// Determine whether the address is a class C address. ++ STDNET_CONSTEXPR bool is_class_c() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xE0000000) == 0xC0000000; ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xF0000000) == 0xE0000000; ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() < a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() > a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() <= a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() >= a2.to_ulong(); ++ } ++ ++ /// Obtain an address object that represents any address. ++ static STDNET_CONSTEXPR address_v4 any() STDNET_NOEXCEPT ++ { ++ return address_v4(); ++ } ++ ++ /// Obtain an address object that represents the loopback address. ++ static STDNET_CONSTEXPR address_v4 loopback() STDNET_NOEXCEPT ++ { ++ return address_v4(0x7F000001); ++ } ++ ++ /// Obtain an address object that represents the broadcast address. ++ static STDNET_CONSTEXPR address_v4 broadcast() STDNET_NOEXCEPT ++ { ++ return address_v4(0xFFFFFFFF); ++ } ++ ++ /// Obtain an address object that represents the broadcast address that ++ /// corresponds to the specified address and netmask. ++ static STDNET_CONSTEXPR address_v4 broadcast(const address_v4& addr, ++ const address_v4& mask) STDNET_NOEXCEPT ++ { ++ return address_v4(addr.to_ulong() | (mask.to_ulong() ^ 0xFFFFFFFF)); ++ } ++ ++private: ++ // The underlying IPv4 address. ++ bytes_type bytes_; ++}; ++ ++/// Construct an address_v4 from raw bytes. ++inline STDNET_CONSTEXPR address_v4 make_address_v4(const address_v4::bytes_type& bytes) ++{ ++ return bytes; ++} ++ ++/// Construct an address_v4 from a unsigned long in host byte order. ++inline STDNET_CONSTEXPR address_v4 make_address_v4(unsigned long addr) ++{ ++ return ++#if ULONG_MAX > 0xFFFFFFFF ++ (addr > 0xFFFFFFFF) ++ ? throw std::out_of_range("address_v4 from unsigned long") : ++#endif // ULONG_MAX > 0xFFFFFFFF ++ address_v4::bytes_type((addr >> 24) & 0xFF, ++ (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF); ++} ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const char* str); ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const std::string& str); ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++#if defined(STDNET_HAS_CONSTEXPR) ++ ++/// The IPv4 unspecified address. ++STDNET_CONSTEXPR address_v4 any_v4(0); ++ ++/// The IPv4 loopback address. ++STDNET_CONSTEXPR address_v4 loopback_v4(0x7F000001); ++ ++/// The IPv4 broadcast address. ++STDNET_CONSTEXPR address_v4 broadcast_v4(0xFFFFFFFF); ++ ++#else // defined(STDNET_HAS_CONSTEXPR) ++ ++static const address_v4 any_v4(0); ++static const address_v4 loopback_v4(0x7F000001); ++static const address_v4 broadcast_v4(0xFFFFFFFF); ++ ++#endif // defined(STDNET_HAS_CONSTEXPR) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address_v4 ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v4& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address_v4.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address_v4.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_IP_ADDRESS_V4_HPP +diff --git a/ip-address/include/std/net/ip/address_v6.hpp b/ip-address/include/std/net/ip/address_v6.hpp +new file mode 100644 +index 0000000..3c4f440 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_v6.hpp +@@ -0,0 +1,440 @@ ++// ++// ip/address_v6.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_V6_HPP ++#define STDNET_IP_ADDRESS_V6_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/bad_address_cast.hpp" ++#include "std/net/detail/winsock_init.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++class address; ++class address_v4; ++ ++/// Implements IP version 6 style addresses. ++/** ++ * The ip::address_v6 class provides the ability to use and manipulate IP ++ * version 6 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address_v6 ++{ ++public: ++ /// A standard-layout type used to represent an address as an array of bytes. ++ struct bytes_type : std::array ++ { ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR bytes_type(T... t) ++ : std::array{{static_cast(t)...}} ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ explicit STDNET_CONSTEXPR bytes_type( ++ unsigned char a = 0, unsigned char b = 0, ++ unsigned char c = 0, unsigned char d = 0, ++ unsigned char e = 0, unsigned char f = 0, ++ unsigned char g = 0, unsigned char h = 0, ++ unsigned char i = 0, unsigned char j = 0, ++ unsigned char k = 0, unsigned char l = 0, ++ unsigned char m = 0, unsigned char n = 0, ++ unsigned char o = 0, unsigned char p = 0) ++# if defined(STDNET_HAS_CONSTEXPR) ++ : std::array{{a, b, c, d, e, f, g, h, i, h, k, l, m, n, o, p}} ++ { ++ } ++# else // defined(STDNET_HAS_CONSTEXPR) ++ { ++ (*this)[0] = a, (*this)[1] = b, (*this)[2] = c, (*this)[3] = d; ++ (*this)[4] = e, (*this)[5] = f, (*this)[6] = g, (*this)[7] = h; ++ (*this)[8] = i, (*this)[9] = j, (*this)[10] = k, (*this)[11] = l; ++ (*this)[12] = m, (*this)[13] = n, (*this)[14] = o, (*this)[15] = p; ++ } ++# endif // defined(STDNET_HAS_CONSTEXPR) ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ }; ++ ++ /// Default constructor. ++ STDNET_CONSTEXPR address_v6() STDNET_NOEXCEPT ++ : bytes_(0), ++ scope_id_(0) ++ { ++ } ++ ++ /// Implicit construction from bytes, in network byte order. ++ STDNET_CONSTEXPR address_v6(const bytes_type& bytes, unsigned long scope = 0) ++ : bytes_( ++#if UCHAR_MAX > 0xFF ++ (bytes[0] > 0xFF || bytes[1] > 0xFF || bytes[2] > 0xFF || bytes[3] > 0xFF ++ || bytes[4] > 0xFF || bytes[5] > 0xFF || bytes[6] > 0xFF || bytes[7] > 0xFF ++ || bytes[8] > 0xFF || bytes[9] > 0xFF || bytes[10] > 0xFF || bytes[11] > 0xFF ++ || bytes[12] > 0xFF || bytes[13] > 0xFF || bytes[14] > 0xFF || bytes[15] > 0xFF) ++ ? throw std::out_of_range("address_v6 from bytes_type") : ++#endif // UCHAR_MAX > 0xFF ++ bytes), ++ scope_id_(scope) ++ { ++ } ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address_v6(T&&... t) ++ : address_v6(make_address_v6(static_cast(t)...)) ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR address_v6(T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1).to_bytes()) {} ++ template ++ explicit STDNET_CONSTEXPR address_v6(const T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(const T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(const T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address_v6(const address_v6& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_), scope_id_(other.scope_id_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address_v6(address_v6&& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_), scope_id_(other.scope_id_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address_v6& operator=(const address_v6& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ scope_id_ = other.scope_id_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address_v6& operator=(address_v6&& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ scope_id_ = other.scope_id_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// The scope ID of the address. ++ /** ++ * Returns the scope ID associated with the IPv6 address. ++ */ ++ STDNET_CONSTEXPR unsigned long scope_id() const STDNET_NOEXCEPT ++ { ++ return scope_id_; ++ } ++ ++ /// The scope ID of the address. ++ /** ++ * Modifies the scope ID associated with the IPv6 address. ++ */ ++ void scope_id(unsigned long id) STDNET_NOEXCEPT ++ { ++ scope_id_ = id; ++ } ++ ++ /// Get the address in bytes, in network byte order. ++ STDNET_CONSTEXPR bytes_type to_bytes() const STDNET_NOEXCEPT ++ { ++ return bytes_; ++ } ++ ++ /// Get the address as a string. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0) && (bytes_[11] == 0) ++ && (bytes_[12] == 0) && (bytes_[13] == 0) ++ && (bytes_[14] == 0) && (bytes_[15] == 1)); ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0) && (bytes_[11] == 0) ++ && (bytes_[12] == 0) && (bytes_[13] == 0) ++ && (bytes_[14] == 0) && (bytes_[15] == 0)); ++ } ++ ++ /// Determine whether the address is link local. ++ STDNET_CONSTEXPR bool is_link_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xfe) && ((bytes_[1] & 0xc0) == 0x80)); ++ } ++ ++ /// Determine whether the address is site local. ++ STDNET_CONSTEXPR bool is_site_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xfe) && ((bytes_[1] & 0xc0) == 0xc0)); ++ } ++ ++ /// Determine whether the address is a mapped IPv4 address. ++ STDNET_CONSTEXPR bool is_v4_mapped() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0xff) && (bytes_[11] == 0xff)); ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (bytes_[0] == 0xff); ++ } ++ ++ /// Determine whether the address is a global multicast address. ++ STDNET_CONSTEXPR bool is_multicast_global() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x0e)); ++ } ++ ++ /// Determine whether the address is a link-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_link_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x02)); ++ } ++ ++ /// Determine whether the address is a node-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_node_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x01)); ++ } ++ ++ /// Determine whether the address is a org-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_org_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x08)); ++ } ++ ++ /// Determine whether the address is a site-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_site_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x05)); ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_ && a1.scope_id_ == a2.scope_id_; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 == a2); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ if (a1.bytes_ < a2.bytes_) ++ return true; ++ if (a1.bytes_ > a2.bytes_) ++ return false; ++ return a1.scope_id_ < a2.scope_id_; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return a2 < a1; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a2 < a1); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 < a2); ++ } ++ ++ /// Obtain an address object that represents any address. ++ static STDNET_CONSTEXPR address_v6 any() STDNET_NOEXCEPT ++ { ++ return address_v6(); ++ } ++ ++ /// Obtain an address object that represents the loopback address. ++ static STDNET_CONSTEXPR address_v6 loopback() STDNET_NOEXCEPT ++ { ++ return bytes_type(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); ++ } ++ ++private: ++ friend STDNET_CONSTEXPR address_v4 make_address_v4( ++ v4_mapped_t, const address_v6&); ++ ++ // The underlying IPv6 address. ++ bytes_type bytes_; ++ ++ // The scope ID associated with the address. ++ unsigned long scope_id_; ++}; ++ ++/// Construct an address_v6 from raw bytes. ++inline STDNET_CONSTEXPR address_v6 make_address_v6( ++ const address_v6::bytes_type& bytes, unsigned long scope_id = 0) ++{ ++ return address_v6(bytes, scope_id); ++} ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const char* str); ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const std::string& str); ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an IPv4-mapped address_v6 from an IPv4 address. ++inline STDNET_CONSTEXPR address_v6 make_address_v6( ++ v4_mapped_t, const address_v4& addr) STDNET_NOEXCEPT ++{ ++ return address_v6::bytes_type(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, ++ static_cast(addr.to_bytes())[0], ++ static_cast(addr.to_bytes())[1], ++ static_cast(addr.to_bytes())[2], ++ static_cast(addr.to_bytes())[3]); ++} ++ ++/// Create an address_v4 from an IPv4-mapped address_v6. ++inline STDNET_CONSTEXPR address_v4 make_address_v4( ++ v4_mapped_t, const address_v6& addr) ++{ ++ return !addr.is_v4_mapped() ? throw bad_address_cast() : ++ address_v4::bytes_type(addr.bytes_[12], addr.bytes_[13], ++ addr.bytes_[14], addr.bytes_[15]); ++} ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address_v6 ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v6& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address_v6.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address_v6.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_IP_ADDRESS_V6_HPP +diff --git a/ip-address/include/std/net/ip/bad_address_cast.hpp b/ip-address/include/std/net/ip/bad_address_cast.hpp +new file mode 100644 +index 0000000..bc330c2 +--- /dev/null ++++ b/ip-address/include/std/net/ip/bad_address_cast.hpp +@@ -0,0 +1,46 @@ ++// ++// ip/bad_address_cast.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_BAD_ADDRESS_CAST_HPP ++#define STDNET_IP_BAD_ADDRESS_CAST_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++/// Exception thrown on a failed address_cast. ++class bad_address_cast ++ : public bad_cast ++{ ++public: ++ virtual const char* what() const STDNET_NOEXCEPT ++ { ++ return "bad address cast"; ++ } ++}; ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_BAD_ADDRESS_CAST_HPP +diff --git a/ip-address/include/std/net/ip/fwd.hpp b/ip-address/include/std/net/ip/fwd.hpp +new file mode 100644 +index 0000000..2c8f929 +--- /dev/null ++++ b/ip-address/include/std/net/ip/fwd.hpp +@@ -0,0 +1,149 @@ ++// ++// ip/fwd.hpp ++// ~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_FWD_HPP ++#define STDNET_IP_FWD_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++#if defined(STDNET_HAS_CONSTEXPR) ++struct v4_mapped_t { STDNET_CONSTEXPR v4_mapped_t() {} }; ++STDNET_CONSTEXPR v4_mapped_t v4_mapped; ++#else // !defined(STDNET_HAS_CONSTEXPR) ++enum v4_mapped_t { v4_mapped }; ++#endif // !defined(STDNET_HAS_CONSTEXPR) ++ ++class address; ++class address_v4; ++class address_v6; ++ ++// address comparisons: ++bool operator==(const address&, const address&) STDNET_NOEXCEPT; ++bool operator!=(const address&, const address&) STDNET_NOEXCEPT; ++bool operator< (const address&, const address&) STDNET_NOEXCEPT; ++bool operator> (const address&, const address&) STDNET_NOEXCEPT; ++bool operator<=(const address&, const address&) STDNET_NOEXCEPT; ++bool operator>=(const address&, const address&) STDNET_NOEXCEPT; ++ ++// address creation: ++address make_address(const char*); ++address make_address(const char*, std::error_code&) STDNET_NOEXCEPT; ++address make_address(const std::string&); ++address make_address(const std::string&, std::error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// address_v4 comparisons: ++bool operator==(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator!=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator< (const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator> (const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator<=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator>=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++ ++// address_v4 creation: ++//STDNET_CONSTEXPR address_v4 make_address_v4(const address_v4::octets&); ++STDNET_CONSTEXPR address_v4 make_address_v4(unsigned long); ++STDNET_CONSTEXPR address_v4 make_address_v4(v4_mapped_t, const address_v6&); ++address_v4 make_address_v4(const char*); ++address_v4 make_address_v4(const char*, error_code&) STDNET_NOEXCEPT; ++address_v4 make_address_v4(const std::string&); ++address_v4 make_address_v4(const std::string&, std::error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address_v4 I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address_v4&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// address_v6 comparisons: ++bool operator==(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator!=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator< (const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator> (const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator<=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator>=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++ ++// address_v6 creation: ++//STDNET_CONSTEXPR address_v6 make_address_v6(const address_v6::octets&, unsigned long = 0); ++STDNET_CONSTEXPR address_v6 make_address_v6(v4_mapped_t, const address_v4&) STDNET_NOEXCEPT; ++address_v6 make_address_v6(const char*); ++address_v6 make_address_v6(const char*, error_code&) STDNET_NOEXCEPT; ++address_v6 make_address_v6(const std::string&); ++address_v6 make_address_v6(const std::string&, error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address_v6 I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address_v6&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++class bad_address_cast; ++ ++// address conversion: ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0); ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0); ++template STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_DELETED; ++template STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_DELETED; ++template STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_FWD_HPP +diff --git a/ip-address/include/std/net/ip/impl/address.hpp b/ip-address/include/std/net/ip/impl/address.hpp +new file mode 100644 +index 0000000..82dc09c +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address.hpp +@@ -0,0 +1,74 @@ ++// ++// ip/impl/address.hpp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_HPP ++#define STDNET_IP_IMPL_ADDRESS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/ip/address_cast.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++inline STDNET_CONSTEXPR address::address(const T& t) STDNET_NOEXCEPT ++ : address(address_cast
(t)) ++{ ++} ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++template ++inline STDNET_CONSTEXPR address::address(T&&... t) ++ : address(make_address(static_cast(t)...)) ++{ ++} ++ ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_HPP +diff --git a/ip-address/include/std/net/ip/impl/address.ipp b/ip-address/include/std/net/ip/impl/address.ipp +new file mode 100644 +index 0000000..b74189c +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address.ipp +@@ -0,0 +1,91 @@ ++// ++// ip/impl/address.ipp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_IPP ++#define STDNET_IP_IMPL_ADDRESS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/ip/address.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address::to_string() const ++{ ++ if (type_ == ipv4) ++ return ipv4_address_.to_string(); ++ if (type_ == ipv6) ++ return ipv6_address_.to_string(); ++ throw bad_address_cast(); ++} ++ ++std::string address::to_string(std::error_code& ec) const ++{ ++ if (type_ == ipv4) ++ return ipv4_address_.to_string(ec); ++ if (type_ == ipv6) ++ return ipv6_address_.to_string(ec); ++ throw bad_address_cast(); ++} ++ ++address make_address(const char* str) ++{ ++ std::error_code ec; ++ address addr = make_address(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address make_address(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v6 ipv6_address = make_address_v6(str, ec); ++ if (!ec) ++ return ipv6_address; ++ ++ address_v4 ipv4_address = make_address_v4(str, ec); ++ if (!ec) ++ return ipv4_address; ++ ++ return address(); ++} ++ ++address make_address(const std::string& str) ++{ ++ return make_address(str.c_str()); ++} ++ ++address make_address(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_IPP +diff --git a/ip-address/include/std/net/ip/impl/address_v4.hpp b/ip-address/include/std/net/ip/impl/address_v4.hpp +new file mode 100644 +index 0000000..8544419 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v4.hpp +@@ -0,0 +1,57 @@ ++// ++// ip/impl/address_v4.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V4_HPP ++#define STDNET_IP_IMPL_ADDRESS_V4_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v4& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V4_HPP +diff --git a/ip-address/include/std/net/ip/impl/address_v4.ipp b/ip-address/include/std/net/ip/impl/address_v4.ipp +new file mode 100644 +index 0000000..1ed99f7 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v4.ipp +@@ -0,0 +1,90 @@ ++// ++// ip/impl/address_v4.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V4_IPP ++#define STDNET_IP_IMPL_ADDRESS_V4_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/address_v4.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address_v4::to_string() const ++{ ++ std::error_code ec; ++ std::string addr = to_string(ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++std::string address_v4::to_string(std::error_code& ec) const ++{ ++ char addr_str[std::experimental::net::detail::max_addr_v4_str_len]; ++ const char* addr = ++ std::experimental::net::detail::socket_ops::inet_ntop( ++ AF_INET, bytes_.data(), addr_str, ++ std::experimental::net::detail::max_addr_v4_str_len, 0, ec); ++ if (addr == 0) ++ return std::string(); ++ return addr; ++} ++ ++address_v4 make_address_v4(const char* str) ++{ ++ std::error_code ec; ++ address_v4 addr = make_address_v4(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address_v4 make_address_v4(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v4::bytes_type bytes; ++ if (std::experimental::net::detail::socket_ops::inet_pton( ++ AF_INET, str, bytes.data(), 0, ec) <= 0) ++ return address_v4(); ++ return address_v4(bytes); ++} ++ ++address_v4 make_address_v4(const std::string& str) ++{ ++ return make_address_v4(str.c_str()); ++} ++ ++address_v4 make_address_v4(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address_v4(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V4_IPP +diff --git a/ip-address/include/std/net/ip/impl/address_v6.hpp b/ip-address/include/std/net/ip/impl/address_v6.hpp +new file mode 100644 +index 0000000..1b3fd23 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v6.hpp +@@ -0,0 +1,57 @@ ++// ++// ip/impl/address_v6.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V6_HPP ++#define STDNET_IP_IMPL_ADDRESS_V6_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v6& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V6_HPP +diff --git a/ip-address/include/std/net/ip/impl/address_v6.ipp b/ip-address/include/std/net/ip/impl/address_v6.ipp +new file mode 100644 +index 0000000..682160b +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v6.ipp +@@ -0,0 +1,90 @@ ++// ++// ip/impl/address_v6.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V6_IPP ++#define STDNET_IP_IMPL_ADDRESS_V6_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address_v6::to_string() const ++{ ++ std::error_code ec; ++ std::string addr = to_string(ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++std::string address_v6::to_string(std::error_code& ec) const ++{ ++ char addr_str[std::experimental::net::detail::max_addr_v6_str_len]; ++ const char* addr = ++ std::experimental::net::detail::socket_ops::inet_ntop( ++ AF_INET6, bytes_.data(), addr_str, ++ std::experimental::net::detail::max_addr_v6_str_len, ++ scope_id_, ec); ++ if (addr == 0) ++ return std::string(); ++ return addr; ++} ++ ++address_v6 make_address_v6(const char* str) ++{ ++ std::error_code ec; ++ address_v6 addr = make_address_v6(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address_v6 make_address_v6(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v6::bytes_type bytes; ++ unsigned long scope_id = 0; ++ if (std::experimental::net::detail::socket_ops::inet_pton( ++ AF_INET6, str, bytes.data(), &scope_id, ec) <= 0) ++ return address_v6(); ++ return address_v6(bytes, scope_id); ++} ++ ++address_v6 make_address_v6(const std::string& str) ++{ ++ return make_address_v6(str.c_str()); ++} ++ ++address_v6 make_address_v6(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address_v6(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V6_IPP +diff --git a/ip-address/include/std/net/literals.hpp b/ip-address/include/std/net/literals.hpp +new file mode 100644 +index 0000000..2f10279 +--- /dev/null ++++ b/ip-address/include/std/net/literals.hpp +@@ -0,0 +1,51 @@ ++// ++// literals.hpp ++// ~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_LITERALS_HPP ++#define STDNET_LITERALS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++inline namespace literals { ++inline namespace net_literals { ++ ++inline net::ip::address operator"" _ip(const char* str, std::size_t) ++{ ++ return net::ip::make_address(str); ++} ++ ++inline net::ip::address_v4 operator"" _ipv4(const char* str, std::size_t) ++{ ++ return net::ip::make_address_v4(str); ++} ++ ++inline net::ip::address_v6 operator"" _ipv6(const char* str, std::size_t) ++{ ++ return net::ip::make_address_v6(str); ++} ++ ++} // inline namespace net_literals ++} // inline namespace literals ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_LITERALS_HPP +diff --git a/ip_prefix.cc b/ip_prefix.cc +new file mode 100644 +index 0000000..93b59ca +--- /dev/null ++++ b/ip_prefix.cc +@@ -0,0 +1,171 @@ ++// ip_prefix.cc: IP_prefix class definition ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++#include ++#include ++#include ++ ++ ++// Namespace aliases ++namespace ip = std::experimental::net::ip; ++ ++// Deafult namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++string IP_prefix::to_bitstring(unsigned short int byte) { ++ string result = "00000000"; ++ for (int i = 7; i >= 0; i--) { ++ if (byte > 0) { ++ if (byte % 2 == 0) { ++ result[i] = '0'; ++ } else { ++ result[i] = '1'; ++ } ++ byte /= 2; ++ } ++ } ++ return result; ++} // end to_bitstring() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++IP_prefix::IP_prefix(const string& str, bool bitstring) { ++ if (bitstring) { // str represents bits of an IPv4/IPv6 prefix ++ prefix = str; ++ } else { // str represents a valid IPv4/IPv6 prefix in the standard notation ++ // extract prefix ++ string pref = str.substr(0, str.find('/')); ++ // extract prefix length ++ int len = atoi(str.substr(str.find('/')+1).c_str()); ++ ++ // transform address part of the prefix into generic format ++ ip::address addr(pref); ++ ++ // transform generic format into bitstring format ++ string addr_bitstring; ++ if (addr.is_v4()) { // IPv4 ++ ip::address_v4 addr_v4(pref); ++ ip::address_v4::bytes_type addr_v4_bytes = addr_v4.to_bytes(); ++ for (ip::address_v4::bytes_type::iterator it = addr_v4_bytes.begin(); it != addr_v4_bytes.end(); ++it) { ++ addr_bitstring.append(to_bitstring(*it)); ++ } ++ } else if (addr.is_v6()){ // IPv6 ++ ip::address_v6 addr_v6(pref); ++ ip::address_v6::bytes_type addr_v6_bytes = addr_v6.to_bytes(); ++ for (ip::address_v6::bytes_type::iterator it = addr_v6_bytes.begin(); it != addr_v6_bytes.end(); ++it) { ++ addr_bitstring.append(to_bitstring(*it)); ++ } ++ } ++ ++ // store only bits actually involved in IP prefix ++ prefix = addr_bitstring.substr(0, len); ++ } ++} // end IP_prefix() ++ ++ ++IP_prefix::IP_prefix(unsigned addr, int len) { ++ // bitstring representation of addr ++ string addr_bitstring; ++ ++ // convert addr into bitstring representation ++ addr_bitstring.append(to_bitstring(addr >> 24)); ++ addr_bitstring.append(to_bitstring(addr >> 16)); ++ addr_bitstring.append(to_bitstring(addr >> 8)); ++ addr_bitstring.append(to_bitstring(addr)); ++ ++ // store only bits actually involved in IP prefix ++ prefix = addr_bitstring.substr(0, len); ++} // end IP_prefix() ++ ++ ++IP_prefix::IP_prefix(uint128_t addr, int len) { ++ // bitstring representation of addr ++ string addr_bitstring; ++ ++ // convert addr into bitstring representation ++ addr_bitstring.append(to_bitstring(addr >> 120)); ++ addr_bitstring.append(to_bitstring(addr >> 112)); ++ addr_bitstring.append(to_bitstring(addr >> 104)); ++ addr_bitstring.append(to_bitstring(addr >> 96)); ++ addr_bitstring.append(to_bitstring(addr >> 88)); ++ addr_bitstring.append(to_bitstring(addr >> 80)); ++ addr_bitstring.append(to_bitstring(addr >> 72)); ++ addr_bitstring.append(to_bitstring(addr >> 64)); ++ addr_bitstring.append(to_bitstring(addr >> 56)); ++ addr_bitstring.append(to_bitstring(addr >> 48)); ++ addr_bitstring.append(to_bitstring(addr >> 40)); ++ addr_bitstring.append(to_bitstring(addr >> 32)); ++ addr_bitstring.append(to_bitstring(addr >> 24)); ++ addr_bitstring.append(to_bitstring(addr >> 16)); ++ addr_bitstring.append(to_bitstring(addr >> 8)); ++ addr_bitstring.append(to_bitstring(addr)); ++ ++ // store only bits actually involved in IP prefix ++ prefix = addr_bitstring.substr(0, len); ++} // end IP_prefix() ++ ++ ++IP_prefix& IP_prefix::operator= (const IP_prefix& orig) { ++ // create a copy of class members ++ prefix = orig.get_prefix(); ++ // return the created object ++ return *this; ++} // end operator= () ++ ++ ++unsigned IP_prefix::get_prefix_unsigned() const { ++ // initialize auxiliary variables ++ unsigned prefix_uns = 0; ++ unsigned pow = 1; ++ ++ // iterate over all bits of an unsigned integer from right to left ++ for (int i = 31; i >= 0; i--) { ++ if (i < (int)prefix.length()) { ++ if (prefix[i] == '1') { ++ prefix_uns += pow; ++ } ++ } ++ pow += pow; ++ } ++ ++ // return the prefix value ++ return prefix_uns; ++} // end get_prefix_unsigned(); ++ ++ ++uint128_t IP_prefix::get_prefix_uint128_t() const { ++ // initialize auxiliary variables ++ uint128_t prefix_uns128 = 0; ++ uint128_t pow = 1; ++ ++ // iterate over all bits of a 128-bit unsigned integer from right to left ++ for (int i = 127; i >= 0; i--) { ++ if (i < (int)prefix.length()) { ++ if (prefix[i] == '1') { ++ prefix_uns128 += pow; ++ } ++ } ++ pow += pow; ++ } ++ ++ // return the prefix value ++ return prefix_uns128; ++} // end get_prefix_uint128_t(); +diff --git a/ip_prefix.h b/ip_prefix.h +new file mode 100644 +index 0000000..59efa2c +--- /dev/null ++++ b/ip_prefix.h +@@ -0,0 +1,146 @@ ++// ip_prefix.h: header file for IP_prefix class ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef IP_PREFIX_H ++#define IP_PREFIX_H ++ ++ ++#include "uint128_t.h" ++#include ++ ++// Deafult namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of IPv4/IPv6 prefixes. ++ * ++ * IP prefixes are represented as bitstrings where the first character ++ * represents the MSB of an IP address. Prefix length is determined by the ++ * length of the bitstring. ++ */ ++class IP_prefix { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * String of bits representing the prefix. ++ * The first character represents the MSB of the prefix and the prefix ++ * length is given by the length of this string. ++ */ ++ string prefix; ++ ++ /* ++ * Static function for conversion of a single byte into a bitstring. ++ * @param byte Byte to be converted. ++ * @return Byte converted into bitstring. ++ */ ++ static string to_bitstring(unsigned short int byte); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * Constructs an empty object of the IP_prefix class ++ */ ++ inline IP_prefix() {}; ++ ++ /* ++ * Constructor. ++ * Constructs an object of the IP_prefix class from a given string ++ * representing either bits of an IPv4/IPv6 prefix (the length of the ++ * string being the lenght of the prefix) or a valid IPv4/IPv6 prefix in ++ * the standard notation. ++ * @param str String representing an IPv4/IPv6 prefix in a format ++ * determined by the bitsring parameter. ++ * @param bitstring str represents bits of an IPv4/IPv6 prefix (TRUE) ++ * or a valid IPv4/IPv6 prefix in the standard ++ * notation (FALSE). ++ */ ++ IP_prefix(const string& str, bool bitsring); ++ ++ /* ++ * Constructor. ++ * Constructs an object of the IP_prefix class from a given IPv4 prefix ++ * represented by its address part (unsigned integer) and length ++ * (integer). ++ * @param addr Address part of the IPv4 prefix. ++ * @param len Prefix length. ++ */ ++ IP_prefix(unsigned addr, int len); ++ ++ /* ++ * Constructor. ++ * Constructs an object of the IP_prefix class from a given IPv4/IPv6 ++ * prefix represented by its address part (128-bit unsigned integer) and ++ * length (integer). ++ * @param addr Address part of the IPv4/IPv6 prefix. ++ * @param len Prefix length. ++ */ ++ IP_prefix(uint128_t addr, int len); ++ ++ /* ++ * Copy assignment. ++ * Constructs a new IP prefix object by asigning a copy of the original ++ * IP prefix object. ++ * @param orig Reference to the original IP prefix object. ++ * @return Reference to the new IP prefix object. ++ */ ++ IP_prefix& operator= (const IP_prefix& orig); ++ ++ /* ++ * Comparison operator. ++ * Compares the current IP prefix object with the given IP prefix object. ++ * @param rhs_prefix IP prefix object to be compared with the current ++ * IP prefix object. ++ * @return TRUE if IP prefixes are equal, ++ * FALSE otherwise. ++ */ ++ inline bool operator== (const IP_prefix& rhs_prefix) const { ++ return (prefix == rhs_prefix.get_prefix()); ++ } ++ ++ /* ++ * Get function for the prefix bitstring. ++ * @return Bitstring representing IPv4/IPv6 prefix. ++ */ ++ inline string get_prefix() const { ++ return prefix; ++ } // end get_prefix() ++ ++ /* ++ * Get function for the prefix in the form of an unsigned integer. ++ * @return Unsigned integer representing IPv4 prefix. ++ */ ++ unsigned get_prefix_unsigned() const; ++ ++ /* ++ * Get function for the prefix in the form of a 128-bit unsigned ++ * integer. ++ * @return 128-bit unsigned integer representing IPv4/IPv6 prefix. ++ */ ++ uint128_t get_prefix_uint128_t() const; ++ ++ /* ++ * Get function for the prefix length. ++ * @return Prefix length. ++ */ ++ inline int get_length() const { ++ return prefix.length(); ++ } // end get_prefix() ++}; ++ ++#endif +diff --git a/makefile b/makefile +old mode 100755 +new mode 100644 +index 773f4c1..3cfcce6 +--- a/makefile ++++ b/makefile +@@ -9,15 +9,16 @@ + ## See README file for details + + CC = g++ ++LIB = -I./ip-address/include + ##CFLAGS = -g -pg +-CFLAGS = -O2 ++CFLAGS = -O2 -std=c++11 $(LIB) + .cc.o: + ${CC} ${CFLAGS} -c $*.cc + + sbintree.o : stdinc.h dlist.h sbintree.h + dbintree.o : stdinc.h dlist.h dbintree.h + random_db.o : stdinc.h FilterList.h random_db.h +-custom_db.o : stdinc.h FilterList.h ProtList.h FlagList.h ExtraList.h PortList.h PrefixList.h dlist.h sbintree.h dbintree.h redundant_filter_check.h TupleBST.h custom_db.h ++custom_db.o : stdinc.h FilterList.h ProtList.h FlagList.h ExtraList.h PortList.h PrefixList.h dlist.h sbintree.h dbintree.h redundant_filter_check.h TupleBST.h custom_db.h ip_prefix.h trie.h filter_graph.h + dlist.o : stdinc.h dlist.h + redundant_filter_check.o : stdinc.h redundant_filter_check.h + ## nesting_filter_check.o : stdinc.h nesting_filter_check.h +@@ -29,8 +30,16 @@ PrefixList.o : stdinc.h PrefixList.h + FilterList.o : stdinc.h FilterList.h + TupleBST.o : stdinc.h dlist.h TupleBST.h + db_generator.o : stdinc.h random_db.h PortList.h FilterList.h custom_db.h ++uint128_t.o : uint128_t.h ++ip_prefix.o : ip_prefix.h ++trie.o : trie.h ++flow_network.o : flow_network.h ++filter_graph.o : stdinc.h filter_graph.h + +-db_generator: db_generator.o random_db.o dlist.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o sbintree.o dbintree.o redundant_filter_check.o FilterList.o TupleBST.o custom_db.o +- ${CC} ${CFLAGS} db_generator.o random_db.o dlist.o sbintree.o dbintree.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o FilterList.o redundant_filter_check.o TupleBST.o custom_db.o -o db_generator ++db_generator: db_generator.o random_db.o dlist.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o sbintree.o dbintree.o redundant_filter_check.o FilterList.o TupleBST.o custom_db.o uint128_t.o ip_prefix.o trie.o flow_network.o filter_graph.o ++ ${CC} ${CFLAGS} db_generator.o random_db.o dlist.o sbintree.o dbintree.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o FilterList.o redundant_filter_check.o TupleBST.o custom_db.o uint128_t.o ip_prefix.o trie.o flow_network.o filter_graph.o -o db_generator + + all: db_generator ++ ++clean: ++ rm -rf *.o db_generator +diff --git a/random_db.cc b/random_db.cc +index 8da4c37..b71ff3e 100644 +--- a/random_db.cc ++++ b/random_db.cc +@@ -16,28 +16,66 @@ int random_db_gen(int num_filters, FilterList* filters){ + int i; + unsigned temp1; + unsigned temp2; ++ uint128_t temp1_128; ++ uint128_t temp2_128; ++ uint128_t temp3_128; ++ uint128_t temp4_128; + struct filter temp_filter; + + for (i = 0; i < num_filters; i++) { +- // Source Address +- temp1 = 0; +- temp1 = mrand48(); +- temp_filter.sa = temp1; ++ if (ADDRLEN == 32) { //IPv4 ++ // Source Address ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.sa = temp1; + +- // Source Address Length +- temp1 = 0; +- temp1 = mrand48(); +- temp_filter.sa_len = (temp1 >> 27); ++ // Source Address Length ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.sa_len = (temp1 >> 27); + +- // Destination Address +- temp1 = 0; +- temp1 = mrand48(); +- temp_filter.da = temp1; ++ // Destination Address ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.da = temp1; + +- // Destination Address Length +- temp1 = 0; +- temp1 = mrand48(); +- temp_filter.da_len = (temp1 >> 27); ++ // Destination Address Length ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.da_len = (temp1 >> 27); ++ } else { // IPv6 ++ // Source Address ++ temp1_128 = temp2_128 = temp3_128 = temp4_128 = 0; ++ temp1_128 = lrand48(); ++ temp2_128 = lrand48(); ++ temp3_128 = lrand48(); ++ temp4_128 = lrand48(); ++ temp2_128 <<= 32; ++ temp3_128 <<= 64; ++ temp4_128 <<= 96; ++ temp_filter.sa = temp4_128 | temp3_128 | temp2_128 | temp1_128; ++ ++ // Source Address Length ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.sa_len = (temp1 >> 25); ++ ++ // Destination Address ++ temp1_128 = temp2_128 = temp3_128 = temp4_128 = 0; ++ temp1_128 = lrand48(); ++ temp2_128 = lrand48(); ++ temp3_128 = lrand48(); ++ temp4_128 = lrand48(); ++ temp2_128 <<= 32; ++ temp3_128 <<= 64; ++ temp4_128 <<= 96; ++ temp_filter.da = temp4_128 | temp3_128 | temp2_128 | temp1_128; ++ ++ // Destination Address Length ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.da_len = (temp1 >> 25); ++ } + + // Source Port Ranges + temp1 = 0; +diff --git a/redundant_filter_check.cc b/redundant_filter_check.cc +index 38771e7..fbac9d3 100644 +--- a/redundant_filter_check.cc ++++ b/redundant_filter_check.cc +@@ -21,7 +21,7 @@ int redundant_check(struct filter filt1, struct filter filt2){ + + int sa_prefix_match(struct filter filt1, struct filter filt2){ + +- unsigned addr1, addr2; ++ uint128_t addr1, addr2; + int len; + + len = filt1.sa_len; +@@ -33,11 +33,11 @@ int sa_prefix_match(struct filter filt1, struct filter filt2){ + // Check source address prefixes + addr1 = filt1.sa; + // mask bits +- addr1 = ((addr1 >> (32-len)) << (32-len)); ++ addr1 = ((addr1 >> (128-len)) << (128-len)); + + addr2 = filt2.sa; + // mask bits +- addr2 = ((addr2 >> (32-len)) << (32-len)); ++ addr2 = ((addr2 >> (128-len)) << (128-len)); + } + // Check source address match + if (addr1 == addr2) return 1; +@@ -47,7 +47,7 @@ int sa_prefix_match(struct filter filt1, struct filter filt2){ + + int da_prefix_match(struct filter filt1, struct filter filt2){ + +- unsigned addr1, addr2; ++ uint128_t addr1, addr2; + int len; + + len = filt1.da_len; +@@ -59,11 +59,11 @@ int da_prefix_match(struct filter filt1, struct filter filt2){ + // Check source address prefixes + addr1 = filt1.da; + // mask bits +- addr1 = ((addr1 >> (32-len)) << (32-len)); ++ addr1 = ((addr1 >> (128-len)) << (128-len)); + + addr2 = filt2.da; + // mask bits +- addr2 = ((addr2 >> (32-len)) << (32-len)); ++ addr2 = ((addr2 >> (128-len)) << (128-len)); + } + + // Check source address match +diff --git a/sbintree.cc b/sbintree.cc +index d755099..062fbaf 100644 +--- a/sbintree.cc ++++ b/sbintree.cc +@@ -13,12 +13,12 @@ + + sbintree::sbintree() { + // Initialize to graph with N vertices and no edges. +- skew = new float[33]; +- p1child = new float[33]; +- p2child = new float[33]; ++ skew = new float[129]; ++ p1child = new float[129]; ++ p2child = new float[129]; + num_stnodes = 0; + root = NULL; +- for (int u = 0; u < 33; u++) { ++ for (int u = 0; u < 129; u++) { + skew[u] = 0; + p1child[u] = 0; + p2child[u] = 0; +@@ -26,9 +26,9 @@ sbintree::sbintree() { + } + + sbintree::~sbintree() { +- delete(skew); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } +@@ -96,13 +96,13 @@ void sbintree::read_skew(FILE* fp_in){ + // printf("matches = %d\n",matches); + // printf("level = %d, skew = %.4f\n",level,skew); + if (matches == 4) { +- if (level <= 32) { ++ if (level <= 128) { + p1child[level] = p1_t; + p2child[level] = p2_t; + skew[level] = f_skew; + } + else { +- fprintf(stderr,"Level for source address skew is greater than 32.\n"); ++ fprintf(stderr,"Level for source address skew is greater than 128.\n"); + exit(1); + } + // printf("Read line: %d\t%.4f\t%.4f\t%.4f\n",level,p1_t,p2_t,f_skew); +@@ -117,7 +117,7 @@ void sbintree::read_skew(FILE* fp_in){ + void sbintree::print_skew(FILE *fp) { + + fprintf(fp,"Level\tp1\tp2\tSkew\n"); +- for (int i = 0; i < 33; i++) { ++ for (int i = 0; i < 129; i++) { + fprintf(fp,"%d\t%.4f\t%.4f\t%.4f\n", + i,p1child[i],p2child[i],skew[i]); + } +@@ -125,7 +125,7 @@ void sbintree::print_skew(FILE *fp) { + } + + void sbintree::build_tree(dlist* Flist, struct filter filters[]){ +- unsigned int addr = 0; ++ uint128_t addr = 0; + // Create copy of list + dlist* temp_list = new dlist; + (*temp_list)=(Flist); +@@ -138,7 +138,7 @@ void sbintree::build_tree(dlist* Flist, struct filter filters[]){ + return; + } + +-void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr, dlist* Flist, struct filter filters[], int CurrNest){ ++void sbintree::add_node(struct stnode *prnt, int lev, int dir, uint128_t addr, dlist* Flist, struct filter filters[], int CurrNest){ + int Flist_size = 0; + /* + printf("add_node:\n"); +@@ -215,7 +215,7 @@ void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr + + double temp; + int path; +- unsigned int addr0, addr1; ++ uint128_t addr0, addr1; + int lev1; + + // If list is empty, return +@@ -231,19 +231,19 @@ void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr + if (lev == 0) { + addr0 = 0; + addr1 = 1; +- addr1 = addr1 << 31; ++ addr1 = addr1 << 127; + } else { +- addr0 = addr >> (32 - lev); +- addr0 = addr0 << (32 - lev); +- addr1 = addr >> (32 - lev); ++ addr0 = addr >> (128 - lev); ++ addr0 = addr0 << (128 - lev); ++ addr1 = addr >> (128 - lev); + addr1 = addr1 << 1; + addr1 += 1; +- addr1 = addr1 << (31 - lev); ++ addr1 = addr1 << (127 - lev); + } + // If at the nesting threshold and list has more than one child, + // then split list (allocate all nodes with level == lev1 to one path) + // printf("lev = %d, MyNest = %d, Nest = %d, lev1_flag = %d\n",lev,MyNest,Nest,lev1_flag); +- if ((Flist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 31)){ ++ if ((Flist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 127)){ + // Allocate nest_list + dlist *nest_list = new dlist(); + dlist *other_list = new dlist(); +@@ -291,6 +291,10 @@ void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr + add_node(me, lev1, 1, addr1, other_list, filters, MyNest); + } + } ++ ++ // Deallocate nest_list ++ delete(nest_list); ++ delete(other_list); + } + else { + // Othewise, branch based on branching probability and skew +diff --git a/sbintree.h b/sbintree.h +index b085696..8130000 100644 +--- a/sbintree.h ++++ b/sbintree.h +@@ -31,7 +31,7 @@ class sbintree { + float *p1child; // probability that a node at a given level has one child + float *p2child; // probability that a node at a given level has two children + int num_stnodes; // number of tree nodes +- void add_node(struct stnode *prnt, int lev, int dir, unsigned int addr, dlist* Flist, struct filter filters[], int CurrNest); ++ void add_node(struct stnode *prnt, int lev, int dir, uint128_t addr, dlist* Flist, struct filter filters[], int CurrNest); + int Nest; // Maximum allowed nesting + public: + sbintree(); +@@ -43,6 +43,17 @@ class sbintree { + void scale_skew(float scale_factor); // scale branching and skew according to scaling factor + void print_skew(FILE*); // print average skew per level + void build_tree(dlist* Flist, struct filter filters[]); ++ ++ // get methods for selected private members ++ inline float* get_skew() { ++ return skew; ++ }; ++ inline float* get_p1child() { ++ return p1child; ++ }; ++ inline float* get_p2child() { ++ return p2child; ++ }; + }; + + #endif +diff --git a/stdinc.h b/stdinc.h +index f566e0f..3c2f685 100644 +--- a/stdinc.h ++++ b/stdinc.h +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include "uint128_t.h" + + typedef char bit; + // const int false = 0; +@@ -24,7 +25,7 @@ inline double max(double x, double y) { return x > y ? x : y; } + inline int min(int x, int y) { return x < y ? x : y; } + inline double min(double x, double y) { return x < y ? x : y; } + inline int abs(int x) { return x < 0 ? -x : x; } +-inline bit isdigit(int c) { return (c >= '0') && (c <= '9'); } ++// inline bit isdigit(int c) { return (c >= '0') && (c <= '9'); } + + inline void warning(char* p) { fprintf(stderr,"Warning:%s \n",p); } + inline void fatal(char* string) {fprintf(stderr,"Fatal:%s\n",string); exit(1); } +@@ -49,15 +50,15 @@ inline int randgeo(double p) { return int(.999999 + log(randfrac())/log(1-p)); } + + // Filter database stuff + +-#define ADDRLEN 32 // IPv4 ++extern int ADDRLEN; // set in db_generator.cc + #define ADDRBYTES ADDRLEN/8 + #define MAXFILTERS 130000 + #define MAXSTR 100 + // #define NULL 0 + + struct filter { +- unsigned sa; // IP source address +- unsigned da; // IP destination address ++ uint128_t sa; // IP source address ++ uint128_t da; // IP destination address + int sa_len; // IP source address mask length + int da_len; // IP destination address mask length + int sp[2]; // Transport source port range [low,high] +@@ -69,6 +70,30 @@ struct filter { + int *ext_field; // Pointer to array of extra header fields + }; + ++// Do a deep copy of orig filter ++inline void copy_filter(struct filter& copy, struct filter orig) { ++ copy.sa = orig.sa; ++ copy.da = orig.da; ++ copy.sa_len = orig.sa_len; ++ copy.da_len = orig.da_len; ++ copy.sp[0] = orig.sp[0]; ++ copy.sp[1] = orig.sp[1]; ++ copy.dp[0] = orig.dp[0]; ++ copy.dp[1] = orig.dp[1]; ++ copy.prot_num = orig.prot_num; ++ copy.flags = orig.flags; ++ copy.flags_mask = orig.flags_mask; ++ copy.num_ext_field = orig.num_ext_field; ++ if (copy.num_ext_field > 0) { ++ copy.ext_field = new int[copy.num_ext_field]; ++ for (int i = 0; i < copy.num_ext_field; i++) { ++ copy.ext_field[i] = orig.ext_field[i]; ++ } ++ } else { ++ copy.ext_field = NULL; ++ } ++} ++ + struct range { + int low; + int high; +diff --git a/trie.cc b/trie.cc +new file mode 100644 +index 0000000..12f15de +--- /dev/null ++++ b/trie.cc +@@ -0,0 +1,1190 @@ ++// trie.cc: trie class definition ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "trie.h" ++ ++// Library includes ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Auxiliary class definitions ++// **************************************************************************** ++ ++class trie_nodes_greater_than_prefixes { ++public: ++ // implements operation "node1 is GREATER THAN node2" ++ // according to the number of prefixes ++ bool operator()(trie_node* node1, trie_node* node2) ++ { ++ if (node2->prefixes < node1->prefixes) { ++ return true; ++ } else { ++ return false; ++ } ++ } ++}; ++ ++class trie_nodes_greater_than_weight { ++public: ++ // implements operation "node1 is GREATER THAN node2" ++ // according to the total weight of nodes' subtrees ++ bool operator()(trie_node* node1, trie_node* node2) ++ { ++ if ((node2->zero_weight + node2->one_weight) < ++ (node1->zero_weight + node1->one_weight)) { ++ return true; ++ } else { ++ return false; ++ } ++ } ++}; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++trie_node* Trie::copy(const trie_node* node, int level) { ++ // create a pointer to the root of a new trie ++ trie_node* copy_root; ++ // copy the given subtree ++ if (node != NULL) { // non-empty subtree ++ copy_root = new trie_node; ++ copy_root->level = level; ++ copy_root->prefixes = node->prefixes; ++ copy_root->prefix_nesting_branches = node->prefix_nesting_branches; ++ copy_root->zero = copy(node->zero, level+1); ++ copy_root->zero_weight = node->zero_weight; ++ copy_root->one = copy(node->one, level+1); ++ copy_root->one_weight = node->one_weight; ++ } else { // empty subtree ++ copy_root = NULL; ++ } ++ // return the pointer to the root node of the copy ++ return copy_root; ++} // end copy() ++ ++ ++void Trie::destruct(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ destruct(node->zero); ++ destruct(node->one); ++ delete node; ++ } ++ return; ++} // end destruct() ++ ++ ++int Trie::compute_weights(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ node->zero_weight = compute_weights(node->zero); ++ node->one_weight = compute_weights(node->one); ++ return node->zero_weight + node->one_weight + node->prefixes; ++ } else { // empty subtree ++ return 0; ++ } ++} // end compute_weights() ++ ++ ++float Trie::compute_skew(trie_node* node) { ++ if (node->zero_weight > node->one_weight) { // lighter 1-subtree ++ return 1 - ((float)node->one_weight / (float)node->zero_weight); ++ } else { // lighter 0-subtree ++ return 1 - ((float)node->zero_weight / (float)node->one_weight); ++ } ++} // end compute_skew() ++ ++ ++int Trie::get_prefix_nesting(const trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ // get prefix nesting from successor nodes ++ int zero_nesting = get_prefix_nesting(node->zero); ++ int one_nesting = get_prefix_nesting(node->one); ++ // will this node increase prefix nesting? ++ int is_prefix; ++ if (node->prefixes > 0) { // this is a prefix node ++ is_prefix = 1; ++ } else { ++ is_prefix = 0; ++ } ++ // return maximum of successors' nesting, possibly incremented ++ if (zero_nesting > one_nesting) { ++ return zero_nesting + is_prefix; ++ } else { ++ return one_nesting + is_prefix; ++ } ++ } else { // empty subtree ++ return 0; ++ } ++} // end get_prefix_nesting() ++ ++ ++void Trie::remove_lightest_subtree(queue q, bool one_child, ++ int prefix_nesting_branches) { ++ trie_node** lightest_subtree_ptr = NULL; ++ int* lightest_weight_ptr = NULL; ++ // find the lightest subtree of nodes stored in the queue ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // auxiliary variables ++ trie_node** subtree_ptr = NULL; ++ int* weight_ptr = NULL; ++ if (one_child) { // consider only nodes with one child ++ // consider only nodes that can become a valid leaf node ++ if (node->prefixes > 0) { ++ // one-subtree only ++ if ((node->zero == NULL) && (node->one != NULL)) { ++ // the last maximum prefix nesting branch is not going through ++ // the one-subtree ++ if (node->one->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->one); ++ weight_ptr = &(node->one_weight); ++ } ++ // zero-subtree only ++ } else if ((node->zero != NULL) && (node->one == NULL)) { ++ // the last maximum prefix nesting branch is not going through ++ // the zero-subtree ++ if (node->zero->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->zero); ++ weight_ptr = &(node->zero_weight); ++ } ++ } ++ } ++ } else { // consider only nodes with two children ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // determine lighter subtree ++ if (node->zero_weight <= node->one_weight) { ++ // the last maximum prefix nesting branch is not going through ++ // the zero-subtree ++ if (node->zero->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->zero); ++ weight_ptr = &(node->zero_weight); ++ } ++ } else { ++ // the last maximum prefix nesting branch is not going through ++ // the one-subtree ++ if (node->one->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->one); ++ weight_ptr = &(node->one_weight); ++ } ++ } ++ } ++ } ++ // no lightest subtree has been found so far ++ if (lightest_weight_ptr == NULL) { ++ if (weight_ptr != NULL) { // new candidate for the lightest subtree ++ lightest_subtree_ptr = subtree_ptr; ++ lightest_weight_ptr = weight_ptr; ++ } ++ } else { // a candidate for the lightest subtree has already been found ++ if (weight_ptr != NULL) { // new candidate for the lightest subtree ++ // new lightest subtree ++ if ((*weight_ptr) < (*lightest_weight_ptr)) { ++ lightest_subtree_ptr = subtree_ptr; ++ lightest_weight_ptr = weight_ptr; ++ } ++ } ++ } ++ } // end of while (!q.empty()) ++ // if lightest subtree, which can be removed, has been found ++ if (lightest_subtree_ptr != NULL) { ++ destruct(*lightest_subtree_ptr); ++ *lightest_subtree_ptr = NULL; ++ *lightest_weight_ptr = 0; ++ } ++ return; ++} // end remove_lightest_subtree() ++ ++ ++int Trie::mark_prefix_nesting_branches(trie_node* node, int prefix_nesting, ++ int seen_prefixes) { ++ if (node == NULL) { // empty subtree ++ return 0; ++ } ++ if (node->prefixes > 0) { // the current root node is a prefix node ++ seen_prefixes++; ++ } ++ // when a prefix nesting branch has been found ++ if (seen_prefixes == prefix_nesting) { ++ node->prefix_nesting_branches = 1; ++ } else { // look for maximum prefix nesting branches in subtrees ++ int branches_zero = mark_prefix_nesting_branches(node->zero, ++ prefix_nesting, ++ seen_prefixes); ++ int branches_one = mark_prefix_nesting_branches(node->one, ++ prefix_nesting, ++ seen_prefixes); ++ node->prefix_nesting_branches = branches_zero + branches_one; ++ } ++ return node->prefix_nesting_branches; ++} // end mark_refix_nesting_branches() ++ ++ ++int Trie::get_removable_prefixes(trie_node* node) { ++ if (node == NULL) { ++ return 0; ++ } ++ int removable_prefixes_zero = get_removable_prefixes(node->zero); ++ int removable_prefixes_one = get_removable_prefixes(node->one); ++ int removable_prefixes_this = node->prefixes; ++ // keep at least one prefix in a leaf node ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_this--; ++ } ++ // different handling for 2-children node ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // allow removing prefixes from subtrees only if both subtrees contain ++ // removable prefixes ++ if ((removable_prefixes_zero > 0) && (removable_prefixes_one > 0)) { ++ // initialize auxiliar variables ++ int zero_weight = node->zero_weight; ++ int one_weight = node->one_weight; ++ int d = 1; // divisor of zero_weight and one_weight ++ int x = 0; // to be removed prefixes from zero subtree ++ int y = 0; // to be removed prefixes from one subtree ++ // find x and y such that ++ // a) x <= removable_prefixes_zero ++ // b) y <= removable_prefixes_one ++ // where ++ // x = zero_weight - (zero_weight / gcd) ++ // y = one_weight - (one_weight / gcd) ++ // and gcd is the gratest common divisor of zero_weight and one_weight ++ while ((d <= zero_weight) && (d <= one_weight)) { ++ // if d is the gcd ++ if (((zero_weight % d) == 0) && ((one_weight % d) == 0)) { ++ // if to be removed prefixes from both zero and one subtrees is ++ // smaller than removable prefixes from these subtrees ++ if ((zero_weight - zero_weight / d <= removable_prefixes_zero) ++ && ++ (one_weight - one_weight / d <= removable_prefixes_one)) { ++ x = zero_weight - (zero_weight / d); ++ y = one_weight - (one_weight / d); ++ } else { ++ break; ++ } ++ } ++ d++; ++ } ++ // return the total number of prefixes that can be removed without ++ // altering the skew ++ return removable_prefixes_this + ++ x + ++ y; ++ } else { ++ return removable_prefixes_this; ++ } ++ } else { ++ return removable_prefixes_this + ++ removable_prefixes_zero + ++ removable_prefixes_one; ++ } ++} // end get_removable_prefixes ++ ++ ++void Trie::adjust_node_skew(trie_node* node, float target_skew) { ++ // initialize lighter_* and heavier_* variables ++ int lighter_weight; ++ int heavier_weight; ++ trie_node* lighter_subtree; ++ trie_node* heavier_subtree; ++ // initialize auxiliary variables for skew computation ++ float skew; ++ int zero_weight = node->zero_weight; ++ int one_weight = node->one_weight; ++ // compute skew of the given node and set lighter_* and heavier_* variables ++ if (zero_weight > one_weight) { // zero subtree is heavier ++ skew = 1 - ((float)one_weight / (float)zero_weight); ++ lighter_weight = one_weight; ++ heavier_weight = zero_weight; ++ lighter_subtree = node->one; ++ heavier_subtree = node->zero; ++ } else { // one subtree is heavier ++ skew = 1 - ((float)zero_weight / (float)one_weight); ++ lighter_weight = zero_weight; ++ heavier_weight = one_weight; ++ lighter_subtree = node->zero; ++ heavier_subtree = node->one; ++ } ++ // initialize auxiliary variables ++ double new_weight_real; ++ int weight; ++ trie_node* subtree; ++ // decrease working skew - remove prefixes from heavier subtree ++ if ((skew - target_skew) > 0) { ++ new_weight_real = lighter_weight / (1 - target_skew); ++ weight = heavier_weight; ++ subtree = heavier_subtree; ++ // increase working skew - remove prefixes from lighter subtree ++ } else { ++ new_weight_real = heavier_weight * (1 - target_skew); ++ weight = lighter_weight; ++ subtree = lighter_subtree; ++ } ++ // determine new integer weight of a selected subtree ++ int new_weight = round(new_weight_real); ++ // determine number of prefixes that will be removed ++ int remove_prefixes = weight - new_weight; ++ int removable_prefixes = get_removable_prefixes(subtree); ++ if (remove_prefixes > removable_prefixes) { ++ // decrease the number of removed prefixes to the maximum number of ++ // prefixes that can be removed ++ remove_prefixes = removable_prefixes; ++ } ++ // make the selected subtree lighter by removing the given number of ++ //prefixes ++ make_subtree_lighter(subtree, remove_prefixes); ++ compute_weights(node); ++ return; ++} // end adjust_node_skew() ++ ++ ++void Trie::make_subtree_lighter(trie_node* root, int remove_prefixes) { ++ // nothing to do when the subtree is empty or 0 prefixes are to be removed ++ if ((root == NULL) || (remove_prefixes == 0)) { ++ return; ++ } ++ // auxiliary variables for counting statistics ++ trie_node* node = root; ++ int removable_prefixes_node = 0; ++ int removable_prefixes_branch = 0; ++ // in priority queue, nodes with less prefixes have higher priority ++ priority_queue, ++ trie_nodes_greater_than_prefixes> pq; ++ // initialize auxiliary variables (keep at least one prefix in a leaf node) ++ removable_prefixes_node = node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ if (removable_prefixes_node > 0) { ++ removable_prefixes_branch = removable_prefixes_node; ++ pq.push(node); ++ } ++ // traverse a non-branching part of the subtree (i.e. up to the closest ++ // 2-children node or a leaf node) and compute basic statistics about it ++ while (((node->zero == NULL) && (node->one != NULL)) || ++ ((node->zero != NULL) && (node->one == NULL))) { ++ // determine the next step ++ if (node->zero == NULL) { ++ node = node->one; ++ } else { ++ node = node->zero; ++ } ++ // compute statistics (keep at least one prefix in a leaf node) ++ removable_prefixes_node = node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ if (removable_prefixes_node > 0) { ++ removable_prefixes_branch += removable_prefixes_node; ++ pq.push(node); ++ } ++ } ++ // get the number of removable prefixes in the remaining subtree ++ int removable_prefixes_subtree = get_removable_prefixes(node); ++ int removable_prefixes_zero = 0; ++ // adjust it to not contain removable prefixes of the subtree's root node ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_subtree = 0; ++ } else { ++ removable_prefixes_subtree -= node->prefixes; ++ } ++ // get the number of removable prefixes in branches of the remaining subtree ++ if (removable_prefixes_subtree > 0) { ++ int subtree_weight = node->zero_weight + node->one_weight; ++ removable_prefixes_zero = ++ round(((float)node->zero_weight / (float)subtree_weight) * ++ removable_prefixes_subtree); ++ } ++ // do not continue when no removable prefixes in the branch nor the subtree ++ if ((removable_prefixes_branch + removable_prefixes_subtree) == 0) { ++ return; ++ } ++ // distribute prefixes that are to be removed between the branch and the ++ // subtree ++ int remove_prefixes_branch = round(((float)removable_prefixes_branch / ++ (float)(removable_prefixes_subtree + ++ removable_prefixes_branch)) * ++ remove_prefixes); ++ int remove_prefixes_subtree = remove_prefixes - remove_prefixes_branch; ++ // initialize auxiliary variable for test purposes ++ int removed_prefixes_branch = 0; ++ // while there are some prefix nodes in the branch, remove prefixes ++ // proportionally from all these nodes ++ while (!pq.empty()) { ++ // deque the front element from the priority queue ++ trie_node* working_node = pq.top(); ++ pq.pop(); ++ // determine the number of prefixes that are to be removed from this node ++ int remove_prefixes_node; ++ if (!pq.empty()) { // not the last node of the branch ++ // keep at least one prefix in a leaf node ++ removable_prefixes_node = working_node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ // the nuber of prefixes to be removed is computed proportionally ++ remove_prefixes_node = round(((float)removable_prefixes_node / ++ (float)removable_prefixes_branch) * ++ remove_prefixes_branch); ++ } else { // the last node of the branch ++ // the number of prefixes to be removed ensures removing all the remaining prefixes ++ remove_prefixes_node = remove_prefixes_branch - removed_prefixes_branch; ++ } ++ // remove the given number of prefixes ++ working_node->prefixes -= remove_prefixes_node; ++ // adjust the test variable ++ removed_prefixes_branch += remove_prefixes_node; ++ } ++ // the last node in the non-branching part of the subtree is a 2-children ++ // node ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // there are some prefixes to be removed from the subtree rooted at node ++ if (remove_prefixes_subtree > 0) { ++ // distribute prefixes that are to be removed from from the subtree ++ // between its zero and one subtrees ++ int remove_prefixes_zero = round(((float)removable_prefixes_zero / ++ (float)removable_prefixes_subtree) * ++ remove_prefixes_subtree); ++ int remove_prefixes_one = remove_prefixes_subtree - ++ remove_prefixes_zero; ++ // remove prefixes from subtrees of the 2-children node ++ compute_weights(node); ++ make_subtree_lighter(node->zero, remove_prefixes_zero); ++ make_subtree_lighter(node->one, remove_prefixes_one); ++ compute_weights(node); ++ } ++ } ++ return; ++} // end make_subtree_lighter() ++ ++ ++trie_node* Trie::remove_nonprefix_branches(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ node->zero = remove_nonprefix_branches(node->zero); ++ node->one = remove_nonprefix_branches(node->one); ++ if ((node->zero == NULL) && (node->one == NULL) && ++ (node->prefixes == 0)) { ++ delete node; ++ return NULL; ++ } ++ } ++ return node; ++} //end remove_nonprefix_branches() ++ ++ ++void Trie::adjust_branching(vector branching_one_child, ++ vector branching_two_children) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // recursively compute weight of all subtrees ++ compute_weights(root); ++ // recursively compute maximum prefix nesting ++ int prefix_nesting = get_prefix_nesting(root); ++ // mark branches with maximum prefix nesting ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ // initialize auxiliary variables ++ queue q; ++ q.push(root); ++ int level = -1; ++ // do a breadth-first search ++ while (!q.empty()) { ++ // get pointer to the front element ++ trie_node* node = q.front(); ++ // first node at this level - perform branching adjustment ++ // (all nodes from the current level are enqueued) ++ if (node->level != level) { ++ level = node->level; ++ // compute branching statistics for this level ++ queue q_copy (q); ++ int one_child = 0; ++ int two_children = 0; ++ int sum = 0; ++ while (!q_copy.empty()) { ++ // dequeue front element from the auxiliary queue ++ trie_node* node_copy = q_copy.front(); ++ q_copy.pop(); ++ // increment correct counter ++ if ((node_copy->zero != NULL) && (node_copy->one != NULL)) { ++ two_children++; ++ } else if ((node_copy->zero != NULL) || (node_copy->one != NULL)) { ++ one_child++; ++ } ++ } ++ sum = one_child + two_children; ++ // branching probabilities are defined at this level ++ if (sum != 0) { // there is some branching at this level ++ float current_branching_two = (float) two_children / (float) (sum); ++ // adjust branching by reducing the number of two-children nodes ++ if (current_branching_two > branching_two_children[level]) { ++ // determine the ideal number of subtree removing steps ++ float remove_subtrees = two_children - ++ (branching_two_children[level] * sum); ++ // diff from ideal branching when remove min./max. subtrees ++ float diff_min = ((two_children - floor(remove_subtrees)) / sum) ++ - branching_two_children[level]; ++ float diff_max = branching_two_children[level] - ++ ((two_children - ceil(remove_subtrees)) / sum); ++ // determine the number of subtree removing steps ++ int remove_steps = 0; ++ if (diff_min <= diff_max) { ++ remove_steps = (int) floor(remove_subtrees); ++ } else { ++ remove_steps = (int) ceil(remove_subtrees); ++ } ++ // remove the given number of "lightest" subtrees + ++ // actualize markers of maximum prefix nesting branches ++ for (int i = 0; i < remove_steps; i++) { ++ remove_lightest_subtree(q, false, ++ root->prefix_nesting_branches); ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ } ++ // adjust branching nodes count variables ++ one_child += remove_steps; ++ two_children -= remove_steps; ++ } ++ // removing subtree of one-child nodes can change branching ++ // probabilities ++ if (two_children != 0) { ++ float current_branching_one = (float) one_child / (float) (sum); ++ // adjust branching by reducing the number of one-child nodes ++ if (current_branching_one > branching_one_child[level]) { ++ // determine the ideal number of subtree removing steps ++ float remove_subtrees = ++ ((branching_one_child[level] * sum) - one_child) / ++ (branching_one_child[level] - 1); ++ // diff from ideal branching when remove min./max. subtrees ++ float diff_min = ((one_child - floor(remove_subtrees)) / ++ (sum - floor(remove_subtrees))) - ++ branching_one_child[level]; ++ float diff_max = branching_one_child[level] - ++ ((one_child - ceil(remove_subtrees)) / ++ (sum - ceil(remove_subtrees))); ++ // determine the number of subtree removing steps ++ int remove_steps = 0; ++ if (diff_min <= diff_max) { ++ remove_steps = (int) floor(remove_subtrees); ++ } else { ++ remove_steps = (int) ceil(remove_subtrees); ++ } ++ // remove the given number of "lightest" subtrees + ++ // actualize markers of maximum prefix nesting branches ++ for (int i = 0; i < remove_steps; i++) { ++ remove_lightest_subtree(q, true, ++ root->prefix_nesting_branches); ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ } ++ one_child -= remove_steps; ++ sum -= remove_steps; ++ } ++ } ++ } // end of if (sum != 0) ++ } // end of if (node->level != level) ++ // enqueue possible successors of the current node ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // remove the front element from the queue ++ q.pop(); ++ } // end of while (!q.empty()) ++ return; ++} // end adjust_branching() ++ ++ ++void Trie::adjust_skew(vector skew, float skew_epsilon) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // initialize auxiliary variables ++ queue q; ++ stack s; ++ q.push(root); ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue front element from the queue ++ trie_node* node = q.front(); ++ q.pop(); ++ // store nodes with 2 children into a stack ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ s.push(node); ++ } ++ // enqueue possible successors of the current node ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ } ++ // initialize auxiliary variables ++ // in priority queue, lighter nodes have higher priority ++ priority_queue, ++ trie_nodes_greater_than_weight> pq; ++ float total_skew = 0.0; ++ int level; ++ if (!s.empty()) { ++ level = s.top()->level; ++ } ++ // do inverse breadth-first search on two-children nodes ++ while (!s.empty()) { ++ // pop top element from the stack ++ trie_node* node = s.top(); ++ s.pop(); ++ // next level - adjust total skew of the current level ++ if (level != node->level) { ++ // store the number of 2-children nodes at current level ++ int two_children_nodes = pq.size(); ++ // compute target total skew ("sum of all skew values at this level") ++ float target_total_skew = skew[level] * two_children_nodes; ++ // compute skew that is going to be added/removed ++ float skew_change = target_total_skew - total_skew; ++ // compute average skew that is going to be added/removed ++ float average_skew_change; ++ if (two_children_nodes > 0) { ++ average_skew_change = skew_change / (float)two_children_nodes; ++ } else { ++ average_skew_change = skew_change; ++ } ++ // iteratively adjust total skew at this level ++ while (!pq.empty()) { ++ // skip further skew adjustment when average_skew_change is less ++ // than the given skew_epsilon ++ if (abs(average_skew_change) < skew_epsilon) { ++ // remove remaining nodes from the priority queue ++ while (!pq.empty()) { ++ pq.pop(); ++ } ++ // end the outer "while (!pq.empty())" loop ++ break; ++ } ++ // pop the top element from the priority queue ++ trie_node* working_node = pq.top(); ++ pq.pop(); ++ // compute original skew of the working node ++ float original_skew = compute_skew(working_node); ++ float target_skew = original_skew + skew_change; ++ // adjust skew of the working node ++ if (target_skew < 0.0) { ++ target_skew = 0.0; ++ } else if (target_skew > 1.0) { ++ target_skew = 1.0; ++ } ++ adjust_node_skew(working_node, target_skew); ++ // recursively compute weight of node's subtrees ++ compute_weights(working_node); ++ // compute adjusted skew of the working node ++ float adjusted_skew = compute_skew(working_node); ++ // update total skew, skew that is going to be added/removed, and ++ // its average value ++ total_skew = total_skew - original_skew + adjusted_skew; ++ skew_change = target_total_skew - total_skew; ++ two_children_nodes = pq.size(); ++ if (two_children_nodes > 0) { ++ average_skew_change = skew_change / (float)two_children_nodes; ++ } else { ++ average_skew_change = skew_change; ++ } ++ } ++ level = node->level; ++ total_skew = 0.0; ++ } ++ // recursively compute weight of node's subtrees ++ compute_weights(node); ++ // insert the node into the priority queue ++ pq.push(node); ++ // actualize total skew value ++ total_skew += compute_skew(node); ++ } ++ return; ++} // end adjust_skew() ++ ++ ++void Trie::adjust_prefixes(vector prefixes_proportion, ++ const int target_size) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // compute the total number of prefixes at each level ++ vector all_prefixes(129,0); ++ queue q; ++ q.push(root); ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // enqueue its possible successors ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // update the total number of prefixes at current level ++ all_prefixes[node->level] += node->prefixes; ++ } ++ // compute the number of target and to be removed prefixes at each level ++ vector target_prefixes(129,0); ++ vector remove_prefixes(129,0); ++ int target_prefixes_total = 0; ++ int leaf_level = 0; ++ for (int i = 0; i < (int) prefixes_proportion.size(); i++) { ++ target_prefixes[i] = round(prefixes_proportion[i]*target_size); ++ target_prefixes_total += target_prefixes[i]; ++ remove_prefixes[i] = all_prefixes[i] - target_prefixes[i]; ++ if (target_prefixes[i] != 0) { ++ leaf_level = i; ++ } ++ } ++ // final correction to given target_size ++ if (target_prefixes_total != target_size) { ++ int diff = target_size - target_prefixes_total; ++ target_prefixes[leaf_level] += diff; ++ target_prefixes_total += diff; ++ remove_prefixes[leaf_level] -= diff; ++ } ++ // compute the number of prefixes to be removed at remaining levels ++ vector remove_prefixes_remaining(129,0); ++ for (int i = 127; i >= 0; i--) { ++ remove_prefixes_remaining[i] = remove_prefixes_remaining[i+1] + ++ remove_prefixes[i+1]; ++ } ++ // starting from the root, adjust prefixes distribution ++ queue nodes; ++ nodes.push(root); ++ queue remove_prefixes_subtrees; ++ remove_prefixes_subtrees.push(remove_prefixes[0] + remove_prefixes_remaining[0]); ++ int level = -1; ++ while (!nodes.empty()) { ++ // get the front element ++ // (from both nodes and remove_prefixes_subtrees queues) ++ trie_node* node = nodes.front(); ++ // next level - adjust prefixes at this level ++ // (all nodes of this level are stored in nodes queue) ++ if (node->level != level) { ++ level = node->level; ++ // actualize subtrees' weight information in nodes ++ compute_weights(root); ++ // initialize vectors to contain all current elements of queues ++ queue nodes_copy (nodes); ++ vector nodes_vect; ++ queue remove_prefixes_subtrees_copy (remove_prefixes_subtrees); ++ vector remove_prefixes_subtrees_vect; ++ while (!nodes_copy.empty()) { ++ nodes_vect.push_back(nodes_copy.front()); ++ nodes_copy.pop(); ++ remove_prefixes_subtrees_vect.push_back(remove_prefixes_subtrees_copy.front()); ++ remove_prefixes_subtrees_copy.pop(); ++ } ++ // from all leaf nodes at this level ++ // remove prefixes that have to be removed ++ int i = 0; ++ while (i < (int) nodes_vect.size()) { ++ if ((nodes_vect[i]->zero == NULL) && ++ (nodes_vect[i]->one == NULL)) { ++ // determine the real number of prefixes to be removed ++ // (do not remove the last prefix from a leaf node) ++ int remove_prefixes_node; ++ if (nodes_vect[i]->prefixes > remove_prefixes_subtrees_vect[i]) { ++ remove_prefixes_node = remove_prefixes_subtrees_vect[i]; ++ } else { ++ remove_prefixes_node = nodes_vect[i]->prefixes - 1; ++ } ++ // consider all prefixes of this node and this subtree to be ++ // removed, regardless they are really removed or not ++ // (in any case, there are no other prefixes that could be ++ // removed) ++ all_prefixes[level] -= nodes_vect[i]->prefixes; ++ remove_prefixes_subtrees_vect[i] = 0; ++ // remove the prefixes ++ nodes_vect[i]->prefixes -= remove_prefixes_node; ++ remove_prefixes[level] -= remove_prefixes_node; ++ // remove this node from both vectors ++ nodes_vect.erase(nodes_vect.begin()+i); ++ remove_prefixes_subtrees_vect.erase(remove_prefixes_subtrees_vect.begin()+i); ++ } else { ++ // the node has not been removed, thus increase the index ++ i++; ++ } ++ } ++ // if there are some nodes with prefixes that could be removed AND ++ // the number of prefixes to be removed is not negative ++ if ((all_prefixes[level] > 0) && (remove_prefixes[level] >= 0)) { ++ // initialize auxiliary constant (for this level) ++ float remove_all_ratio = (float)(remove_prefixes[level]) / ++ (float)(all_prefixes[level]); ++ // from all non-leaf nodes at this level ++ // remove prefixes that are to be removed at this level ++ for (int i = 0; i < (int) nodes_vect.size(); i++) { ++ int remove_prefixes_node = round((float)(nodes_vect[i]->prefixes) * ++ remove_all_ratio); ++ // do not remove more than all prefixes to be removed from this subtree ++ if (remove_prefixes_node > remove_prefixes_subtrees_vect[i]) { ++ remove_prefixes_node = remove_prefixes_subtrees_vect[i]; ++ } ++ // do not remove more than all prefixes of this node ++ if (remove_prefixes_node > nodes_vect[i]->prefixes) { ++ remove_prefixes_node = nodes_vect[i]->prefixes; ++ } ++ // remove the prefixes and adjust other variables ++ nodes_vect[i]->prefixes -= remove_prefixes_node; ++ all_prefixes[level] -= remove_prefixes_node; ++ remove_prefixes[level] -= remove_prefixes_node; ++ remove_prefixes_subtrees_vect[i] -= remove_prefixes_node; ++ } ++ } ++ // for all nodes at this level ++ // distribute prefixes to be removed in a subtree rooted at this node ++ // into node's subtrees ++ for (int i = 0; i < (int) nodes_vect.size(); i++) { ++ // distribution for 2-children nodes ++ if ((nodes_vect[i]->zero != NULL) && (nodes_vect[i]->one != NULL)) { ++ // determine the distribution ++ int total_weight = nodes_vect[i]->zero_weight + ++ nodes_vect[i]->one_weight; ++ int remove_prefixes_zero = round(((float)(nodes_vect[i]->zero_weight) / ++ (float)total_weight) * ++ (float)(remove_prefixes_subtrees_vect[i])); ++ int remove_prefixes_one = remove_prefixes_subtrees_vect[i] - ++ remove_prefixes_zero; ++ // do not remove more than all prefixes from zero subtree ++ if (remove_prefixes_zero > nodes_vect[i]->zero_weight) { ++ remove_prefixes_zero = nodes_vect[i]->zero_weight; ++ } ++ // do not remove more than all prefixes from one subtree ++ if (remove_prefixes_one > nodes_vect[i]->one_weight) { ++ remove_prefixes_one = nodes_vect[i]->one_weight; ++ } ++ // store the distribution into main queues ++ nodes.push(nodes_vect[i]->zero); ++ remove_prefixes_subtrees.push(remove_prefixes_zero); ++ nodes.push(nodes_vect[i]->one); ++ remove_prefixes_subtrees.push(remove_prefixes_one); ++ } else { ++ // distribution for 1-child nodes ++ if (nodes_vect[i]->zero != NULL) { ++ nodes.push(nodes_vect[i]->zero); ++ } else if (nodes_vect[i]->one != NULL) { ++ nodes.push(nodes_vect[i]->one); ++ } ++ remove_prefixes_subtrees.push(remove_prefixes_subtrees_vect[i]); ++ } ++ } ++ } ++ // remove the front elements from the main queues ++ nodes.pop(); ++ remove_prefixes_subtrees.pop(); ++ } ++ return; ++} // end adjust_prefixes() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++// Default constructor ++Trie::Trie() { ++ root = NULL; ++} // end Trie() ++ ++ ++// Copy constructor ++Trie::Trie(const Trie& orig) { ++ root = copy(orig.get_root(), 0); ++} // end Trie() ++ ++ ++// Destructor ++Trie::~Trie() { ++ destruct(root); ++} // end ~Trie() ++ ++ ++// Copy assignment ++Trie& Trie::operator= (const Trie& orig) { ++ // replace the original trie by a copy of the assigned trie ++ destruct(root); ++ root = copy(orig.get_root(), 0); ++ // return created object ++ return *this; ++} // end operator= () ++ ++ ++void Trie::insert(const IP_prefix& pref) { ++ // insert at least a root node when the trie is empty ++ if (root == NULL) { ++ root = new trie_node; ++ root->level = 0; ++ root->prefixes = 0; ++ root->prefix_nesting_branches = 0; ++ root->zero = NULL; ++ root->zero_weight = 0; ++ root->one = NULL; ++ root->one_weight = 0; ++ } ++ // insert the given prefix into the trie ++ if (pref.get_length() == 0) { // prefix of length 0 ++ (root->prefixes)++; ++ } else { // prefix of length > 0 ++ // auxiliary variables ++ trie_node* node = root; ++ trie_node** next_node_ptr; ++ string prefix = pref.get_prefix(); ++ // trie traversal ++ for (int i = 0; i < pref.get_length(); i++) { ++ // determine the next node and store the pointer to it ++ if (prefix[i] == '0') { ++ next_node_ptr = &(node->zero); ++ } else { // (prefix[i] == '1') ++ next_node_ptr = &(node->one); ++ } ++ // insert the next node if it does not exist ++ if ((*next_node_ptr) == NULL) { ++ (*next_node_ptr) = new trie_node; ++ (*next_node_ptr)->level = i+1; ++ (*next_node_ptr)->prefixes = 0; ++ (*next_node_ptr)->prefix_nesting_branches = 0; ++ (*next_node_ptr)->zero = NULL; ++ (*next_node_ptr)->zero_weight = 0; ++ (*next_node_ptr)->one = NULL; ++ (*next_node_ptr)->one_weight = 0; ++ } ++ // move to the next node; ++ node = (*next_node_ptr); ++ } ++ // prefix insertion ++ (node->prefixes)++; ++ } ++ return; ++} // end insert() ++ ++ ++bool Trie::erase(const IP_prefix& pref) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return root; ++ } ++ // search for the given prefix ++ if (pref.get_length() == 0) { // prefix of length 0 ++ if (root->prefixes > 0) { // we have found the prefix node ++ (root->prefixes)--; ++ if ((root->prefixes == 0) && ++ (root->zero == NULL) && ++ (root->one == NULL)) { ++ // all the conditions for removing the node were met ++ destruct(root); ++ root = NULL; ++ } ++ return true; ++ } else { // the corresponding node is a non-prefix node ++ return false; ++ } ++ } else { // prefix of length > 0 ++ // auxiliary variables ++ trie_node* node = root; ++ trie_node** destruct_root = &(root); ++ string prefix = pref.get_prefix(); ++ for (int i = 0; i < pref.get_length(); i++) { ++ // determine the next node ++ if (prefix[i] == '0') { ++ // adjust desctruct_root ++ if ((node->prefixes != 0) || ++ (node->one != NULL)) { // this node cannot be removed ++ destruct_root = &(node->zero); ++ } ++ // move to the next node ++ node = node->zero; ++ } else { // (prefix[i] == '1') ++ // adjust desctruct_root ++ if ((node->prefixes != 0) || ++ (node->zero != NULL)) { // this node cannot be removed ++ destruct_root = &(node->one); ++ } ++ // move to the next node ++ node = node->one; ++ } ++ // chceck whether the next node exists (terminate search if not) ++ if (node == NULL) { ++ return false; ++ } ++ } ++ if (node->prefixes > 0) { // we have found the prefix node ++ (node->prefixes)--; ++ if ((node->prefixes == 0) && ++ (node->zero == NULL) && ++ (node->one == NULL)) { ++ // all the conditions for removing the node were met ++ destruct(*destruct_root); ++ *destruct_root = NULL; ++ } ++ return true; ++ } else { // the corresponding node is a non-prefix node ++ return false; ++ } ++ } ++} // end erase() ++ ++ ++void Trie::prune(const int target_size, ++ const vector& prefixes, ++ const vector& one_child, ++ const vector& two_children, ++ const vector& skew, ++ const int iterations) { ++ // get original prefix set size ++ trie_stats s; ++ this->get_stats(s); ++ int orig_size = s.classbench.prefixes; ++ ++ // adjust branching (1st step of trie pruning) ++ this->adjust_branching(one_child, two_children); ++ ++ // iteratively adjust skew and prefixes proportion ++ // (multiple iterations help to reduce the negative effect of ++ // adjust_prefixes function on skew) ++ for (int i = 1; i <= iterations; i++) { ++ // adjust skew (2nd step of trie pruning) ++ this->adjust_skew(skew); ++ // adjust prefixes proportion (3rd step of trie pruning) ++ if (i == iterations) { ++ this->adjust_prefixes(prefixes, target_size); ++ } else { ++ this->adjust_prefixes(prefixes, round((1-(float)i/4)*orig_size)); ++ } ++ } ++} // end prune() ++ ++ ++void Trie::get_stats(trie_stats& stats) { ++ // initialize classbench statistics ++ stats.classbench.prefixes = 0; ++ stats.classbench.prefix_lengths = vector(129,0); ++ stats.classbench.branching_one_child = vector(129,0.0); ++ stats.classbench.branching_two_children = vector(129,0.0); ++ stats.classbench.skew = vector(129,0.0); ++ stats.classbench.prefix_nesting = 0; ++ // initialize nodes statistics ++ stats.nodes.leaf = vector(129,0); ++ stats.nodes.one_child = vector(129,0); ++ stats.nodes.two_children = vector(129,0); ++ stats.nodes.prefix = vector(129,0); ++ stats.nodes.non_prefix = vector(129,0); ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // compute zero_weight and one_weight in each node of the trie ++ compute_weights(root); ++ // initialize auxiliary variables ++ queue q; ++ q.push(root); ++ int level = root->level; ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // enqueue its possible successors ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // level change - finish statistics computation for the previous level ++ if (node->level != level) { ++ // auxiliary variables ++ int one_child = stats.nodes.one_child[level]; ++ int two_children = stats.nodes.two_children[level]; ++ int sum = one_child + two_children; ++ // branching_one_child and branching_two_children ++ if (sum != 0) { ++ stats.classbench.branching_one_child[level] = ++ (float)one_child / (float)sum; ++ stats.classbench.branching_two_children[level] = ++ (float)two_children / (float)sum; ++ } ++ // skew ++ if (two_children != 0) { ++ stats.classbench.skew[level] /= (float)two_children; ++ } ++ // increment the level counter ++ level++; ++ } ++ // trie node visit - classbench statistics ++ stats.classbench.prefixes += node->prefixes; ++ stats.classbench.prefix_lengths[level] += node->prefixes; ++ if ((node->zero != NULL) && (node->one != NULL)) { // skew is defined ++ stats.classbench.skew[level] += compute_skew(node); ++ } ++ // trie node visit - nodes statistics ++ if (node->zero == NULL) { ++ if (node->one == NULL) { // leaf node ++ (stats.nodes.leaf[level])++; ++ } else { // one child node ++ (stats.nodes.one_child[level])++; ++ } ++ } else { // node->zero != NULL ++ if (node->one != NULL) { // two child node ++ (stats.nodes.two_children[level])++; ++ } else { // one child node ++ (stats.nodes.one_child[level])++; ++ } ++ } ++ if (node->prefixes > 0) { // prefix node ++ (stats.nodes.prefix[level])++; ++ } else { // non-prefix node ++ (stats.nodes.non_prefix[level])++; ++ } ++ } // end of while (!q.empty()) ++ // finish statistics computation for the last level ++ // auxiliary variables ++ int one_child = stats.nodes.one_child[level]; ++ int two_children = stats.nodes.two_children[level]; ++ int sum = one_child + two_children; ++ // branching_one_child and branching_two_children ++ if (sum != 0) { ++ stats.classbench.branching_one_child[level] = ++ (float)one_child / (float)sum; ++ stats.classbench.branching_two_children[level] = ++ (float)two_children / (float)sum; ++ } ++ // skew ++ if (two_children != 0) { ++ stats.classbench.skew[level] /= (float)two_children; ++ } ++ // compute prefix nesting ++ stats.classbench.prefix_nesting = get_prefix_nesting(root); ++ return; ++} // end get_stats() +diff --git a/trie.h b/trie.h +new file mode 100644 +index 0000000..4cbe414 +--- /dev/null ++++ b/trie.h +@@ -0,0 +1,477 @@ ++// trie.h: header file for trie class ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef TRIE_H ++#define TRIE_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++/* ++ * Structure representing a node of a trie. ++ * ++ * Each node can be a prefix node (prefixes > 0) or a non-prefix node ++ * (prefixes = 0) and it can have at most two successors accessible using ++ * pointers zero (when the next bit of the prefix is 0) or one (when the next ++ * bit of the prefix is 1). ++ * Except these basic members, each trie node stores some other values that ++ * make the computation of trie characteristics easier. These values are ++ * further described directly in the trie node structure declaration. ++ */ ++ ++struct trie_node { ++ // trie level (i.e. distance from the root) at which the node resides ++ int level; ++ ++ // number of occurences of the prefix ++ int prefixes; ++ ++ // counter of branches with maximum prefix nesting that this node is part of ++ int prefix_nesting_branches; ++ ++ // 0-subtree-related members ++ trie_node* zero; // pointer to the subtree root ++ int zero_weight; // number of prefixes in the subtree ++ ++ // 1-subtree-related members ++ trie_node* one; // pointer to the subtree root ++ int one_weight; // number of prefixes in the subtree ++}; ++ ++/* ++ * Structure representing trie statistics proposed in the ClassBench tool. ++ * ++ * Vector members store statistics defined separately for each level of the ++ * trie. Prefix nesting is defined for the whole trie. ++ */ ++struct classbench_stats { ++ // total number of prefixes ++ int prefixes; ++ ++ // number of prefixes (not prefix nodes) with given length ++ vector prefix_lengths; ++ ++ // probability of node with only one child (from all non-leaf nodes) ++ vector branching_one_child; ++ // probability of node with two children (from all non-leaf nodes) ++ vector branching_two_children; ++ ++ // average relative weight ratio of lighter vs heavier subtree ++ // (nodes with two children only) ++ vector skew; ++ ++ // maximum number of prefix nodes on an arbitrary path in the trie ++ int prefix_nesting; ++}; ++ ++/* ++ * Structure representing statistics related to trie nodes. ++ * ++ * All the statistics are stored separately for each level of the trie. ++ */ ++struct node_stats { ++ vector leaf; // number of leaf nodes ++ vector one_child; // number of nodes with one child only ++ vector two_children; // number of nodes with both children ++ vector prefix; // number of prefix nodes (not prefixes) ++ vector non_prefix; // number of non-prefix nodes ++}; ++ ++/* ++ * Structure representing statistics related to the trie. ++ * ++ * Statistics are divided into two groups: ++ * 1) statistics proposed in ClassBench tool and ++ * 2) statistics related to trie nodes. ++ */ ++struct trie_stats { ++ classbench_stats classbench; // ClassBench statistics ++ node_stats nodes; // nodes statistics ++}; ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a binary prefix tree - trie. ++ * ++ * Class functions do not adjust zero_weight and one_weight counters in a trie ++ * node by default. These feilds are viewed as place holders and they can be ++ * set to the correct value by calling the compute_weights(). ++ */ ++class Trie { ++ private: ++ /* ++ * Pointer to the root node of the trie. ++ */ ++ trie_node* root; ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++// (MAYBE JUST ONE REASON -- BY COPYING ONLY A SUBTREE YOU LOOSE THE ++// INFORMATION ABOUT THE COMMON PREFIX, I.E. PATH IN TRIE PRECEDING THIS ++// SUBTREE) ++ /* ++ * Private static function for copying a subtree of the trie, where the ++ * subtree is specified by a pointer to its root node. ++ * Trie node members prefixes, zero_weight, and one_weight are copied ++ * without any change, while the level member is set to the given value. ++ * This approach allows e.g. to create a new valid trie by copying the ++ * given subtree. (In such a case the level parameter have to be set to ++ * 0 during the initial function call.) ++ * Trie node members zero and one are set to the values returned by the ++ * recursive call of the copy() onto the 0-subtree and 1-subtree, ++ * respectively. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of a subtree that is to be ++ * copied. ++ * @param level Value for the level member of the copied trie node. ++ * @return Pointer to the root node of the copy. ++ */ ++ static trie_node* copy(const trie_node* node, int level); ++ ++ /* ++ * Private static function for destruction of a trie's subtree. The ++ * subtree is given by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of a subtree that is to be ++ * destructed. ++ */ ++ static void destruct(trie_node* node); ++ ++ /* ++ * Private static function for computation of zero_weight and one_weight ++ * values of all the trie nodes in a given subtree. The subtree is given ++ * by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which the ++ * weights are to be computed. ++ * @return Weights of the given subtree. ++ */ ++ static int compute_weights(trie_node* node); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function for computation of node's skew as defined in ++ * the ClassBench paper. This function expects that the pointed node is ++ * a 2-children node and that its fields zero_weight and one_weight ++ * contain valid values. ++ * @param node Pointer to the node of which the skew is going to be ++ * computed. ++ * @return Skew of the given node. ++ */ ++ static float compute_skew(trie_node* node); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that determines the maximum prefix nesting in ++ * a given subtree, i.e. the maximum number of prefixes on any path from ++ * the root to the leaves in the subtree. The subtree is given by a ++ * pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which the ++ * prefix nesting is to be computed. ++ * @return Maximum prefix nesting in the given subtree. ++ */ ++ static int get_prefix_nesting(const trie_node* node); ++ ++ /* ++ * Private static function that removes the lightest subtree among trie ++ * nodes passed in a queue. The lightest subtree can be selected ++ * either among one-child nodes or two-children nodes. The selection is ++ * done in such a way that when the lightest subtree is removed, there ++ * is still at least one branch with maximum prefix nesting in the trie. ++ * After removing the lightest subtree, corresponding subtree weight is ++ * set to 0. ++ * @param q Queue with trie nodes that are to be ++ * inspected. ++ * @param one_child Select lightest subtree either among ++ * one-child nodes (TRUE) or ++ * two-children nodes (FALSE). ++ * @param prefix_nesting_branches The number of branches in the trie ++ * with maximum prefix nesting. ++ */ ++ static void remove_lightest_subtree(queue q, bool one_child, ++ int prefix_nesting_branches); ++ ++ /* ++ * Private static function for marking branches with maximum prefix ++ * nesting in a given subtree. The subtree is given by a pointer to its ++ * root node. Maximum prefix nesting is specified as a parameter of the ++ * function (therefore, it has to be computed outside the function). ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in ++ * which prefix nesting branches are to be ++ marked. ++ * @param prefix_nesting Maximum prefix nesting in the given subtree. ++ * @param seen_prefixes Number of prefixes that has been seen so far. ++ * @return Weights of the given subtree. ++ */ ++ static int mark_prefix_nesting_branches(trie_node* node, ++ int prefix_nesting, ++ int seen_prefixes); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function for computation of the maximum number of ++ * prefixes that can be removed from a given subtree. When computing the ++ * result of this function, the following contraints are taken into ++ * account: ++ * * no prefix node within the subtree must not become a non-prefix ++ * node after removing the prefixes; ++ * * removing the prefixes from subtrees of 2-children node should not ++ * alter the skew of this node. ++ * The subtree is given by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node A Pointer to the root node of the subtree in which the ++ number of removable prefixes is going to be computed. ++ * @return The number of removable prefixes in the given subtree. ++ */ ++ static int get_removable_prefixes(trie_node* node); ++ ++ /* ++ * Private static function for adjusting skew of a specified node to the ++ * given value. The node is specified by it's pointer and the target ++ * skew is given as a float number. ++ * @param node Pointer to the node whose skew is going to be ++ * adjusted. ++ * @param target_skew The value to which the node's skew should be ++ * adjusted. ++ */ ++ static void adjust_node_skew(trie_node* node, float target_skew); ++ ++ /* ++ * Private static function that removes the given number of prefixes from ++ * a subtree specified by the pointer to its root node. Prefixes are ++ * removed as equally as possible while following a rule that no prefix ++ * node can be turned to a non-prefix node. Removing of prefixes is ++ * performed over all prefix nodes from the root node up to the closest ++ * 2-children node or a leaf node... ++ * @param root Pointer to the root node of the subtree in which ++ * prefixes are going to be removed. ++ * @remove_prefixes The number of prefixes that should be removed from ++ * the specified subtree. ++ */ ++ static void make_subtree_lighter(trie_node* root, int remove_prefixes); ++ ++ /* ++ * Private static function for removing branches without a prefix node ++ * from a given subtree. The subtree is given by a pointer to its root ++ * node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which ++ * nonprefix are to be removed. ++ * @return actualized pointer to the subtree's root node ++ * (NULL when the whole subtree was removed) ++ */ ++ static trie_node* remove_nonprefix_branches(trie_node* node); ++ ++ /* ++ * Private function that removes some subtrees in order to achieve ++ * branching probabilities that are as close as possible to the given ++ * values. ++ * Modifications are done on a per level basis, starting from the root ++ * node. Changes at each level are done in two steps: ++ * 1) lightest subtrees of two-children nodes are removed to achieve ++ * given branching_two_children probability ++ * 2) lightest subtrees of one-child nodes are removed to achieve ++ * given branching_one_child probability ++ * @param branching_one_child Vector specifying probability of ++ * occurence of a trie node with one ++ * child at the given level of the trie. ++ * @param branching_two_children Vector specifying probability of ++ * occurence of a trie node with two ++ * children at the given level of the ++ * trie. ++ */ ++ void adjust_branching(vector branching_one_child, ++ vector branching_two_children); ++ ++ /* ++ * Private function that removes some prefixes in order to achieve an ++ * average skew that is as close as possible to the given values for ++ * particular levels. ++ * Prefixes are removed on a per level basis, starting from the lowest ++ * level. At each level, an average skew is increased/decreased by ++ * removing prefixes from lighter/heavier subtree of the level's nodes. ++ * This adjustment starts from nodes with the lightest subtrees ++ * (adjusting their skew requires removing of the lowest number of ++ * prefixes) and it is implemented such that it (almost) does not change ++ * a skew of nodes at lower levels. ++ * @param skew Vector specifying an average skew at all levels of ++ * the trie. ++ * @ skew_epsilon Threshold value for average skew change at not yet ++ * adjusted nodes (skew adjustment stops when average ++ * skew change is less than the given skew_epsilon). ++ */ ++ void adjust_skew(vector skew, float skew_epsilon = 0.01); ++ ++ /* ++ * Private function that removes some prefixes in order to achieve ++ * prefixes distribution that is as close as possible to the given values ++ * for particular levels. ++ * Prefixes are removed on a per level basis, starting from the root ++ * node. Removing the prefixes consists of three steps: ++ * 1) removing the prefixes from leaf nodes (the last prefix ++ * represented by a leaf node is never removed) ++ * 2) removing the prefixes from non-leaf nodes, proportionally to ++ * their weight ++ * 3) distributing prefixes that are to be removed at lower levels to ++ * subtrees of non-leaf nodes (this distribution is driven by skew) ++ * @param prefixes_proportion Vector that for all trie levels specifies ++ * proportion of prefixes at the given level ++ * to all prefixes in the trie. ++ * @param target_size Target total number of prefixes in the ++ * trie. ++ */ ++ void adjust_prefixes(vector prefixes_proportion, ++ const int target_size); ++ ++ public: ++ /* ++ * Default constructor. ++ * Pointer to the root node is initialized to NULL. ++ */ ++ Trie(); ++ ++ /* ++ * Copy constructor. ++ * Pointer to the root node is initialized by the result of the private ++ * copy(). ++ * @param orig Reference to the original trie object. ++ */ ++ Trie(const Trie& orig); ++ ++ /* ++ * Destructor. ++ * Trie specified by the root pointer is destructed by the private ++ * destruct(). ++ */ ++ ~Trie(); ++ ++ /* ++ * Copy assignment. ++ * Original trie is destructed by the private destruct() and the new trie ++ * is created by the private copy(). ++ * @param orig Reference to the original trie object. ++ * @return Reference to the new trie object. ++ */ ++ Trie& operator= (const Trie& orig); ++ ++ /* ++ * Get function for the root pointer. ++ * @return Pointer to the root node of the trie. ++ */ ++ inline const trie_node* get_root() const { ++ return root; ++ } // end get_root() ++ ++ /* ++ * Inserts the specified prefix into the trie. ++ * The trie is non-recursively traversed to the corresponding trie node, ++ * where the prefix is newly inserted or at least the counter of its ++ * occurences is incremented. ++ * All the missing nodes on a way to the prefix node are newly created ++ * and inserted into the trie as non-prefix nodes. ++ * @param pref Reference to the IP_prefix object representing the ++ * prefix that is to be inserted. ++ */ ++ void insert(const IP_prefix& pref); ++ ++ /* ++ * Erases the specified prefix from the trie. ++ * The prefix is searched by non-recursively traversing the trie. If the ++ * erase() finds the prefix, the counter of its occurences is decremented ++ * and return value is set to TRUE. ++ * If the erased prefix was the last one (i.e. prefix node has changed to ++ * non-prefix node) and there is not more specific prefix (i.e. prefix ++ * node is a leaf node of the trie), its corresponding node and all its ++ * non-prefix predecessors (up to the closest node with two children) are ++ * removed from the trie using private destruct(). ++ * If the erase() does not find the prefix, it silently ends without any ++ * further action and with return value set to FALSE. ++ * @param pref Reference to the IP_prefix object representing the ++ * prefix that is to be removed. ++ * @return TRUE if the prefix was removed, ++ * FALSE otherwise. ++ */ ++ bool erase(const IP_prefix& pref); ++ ++ /* ++ * Prunes the trie in order to achieve the given characteristics. ++ * The function first adjusts branching probability distributions at all ++ * trie levels. Next, average skew and prefix length distributions are ++ * adjusted while the number of prefixes in the trie is iteratively ++ * decreased towards the given target size. ++ * @param target_size Target number of prefixes in the trie. The ++ * final number of prefixes in the pruned trie can ++ * be slightly different. ++ * @param prefixes The vector of target prefix length distribution ++ * over the trie levels. ++ * @param one_child The vector of target one-child branching ++ * probability distribution over the trie levels. ++ * @param two_children The vector of target two-children branching ++ * probability distribution over the trie levels. ++ * @param skew The vector of target average skew distribution ++ * over the trie levels. ++ * @param iterations The number of iterations of average skew and ++ * prefix length distribution adjustment. ++ */ ++ void prune(const int target_size, ++ const vector& prefixes, ++ const vector& one_child, ++ const vector& two_children, ++ const vector& skew, ++ const int iterations = 4); ++ ++ /* ++ * Computes all defined trie statistics and stores them into a given ++ * structure. ++ * Except prefix nesting, which is computed during separate recursive ++ * traversal, all the other statistics are computed during single ++ * breadth-first search. Following statistics are actualized when ++ * visiting the nodes: ++ * * classbench.prefix_lengths ++ * * classbench.skew ++ * * nodes.leaf ++ * * nodes.one_child ++ * * nodes.two_children ++ * * nodes.prefix ++ * * nodes.non_prefix ++ * The value classbech.skew is also adjusted (divided by ++ * nodes.two_children) after visiting all the nodes at the current trie ++ * level. ++ * There are also two statistics (classbench.branching_one_child and ++ * classbench.branching_two_children) that are fully computed after ++ * visiting all the nodes at the current trie level. Their computation is ++ * based on values nodes.one_child and nodes.two_children. ++ * @param stats Reference to a data structure for computed trie ++ * statistics. ++ */ ++ void get_stats(trie_stats& stats); ++}; ++ ++#endif +diff --git a/uint128_t.cc b/uint128_t.cc +new file mode 100644 +index 0000000..1e16bbd +--- /dev/null ++++ b/uint128_t.cc +@@ -0,0 +1,372 @@ ++#include "uint128_t.h" ++ ++const uint128_t uint128_0(0); ++const uint128_t uint128_1(1); ++const uint128_t uint128_64(64); ++const uint128_t uint128_128(128); ++ ++uint128_t::uint128_t(){ ++ UPPER = 0; ++ LOWER = 0; ++} ++ ++uint128_t::uint128_t(const uint128_t & rhs){ ++ UPPER = rhs.UPPER; ++ LOWER = rhs.LOWER; ++} ++ ++uint128_t uint128_t::operator=(const uint128_t & rhs){ ++ UPPER = rhs.UPPER; ++ LOWER = rhs.LOWER; ++ return *this; ++} ++ ++uint128_t::operator bool() const{ ++ return (bool) (UPPER | LOWER); ++} ++ ++uint128_t::operator char() const{ ++ return (char) LOWER; ++} ++uint128_t::operator int() const{ ++ return (int) LOWER; ++} ++ ++uint128_t::operator uint8_t() const{ ++ return (uint8_t) LOWER; ++} ++ ++uint128_t::operator uint16_t() const{ ++ return (uint16_t) LOWER; ++} ++ ++uint128_t::operator uint32_t() const{ ++ return (uint32_t) LOWER; ++} ++ ++uint128_t::operator uint64_t() const{ ++ return (uint64_t) LOWER; ++} ++ ++uint128_t uint128_t::operator&(const uint128_t & rhs) const{ ++return uint128_t(UPPER & rhs.UPPER, LOWER & rhs.LOWER); ++} ++ ++uint128_t uint128_t::operator|(const uint128_t & rhs) const{ ++ return uint128_t(UPPER | rhs.UPPER, LOWER | rhs.LOWER); ++} ++ ++uint128_t uint128_t::operator^(const uint128_t & rhs) const{ ++ return uint128_t(UPPER ^ rhs.UPPER, LOWER ^ rhs.LOWER); ++} ++ ++uint128_t uint128_t::operator&=(const uint128_t & rhs){ ++ UPPER &= rhs.UPPER; ++ LOWER &= rhs.LOWER; ++ return *this; ++} ++ ++uint128_t uint128_t::operator|=(const uint128_t & rhs){ ++ UPPER |= rhs.UPPER; ++ LOWER |= rhs.LOWER; ++ return *this; ++} ++ ++uint128_t uint128_t::operator^=(const uint128_t & rhs){ ++ UPPER ^= rhs.UPPER; ++ LOWER ^= rhs.LOWER; ++ return *this; ++} ++ ++uint128_t uint128_t::operator~() const{ ++ return uint128_t(~UPPER, ~LOWER); ++} ++ ++uint128_t uint128_t::operator<<(const uint128_t & rhs) const{ ++ uint64_t shift = rhs.LOWER; ++ if (((bool) rhs.UPPER) || (shift >= 128)){ ++ return uint128_0; ++ } ++ else if (shift == 64){ ++ return uint128_t(LOWER, 0); ++ } ++ else if (shift == 0){ ++ return *this; ++ } ++ else if (shift < 64){ ++ return uint128_t((UPPER << shift) + (LOWER >> (64 - shift)), LOWER << shift); ++ } ++ else if ((128 > shift) && (shift > 64)){ ++ return uint128_t(LOWER << (shift - 64), 0); ++ } ++ else{ ++ return uint128_0; ++ } ++} ++ ++uint128_t uint128_t::operator>>(const uint128_t & rhs) const{ ++ uint64_t shift = rhs.LOWER; ++ if (((bool) rhs.UPPER) || (shift >= 128)){ ++ return uint128_0; ++ } ++ else if (shift == 64){ ++ return uint128_t(0, UPPER); ++ } ++ else if (shift == 0){ ++ return *this; ++ } ++ else if (shift < 64){ ++ return uint128_t(UPPER >> shift, (UPPER << (64 - shift)) + (LOWER >> shift)); ++ } ++ else if ((128 > shift) && (shift > 64)){ ++ return uint128_t(0, (UPPER >> (shift - 64))); ++ } ++ else{ ++ return uint128_0; ++ } ++} ++ ++uint128_t uint128_t::operator<<=(const uint128_t & rhs){ ++ *this = *this << rhs; ++ return *this; ++} ++ ++uint128_t uint128_t::operator>>=(const uint128_t & rhs){ ++ *this = *this >> rhs; ++ return *this; ++} ++ ++bool uint128_t::operator!() const{ ++ return !(bool) (UPPER | LOWER); ++} ++ ++bool uint128_t::operator&&(const uint128_t & rhs) const{ ++ return ((bool) *this && rhs); ++} ++ ++bool uint128_t::operator||(const uint128_t & rhs) const{ ++ return ((bool) *this || rhs); ++} ++ ++bool uint128_t::operator==(const uint128_t & rhs) const{ ++ return ((UPPER == rhs.UPPER) && (LOWER == rhs.LOWER)); ++} ++ ++bool uint128_t::operator!=(const uint128_t & rhs) const{ ++ return ((UPPER != rhs.UPPER) | (LOWER != rhs.LOWER)); ++} ++ ++bool uint128_t::operator>(const uint128_t & rhs) const{ ++ if (UPPER == rhs.UPPER){ ++ return (LOWER > rhs.LOWER); ++ } ++ return (UPPER > rhs.UPPER); ++} ++ ++bool uint128_t::operator<(const uint128_t & rhs) const{ ++ if (UPPER == rhs.UPPER){ ++ return (LOWER < rhs.LOWER); ++ } ++ return (UPPER < rhs.UPPER); ++} ++ ++bool uint128_t::operator>=(const uint128_t & rhs) const{ ++ return ((*this > rhs) | (*this == rhs)); ++} ++ ++bool uint128_t::operator<=(const uint128_t & rhs) const{ ++ return ((*this < rhs) | (*this == rhs)); ++} ++ ++uint128_t uint128_t::operator+(const uint128_t & rhs) const{ ++ return uint128_t(UPPER + rhs.UPPER + ((LOWER + rhs.LOWER) < LOWER), LOWER + rhs.LOWER); ++} ++ ++uint128_t uint128_t::operator+=(const uint128_t & rhs){ ++ UPPER = rhs.UPPER + UPPER + ((LOWER + rhs.LOWER) < LOWER); ++ LOWER += rhs.LOWER; ++ return *this; ++} ++ ++uint128_t uint128_t::operator-(const uint128_t & rhs) const{ ++ return uint128_t(UPPER - rhs.UPPER - ((LOWER - rhs.LOWER) > LOWER), LOWER - rhs.LOWER); ++} ++ ++uint128_t uint128_t::operator-=(const uint128_t & rhs){ ++ *this = *this - rhs; ++ return *this; ++} ++ ++uint128_t uint128_t::operator*(const uint128_t & rhs) const{ ++ // split values into 4 32-bit parts ++ uint64_t top[4] ={UPPER >> 32, UPPER & 0xffffffff, LOWER >> 32, LOWER & 0xffffffff}; ++ uint64_t bottom[4] ={rhs.UPPER >> 32, rhs.UPPER & 0xffffffff, rhs.LOWER >> 32, rhs.LOWER & 0xffffffff}; ++ uint64_t products[4][4]; ++ ++ for(int y = 3; y > -1; y--){ ++ for(int x = 3; x > -1; x--){ ++ products[3 - x][y] = top[x] * bottom[y]; ++ } ++ } ++ ++ // initial row ++ uint64_t fourth32 = products[0][3] & 0xffffffff; ++ uint64_t third32 = (products[0][2] & 0xffffffff) + (products[0][3] >> 32); ++ uint64_t second32 = (products[0][1] & 0xffffffff) + (products[0][2] >> 32); ++ uint64_t first32 = (products[0][0] & 0xffffffff) + (products[0][1] >> 32); ++ ++ // second row ++ third32 += products[1][3] & 0xffffffff; ++ second32 += (products[1][2] & 0xffffffff) + (products[1][3] >> 32); ++ first32 += (products[1][1] & 0xffffffff) + (products[1][2] >> 32); ++ ++ // third row ++ second32 += products[2][3] & 0xffffffff; ++ first32 += (products[2][2] & 0xffffffff) + (products[2][3] >> 32); ++ ++ // fourth row ++ first32 += products[3][3] & 0xffffffff; ++ ++ // combines the values, taking care of carry over ++ return uint128_t(first32 << 32, 0) + uint128_t(third32 >> 32, third32 << 32) + uint128_t(second32, 0) + uint128_t(fourth32); ++} ++ ++uint128_t uint128_t::operator*=(const uint128_t & rhs){ ++ *this = *this * rhs; ++ return *this; ++} ++ ++std::pair uint128_t::divmod(const uint128_t & lhs, const uint128_t & rhs) const{ ++ // Save some calculations ///////////////////// ++ if (rhs == uint128_0){ ++ throw std::runtime_error("Error: division or modulus by 0"); ++ } ++ else if (rhs == uint128_1){ ++ return std::pair (lhs, uint128_0); ++ } ++ else if (lhs == rhs){ ++ return std::pair (uint128_1, uint128_0); ++ } ++ else if ((lhs == uint128_0) || (lhs < rhs)){ ++ return std::pair (uint128_0, lhs); ++ } ++ ++ std::pair qr(uint128_0, lhs); ++ uint128_t copyd = rhs << (lhs.bits() - rhs.bits()); ++ uint128_t adder = uint128_1 << (lhs.bits() - rhs.bits()); ++ if (copyd > qr.second){ ++ copyd >>= uint128_1; ++ adder >>= uint128_1; ++ } ++ while (qr.second >= rhs){ ++ if (qr.second >= copyd){ ++ qr.second -= copyd; ++ qr.first |= adder; ++ } ++ copyd >>= uint128_1; ++ adder >>= uint128_1; ++ } ++ return qr; ++} ++ ++uint128_t uint128_t::operator/(const uint128_t & rhs) const{ ++ return divmod(*this, rhs).first; ++} ++ ++uint128_t uint128_t::operator/=(const uint128_t & rhs){ ++ *this = *this / rhs; ++ return *this; ++} ++ ++uint128_t uint128_t::operator%(const uint128_t & rhs) const{ ++ return *this - (rhs * (*this / rhs)); ++} ++ ++uint128_t uint128_t::operator%=(const uint128_t & rhs){ ++ *this = *this % rhs; ++ return *this; ++} ++ ++uint128_t uint128_t::operator++(){ ++ *this += uint128_1; ++ return *this; ++} ++ ++uint128_t uint128_t::operator++(int){ ++ uint128_t temp(*this); ++ ++*this; ++ return temp; ++} ++ ++uint128_t uint128_t::operator--(){ ++ *this -= uint128_1; ++ return *this; ++} ++ ++uint128_t uint128_t::operator--(int){ ++ uint128_t temp(*this); ++ --*this; ++ return temp; ++} ++ ++uint64_t uint128_t::upper() const{ ++ return UPPER; ++} ++ ++uint64_t uint128_t::lower() const{ ++ return LOWER; ++} ++ ++uint8_t uint128_t::bits() const{ ++ uint8_t out = 0; ++ if (UPPER){ ++ out = 64; ++ uint64_t up = UPPER; ++ while (up){ ++ up >>= 1; ++ out++; ++ } ++ } ++ else{ ++ uint64_t low = LOWER; ++ while (low){ ++ low >>= 1; ++ out++; ++ } ++ } ++ return out; ++} ++ ++std::string uint128_t::str(uint8_t base, const unsigned int & len) const{ ++ if ((base < 2) || (base > 16)){ ++ throw std::invalid_argument("Base must be in th range 2-16"); ++ } ++ std::string out = ""; ++ if (!(*this)){ ++ out = "0"; ++ } ++ else{ ++ std::pair qr(*this, uint128_0); ++ do{ ++ qr = divmod(qr.first, base); ++ out = "0123456789abcdef"[(uint8_t) qr.second] + out; ++ } while (qr.first); ++ } ++ if (out.size() < len){ ++ out = std::string(len - out.size(), '0') + out; ++ } ++ return out; ++} ++ ++std::ostream & operator<<(std::ostream & stream, const uint128_t & rhs){ ++ if (stream.flags() & stream.oct){ ++ stream << rhs.str(8); ++ } ++ else if (stream.flags() & stream.dec){ ++ stream << rhs.str(10); ++ } ++ else if (stream.flags() & stream.hex){ ++ stream << rhs.str(16); ++ } ++ return stream; ++} +diff --git a/uint128_t.h b/uint128_t.h +new file mode 100644 +index 0000000..7da340a +--- /dev/null ++++ b/uint128_t.h +@@ -0,0 +1,384 @@ ++/* ++uint128_t.h ++An unsigned 128 bit integer type for C++ ++Copyright (c) 2014 Jason Lee @ calccrypto at gmail.com ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++THE SOFTWARE. ++ ++With much help from Auston Sterling ++ ++Thanks to Stefan Deigmüller for finding ++a bug in operator*. ++ ++Thanks to François Dessenne for convincing me ++to do a general rewrite of this class. ++*/ ++ ++#ifndef __UINT128_T__ ++#define __UINT128_T__ ++ ++#include ++#include ++#include ++#include ++ ++class uint128_t{ ++ private: ++ uint64_t UPPER, LOWER; ++ ++ public: ++ // Constructors ++ uint128_t(); ++ uint128_t(const uint128_t & rhs); ++ ++ template uint128_t(const T & rhs){ ++ UPPER = 0; ++ LOWER = rhs; ++ } ++ ++ template uint128_t(const S & upper_rhs, const T & lower_rhs){ ++ UPPER = upper_rhs; ++ LOWER = lower_rhs; ++ } ++ ++ // RHS input args only ++ ++ // Assignment Operator ++ uint128_t operator=(const uint128_t & rhs); ++ ++ template uint128_t operator=(const T & rhs){ ++ UPPER = 0; ++ LOWER = rhs; ++ return *this; ++ } ++ ++ // Typecast Operators ++ operator bool() const; ++ operator char() const; ++ operator int() const; ++ operator uint8_t() const; ++ operator uint16_t() const; ++ operator uint32_t() const; ++ operator uint64_t() const; ++ ++ // Bitwise Operators ++ uint128_t operator&(const uint128_t & rhs) const; ++ uint128_t operator|(const uint128_t & rhs) const; ++ uint128_t operator^(const uint128_t & rhs) const; ++ uint128_t operator&=(const uint128_t & rhs); ++ uint128_t operator|=(const uint128_t & rhs); ++ uint128_t operator^=(const uint128_t & rhs); ++ uint128_t operator~() const; ++ ++ template uint128_t operator&(const T & rhs) const{ ++ return uint128_t(0, LOWER & (uint64_t) rhs); ++ } ++ ++ template uint128_t operator|(const T & rhs) const{ ++ return uint128_t(UPPER, LOWER | (uint64_t) rhs); ++ } ++ ++ template uint128_t operator^(const T & rhs) const{ ++ return uint128_t(UPPER, LOWER ^ (uint64_t) rhs); ++ } ++ ++ template uint128_t operator&=(const T & rhs){ ++ UPPER = 0; ++ LOWER &= rhs; ++ return *this; ++ } ++ ++ template uint128_t operator|=(const T & rhs){ ++ LOWER |= (uint64_t) rhs; ++ return *this; ++ } ++ ++ template uint128_t operator^=(const T & rhs){ ++ LOWER ^= (uint64_t) rhs; ++ return *this; ++ } ++ ++ // Bit Shift Operators ++ uint128_t operator<<(const uint128_t & rhs) const; ++ uint128_t operator>>(const uint128_t & rhs) const; ++ uint128_t operator<<=(const uint128_t & rhs); ++ uint128_t operator>>=(const uint128_t & rhs); ++ ++ template uint128_t operator<<(const T & rhs) const{ ++ return *this << uint128_t(rhs); ++ } ++ ++ template uint128_t operator>>(const T & rhs) const{ ++ return *this >> uint128_t(rhs); ++ } ++ ++ template uint128_t operator<<=(const T & rhs){ ++ *this = *this << uint128_t(rhs); ++ return *this; ++ } ++ ++ template uint128_t operator>>=(const T & rhs){ ++ *this = *this >> uint128_t(rhs); ++ return *this; ++ } ++ ++ // Logical Operators ++ bool operator!() const; ++ bool operator&&(const uint128_t & rhs) const; ++ bool operator||(const uint128_t & rhs) const; ++ ++ template bool operator&&(const T & rhs){ ++ return ((bool) *this && rhs); ++ } ++ ++ template bool operator||(const T & rhs){ ++ return ((bool) *this || rhs); ++ } ++ ++ // Comparison Operators ++ bool operator==(const uint128_t & rhs) const; ++ bool operator!=(const uint128_t & rhs) const; ++ bool operator>(const uint128_t & rhs) const; ++ bool operator<(const uint128_t & rhs) const; ++ bool operator>=(const uint128_t & rhs) const; ++ bool operator<=(const uint128_t & rhs) const; ++ ++ template bool operator==(const T & rhs) const{ ++ return (!UPPER && (LOWER == (uint64_t) rhs)); ++ } ++ ++ template bool operator!=(const T & rhs) const{ ++ return (UPPER | (LOWER != (uint64_t) rhs)); ++ } ++ ++ template bool operator>(const T & rhs) const{ ++ return (UPPER || (LOWER > (uint64_t) rhs)); ++ } ++ ++ template bool operator<(const T & rhs) const{ ++ return (!UPPER)?(LOWER < (uint64_t) rhs):false; ++ } ++ ++ template bool operator>=(const T & rhs) const{ ++ return ((*this > rhs) | (*this == rhs)); ++ } ++ ++ template bool operator<=(const T & rhs) const{ ++ return ((*this < rhs) | (*this == rhs)); ++ } ++ ++ // Arithmetic Operators ++ uint128_t operator+(const uint128_t & rhs) const; ++ uint128_t operator+=(const uint128_t & rhs); ++ uint128_t operator-(const uint128_t & rhs) const; ++ uint128_t operator-=(const uint128_t & rhs); ++ uint128_t operator*(const uint128_t & rhs) const; ++ uint128_t operator*=(const uint128_t & rhs); ++ ++ private: ++ std::pair divmod(const uint128_t & lhs, const uint128_t & rhs) const; ++ ++ public: ++ uint128_t operator/(const uint128_t & rhs) const; ++ uint128_t operator/=(const uint128_t & rhs); ++ uint128_t operator%(const uint128_t & rhs) const; ++ uint128_t operator%=(const uint128_t & rhs); ++ ++ template uint128_t operator+(const T & rhs) const{ ++ return uint128_t(UPPER + ((LOWER + (uint64_t) rhs) < LOWER), LOWER + (uint64_t) rhs); ++ } ++ ++ template uint128_t operator+=(const T & rhs){ ++ UPPER = UPPER + ((LOWER + rhs) < LOWER); ++ LOWER = LOWER + rhs; ++ return *this; ++ } ++ ++ template uint128_t operator-(const T & rhs) const{ ++ return uint128_t((uint64_t) (UPPER - ((LOWER - rhs) > LOWER)), (uint64_t) (LOWER - rhs)); ++ } ++ ++ template uint128_t operator-=(const T & rhs){ ++ *this = *this - rhs; ++ return *this; ++ } ++ ++ template uint128_t operator*(const T & rhs) const{ ++ return (*this) * (uint128_t(rhs)); ++ } ++ ++ template uint128_t operator*=(const T & rhs){ ++ *this = *this * uint128_t(rhs); ++ return *this; ++ } ++ ++ template uint128_t operator/(const T & rhs) const{ ++ return *this / uint128_t(rhs); ++ } ++ ++ template uint128_t operator/=(const T & rhs){ ++ *this = *this / uint128_t(rhs); ++ return *this; ++ } ++ ++ template uint128_t operator%(const T & rhs) const{ ++ return *this - (rhs * (*this / rhs)); ++ } ++ ++ template uint128_t operator%=(const T & rhs){ ++ *this = *this % uint128_t(rhs); ++ return *this; ++ } ++ ++ // Increment Operator ++ uint128_t operator++(); ++ uint128_t operator++(int); ++ ++ // Decrement Operator ++ uint128_t operator--(); ++ uint128_t operator--(int); ++ ++ // Get private values ++ uint64_t upper() const; ++ uint64_t lower() const; ++ ++ // Get bitsize of value ++ uint8_t bits() const; ++ ++ // Get string representation of value ++ std::string str(uint8_t base = 10, const unsigned int & len = 0) const; ++}; ++ ++// Useful values ++extern const uint128_t uint128_0; ++extern const uint128_t uint128_1; ++extern const uint128_t uint128_64; ++extern const uint128_t uint128_128; ++ ++// lhs type T as first arguemnt ++// If the output is not a bool, casts to type T ++ ++// Bitwise Operators ++template T operator&(const T & lhs, const uint128_t & rhs){ ++ return (T) (lhs & (T) rhs.lower()); ++} ++ ++template T operator|(const T & lhs, const uint128_t & rhs){ ++ return (T) (lhs | (T) rhs.lower()); ++} ++ ++template T operator^(const T & lhs, const uint128_t & rhs){ ++ return (T) (lhs ^ (T) rhs.lower()); ++} ++ ++template T operator&=(T & lhs, const uint128_t & rhs){ ++ lhs &= (T) rhs.lower(); return lhs; ++} ++ ++template T operator|=(T & lhs, const uint128_t & rhs){ ++ lhs |= (T) rhs.lower(); return lhs; ++} ++ ++template T operator^=(T & lhs, const uint128_t & rhs){ ++ lhs ^= (T) rhs.lower(); return lhs; ++} ++ ++// Comparison Operators ++template bool operator==(const T & lhs, const uint128_t & rhs){ ++ return (!rhs.upper() && ((uint64_t) lhs == rhs.lower())); ++} ++ ++template bool operator!=(const T & lhs, const uint128_t & rhs){ ++ return (rhs.upper() | ((uint64_t) lhs != rhs.lower())); ++} ++ ++template bool operator>(const T & lhs, const uint128_t & rhs){ ++ return (!rhs.upper()) && ((uint64_t) lhs > rhs.lower()); ++} ++ ++template bool operator<(const T & lhs, const uint128_t & rhs){ ++ if (rhs.upper()){ ++ return true; ++ } ++ return ((uint64_t) lhs < rhs.lower()); ++} ++ ++template bool operator>=(const T & lhs, const uint128_t & rhs){ ++ if (rhs.upper()){ ++ return false; ++ } ++ return ((uint64_t) lhs >= rhs.lower()); ++} ++ ++template bool operator<=(const T & lhs, const uint128_t & rhs){ ++ if (rhs.upper()){ ++ return true; ++ } ++ return ((uint64_t) lhs <= rhs.lower()); ++} ++ ++// Arithmetic Operators ++template T operator+(const T & lhs, const uint128_t & rhs){ ++ return (T) (rhs + lhs); ++} ++ ++template T & operator+=(T & lhs, const uint128_t & rhs){ ++ lhs = (T) (rhs + lhs); ++ return lhs; ++} ++ ++template T operator-(const T & lhs, const uint128_t & rhs){ ++ return (T) (uint128_t(lhs) - rhs); ++} ++ ++template T & operator-=(T & lhs, const uint128_t & rhs){ ++ lhs = (T) (uint128_t(lhs) - rhs); ++ return lhs; ++} ++ ++template T operator*(const T & lhs, const uint128_t & rhs){ ++ return lhs * (T) rhs.lower(); ++} ++ ++template T & operator*=(T & lhs, const uint128_t & rhs){ ++ lhs *= (T) rhs.lower(); ++ return lhs; ++} ++ ++template T operator/(const T & lhs, const uint128_t & rhs){ ++ return (T) (uint128_t(lhs) / rhs); ++} ++ ++template T & operator/=(T & lhs, const uint128_t & rhs){ ++ lhs = (T) (uint128_t(lhs) / rhs); ++ return lhs; ++} ++ ++template T operator%(const T & lhs, const uint128_t & rhs){ ++ return (T) (uint128_t(lhs) % rhs); ++} ++ ++template T & operator%=(T & lhs, const uint128_t & rhs){ ++ lhs = (T) (uint128_t(lhs) % rhs); ++ return lhs; ++} ++ ++// IO Operator ++std::ostream & operator<<(std::ostream & stream, const uint128_t & rhs); ++#endif diff --git a/vendor/Makefile b/vendor/Makefile index 8d8688e..1493301 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -20,7 +20,9 @@ download: patch: download # Apply patches from ../patches - git apply --directory=vendor/db_generator ../patches/ipv6.patch + git apply --directory=vendor/db_generator ../patches/improvements_ipv6.patch + #git apply --directory=vendor/db_generator ../patches/ipv6.patch + #git apply --directory=vendor/db_generator ../patches/improvements.patch # Patching PortList (extension of preallocated array is necessary) # Raise limit of L5 rules from 200 to 20000. From d534c4d39f47f3166d2c34234c6734bf984b1e9d Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Mon, 10 Jul 2017 10:08:08 +0200 Subject: [PATCH 17/51] README [FEATURE]: updates according to the current version of the tool --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c2dfc14..272e2fe 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ make # Downloads, patches and compiles original ClassBench in ./vendor/db_gene ``` ### Patching ClassBench -Original ClassBench is improved using patches in `./patches` directory and the size of its statically initialized arrays is increased, where necessary. +Original ClassBench can be improved using one of the patches in `./patches` directory (`./patches/improvements_ipv6.patch` by default) and the size of its statically initialized arrays is increased, where necessary. These changes are automatically applied on downloaded original ClassBench during ClassBench-ng installation (see `./vendor/Makefile`). ## Usage @@ -67,3 +67,6 @@ The output consists of `attribute=value` pairs joined by `, `. ./classbench -h | --help ``` Prints deatiled usage information. + +## Known Issues +- the number of generated rules is usually lower than in original ClassBench (i.e., ClassBench-ng generates higher number of redundant rules that are removed in the last phase) From cb27978bd2bfe8a032835c866e8000c805baf11a Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Mon, 10 Jul 2017 10:29:18 +0200 Subject: [PATCH 18/51] vendor/Makefile [MAINTENANCE]: corrected typo --- vendor/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/Makefile b/vendor/Makefile index 1493301..8b7ac5b 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -15,7 +15,7 @@ download: # Make backup of parameter_files, if exists -[ -d parameter_files ] && mv parameter_files parameter_files-$(BACKUP_TIME) - # Download and unpack ClassBBnch parameter files + # Download and unpack ClassBench parameter files wget -O- -q http://www.arl.wustl.edu/classbench/parameter_files.tar.gz | tar -xvz patch: download From 43ef29762f23f483d5ae5c34e8b3f8d95d78d8cd Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Mon, 10 Jul 2017 20:57:30 +0200 Subject: [PATCH 19/51] Update README.md Known issues on Ubuntu 17.04. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 272e2fe..d06c9a3 100644 --- a/README.md +++ b/README.md @@ -70,3 +70,4 @@ Prints deatiled usage information. ## Known Issues - the number of generated rules is usually lower than in original ClassBench (i.e., ClassBench-ng generates higher number of redundant rules that are removed in the last phase) +- running ClassBench-ng on Ubuntu 17.04 fails on "stack smashing error" (the tool was developed on Ubuntu 16.04 LTS and it works also on Ubuntu 15.04) From 74da4ff50eeb4db850a6310b70619e8caa136001 Mon Sep 17 00:00:00 2001 From: GianniAntichi Date: Wed, 19 Jul 2017 11:40:03 +0100 Subject: [PATCH 20/51] added make clean --- Makefile | 3 +++ vendor/Makefile | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Makefile b/Makefile index e9f0190..02f37af 100644 --- a/Makefile +++ b/Makefile @@ -3,3 +3,6 @@ # (downloads, patches and compiles ClassBench) all: make -C vendor all + +clean: + $(MAKE) -C vendor $@ diff --git a/vendor/Makefile b/vendor/Makefile index 8b7ac5b..4377388 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -31,3 +31,6 @@ patch: download compile: patch # Recurse to ClassBench compilation make -C db_generator -B db_generator + +clean: + rm -rf db_generator* parameter_files* From a8c7888b14d786377415308dac7e75aaa833e17d Mon Sep 17 00:00:00 2001 From: GianniAntichi Date: Wed, 19 Jul 2017 11:50:41 +0100 Subject: [PATCH 21/51] updated the README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index d06c9a3..cd0c703 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,12 @@ Original ClassBench can be improved using one of the patches in `./patches` dire These changes are automatically applied on downloaded original ClassBench during ClassBench-ng installation (see `./vendor/Makefile`). ## Usage +Classbench-ng can be used in two different ways: +- To analyse an existing rule set and extract the associated classbench-ng SEED. +- To generate a synthetic rule set from an input SEED. + +# Classbench-ng analyser +The current version of the analyser support only OpenFlow rules. ``` ./classbench analyse FILE ``` @@ -36,6 +42,10 @@ Fields extracted from FILE are: The output is an original ClassBench seed with an OpenFlow YAML structure as the last section. +# Classbench-ng rule generator +The current version can successfully generate IPv4, IPv6 and OpenFlow 1.0 flow rules. +IPv4 SEEDs can be found in `./vendor/parameter_files` +OpenFlow SEEDs can be found in `./seeds` ``` ./classbench generate v4 SEED [--count=] [--db-generator=] ``` From 87c9f1ce77939016cd896526231d0d899d1e49de Mon Sep 17 00:00:00 2001 From: Gianni Antichi Date: Wed, 19 Jul 2017 11:51:42 +0100 Subject: [PATCH 22/51] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cd0c703..b2c1e2b 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Classbench-ng can be used in two different ways: - To analyse an existing rule set and extract the associated classbench-ng SEED. - To generate a synthetic rule set from an input SEED. -# Classbench-ng analyser +#### Classbench-ng analyser The current version of the analyser support only OpenFlow rules. ``` ./classbench analyse FILE @@ -42,7 +42,7 @@ Fields extracted from FILE are: The output is an original ClassBench seed with an OpenFlow YAML structure as the last section. -# Classbench-ng rule generator +#### Classbench-ng rule generator The current version can successfully generate IPv4, IPv6 and OpenFlow 1.0 flow rules. IPv4 SEEDs can be found in `./vendor/parameter_files` OpenFlow SEEDs can be found in `./seeds` From 5abdee683b83c833c9d525918faf85e454dbcda3 Mon Sep 17 00:00:00 2001 From: Gianni Antichi Date: Wed, 19 Jul 2017 11:53:08 +0100 Subject: [PATCH 23/51] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b2c1e2b..2849945 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,8 @@ The output is an original ClassBench seed with an OpenFlow YAML structure as the #### Classbench-ng rule generator The current version can successfully generate IPv4, IPv6 and OpenFlow 1.0 flow rules. -IPv4 SEEDs can be found in `./vendor/parameter_files` -OpenFlow SEEDs can be found in `./seeds` +- IPv4 SEEDs can be found in `./vendor/parameter_files` +- OpenFlow SEEDs can be found in `./seeds` ``` ./classbench generate v4 SEED [--count=] [--db-generator=] ``` From 5161bb0663c620942635d6edb5afd27cae3308e9 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Wed, 9 Aug 2017 13:11:12 +0200 Subject: [PATCH 24/51] Update README.md --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2849945..1a91928 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,13 @@ Original ClassBench can be improved using one of the patches in `./patches` dire These changes are automatically applied on downloaded original ClassBench during ClassBench-ng installation (see `./vendor/Makefile`). ## Usage -Classbench-ng can be used in two different ways: -- To analyse an existing rule set and extract the associated classbench-ng SEED. +ClassBench-ng can be used in two different ways: +- To analyse an existing rule set and extract the associated ClassBench-ng SEED. - To generate a synthetic rule set from an input SEED. -#### Classbench-ng analyser -The current version of the analyser support only OpenFlow rules. +### ClassBench-ng Analyser +The current version of the analyser supports only OpenFlow rules. + ``` ./classbench analyse FILE ``` @@ -42,10 +43,11 @@ Fields extracted from FILE are: The output is an original ClassBench seed with an OpenFlow YAML structure as the last section. -#### Classbench-ng rule generator +### ClassBench-ng Rule Generator The current version can successfully generate IPv4, IPv6 and OpenFlow 1.0 flow rules. - IPv4 SEEDs can be found in `./vendor/parameter_files` - OpenFlow SEEDs can be found in `./seeds` + ``` ./classbench generate v4 SEED [--count=] [--db-generator=] ``` From 3f6efd3e9019766b52d93d61f6ece82fc38ab06f Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Wed, 9 Aug 2017 13:12:46 +0200 Subject: [PATCH 25/51] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a91928..1b3c8ab 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ The output consists of `attribute=value` pairs joined by `, `. ``` ./classbench -h | --help ``` -Prints deatiled usage information. +Prints detailed usage information. ## Known Issues - the number of generated rules is usually lower than in original ClassBench (i.e., ClassBench-ng generates higher number of redundant rules that are removed in the last phase) From dfa2894bc8cafcc781cad6090223de04e65e5e0a Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Wed, 9 Aug 2017 14:04:33 +0200 Subject: [PATCH 26/51] Update README.md --- README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1b3c8ab..1c854f6 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,23 @@ make # Downloads, patches and compiles original ClassBench in ./vendor/db_gene ``` ### Patching ClassBench -Original ClassBench can be improved using one of the patches in `./patches` directory (`./patches/improvements_ipv6.patch` by default) and the size of its statically initialized arrays is increased, where necessary. -These changes are automatically applied on downloaded original ClassBench during ClassBench-ng installation (see `./vendor/Makefile`). +Original ClassBench is patched using `./patches/improvements_ipv6.patch` and the size of its statically initialized arrays is increased, where necessary. +These changes are automatically applied on downloaded original ClassBench during ClassBench-ng installation. + +By modifying `./vendor/Makefile` the user can select a different patch from `./patches` directory to be applied during installation. +Basic characteristics of patches available in `./patches` directory and suggestions when to use them are following: + +`improvements.patch` +- improves precision of IPv4 prefixes generation +- use when IPv6 prefixes generation is not required + +`ipv6.patch` +- adds support for IPv6 prefixes generation +- use when IPv6 prefixes generation is required and precision of IPv4/IPv6 prefixes generation is not crucial + +`improvements_ipv6.patch` +- adds support for IPv6 prefixes generation and improves precision of both IPv4 and IPv6 prefixes generation +- use when IPv6 prefixes generation is required and precision of IPv4/IPv6 prefixes generation is crucial ## Usage ClassBench-ng can be used in two different ways: From acf51076600aaa0fe29a842c393c48cc57a078d0 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Wed, 9 Aug 2017 14:20:32 +0200 Subject: [PATCH 27/51] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1c854f6..2ad342a 100644 --- a/README.md +++ b/README.md @@ -98,3 +98,8 @@ Prints detailed usage information. ## Known Issues - the number of generated rules is usually lower than in original ClassBench (i.e., ClassBench-ng generates higher number of redundant rules that are removed in the last phase) - running ClassBench-ng on Ubuntu 17.04 fails on "stack smashing error" (the tool was developed on Ubuntu 16.04 LTS and it works also on Ubuntu 15.04) + +## How to Contribute +Contributions are welcome via: +- pull requests (preferred) +- e-mail to imatousek at fit.vutbr.cz From 29024ad25b5fe7aa911dccc9d75335dc00bb57ab Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Tue, 29 Aug 2017 18:30:09 +0200 Subject: [PATCH 28/51] Original ClassBench [BUGFIX]: fixed size of char arrays to prevent "stack smashing error" on (probably not only) Ubuntu 17.04 Patch provided by Salvatore Pontarelli . --- vendor/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vendor/Makefile b/vendor/Makefile index 4377388..f7594ad 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -27,6 +27,8 @@ patch: download # Patching PortList (extension of preallocated array is necessary) # Raise limit of L5 rules from 200 to 20000. sed -i 's/200/20000/' db_generator/PortList.h + # solve bug for stack corruption in Ubuntu 17.04 + sed -i 's/comm\[[0-9]\]/comm\[7\]/g' db_generator/*.cc compile: patch # Recurse to ClassBench compilation From 6fa8ffdd97078fdbc7b9e11673228610994cf1f0 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Tue, 29 Aug 2017 18:49:41 +0200 Subject: [PATCH 29/51] Update README.md "Stack smashing error" on Ubuntu 17.04 removed from the list of known issues. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 2ad342a..7f02708 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,6 @@ Prints detailed usage information. ## Known Issues - the number of generated rules is usually lower than in original ClassBench (i.e., ClassBench-ng generates higher number of redundant rules that are removed in the last phase) -- running ClassBench-ng on Ubuntu 17.04 fails on "stack smashing error" (the tool was developed on Ubuntu 16.04 LTS and it works also on Ubuntu 15.04) ## How to Contribute Contributions are welcome via: From 37c00e20046b0d7ca4e0299547c3fd8ec72b4413 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 12 Oct 2017 11:08:59 +0200 Subject: [PATCH 30/51] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7f02708..fc91119 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ Prints detailed usage information. ## Known Issues - the number of generated rules is usually lower than in original ClassBench (i.e., ClassBench-ng generates higher number of redundant rules that are removed in the last phase) +- ClassBench-ng Analyser does not correctly analyses source/destination port prefixes specified using a bit map in the ovs-ofctl format ## How to Contribute Contributions are welcome via: From f3a3603d81e5bcd30713aebbaf1b42cc7573a5cf Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Fri, 24 Aug 2018 15:32:18 +0200 Subject: [PATCH 31/51] Update README.md Updated the Known Issues list. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fc91119..528cd8c 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ Prints detailed usage information. ## Known Issues - the number of generated rules is usually lower than in original ClassBench (i.e., ClassBench-ng generates higher number of redundant rules that are removed in the last phase) - ClassBench-ng Analyser does not correctly analyses source/destination port prefixes specified using a bit map in the ovs-ofctl format +- ClassBench-ng Analyser is not able to analyse rule sets with source/destination IPv6 prefixes ## How to Contribute Contributions are welcome via: From 0d9a0019623c5a1fff2739245c37e5c2f77aca07 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Wed, 12 Sep 2018 11:49:39 +0200 Subject: [PATCH 32/51] vendor/Makefile [FEATURE]: another patch of original ClassBench's source code There was no return type defined for ClassBench's main function. --- vendor/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vendor/Makefile b/vendor/Makefile index f7594ad..3517387 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -29,6 +29,8 @@ patch: download sed -i 's/200/20000/' db_generator/PortList.h # solve bug for stack corruption in Ubuntu 17.04 sed -i 's/comm\[[0-9]\]/comm\[7\]/g' db_generator/*.cc + # Define return type for original ClassBench's main function + sed -i 's/main/int main/' db_generator/db_generator.cc compile: patch # Recurse to ClassBench compilation From 674dbc21e45a31bee47ac2f6b028e4b1e16c5cc5 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Fri, 26 Oct 2018 14:35:38 +0200 Subject: [PATCH 33/51] vendor/Makefile [FEATURE]: another patch of original ClassBench's source code Sometimes Null (i.e., an integer constant equal to 0) was used instead of NULL (i.e., a null pointer), which caused an error in newer C++ compilers (because of unsupported comparison of a pointer with an integer). --- vendor/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vendor/Makefile b/vendor/Makefile index 3517387..1f757d4 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -31,6 +31,8 @@ patch: download sed -i 's/comm\[[0-9]\]/comm\[7\]/g' db_generator/*.cc # Define return type for original ClassBench's main function sed -i 's/main/int main/' db_generator/db_generator.cc + # Replace Null (i.e., integer constant equal to 0) with NULL (i.e., null pointer) + sed -i 's/Null/NULL/' db_generator/FlagList.cc db_generator/custom_db.cc compile: patch # Recurse to ClassBench compilation From bbb1b57d142f597d140f309585f4d361a13a6dc5 Mon Sep 17 00:00:00 2001 From: kyontan Date: Fri, 9 Nov 2018 15:22:52 +0900 Subject: [PATCH 34/51] Add ipaddress gem to Gemfile --- Gemfile | 1 + Gemfile.lock | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 22b3d23..d360bdd 100644 --- a/Gemfile +++ b/Gemfile @@ -9,3 +9,4 @@ end gem "docopt" gem "ruby-ip" gem "open4" +gem "ipaddress" diff --git a/Gemfile.lock b/Gemfile.lock index 50da9c7..5df3e23 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,6 +2,7 @@ GEM remote: http://rubygems.org/ specs: docopt (0.5.0) + ipaddress (0.8.3) open4 (1.3.4) ruby-ip (0.9.3) @@ -11,8 +12,9 @@ PLATFORMS DEPENDENCIES bundler docopt + ipaddress open4 ruby-ip BUNDLED WITH - 1.10.6 + 1.15.4 From de0cd956c5d8ea82d9916c2105719e95c399deea Mon Sep 17 00:00:00 2001 From: Jozef Sabo Date: Sat, 29 Jun 2019 21:14:11 +0200 Subject: [PATCH 35/51] Added 5-tuples analyser. --- README.md | 27 +- classbench | 25 +- lib/classbench.rb | 34 +- lib/tuples_analyzer/README | 107 +++++ lib/tuples_analyzer/__init__.py | 1 + lib/tuples_analyzer/__main__.py | 26 ++ .../calculation_parameters/__init__.py | 1 + .../calculation_parameters/distribution.py | 32 ++ .../calculation_parameters/enums/__init__.py | 1 + .../enums/port_distribution_type.py | 19 + .../calculation_parameters/enums/trie_type.py | 15 + .../interfaces/IParameter.py | 39 ++ .../interfaces/__init__.py | 1 + .../calculation_parameters/parameter_file.py | 112 +++++ .../port_distribution.py | 79 ++++ .../ppc_prefixlen_distribution.py | 92 ++++ .../prefix_correlation_distribution.py | 100 +++++ .../protocol_ppc_distribution.py | 79 ++++ .../trie_distributions.py | 156 +++++++ .../calculation_parameters/trie_node.py | 183 ++++++++ lib/tuples_analyzer/examples/formats/format_1 | 1 + lib/tuples_analyzer/examples/formats/format_2 | 1 + lib/tuples_analyzer/examples/formats/ipfw | 1 + lib/tuples_analyzer/examples/formats/iptables | 1 + lib/tuples_analyzer/examples/formats/openflow | 2 + lib/tuples_analyzer/examples/sets/ipfw | 4 + lib/tuples_analyzer/examples/sets/iptables | 5 + lib/tuples_analyzer/examples/sets/openflow | 58 +++ lib/tuples_analyzer/examples/sets/set_1 | 58 +++ lib/tuples_analyzer/examples/sets/set_2 | 58 +++ .../printing_output/__init__.py | 1 + .../printing_output/enums/__init__.py | 1 + .../printing_output/enums/output_direction.py | 15 + .../printing_output/output_print.py | 69 +++ .../processing_arguments/__init__.py | 1 + .../processed_arguments.py | 97 ++++ .../processing_errors/__init__.py | 1 + .../processing_errors/enums/Error.py | 21 + .../processing_errors/enums/__init__.py | 1 + .../processing_errors/error_process.py | 47 ++ .../processing_files/__init__.py | 1 + .../processing_file_helper.py | 49 +++ .../processing_rules/__init__.py | 1 + .../processing_rules/enums/__init__.py | 1 + .../enums/filter_rule_part_location.py | 15 + .../filter_rule_part_processing_result.py | 19 + .../enums/filter_rule_part_type.py | 30 ++ .../processing_rules/enums/ordered_enum.py | 26 ++ .../processing_rules/enums/port_class.py | 21 + .../processing_rules/enums/port_pair_class.py | 63 +++ .../enums/protocol_numbers.py | 38 ++ .../processing_rules/filter_rule.py | 242 ++++++++++ .../processing_rules/filter_rule_generator.py | 413 ++++++++++++++++++ .../processing_rules/supported_values.py | 8 + lib/tuples_analyzer/value_formats/__init__.py | 1 + .../value_formats/value_format.py | 19 + 56 files changed, 2512 insertions(+), 7 deletions(-) create mode 100644 lib/tuples_analyzer/README create mode 100644 lib/tuples_analyzer/__init__.py create mode 100644 lib/tuples_analyzer/__main__.py create mode 100644 lib/tuples_analyzer/calculation_parameters/__init__.py create mode 100644 lib/tuples_analyzer/calculation_parameters/distribution.py create mode 100644 lib/tuples_analyzer/calculation_parameters/enums/__init__.py create mode 100644 lib/tuples_analyzer/calculation_parameters/enums/port_distribution_type.py create mode 100644 lib/tuples_analyzer/calculation_parameters/enums/trie_type.py create mode 100644 lib/tuples_analyzer/calculation_parameters/interfaces/IParameter.py create mode 100644 lib/tuples_analyzer/calculation_parameters/interfaces/__init__.py create mode 100644 lib/tuples_analyzer/calculation_parameters/parameter_file.py create mode 100644 lib/tuples_analyzer/calculation_parameters/port_distribution.py create mode 100644 lib/tuples_analyzer/calculation_parameters/ppc_prefixlen_distribution.py create mode 100644 lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py create mode 100644 lib/tuples_analyzer/calculation_parameters/protocol_ppc_distribution.py create mode 100644 lib/tuples_analyzer/calculation_parameters/trie_distributions.py create mode 100644 lib/tuples_analyzer/calculation_parameters/trie_node.py create mode 100644 lib/tuples_analyzer/examples/formats/format_1 create mode 100644 lib/tuples_analyzer/examples/formats/format_2 create mode 100644 lib/tuples_analyzer/examples/formats/ipfw create mode 100644 lib/tuples_analyzer/examples/formats/iptables create mode 100644 lib/tuples_analyzer/examples/formats/openflow create mode 100644 lib/tuples_analyzer/examples/sets/ipfw create mode 100644 lib/tuples_analyzer/examples/sets/iptables create mode 100644 lib/tuples_analyzer/examples/sets/openflow create mode 100644 lib/tuples_analyzer/examples/sets/set_1 create mode 100644 lib/tuples_analyzer/examples/sets/set_2 create mode 100644 lib/tuples_analyzer/printing_output/__init__.py create mode 100644 lib/tuples_analyzer/printing_output/enums/__init__.py create mode 100644 lib/tuples_analyzer/printing_output/enums/output_direction.py create mode 100644 lib/tuples_analyzer/printing_output/output_print.py create mode 100644 lib/tuples_analyzer/processing_arguments/__init__.py create mode 100644 lib/tuples_analyzer/processing_arguments/processed_arguments.py create mode 100644 lib/tuples_analyzer/processing_errors/__init__.py create mode 100644 lib/tuples_analyzer/processing_errors/enums/Error.py create mode 100644 lib/tuples_analyzer/processing_errors/enums/__init__.py create mode 100644 lib/tuples_analyzer/processing_errors/error_process.py create mode 100644 lib/tuples_analyzer/processing_files/__init__.py create mode 100644 lib/tuples_analyzer/processing_files/processing_file_helper.py create mode 100644 lib/tuples_analyzer/processing_rules/__init__.py create mode 100644 lib/tuples_analyzer/processing_rules/enums/__init__.py create mode 100644 lib/tuples_analyzer/processing_rules/enums/filter_rule_part_location.py create mode 100644 lib/tuples_analyzer/processing_rules/enums/filter_rule_part_processing_result.py create mode 100644 lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py create mode 100644 lib/tuples_analyzer/processing_rules/enums/ordered_enum.py create mode 100644 lib/tuples_analyzer/processing_rules/enums/port_class.py create mode 100644 lib/tuples_analyzer/processing_rules/enums/port_pair_class.py create mode 100644 lib/tuples_analyzer/processing_rules/enums/protocol_numbers.py create mode 100644 lib/tuples_analyzer/processing_rules/filter_rule.py create mode 100644 lib/tuples_analyzer/processing_rules/filter_rule_generator.py create mode 100644 lib/tuples_analyzer/processing_rules/supported_values.py create mode 100644 lib/tuples_analyzer/value_formats/__init__.py create mode 100644 lib/tuples_analyzer/value_formats/value_format.py diff --git a/README.md b/README.md index 528cd8c..cec5243 100644 --- a/README.md +++ b/README.md @@ -44,10 +44,14 @@ ClassBench-ng can be used in two different ways: - To generate a synthetic rule set from an input SEED. ### ClassBench-ng Analyser -The current version of the analyser supports only OpenFlow rules. +ClassBench-ng offers two versions of the analysers: OpenFlow analyser and Tuples analyser. +#### OpenFlow Analyser +First version of analyser supports only OpenFlow rules. +The output is an original ClassBench seed with an OpenFlow YAML structure as the last section. +This version can be run with these arguments: ``` -./classbench analyse FILE +./classbench analyse of FILE ``` Analyses FILE, expecting FILE to be in the format used by `ovs-ofctl`. Fields extracted from FILE are: @@ -56,7 +60,24 @@ Fields extracted from FILE are: - nw_src, nw_dst, nw_tos, nw_proto, - tp_src, tp_dst -The output is an original ClassBench seed with an OpenFlow YAML structure as the last section. +#### OpenFlow Analyser +Second version of analyser accepts any filter rule sets format but file, +describing format of rules in set, has to be given to analyser as argument. +How to define file with format is described in file lib/tuples_analyzer/README. +In folder lib/tuples_analyzer/examples there are also examples of filter rule sets and +files with formats of rules defined to them. +Fields extracted from rules are only parts of standard IP 5-tuple: +(protocol, source IPv4 address, source port or source port range, destination IPv4 address, +destination port or destination port range) +The output is an original ClassBench seed without OpenFlow YAML structure. +It can be run with these arguments: +``` +./classbench analyse tuples --rules= --format= [--output=] [--logs] +``` +- `--rules=` specifies the path to file with filter rules +- `--format=` specifies the path to file with format of rules +- `--output=` specifies the path to output file +- `--logs` enables printing error logs during processing of filter rules ### ClassBench-ng Rule Generator The current version can successfully generate IPv4, IPv6 and OpenFlow 1.0 flow rules. diff --git a/classbench b/classbench index 3f9afc1..fe9d2fe 100755 --- a/classbench +++ b/classbench @@ -9,20 +9,25 @@ ClassBench-ng A tool for generation of synthetic classification rule sets for benchmarking. Usage: - #{__FILE__} analyse FILE + #{__FILE__} analyse of FILE + #{__FILE__} analyse tuples --rules= --format= [--output=] [--logs] #{__FILE__} generate v4 SEED [--count=] [--db-generator=] #{__FILE__} generate v6 SEED [--count=] [--db-generator=] #{__FILE__} generate of SEED [--count=] [--db-generator=] #{__FILE__} -h | --help Options: + --rules= Path to file with filter rules. + --format= Path to file with format of rules. + --output= Path to output file. + --logs Enable printing error logs during processing of filter rules. --db-generator= Path to an original ClassBench binary. [default: ./vendor/db_generator/db_generator] --count= The number of rules to be generated. [default: 100] -h --help Show this screen. -Analyser accepts as an input an ovs-ofctl dump. +Analyser launched with arguments: "analyse of", accepts as an input an ovs-ofctl dump. Fields extracted from the dump are: - in_port, - dl_src, dl_dst, eth_type, dl_vlan, dl_vlan_pcp, @@ -31,6 +36,16 @@ Fields extracted from the dump are: The output is an original ClassBench seed with an OpenFlow YAML structure as the last section. +Analyser launched with arguments: "analyse tuples", accepts any filter rule sets format but file, +describing format of rules in set, has to be given to analyser as argument. +How to define file with format is described in file lib/tuples_analyzer/README. +In folder lib/tuples_analyzer/examples there are also examples of filter rule sets and +formats belonging to them. +Fields extracted from the rules are parts of standard IP 5-tuple: +(protocol, source IPv4 address, source port or source port range, destination IPv4 address, +destination port or destination port range) +The output is an original ClassBench seed without OpenFlow YAML structure. + Generator accepts as an input an original ClassBench seed that has to contain an OpenFlow section in case of "generate of". The output is either the same as of original ClassBench outputs or it consists @@ -44,7 +59,11 @@ DOCOPT begin opts = Docopt::docopt(doc) if opts["analyse"] - Classbench::analyse(opts["FILE"]) + if opts["of"] + Classbench::analyse_of(opts["FILE"]) + elsif opts["tuples"] + Classbench::analyse_tuples(opts["--rules"], opts["--format"], opts["--output"], opts["--logs"]) + end elsif opts["generate"] if opts["v4"] Classbench::generate("v4", opts["SEED"], (opts["--count"].to_i), opts["--db-generator"]) diff --git a/lib/classbench.rb b/lib/classbench.rb index bb5e05c..f5bc9e8 100644 --- a/lib/classbench.rb +++ b/lib/classbench.rb @@ -32,7 +32,7 @@ def self.load_prefixes_from_file(filename) t end - def self.analyse(filename) + def self.analyse_of(filename) analyser = Analyser.new analyser.parse_openflow(File.read(filename)) @@ -42,6 +42,38 @@ def self.analyse(filename) end + def self.analyse_tuples(rules_filename, format_filename, output_filename, logs_enabled) + if logs_enabled and !output_filename.to_s.empty? + pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename, "-o", output_filename, "-l") + elsif logs_enabled + pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename, "-l") + elsif !output_filename.to_s.empty? + pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename, "-o", output_filename) + else + pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename) + end + + ignored, status = Process::waitpid2 pid + + if status.exitstatus == 0 + if output_filename.to_s.empty? + puts stdout.read.strip + end + + if logs_enabled + warnings = stderr.read.strip + + if !warnings.to_s.empty? + puts warnings + end + end + else + puts stderr.read.strip + exit(status.exitstatus) + end + + end + def self.generate(format, filename, count, db_generator_path) generator = Generator.new(filename, db_generator_path) if format == "of" diff --git a/lib/tuples_analyzer/README b/lib/tuples_analyzer/README new file mode 100644 index 0000000..45db017 --- /dev/null +++ b/lib/tuples_analyzer/README @@ -0,0 +1,107 @@ +1.PROGRAM: + tuples_analyzer + +2.FUNCTION: + Program creates parameter file from statistics and distributions of real filter set. + File with format of rules is needed for processing filter rules. Format is described in section 7. + Computed parameters are then used to generate synthetic filter set by tools ClassBench and ClassBench-ng. + +3.USAGE: + python3 -m tuples_analyzer -r -f [-o -l -h] + +4.USAGE EXAMPLES: + a.) python3 -m tuples_analyzer -h + b.) python3 -m tuples_analyzer -r rules.txt -f format.txt + c.) python3 -m tuples_analyzer -r rules.txt -f format.txt -l + d.) python3 -m tuples_analyzer -r rules.txt -f format.txt -o output.txt + e.) python3 -m tuples_analyzer -r rules.txt -f format.txt -o output.txt -l + +5.MANDATORY ARGUMENTS: + -r rules_file | --rules=rules_file specify path to file with filter rules + -f format_file | --format=format_file specify path to file with format of rules + +6.OPTIONAL ARGUMENTS: + -o output_file | --output=output_file specify path to file, which will be created + to store computed parameters + + -l | --logs printing error logs during computation is enabled + -h | --help display manual + +7.FORMAT OF RULES: + Format tells, how one rule in set should look like. Program loads format from first line of format file. Specify path to + file with argument '-f'. + + Format of rule is sentence consisting of parameters and keywords. Parameters (specified uppercase words) are like + variables. They always represent different value in filter rule than its notation in format. E.g. parameter 'PROTOCOL' + in format, represents network protocol abbreviation in rule (e.g. 'tcp'). Keywords in format are exactly same strings + in rule (e.g. 'from', 'to'). + + Order of placement parameters and keywords in format sentence is important. In process of parsing + rule, is from beginning of rule to its end checked, if every part of rule matches to its definition + in format. E.g. if format starts with 'from SRC_IP', it is expected, that first part of rule will be + 'from' (same as 'from' in format) and second part will be ip address for example '10.10.10.0/24' + (parameter 'SRC_IP' representation). If order is not correct, rule will be ignored. + + a.)parameters + + Parameters (PROTOCOL, SRC_IP, SRC_PORT, DST_IP, DST_PORT, NUMBER, WILDCARD) in format definition tell, what type of + value is expected on same position in rule. What every parameter represents is described in this list: + + PROTOCOL network protocol abbreviation + SRC_IP source IPv4 address + SRC_PORT source port or port range + DST_IP destination IPv4 address + DST_PORT destination port or port range + NUMBER some number, not used for computation parameters + WILDCARD some string, not used for computation parameters + + b.)supported representation of parameters in rules + + Supported IPv4 address definitions in rules are: 10.0.0.0/24, 192.168.0.33 (with or without mask in digit form) + Supported port definitions in rules are: 80, 0:1023 (port or port range) + Supported network protocol case-insensitive abbreviations in rules are: + 'ICMP', 'IGMP', 'GGP', 'ST', 'TCP', 'EGP', 'UDP', 'GRE', 'ESP', 'AH', 'EIGRP', 'OSPFIGP' + Supported wildcard values of parameters in rules are: 'any', 'all', ''*', 'ip', '0' + + b.)keywords + + Keywords are every possible strings except all parameters and character '?'. Keywords in format definition tell, + that exactly same string value as keywords is expected on same position in rule. They does not represent valuable + content for computation parameters. They are usually used to introduce parameters. E.g. if you define your format + starting with 'from=SRC_IP', then rule definition in filter set can start with 'from=10.10.10.0/24'. + + Characters ' ', ',', '=' (empty space, comma, equal) are used as separators between parameters and keywords + in format and also separators between parts in filter rules. + + c.)optional parts + + You can define optional parts of rule in your format definition, if you after parameter or keyword + add character '?'. E.g. if format ends with 'ip-port?=DST_PORT?', then at the end of rule is not + required any of these words 'ip-port' or '0:1023' (example of port range) but they can both + be there (of course in correct order). + + +8.FORMAT OF RULES EXAMPLES: + Example sets, formats and correct outputs are located in examples folder. + + a.) format1: + PROTOCOL from SRC_IP SRC_PORT to DST_IP DST_PORT + + b.) format2: + PROTOCOL destination DST_IP ip-port? DST_PORT? source SRC_IP ip-port? SRC_PORT? + + c.) openflow: + nw_proto=PROTOCOL, nw_src?=SRC_IP?, nw_dst?=DST_IP?, tp_src?=SRC_PORT?, tp_dst?=DST_PORT? + + d.)iptables long format: + iptables WILDCARD WILDCARD --source? SRC_IP? --destination? DST_IP? --protocol? PROTOCOL? --source-port? SRC_PORT? --destination-port? DST_PORT? -j WILDCARD + + e.)iptables short format: + iptables WILDCARD WILDCARD -s? SRC_IP? -d? DST_IP? -p? PROTOCOL? --sport? SRC_PORT? --dport? DST_PORT? -j WILDCARD + + f.)ipfw format: + ipfw add WILDCARD PROTOCOL? from SRC_IP? SRC_PORT? to DST_IP? DST_PORT? + +9.AUTHOR: + Jozef Sabo + xsaboj00@stud.fit.vutbr.cz diff --git a/lib/tuples_analyzer/__init__.py b/lib/tuples_analyzer/__init__.py new file mode 100644 index 0000000..9429a2c --- /dev/null +++ b/lib/tuples_analyzer/__init__.py @@ -0,0 +1 @@ +"""Main package of program.""" diff --git a/lib/tuples_analyzer/__main__.py b/lib/tuples_analyzer/__main__.py new file mode 100644 index 0000000..251f817 --- /dev/null +++ b/lib/tuples_analyzer/__main__.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +"""Main module for launching program.""" + +from .calculation_parameters.parameter_file import ParameterFile +from .processing_arguments.processed_arguments import ProcessedArguments +from .processing_files.processing_file_helper import ProcessingFileHelper +from .processing_rules.filter_rule_generator import FilterRuleGenerator + +if __name__ == "__main__": + # instance of class ProcessedArguments contains all processed command line arguments + processed_arguments = ProcessedArguments() + + # generator of lines from filter set file + lines_generator = ProcessingFileHelper.create_lines_generator(processed_arguments.rules_path) + + # string with format of rules in filter set + rule_format = ProcessingFileHelper.get_format(processed_arguments.format_path) + + # generator of FilterRule class instances + rule_generator = FilterRuleGenerator.create_generator(lines_generator, rule_format, processed_arguments.is_stderr_on) + + # instance of class ParameterFile creates and holds all parameters + parameter_file = ParameterFile(rule_generator, processed_arguments.output_path) + + # printing calculated parameters to output + parameter_file.print_parameters() diff --git a/lib/tuples_analyzer/calculation_parameters/__init__.py b/lib/tuples_analyzer/calculation_parameters/__init__.py new file mode 100644 index 0000000..c97a818 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/__init__.py @@ -0,0 +1 @@ +"""Package with classes for computation parameters.""" diff --git a/lib/tuples_analyzer/calculation_parameters/distribution.py b/lib/tuples_analyzer/calculation_parameters/distribution.py new file mode 100644 index 0000000..56a8d30 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/distribution.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +"""Module containing definition of class Distribution.""" + +from collections import Counter + + +class Distribution: + """ + Class representing distribution over different type of values. + """ + + def __init__(self): + """ + Constructor initialize instance variable total_counts with zero. + Variable distribution is initialized as new instance of class Counter. + Counter is collection for counting objects. + """ + self.total_count = 0 + """Total count of values in distribution.""" + self.distribution = Counter() + """Variable holding count of every unique value in distribution.""" + + def add_value(self, value): + """ + When adding new value to distribution, total counts of values has to be incremented by one and + instance variable distribution has to be updated with new value (updating counts of unique values in collection + Counter). + + :param value: Distribution value. + """ + self.total_count += 1 + self.distribution.update({value: 1}) diff --git a/lib/tuples_analyzer/calculation_parameters/enums/__init__.py b/lib/tuples_analyzer/calculation_parameters/enums/__init__.py new file mode 100644 index 0000000..2997f06 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/enums/__init__.py @@ -0,0 +1 @@ +"""Package with enum classes used while computation parameters.""" diff --git a/lib/tuples_analyzer/calculation_parameters/enums/port_distribution_type.py b/lib/tuples_analyzer/calculation_parameters/enums/port_distribution_type.py new file mode 100644 index 0000000..c26fe79 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/enums/port_distribution_type.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"""Module containing definition of enum class PortDistributionType.""" + +from enum import Enum + + +class PortDistributionType(Enum): + """ + Enum for every possible distribution type of port values. + """ + + SPAR = 0 + """Source arbitrary port ranges distribution.""" + SPEM = 1 + """Source exact match ports distribution.""" + DPAR = 2 + """Destination arbitrary port ranges distribution.""" + DPEM = 3 + """Destination exact match ports distribution.""" diff --git a/lib/tuples_analyzer/calculation_parameters/enums/trie_type.py b/lib/tuples_analyzer/calculation_parameters/enums/trie_type.py new file mode 100644 index 0000000..dfa63cc --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/enums/trie_type.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +"""Module containing definition of enum class TrieType.""" + +from enum import Enum + + +class TrieType(Enum): + """ + Enum for types of trie (binary prefix tree). + """ + + SPT = 0 + """Trie created from source prefixes of filter rules.""" + DPT = 1 + """Trie created from destination prefixes of filter rules.""" diff --git a/lib/tuples_analyzer/calculation_parameters/interfaces/IParameter.py b/lib/tuples_analyzer/calculation_parameters/interfaces/IParameter.py new file mode 100644 index 0000000..70a39ba --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/interfaces/IParameter.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +"""Module containing definition of interface IParameter.""" + +from abc import ABCMeta, abstractmethod + + +class IParameter: + """ + Interface which has to be implemented by all parameter computation classes. + """ + __metaclass__ = ABCMeta + + @abstractmethod + def extract_data(self, filter_rule): + """ + Function extracts all needed data from FilterRule instance to compute specific parameter. + Extracted data are stored in instance variables. + + :param filter_rule: FilterRule instance. + """ + pass + + @abstractmethod + def compute_parameter(self): + """ + Function computes parameter from all extracted data. + + :return: Computed parameter. + """ + pass + + @abstractmethod + def print_parameter(self, output): + """ + Function prints parameter to output in ClassBench format. + + :param output: OutputPrint instance. + """ + pass diff --git a/lib/tuples_analyzer/calculation_parameters/interfaces/__init__.py b/lib/tuples_analyzer/calculation_parameters/interfaces/__init__.py new file mode 100644 index 0000000..91d2233 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/interfaces/__init__.py @@ -0,0 +1 @@ +"""Package with interface implemented by all parameter classes.""" diff --git a/lib/tuples_analyzer/calculation_parameters/parameter_file.py b/lib/tuples_analyzer/calculation_parameters/parameter_file.py new file mode 100644 index 0000000..cd03da3 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/parameter_file.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +"""Module containing definition of class ParameterFile.""" + +from .enums.port_distribution_type import PortDistributionType +from .enums.trie_type import TrieType +from .port_distribution import PortDistribution +from .ppc_prefixlen_distribution import PpcPrefixLenDistribution +from .prefix_correlation_distribution import PrefixCorrelationDistribution +from .protocol_ppc_distribution import ProtocolPpcDistribution +from .trie_distributions import TrieDistributions +from ..printing_output.output_print import OutputPrint +from ..processing_rules.enums.port_pair_class import PPC + + +class ParameterFile: + """ + Class representing parameter file. + Every parameter located in ClassBench parameter file has its own class. + This class holds all instances of parameter classes required to create desired parameter file. + """ + loaded_rules = 0 + """Count of processed rules in process of extraction data.""" + + def __init__(self, rule_generator, output_path): + """ + Constructor initialize instance variables as new instances of parameter classes, rule generator class + and output class. + It also calls function load_rules() to load parameter instances with extracted data from filter rules. + + :param rule_generator: Generator of FilterRule instances. + + :param output_path: Path to file, where user wants to save computed parameters. + """ + self.rule_generator = rule_generator + """Generator of FilterRule instances.""" + self.output = OutputPrint(output_path) + """Instance of class used to print computed parameters to output.""" + self.protocol_ppc_distribution = ProtocolPpcDistribution() + """Instance of class ProtocolPpcDistribution.""" + self.port_distributions = [] + """List of instances of class PortDistribution.""" + i = 0 + while i < 4: + self.port_distributions.insert(i, PortDistribution(PortDistributionType(i))) + i += 1 + + self.ppc_prefix_length_distributions = [] + """List of instances of class PpcPrefixLenDistribution.""" + i = 0 + while i < 25: + self.ppc_prefix_length_distributions.insert(i, PpcPrefixLenDistribution(PPC(i))) + i += 1 + + self.trie_distributions = [] + """List of instances of class TrieDistributions.""" + i = 0 + while i < 2: + self.trie_distributions.insert(i, TrieDistributions(TrieType(i))) + i += 1 + + self.prefix_correlation_distribution = PrefixCorrelationDistribution() + """Instance of class PrefixCorrelationDistribution.""" + + self.load_parameters() + + def load_parameters(self): + """ + Function fills structures of all parameter instances with data needed to calculate parameters. + Data are extracted from generator of FilterRule instances. + """ + for rule in self.rule_generator: + self.protocol_ppc_distribution.extract_data(rule) + + for port_distribution in self.port_distributions: + port_distribution.extract_data(rule) + + for ppc_prefix_length_distribution in self.ppc_prefix_length_distributions: + ppc_prefix_length_distribution.extract_data(rule) + + for trie_distributions in self.trie_distributions: + trie_distributions.extract_data(rule) + + self.prefix_correlation_distribution.extract_data(rule) + ParameterFile.loaded_rules += 1 + + def print_parameters(self): + """ + Function calls print functions of all parameter instances to print calculated parameters in ClassBench format. + """ + self.output.print('-scale') + self.output.print(str(ParameterFile.loaded_rules)) + self.output.print('#') + + self.protocol_ppc_distribution.print_parameter(self.output) + + self.output.print('-flags') + self.output.print('#') + + self.output.print('-extra') + self.output.print('0') + self.output.print('#') + + for port_distribution in self.port_distributions: + port_distribution.print_parameter(self.output) + + for ppc_prefix_length_distribution in self.ppc_prefix_length_distributions: + ppc_prefix_length_distribution.print_parameter(self.output) + + for trie_distributions in self.trie_distributions: + trie_distributions.print_parameter(self.output) + + self.prefix_correlation_distribution.print_parameter(self.output) diff --git a/lib/tuples_analyzer/calculation_parameters/port_distribution.py b/lib/tuples_analyzer/calculation_parameters/port_distribution.py new file mode 100644 index 0000000..1db1f92 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/port_distribution.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +"""Module containing definition of class PortDistribution.""" + +from .distribution import Distribution +from .enums.port_distribution_type import PortDistributionType +from .interfaces.IParameter import IParameter +from ..value_formats.value_format import Format +from ..processing_rules.enums.port_class import PC + + +class PortDistribution(IParameter): + """ + Class representing parameter: port values distribution. + There are 4 types of port values distributions (SPAR, SPEM, DPAR, DPEM). + Type of distribution tells from which port values of filter rules will be created distribution. + Types are more described in enum class PortDistributionClass. + """ + + def __init__(self, port_distribution_type): + """ + Parameter of constructor decides which type of port values distribution will be represented by created instance + of that class. + + :param port_distribution_type: Enum value of type of port values distribution. + """ + self.distribution_type = port_distribution_type + """Type of port values distribution.""" + self.distribution = Distribution() + """Distribution of unique port values.""" + + def extract_data(self, filter_rule): + """ + Function updates instance variable distribution with new counts of unique port values extracted from filter rules. + + :param filter_rule: FilterRule instance. + """ + if self.distribution_type == PortDistributionType.SPAR and filter_rule.src_port_class == PC.AR: + self.distribution.add_value(filter_rule.src_port) + + elif self.distribution_type == PortDistributionType.SPEM and filter_rule.src_port_class == PC.EM: + self.distribution.add_value(filter_rule.src_port) + + elif self.distribution_type == PortDistributionType.DPAR and filter_rule.dst_port_class == PC.AR: + self.distribution.add_value(filter_rule.dst_port) + + elif self.distribution_type == PortDistributionType.DPEM and filter_rule.dst_port_class == PC.EM: + self.distribution.add_value(filter_rule.dst_port) + + def compute_parameter(self): + """ + Function computes parameter from all counts of unique port values stored in instance variable distribution. + + :return: Port values distribution in string format. + """ + parameter = "" + + first = True + for port_range in self.distribution.distribution.most_common(): + + # for first port range we do not want print new line + if first: + first = False + else: + parameter += '\n' + + parameter += str(Format.decimal(port_range[1] / self.distribution.total_count)) + '\t' + str(port_range[0]) + return parameter + + def print_parameter(self, output): + """ + Function calls method compute_parameter() to compute parameter and then prints parameter to output in + ClassBench format. + + :param output: OutputPrint instance. + """ + output.print('-' + str(self.distribution_type)[-4:].lower()) + if self.distribution.total_count != 0: + output.print(self.compute_parameter()) + output.print('#') diff --git a/lib/tuples_analyzer/calculation_parameters/ppc_prefixlen_distribution.py b/lib/tuples_analyzer/calculation_parameters/ppc_prefixlen_distribution.py new file mode 100644 index 0000000..f9a76e9 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/ppc_prefixlen_distribution.py @@ -0,0 +1,92 @@ +# !/usr/bin/env python +"""Module containing definition of class PpcPrefixLenDistribution.""" + +from .distribution import Distribution +from .interfaces.IParameter import IParameter +from ..value_formats.value_format import Format + + +class PpcPrefixLenDistribution(IParameter): + """ + Class representing parameter: prefix lengths distribution from rules with same port pair class (PPC). + There are total 25 PPCs, so for every group of rules with same PPC program has to create one independent instance of + class. + """ + + def __init__(self, port_pair_class): + """ + Constructor decides from which rules will be made prefix lengths distribution. Decision is made by enum value of + PPC given by parameter of constructor. + + :param port_pair_class: Enum value of PPC. + """ + self.port_pair_class = port_pair_class + """PPC of rules from which is made distribution.""" + self.distribution = dict() + """Instance variable of type dictionary. Elements in dictionary have total prefix length as key and + instance of class Distribution as value. In value of dictionary are stored counts of unique source prefix + lengths.""" + + def extract_data(self, filter_rule): + """ + Function fills dictionary (instance variable distribution) with new elements and data (counts of unique lengths). + If total prefix length extracted from filter rule is new key in dictionary, then add new element to dictionary + with this key. + Value (instance of class Distribution) of element with extracted total prefix length as key is always updated + with source prefix length of filter rule. + + :param filter_rule: FilterRule instance. + """ + if self.port_pair_class == filter_rule.get_ppc_class(): + total_length = filter_rule.src_ip_add_prefix_length + filter_rule.dst_ip_add_prefix_length + + if total_length not in self.distribution: + self.distribution[total_length] = Distribution() + + self.distribution.get(total_length).add_value(filter_rule.src_ip_add_prefix_length) + + def compute_parameter(self): + """ + Function computes parameter from all elements stored in dictionary (instance variable distribution). + + :return: Prefix lengths distribution in string format. + """ + parameter = "" + + # total count of processed rules with same PPC + rules_count = sum([value.total_count for key, value in self.distribution.items()]) + + first = True + for total_prefix_length, value in sorted(self.distribution.items()): + + # for first total prefix length we do not want print new line + if first: + first = False + else: + parameter += '\n' + + # total count of rules with same total prefix length + total_prefix_len_count = value.total_count + + parameter += str(total_prefix_length) + ',' + str(Format.decimal(total_prefix_len_count / rules_count)) + + for source_prefix_length in sorted(value.distribution): + # total count of rules with same source prefix length + src_prefix_len_count = value.distribution[source_prefix_length] + + parameter += '\t' + str(source_prefix_length) + ',' + parameter += str(Format.decimal(src_prefix_len_count / total_prefix_len_count)) + + return parameter + + def print_parameter(self, output): + """ + Function calls method compute_parameter() to compute parameter and then prints parameter to output in + ClassBench format. + + :param output: OutputPrint instance. + """ + output.print('-' + str(self.port_pair_class)[-5:].lower()) + if self.distribution: + output.print(self.compute_parameter()) + output.print('#') diff --git a/lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py b/lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py new file mode 100644 index 0000000..c1b1e24 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +"""Module containing definition of class PrefixCorrelationDistribution.""" + +from .interfaces.IParameter import IParameter +from ..value_formats.value_format import Format + + +class PrefixCorrelationDistribution(IParameter): + """ + Class representing parameter: prefix correlation distribution. + Correlation means source and destination prefixes of one filter rule are continuing to be same, + in length where are both defined. + """ + + def __init__(self): + """ + Constructor initialize two instance variable as lists with zero values. + Both lists are sizes of 32. Indexes of lists are representing prefix levels. + """ + self.all_on_level = [0] * 32 + """List with counts of rules which have same source and destination prefixes until previous level.""" + self.same_on_level = [0] * 32 + """List with counts of rules which source and destination prefixes are same on level.""" + + def extract_data(self, filter_rule): + """ + Function updates counts of rules on levels (indexes) in list instance variables. + + :param filter_rule: FilterRule instance. + """ + # do not care about prefixes with wildcards + if filter_rule.src_ip_add_bin != '*' and filter_rule.dst_ip_add_bin != '*': + + # prefix length where are both prefixes defined + valid_length = PrefixCorrelationDistribution.get_smaller_prefix(filter_rule) + + i = 0 + # going through bits of prefix + for b in filter_rule.src_ip_add_bin[:valid_length]: + + self.all_on_level[i] += 1 + + # if prefixes do not continue to be same break the cycle + if b == filter_rule.dst_ip_add_bin[i]: + self.same_on_level[i] += 1 + else: + break + + i += 1 + + def compute_parameter(self): + """ + Function computes parameter from counts of rules stored in list instance variables. + + :return: Prefix correlation distribution in string format. + """ + parameter = "" + i = 1 + first = True + + for rules_count in self.all_on_level: + + # for first correlation we do not want print new line + if first: + first = False + else: + parameter += '\n' + + parameter += str(i) + '\t' + if rules_count == 0: + parameter += '0.00000000' + else: + parameter += str(Format.decimal(self.same_on_level[i - 1] / rules_count)) + i += 1 + + return parameter + + def print_parameter(self, output): + """ + Function calls method compute_parameter() to compute parameter and then prints parameter to output in + ClassBench format. + + :param output: OutputPrint instance. + """ + output.print('-pcorr') + output.print(self.compute_parameter()) + output.print('#') + + @staticmethod + def get_smaller_prefix(filter_rule): + """ + Function returns smaller one prefix length of source and destination prefixes in filter rule. + + :param filter_rule: FilterRule instance. + :return: Smaller prefix length of prefixes in filter rule. + """ + if filter_rule.src_ip_add_prefix_length > filter_rule.dst_ip_add_prefix_length: + return filter_rule.dst_ip_add_prefix_length + else: + return filter_rule.src_ip_add_prefix_length diff --git a/lib/tuples_analyzer/calculation_parameters/protocol_ppc_distribution.py b/lib/tuples_analyzer/calculation_parameters/protocol_ppc_distribution.py new file mode 100644 index 0000000..20f3550 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/protocol_ppc_distribution.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +"""Module containing definition of class ProtocolPpcDistribution.""" + +from .distribution import Distribution +from .interfaces.IParameter import IParameter +from ..value_formats.value_format import Format +from ..processing_rules.enums.port_pair_class import PPC + + +class ProtocolPpcDistribution(IParameter): + """ + Class representing parameter: port pair classes (PPCs) distribution over unique protocols in filter set. + """ + + def __init__(self): + """ + Constructor only initialize instance variable distribution as new instance of dictionary. + """ + self.distribution = dict() + """Instance variable of type dictionary. Elements in dictionary have protocol enum value as key and + instance of class Distribution as value.""" + + def extract_data(self, filter_rule): + """ + Function fills dictionary (instance variable distribution) with new elements and data. + If protocol extracted from filter rule is new key in dictionary, then it adds new element + with this key to dictionary. + Value (instance of class Distribution) of element with extracted protocol as key is always updated + with PPC class of filter rule. + + :param filter_rule: FilterRule instance. + """ + if filter_rule.protocol not in self.distribution: + self.distribution[filter_rule.protocol] = Distribution() + + self.distribution.get(filter_rule.protocol).add_value(filter_rule.get_ppc_class()) + + def compute_parameter(self): + """ + Function computes parameter from all elements stored in dictionary (instance variable distribution). + + :return: PPCs distribution over protocols in string format. + """ + parameter = "" + + # total count of processed protocols in all filter rules + rules_count = sum([value.total_count for key, value in self.distribution.items()]) + first = True + + for protocol, value in sorted(self.distribution.items()): + + # for first protocol we do not want print new line + if first: + first = False + else: + parameter += '\n' + + # total count of processed filter rules with specific protocol + protocol_count = value.total_count + parameter += str(protocol.value) + '\t' + str(Format.decimal(protocol_count / rules_count)) + + i = 0 + while i < 25: + ppc_distribution = value.distribution[PPC(i)] + parameter += '\t' + str(Format.decimal(ppc_distribution / protocol_count)) + i += 1 + + return parameter + + def print_parameter(self, output): + """ + Function calls method compute_parameter() to compute parameter and then prints parameter to output in + ClassBench format. + + :param output: OutputPrint instance. + """ + output.print('-prots') + output.print(self.compute_parameter()) + output.print('#') diff --git a/lib/tuples_analyzer/calculation_parameters/trie_distributions.py b/lib/tuples_analyzer/calculation_parameters/trie_distributions.py new file mode 100644 index 0000000..afd1a00 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/trie_distributions.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python +"""Module containing definition of class TrieDistributions.""" + +from .enums.trie_type import TrieType +from .interfaces.IParameter import IParameter +from .trie_node import TrieNode +from ..value_formats.value_format import Format + + +class TrieDistributions(IParameter): + """ + Class representing 3 parameters gained by constructing binary prefix tree (trie). + These parameters are: distributions over prefix branching probability, skew average and prefix nesting threshold. + """ + + def __init__(self, trie_type): + """ + Constructor decides from which prefixes (source/destination) will be created trie. Decision is made by enum + value of trie type given by parameter. + + :param trie_type: Enum value of trie type. + """ + self.trie_type = trie_type + """Type of trie is telling from which prefixes is trie constructed (source/destination prefixes).""" + self.root_node = TrieNode('*') + """Root node of trie. Trie is constructed by adding new prefixes to root.""" + + def extract_data(self, filter_rule): + """ + Function is filling trie with source or destination prefixes extracted from filter rule. + + :param filter_rule: FilterRule instance. + """ + if self.trie_type == TrieType.SPT and filter_rule.src_ip_add_bin != '*': + self.root_node.add_prefix(filter_rule.src_ip_add_bin) + + elif self.trie_type == TrieType.DPT and filter_rule.dst_ip_add_bin != '*': + self.root_node.add_prefix(filter_rule.dst_ip_add_bin) + + def compute_parameter(self): + """ + Function computes parameters from constructed trie. + + :return: Computed parameters of trie distributions in string form. + """ + parameter = "" + first = True + i = 0 + + # checking if trie is not empty + if self.root_node.children: + # current level nodes + nodes = [self.root_node] + + while self.root_node.max_level > i: + + # for first level we do not want print new line + if first: + first = False + else: + parameter += '\n' + + count_1child = 0 + count_2children = 0 + # skew values on level + skew_list = [] + # nodes on next level are stored here + temp_list = [] + + for node in nodes: + if len(node.children) == 1: + count_1child += 1 + temp_list.extend(node.children) + elif len(node.children) == 2: + count_2children += 1 + temp_list.extend(node.children) + skew_list.append(node.count_skew()) + + nodes = temp_list + parameter += str(i) + '\t' + TrieDistributions.get_branching_probability(count_1child, count_2children) + parameter += '\t' + TrieDistributions.get_average_skews(skew_list) + i += 1 + + # for undefined levels of trie, lines have this format: + while i < 33: + if first: + first = False + else: + parameter += '\n' + parameter += str(i) + "\t0.00000000\t0.00000000\t0.00000000" + i += 1 + + return parameter + + def print_parameter(self, output): + """ + Function calls method compute_parameter() to compute parameter and then prints parameter to output in + ClassBench format. + + :param output: OutputPrint instance. + """ + if self.trie_type == TrieType.SPT: + output.print('-snest') + output.print(str(self.root_node.threshold)) + output.print('#') + output.print('-sskew') + output.print(self.compute_parameter()) + output.print('#') + + elif self.trie_type == TrieType.DPT: + output.print('-dnest') + output.print(str(self.root_node.threshold)) + output.print('#') + output.print('-dskew') + output.print(self.compute_parameter()) + output.print('#') + + @staticmethod + def get_branching_probability(count_1child, count_2children): + """ + Function returns probability of node having 1 child or 2 children on some level of prefix trie. + + :param count_1child: Count of nodes with 1 child on level. + + :param count_2children: Count of nodes with 2 children on level. + + :return: Probability of node having 1 child or 2 children on level. + """ + sum = count_1child + count_2children + probability_1child = Format.decimal(count_1child / sum) + probability_2children = Format.decimal(count_2children / sum) + probability = str(probability_1child) + '\t' + str(probability_2children) + return probability + + @staticmethod + def get_average_skews(skew_list): + """ + Function returns average of skews in list given by parameter. + + :param skew_list: List with skew values. + + :return: Average of skew values in list. + """ + # skew list is empty + if len(skew_list) == 0: + return '0.00000000' + + count_skews = 0 + sum_skews = 0 + + for skew in skew_list: + sum_skews += skew + count_skews += 1 + + skew_average = str(Format.decimal(sum_skews / count_skews)) + return skew_average diff --git a/lib/tuples_analyzer/calculation_parameters/trie_node.py b/lib/tuples_analyzer/calculation_parameters/trie_node.py new file mode 100644 index 0000000..19ebdad --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/trie_node.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python +"""Module containing definition of class TrieNode.""" + + +class TrieNode: + """ + Class is representing node of trie (binary prefix tree). + """ + + def __init__(self, bit): + """ + Constructor initialize node instance variable bit with value of parameter bit. + Other instance variable are initialized as empty list, zero or None. + + :param bit: Bit value. + """ + self.parent = None + """Parent of node. Only root node does not have parent.""" + self.bit = bit + """Last bit of prefix. For trie nodes can be bit value '0' or '1'. Bit of root node is '*'.""" + self.prefix = False + """Instance variable prefix is boolean type and is telling, if node is prefix or only node on path to prefix.""" + self.level = 0 + """Prefix level of node in trie (0-32).""" + self.children = [] + """List holding instances of children nodes. Trie node can have max. 2 children.""" + self.prefixes = [0, 0] + """List with prefix counts under children nodes.""" + self.threshold = 0 + """Prefix nesting threshold.""" + self.max_level = 0 + """Highest prefix level of node in trie. Only root node uses this variable while printing distributions.""" + + def get_prefix(self, prefix): + """ + Function returns instance of child node in trie represented by prefix string given by parameter. + + :param prefix: String consisting of numbers 0 and 1. + + :return: If node was found return instance of that node, otherwise return None. + """ + # trying to find node in trie, which is representing wanted string of prefix + node = self + for bit in prefix: + bit_not_found = True + + for child in node.children: + if child.bit == bit: + bit_not_found = False + node = child + break + + if bit_not_found: + return None + + # checking if found node is prefix or only path to some different prefix + if node.prefix: + return node + else: + return None + + def add_prefix(self, prefix): + """ + Function adds new prefix to trie. + Process of adding new prefix always starts from root node. + + :param prefix: String consisting of numbers 0 and 1. + """ + already_in_trie = self.get_prefix(prefix) + + # if prefix is already in trie, function only needs recalculate prefix counts of parent nodes + if already_in_trie: + TrieNode.recalculate_prefix_counts(already_in_trie) + + else: + node = self + + # search for bit in children of present node, or add a new node to trie if not found + for bit in prefix: + found_in_child = False + + for child in node.children: + if child.bit == bit: + node = child + found_in_child = True + break + + if not found_in_child: + new_node = TrieNode(bit) + new_node.level = node.level + 1 + new_node.parent = node + node.children.append(new_node) + node = new_node + + # mark new node as prefix + node.prefix = True + + # update max level of root node + if node.level > self.max_level: + self.max_level = node.level + + # recalculate prefix counts of parent nodes + TrieNode.recalculate_prefix_counts(node) + + # recalculate prefix nesting thresholds of current and parent nodes + TrieNode.recalculate_prefix_thresholds(node) + + def count_skew(self): + """ + Function computes skew of current node. It is called only on nodes, which have 2 children. + + :return: Computed skew. + """ + if self.prefixes[0] > self.prefixes[1]: + bigger = self.prefixes[0] + smaller = self.prefixes[1] + else: + bigger = self.prefixes[1] + smaller = self.prefixes[0] + + skew = 1 - smaller / bigger + return skew + + @staticmethod + def recalculate_prefix_counts(node): + """ + After adding node to trie, recalculation of prefix counts of parent nodes has to be done. + + :param node: Instance of newly added node to trie. + """ + child = node + parent = child.parent + + while parent: + if child.bit == '0': + parent.prefixes[0] += 1 + elif child.bit == '1': + parent.prefixes[1] += 1 + + child = parent + parent = child.parent + + @staticmethod + def recalculate_prefix_thresholds(node): + """ + After adding new node to trie, calculation of prefix nesting threshold of current node and recalculation of + parent thresholds has to be done. + + :param node: Instance of newly added node to trie. + """ + # finding bigger of children thresholds + bigger_child_threshold = 0 + + for child in node.children: + child_threshold = 0 + + if child.prefix: + child_threshold += 1 + + child_threshold += child.threshold + + if child_threshold > bigger_child_threshold: + bigger_child_threshold = child_threshold + + # setting threshold of added node + node.threshold = bigger_child_threshold + + # recalculate prefix nesting thresholds of parent nodes + child = node + parent = child.parent + threshold = bigger_child_threshold + 1 + + while parent: + if threshold > parent.threshold: + parent.threshold = threshold + else: + break + + if parent.prefix: + threshold += 1 + + child = parent + parent = child.parent diff --git a/lib/tuples_analyzer/examples/formats/format_1 b/lib/tuples_analyzer/examples/formats/format_1 new file mode 100644 index 0000000..0afa4aa --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/format_1 @@ -0,0 +1 @@ +PROTOCOL from SRC_IP SRC_PORT to DST_IP DST_PORT diff --git a/lib/tuples_analyzer/examples/formats/format_2 b/lib/tuples_analyzer/examples/formats/format_2 new file mode 100644 index 0000000..6259e4d --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/format_2 @@ -0,0 +1 @@ +PROTOCOL destination DST_IP ip-port? DST_PORT? source SRC_IP ip-port? SRC_PORT? diff --git a/lib/tuples_analyzer/examples/formats/ipfw b/lib/tuples_analyzer/examples/formats/ipfw new file mode 100644 index 0000000..86004fa --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/ipfw @@ -0,0 +1 @@ +ipfw add WILDCARD PROTOCOL? from SRC_IP? SRC_PORT? to DST_IP? DST_PORT? \ No newline at end of file diff --git a/lib/tuples_analyzer/examples/formats/iptables b/lib/tuples_analyzer/examples/formats/iptables new file mode 100644 index 0000000..6d1933f --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/iptables @@ -0,0 +1 @@ +iptables WILDCARD INPUT -s? SRC_IP? -d? DST_IP? -p? PROTOCOL? --sport? SRC_PORT? --dport? DST_PORT? -j WILDCARD \ No newline at end of file diff --git a/lib/tuples_analyzer/examples/formats/openflow b/lib/tuples_analyzer/examples/formats/openflow new file mode 100644 index 0000000..0daaf50 --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/openflow @@ -0,0 +1,2 @@ +nw_proto=PROTOCOL, nw_src?=SRC_IP?, nw_dst?=DST_IP?, tp_src?=SRC_PORT?, tp_dst?=DST_PORT? + diff --git a/lib/tuples_analyzer/examples/sets/ipfw b/lib/tuples_analyzer/examples/sets/ipfw new file mode 100644 index 0000000..6ca835d --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/ipfw @@ -0,0 +1,4 @@ +ipfw add allow tcp from to 10.0.0.0/24 80 +ipfw add accept udp from to 192.0.0.14 +ipfw add deny any from to 5000:5100 +ipfw add drop from 443 to \ No newline at end of file diff --git a/lib/tuples_analyzer/examples/sets/iptables b/lib/tuples_analyzer/examples/sets/iptables new file mode 100644 index 0000000..efce55c --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/iptables @@ -0,0 +1,5 @@ +iptables -A INPUT -s 10.0.0.0/24 -p tcp --dport 0:1023 -j ACCEPT +iptables -A INPUT -s 128.0.0.0/24 -p tcp --sport all -j ACCEPT +iptables -I INPUT -s 192.0.0.1 -p udp --dport 80 -j DROP +iptables -I INPUT -s 192.0.0.0/3 -p udp --dport 1024:65535 -j DROP +iptables -I INPUT -s 192.0.0.0/3 -p udp --dport 5000:5100 -j ACCEPT \ No newline at end of file diff --git a/lib/tuples_analyzer/examples/sets/openflow b/lib/tuples_analyzer/examples/sets/openflow new file mode 100644 index 0000000..c214288 --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/openflow @@ -0,0 +1,58 @@ +nw_proto=0 ,nw_src=147.229.35.0/24 ,nw_dst=147.229.37.9/32 +nw_proto=6 ,nw_dst=147.229.37.9/32 ,tp_dst=443 +nw_proto=6 ,nw_src=147.229.32.0/20 ,nw_dst=147.229.37.9/32 ,tp_dst=80 +nw_proto=6 ,nw_src=147.229.82.0/23 ,nw_dst=147.229.37.9/32 ,tp_dst=80 +nw_proto=6 ,nw_src=147.229.84.0/22 ,nw_dst=147.229.37.9/32 ,tp_dst=80 +nw_proto=6 ,nw_src=147.229.128.0/20 ,nw_dst=147.229.37.9/32 ,tp_dst=80 +nw_proto=6 ,nw_dst=147.229.37.9/32 +nw_proto=0 ,nw_src=147.229.35.0/24 ,nw_dst=147.229.87.12/30 +nw_proto=0 ,nw_src=147.229.37.0/24 ,nw_dst=147.229.87.12/30 +nw_proto=0 ,nw_src=147.229.87.0/24 ,nw_dst=147.229.87.12/30 +nw_proto=0 ,nw_src=147.229.128.248/29 ,nw_dst=147.229.87.12/30 +nw_proto=0 ,nw_dst=147.229.87.12/30 +nw_proto=0 ,nw_src=147.229.35.0/24 ,nw_dst=147.229.128.0/24 +nw_proto=0 ,nw_src=147.229.37.0/24 ,nw_dst=147.229.128.0/24 +nw_proto=0 ,nw_src=147.229.128.0/24 ,nw_dst=147.229.128.0/24 +nw_proto=0 ,nw_src=147.229.87.12/30 ,nw_dst=147.229.128.248/29 +nw_proto=0 ,nw_src=147.229.131.230/32 ,nw_dst=147.229.128.64/28 +nw_proto=0 ,nw_src=147.229.0.0/16 ,nw_dst=147.229.128.79/32 +nw_proto=0 ,nw_src=147.229.153.0/24 ,nw_dst=147.229.128.128/28 +nw_proto=0 ,nw_src=147.229.0.0/16 ,nw_dst=147.229.128.248/29 +nw_proto=0 ,nw_dst=147.229.128.0/24 +nw_proto=0 ,nw_src=147.229.35.0/24 ,nw_dst=147.229.131.240/28 +nw_proto=0 ,nw_src=147.229.37.0/24 ,nw_dst=147.229.131.240/28 +nw_proto=0 ,nw_src=147.229.185.0/24 ,nw_dst=147.229.131.240/28 +nw_proto=6 ,nw_src=147.229.131.240/28 +nw_proto=6 ,nw_dst=147.229.131.240/28 +nw_proto=0 ,nw_src=147.229.34.0/23 ,nw_dst=147.229.34.0/24 +nw_proto=0 ,nw_src=147.229.36.0/23 ,nw_dst=147.229.34.0/24 +nw_proto=0 ,nw_dst=147.229.34.0/28 +nw_proto=0 ,nw_dst=147.229.34.152/29 +nw_proto=6 ,nw_dst=147.229.34.0/24 +nw_proto=6 ,nw_dst=147.229.37.10/31 ,tp_dst=25 +nw_proto=6 ,nw_dst=147.229.37.12/31 ,tp_dst=25 +nw_proto=6 ,nw_src=147.229.32.0/20 ,tp_dst=25 +nw_proto=6 ,nw_src=147.229.82.0/23 ,tp_dst=25 +nw_proto=6 ,nw_src=147.229.84.0/22 ,tp_dst=25 +nw_proto=6 ,nw_src=147.229.128.0/20 ,tp_dst=25 +nw_proto=6 ,nw_dst=147.229.32.0/20 ,tp_dst=25 +nw_proto=6 ,nw_dst=147.229.82.0/23 ,tp_dst=25 +nw_proto=6 ,nw_dst=147.229.84.0/22 ,tp_dst=25 +nw_proto=6 ,nw_dst=147.229.128.0/20 ,tp_dst=25 +nw_proto=6 ,nw_src=147.229.0.0/16 ,nw_dst=147.229.37.128/25 ,tp_dst=80 +nw_proto=6 ,nw_dst=147.229.37.128/25 ,tp_dst=80 +nw_proto=6 ,nw_dst=147.229.35.90/32 +nw_proto=0 ,nw_src=147.229.32.0/20 ,nw_dst=147.229.35.90/32 +nw_proto=0 ,nw_src=147.229.2.218/31 ,nw_dst=147.229.131.240/28 +nw_proto=0 ,nw_src=147.229.131.243/32 ,nw_dst=147.229.2.218/31 +nw_proto=0 ,nw_src=147.229.2.218/31 ,nw_dst=147.229.131.243/32 +nw_proto=0 ,nw_src=147.229.131.243/32 +nw_proto=0 ,nw_src=147.229.131.230/32 ,nw_dst=147.229.128.80/28 +nw_proto=6 ,nw_src=147.229.137.176/32 ,nw_dst=147.229.131.244/30 ,tp_dst=80 +nw_proto=6 ,nw_src=62.84.154.90/32 ,nw_dst=147.229.131.244/30 ,tp_dst=80 +nw_proto=0 ,nw_src=147.229.43.128/28 ,nw_dst=147.229.43.0/24 +nw_proto=0 ,nw_src=147.229.43.144/30 ,nw_dst=147.229.43.0/24 +nw_proto=0 ,nw_src=147.229.43.128/28 ,nw_dst=147.229.37.0/25 +nw_proto=0 ,nw_src=147.229.43.144/30 ,nw_dst=147.229.37.0/25 +nw_proto=0 ,nw_src=147.229.43.128/28 +nw_proto=0 ,nw_src=147.229.43.144/30 diff --git a/lib/tuples_analyzer/examples/sets/set_1 b/lib/tuples_analyzer/examples/sets/set_1 new file mode 100644 index 0000000..568440e --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/set_1 @@ -0,0 +1,58 @@ +any from 147.229.35.0/24 any to 147.229.37.9 any +tcp from any any to 147.229.37.9 443 +tcp from 147.229.32.0/20 any to 147.229.37.9/32 80 +tcp from 147.229.82.0/23 any to 147.229.37.9/32 80 +tcp from 147.229.84.0/22 any to 147.229.37.9/32 80 +tcp from 147.229.128.0/20 any to 147.229.37.9/32 80 +tcp from any any to 147.229.37.9/32 any +any from 147.229.35.0/24 any to 147.229.87.12/30 any +any from 147.229.37.0/24 any to 147.229.87.12/30 any +any from 147.229.87.0/24 any to 147.229.87.12/30 any +any from 147.229.128.248/29 any to 147.229.87.12/30 any +any from any any to 147.229.87.12/30 any +any from 147.229.35.0/24 any to 147.229.128.0/24 any +any from 147.229.37.0/24 any to 147.229.128.0/24 any +any from 147.229.128.0/24 any to 147.229.128.0/24 any +any from 147.229.87.12/30 any to 147.229.128.248/29 any +any from 147.229.131.230/32 any to 147.229.128.64/28 any +any from 147.229.0.0/16 any to 147.229.128.79/32 any +any from 147.229.153.0/24 any to 147.229.128.128/28 any +any from 147.229.0.0/16 any to 147.229.128.248/29 any +any from any any to 147.229.128.0/24 any +any from 147.229.35.0/24 any to 147.229.131.240/28 any +any from 147.229.37.0/24 any to 147.229.131.240/28 any +any from 147.229.185.0/24 any to 147.229.131.240/28 any +tcp from 147.229.131.240/28 any to any any +tcp from any any to 147.229.131.240/28 any +any from 147.229.34.0/23 any to 147.229.34.0/24 any +any from 147.229.36.0/23 any to 147.229.34.0/24 any +any from any any to 147.229.34.0/28 any +any from any any to 147.229.34.152/29 any +tcp from any any to 147.229.34.0/24 any +tcp from any any to 147.229.37.10/31 25 +tcp from any any to 147.229.37.12/31 25 +tcp from 147.229.32.0/20 any to any 25 +tcp from 147.229.82.0/23 any to any 25 +tcp from 147.229.84.0/22 any to any 25 +tcp from 147.229.128.0/20 any to any 25 +tcp from any any to 147.229.32.0/20 25 +tcp from any any to 147.229.82.0/23 25 +tcp from any any to 147.229.84.0/22 25 +tcp from any any to 147.229.128.0/20 25 +tcp from 147.229.0.0/16 any to 147.229.37.128/25 80 +tcp from any any to 147.229.37.128/25 80 +tcp from any any to 147.229.35.90/32 any +any from 147.229.32.0/20 any to 147.229.35.90/32 any +any from 147.229.2.218/31 any to 147.229.131.240/28 any +any from 147.229.131.243/32 any to 147.229.2.218/31 any +any from 147.229.2.218/31 any to 147.229.131.243/32 any +any from 147.229.131.243 any to any any +any from 147.229.131.230 any to 147.229.128.80/28 any +tcp from 147.229.137.176 any to 147.229.131.244/30 80 +tcp from 62.84.154.90/32 any to 147.229.131.244/30 80 +any from 147.229.43.128/28 any to 147.229.43.0/24 any +any from 147.229.43.144/30 any to 147.229.43.0/24 any +any from 147.229.43.128/28 any to 147.229.37.0/25 any +any from 147.229.43.144/30 any to 147.229.37.0/25 any +any from 147.229.43.128/28 any to any any +any from 147.229.43.144/30 any to any any diff --git a/lib/tuples_analyzer/examples/sets/set_2 b/lib/tuples_analyzer/examples/sets/set_2 new file mode 100644 index 0000000..2f10acc --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/set_2 @@ -0,0 +1,58 @@ +ip destination 147.229.37.9/32 source 147.229.35.0/24 permit ports any precedence 101 +tcp destination 147.229.37.9/32 ip-port 443 source any ip-port any permit ports any precedence 111 +tcp destination 147.229.37.9/32 ip-port 80 source 147.229.32.0/20 ip-port any permit ports any precedence 121 +tcp destination 147.229.37.9/32 ip-port 80 source 147.229.82.0/23 ip-port any permit ports any precedence 122 +tcp destination 147.229.37.9/32 ip-port 80 source 147.229.84.0/22 ip-port any permit ports any precedence 123 +tcp destination 147.229.37.9/32 ip-port 80 source 147.229.128.0/20 ip-port any permit ports any precedence 124 +tcp destination 147.229.37.9/32 ip-port any source any ip-port any permit-established ports any precedence 141 +ip destination 147.229.87.12/30 source 147.229.35.0/24 permit ports any precedence 201 +ip destination 147.229.87.12/30 source 147.229.37.0/24 permit ports any precedence 202 +ip destination 147.229.87.12/30 source 147.229.87.0/24 permit ports any precedence 203 +ip destination 147.229.87.12/30 source 147.229.128.248/29 permit ports any precedence 204 +ip destination 147.229.87.12/30 source any deny ports any precedence 241 +ip destination 147.229.128.0/24 source 147.229.35.0/24 permit ports any precedence 301 +ip destination 147.229.128.0/24 source 147.229.37.0/24 permit ports any precedence 302 +ip destination 147.229.128.0/24 source 147.229.128.0/24 permit ports any precedence 303 +ip destination 147.229.128.248/29 source 147.229.87.12/30 permit ports any precedence 311 +ip destination 147.229.128.64/28 source 147.229.131.230/32 permit ports any precedence 321 +ip destination 147.229.128.79/32 source 147.229.0.0/16 permit ports any precedence 322 +ip destination 147.229.128.128/28 source 147.229.153.0/24 permit ports any precedence 331 +ip destination 147.229.128.248/29 source 147.229.0.0/16 permit ports any precedence 341 +ip destination 147.229.128.0/24 source any deny ports any precedence 361 +ip destination 147.229.131.240/28 source 147.229.35.0/24 permit ports any precedence 401 +ip destination 147.229.131.240/28 source 147.229.37.0/24 permit ports any precedence 402 +ip destination 147.229.131.240/28 source 147.229.185.0/24 permit ports any precedence 403 +tcp destination any ip-port any source 147.229.131.240/28 ip-port any permit ports any precedence 411 +tcp destination 147.229.131.240/28 ip-port any source any ip-port any permit-established ports any precedence 441 +ip destination 147.229.34.0/24 source 147.229.34.0/23 permit ports any precedence 501 +ip destination 147.229.34.0/24 source 147.229.36.0/23 permit ports any precedence 502 +ip destination 147.229.34.0/28 source any permit ports any precedence 511 +ip destination 147.229.34.152/29 source any permit ports any precedence 512 +tcp destination 147.229.34.0/24 ip-port any source any ip-port any permit-established ports any precedence 541 +tcp destination 147.229.37.10/31 ip-port 25 source any ip-port any permit ports any precedence 601 +tcp destination 147.229.37.12/31 ip-port 25 source any ip-port any permit ports any precedence 602 +tcp destination any ip-port 25 source 147.229.32.0/20 ip-port any permit ports any precedence 621 +tcp destination any ip-port 25 source 147.229.82.0/23 ip-port any permit ports any precedence 622 +tcp destination any ip-port 25 source 147.229.84.0/22 ip-port any permit ports any precedence 623 +tcp destination any ip-port 25 source 147.229.128.0/20 ip-port any permit ports any precedence 624 +tcp destination 147.229.32.0/20 ip-port 25 source any ip-port any deny ports any precedence 641 +tcp destination 147.229.82.0/23 ip-port 25 source any ip-port any deny ports any precedence 642 +tcp destination 147.229.84.0/22 ip-port 25 source any ip-port any deny ports any precedence 643 +tcp destination 147.229.128.0/20 ip-port 25 source any ip-port any deny ports any precedence 644 +tcp destination 147.229.37.128/25 ip-port 80 source 147.229.0.0/16 ip-port any permit ports any precedence 191 +tcp destination 147.229.37.128/25 ip-port 80 source any ip-port any deny ports any precedence 192 +tcp destination 147.229.35.90/32 ip-port any source any ip-port any permit-established ports any precedence 709 +ip destination 147.229.35.90/32 source 147.229.32.0/20 permit ports any precedence 701 +ip destination 147.229.131.240/28 source 147.229.2.218/31 permit ports any precedence 404 +ip destination 147.229.2.218/31 source 147.229.131.243/32 permit ports any precedence 390 +ip destination 147.229.131.243/32 source 147.229.2.218/31 permit ports any precedence 391 +ip destination any source 147.229.131.243/32 permit ports any precedence 393 +ip destination 147.229.128.80/28 source 147.229.131.230/32 permit ports any precedence 323 +tcp destination 147.229.131.244/30 ip-port 80 source 147.229.137.176/32 ip-port any permit ports any precedence 421 +tcp destination 147.229.131.244/30 ip-port 80 source 62.84.154.90/32 ip-port any permit ports any precedence 422 +ip destination 147.229.43.0/24 source 147.229.43.128/28 permit ports any precedence 551 +ip destination 147.229.43.0/24 source 147.229.43.144/30 permit ports any precedence 552 +ip destination 147.229.37.0/25 source 147.229.43.128/28 permit ports any precedence 553 +ip destination 147.229.37.0/25 source 147.229.43.144/30 permit ports any precedence 554 +ip destination any source 147.229.43.128/28 deny ports any precedence 561 +ip destination any source 147.229.43.144/30 deny ports any precedence 562 diff --git a/lib/tuples_analyzer/printing_output/__init__.py b/lib/tuples_analyzer/printing_output/__init__.py new file mode 100644 index 0000000..3e1765d --- /dev/null +++ b/lib/tuples_analyzer/printing_output/__init__.py @@ -0,0 +1 @@ +"""Package with classes for printing output data to different directions.""" diff --git a/lib/tuples_analyzer/printing_output/enums/__init__.py b/lib/tuples_analyzer/printing_output/enums/__init__.py new file mode 100644 index 0000000..7462f7d --- /dev/null +++ b/lib/tuples_analyzer/printing_output/enums/__init__.py @@ -0,0 +1 @@ +"""Package with enum classes used while printing output data.""" diff --git a/lib/tuples_analyzer/printing_output/enums/output_direction.py b/lib/tuples_analyzer/printing_output/enums/output_direction.py new file mode 100644 index 0000000..a52955c --- /dev/null +++ b/lib/tuples_analyzer/printing_output/enums/output_direction.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +"""Module containing definition of enum class OutputDirection.""" + +from enum import Enum + + +class OutputDirection(Enum): + """ + Enum for every possible output direction of program. + """ + + STDOUT = 0 + """Standard output.""" + FILE = 1 + """Output to file.""" diff --git a/lib/tuples_analyzer/printing_output/output_print.py b/lib/tuples_analyzer/printing_output/output_print.py new file mode 100644 index 0000000..bee605b --- /dev/null +++ b/lib/tuples_analyzer/printing_output/output_print.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +"""Module containing definition of class OutputDirection.""" + +import os +from .enums.output_direction import OutputDirection +from ..processing_errors.enums.Error import Error +from ..processing_errors.error_process import ErrorProcess + + +class OutputPrint: + """ + Class used to print computed parameters in same way to different directions (STDOUT or to file). + """ + + def __init__(self, output_file_path): + """ + Constructor is calling function decide_direction() to initialize instance variables. + + :param output_file_path: Path to file, where user wants to save computed parameters. + """ + self.output_direction = None + """Printing output direction.""" + self.output_file_path = None + """Path to file, where user wants to save computed parameters.""" + self.decide_direction(output_file_path) + + def decide_direction(self, output_file_path): + """ + Function decides, where will be printed output. + If parameter output_file_path is None, output will be printed on STDOUT, + otherwise output will be printed to file specified by parameter. + + :param output_file_path: Path to file, where user wants to save computed parameters. + + :return: If file where user wants to save computed parameters already exists or is not at least empty, + then program prints error message and exits with error code 40. + """ + if output_file_path is None: + self.output_direction = OutputDirection.STDOUT + + else: + if not os.path.isfile(output_file_path) or os.stat(output_file_path).st_size == 0: + try: + with open(output_file_path, 'a+'): + pass + + except EnvironmentError: + ErrorProcess.process_error(Error.CREATING_FILE_ERROR, + f'Wrong path to file where you want to save computed parameters: ' + f'\'{output_file_path}\'.') + self.output_direction = OutputDirection.FILE + self.output_file_path = output_file_path + else: + ErrorProcess.process_error(Error.CREATING_FILE_ERROR, + f'File where you want to save computed parameters: ' + f'\'{output_file_path}\' ' + f'already exists.') + + def print(self, message): + """ + Function prints message to output direction specified in instance variable output_direction. + + :param message: String message. + """ + if self.output_direction == OutputDirection.STDOUT: + print(message) + else: + with open(self.output_file_path, 'a+') as the_file: + the_file.write(str(message) + '\n') diff --git a/lib/tuples_analyzer/processing_arguments/__init__.py b/lib/tuples_analyzer/processing_arguments/__init__.py new file mode 100644 index 0000000..14e8641 --- /dev/null +++ b/lib/tuples_analyzer/processing_arguments/__init__.py @@ -0,0 +1 @@ +"""Package with classes for processing arguments from command line.""" diff --git a/lib/tuples_analyzer/processing_arguments/processed_arguments.py b/lib/tuples_analyzer/processing_arguments/processed_arguments.py new file mode 100644 index 0000000..0d6972c --- /dev/null +++ b/lib/tuples_analyzer/processing_arguments/processed_arguments.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +"""Module containing definition of class ProcessedArguments.""" + +import sys +import getopt +from ..processing_errors.enums.Error import Error +from ..processing_errors.error_process import ErrorProcess + + +class ProcessedArguments: + """ + Class for processing and storing command line arguments from user. + """ + + def __init__(self): + """ + Constructor is calling function process_arguments() to process arguments and + to initialize instance variables with argument values. + """ + self.rules_path = None + """Path to file with filter rules.""" + self.format_path = None + """Path to file with format of filter rules.""" + self.output_path = None + """Path to file, where user wants to save computed parameters.""" + self.is_stderr_on = False + """Variable telling, if printing error logs while parsing filter rules is enabled.""" + self.process_arguments() + + def process_arguments(self): + """ + Function processing command line arguments of program. + + :return: If it processed wrong or no arguments, it prints error message and exits with error code 10. + + If it processed argument -h, it calls function usage() and exit. + + If it processed both mandatory arguments: -r and -f with specified path to file with rules and + path to file with format of rules, then it initializes instance variables. + """ + argv = sys.argv[1:] + + rules_path = None + format_path = None + output_path = None + is_stderr_on = False + + try: + opts, args = getopt.getopt(argv, "r:f:o:lh", ["rules=", "format=", "output=", "logs", "help"]) + except getopt.GetoptError as err: + ErrorProcess.process_error(Error.ARGUMENTS_ERROR, f'{err}') + + if len(opts) < 1 or len(opts) > 4 or len(args) > 0: + ErrorProcess.process_error(Error.ARGUMENTS_ERROR, f'Wrong or no arguments selected.') + + for o, a in opts: + if o in ("-h", "--help"): + ProcessedArguments.print_manual() + sys.exit() + elif o in ("-r", "--rules"): + rules_path = a + elif o in ("-f", "--format"): + format_path = a + elif o in ("-o", "--output"): + output_path = a + elif o in ("-l", "--logs"): + is_stderr_on = True + + if rules_path is None or format_path is None: + ErrorProcess.process_error(Error.ARGUMENTS_ERROR, f'Missing argument -r or -f.') + else: + self.rules_path = rules_path + self.format_path = format_path + self.output_path = output_path + self.is_stderr_on = is_stderr_on + + @staticmethod + def print_manual(): + """ + Function prints manual of program. + """ + print('1.PROGRAM:\n\ttuples_analyzer\n\n' + '2.FUNCTION:\n\tProgram creates parameter file from statistics and distributions of real filter set.\n\t' + 'File with format of rules is needed for processing filter rules.\n\t' + 'Computed parameters are then used to generate synthetic filter set by tools ClassBench and ' + 'ClassBench-ng. \n\tFormat of rules and examples usages of program are described in README file.\n\n' + '3.USAGE:\n\tpython3 -m tuples_analyzer -r -f [-o -l -h]' + '\n\n' + '4.MANDATORY ARGUMENTS:\n' + '\t-r rules_file | --rules=rules_file\t\tspecify path to file with filter rules\n' + '\t-f format_file | --format=format_file\t\tspecify path to file with format of rules\n\n' + '5.OPTIONAL ARGUMENTS:\n' + '\t-o output_file | --output=output_file\t\tspecify path to file, which will be created\n' + '\t\t\t\t\t\t\tto store computed parameters\n\n' + '\t-l | --logs\t\t\t\t\tprinting error logs during computation is enabled\n' + '\t-h | --help\t\t\t\t\tdisplay this manual\n' + '\n6.AUTHOR:\n\tJozef Sabo') diff --git a/lib/tuples_analyzer/processing_errors/__init__.py b/lib/tuples_analyzer/processing_errors/__init__.py new file mode 100644 index 0000000..d1b98d4 --- /dev/null +++ b/lib/tuples_analyzer/processing_errors/__init__.py @@ -0,0 +1 @@ +"""Package with classes to correctly end program while error occurred and for printing error logs to stderr.""" diff --git a/lib/tuples_analyzer/processing_errors/enums/Error.py b/lib/tuples_analyzer/processing_errors/enums/Error.py new file mode 100644 index 0000000..6610337 --- /dev/null +++ b/lib/tuples_analyzer/processing_errors/enums/Error.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +"""Module containing definition of enum class Error.""" + +from enum import Enum + + +class Error(Enum): + """ + Enum for every possible error, which can occur in program. + """ + + ARGUMENTS_ERROR = 10 + """Error which occurred while processing command line arguments.""" + FILE_OPENING_ERROR = 20 + """Error which occurred while opening file.""" + RULE_FORMAT_ERROR = 30 + """Error which occurred while processing file with format of rules.""" + CREATING_FILE_ERROR = 40 + """Error which occurred while creating file for storing output parameters.""" + NO_VALUE_FILTER_SET_ERROR = 50 + """Error telling that file with filter rules has no valuable content in it.""" diff --git a/lib/tuples_analyzer/processing_errors/enums/__init__.py b/lib/tuples_analyzer/processing_errors/enums/__init__.py new file mode 100644 index 0000000..cf8e378 --- /dev/null +++ b/lib/tuples_analyzer/processing_errors/enums/__init__.py @@ -0,0 +1 @@ +"""Package with enum classes used while processing errors.""" diff --git a/lib/tuples_analyzer/processing_errors/error_process.py b/lib/tuples_analyzer/processing_errors/error_process.py new file mode 100644 index 0000000..bc654bf --- /dev/null +++ b/lib/tuples_analyzer/processing_errors/error_process.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +"""Module containing definition of class ErrorProcess.""" + +import sys +from .enums.Error import Error + + +class ErrorProcess: + """ + Class used for correctly ending program while different type of error occurred. + Class also used for printing error logs to stderr. + """ + + @staticmethod + def print_warning(message): + """ + Function prints warning log message to stderr. + + :param message: Message which will be printed to stderr. + """ + sys.stderr.write(f'{sys.argv[0]}:\nWARNING: {message}\n\n') + + @staticmethod + def process_error(error, message=''): + """ + Function prints error message and exits program with value of parameter error. + + :param error: Enum value representing error which occurred. + + :param message: Message which will be printed to stderr. + """ + if error == Error.ARGUMENTS_ERROR: + sys.stderr.write(f'{sys.argv[0]}:\nERROR: {message}\nTry \'python3 -m filter_rule_analyzer --help\'.\n') + + elif error == Error.FILE_OPENING_ERROR: + sys.stderr.write(f'{sys.argv[0]}:\nERROR: Error while opening file with path: \'{message}\'.\n') + + elif error == Error.RULE_FORMAT_ERROR: + sys.stderr.write(f'{sys.argv[0]}:\nERROR: Error while processing file with format: \'{message}\'.\n') + + elif error == Error.CREATING_FILE_ERROR: + sys.stderr.write(f'{sys.argv[0]}:\nERROR: {message}\n') + + elif error == Error.NO_VALUE_FILTER_SET_ERROR: + sys.stderr.write(f'{sys.argv[0]}:\nERROR: File with filter rules is empty or has not valuable content.\n') + + exit(error.value) diff --git a/lib/tuples_analyzer/processing_files/__init__.py b/lib/tuples_analyzer/processing_files/__init__.py new file mode 100644 index 0000000..2a703be --- /dev/null +++ b/lib/tuples_analyzer/processing_files/__init__.py @@ -0,0 +1 @@ +"""Package with classes for processing data from files.""" diff --git a/lib/tuples_analyzer/processing_files/processing_file_helper.py b/lib/tuples_analyzer/processing_files/processing_file_helper.py new file mode 100644 index 0000000..993b09b --- /dev/null +++ b/lib/tuples_analyzer/processing_files/processing_file_helper.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +"""Module containing definition of class ProcessingFileHelper.""" + +from ..processing_errors.enums.Error import Error +from ..processing_errors.error_process import ErrorProcess + + +class ProcessingFileHelper: + """ + Class contains only static functions to help with processing of files. + """ + + @staticmethod + def create_lines_generator(file_path): + """ + Function creates generator of lines from file. + + :param file_path: Path to file. + + :return: Generator of lines in file. + If function can not open file, it prints error message and exits with error code 20. + """ + try: + with open(file_path, 'r') as file: + for line in file: + yield line.strip() + except EnvironmentError: + ErrorProcess.process_error(Error.FILE_OPENING_ERROR, file_path) + + @staticmethod + def get_format(file_path): + """ + Function processes file with format of rules and returns format from first line of file. + + :param file_path: Path to file with format of rule. + + :return: First line of file. + If line is empty, it prints error message and exits with error code 30. + """ + rule_format = '' + + for line in ProcessingFileHelper.create_lines_generator(file_path): + rule_format = line + break + + if not rule_format or rule_format.isspace(): + ErrorProcess.process_error(Error.RULE_FORMAT_ERROR, file_path) + else: + return rule_format diff --git a/lib/tuples_analyzer/processing_rules/__init__.py b/lib/tuples_analyzer/processing_rules/__init__.py new file mode 100644 index 0000000..69d6693 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/__init__.py @@ -0,0 +1 @@ +"""Package with classes for processing filter rules from filter set file into generator of FilterRule instances.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/__init__.py b/lib/tuples_analyzer/processing_rules/enums/__init__.py new file mode 100644 index 0000000..8bdc644 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/__init__.py @@ -0,0 +1 @@ +"""Package with enum classes used while processing filter rules into generator of FilterRule instances.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_location.py b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_location.py new file mode 100644 index 0000000..ad48e64 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_location.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +"""Module containing definition of enum class FilterRulePartLocation.""" + +from enum import Enum + + +class FilterRulePartLocation(Enum): + """ + Enum for every possible 'location' of these filter rule parameters: port and ip address. + """ + + SOURCE = 0 + """Source location of filter rule parameter.""" + DESTINATION = 1 + """Destination location of filter rule parameter.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_processing_result.py b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_processing_result.py new file mode 100644 index 0000000..f52ac94 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_processing_result.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"""Module containing definition of enum class FilterRulePartProcessingResult.""" + +from enum import Enum + + +class FilterRulePartProcessingResult(Enum): + """ + Enum for every possible result scenario while processing filter rule part into FilterRule instance. + """ + + MANDATORY_PART_PROCESSED = 0 + """Mandatory part of filter rule was processed.""" + OPTIONAL_PART_PROCESSED = 1 + """Optional part of filter rule was processed.""" + MANDATORY_PART_MISSING = 2 + """Mandatory part of filter rule is missing.""" + OPTIONAL_PART_MISSING = 3 + """Optional part of filter rule is missing.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py new file mode 100644 index 0000000..229f7d9 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +"""Module containing definition of enum class FilterRulePartType.""" + +from enum import Enum + + +class FilterRulePartType(Enum): + """ + Enum for every possible type of filter rule part. One word of filter rule is considered as filter part. + """ + + ANY = 0 + """Representation of wildcard value.""" + PROTOCOL = 1 + """Network protocol abbreviation.""" + IP_ADDRESS = 2 + """IP address without mask.""" + IP_ADDRESS_MASK = 3 + """IP address with mask.""" + PORT = 4 + """Port value.""" + PORT_RANGE = 5 + """Port range value.""" + NUMBER = 6 + """Number bigger than 65535 (not used for computation parameters e.g. precedence number).""" + KEYWORD = 7 + """Word which is part of rule format definition e.g. from, to.""" + WORD = 8 + """Every other value.""" + diff --git a/lib/tuples_analyzer/processing_rules/enums/ordered_enum.py b/lib/tuples_analyzer/processing_rules/enums/ordered_enum.py new file mode 100644 index 0000000..c486b90 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/ordered_enum.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +"""Module containing definition of enum class OrderedEnum.""" + +from enum import Enum + + +class OrderedEnum(Enum): + """ + Class inheriting from base enum class and making enum values comparable. + """ + + def __ge__(self, other): + if self.__class__ is other.__class__: + return self.value >= other.value + + def __gt__(self, other): + if self.__class__ is other.__class__: + return self.value > other.value + + def __le__(self, other): + if self.__class__ is other.__class__: + return self.value <= other.value + + def __lt__(self, other): + if self.__class__ is other.__class__: + return self.value < other.value diff --git a/lib/tuples_analyzer/processing_rules/enums/port_class.py b/lib/tuples_analyzer/processing_rules/enums/port_class.py new file mode 100644 index 0000000..a5ff3bb --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/port_class.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +"""Module containing definition of enum class PC.""" + +from enum import Enum + + +class PC(Enum): + """ + Enum for every possible port class (PC). + """ + + WC = 0 + """Wildcard.""" + LO = 1 + """Port range 0:1023.""" + HI = 2 + """Port range 1024:65535.""" + EM = 3 + """Exact match e.g port 80.""" + AR = 4 + """Arbitrary range e.g. port range 50000:51000.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/port_pair_class.py b/lib/tuples_analyzer/processing_rules/enums/port_pair_class.py new file mode 100644 index 0000000..eb315c5 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/port_pair_class.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +"""Module containing definition of enum class PPC.""" + +from enum import Enum + + +class PPC(Enum): + """ + Enum for every possible port pair class (PPC). + PPC is pair consisting of source and destination port classes. + There are 25 total PPC for every combination of source and destination port classes. + """ + + WC_WC = 0 + """Source port class is WC and destination port class is WC.""" + WC_HI = 1 + """Source port class is WC and destination port class is HI.""" + HI_WC = 2 + """Source port class is HI and destination port class is WC.""" + HI_HI = 3 + """Source port class is HI and destination port class is HI.""" + WC_LO = 4 + """Source port class is WC and destination port class is LO.""" + LO_WC = 5 + """Source port class is LO and destination port class is WC.""" + HI_LO = 6 + """Source port class is HI and destination port class is LO.""" + LO_HI = 7 + """Source port class is LO and destination port class is HI.""" + LO_LO = 8 + """Source port class is LO and destination port class is LO.""" + WC_AR = 9 + """Source port class is WC and destination port class is AR.""" + AR_WC = 10 + """Source port class is AR and destination port class is WC.""" + HI_AR = 11 + """Source port class is HI and destination port class is AR.""" + AR_HI = 12 + """Source port class is AR and destination port class is HI.""" + WC_EM = 13 + """Source port class is WC and destination port class is EM.""" + EM_WC = 14 + """Source port class is EM and destination port class is WC.""" + HI_EM = 15 + """Source port class is HI and destination port class is EM.""" + EM_HI = 16 + """Source port class is EM and destination port class is HI.""" + LO_AR = 17 + """Source port class is LO and destination port class is AR.""" + AR_LO = 18 + """Source port class is AR and destination port class is LO.""" + LO_EM = 19 + """Source port class is LO and destination port class is EM.""" + EM_LO = 20 + """Source port class is EM and destination port class is LO.""" + AR_AR = 21 + """Source port class is AR and destination port class is AR.""" + AR_EM = 22 + """Source port class is AR and destination port class is EM.""" + EM_AR = 23 + """Source port class is EM and destination port class is AR.""" + EM_EM = 24 + """Source port class is EM and destination port class is EM.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/protocol_numbers.py b/lib/tuples_analyzer/processing_rules/enums/protocol_numbers.py new file mode 100644 index 0000000..d52a92f --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/protocol_numbers.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +"""Module containing definition of enum class Protocol.""" + +from .ordered_enum import OrderedEnum + + +class Protocol(OrderedEnum): + """ + Enum for every protocol located in ClassBench example parameter files. + Enum values are given by protocol number definition by IANA. + """ + + ANY = 0 + """Wildcard protocol.""" + ICMP = 1 + """Internet Control Message.""" + IGMP = 2 + """Internet Group Management.""" + GGP = 3 + """Gateway-to-Gateway.""" + ST = 5 + """Stream.""" + TCP = 6 + """Transmission Control.""" + EGP = 8 + """Exterior Gateway Protocol.""" + UDP = 17 + """User Datagram.""" + GRE = 47 + """Generic Routing Encapsulation.""" + ESP = 50 + """Encap Security Payload.""" + AH = 51 + """Authentication Header.""" + EIGRP = 88 + """EIGRP.""" + OSPFIGP = 89 + """OSPFIGP.""" diff --git a/lib/tuples_analyzer/processing_rules/filter_rule.py b/lib/tuples_analyzer/processing_rules/filter_rule.py new file mode 100644 index 0000000..a4aec2e --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/filter_rule.py @@ -0,0 +1,242 @@ +#!/usr/bin/env python +"""Module containing definition of class FilterRule.""" + +from .enums.filter_rule_part_location import FilterRulePartLocation +from .enums.port_class import PC +from .enums.port_pair_class import PPC +from .enums.protocol_numbers import Protocol +import ipaddress + + +class FilterRule: + """ + Class representing filter rule. + """ + + def __init__(self): + """ + Constructor initialize all filter rule attributes with wildcard values. + """ + self.protocol = Protocol.ANY + """Protocol number defined by IANA.""" + self.src_port_class = PC.WC + """Source port class.""" + self.src_port = None + """Source port value.""" + self.dst_port_class = PC.WC + """Destination port class.""" + self.dst_port = None + """Destination port value.""" + self.src_ip_add_bin = '*' + """Source IP address in binary form.""" + self.src_ip_add_prefix_length = 0 + """Source IP address prefix length.""" + self.dst_ip_add_bin = '*' + """Destination IP address in binary form.""" + self.dst_ip_add_prefix_length = 0 + """Destination IP address prefix length.""" + + def get_ppc_class(self): + """ + Function returns enum value representing port pair class (PPC) of this filter rule. + + :return: Enum value representing PPC of this filter rule. + """ + if self.src_port_class == PC.WC and self.dst_port_class == PC.WC: + return PPC.WC_WC + + elif self.src_port_class == PC.WC and self.dst_port_class == PC.HI: + return PPC.WC_HI + + elif self.src_port_class == PC.HI and self.dst_port_class == PC.WC: + return PPC.HI_WC + + elif self.src_port_class == PC.HI and self.dst_port_class == PC.HI: + return PPC.HI_HI + + elif self.src_port_class == PC.WC and self.dst_port_class == PC.LO: + return PPC.WC_LO + + elif self.src_port_class == PC.LO and self.dst_port_class == PC.WC: + return PPC.LO_WC + + elif self.src_port_class == PC.HI and self.dst_port_class == PC.LO: + return PPC.HI_LO + + elif self.src_port_class == PC.LO and self.dst_port_class == PC.HI: + return PPC.LO_HI + + elif self.src_port_class == PC.LO and self.dst_port_class == PC.LO: + return PPC.LO_LO + + elif self.src_port_class == PC.WC and self.dst_port_class == PC.AR: + return PPC.WC_AR + + elif self.src_port_class == PC.AR and self.dst_port_class == PC.WC: + return PPC.AR_WC + + elif self.src_port_class == PC.HI and self.dst_port_class == PC.AR: + return PPC.HI_AR + + elif self.src_port_class == PC.AR and self.dst_port_class == PC.HI: + return PPC.AR_HI + + elif self.src_port_class == PC.WC and self.dst_port_class == PC.EM: + return PPC.WC_EM + + elif self.src_port_class == PC.EM and self.dst_port_class == PC.WC: + return PPC.EM_WC + + elif self.src_port_class == PC.HI and self.dst_port_class == PC.EM: + return PPC.HI_EM + + elif self.src_port_class == PC.EM and self.dst_port_class == PC.HI: + return PPC.EM_HI + + elif self.src_port_class == PC.LO and self.dst_port_class == PC.AR: + return PPC.LO_AR + + elif self.src_port_class == PC.AR and self.dst_port_class == PC.LO: + return PPC.AR_LO + + elif self.src_port_class == PC.LO and self.dst_port_class == PC.EM: + return PPC.LO_EM + + elif self.src_port_class == PC.EM and self.dst_port_class == PC.LO: + return PPC.EM_LO + + elif self.src_port_class == PC.AR and self.dst_port_class == PC.AR: + return PPC.AR_AR + + elif self.src_port_class == PC.AR and self.dst_port_class == PC.EM: + return PPC.AR_EM + + elif self.src_port_class == PC.EM and self.dst_port_class == PC.AR: + return PPC.EM_AR + + elif self.src_port_class == PC.EM and self.dst_port_class == PC.EM: + return PPC.EM_EM + + def set_protocol_number(self, protocol): + """ + Function takes network protocol abbreviation as parameter and sets instance variable protocol_number as + enum value of that protocol. + + :param protocol: Network protocol abbreviation. + """ + if protocol == 'any': + self.protocol = Protocol.ANY + + elif protocol == 'tcp': + self.protocol = Protocol.TCP + + elif protocol == 'udp': + self.protocol = Protocol.UDP + + elif protocol == 'icmp': + self.protocol = Protocol.ICMP + + elif protocol == 'igmp': + self.protocol = Protocol.IGMP + + elif protocol == 'ggp': + self.protocol = Protocol.GGP + + elif protocol == 'st': + self.protocol = Protocol.ST + + elif protocol == 'egp': + self.protocol = Protocol.EGP + + elif protocol == 'gre': + self.protocol = Protocol.GRE + + elif protocol == 'esp': + self.protocol = Protocol.ESP + + elif protocol == 'ah': + self.protocol = Protocol.AH + + elif protocol == 'eigrp': + self.protocol = Protocol.EIGRP + + elif protocol == 'ospfigp': + self.protocol = Protocol.OSPFIGP + + def set_port(self, port, location): + """ + Function takes port value as parameter and sets instance variables source or destination port and port_class + with parameter value and port class of parameter. + + :param port: Port or port range value. + + :param location: Location of port or port range value (source/destination). + """ + if location == FilterRulePartLocation.SOURCE: + if port == 'any': + self.src_port_class = PC.WC + elif port == '0:1023': + self.src_port = port + self.src_port_class = PC.LO + elif port == '1024:65535': + self.src_port = port + self.src_port_class = PC.HI + elif len(port.split(':')) == 2: + self.src_port = port + self.src_port_class = PC.AR + else: + self.src_port = port + ':' + port + self.src_port_class = PC.EM + + elif location == FilterRulePartLocation.DESTINATION: + if port == 'any': + self.dst_port_class = PC.WC + elif port == '0:1023': + self.dst_port = port + self.dst_port_class = PC.LO + elif port == '1024:65535': + self.dst_port = port + self.dst_port_class = PC.HI + elif len(port.split(':')) == 2: + self.dst_port = port + self.dst_port_class = PC.AR + else: + self.dst_port = port + ':' + port + self.dst_port_class = PC.EM + + def set_ip_add(self, ip_address, location): + """ + Function takes parameter ip address in decimal form and sets instance variable source or destination ip_add_bin + as binary form of that ip address. It also sets instance variable source or destination ip_add_prefix_length + with ip address prefix length. + + :param ip_address: Ip address with prefix length in decimal form. + + :param location: Location of ip address (source/destination). + """ + if location == FilterRulePartLocation.SOURCE: + if ip_address == 'any': + self.src_ip_add_bin = '*' + self.src_ip_add_prefix_length = 0 + else: + ip_address = ip_address.split('/') + bin_ip_address = bin(int(ipaddress.IPv4Address(ip_address[0]))) + bin_ip_address = bin_ip_address[2:].zfill(32) + prefix_length = int(ip_address[1]) + binary_ip_address_cut = bin_ip_address[:prefix_length] + self.src_ip_add_bin = binary_ip_address_cut + self.src_ip_add_prefix_length = prefix_length + + elif location == FilterRulePartLocation.DESTINATION: + if ip_address == 'any': + self.dst_ip_add_bin = '*' + self.dst_ip_add_prefix_length = 0 + else: + ip_address = ip_address.split('/') + bin_ip_address = bin(int(ipaddress.IPv4Address(ip_address[0]))) + bin_ip_address = bin_ip_address[2:].zfill(32) + prefix_length = int(ip_address[1]) + binary_ip_address_cut = bin_ip_address[:prefix_length] + self.dst_ip_add_bin = binary_ip_address_cut + self.dst_ip_add_prefix_length = prefix_length + diff --git a/lib/tuples_analyzer/processing_rules/filter_rule_generator.py b/lib/tuples_analyzer/processing_rules/filter_rule_generator.py new file mode 100644 index 0000000..ab6b7e5 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/filter_rule_generator.py @@ -0,0 +1,413 @@ +#!/usr/bin/env python +"""Module containing definition of class FilterRuleGenerator.""" + +from ..processing_errors.enums.Error import Error +from ..processing_errors.error_process import ErrorProcess +from .enums.filter_rule_part_location import FilterRulePartLocation +from .enums.filter_rule_part_processing_result import FilterRulePartProcessingResult +from .enums.filter_rule_part_type import FilterRulePartType +from .filter_rule import FilterRule +from .supported_values import * +import ipaddress + + +class FilterRuleGenerator: + """ + Class containing only static functions for creating generator of FilterRule instances from filter set file and + specified rule format. + """ + + @staticmethod + def create_generator(lines_generator, rule_format, is_stderr_on): + """ + Function creates FilterRule class instances generator from all filter rules in filter set file. + Format of rules is needed for processing rules into instances. + + :param lines_generator: Generator of lines from file with filter rules. + + :param rule_format: String with rule format. + + :param is_stderr_on: If variable is true, printing error logs to stderr during parsing is enabled. + + :return: Generator of FilterRule instances. + """ + format_words = FilterRuleGenerator.split_line(rule_format) + format_length = len(format_words) + mandatory_words_count = FilterRuleGenerator.how_many_mandatory(format_words) + successful_yields = 0 + + # going through all lines + for line in lines_generator: + + # empty line check + if not line: + continue + + rule_parts = FilterRuleGenerator.split_line(line) + filter_rule = FilterRule() + + format_position = 0 + mandatory_processed = 0 + successful_assigment = 0 + + missing_mandatory = False + standalone_question_mark = False + + # going through all parts of line + for part in rule_parts: + + if part == '?': + standalone_question_mark = True + break + + # going through format parameters and keywords + while format_position != format_length: + + expected_part_type = format_words[format_position] + result = FilterRuleGenerator.part_processing(expected_part_type, part, filter_rule, format_words) + + if result == FilterRulePartProcessingResult.MANDATORY_PART_PROCESSED: + mandatory_processed += 1 + + if expected_part_type in format_parameters: + successful_assigment += 1 + + format_position += 1 + break + + elif result == FilterRulePartProcessingResult.MANDATORY_PART_MISSING: + missing_mandatory = True + break + + elif result == FilterRulePartProcessingResult.OPTIONAL_PART_PROCESSED: + + if expected_part_type[:-1] in format_parameters: + successful_assigment += 1 + + format_position += 1 + break + + elif result == FilterRulePartProcessingResult.OPTIONAL_PART_MISSING: + format_position += 1 + + # if condition is true, stop iterating through parts of filter rule + if format_position == format_length or missing_mandatory: + break + + # processing errors or yielding instance of FilterRule class + if (missing_mandatory or mandatory_processed != mandatory_words_count or successful_assigment == 0 + or standalone_question_mark) and not is_stderr_on: + pass + + elif missing_mandatory: + ErrorProcess.print_warning(f'Mandatory part: \'{expected_part_type}\' was expected ' + f'instead of: \'{str(FilterRuleGenerator.get_type(part, format_words).name)}' + f': {part}\', following rule is ignored: \'{line}\'.') + + elif mandatory_processed != mandatory_words_count: + ErrorProcess.print_warning(f'Not all mandatory parts of rule have been processed, ' + f'following rule is ignored: \'{line}\'.') + + elif successful_assigment == 0: + ErrorProcess.print_warning(f'Rule has not valuable content, ' + f'following rule is ignored: \'{line}\'.') + + elif standalone_question_mark: + ErrorProcess.print_warning(f'Character \'?\' can not be standalone part of rule, ' + f'following rule is ignored: \'{line}\'.') + + else: + successful_yields += 1 + yield filter_rule + + if successful_yields == 0: + ErrorProcess.process_error(Error.NO_VALUE_FILTER_SET_ERROR) + + @staticmethod + def part_processing(expected_part_type, part, filter_rule, format_words): + """ + If expected part (from format) matches with real part (from filter rule line), function sets one of attributes + in FilterRule instance to value of part and returns enum telling that mandatory or optional part was + processed. If mandatory or optional part is missing, function returns corresponding enum. + + :param expected_part_type: Parameter or keyword from rule format file. + + :param part: Part from filter rule line. + + :param filter_rule: Instance of FilterRule class. + + :param format_words: List with all format words. + + :return: Result type of processing filter rule part. + """ + part_type = FilterRuleGenerator.get_type(part, format_words) + + if part_type == FilterRulePartType.ANY: + part = "any" + + if part_type == FilterRulePartType.IP_ADDRESS: + part += '/32' + + if ((expected_part_type == "PROTOCOL" or expected_part_type == "PROTOCOL?") and + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.PROTOCOL)): + + filter_rule.set_protocol_number(part) + + elif ((expected_part_type == "PROTOCOL" or expected_part_type == "PROTOCOL?") and + (part.isdigit() and int(part) in [e.value for e in Protocol])): + + filter_rule.set_protocol_number(Protocol(int(part)).name.lower()) + + elif ((expected_part_type == "SRC_PORT" or expected_part_type == "SRC_PORT?") and + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.PORT or + part_type == FilterRulePartType.PORT_RANGE)): + + filter_rule.set_port(part, FilterRulePartLocation.SOURCE) + + elif ((expected_part_type == "DST_PORT" or expected_part_type == "DST_PORT?") and + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.PORT or + part_type == FilterRulePartType.PORT_RANGE)): + + filter_rule.set_port(part, FilterRulePartLocation.DESTINATION) + + elif ((expected_part_type == "SRC_IP" or expected_part_type == "SRC_IP?") and + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.IP_ADDRESS_MASK + or part_type == FilterRulePartType.IP_ADDRESS)): + + filter_rule.set_ip_add(part, FilterRulePartLocation.SOURCE) + + elif ((expected_part_type == "DST_IP" or expected_part_type == "DST_IP?") and + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.IP_ADDRESS_MASK + or part_type == FilterRulePartType.IP_ADDRESS)): + + filter_rule.set_ip_add(part, FilterRulePartLocation.DESTINATION) + + elif ((expected_part_type == "NUMBER" or expected_part_type == "NUMBER?") and + (part_type == FilterRulePartType.NUMBER or part_type == FilterRulePartType.PORT)): + pass + + elif ((expected_part_type == "WILDCARD" or expected_part_type == "WILDCARD?") and + (part_type == FilterRulePartType.WORD)): + pass + + elif ((expected_part_type == part or expected_part_type == part + '?') and + part_type == FilterRulePartType.KEYWORD): + pass + + elif FilterRuleGenerator.is_word_mandatory(expected_part_type): + return FilterRulePartProcessingResult.MANDATORY_PART_MISSING + + else: + return FilterRulePartProcessingResult.OPTIONAL_PART_MISSING + + if FilterRuleGenerator.is_word_mandatory(expected_part_type): + return FilterRulePartProcessingResult.MANDATORY_PART_PROCESSED + + else: + return FilterRulePartProcessingResult.OPTIONAL_PART_PROCESSED + + @staticmethod + def how_many_mandatory(rule_format): + """ + Function counts how many words are mandatory in rule format definition. + + :param rule_format: String with rule format. + + :return: Count of mandatory words in format. + """ + count = 0 + for part in rule_format: + if FilterRuleGenerator.is_word_mandatory(part): + count = count + 1 + return count + + @staticmethod + def is_word_mandatory(word): + """ + Every parameter or keyword in format is holding information, if part in filter rule is mandatory or optional. + Part is optional, if its definition in format ends with character '?', otherwise part is mandatory. + + :param word: Parameter or keyword from format. + + :return: Function returns true, if parameter word ends with '?'. + """ + string_length = len(word) + + if word[string_length - 1] != '?': + return True + else: + return False + + @staticmethod + def get_type(part, format_words): + """ + Function determines type of part of filter rule. Decision is made by acceptable format of part. + E.g. function knows it is a port, if part of rule is number between 0-65535. + + :param part: String with filter rule part. + + :param format_words: List with all format words. + + :return: Type of filter rule part. + """ + if FilterRuleGenerator.is_wildcard(part): + return FilterRulePartType.ANY + + elif FilterRuleGenerator.is_protocol(part): + return FilterRulePartType.PROTOCOL + + elif FilterRuleGenerator.is_ip_address(part): + return FilterRulePartType.IP_ADDRESS + + elif FilterRuleGenerator.is_ip_address_with_mask(part): + return FilterRulePartType.IP_ADDRESS_MASK + + elif FilterRuleGenerator.is_port(part): + return FilterRulePartType.PORT + + elif part.isdigit(): + return FilterRulePartType.NUMBER + + elif FilterRuleGenerator.is_port_range(part): + return FilterRulePartType.PORT_RANGE + + elif FilterRuleGenerator.is_keyword(part, format_words): + return FilterRulePartType.KEYWORD + + else: + return FilterRulePartType.WORD + + @staticmethod + def is_wildcard(value): + """ + Function returns true, if parameter value is wildcard. + + :param value: String with possible wildcard. + + :return: True, if parameter is representation of wildcard, otherwise false. + """ + + if not isinstance(value, str): + return False + + value = value.lower() + + if value in supported_wildcard_list: + return True + else: + return False + + @staticmethod + def is_protocol(protocol): + """ + Function returns true, if parameter is network protocol abbreviation (TCP, UDP, ip, ...). + + :param protocol: String with possible network protocol abbreviation. + + :return: True, if parameter is network protocol abbreviation, otherwise false. + """ + if not isinstance(protocol, str): + return False + + case_insensitive_protocol = protocol.lower() + + if case_insensitive_protocol in supported_protocols: + return True + else: + return False + + @staticmethod + def is_port(port): + """ + Function finds out, if parameter is port (number between 0-65535). + + :param port: String with possible port. + + :return: Function returns true, if parameter of function is port. + """ + if port.isdigit() and 0 <= int(port) < 65536: + return True + else: + return False + + @staticmethod + def is_port_range(port_range): + """ + Function finds out, if parameter is port range (two ports with ':'as delimiter). + + :param port_range: String with possible port range. + + :return: Function returns true, if parameter of function is port range. + """ + port_range = port_range.split(':') + + if (len(port_range) == 2 and + FilterRuleGenerator.is_port(port_range[0]) and + FilterRuleGenerator.is_port(port_range[1]) and + int(port_range[0]) < int(port_range[1])): + return True + else: + return False + + @staticmethod + def is_keyword(keyword, format_words): + """ + Function finds out, if parameter keyword is part of rule format definition. + + :param keyword: String with possible keyword. + + :param format_words: List with all format words. + + :return: True, if parameter of function is keyword in format. + """ + if keyword in format_words or keyword + '?' in format_words: + return True + else: + return False + + @staticmethod + def is_ip_address(ip_address): + """ + Function returns true, if parameter of function is IP address in decimal form without mask (prefix length). + + :param ip_address: String with possible IP address in decimal form. + + :return: True, if parameter of function is IP address. + """ + try: + ipaddress.IPv4Address(ip_address) + except ipaddress.AddressValueError: + return False + + return True + + @staticmethod + def is_ip_address_with_mask(ip_address): + """ + Function returns true, if parameter of function is IP address in decimal form with mask (prefix length). + + :param ip_address: String with possible IP address with mask in decimal form. + + :return: True, if parameter of function is IP address with mask. + """ + possible_address = ip_address.split('/') + + if len(possible_address) != 2 or not possible_address[1].isdigit() or int(possible_address[1]) < 0 or int( + possible_address[1]) > 32 or not FilterRuleGenerator.is_ip_address(possible_address[0]): + return False + + return True + + @staticmethod + def split_line(line): + """ + Function firstly replaces line characters ',' and '=' with empty space. Then split the line by whitespace + into parts and returns list with splitted parts from line. + + :param line: String which will be splitted to parts. + + :return: List with splitted parts by whitespace from line. + """ + line = line.replace("=", " ") + line = line.replace(",", " ") + return line.split() diff --git a/lib/tuples_analyzer/processing_rules/supported_values.py b/lib/tuples_analyzer/processing_rules/supported_values.py new file mode 100644 index 0000000..b49fc12 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/supported_values.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python +"""Module containing global lists of supported protocols, wildcard representations and valuable format parameters.""" +from .enums.protocol_numbers import Protocol + +supported_protocols = [str(e.name).lower() for e in Protocol] +format_parameters = ["PROTOCOL", "SRC_IP", "SRC_PORT", "DST_IP", "DST_PORT"] +supported_wildcard_list = ["any", "all", "*", "ip", "0"] + diff --git a/lib/tuples_analyzer/value_formats/__init__.py b/lib/tuples_analyzer/value_formats/__init__.py new file mode 100644 index 0000000..aa33cb3 --- /dev/null +++ b/lib/tuples_analyzer/value_formats/__init__.py @@ -0,0 +1 @@ +"""Package with classes for formatting different types of values to specified form.""" diff --git a/lib/tuples_analyzer/value_formats/value_format.py b/lib/tuples_analyzer/value_formats/value_format.py new file mode 100644 index 0000000..ef636f0 --- /dev/null +++ b/lib/tuples_analyzer/value_formats/value_format.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"""Module containing definition of class Format.""" + + +class Format: + """ + Class contains functions for formatting different types of values to specified form. + """ + + @staticmethod + def decimal(decimal_value): + """ + Function formats decimal value to form with 8 decimal numbers. + + :param decimal_value: Decimal value. + + :return: Decimal value with 8 decimal numbers. + """ + return format(decimal_value, '.8f') From c00c4edd0a07f8fef842937297c13ee712de658e Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 12 Sep 2019 18:18:48 +0200 Subject: [PATCH 36/51] Rule class [BUGFIX]: set wildcard prefix length to 0 instead of 32. --- lib/classbench/rule.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/classbench/rule.rb b/lib/classbench/rule.rb index 6a90997..41aa04c 100644 --- a/lib/classbench/rule.rb +++ b/lib/classbench/rule.rb @@ -32,11 +32,11 @@ def self.from_classbench_format(line) end def src_length - IPAddress.parse(attributes["nw_src"] || '0.0.0.0').prefix.to_i + IPAddress.parse(attributes["nw_src"] || '0.0.0.0/0').prefix.to_i end def dst_length - IPAddress.parse(attributes["nw_dst"] || '0.0.0.0').prefix.to_i + IPAddress.parse(attributes["nw_dst"] || '0.0.0.0/0').prefix.to_i end def remove_missing_attributes(attrs) From 9f86e7c80b1eb91643915f77d2095336e67ba8ec Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 12 Sep 2019 18:22:14 +0200 Subject: [PATCH 37/51] Analyser class [BUGFIX]: correct computation of a prefix pair length distribution. Both ClassBench and ClassBench-ng represent prefix pair lengths using a total prefix length and a source prefix length. --- lib/classbench/analyser.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/classbench/analyser.rb b/lib/classbench/analyser.rb index 8b2ffcf..ae4a90c 100644 --- a/lib/classbench/analyser.rb +++ b/lib/classbench/analyser.rb @@ -188,7 +188,7 @@ def calculate_stats lengths_of_class = port_class_prefix_lengths[r.port_class_name] specific_length = lengths_of_class[r.src_length + r.dst_length] ||= {} - specific_length[r.dst_length] = (specific_length[r.dst_length] || 0) + 1 + specific_length[r.src_length] = (specific_length[r.src_length] || 0) + 1 end end From 04b54df5446cbca5e908dd95ac31096310e6435c Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 12 Sep 2019 18:28:04 +0200 Subject: [PATCH 38/51] Analyser class [MAINTENANCE]: compute rule set statistics right after its parsing. This approach is more defensive than relying on a users's call of the 'calculate_stats' method and it is more sensible than calling this method at the beginning of the 'generate_seed' method. --- lib/classbench.rb | 2 -- lib/classbench/analyser.rb | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/classbench.rb b/lib/classbench.rb index bb5e05c..621d216 100644 --- a/lib/classbench.rb +++ b/lib/classbench.rb @@ -36,8 +36,6 @@ def self.analyse(filename) analyser = Analyser.new analyser.parse_openflow(File.read(filename)) - analyser.calculate_stats - puts analyser.generate_seed end diff --git a/lib/classbench/analyser.rb b/lib/classbench/analyser.rb index ae4a90c..df1a01b 100644 --- a/lib/classbench/analyser.rb +++ b/lib/classbench/analyser.rb @@ -34,6 +34,8 @@ def parse_openflow(lines) end self.rules << Rule.new(rule) end + + calculate_stats end def rules_per_port_class(class_name) @@ -41,8 +43,6 @@ def rules_per_port_class(class_name) end def generate_seed - calculate_stats - seed = "" seed += "-scale\n#{rules.size}\n#\n" From 945812fab6d85e06403890f6e2ff724e5767ab15 Mon Sep 17 00:00:00 2001 From: Matousek Jiri Date: Sun, 6 Oct 2019 21:46:34 +0200 Subject: [PATCH 39/51] ClassBench-ng top [FEATURE]: remove the output file parameter of 5-Tuples Analyser. Similarly fo OpenFlow Analyser, an output seed is printed directly to the stdout. --- classbench | 5 ++--- lib/classbench.rb | 16 ++++------------ 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/classbench b/classbench index fe9d2fe..be3844a 100755 --- a/classbench +++ b/classbench @@ -10,7 +10,7 @@ ClassBench-ng Usage: #{__FILE__} analyse of FILE - #{__FILE__} analyse tuples --rules= --format= [--output=] [--logs] + #{__FILE__} analyse tuples --rules= --format= [--logs] #{__FILE__} generate v4 SEED [--count=] [--db-generator=] #{__FILE__} generate v6 SEED [--count=] [--db-generator=] #{__FILE__} generate of SEED [--count=] [--db-generator=] @@ -19,7 +19,6 @@ Usage: Options: --rules= Path to file with filter rules. --format= Path to file with format of rules. - --output= Path to output file. --logs Enable printing error logs during processing of filter rules. --db-generator= Path to an original ClassBench binary. [default: ./vendor/db_generator/db_generator] @@ -62,7 +61,7 @@ begin if opts["of"] Classbench::analyse_of(opts["FILE"]) elsif opts["tuples"] - Classbench::analyse_tuples(opts["--rules"], opts["--format"], opts["--output"], opts["--logs"]) + Classbench::analyse_tuples(opts["--rules"], opts["--format"], opts["--logs"]) end elsif opts["generate"] if opts["v4"] diff --git a/lib/classbench.rb b/lib/classbench.rb index f5bc9e8..b994890 100644 --- a/lib/classbench.rb +++ b/lib/classbench.rb @@ -42,27 +42,19 @@ def self.analyse_of(filename) end - def self.analyse_tuples(rules_filename, format_filename, output_filename, logs_enabled) - if logs_enabled and !output_filename.to_s.empty? - pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename, "-o", output_filename, "-l") - elsif logs_enabled + def self.analyse_tuples(rules_filename, format_filename, logs_enabled) + if logs_enabled pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename, "-l") - elsif !output_filename.to_s.empty? - pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename, "-o", output_filename) else pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename) end ignored, status = Process::waitpid2 pid - + if status.exitstatus == 0 - if output_filename.to_s.empty? - puts stdout.read.strip - end - + puts stdout.read.strip if logs_enabled warnings = stderr.read.strip - if !warnings.to_s.empty? puts warnings end From e01c947c06b88d7abee841f0abf96ad19d298c80 Mon Sep 17 00:00:00 2001 From: Matousek Jiri Date: Sun, 6 Oct 2019 22:05:11 +0200 Subject: [PATCH 40/51] ClassBench-ng top [MAINTENANCE]: simplify parameters of 5-Tuples Analyser. The used format (position-based or short parameters) is simpler and it better follows the format already used by other parts of ClassBench-ng (e.g., OpenFlow Analyser). --- classbench | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/classbench b/classbench index be3844a..e51e315 100755 --- a/classbench +++ b/classbench @@ -10,16 +10,14 @@ ClassBench-ng Usage: #{__FILE__} analyse of FILE - #{__FILE__} analyse tuples --rules= --format= [--logs] + #{__FILE__} analyse tuples FILE FORMAT [-l] #{__FILE__} generate v4 SEED [--count=] [--db-generator=] #{__FILE__} generate v6 SEED [--count=] [--db-generator=] #{__FILE__} generate of SEED [--count=] [--db-generator=] #{__FILE__} -h | --help Options: - --rules= Path to file with filter rules. - --format= Path to file with format of rules. - --logs Enable printing error logs during processing of filter rules. + -l Enable printing analysis error logs. --db-generator= Path to an original ClassBench binary. [default: ./vendor/db_generator/db_generator] --count= The number of rules to be generated. @@ -61,7 +59,7 @@ begin if opts["of"] Classbench::analyse_of(opts["FILE"]) elsif opts["tuples"] - Classbench::analyse_tuples(opts["--rules"], opts["--format"], opts["--logs"]) + Classbench::analyse_tuples(opts["FILE"], opts["FORMAT"], opts["-l"]) end elsif opts["generate"] if opts["v4"] From 767227851209f3d3ed270a4bd90ba85054572a6f Mon Sep 17 00:00:00 2001 From: Matousek Jiri Date: Sun, 6 Oct 2019 22:23:21 +0200 Subject: [PATCH 41/51] ClassBench-ng top [FEATURE]: put stdout and stderr of 5-Tuples Analyser to global stdout and stderr, respectively. Before this commit, everything was put to global stdout only. --- lib/classbench.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/classbench.rb b/lib/classbench.rb index b994890..838950c 100644 --- a/lib/classbench.rb +++ b/lib/classbench.rb @@ -52,15 +52,15 @@ def self.analyse_tuples(rules_filename, format_filename, logs_enabled) ignored, status = Process::waitpid2 pid if status.exitstatus == 0 - puts stdout.read.strip + STDOUT.puts stdout.read.strip if logs_enabled warnings = stderr.read.strip if !warnings.to_s.empty? - puts warnings + STDERR.puts warnings end end else - puts stderr.read.strip + STDERR.puts stderr.read.strip exit(status.exitstatus) end From 6818f27a7f60893e94d31cbbdf24b2cf2bd190d8 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Wed, 23 Oct 2019 18:25:53 +0200 Subject: [PATCH 42/51] ClassBench-ng top [MAINTENANCE]: simplify Analyser's description in the help. A shorter description is expected to be read by more users. --- classbench | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/classbench b/classbench index e51e315..60fa61f 100755 --- a/classbench +++ b/classbench @@ -24,24 +24,12 @@ Options: [default: 100] -h --help Show this screen. -Analyser launched with arguments: "analyse of", accepts as an input an ovs-ofctl dump. -Fields extracted from the dump are: - - in_port, - - dl_src, dl_dst, eth_type, dl_vlan, dl_vlan_pcp, - - nw_src, nw_dst, nw_tos, nw_proto, - - tp_src, tp_dst -The output is an original ClassBench seed with an OpenFlow YAML structure as -the last section. - -Analyser launched with arguments: "analyse tuples", accepts any filter rule sets format but file, -describing format of rules in set, has to be given to analyser as argument. -How to define file with format is described in file lib/tuples_analyzer/README. -In folder lib/tuples_analyzer/examples there are also examples of filter rule sets and -formats belonging to them. -Fields extracted from the rules are parts of standard IP 5-tuple: -(protocol, source IPv4 address, source port or source port range, destination IPv4 address, -destination port or destination port range) -The output is an original ClassBench seed without OpenFlow YAML structure. +Analyser accepts as an input either a rule set in a given format in case of +"analyse tuples" (the expected structure of a format file is described in +lib/tuples_analyzer/README, section 7) or an ovs-ofctl dump in case of +"analyse of". +The output is an original ClassBench seed or this seed with an OpenFlow YAML +structure as the last section, respectively. Generator accepts as an input an original ClassBench seed that has to contain an OpenFlow section in case of "generate of". From 3e06fb455d106d0a8af4e6355ac2473638cd04c0 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Wed, 23 Oct 2019 22:48:50 +0200 Subject: [PATCH 43/51] README [MAINTENANCE]: simplify ClassBench-ng Analyser's description in README. A shorter description is expected to be read by more users. --- README.md | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index cec5243..aef4c71 100644 --- a/README.md +++ b/README.md @@ -40,16 +40,20 @@ Basic characteristics of patches available in `./patches` directory and suggesti ## Usage ClassBench-ng can be used in two different ways: -- To analyse an existing rule set and extract the associated ClassBench-ng SEED. +- To analyse an existing rule set and extract a corresponding SEED. - To generate a synthetic rule set from an input SEED. ### ClassBench-ng Analyser -ClassBench-ng offers two versions of the analysers: OpenFlow analyser and Tuples analyser. +The current version can successfully analyse IPv4 5-tuples and OpenFlow rules. + +``` +./classbench analyse tuples FILE FORMAT [-l] +``` +Analyses FILE, expecting FILE to be in the format specified in FORMAT (see `./lib/tuples_analyzer/README` for more information on how to specify the format). +- `-l` enables printing analysis error logs. + +The output is an original ClassBench seed. -#### OpenFlow Analyser -First version of analyser supports only OpenFlow rules. -The output is an original ClassBench seed with an OpenFlow YAML structure as the last section. -This version can be run with these arguments: ``` ./classbench analyse of FILE ``` @@ -60,24 +64,7 @@ Fields extracted from FILE are: - nw_src, nw_dst, nw_tos, nw_proto, - tp_src, tp_dst -#### OpenFlow Analyser -Second version of analyser accepts any filter rule sets format but file, -describing format of rules in set, has to be given to analyser as argument. -How to define file with format is described in file lib/tuples_analyzer/README. -In folder lib/tuples_analyzer/examples there are also examples of filter rule sets and -files with formats of rules defined to them. -Fields extracted from rules are only parts of standard IP 5-tuple: -(protocol, source IPv4 address, source port or source port range, destination IPv4 address, -destination port or destination port range) -The output is an original ClassBench seed without OpenFlow YAML structure. -It can be run with these arguments: -``` -./classbench analyse tuples --rules= --format= [--output=] [--logs] -``` -- `--rules=` specifies the path to file with filter rules -- `--format=` specifies the path to file with format of rules -- `--output=` specifies the path to output file -- `--logs` enables printing error logs during processing of filter rules +The output is an original ClassBench seed with an OpenFlow YAML structure as the last section. ### ClassBench-ng Rule Generator The current version can successfully generate IPv4, IPv6 and OpenFlow 1.0 flow rules. From 456cbf79175cbc245acb058d033ee02be78ac11e Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Wed, 23 Oct 2019 22:55:33 +0200 Subject: [PATCH 44/51] README [MAINTENANCE]: move instructions for printing help at the beginning of the Usage section. This kind of information fits better to this place. --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index aef4c71..6b9237f 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,11 @@ ClassBench-ng can be used in two different ways: - To analyse an existing rule set and extract a corresponding SEED. - To generate a synthetic rule set from an input SEED. +``` +./classbench -h | --help +``` +Prints detailed usage information. + ### ClassBench-ng Analyser The current version can successfully analyse IPv4 5-tuples and OpenFlow rules. @@ -98,11 +103,6 @@ Generates OpenFlow rules following the properties from SEED that has to contain The output consists of `attribute=value` pairs joined by `, `. -``` -./classbench -h | --help -``` -Prints detailed usage information. - ## Known Issues - the number of generated rules is usually lower than in original ClassBench (i.e., ClassBench-ng generates higher number of redundant rules that are removed in the last phase) - ClassBench-ng Analyser does not correctly analyses source/destination port prefixes specified using a bit map in the ovs-ofctl format From 7765867afdd078bf134baf9bd81d9a2d024a8325 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Wed, 23 Oct 2019 23:02:30 +0200 Subject: [PATCH 45/51] README [MAINTENANCE]: add Python3 to the list of ClassBench-ng requirements. Python3 is required by tuples_analyzer (see the "analyse tuples" mode). --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6b9237f..e769aa9 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ The format of the generated rules can be one of the following: - OpenFlow ## Requirements +- Python3 - Ruby 1.9.3+ - RubyGems ``` From bde53fef65e52fcabf7c19ec11705bda214b33df Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Wed, 23 Oct 2019 23:24:21 +0200 Subject: [PATCH 46/51] ClassBench-ng top [MAINTENANCE]: move 5-tuples analysis in front of OpenFlow analysis in the code. This order is more logical and applied also throughout the ClassBench-ng paper and documentation. --- classbench | 8 ++++---- lib/classbench.rb | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/classbench b/classbench index 60fa61f..e030cd3 100755 --- a/classbench +++ b/classbench @@ -9,8 +9,8 @@ ClassBench-ng A tool for generation of synthetic classification rule sets for benchmarking. Usage: - #{__FILE__} analyse of FILE #{__FILE__} analyse tuples FILE FORMAT [-l] + #{__FILE__} analyse of FILE #{__FILE__} generate v4 SEED [--count=] [--db-generator=] #{__FILE__} generate v6 SEED [--count=] [--db-generator=] #{__FILE__} generate of SEED [--count=] [--db-generator=] @@ -44,10 +44,10 @@ DOCOPT begin opts = Docopt::docopt(doc) if opts["analyse"] - if opts["of"] - Classbench::analyse_of(opts["FILE"]) - elsif opts["tuples"] + if opts["tuples"] Classbench::analyse_tuples(opts["FILE"], opts["FORMAT"], opts["-l"]) + elsif opts["of"] + Classbench::analyse_of(opts["FILE"]) end elsif opts["generate"] if opts["v4"] diff --git a/lib/classbench.rb b/lib/classbench.rb index 838950c..46b1c0b 100644 --- a/lib/classbench.rb +++ b/lib/classbench.rb @@ -32,16 +32,6 @@ def self.load_prefixes_from_file(filename) t end - def self.analyse_of(filename) - analyser = Analyser.new - analyser.parse_openflow(File.read(filename)) - - analyser.calculate_stats - - puts analyser.generate_seed - - end - def self.analyse_tuples(rules_filename, format_filename, logs_enabled) if logs_enabled pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename, "-l") @@ -66,6 +56,16 @@ def self.analyse_tuples(rules_filename, format_filename, logs_enabled) end + def self.analyse_of(filename) + analyser = Analyser.new + analyser.parse_openflow(File.read(filename)) + + analyser.calculate_stats + + puts analyser.generate_seed + + end + def self.generate(format, filename, count, db_generator_path) generator = Generator.new(filename, db_generator_path) if format == "of" From cf506c6674f628d3ef9b5388995a6ac7de5594aa Mon Sep 17 00:00:00 2001 From: Jozef Sabo Date: Tue, 19 May 2020 17:29:44 +0200 Subject: [PATCH 47/51] Modified README file and renamed example files. --- lib/tuples_analyzer/README | 32 +++++++++++-------- .../formats/{format_1 => custom1.format} | 0 .../formats/{format_2 => custom2.format} | 0 .../examples/formats/custom_with_ipv6.format | 1 + .../examples/formats/{ipfw => ipfw.format} | 0 .../formats/{iptables => iptables.format} | 0 .../formats/{openflow => openflow.format} | 0 .../examples/sets/{set_1 => custom1.set} | 0 .../examples/sets/{set_2 => custom2.set} | 0 .../examples/sets/custom_with_ipv6.set | 6 ++++ .../examples/sets/{ipfw => ipfw.set} | 0 .../examples/sets/{iptables => iptables.set} | 0 .../examples/sets/{openflow => openflow.set} | 0 13 files changed, 25 insertions(+), 14 deletions(-) rename lib/tuples_analyzer/examples/formats/{format_1 => custom1.format} (100%) rename lib/tuples_analyzer/examples/formats/{format_2 => custom2.format} (100%) create mode 100644 lib/tuples_analyzer/examples/formats/custom_with_ipv6.format rename lib/tuples_analyzer/examples/formats/{ipfw => ipfw.format} (100%) rename lib/tuples_analyzer/examples/formats/{iptables => iptables.format} (100%) rename lib/tuples_analyzer/examples/formats/{openflow => openflow.format} (100%) rename lib/tuples_analyzer/examples/sets/{set_1 => custom1.set} (100%) rename lib/tuples_analyzer/examples/sets/{set_2 => custom2.set} (100%) create mode 100644 lib/tuples_analyzer/examples/sets/custom_with_ipv6.set rename lib/tuples_analyzer/examples/sets/{ipfw => ipfw.set} (100%) rename lib/tuples_analyzer/examples/sets/{iptables => iptables.set} (100%) rename lib/tuples_analyzer/examples/sets/{openflow => openflow.set} (100%) diff --git a/lib/tuples_analyzer/README b/lib/tuples_analyzer/README index 45db017..8ab9143 100644 --- a/lib/tuples_analyzer/README +++ b/lib/tuples_analyzer/README @@ -48,20 +48,20 @@ value is expected on same position in rule. What every parameter represents is described in this list: PROTOCOL network protocol abbreviation - SRC_IP source IPv4 address + SRC_IP source IPv4 or IPv6 address SRC_PORT source port or port range - DST_IP destination IPv4 address + DST_IP destination IPv4 or IPv6 address DST_PORT destination port or port range NUMBER some number, not used for computation parameters - WILDCARD some string, not used for computation parameters + WILDCARD some string, not used for computation parameters b.)supported representation of parameters in rules - Supported IPv4 address definitions in rules are: 10.0.0.0/24, 192.168.0.33 (with or without mask in digit form) - Supported port definitions in rules are: 80, 0:1023 (port or port range) - Supported network protocol case-insensitive abbreviations in rules are: + Supported IPv4 and IPv6 address definitions are with or without mask in digit form, e.g.: 2001:db8:a::/64, 192.168.0.33 + Supported port definitions are port number or port range, e.g.: 80, 0:1023 + All supported network protocol case-insensitive abbreviations are: 'ICMP', 'IGMP', 'GGP', 'ST', 'TCP', 'EGP', 'UDP', 'GRE', 'ESP', 'AH', 'EIGRP', 'OSPFIGP' - Supported wildcard values of parameters in rules are: 'any', 'all', ''*', 'ip', '0' + All supported wildcard values of parameters are: 'any', 'all', '*', 'ip', '0' b.)keywords @@ -82,26 +82,30 @@ 8.FORMAT OF RULES EXAMPLES: - Example sets, formats and correct outputs are located in examples folder. + Example sets and formats are located in examples folder. - a.) format1: + a.) custom1.format: PROTOCOL from SRC_IP SRC_PORT to DST_IP DST_PORT - b.) format2: + b.) custom2.format: PROTOCOL destination DST_IP ip-port? DST_PORT? source SRC_IP ip-port? SRC_PORT? - c.) openflow: + c.)custom_with_ipv6.format: + rule NUMBER WILDCARD PROTOCOL source? SRC_IP? destination? DST_IP? destination-port DST_PORT? + + d.) openflow.format: nw_proto=PROTOCOL, nw_src?=SRC_IP?, nw_dst?=DST_IP?, tp_src?=SRC_PORT?, tp_dst?=DST_PORT? - d.)iptables long format: + e.)iptables_long.format (long format): iptables WILDCARD WILDCARD --source? SRC_IP? --destination? DST_IP? --protocol? PROTOCOL? --source-port? SRC_PORT? --destination-port? DST_PORT? -j WILDCARD - e.)iptables short format: + f.)iptables_short.format (short format): iptables WILDCARD WILDCARD -s? SRC_IP? -d? DST_IP? -p? PROTOCOL? --sport? SRC_PORT? --dport? DST_PORT? -j WILDCARD - f.)ipfw format: + g.)ipfw.format: ipfw add WILDCARD PROTOCOL? from SRC_IP? SRC_PORT? to DST_IP? DST_PORT? + 9.AUTHOR: Jozef Sabo xsaboj00@stud.fit.vutbr.cz diff --git a/lib/tuples_analyzer/examples/formats/format_1 b/lib/tuples_analyzer/examples/formats/custom1.format similarity index 100% rename from lib/tuples_analyzer/examples/formats/format_1 rename to lib/tuples_analyzer/examples/formats/custom1.format diff --git a/lib/tuples_analyzer/examples/formats/format_2 b/lib/tuples_analyzer/examples/formats/custom2.format similarity index 100% rename from lib/tuples_analyzer/examples/formats/format_2 rename to lib/tuples_analyzer/examples/formats/custom2.format diff --git a/lib/tuples_analyzer/examples/formats/custom_with_ipv6.format b/lib/tuples_analyzer/examples/formats/custom_with_ipv6.format new file mode 100644 index 0000000..33aa4d3 --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/custom_with_ipv6.format @@ -0,0 +1 @@ +rule NUMBER WILDCARD PROTOCOL source? SRC_IP? destination? DST_IP? destination-port DST_PORT? diff --git a/lib/tuples_analyzer/examples/formats/ipfw b/lib/tuples_analyzer/examples/formats/ipfw.format similarity index 100% rename from lib/tuples_analyzer/examples/formats/ipfw rename to lib/tuples_analyzer/examples/formats/ipfw.format diff --git a/lib/tuples_analyzer/examples/formats/iptables b/lib/tuples_analyzer/examples/formats/iptables.format similarity index 100% rename from lib/tuples_analyzer/examples/formats/iptables rename to lib/tuples_analyzer/examples/formats/iptables.format diff --git a/lib/tuples_analyzer/examples/formats/openflow b/lib/tuples_analyzer/examples/formats/openflow.format similarity index 100% rename from lib/tuples_analyzer/examples/formats/openflow rename to lib/tuples_analyzer/examples/formats/openflow.format diff --git a/lib/tuples_analyzer/examples/sets/set_1 b/lib/tuples_analyzer/examples/sets/custom1.set similarity index 100% rename from lib/tuples_analyzer/examples/sets/set_1 rename to lib/tuples_analyzer/examples/sets/custom1.set diff --git a/lib/tuples_analyzer/examples/sets/set_2 b/lib/tuples_analyzer/examples/sets/custom2.set similarity index 100% rename from lib/tuples_analyzer/examples/sets/set_2 rename to lib/tuples_analyzer/examples/sets/custom2.set diff --git a/lib/tuples_analyzer/examples/sets/custom_with_ipv6.set b/lib/tuples_analyzer/examples/sets/custom_with_ipv6.set new file mode 100644 index 0000000..cddcdaa --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/custom_with_ipv6.set @@ -0,0 +1,6 @@ +rule 1 permit tcp source 147.240.1.0/24 destination-port 1 +rule 2 permit tcp destination 147.10.10.1/32 destination-port smtp +rule 3 permit udp source fd6d:fa5:24bc:a286::/64 destination-port 2:10 +rule 4 deny udp destination 2001:ABC:1230::/48 destination-port 11 +rule 5 permit tcp destination 2001:ABC:1230::1234:123/128 destination-port 11 +rule 6 permit tcp source 2001:67B:1220:F000::/52 destination 2001:FED:1230::/48 destination-port 12:300 diff --git a/lib/tuples_analyzer/examples/sets/ipfw b/lib/tuples_analyzer/examples/sets/ipfw.set similarity index 100% rename from lib/tuples_analyzer/examples/sets/ipfw rename to lib/tuples_analyzer/examples/sets/ipfw.set diff --git a/lib/tuples_analyzer/examples/sets/iptables b/lib/tuples_analyzer/examples/sets/iptables.set similarity index 100% rename from lib/tuples_analyzer/examples/sets/iptables rename to lib/tuples_analyzer/examples/sets/iptables.set diff --git a/lib/tuples_analyzer/examples/sets/openflow b/lib/tuples_analyzer/examples/sets/openflow.set similarity index 100% rename from lib/tuples_analyzer/examples/sets/openflow rename to lib/tuples_analyzer/examples/sets/openflow.set From 835f6b48a656d7269f556bca8268cb980464c994 Mon Sep 17 00:00:00 2001 From: Jozef Sabo Date: Tue, 19 May 2020 23:14:13 +0200 Subject: [PATCH 48/51] Added IPv6 support for 5-tuples analyzer. --- .../prefix_correlation_distribution.py | 10 ++- .../calculation_parameters/trie_node.py | 2 +- .../enums/filter_rule_part_type.py | 13 +-- .../processing_rules/filter_rule.py | 33 ++++--- .../processing_rules/filter_rule_generator.py | 87 ++++++++++++++----- 5 files changed, 106 insertions(+), 39 deletions(-) diff --git a/lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py b/lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py index c1b1e24..a3f4281 100644 --- a/lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py +++ b/lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py @@ -15,11 +15,11 @@ class PrefixCorrelationDistribution(IParameter): def __init__(self): """ Constructor initialize two instance variable as lists with zero values. - Both lists are sizes of 32. Indexes of lists are representing prefix levels. + Both lists are sizes of 128. Indexes of lists are representing prefix levels. """ - self.all_on_level = [0] * 32 + self.all_on_level = [0] * 128 """List with counts of rules which have same source and destination prefixes until previous level.""" - self.same_on_level = [0] * 32 + self.same_on_level = [0] * 128 """List with counts of rules which source and destination prefixes are same on level.""" def extract_data(self, filter_rule): @@ -60,6 +60,10 @@ def compute_parameter(self): for rules_count in self.all_on_level: + # at least 32 will be printed + if i > 32 and rules_count == 0: + break + # for first correlation we do not want print new line if first: first = False diff --git a/lib/tuples_analyzer/calculation_parameters/trie_node.py b/lib/tuples_analyzer/calculation_parameters/trie_node.py index 19ebdad..bcc042e 100644 --- a/lib/tuples_analyzer/calculation_parameters/trie_node.py +++ b/lib/tuples_analyzer/calculation_parameters/trie_node.py @@ -21,7 +21,7 @@ def __init__(self, bit): self.prefix = False """Instance variable prefix is boolean type and is telling, if node is prefix or only node on path to prefix.""" self.level = 0 - """Prefix level of node in trie (0-32).""" + """Prefix level of node in trie.""" self.children = [] """List holding instances of children nodes. Trie node can have max. 2 children.""" self.prefixes = [0, 0] diff --git a/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py index 229f7d9..ee15c74 100644 --- a/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py +++ b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py @@ -13,10 +13,10 @@ class FilterRulePartType(Enum): """Representation of wildcard value.""" PROTOCOL = 1 """Network protocol abbreviation.""" - IP_ADDRESS = 2 - """IP address without mask.""" - IP_ADDRESS_MASK = 3 - """IP address with mask.""" + IPV4_ADDRESS = 2 + """IPv4 address without mask.""" + IPV4_ADDRESS_MASK = 3 + """IPv4 address with mask.""" PORT = 4 """Port value.""" PORT_RANGE = 5 @@ -27,4 +27,7 @@ class FilterRulePartType(Enum): """Word which is part of rule format definition e.g. from, to.""" WORD = 8 """Every other value.""" - + IPV6_ADDRESS = 9 + """IPv6 address without mask.""" + IPV6_ADDRESS_MASK = 10 + """IPv6 address with mask.""" diff --git a/lib/tuples_analyzer/processing_rules/filter_rule.py b/lib/tuples_analyzer/processing_rules/filter_rule.py index a4aec2e..f4dfc9d 100644 --- a/lib/tuples_analyzer/processing_rules/filter_rule.py +++ b/lib/tuples_analyzer/processing_rules/filter_rule.py @@ -204,15 +204,17 @@ def set_port(self, port, location): self.dst_port = port + ':' + port self.dst_port_class = PC.EM - def set_ip_add(self, ip_address, location): + def set_ip_add(self, ip_address, location, is_ipv6): """ - Function takes parameter ip address in decimal form and sets instance variable source or destination ip_add_bin + Function takes parameter ip address and sets instance variable source or destination ip_add_bin as binary form of that ip address. It also sets instance variable source or destination ip_add_prefix_length with ip address prefix length. - :param ip_address: Ip address with prefix length in decimal form. + :param ip_address: Ip address with prefix length. :param location: Location of ip address (source/destination). + + :param is_ipv6: True, if it is IPv6 address. """ if location == FilterRulePartLocation.SOURCE: if ip_address == 'any': @@ -220,12 +222,18 @@ def set_ip_add(self, ip_address, location): self.src_ip_add_prefix_length = 0 else: ip_address = ip_address.split('/') - bin_ip_address = bin(int(ipaddress.IPv4Address(ip_address[0]))) - bin_ip_address = bin_ip_address[2:].zfill(32) prefix_length = int(ip_address[1]) + self.src_ip_add_prefix_length = prefix_length + + if not is_ipv6: + bin_ip_address = bin(int(ipaddress.IPv4Address(ip_address[0]))) + bin_ip_address = bin_ip_address[2:].zfill(32) + else: + bin_ip_address = bin(int(ipaddress.IPv6Address(ip_address[0]))) + bin_ip_address = bin_ip_address[2:].zfill(128) + binary_ip_address_cut = bin_ip_address[:prefix_length] self.src_ip_add_bin = binary_ip_address_cut - self.src_ip_add_prefix_length = prefix_length elif location == FilterRulePartLocation.DESTINATION: if ip_address == 'any': @@ -233,10 +241,15 @@ def set_ip_add(self, ip_address, location): self.dst_ip_add_prefix_length = 0 else: ip_address = ip_address.split('/') - bin_ip_address = bin(int(ipaddress.IPv4Address(ip_address[0]))) - bin_ip_address = bin_ip_address[2:].zfill(32) prefix_length = int(ip_address[1]) - binary_ip_address_cut = bin_ip_address[:prefix_length] - self.dst_ip_add_bin = binary_ip_address_cut self.dst_ip_add_prefix_length = prefix_length + if not is_ipv6: + bin_ip_address = bin(int(ipaddress.IPv4Address(ip_address[0]))) + bin_ip_address = bin_ip_address[2:].zfill(32) + else: + bin_ip_address = bin(int(ipaddress.IPv6Address(ip_address[0]))) + bin_ip_address = bin_ip_address[2:].zfill(128) + + binary_ip_address_cut = bin_ip_address[:prefix_length] + self.dst_ip_add_bin = binary_ip_address_cut diff --git a/lib/tuples_analyzer/processing_rules/filter_rule_generator.py b/lib/tuples_analyzer/processing_rules/filter_rule_generator.py index ab6b7e5..3bc3196 100644 --- a/lib/tuples_analyzer/processing_rules/filter_rule_generator.py +++ b/lib/tuples_analyzer/processing_rules/filter_rule_generator.py @@ -145,9 +145,12 @@ def part_processing(expected_part_type, part, filter_rule, format_words): if part_type == FilterRulePartType.ANY: part = "any" - if part_type == FilterRulePartType.IP_ADDRESS: + if part_type == FilterRulePartType.IPV4_ADDRESS: part += '/32' + if part_type == FilterRulePartType.IPV6_ADDRESS: + part += '/128' + if ((expected_part_type == "PROTOCOL" or expected_part_type == "PROTOCOL?") and (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.PROTOCOL)): @@ -171,16 +174,20 @@ def part_processing(expected_part_type, part, filter_rule, format_words): filter_rule.set_port(part, FilterRulePartLocation.DESTINATION) elif ((expected_part_type == "SRC_IP" or expected_part_type == "SRC_IP?") and - (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.IP_ADDRESS_MASK - or part_type == FilterRulePartType.IP_ADDRESS)): + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.IPV4_ADDRESS_MASK + or part_type == FilterRulePartType.IPV6_ADDRESS or part_type == FilterRulePartType.IPV6_ADDRESS_MASK + or part_type == FilterRulePartType.IPV4_ADDRESS)): - filter_rule.set_ip_add(part, FilterRulePartLocation.SOURCE) + is_ipv6 = part_type == FilterRulePartType.IPV6_ADDRESS or part_type == FilterRulePartType.IPV6_ADDRESS_MASK + filter_rule.set_ip_add(part, FilterRulePartLocation.SOURCE, is_ipv6) elif ((expected_part_type == "DST_IP" or expected_part_type == "DST_IP?") and - (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.IP_ADDRESS_MASK - or part_type == FilterRulePartType.IP_ADDRESS)): + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.IPV4_ADDRESS_MASK + or part_type == FilterRulePartType.IPV6_ADDRESS or part_type == FilterRulePartType.IPV6_ADDRESS_MASK + or part_type == FilterRulePartType.IPV4_ADDRESS)): - filter_rule.set_ip_add(part, FilterRulePartLocation.DESTINATION) + is_ipv6 = part_type == FilterRulePartType.IPV6_ADDRESS or part_type == FilterRulePartType.IPV6_ADDRESS_MASK + filter_rule.set_ip_add(part, FilterRulePartLocation.DESTINATION, is_ipv6) elif ((expected_part_type == "NUMBER" or expected_part_type == "NUMBER?") and (part_type == FilterRulePartType.NUMBER or part_type == FilterRulePartType.PORT)): @@ -256,11 +263,17 @@ def get_type(part, format_words): elif FilterRuleGenerator.is_protocol(part): return FilterRulePartType.PROTOCOL - elif FilterRuleGenerator.is_ip_address(part): - return FilterRulePartType.IP_ADDRESS + elif FilterRuleGenerator.is_ipv4_address(part): + return FilterRulePartType.IPV4_ADDRESS + + elif FilterRuleGenerator.is_ipv4_address_with_mask(part): + return FilterRulePartType.IPV4_ADDRESS_MASK - elif FilterRuleGenerator.is_ip_address_with_mask(part): - return FilterRulePartType.IP_ADDRESS_MASK + elif FilterRuleGenerator.is_ipv6_address(part): + return FilterRulePartType.IPV6_ADDRESS + + elif FilterRuleGenerator.is_ipv6_address_with_mask(part): + return FilterRulePartType.IPV6_ADDRESS_MASK elif FilterRuleGenerator.is_port(part): return FilterRulePartType.PORT @@ -366,13 +379,13 @@ def is_keyword(keyword, format_words): return False @staticmethod - def is_ip_address(ip_address): + def is_ipv4_address(ip_address): """ - Function returns true, if parameter of function is IP address in decimal form without mask (prefix length). + Function returns true, if parameter of function is IPv4 address in decimal form without mask (prefix length). - :param ip_address: String with possible IP address in decimal form. + :param ip_address: String with possible IPv4 address in decimal form. - :return: True, if parameter of function is IP address. + :return: True, if parameter of function is IPv4 address. """ try: ipaddress.IPv4Address(ip_address) @@ -382,18 +395,52 @@ def is_ip_address(ip_address): return True @staticmethod - def is_ip_address_with_mask(ip_address): + def is_ipv4_address_with_mask(ip_address): + """ + Function returns true, if parameter of function is IPv4 address in decimal form with mask (prefix length). + + :param ip_address: String with possible IPv4 address with mask in decimal form. + + :return: True, if parameter of function is IPv4 address with mask. + """ + possible_address = ip_address.split('/') + + if len(possible_address) != 2 or not possible_address[1].isdigit() or int(possible_address[1]) < 0 or int( + possible_address[1]) > 32 or not FilterRuleGenerator.is_ipv4_address(possible_address[0]): + return False + + return True + + + @staticmethod + def is_ipv6_address(ip_address): + """ + Function returns true, if parameter of function is IPv6 address without mask (prefix length). + + :param ip_address: String with possible IPv6 address. + + :return: True, if parameter of function is IPv6 address. + """ + try: + ipaddress.IPv6Address(ip_address) + except ipaddress.AddressValueError: + return False + + return True + + @staticmethod + def is_ipv6_address_with_mask(ip_address): """ - Function returns true, if parameter of function is IP address in decimal form with mask (prefix length). + Function returns true, if parameter of function is IPv6 address with mask (prefix length). - :param ip_address: String with possible IP address with mask in decimal form. + :param ip_address: String with possible IPv6 address with mask. - :return: True, if parameter of function is IP address with mask. + :return: True, if parameter of function is IPv6 address with mask. """ possible_address = ip_address.split('/') if len(possible_address) != 2 or not possible_address[1].isdigit() or int(possible_address[1]) < 0 or int( - possible_address[1]) > 32 or not FilterRuleGenerator.is_ip_address(possible_address[0]): + possible_address[1]) > 128 or not FilterRuleGenerator.is_ipv6_address(possible_address[0]): return False return True From 27249ac464dcf858e5b1aa05710f17df315cbbc8 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Mon, 5 Apr 2021 21:06:18 +0100 Subject: [PATCH 49/51] README.md [MAINTENANCE]: reflect support for IPv6 prefixes in ClassBench-ng Analyser --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index e769aa9..e1f179d 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ ClassBench-ng can be used in two different ways: Prints detailed usage information. ### ClassBench-ng Analyser -The current version can successfully analyse IPv4 5-tuples and OpenFlow rules. +The current version can successfully analyse IPv4 5-tuples, IPv6 5-tuples, and OpenFlow rules. ``` ./classbench analyse tuples FILE FORMAT [-l] @@ -107,7 +107,6 @@ The output consists of `attribute=value` pairs joined by `, `. ## Known Issues - the number of generated rules is usually lower than in original ClassBench (i.e., ClassBench-ng generates higher number of redundant rules that are removed in the last phase) - ClassBench-ng Analyser does not correctly analyses source/destination port prefixes specified using a bit map in the ovs-ofctl format -- ClassBench-ng Analyser is not able to analyse rule sets with source/destination IPv6 prefixes ## How to Contribute Contributions are welcome via: From ef8c85d7af02a310110dce5489b99c35fdf37258 Mon Sep 17 00:00:00 2001 From: Jiri Matousek Date: Thu, 23 Sep 2021 21:49:21 +0100 Subject: [PATCH 50/51] vendor/Makefile [BUGFIX]: enable --no-check-certificate option of wget Nowadays, this is necessary for a successful download of original ClassBench and its parameter files. --- vendor/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/Makefile b/vendor/Makefile index 1f757d4..4af2a11 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -10,13 +10,13 @@ download: -[ -d db_generator ] && mv db_generator db_generator-$(BACKUP_TIME) # Download and unpack ClassBench - wget -O- -q http://www.arl.wustl.edu/classbench/db_generator.tar.gz | tar -xvz + wget -O- --no-check-certificate -q http://www.arl.wustl.edu/classbench/db_generator.tar.gz | tar -xvz # Make backup of parameter_files, if exists -[ -d parameter_files ] && mv parameter_files parameter_files-$(BACKUP_TIME) # Download and unpack ClassBench parameter files - wget -O- -q http://www.arl.wustl.edu/classbench/parameter_files.tar.gz | tar -xvz + wget -O- --no-check-certificate -q http://www.arl.wustl.edu/classbench/parameter_files.tar.gz | tar -xvz patch: download # Apply patches from ../patches From 4454cf606a5e127ef73ee50014769c687d2cc833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=87=E5=BF=A0=E9=AA=8F?= <74434779+Decade-qiu@users.noreply.github.com> Date: Tue, 19 Dec 2023 10:01:59 +0800 Subject: [PATCH 51/51] Update Makefile The folder path here contains an extra "vendor", causing the compilation process to fail. This is because during the make process, the working directory is already within the "vendor" folder. After testing, modifying it in this way allows for successful compilation. --- vendor/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/Makefile b/vendor/Makefile index 4af2a11..5f59624 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -20,9 +20,9 @@ download: patch: download # Apply patches from ../patches - git apply --directory=vendor/db_generator ../patches/improvements_ipv6.patch - #git apply --directory=vendor/db_generator ../patches/ipv6.patch - #git apply --directory=vendor/db_generator ../patches/improvements.patch + git apply --directory=db_generator ../patches/improvements_ipv6.patch + #git apply --directory=db_generator ../patches/ipv6.patch + #git apply --directory=db_generator ../patches/improvements.patch # Patching PortList (extension of preallocated array is necessary) # Raise limit of L5 rules from 200 to 20000.