From d657bc4e3db1a625619f8954d3b92c58fe8ea795 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Sun, 17 Aug 2014 15:01:48 +0200 Subject: [PATCH] Implement IPv6 multicast again (fixes #346) --- auto/gui.files.go | 2 +- beacon/beacon.go | 46 ++++++++++++++++++++++++++++ beacon/broadcast.go | 36 +--------------------- beacon/multicast.go | 70 +++++++++++++++++++++++++++++++++++++++++++ cmd/syncthing/main.go | 2 +- config/config.go | 1 + config/config_test.go | 3 ++ discover/discover.go | 39 +++++++++++++++++------- gui/index.html | 4 --- 9 files changed, 151 insertions(+), 52 deletions(-) create mode 100644 beacon/beacon.go create mode 100644 beacon/multicast.go diff --git a/auto/gui.files.go b/auto/gui.files.go index 28a9ea0b7..24312cdbd 100644 --- a/auto/gui.files.go +++ b/auto/gui.files.go @@ -73,7 +73,7 @@ func init() { bs, _ = ioutil.ReadAll(gr) Assets["favicon.png"] = bs - bs, _ = hex.DecodeString("1f8b080000096e8800ffec7d6b77dc36b2e0f7fc0ab8ef249666c56ec9763cbb8aa4bbb2e44c9487ed23d9379bcdc9ce4193e86e44244103a4e41e45f3dbb7aac0f7a3c956cbb6eebdf9608b4dbcaa0a5585aa02503c7874fafae4ed2f6f5eb2451cf8475f1c3c729c2f261376a2a2a596f345ccb64eb6d993ddbd67ec7b7ea9a6ec85d273c6430f6a84b196d32456dab02d23048b17829dbc7ef5f6fcecc5bbb7afcf2fd84cfa627b8cdd1dfb3ea3ee0cd3c2087d25bc317b6704533368260d332ad1ae60aef204839f73752574283c365dc260eca7b3b78e8997bec0be7ce98ad0e0703c662e944e059ba904409221c1f0e3d9c9cb57172f69f8f1178e03582172cce7e1fc7024c2110be70e8fa2c39159862e0c1fcee9958b1829df17fa707491959cc4da1f31d7e7c61c8eb092aff8e508bb14dc3bfa82b18340c49cb90bae8d880f47493c73fee7a82858c471e488f789bc3a1cfd1fe7ddb173a28288c772ea0be816461421b43a7b7928bcb928b50b79200e4757525c474ac7a5aad7d28b17879eb8023238f463071097b1e4be635cee8bc3bdf16ea3234f1857cb28962a2cf5d5a8c69378a174a3862fc34b98381f2806c5b19bc44cbad8d3428bd9e168c6aff0e73802421e7d810d6219fbe2282722fb83dddce03cbf82f97d05236d6ddfde1e4c6cad7c00dbd954a9d8c49a4713d79849fe6b1cc8700c6f46291cc80d6621443caa77a08106d77cb9a232fd66f132028c63f121c691a884b1a9f296ec861e198bb8e701f4ce54c5b10af6d9df76a30fdfa46533a09033e381f497fb6cf49df0af442c5dce5e89448c7658fe62871d6b989a1d6678681c607d39b35ddc7e417f167b3b6cf104fe3d857fcfe0dfd7f9f0d521ce2d5ad0f706a325feff280d10703d97a113ab689fed8dbf1641a5ee1849e3042a5426e2209bad60fd24425fedb09f54c85df80b4ac128901500f204245a0a0d205e03847937b52138c8010a9e8722ed1dc52455b13e42ae6e96e2ec7497ce8057ba4bf39ebd953db796e63d7b3915a64a7b425bda852aace1e5abb9aa91799fed7e53e5abd21beac6f9ba60af481989c2ba8f1c0ceae2aa3e8034b1132a679a80be8af3a1e835b1b783ec6d41ab3504c4fc2408f3369e3491cf612e650852249ca9afdccb0c0e903aab6480fb33fec81987343ab04e5130e5eee55ca332c6519406f0e7d3ad274f9fefb027cf76f1bfbded6faa14d4dc9389d9674f4bc867f4d98b3eb067c5fb8c904fe0f593ecf56d1d2f60b370ec71d069353ef7c50ca0dd2d18bd82dede6ef19a389ffb728ef44724bfe9a75546e06c8d68d217e7823d92012a741ec62d9200cb57deec7a2163e190cc60d36bd08115dd732d2cf59fedeeb6f6e435d498c5ff0928b13e28bcb109b8ef3b152a76029436fedf81f024675b01ff90d2f46fcfff167dd8ce3b48e50a0c8008d404b0f4917d5396bebc326393bf02ef83191033cef26580c1221be38a22c6f3f17e5e97fd1588a241cb4c61cd67d102286d40a81820a1ae194ed5540b7e69d044f01534d722d20adaf8c08213038b37d81ad7325e947bb4fc64c6ecaf93fc758d081ac894cdca6dce8e07131241301226d64af8e28030c4224f5ed56d8d9757b0d4929d7174308172bb848221c6deaa08444a33b461f05dc8af7253845f6189fd836a287bf4c48c273e580cd0bda07a72ce69ddb72b1c419076825070208e4ecb706d04e9a98ee14c35d87b009b0ce65909eab71133dab58f0e09ccf3676401b00571e6e1e8e99311b3d6ca686fef6fa3096087bde74345b571b013b6901e685de7032cc86d264394b74efc52f30cf9d223c96d8e179908487809164212cd41eb88b370a6c6a1b82ea14f15c1a68d5598da07f6476e014ee3301b001fe15f41706b7e5853128cd4cb7ca0adedea00651acffd65b440eb89e54f8ebb10571afe26d128a3d9572230b9fc179d80488406d607513c3957dc4fe07fa10d4cfae1e8e6a68c2ed630f1edede8e89d7d0b3cc66ebe4c6b7f795b9d221a68624950a2e4c49755baa6b8785a459eba0eabd8f29430ff36aad703b69dcfd10e463d93fe28f752c3f1e8a527630be0fbafc229d0e3609a733248708cd49ac23f5e19bf60947cdc408449054842e32807b53c87a03ccf45a4700e7b276ee179b519aba370ec790cbb83d55de9655a1521ae12b50f22148a41100155ae85a54c0f54d8651f3c3921e595f4506cd6801a1687f8c22a6f33087457cd7bc0cebabb1b19e5702abed7e898f641b380a5e6ecf463d2d02c9218197810d06a36eb85d8767737fac13a1e731d0f64c319545ff4c0736e7bfc9814e453950c0319566e1d3b2288e2659ff4609f2b803e98247ebbf62c4ad2851f1f6079b1ab7dc7426deba379f0add4268675fe7a87a9d05f3270ceaf4326672c14ae3086ebe5372ca529bbe63a44bb2935250a4b0417c447d0ff4ccecf42f4d873350d1d1776410518df093c67ef4979752d95031d84cfe87f271db6ba22d4eb22ad3daa75b0785a5ad32a75285830ca7804dc4ae1090f0caca74739edba0740f3abaef0a3d214be5d60ec096990683296d8821b361502dc097e8571a82406730f4c51177c3168e18d5911dd08129c861430b43ad34a148d0203a3daf5b864c554a6be1b7cf43f6b56ca003b058d1313946d141681bb985a469f5492eb264483a57c90b699fc306a99ccea8bcacfd28fc272ae0a8798273ed8c9c0cb35d6af3079d61f362c966772a7d9161ad7e83b6d173db40ac4f355f2e0a05b1c8d98f490dee9085298d592914ad1cd0d3639c1822d7c1a9f9d82354c53083f058f6d9fe8dde0df1f01ec9acdb952ea2af5a02608619be8d5aa916957b1dc800e3e8f4c66d0456093610cf1df2af866d620be04c4fe22434f7c4083b4d1fd004bb96c70314b25a0cded6d5f5f851c941c0e24a70127d05d58725ec43c4e0a82b742d834c4f34e9ceb8500fb3b092f43b266dfd987a6853dbc2f03ac180940f9c23e6cd497cb43ab9a2fd2a7fede1a7d800a6ce3a00e182820dc3310635b3737d8ef1ba15d601f3e172596ff72bb1dbab521975e2b47b7837d06953f21cc5d2535c7c6be82f5af2ae675fd994a7ea677ca225795f24c7a592ec68dd186acabf58af5a04fbba0dbc053b909ab4561d3df26d69244a09da8711668692fd55d4558b8e85ffd606a7b57be7cf528f902d0f78a81bd1c710ca3a4818b923683f65e274e936ea436c7d706c81c1589b007ef6fa9e63d207c2ab570917e1be19d59b601f86dfeaf29257f1bcbf08afbb28b7b069325b56a1d23e77d7479a9b5da902ced387c4eb698fb6adae70eff1dea70bf2dd8711f449853efdf4a5f18f607e3fe355f9a57493015faf6b6a1bf650c10a6c3efb07f7574f662195367531972e4be179f8fbe0b15f491f747e57e3ceafad8f93d1197fa7a40b4757d95780e863d7cc5fbc275afc1ed7b3d23576f130277d7e71d8a2a04f7d64ec011dbad8680d435fabe85599a45399ad35874b2f12c62572d93d830484aa86576d74aec0e0f01bda3dd1e7876d98bd5f61731cd676228dc02ec61a39fb801ff9da4f5a3b051abb58f74278a9f839ff73af4c150fb45983e3a7676f5a8d6d72bf570a72409dd85702f459f789fcd43a50503b33d90063740cc67981e0b04c260ee63862add3de449a25d5787fb7d9b13177677f667192f365be46840439b3948a9edbb5a5050d2e5654011ed68b7f86e0db78c5eb70725da7d24be3ab857d980c465a2358a811af7317abf8f6b1140978739696cb8e3fe6281d077293ebe0e6e9196012c366d9babb8a1544ce60070c18971a5df67afe77b8c6bc3eaf1702ef4a855f7b2afbe624397783cfba8a5275a96f87ecd170db16ad201d8c9024136abf06dd71f6d51863b046ecb6157dc8c2b055c490eee2de21a42e7c342adb9309562abd8fa6436c7f0eaafd99184adeddf1e4e80d5a2974556f19783700ed9e52a7b1aece626cc4e5ba4389392dc30ec54c0d313700202ff19736ac69c7a15ecf14fec5d2c7df94fda5fda70915c82a91a8ce1cfc370d7626e2e4d0f014edebcbb7702b8519246736bce13fc0c6145d5dcdfdfbbbdfdf23f89237b9a5663e7f06b3302c1d8a17091d0e6d7c7b18ab9ff188352d308392610202beeed2dfedaeaa87b169227f9167f96996cfb73d372d0e2f92efa987454493c9c90af93f8fe2999992fa91c00c8c761a8c0a312af7f608f0e5902ba7126c34e753898e6787479a1745f00351b9d5de0b5918d42a9bd2e5576b0048fbd524393b8789262b48a28cd736aafe970700ee93077ae3176cd9c7c3470ecd96c8dc13fa75eefdb49f90f7b267133214b0f363e6457efaebe0f59a19999f691dc9f8dadff0116b7353aede186c2eaec32c055bc101a51370fe984438b01bee9d186fac9cd963e5acdf5beb15a8f3ef46c9da3fe29af40e968639c077065d1b9755510f9028beba5e37fd07a858187bdddddc19beeef223c4a755a2cb36c0b9a6f7200e05eb038580b89ea8107bb90f78d00f625199afbbb1b9c7768060757603e3a3a95262d5f75a8e4a31d4ca80bcc9f07132a8543362164d8b70971ec7980ec46116eab70b0a34a7ce0b359ed2a0840fff6c58f4106175a85f7e21d0e11dfbab75848f367255584b3dfbb258297b24fd2caeb50aba17032f2943a1bb5d194763cbac9d2d1fba3a1dde30ec87f670fbdcea5031cf57a933ffdf55eaa0e71dbeb6d3e8af7fe9fc32b435240471b2f227fba671f7173a678b41b3493ea197a7c4587db4cfb9d128165f624fad817e13c5ed87daecf7bb9a4cdebab13f9958aa55b288b4d6e98947c58a007faaf25b2e0c878cd1a0402de8edfca40801a00c752ec8fbedb0f827d6346b7b7fb0008d502776fa6a5083d7f69fd5f6c443350bd19db3edff770a7a4e43976ed40172240373a2c7f0cbbadd667bebefee1b3dc26a948407e0d2bbf918daf5f507a906117b5b38b38e94f005278697e91863bde7353bbeb0274f5ce73497fa555c85548951666a7d99f008ae0fe25da88719e11671c8a78d2948d8b24c2c4016cc2be553a093a6fbd0d1ad9c0d073192f92e918ecd3493e76e9490b984b234c13921fe926333bb71536036405095c1866aef472e22937416f23bd4bdf34df4ac51f9d2cd298a48d282f9215b761ef69f016a6b0c99b4eba6f10afbee848dbff22be56fad2ea473c2a013651264df617050a6c2dd22b2366e8680bc6cc6da41c150928da0f806140f3600f6833d2f37813fef1496e8fd9b5eb3128dc1c8f3c5257b91a986250dcf63302f413c6a6a682a16dbfc300608c4a52e62ace22adc0f008289d045b0269d859186336ab9815e6e0181837d64be8efab85f07d99deed4fd5f8c184502ea893dea7a3cb861da4d179958c10d9f19c12fe453f75cc7362ca70a6723a34a73a278334ac18729c45b8eaf5df9074b26b9edb2de3f1b80b4b9b92601592495663058e792ff781623ee0fd6098ddb8ee4430bbe19de18797b873b8f3dda814d9bcb7131b95106dfc5ba0535c698576c4ba9d709e9d764228bdf7206a3ed77380608951ef0a5941bd289395581cd2dbf3a529a2b33e67b0d8c572265d12d5da64b1af028f9bc537e5187771f466bb10d5d21a790d82c4f03f344b6ac9abe827eee6e30a7a73132cedbd9a62c1c7e426d9616528cc8d1edbc626fa6150c901d5184c430ea6bacd7ff25e4ffe1d7b3fcc7a1d4d5a494a38a363d0506f591434f31af2b16db51927e2f12945470f47ce5e0bee54d5f124f7552a3d8e3f6f35b06d619ae0adc3c8b675d070aee746593cab5d29a473868f107460b1971fc0b025e9ac7494dad9459689c5b3019d0eea131da2964eeb665e03b786b97e30533a4873e6e0e328cd8887dcf792666dc56e1336c88e9b91094c6f6f1e83c439b4a03dc664415947e3902200e3bfa4377970e3a1a5d4933a5e36378f0e7c3e050fa820180c6ec104ae3db292750a6b2fd66ab495618417d9d3185a83c205ca28015964be240d84689abba82662a352423da2021d7704014a346e92216069e803b3f2bd4f241eea25fc1d1c447a60301078adc1fdcca9ece08915a24fa19b060c15e12f8d95e724825539b252dfb68dd0bec7d232897682fff8a36d82234d580084987e20b433878605a91c4616455b7ecb1131fd114b138e8c582af6ca16d30e2975376617480143f93a519de22374aa280f24a8962d4987c5bded71e7d64e13d376914726deba2301c03ffc7901eb92cd53062614e64cc04a3bec528808f10e40f9d98c9f942e94884569178038d00c58a982bdc1d3adb152ebe0d5318324bfe39c6357c86a751ef152b522f8a63e0f2fef0d1222e82b92987e60889300ea0c284f0943792c7ca52eadf48dd9598c994312df2362b2af9fa041fbf573ca69ca5d6445dcdb82897171a3ccceb69a313038a0cc3297dde3303bd6e8350dae9b0a6a94f25d072d6a318cee2dc3a6d61da824391e7625158906c56a2519f980c4826eb51e8ebe5341760029d58bd8559b561ca406b93d74dbaeeea2263334f517eea657ec94b2bebab079604213c30a8e5395ae0a990271fdc4d86945c36dcc7e96a03d499030dd9ea43d4d55d2233095389b85de28a21881a8a733590387471f018724c2001a2140d9570042fb80cd73040d66c9c19c1e8c12fc3471b86fd6e376f3157df6e3ec710dfef39680887489a13c6930b2edad660b64d262d0bb726a0eeb45ac87716ccb54bea4e50c376b3938cf1128159ca0918cf66d6ae31c4cd43b05aa308391d06496f12456e8d1bb8cc23430894b9b395a648d87cf60cdf8b910fe6c34645acbc138bc5c36551fda2c83d6292d4daba579de4307ddcbbb9a4d97b37d8fb665a7a39dbf066d0f2029d6b0a75ba2c983f213e59b28a51baefc4aa499d9aaec5e5aeafe925fe4df3cb07c01e3ad082d0f42230f80d3b1300019ef13a6b41974912a50577d37be4fd0b11e0068bba98cb64295e757234421359b2f0af5647982805b452c0627cf03d32de93bc17f4a5d7622d713a6afc4ebb3144efdbe36d67ae0bef69a1ef6c06c934df77b3da7bb6d57b26f9cfbf3c8f1565caf475ede5e6c2b6fdb666cab37c4b32f001ae363cdb36f29edf0ec696c6b3d90cd60ab37c9dd9e62a66fe1298887e641d5ba48f72e4c4de13698214b22d41111e8b128ceed75c692fb9f84f27d8267f0405ca17ac4d1a3080f4793fff72b77fe79ecfcdf5de77f39ff18ff76b3b7f3fcd9ed5f269d2608e139cc77a7aaed3e57cb54e5ee6b4b59e1bf5fe05711803a36a0097a7366b704589ef96c39663fa5ee2abe3768968296e4be9f5bb2646977ba89eb816d5d454b5e5273e40dea32e3e4eeb3ad75af0397bde52efe6f0369a8cf7c179852e65a17a43cc8c04c7d92b79e3f2b7c64325e7d30c8b6dbdde49dcc4726b7187900ff7980edd6787b87fc64b6e56c53295eb1d186be85b2f58fedca18a1bf5c41951657acfbc0cb665aee0d8f17abf49c2defd774353f296b3a2a6b397cb18e82a30eaa2aee5f93d342c9656accd6bba322cbf35415faec936a274be02efd644b0b0d85bf339fb8c4e069d08c72f4d0e1f704d8ac70a65d2dc857036759c645f048e0823066282cb104fa9622455bffdace629609c6113070c0f28fc6ccf25458ec00d9bbb86e49fd6050965e8f37a64baf1e2af16743ec2324d6705d345cea86b85e77b2639e0f37635a3118e6dc52d54e31a4d2814eee7935974cc3c32d09bfcd9db3722558a11ada755f7fccc22666c06079a4c1b3c57b116ca65580ac8e29135880b9f355588e92ed5096e07a85225e7d9d4a95c14bc5b92cc2f29286325243a02da0b6ae167f38935c4947d3ccacd99580e7934e34c699d2f1d954c676ded3ad1186f942295c8eeb39da75e904a7df2f0bd9b7c76fe953635693b544a256c0b7cef475eefb9991cd91432972284eda155aac0f5999bcf265bb9e9b765598ee854f8cf049ca68403a2b5ddc4eaa5f746bbfe5f671f8e382e0ca43c874f087120959c12ead1ab8f5b1c6e4b7bffc2fa2da8dc40329285be979713a37d6107f12bea2c6e753f2187ea33d03dc3cc03d8520c2dd690b197d3588b3b189f317362faad50dc00268697ae800d8d0187db6b03846784f56796913a59bc643cc77dbf00721a22e03be5c636d13be683c3ac2ffb3095ea994ca267ca9037b26aaf47b85b16efdabd51c693bc9cdc2408687a3bd4f175528d3b5cd722f97d74e07d8db64602900e7158c091c8b3be43bb882d9ef5d6ee63297015869423738a40e660e62e140a785e8e1deafa3df841a26b61fe05f5462a1a343063c6678920facb15064d0dfd1e8bf870d9754130c396bd57276a25895da4f5008568921d241c774d73796255748d27a371764e34ee9427a98c6a9d0fb5b92ee74f1f823d8b4f8c1c22b41d34b540d78ec2ec05704c7d05fe6ad31e29545baba8fe27f822da6f4a34ed588678961fedc625a778b69e32da5c1dfd9fa0c5b4ad9b7a63af693d2cf129a07be9fd430872afb3ac5f7b4ee79e7a62fbef1f1ade0564b05af6189908e36e02969f6065c7d0503325bc0fa4e6a50cfd672411e28ba5b27a61807d16b3a5763c625783e9903f913ff702142ef87690402f53a89e70a9711bc2d0b540864ccb67e902f26667b1809cabdad67ab95c85001e99311c2a629a5ab1aa0f72f4669de5296bd615b438950efe9ce846880349818f815f78f40a1f4fe4a8548e9bb3bd1a9d1df06a46ac2f6c958e70dd760d608ff1c6c656162e05a606106c2048e6448665956328c308dfeee4c9626649f52b1d8f4b2568e9122e4eedb9756c3acab5b4a1d6ea25dca700da5072ef89bd0e8dec230f5b31721e5a479f7267c936fad1434c3d7b686375a11ba2991a7dce2be2231ed6ed1c3a09ffd8ec66976acb0858654e3380cd7a363bdd53dd3721352b6db4229bc6ff048669d2a0cdf0e08df945da9472b8851a12b8d786771aec2fda0b74d6a9c977e206715ebd92a6bf35ea3d94367be1ce0f4887d833679f2cf3bb360939415026767fbef66b837e05f6b0be033793fa97703c47e7776478f27eb624db2c180e37cf44fc664ef0c7116207b9cc40b3cc5636f9ee23ede00cea2e5d4accf2388ac1dfa13daa3c65c2bedb5629b150e3545d3ae56611de5951a9817a03c5cd5dc76bcfebbb76fdf5cd0762f60d1665819f1f6c78b1e7d9c4e3d567c401af863ad6717f4f9e3175a5d1ba15b4846e569f1c085acd2e4bf01098f43152e039518d0497c6ea3f4945fa18d03cfd734eccf3f9959bfd06cb2a1b96f6169d0e7cd19fb412c079c79f606a505c0bbc1d97af4e60c7ac6fdb89133eab81d4c3d67b1fa5ce5aef1fdedca1e8488ed985b16826dd0d622149af2d4b56538ea9c89b6797870377ab2d8f2fd2483faafb1a1b2ee1e84550a9a9442c73e44a25b772008c529772f3dad22fc8e345ea64b5f5f8ae554710d8d67dc379f73bb82715f0066f47f9e7a7fbd2d8c63df57d7ac538ffefb665b1b95c42af67eb5ab97119ef848ca73238d3de4e771e92fe98275798755c33cd07548e0a708ba42c1343bd49619f9cff4e6348fa27c131dba98e54777350e479f090015821ddb03691ee61acacf18465a0504175dc8a6a34ae98cf1399761f54c4ae59c4cfee45c713f114ea2fd2233140e5b4d9065f7fdf97caec59cce0a136f1960aff4f864320525e02f19bf026250ac8ac7ece64be8f6cbdb1a18eba9d6b24e4db7c62d79de687125c575fdab99e7e5425443e96385475a8434d295330745ff45fa3efbfe14e7e40ff6bbb1df1bb08580a1169f40ed96bf549122cde14d14bf3bbf1f95fb4be93b6177d5b8c5172df27d5f17bf563110c6412af795ba377d8bdf59c573bf744cac3b2519565a9511c96641aa250366e53c49696624fcdaacb25f9b059d21823c11606712f234e9783d2579a18dedf75cb2a39d333c0892018c3c1d4a78cbd921bd3ca6cc645bb3f269cf520a57e2670735c080a9bab9c11ecff02accaffc374cd754fac6583e962dabe67ea574cf59a6a819e54ac0e6d93326cae5a05ce975b36546a33cdd2c6b829d0af36c7c01ca96929252eff4abf2cdab948d8a318a4cb4a5f4b28d4c4fc75395d4d7e7825f389656d9a5cc0a55d64909413d66ccb0d8ab609925b5a20c56dc87f9cc337e1589c28a3794b30ad601e550eb275f3f1f47f43e5e624dca8fe0821ee2be9c87fbccd97b1e8147b11048cbc3117efb0096142f5e1c8e9e3e7f3e9a1c1d4cf5a45084a5cfad64ea6fb197c1ad33a7a0b28c9ea8686967ea2b171ebf614f76f79eb1eff9a59ab2174acff3fb5233856b3beea69d60f84182742b6df6f325a4ebda44df7703938a078149128fb906667e21c5940243b2511e7a1ad68dd3245cf0a0b5828e178966c71ff02ae7f9cb9fd985bb08806aad75134f4bb0545e24f125ac2b2e3cb7557b21427621bd856a1df00590d3c3e0ce42fa326aede0ef601948e8629e68cf18cc1a50c90d392993a1aa28d7a6dff7209c066f6de19db5fa486915d053ec548aa09dc2168f4820e130c9bf6e45e97c09d27c91005e57bc7594b750b664e70a64ba038eff102296002a0f792886d2a4fcd8c1d5a52482a1eb277470bcc2c346cde26b4ac6a41919a7749c13733ea95989a70b08d2ec9d95a4a573e5c3923a062999583becef0a0fb1cc350f021ce447284dc0b8c1749c3bac4dd29eb0b4194609419cc695ac9df521d1049cca789ab89722a6612fc171901cdce909a8b00fa0a36a2f568d7cca4309020200a8084c58316070bc1d369e2b35f705a5278d2626044379e9cc1550207fee1e758ff0bdb015d741bb9413d5527d42d10b97bb0bb0488ae789af93eee19f02a911787616ba6b8df97bf27b32c1d8808f87724647d5dfdd033e6327301921aa74f663ecad3526d8f95eac115d71257c6f0a04aebd5931bb3b20981ae4d3e33a616fb5c4a790af33fc958c75124ede73dcd82bfde818745d3e46d18045f877938acfb1fdfdfd453752bb0e51d44ee14eff1c223e229e82450f761a8f08abd1d18becf70a2eb503bd05e70d54687da44c2f158607fe302e9882b15ddf53dcf018f4f8777b50924a8f3a2a3ab9e2ba431307ed593160b0dfdf27422f9d27e3ddf1d3feda39d926bf9b4941c3de7636a5204aa8e941248a6a15c063a0af0980d1120740d7ff0f0000ffff010000ffffeed101e31da30000") + bs, _ = hex.DecodeString("1f8b080000096e8800ffec7d6b77dc36b2e0f7fc0ab8ef249666c56ec9763cbb8aa4bbb2e44c9487ed23d9379bcdc9ce4193e86e44244103a4e41e45f3dbb7aac0f7a3c956cbb6eebdf9608b4dbcaa0a5585aa02503c7874fafae4ed2f6f5eb2451cf8475f1c3c729c2f261376a2a2a596f345ccb64eb6d993ddbd67ec7b7ea9a6ec85d273c6430f6a84b196d32456dab02d23048b17829dbc7ef5f6fcecc5bbb7afcf2fd84cfa627b8cdd1dfb3ea3ee0cd3c2087d25bc317b6704533368260d332ad1ae60aef204839f73752574283c365dc260eca7b3b78e8997bec0be7ce98ad0e0703c662e944e059ba904409221c1f0e3d9c9cb57172f69f8f1178e03582172cce7e1fc7024c2110be70e8fa2c39159862e0c1fcee9958b1829df17fa707491959cc4da1f31d7e7c61c8eb092aff8e508bb14dc3bfa82b18340c49cb90bae8d880f47493c73fee7a82858c471e488f789bc3a1cfd1fe7ddb173a28288c772ea0be816461421b43a7b7928bcb928b50b79200e4757525c474ac7a5aad7d28b17879eb8023238f463071097b1e4be635cee8bc3bdf16ea3234f1857cb28962a2cf5d5a8c69378a174a3862fc34b98381f2806c5b19bc44cbad8d3428bd9e168c6aff0e73802421e7d810d6219fbe2282722fb83dddce03cbf82f97d05236d6ddfde1e4c6cad7c00dbd954a9d8c49a4713d79849fe6b1cc8700c6f46291cc80d6621443caa77a08106d77cb9a232fd66f132028c63f121c691a884b1a9f296ec861e198bb8e701f4ce54c5b10af6d9df76a30fdfa46533a09033e381f497fb6cf49df0af442c5dce5e89448c7658fe62871d6b989a1d6678681c607d39b35ddc7e417f167b3b6cf104fe3d857fcfe0dfd7f9f0d521ce2d5ad0f706a325feff280d10703d97a113ab689fed8dbf1641a5ee1849e3042a5426e2209bad60fd24425fedb09f54c85df80b4ac128901500f204245a0a0d205e03847937b52138c8010a9e8722ed1dc52455b13e42ae6e96e2ec7497ce8057ba4bf39ebd953db796e63d7b3915a64a7b425bda852aace1e5abb9aa91799fed7e53e5abd21beac6f9ba60af481989c2ba8f1c0ceae2aa3e8034b1132a679a80be8af3a1e835b1b783ec6d41ab3504c4fc2408f3369e3491cf612e650852249ca9afdccb0c0e903aab6480fb33fec81987343ab04e5130e5eee55ca332c6519406f0e7d3ad274f9fefb027cf76f1bfbded6faa14d4dc9389d9674f4bc867f4d98b3eb067c5fb8c904fe0f593ecf56d1d2f60b370ec71d069353ef7c50ca0dd2d18bd82dede6ef19a389ffb728ef44724bfe9a75546e06c8d68d217e7823d92012a741ec62d9200cb57deec7a2163e190cc60d36bd08115dd732d2cf59fedeeb6f6e435d498c5ff0928b13e28bcb109b8ef3b152a76029436fedf81f024675b01ff90d2f46fcfff167dd8ce3b48e50a0c8008d404b0f4917d5396bebc326393bf02ef83191033cef26580c1221be38a22c6f3f17e5e97fd1588a241cb4c61cd67d102286d40a81820a1ae194ed5540b7e69d044f01534d722d20adaf8c08213038b37d81ad7325e947bb4fc64c6ecaf93fc758d081ac894cdca6dce8e07131241301226d64af8e28030c4224f5ed56d8d9757b0d4929d7174308172bb848221c6deaa08444a33b461f05dc8af7253845f6189fd836a287bf4c48c273e580cd0bda07a72ce69ddb72b1c419076825070208e4ecb706d04e9a98ee14c35d87b009b0ce65909eab71133dab58f0e09ccf3676401b00571e6e1e8e99311b3d6ca686fef6fa3096087bde74345b571b013b6901e685de7032cc86d264394b74efc52f30cf9d223c96d8e179908487809164212cd41eb88b370a6c6a1b82ea14f15c1a68d5598da07f6476e014ee3301b001fe15f41706b7e5853128cd4cb7ca0adedea00651acffd65b440eb89e54f8ebb10571afe26d128a3d9572230b9fc179d80488406d607513c3957dc4fe07fa10d4cfae1e8e6a68c2ed630f1edede8e89d7d0b3cc66ebe4c6b7f795b9d221a68624950a2e4c49755baa6b8785a459eba0eabd8f29430ff36aad703b69dcfd10e463d93fe28f752c3f1e8a527630be0fbafc229d0e3609a733248708cd49ac23f5e19bf60947cdc408449054842e32807b53c87a03ccf45a4700e7b276ee179b519aba370ec790cbb83d55de9655a1521ae12b50f22148a41100155ae85a54c0f54d8651f3c3921e595f4506cd6801a1687f8c22a6f33087457cd7bc0cebabb1b19e5702abed7e898f641b380a5e6ecf463d2d02c9218197810d06a36eb85d8767737fac13a1e731d0f64c319545ff4c0736e7bfc9814e453950c0319566e1d3b2288e2659ff4609f2b803e98247ebbf62c4ad2851f1f6079b1ab7dc7426deba379f0add4268675fe7a87a9d05f3270ceaf4326672c14ae3086ebe5372ca529bbe63a44bb2935250a4b0417c447d0ff4ccecf42f4d873350d1d1776410518df093c67ef4979752d95031d84cfe87f271db6ba22d4eb22ad3daa75b0785a5ad32a75285830ca7804dc4ae1090f0caca74739edba0740f3abaef0a3d214be5d60ec096990683296d8821b361502dc097e8571a82406730f4c51177c3168e18d5911dd08129c861430b43ad34a148d0203a3daf5b864c554a6be1b7cf43f6b56ca003b058d1313946d141681bb985a469f5492eb264483a57c90b699fc306a99ccea8bcacfd28fc272ae0a8798273ed8c9c0cb35d6af3079d61f362c966772a7d9161ad7e83b6d173db40ac4f355f2e0a05b1c8d98f490dee9085298d592914ad1cd0d3639c1822d7c1a9f9d82354c53083f058f6d9fe8dde0df1f01ec9acdb952ea2af5a02608619be8d5aa916957b1dc800e3e8f4c66d0456093610cf1df2af866d620be04c4fe22434f7c4083b4d1fd004bb96c70314b25a0cded6d5f5f851c941c0e24a70127d05d58725ec43c4e0a82b742d834c4f34e9ceb8500fb3b092f43b266dfd987a6853dbc2f03ac180940f9c23e6cd497cb43ab9a2fd2a7fede1a7d800a6ce3a00e182820dc3310635b3737d8ef1ba15d601f3e172596ff72bb1dbab521975e2b47b7837d06953f21cc5d2535c7c6be82f5af2ae675fd994a7ea677ca225795f24c7a592ec68dd186acabf58af5a04fbba0dbc053b909ab4561d3df26d69244a09da8711668692fd55d4558b8e85ffd606a7b57be7cf528f902d0f78a81bd1c710ca3a4818b923683f65e274e936ea436c7d706c81c1589b007ef6fa9e63d207c2ab570917e1be19d59b601f86dfeaf29257f1bcbf08afbb28b7b069325b56a1d23e77d7479a9b5da902ced387c4eb698fb6adae70eff1dea70bf2dd8711f449853efdf4a5f18f607e3fe355f9a57493015faf6b6a1bf650c10a6c3efb07f7574f662195367531972e4be179f8fbe0b15f491f747e57e3ceafad8f93d1197fa7a40b4757d95780e863d7cc5fbc275afc1ed7b3d23576f130277d7e71d8a2a04f7d64ec011dbad8680d435fabe85599a45399ad35874b2f12c62572d93d830484aa86576d74aec0e0f01bda3dd1e7876d98bd5f61731cd676228dc02ec61a39fb801ff9da4f5a3b051abb58f74278a9f839ff73af4c150fb45983e3a7676f5a8d6d72bf570a72409dd85702f459f789fcd43a50503b33d90063740cc67981e0b04c260ee63862add3de449a25d5787fb7d9b13177677f667192f365be46840439b3948a9edbb5a5050d2e5654011ed68b7f86e0db78c5eb70725da7d24be3ab857d980c465a2358a811af7317abf8f6b1140978739696cb8e3fe6281d077293ebe0e6e9196012c366d9babb8a1544ce60070c18971a5df67afe77b8c6bc3eaf1702ef4a855f7b2afbe624397783cfba8a5275a96f87ecd170db16ad201d8c9024136abf06dd71f6d51863b046ecb6157dc8c2b055c490eee2de21a42e7c342adb9309562abd8fa6436c7f0eaafd99184adeddf1e4e80d5a2974556f19783700ed9e52a7b1aece626cc4e5ba4389392dc30ec54c0d313700202ff19736ac69c7a15ecf14fec5d2c7df94fda5fda70915c82a91a8ce1cfc370d7626e2e4d0f014edebcbb7702b8519246736bce13fc0c6145d5dcdfdfbbbdfdf23f89237b9a5663e7f06b3302c1d8a17091d0e6d7c7b18ab9ff188352d308392610202beeed2dfedaeaa87b169227f9167f96996cfb73d372d0e2f92efa987454493c9c90af93f8fe2999992fa91c00c8c761a8c0a312af7f608f0e5902ba7126c34e753898e6787479a1745f00351b9d5de0b5918d42a9bd2e5576b0048fbd524393b8789262b48a28cd736aafe970700ee93077ae3176cd9c7c3470ecd96c8dc13fa75eefdb49f90f7b267133214b0f363e6457efaebe0f59a19999f691dc9f8dadff0116b7353aede186c2eaec32c055bc101a51370fe984438b01bee9d186fac9cd963e5acdf5beb15a8f3ef46c9da3fe29af40e968639c077065d1b9755510f9028beba5e37fd07a858187bdddddc19beeef223c4a755a2cb36c0b9a6f7200e05eb038580b89ea8107bb90f78d00f625199afbbb1b9c7768060757603e3a3a95262d5f75a8e4a31d4ca80bcc9f07132a8543362164d8b70971ec7980ec46116eab70b0a34a7ce0b359ed2a0840fff6c58f4106175a85f7e21d0e11dfbab75848f367255584b3dfbb258297b24fd2caeb50aba17032f2943a1bb5d194763cbac9d2d1fba3a1dde30ec87f670fbdcea5031cf57a933ffdf55eaa0e71dbeb6d3e8af7fe9fc32b435240471b2f227fba671f7173a678b41b3493ea197a7c4587db4cfb9d128165f624fad817e13c5ed87daecf7bb9a4cdebab13f9958aa55b288b4d6e98947c58a007faaf25b2e0c878cd1a0402de8edfca40801a00c752ec8fbedb0f827d6346b7b7fb0008d502776fa6a5083d7f69fd5f6c443350bd19db3edff770a7a4e43976ed40172240373a2c7f0cbbadd667bebefee1b3dc26a948407e0d2bbf918daf5f507a906117b5b38b38e94f005278697e91863bde7353bbeb0274f5ce73497fa555c85548951666a7d99f008ae0fe25da88719e11671c8a78d2948d8b24c2c4016cc2be553a093a6fbd0d1ad9c0d073192f92e918ecd3493e76e9490b984b234c13921fe926333bb71536036405095c1866aef472e22937416f23bd4bdf34df4ac51f9d2cd298a48d282f9215b761ef69f016a6b0c99b4eba6f10afbee848dbff22be56fad2ea473c2a013651264df617050a6c2dd22b2366e8680bc6cc6da41c150928da0f806140f3600f6833d2f37813fef1496e8fd9b5eb3128dc1c8f3c5257b91a986250dcf63302f413c6a6a682a16dbfc300608c4a52e62ace22adc0f008289d045b0269d859186336ab9815e6e0181837d64be8efab85f07d99deed4fd5f8c184502ea893dea7a3cb861da4d179958c10d9f19c12fe453f75cc7362ca70a6723a34a73a278334ac18729c45b8eaf5df9074b26b9edb2de3f1b80b4b9b92601592495663058e792ff781623ee0fd6098ddb8ee4430bbe19de18797b873b8f3dda814d9bcb7131b95106dfc5ba0535c698576c4ba9d709e9d764228bdf7206a3ed77380608951ef0a5941bd289395581cd2dbf3a529a2b33e67b0d8c572265d12d5da64b1af028f9bc537e5187771f466bb10d5d21a790d82c4f03f344b6ac9abe827eee6e30a7a73132cedbd9a62c1c7e426d9616528cc8d1edbc626fa6150c901d5184c430ea6bacd7ff25e4ffe1d7b3fcc7a1d4d5a494a38a363d0506f591434f31af2b16db51927e2f12945470f47ce5e0bee54d5f124f7552a3d8e3f6f35b06d619ae0adc3c8b675d070aee746593cab5d29a473868f107460b1971fc0b025e9ac7494dad9459689c5b3019d0eea131da2964eeb665e03b786b97e30533a4873e6e0e328cd8887dcf792666dc56e1336c88e9b91094c6f6f1e83c439b4a03dc664415947e3902200e3bfa4377970e3a1a5d4933a5e36378f0e7c3e050fa820180c6ec104ae3db292750a6b2fd66ab495618417d9d3185a83c205ca28015964be240d84689abba82662a352423da2021d7704014a346e92216069e803b3f2bd4f241eea25fc1d1c447a60301078adc1fdcca9ece08915a24fa19b060c15e12f8d95e724825539b252dfb68dd0bec7d232897682fff8a36d82234d580084987e20b433878605a91c4616455b7ecb1131fd114b138e8c582af6ca16d30e2975376617480143f93a519de22374aa280f24a8962d4987c5bded71e7d64e13d376914726deba2301c03ffc7901eb92cd53062614e64cc04a3bec528808f10e40f9d98c9f942e94884569178038d00c58a982bdc1d3adb152ebe0d5318324bfe39c6357c86a751ef152b522f8a63e0f2fef0d1222e82b92987e60889300ea0c284f0943792c7ca52eadf48dd9598c994312df2362b2af9fa041fbf573ca69ca5d6445dcdb82897171a3ccceb69a313038a0cc3297dde3303bd6e8350dae9b0a6a94f25d072d6a318cee2dc3a6d61da824391e7625158906c56a2519f980c4826eb51e8ebe5341760029d58bd8559b561ca406b93d74dbaeeea2263334f517eea657ec94b2bebab079604213c30a8e5395ae0a990271fdc4d86945c36dcc7e96a03d499030dd9ea43d4d55d2233095389b85de28a21881a8a733590387471f018724c2001a2140d9570042fb80cd73040d66c9c19c1e8c12fc3471b86fd6e376f3157df6e3ec710dfef39680887489a13c6930b2edad660b64d262d0bb726a0eeb45ac87716ccb54bea4e50c376b3938cf1128159ca0918cf66d6ae31c4cd43b05aa308391d06496f12456e8d1bb8cc23430894b9b395a648d87cf60cdf8b910fe6c34645acbc138bc5c36551fda2c83d6292d4daba579de4307ddcbbb9a4d97b37d8fb665a7a39dbf066d0f2029d6b0a75ba2c983f213e59b28a51baefc4aa499d9aaec5e5aeafe925fe4df3cb07c01e3ad082d0f42230f80d3b1300019ef13a6b41974912a50577d37be4fd0b11e0068bba98cb64295e757234421359b2f0af5647982805b452c0627cf03d32de93bc17f4a5d7622d713a6afc4ebb3144efdbe36d67ae0bef69a1ef6c06c934df77b3da7bb6d57b26f9cfbf3c8f1565caf475ede5e6c2b6fdb666cab37c4b32f001ae363cdb36f29edf0ec696c6b3d90cd60ab37c9dd9e62a66fe1298887e641d5ba48f72e4c4de13698214b22d41111e8b128ceed75c692fb9f84f27d8267f0405ca17ac4d1a3080f4793fff72b77fe79ecfcdf5de77f39ff18ff76b3b7f3fcd9ed5f269d2608e139cc77a7aaed3e57cb54e5ee6b4b59e1bf5fe05711803a36a0097a7366b704589ef96c39663fa5ee2abe3768968296e4be9f5bb2646977ba89eb816d5d454b5e5273e40dea32e3e4eeb3ad75af0397bde52efe6f0369a8cf7c179852e65a17a43cc8c04c7d92b79e3f2b7c64325e7d30c8b6dbdde49dcc4726b7187900ff7980edd6787b87fc64b6e56c53295eb1d186be85b2f58fedca18a1bf5c41951657acfbc0cb665aee0d8f17abf49c2defd774353f296b3a2a6b397cb18e82a30eaa2aee5f93d342c9656accd6bba322cbf35415faec936a274be02efd644b0b0d85bf339fb8c4e069d08c72f4d0e1f704d8ac70a65d2dc857036759c645f048e0823066282cb104fa9622455bffdace629609c6113070c0f28fc6ccf25458ec00d9bbb86e49fd6050965e8f37a64baf1e2af16743ec2324d6705d345cea86b85e77b2639e0f37635a3118e6dc52d54e31a4d2814eee7935974cc3c32d09bfcd9db3722558a11ada755f7fccc22666c06079a4c1b3c57b116ca65580ac8e29135880b9f355588e92ed5096e07a85225e7d9d4a95c14bc5b92cc2f29286325243a02da0b6ae167f38935c4947d3ccacd99580e7934e34c699d2f1d954c676ded3ad1186f942295c8eeb39da75e904a7df2f0bd9b7c76fe953635693b544a256c0b7cef475eefb9991cd91432972284eda155aac0f5999bcf265bb9e9b765598ee854f8cf049ca68403a2b5ddc4eaa5f746bbfe5f671f8e382e0ca43c874f087120959c12ead1ab8f5b1c6e4b7bffc2fa2da8dc40329285be979713a37d6107f12bea2c6e753f2187ea33d03dc3cc03d8520c2dd690b197d3588b3b189f317362faad50dc00268697ae800d8d0187db6b03846784f56796913a59bc643cc77dbf00721a22e03be5c636d13be683c3ac2ffb3095ea994ca267ca9037b26aaf47b85b16efdabd51c693bc9cdc2408687a3bd4f175528d3b5cd722f97d74e07d8db64602900e7158c091c8b3be43bb882d9ef5d6ee63297015869423738a40e660e62e140a785e8e1deafa3df841a26b61fe05f5462a1a343063c6678920facb15064d0dfd1e8bf870d9754130c396bd57276a25895da4f5008568921d241c774d73796255748d27a371764e34ee9427a98c6a9d0fb5b92ee74f1f823d8b4f8c1c22b41d34b540d78ec2ec05704c7d05fe6ad31e29545baba8fe27f822da6f4a34ed588678961fedc625a778b69e32da5c1dfd9fa0c5b4ad9b7a63af693d2cf129a07be9fd430872afb3ac5f7b4ee79e7a62fbef1f1ade0564b05af6189908e36e02969f6065c7d0503325bc0fa4e6a50cfd672411e28ba5b27a61807d16b3a5763c625783e9903f913ff702142ef87690402f53a89e70a9711bc2d0b540864ccb67e902f26667b1809cabdad67ab95c85001e99311c2a629a5ab1aa0f72f4669de5296bd615b438950efe9ce846880349818f815f78f40a1f4fe4a8548e9bb3bd1a9d1df06a46ac2f6c958e70dd760d608ff1c6c656162e05a606106c2048e6448665956328c308dfeee4c9626649f52b1d8f4b2568e9122e4eedb9756c3acab5b4a1d6ea25dca700da5072ef89bd0e8dec230f5b31721e5a479f7267c936fad1434c3d7b686375a11ba2991a7dce2be2231ed6ed1c3a09ffd8ec66976acb0858654e3380cd7a363bdd53dd3f2219232fde2cb2a5ada2a6b13b3d1ec0151b355f9e500a767c61bb4c9b359f686c4caeee9a35534a912383bac7e374bb401ff5a31edcf64cea7e63a10fbddd91d4df8ac8b35c906038ef3d13f1993bd33c45980ec71122ff0588abd4a891b5303388bd607b33e8f20b276e84f68601973adb4d78a6d5638d4b64abb5a857594576a605e80f2705573db79f1efdebe7d7341fb9780459ba560c4db1f2f7af4713af558f10169e08fb59e5dd0f77c5f68756d846e211995a7c50317b24a93ff06243c0e55b80c54624027f1b90d3b53c280360e3c5fd3523dff6476ea42b3c986f6ab85a5419f3767ec07b11c708877d83d77bcec9aad476fcea067dc601a39a38eebaed473167cce55ee1a1f94ae04d5456cc7dcb2106c83b616a1d09478ad2d654fe74cb4cdc383bba292054bef27bbd17f8d1d827583ea562968520a1d81f544b786d409c529772f3dad22fc3032de0e4b5f5f8ae554710d8d67dc379f33feceb82f0033fa3fcf25bf5e4cfed8f7d535ebd4a3ffbe59acbef1117c11ba7a19e11186a43c37d2d8536b1e97fe926e0c97b70c35cc03ddef037e8aa02b144cb3436d9991ff4caf02f328ca7785a18b597e1655e37094f71e5408766c4f5879983c273f34176915105c74c398cedea433c6e75cd63eaa5f39f8913f3957dc4f849368bf487584c356333ed98d6c3e9f6b31a7c3afc45b06d82b3d0f984c4109f84bc6af8018147ce131bbf912bafdf2b606c67aaab5ac53d3bd5e4b9e375a5c49715dff0ce479b910d550fa58e19116218d746513bde8bfc84767df9fe29cfcc17e373681be2d040cb5f8046ab7fce98514690e6fa2f8ddf9fda8dc5f4a1fbebaabc62d3ed1906f64baf8f98581300e52b9afd4bde95bfc70281e64a5734fdd39b6b0d2aa143f36ad4f2dbb2d2b27fe4953fde0e75395fd7c2ae80c11e499ed3ab36aa759b4eb39b60b6d6c3f50929d559ce1c9860c60e4e950c25bce0ee9e531a5dada9a958f2f967292123f3ba801064cd5cd0df67886773b7ee5bf61fea1d247b3f2b16c59359929e52fce521fcde8f23f36cf9e31f32b07e54aaf9b2d331ae5f9535913ec549867e30b50b69465937aa75f958f38a56c548c51a4562de54b6da42e3a9eaaa4be3e17fcc2b1b4ca2e6556a8b24e4a08ea316386c55e05cb2c4b13a564e23ecc679ec2aac87c55bca1244cb00e28875a3ff9faf938a2f7f1126bd2857f17f410f7e53cdc67cedef3083c8a85405a1e8e30993f2c295ebc381c3d7dfe7c34393a98ea49a1084bdf0fc9d4df622f835b674e4165193d51d1d2ced4572e3c7ec39eecee3d63dff34b35652f949ee71780660ad776dc1e3ac1f08304e956daece74b48d73d80be0fe125150f02b3fe1d730dccfc428a29058664a33cf434ac1ba749b8e0416b051d2f12cd8e3fe0ddc4f3973fb30b771100d55aeb269e9660a9bc48e24b58575c786eabf64284ec427a0bd53ae00b20a787c19d85f465d4dac1dfc13290d0c53cd19e31780dbe92ec705226435551ae4dbfef41380d5e43c24b58f591d22aa0a7d8a914413b852d1e9140c261d67add8ad2f912a4f92201bcae78eb286fa16cc9ce15c874071cff21442c01541ef2500ca549f9b183ab4b59f142d74fe8247485878d9ac5d7945d4833324ee97c22263152b3124f1710a4e9282b5938e7ca8725750c5232b176d8df159eca986b1e0438c88f509a807183f92577589ba43d6169338c1282388d2b6928eb43a2093895f134712f454cc35e82e32039b8d31350611f4047d55eac1af9948712040400501198b062c0e078dd693c576aee0bcab7194d4c0886f2d2992ba040fedc3dea1ee17b612bae837629c9a7a5fa84a2172e7717609114cf135f27ddc33f055223f0ec2c74d71af3f7e4f76482b1011f4f998c8eaabfbb077cc64e60324254e9ecc7d85b6b4cb0f3bd5823bae24af8de14085c7bb3627677403035c8a7c775c2de6a894f215f67f82b19eb249cbce71af02dfde818745d3e46d18045f877938acfb1fdfdfd453752bb0e51d44ee14eff1c223e229e82450f761a8f08abd1d18becf70a2eb503bd05e70d54687da44c2f158607fe302e9882b15ddf53dcf05ceff8777bf28f4a8f3a2a3ab9e2ba431307ed593160b0dfdf27422f9d27e3ddf1d3feda39d926bf9b4941c3de7636471e4aa8e941248a6a15c063a0f4f860b4c401d0f5ff030000ffff010000ffff4d36b2e6eea10000") gr, _ = gzip.NewReader(bytes.NewBuffer(bs)) bs, _ = ioutil.ReadAll(gr) Assets["index.html"] = bs diff --git a/beacon/beacon.go b/beacon/beacon.go new file mode 100644 index 000000000..fd4bc162c --- /dev/null +++ b/beacon/beacon.go @@ -0,0 +1,46 @@ +// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file). +// All rights reserved. Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package beacon + +import "net" + +type recv struct { + data []byte + src net.Addr +} + +type dst struct { + intf string + conn *net.UDPConn +} + +type Interface interface { + Send(data []byte) + Recv() ([]byte, net.Addr) +} + +func genericReader(conn *net.UDPConn, outbox chan<- recv) { + bs := make([]byte, 65536) + for { + n, addr, err := conn.ReadFrom(bs) + if err != nil { + l.Warnln("multicast read:", err) + return + } + if debug { + l.Debugf("recv %d bytes from %s", n, addr) + } + + c := make([]byte, n) + copy(c, bs) + select { + case outbox <- recv{c, addr}: + default: + if debug { + l.Debugln("dropping message") + } + } + } +} diff --git a/beacon/broadcast.go b/beacon/broadcast.go index 11d7d723d..94067892e 100644 --- a/beacon/broadcast.go +++ b/beacon/broadcast.go @@ -6,16 +6,6 @@ package beacon import "net" -type recv struct { - data []byte - src net.Addr -} - -type dst struct { - intf string - conn *net.UDPConn -} - type Broadcast struct { conn *net.UDPConn port int @@ -36,7 +26,7 @@ func NewBroadcast(port int) (*Broadcast, error) { outbox: make(chan recv, 16), } - go b.reader() + go genericReader(b.conn, b.outbox) go b.writer() return b, nil @@ -51,30 +41,6 @@ func (b *Broadcast) Recv() ([]byte, net.Addr) { return recv.data, recv.src } -func (b *Broadcast) reader() { - bs := make([]byte, 65536) - for { - n, addr, err := b.conn.ReadFrom(bs) - if err != nil { - l.Warnln("Broadcast read:", err) - return - } - if debug { - l.Debugf("recv %d bytes from %s", n, addr) - } - - c := make([]byte, n) - copy(c, bs) - select { - case b.outbox <- recv{c, addr}: - default: - if debug { - l.Debugln("dropping message") - } - } - } -} - func (b *Broadcast) writer() { for bs := range b.inbox { diff --git a/beacon/multicast.go b/beacon/multicast.go new file mode 100644 index 000000000..586393231 --- /dev/null +++ b/beacon/multicast.go @@ -0,0 +1,70 @@ +// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file). +// All rights reserved. Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package beacon + +import "net" + +type Multicast struct { + conn *net.UDPConn + addr *net.UDPAddr + conns []dst + inbox chan []byte + outbox chan recv +} + +func NewMulticast(addr string) (*Multicast, error) { + gaddr, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + return nil, err + } + conn, err := net.ListenMulticastUDP("udp", nil, gaddr) + if err != nil { + return nil, err + } + b := &Multicast{ + conn: conn, + addr: gaddr, + inbox: make(chan []byte), + outbox: make(chan recv, 16), + } + + go genericReader(b.conn, b.outbox) + go b.writer() + + return b, nil +} + +func (b *Multicast) Send(data []byte) { + b.inbox <- data +} + +func (b *Multicast) Recv() ([]byte, net.Addr) { + recv := <-b.outbox + return recv.data, recv.src +} + +func (b *Multicast) writer() { + for bs := range b.inbox { + intfs, err := net.Interfaces() + if err != nil { + l.Warnln("multicast interfaces:", err) + continue + } + for _, intf := range intfs { + if intf.Flags&net.FlagUp != 0 && intf.Flags&net.FlagMulticast != 0 { + addr := *b.addr + addr.Zone = intf.Name + _, err = b.conn.WriteTo(bs, &addr) + if err != nil { + if debug { + l.Debugln(err, "on write to", addr) + } + } else if debug { + l.Debugf("sent %d bytes to %s", len(bs), addr.String()) + } + } + } + } +} diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index c86c7ad39..c57d64775 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -985,7 +985,7 @@ func setTCPOptions(conn *net.TCPConn) { } func discovery(extPort int) *discover.Discoverer { - disc, err := discover.NewDiscoverer(myID, cfg.Options.ListenAddress, cfg.Options.LocalAnnPort) + disc, err := discover.NewDiscoverer(myID, cfg.Options.ListenAddress, cfg.Options.LocalAnnPort, cfg.Options.LocalAnnMCAddr) if err != nil { l.Warnf("No discovery possible (%v)", err) return nil diff --git a/config/config.go b/config/config.go index 7b9a29158..61a19eb5b 100644 --- a/config/config.go +++ b/config/config.go @@ -113,6 +113,7 @@ type OptionsConfiguration struct { GlobalAnnEnabled bool `xml:"globalAnnounceEnabled" default:"true"` LocalAnnEnabled bool `xml:"localAnnounceEnabled" default:"true"` LocalAnnPort int `xml:"localAnnouncePort" default:"21025"` + LocalAnnMCAddr string `xml:"localAnnounceMCAddr" default:"[ff32::5222]:21026"` ParallelRequests int `xml:"parallelRequests" default:"16"` MaxSendKbps int `xml:"maxSendKbps"` RescanIntervalS int `xml:"rescanIntervalS" default:"60"` diff --git a/config/config_test.go b/config/config_test.go index ee21a59b3..582276e0f 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -30,6 +30,7 @@ func TestDefaultValues(t *testing.T) { GlobalAnnEnabled: true, LocalAnnEnabled: true, LocalAnnPort: 21025, + LocalAnnMCAddr: "[ff32::5222]:21026", ParallelRequests: 16, MaxSendKbps: 0, RescanIntervalS: 60, @@ -200,6 +201,7 @@ func TestOverriddenValues(t *testing.T) { false false 42123 + quux:3232 32 1234 600 @@ -218,6 +220,7 @@ func TestOverriddenValues(t *testing.T) { GlobalAnnEnabled: false, LocalAnnEnabled: false, LocalAnnPort: 42123, + LocalAnnMCAddr: "quux:3232", ParallelRequests: 32, MaxSendKbps: 1234, RescanIntervalS: 600, diff --git a/discover/discover.go b/discover/discover.go index c9287ec16..901dc6e35 100644 --- a/discover/discover.go +++ b/discover/discover.go @@ -26,7 +26,8 @@ type Discoverer struct { globalBcastIntv time.Duration errorRetryIntv time.Duration cacheLifetime time.Duration - broadcastBeacon *beacon.Broadcast + broadcastBeacon beacon.Interface + multicastBeacon beacon.Interface registry map[protocol.NodeID][]cacheEntry registryLock sync.RWMutex extServer string @@ -54,11 +55,7 @@ var ( // When we hit this many errors in succession, we stop. const maxErrors = 30 -func NewDiscoverer(id protocol.NodeID, addresses []string, localPort int) (*Discoverer, error) { - b, err := beacon.NewBroadcast(localPort) - if err != nil { - return nil, err - } +func NewDiscoverer(id protocol.NodeID, addresses []string, localPort int, localMCAddr string) (*Discoverer, error) { disc := &Discoverer{ myID: id, listenAddrs: addresses, @@ -66,11 +63,26 @@ func NewDiscoverer(id protocol.NodeID, addresses []string, localPort int) (*Disc globalBcastIntv: 1800 * time.Second, errorRetryIntv: 60 * time.Second, cacheLifetime: 5 * time.Minute, - broadcastBeacon: b, registry: make(map[protocol.NodeID][]cacheEntry), } - go disc.recvAnnouncements() + if localPort > 0 { + bb, err := beacon.NewBroadcast(localPort) + if err != nil { + return nil, err + } + disc.broadcastBeacon = bb + go disc.recvAnnouncements(bb) + } + + if len(localMCAddr) > 0 { + mb, err := beacon.NewMulticast(localMCAddr) + if err != nil { + return nil, err + } + disc.multicastBeacon = mb + go disc.recvAnnouncements(mb) + } return disc, nil } @@ -187,7 +199,12 @@ func (d *Discoverer) sendLocalAnnouncements() { msg := pkt.MarshalXDR() for { - d.broadcastBeacon.Send(msg) + if d.multicastBeacon != nil { + d.multicastBeacon.Send(msg) + } + if d.broadcastBeacon != nil { + d.broadcastBeacon.Send(msg) + } select { case <-d.localBcastTick: @@ -284,9 +301,9 @@ loop: } } -func (d *Discoverer) recvAnnouncements() { +func (d *Discoverer) recvAnnouncements(b beacon.Interface) { for { - buf, addr := d.broadcastBeacon.Recv() + buf, addr := b.Recv() if debug { l.Debugf("discover: read announcement from %s:\n%s", addr, hex.Dump(buf)) diff --git a/gui/index.html b/gui/index.html index 2c37892ed..9a23771d9 100644 --- a/gui/index.html +++ b/gui/index.html @@ -614,10 +614,6 @@ -
- - -