1 /* Copyright 2016, Ableton AG, Berlin. All rights reserved.
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * If you would like to incorporate Link into a proprietary software application,
17 * please contact <link-devs@ableton.com>.
18 */
19
20 #pragma once
21
22 #include <ableton/platforms/asio/AsioWrapper.hpp>
23 #include <ableton/util/Injected.hpp>
24 #include <chrono>
25 #include <vector>
26
27 namespace ableton
28 {
29 namespace discovery
30 {
31
32 // Callback takes a range of asio::ip:address which is
33 // guaranteed to be sorted and unique
34 template <typename Callback, typename IoContext>
35 class InterfaceScanner
36 {
37 public:
38 using Timer = typename util::Injected<IoContext>::type::Timer;
39
InterfaceScanner(const std::chrono::seconds period,util::Injected<Callback> callback,util::Injected<IoContext> io)40 InterfaceScanner(const std::chrono::seconds period,
41 util::Injected<Callback> callback,
42 util::Injected<IoContext> io)
43 : mPeriod(period)
44 , mCallback(std::move(callback))
45 , mIo(std::move(io))
46 , mTimer(mIo->makeTimer())
47 {
48 }
49
enable(const bool bEnable)50 void enable(const bool bEnable)
51 {
52 if (bEnable)
53 {
54 scan();
55 }
56 else
57 {
58 mTimer.cancel();
59 }
60 }
61
scan()62 void scan()
63 {
64 using namespace std;
65 debug(mIo->log()) << "Scanning network interfaces";
66 // Rescan the hardware for available network interface addresses
67 vector<asio::ip::address> addrs = mIo->scanNetworkInterfaces();
68 // Sort and unique them to guarantee consistent comparison
69 sort(begin(addrs), end(addrs));
70 addrs.erase(unique(begin(addrs), end(addrs)), end(addrs));
71 // Pass them to the callback
72 (*mCallback)(std::move(addrs));
73 // setup the next scanning
74 mTimer.expires_from_now(mPeriod);
75 using ErrorCode = typename Timer::ErrorCode;
76 mTimer.async_wait([this](const ErrorCode e) {
77 if (!e)
78 {
79 scan();
80 }
81 });
82 }
83
84 private:
85 const std::chrono::seconds mPeriod;
86 util::Injected<Callback> mCallback;
87 util::Injected<IoContext> mIo;
88 Timer mTimer;
89 };
90
91 // Factory function
92 template <typename Callback, typename IoContext>
makeInterfaceScanner(const std::chrono::seconds period,util::Injected<Callback> callback,util::Injected<IoContext> io)93 InterfaceScanner<Callback, IoContext> makeInterfaceScanner(
94 const std::chrono::seconds period,
95 util::Injected<Callback> callback,
96 util::Injected<IoContext> io)
97 {
98 using namespace std;
99 return {period, move(callback), move(io)};
100 }
101
102 } // namespace discovery
103 } // namespace ableton
104