1 #include "connectivity.h"
11 #include <curl/curl.h>
13 int get_connectivity_test_endpoints(std::vector<std::string>& endpoints)
15 static const int MAX_CONNECTIVITY_TEST_ENDPOINTS = 5;
19 const char* filename =
"/opt/persistent/connectivity_test_endpoints";
21 std::ifstream ifs(filename);
24 for (std::string endpoint; endpoints.size() < MAX_CONNECTIVITY_TEST_ENDPOINTS && ifs >> endpoint;)
25 endpoints.push_back(endpoint);
29 if (endpoints.size() < 2)
31 LOG_WARN(
"%d endpoints not sufficient. adding default endpoints to %s", endpoints.size(), filename);
33 if (access(
"/lib/systemd/system/xre-receiver.service", F_OK) == 0)
35 endpoints.push_back(
"xre.ccp.xcal.tv:10601");
36 endpoints.push_back(
"google.com");
37 endpoints.push_back(
"espn.com");
41 endpoints.push_back(
"google.com");
42 endpoints.push_back(
"espn.com");
43 endpoints.push_back(
"speedtest.net");
45 set_connectivity_test_endpoints(endpoints);
48 std::string endpoints_str;
49 for (
const auto& endpoint : endpoints)
50 endpoints_str.append(endpoint).append(
" ");
51 LOG_INFO(
"endpoints = %s", endpoints_str.c_str());
53 return endpoints.size();
56 bool set_connectivity_test_endpoints(
const std::vector<std::string>& endpoints)
60 std::string endpoints_string;
61 for (
auto endpoint : endpoints)
63 endpoints_string.append(endpoint.c_str());
64 endpoints_string.push_back(
' ');
66 LOG_INFO(
"%s", endpoints_string.c_str());
67 std::replace(endpoints_string.begin(), endpoints_string.end(),
' ',
'\n');
69 FILE *f = fopen(
"/opt/persistent/connectivity_test_endpoints",
"w");
72 LOG_ERR(
"fopen error %d (%s)", errno, strerror(errno));
75 fprintf(f,
"%s", endpoints_string.c_str());
78 LOG_ERR(
"fclose error %d (%s)", errno, strerror(errno));
85 static long current_time ()
88 clock_gettime (CLOCK_MONOTONIC, &ts);
89 return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
92 bool test_connectivity(
long timeout_ms)
96 std::vector<std::string> endpoints;
97 int endpoints_count = get_connectivity_test_endpoints(endpoints);
98 long deadline = current_time() + timeout_ms, time_now = 0, time_earlier = 0;
100 CURLM *curl_multi_handle = curl_multi_init();
101 if (!curl_multi_handle)
103 LOG_ERR(
"curl_multi_init returned NULL");
108 std::vector<CURL*> curl_easy_handles;
109 for (
const auto& endpoint : endpoints)
111 CURL *curl_easy_handle = curl_easy_init();
112 if (!curl_easy_handle)
114 LOG_ERR(
"endpoint = <%s> curl_easy_init returned NULL", endpoint.c_str());
117 curl_easy_setopt(curl_easy_handle, CURLOPT_URL, endpoint.c_str());
118 curl_easy_setopt(curl_easy_handle, CURLOPT_PRIVATE, endpoint.c_str());
119 curl_easy_setopt(curl_easy_handle, CURLOPT_CONNECT_ONLY, 1L);
120 curl_easy_setopt(curl_easy_handle, CURLOPT_TIMEOUT_MS, deadline - current_time());
122 curl_easy_setopt(curl_easy_handle, CURLOPT_VERBOSE, 1L);
123 if (CURLM_OK != (mc = curl_multi_add_handle(curl_multi_handle, curl_easy_handle)))
125 LOG_ERR(
"endpoint = <%s> curl_multi_add_handle returned %d (%s)", endpoint.c_str(), mc, curl_multi_strerror(mc));
126 curl_easy_cleanup(curl_easy_handle);
129 curl_easy_handles.push_back(curl_easy_handle);
132 int connectivity = 0, handles, msgs_left;
133 #if LIBCURL_VERSION_NUM < 0x074200
134 int numfds, repeats = 0;
139 if (CURLM_OK != (mc = curl_multi_perform(curl_multi_handle, &handles)))
141 LOG_ERR(
"curl_multi_perform returned %d (%s)", mc, curl_multi_strerror(mc));
144 for (CURLMsg *msg; NULL != (msg = curl_multi_info_read(curl_multi_handle, &msgs_left)); )
146 if (msg->msg != CURLMSG_DONE)
148 if (CURLE_OK == msg->data.result)
150 curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &endpoint);
151 LOG_INFO(
"endpoint = <%s> error = %d (%s)", endpoint, msg->data.result, curl_easy_strerror(msg->data.result));
153 time_earlier = time_now;
154 time_now = current_time();
155 if (handles == 0 || time_now >= deadline)
157 #if LIBCURL_VERSION_NUM < 0x074200
158 if (CURLM_OK != (mc = curl_multi_wait(curl_multi_handle, NULL, 0, deadline - time_now, &numfds)))
160 LOG_ERR(
"curl_multi_wait returned %d (%s)", mc, curl_multi_strerror(mc));
172 if (CURLM_OK != (mc = curl_multi_poll(curl_multi_handle, NULL, 0, deadline - time_now, NULL)))
174 LOG_ERR(
"curl_multi_poll returned %d (%s)", mc, curl_multi_strerror(mc));
179 LOG_INFO(
"connectivity = %d, endpoints count = %d, handles = %d, deadline = %ld, time_now = %ld, time_earlier = %ld",
180 connectivity, endpoints_count, handles, deadline, time_now, time_earlier);
182 for (
const auto& curl_easy_handle : curl_easy_handles)
184 curl_easy_getinfo(curl_easy_handle, CURLINFO_PRIVATE, &endpoint);
185 LOG_DBG(
"endpoint = <%s> terminating attempt", endpoint);
186 curl_multi_remove_handle(curl_multi_handle, curl_easy_handle);
187 curl_easy_cleanup(curl_easy_handle);
189 curl_multi_cleanup(curl_multi_handle);
191 if (connectivity >= endpoints_count - 1)