]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/rec_channel.cc
Merge pull request #7903 from Habbie/dnsdist-doc-nits
[thirdparty/pdns.git] / pdns / rec_channel.cc
CommitLineData
870a0fe4
AT
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
f6f016d1 4#include "rec_channel.hh"
3897b9e1 5#include "utility.hh"
f6f016d1 6#include <sys/socket.h>
f6f016d1 7#include <cerrno>
10ecdfc2 8#include "misc.hh"
eb4e3090 9#include <string.h>
5b09a29b 10#include <cstdlib>
1d5b3ce6
BH
11#include <unistd.h>
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <iostream>
15
5c409fa2 16#include "pdnsexception.hh"
f6f016d1 17
10f4eea8 18#include "namespaces.hh"
f6f016d1 19
a254e9b6
BH
20RecursorControlChannel::RecursorControlChannel()
21{
22 d_fd=-1;
23 *d_local.sun_path=0;
34c513f9 24 d_local.sun_family=0;
a254e9b6
BH
25}
26
27RecursorControlChannel::~RecursorControlChannel()
28{
29 if(d_fd > 0)
30 close(d_fd);
815099b2 31 if(*d_local.sun_path)
a254e9b6
BH
32 unlink(d_local.sun_path);
33}
34
57e5278b
OM
35static void setSocketBuffer(int fd, int optname, uint32_t size)
36{
37 uint32_t psize=0;
38 socklen_t len=sizeof(psize);
39
40 if (getsockopt(fd, SOL_SOCKET, optname, (void*)&psize, &len))
41 throw PDNSException("Unable to getsocket buffer size: "+stringerror());
42
43 if (psize > size)
44 return;
2fa815b4
OM
45
46 // failure to raise is not fatal
47 setsockopt(fd, SOL_SOCKET, optname, (const void*)&size, sizeof(size));
57e5278b
OM
48}
49
50
51static void setSocketReceiveBuffer(int fd, uint32_t size)
52{
53 setSocketBuffer(fd, SO_RCVBUF, size);
54}
55
56static void setSocketSendBuffer(int fd, uint32_t size)
57{
58 setSocketBuffer(fd, SO_SNDBUF, size);
59}
60
f6f016d1
BH
61int RecursorControlChannel::listen(const string& fname)
62{
f6f016d1 63 d_fd=socket(AF_UNIX,SOCK_DGRAM,0);
3897b9e1 64 setCloseOnExec(d_fd);
42c235e5 65
f6f016d1 66 if(d_fd < 0)
76cb4593 67 throw PDNSException("Creating UNIX domain socket: "+stringerror());
f6f016d1
BH
68
69 int tmp=1;
70 if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
76cb4593 71 throw PDNSException("Setsockopt failed: "+stringerror());
f6f016d1
BH
72
73 int err=unlink(fname.c_str());
74 if(err < 0 && errno!=ENOENT)
76cb4593 75 throw PDNSException("Can't remove (previous) controlsocket '"+fname+"': "+stringerror() + " (try --socket-dir)");
f6f016d1 76
76cb4593
CH
77 if(makeUNsockaddr(fname, &d_local))
78 throw PDNSException("Unable to bind to controlsocket, path '"+fname+"' is not a valid UNIX socket path.");
f6f016d1 79
87a5ea63 80 if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0)
76cb4593 81 throw PDNSException("Unable to bind to controlsocket '"+fname+"': "+stringerror());
f6f016d1 82
d4777000 83 // receive buf should be size of max datagram plus address size
57e5278b
OM
84 setSocketReceiveBuffer(d_fd, 60 * 1024);
85 setSocketSendBuffer(d_fd, 64 * 1024);
d4777000 86
1d5b3ce6
BH
87 return d_fd;
88}
89
aaacf7f2 90void RecursorControlChannel::connect(const string& path, const string& fname)
1d5b3ce6 91{
a2bfc3ff 92 struct sockaddr_un remote;
1d5b3ce6
BH
93
94 d_fd=socket(AF_UNIX,SOCK_DGRAM,0);
3897b9e1 95 setCloseOnExec(d_fd);
42c235e5 96
1d5b3ce6 97 if(d_fd < 0)
3f81d239 98 throw PDNSException("Creating UNIX domain socket: "+string(strerror(errno)));
76cb4593
CH
99
100 try {
101 int tmp=1;
102 if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
103 throw PDNSException("Setsockopt failed: "+stringerror());
1d5b3ce6 104
76cb4593 105 string localname=path+"/lsockXXXXXX";
524e4f4d 106 *d_local.sun_path=0;
76cb4593
CH
107 if (makeUNsockaddr(localname, &d_local))
108 throw PDNSException("Unable to bind to local temporary file, path '"+localname+"' is not a valid UNIX socket path.");
aaacf7f2 109
76cb4593
CH
110 if(mkstemp(d_local.sun_path) < 0)
111 throw PDNSException("Unable to generate local temporary file in directory '"+path+"': "+stringerror());
1d5b3ce6 112
76cb4593
CH
113 int err=unlink(d_local.sun_path);
114 if(err < 0 && errno!=ENOENT)
115 throw PDNSException("Unable to remove local controlsocket: "+stringerror());
1d5b3ce6 116
76cb4593
CH
117 if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0)
118 throw PDNSException("Unable to bind to local temporary file: "+stringerror());
1d5b3ce6 119
76cb4593
CH
120 if(chmod(d_local.sun_path,0666)<0) // make sure that pdns can reply!
121 throw PDNSException("Unable to chmod local temporary socket: "+stringerror());
1d5b3ce6 122
76cb4593
CH
123 string remotename=path+"/"+fname;
124 if (makeUNsockaddr(remotename, &remote))
125 throw PDNSException("Unable to connect to controlsocket, path '"+remotename+"' is not a valid UNIX socket path.");
1d5b3ce6 126
524e4f4d 127 if(::connect(d_fd, (sockaddr*)&remote, sizeof(remote)) < 0) {
128 if(*d_local.sun_path)
129 unlink(d_local.sun_path);
76cb4593 130 throw PDNSException("Unable to connect to remote '"+string(remote.sun_path)+"': "+stringerror());
524e4f4d 131 }
76cb4593 132
d4777000 133 // receive buf should be size of max datagram plus address size
57e5278b
OM
134 setSocketReceiveBuffer(d_fd, 60 * 1024);
135 setSocketSendBuffer(d_fd, 64 * 1024);
d4777000 136
76cb4593
CH
137 } catch (...) {
138 close(d_fd);
139 d_fd=-1;
140 d_local.sun_path[0]=0;
141 throw;
1d5b3ce6 142 }
f6f016d1 143}
1d5b3ce6 144
11d641f2 145void RecursorControlChannel::send(const std::string& msg, const std::string* remote, unsigned int timeout)
1d5b3ce6 146{
11d641f2
RG
147 int ret = waitForRWData(d_fd, false, timeout, 0);
148 if(ret == 0) {
149 throw PDNSException("Timeout sending message over control channel");
150 }
151 else if(ret < 0) {
152 throw PDNSException("Error sending message over control channel:" + string(strerror(errno)));
153 }
154
1d5b3ce6
BH
155 if(remote) {
156 struct sockaddr_un remoteaddr;
157 memset(&remoteaddr, 0, sizeof(remoteaddr));
158
159 remoteaddr.sun_family=AF_UNIX;
bb749839 160 strncpy(remoteaddr.sun_path, remote->c_str(), sizeof(remoteaddr.sun_path)-1);
b841314c 161 remoteaddr.sun_path[sizeof(remoteaddr.sun_path)-1] = '\0';
1d5b3ce6
BH
162
163 if(::sendto(d_fd, msg.c_str(), msg.length(), 0, (struct sockaddr*) &remoteaddr, sizeof(remoteaddr) ) < 0)
8effb50c 164 throw PDNSException("Unable to send message over control channel '"+string(remoteaddr.sun_path)+"': "+string(strerror(errno)));
1d5b3ce6
BH
165 }
166 else if(::send(d_fd, msg.c_str(), msg.length(), 0) < 0)
3f81d239 167 throw PDNSException("Unable to send message over control channel: "+string(strerror(errno)));
1d5b3ce6
BH
168}
169
61203240 170string RecursorControlChannel::recv(std::string* remote, unsigned int timeout)
1d5b3ce6
BH
171{
172 char buffer[16384];
173 ssize_t len;
174 struct sockaddr_un remoteaddr;
175 socklen_t addrlen=sizeof(remoteaddr);
12997e9d 176
177 int ret=waitForData(d_fd, timeout, 0);
178 if(ret==0)
179 throw PDNSException("Timeout waiting for answer from control channel");
180
181 if( ret < 0 || (len=::recvfrom(d_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&remoteaddr, &addrlen)) < 0)
3f81d239 182 throw PDNSException("Unable to receive message over control channel: "+string(strerror(errno)));
1d5b3ce6
BH
183
184 if(remote)
185 *remote=remoteaddr.sun_path;
186
187 return string(buffer, buffer+len);
188}
189