]>
git.ipfire.org Git - thirdparty/pdns.git/blob - modules/remotebackend/unixconnector.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
25 #include <sys/types.h>
26 #include <sys/socket.h>
28 #include "remotebackend.hh"
30 #define UNIX_PATH_MAX 108
33 UnixsocketConnector::UnixsocketConnector(std::map
<std::string
, std::string
> optionsMap
)
35 if (optionsMap
.count("path") == 0) {
36 g_log
<< Logger::Error
<< "Cannot find 'path' option in connection string" << endl
;
37 throw PDNSException();
40 if (optionsMap
.find("timeout") != optionsMap
.end()) {
41 this->timeout
= std::stoi(optionsMap
.find("timeout")->second
);
43 this->path
= optionsMap
.find("path")->second
;
44 this->options
= optionsMap
;
45 this->connected
= false;
49 UnixsocketConnector::~UnixsocketConnector()
51 if (this->connected
) {
53 g_log
<< Logger::Info
<< "closing socket connection" << endl
;
61 int UnixsocketConnector::send_message(const Json
& input
)
63 auto data
= input
.dump() + "\n";
64 int rv
= this->write(data
);
70 int UnixsocketConnector::recv_message(Json
& output
)
73 std::string s_output
, err
;
77 gettimeofday(&t0
, NULL
);
78 memcpy(&t
, &t0
, sizeof(t0
));
81 while ((t
.tv_sec
- t0
.tv_sec
) * 1000 + (t
.tv_usec
- t0
.tv_usec
) / 1000 < this->timeout
) {
82 int avail
= waitForData(this->fd
, 0, this->timeout
* 500); // use half the timeout as poll timeout
83 if (avail
< 0) // poll error
85 if (avail
== 0) { // timeout
86 gettimeofday(&t
, NULL
);
90 rv
= this->read(s_output
);
95 // see if it can be parsed
96 output
= Json::parse(s_output
, err
);
97 if (output
!= nullptr)
98 return s_output
.size();
100 gettimeofday(&t
, NULL
);
104 connected
= false; // we need to reconnect
108 ssize_t
UnixsocketConnector::read(std::string
& data
)
111 char buf
[1500] = {0};
116 nread
= ::read(this->fd
, buf
, sizeof buf
);
118 // just try again later...
119 if (nread
== -1 && errno
== EAGAIN
)
122 if (nread
== -1 || nread
== 0) {
128 data
.append(buf
, nread
);
132 ssize_t
UnixsocketConnector::write(const std::string
& data
)
140 while (pos
< data
.size()) {
141 ssize_t written
= ::write(fd
, &data
.at(pos
), data
.size() - pos
);
148 pos
= pos
+ static_cast<size_t>(written
);
154 void UnixsocketConnector::reconnect()
156 struct sockaddr_un sock
;
160 return; // no point reconnecting if connected...
163 g_log
<< Logger::Info
<< "Reconnecting to backend" << std::endl
;
164 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
167 g_log
<< Logger::Error
<< "Cannot create socket: " << strerror(errno
) << std::endl
;
172 if (makeUNsockaddr(path
, &sock
)) {
173 g_log
<< Logger::Error
<< "Unable to create UNIX domain socket: Path '" << path
<< "' is not a valid UNIX socket path." << std::endl
;
177 rv
= connect(fd
, reinterpret_cast<struct sockaddr
*>(&sock
), sizeof sock
);
179 if (rv
!= 0 && errno
!= EISCONN
&& errno
!= 0) {
180 g_log
<< Logger::Error
<< "Cannot connect to socket: " << strerror(errno
) << std::endl
;
187 Json::array parameters
;
188 Json msg
= Json(Json::object
{
189 {"method", "initialize"},
190 {"parameters", Json(options
)},
195 if (this->recv(msg
) == false) {
196 g_log
<< Logger::Warning
<< "Failed to initialize backend" << std::endl
;
198 this->connected
= false;