]>
Commit | Line | Data |
---|---|---|
b6e26895 RG |
1 | /* |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
22 | ||
23 | #include "dnsdist.hh" | |
24 | #include "dolog.hh" | |
25 | ||
26 | bool DownstreamState::reconnect() | |
27 | { | |
28 | std::unique_lock<std::mutex> tl(connectLock, std::try_to_lock); | |
29 | if (!tl.owns_lock()) { | |
30 | /* we are already reconnecting */ | |
31 | return false; | |
32 | } | |
33 | ||
34 | connected = false; | |
35 | for (auto& fd : sockets) { | |
36 | if (fd != -1) { | |
37 | if (sockets.size() > 1) { | |
38 | std::lock_guard<std::mutex> lock(socketsLock); | |
39 | mplexer->removeReadFD(fd); | |
40 | } | |
41 | /* shutdown() is needed to wake up recv() in the responderThread */ | |
42 | shutdown(fd, SHUT_RDWR); | |
43 | close(fd); | |
44 | fd = -1; | |
45 | } | |
46 | if (!IsAnyAddress(remote)) { | |
47 | fd = SSocket(remote.sin4.sin_family, SOCK_DGRAM, 0); | |
48 | if (!IsAnyAddress(sourceAddr)) { | |
49 | SSetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 1); | |
50 | if (!sourceItfName.empty()) { | |
51 | #ifdef SO_BINDTODEVICE | |
52 | int res = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, sourceItfName.c_str(), sourceItfName.length()); | |
53 | if (res != 0) { | |
54 | infolog("Error setting up the interface on backend socket '%s': %s", remote.toStringWithPort(), stringerror()); | |
55 | } | |
56 | #endif | |
57 | } | |
58 | ||
59 | SBind(fd, sourceAddr); | |
60 | } | |
61 | try { | |
62 | SConnect(fd, remote); | |
63 | if (sockets.size() > 1) { | |
64 | std::lock_guard<std::mutex> lock(socketsLock); | |
65 | mplexer->addReadFD(fd, [](int, boost::any) {}); | |
66 | } | |
67 | connected = true; | |
68 | } | |
69 | catch(const std::runtime_error& error) { | |
70 | infolog("Error connecting to new server with address %s: %s", remote.toStringWithPort(), error.what()); | |
71 | connected = false; | |
72 | break; | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
77 | /* if at least one (re-)connection failed, close all sockets */ | |
78 | if (!connected) { | |
79 | for (auto& fd : sockets) { | |
80 | if (fd != -1) { | |
81 | if (sockets.size() > 1) { | |
876887dd RG |
82 | try { |
83 | std::lock_guard<std::mutex> lock(socketsLock); | |
84 | mplexer->removeReadFD(fd); | |
85 | } | |
86 | catch (const FDMultiplexerException& e) { | |
87 | /* some sockets might not have been added to the multiplexer | |
88 | yet, that's fine */ | |
89 | } | |
b6e26895 RG |
90 | } |
91 | /* shutdown() is needed to wake up recv() in the responderThread */ | |
92 | shutdown(fd, SHUT_RDWR); | |
93 | close(fd); | |
94 | fd = -1; | |
95 | } | |
96 | } | |
97 | } | |
98 | ||
99 | return connected; | |
100 | } | |
101 | void DownstreamState::hash() | |
102 | { | |
103 | vinfolog("Computing hashes for id=%s and weight=%d", id, weight); | |
104 | auto w = weight; | |
105 | WriteLock wl(&d_lock); | |
106 | hashes.clear(); | |
50033a8e | 107 | hashes.reserve(w); |
b6e26895 RG |
108 | while (w > 0) { |
109 | std::string uuid = boost::str(boost::format("%s-%d") % id % w); | |
50033a8e RG |
110 | unsigned int wshash = burtleCI(reinterpret_cast<const unsigned char*>(uuid.c_str()), uuid.size(), g_hashperturb); |
111 | hashes.push_back(wshash); | |
b6e26895 RG |
112 | --w; |
113 | } | |
50033a8e | 114 | std::sort(hashes.begin(), hashes.end()); |
b6e26895 RG |
115 | } |
116 | ||
117 | void DownstreamState::setId(const boost::uuids::uuid& newId) | |
118 | { | |
119 | id = newId; | |
120 | // compute hashes only if already done | |
121 | if (!hashes.empty()) { | |
122 | hash(); | |
123 | } | |
124 | } | |
125 | ||
126 | void DownstreamState::setWeight(int newWeight) | |
127 | { | |
128 | if (newWeight < 1) { | |
129 | errlog("Error setting server's weight: downstream weight value must be greater than 0."); | |
130 | return ; | |
131 | } | |
132 | weight = newWeight; | |
133 | if (!hashes.empty()) { | |
134 | hash(); | |
135 | } | |
136 | } | |
137 | ||
138 | DownstreamState::DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf_, const std::string& sourceItfName_, size_t numberOfSockets, bool connect=true): sourceItfName(sourceItfName_), remote(remote_), sourceAddr(sourceAddr_), sourceItf(sourceItf_), name(remote_.toStringWithPort()), nameWithAddr(remote_.toStringWithPort()) | |
139 | { | |
140 | pthread_rwlock_init(&d_lock, nullptr); | |
141 | id = getUniqueID(); | |
142 | threadStarted.clear(); | |
143 | ||
144 | mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent()); | |
145 | ||
146 | sockets.resize(numberOfSockets); | |
147 | for (auto& fd : sockets) { | |
148 | fd = -1; | |
149 | } | |
150 | ||
151 | if (connect && !IsAnyAddress(remote)) { | |
152 | reconnect(); | |
153 | idStates.resize(g_maxOutstanding); | |
154 | sw.start(); | |
155 | } | |
156 | ||
157 | } |