]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rec_channel.cc
4 #include "rec_channel.hh"
6 #include <sys/socket.h>
12 #include <sys/types.h>
16 #include "pdnsexception.hh"
18 #include "namespaces.hh"
20 volatile sig_atomic_t RecursorControlChannel::stop
= 0;
22 RecursorControlChannel::RecursorControlChannel()
29 RecursorControlChannel::~RecursorControlChannel()
34 unlink(d_local
.sun_path
);
37 static void setSocketBuffer(int fd
, int optname
, uint32_t size
)
40 socklen_t len
=sizeof(psize
);
42 if (getsockopt(fd
, SOL_SOCKET
, optname
, (void*)&psize
, &len
))
43 throw PDNSException("Unable to getsocket buffer size: "+stringerror());
48 // failure to raise is not fatal
49 setsockopt(fd
, SOL_SOCKET
, optname
, (const void*)&size
, sizeof(size
));
53 static void setSocketReceiveBuffer(int fd
, uint32_t size
)
55 setSocketBuffer(fd
, SO_RCVBUF
, size
);
58 static void setSocketSendBuffer(int fd
, uint32_t size
)
60 setSocketBuffer(fd
, SO_SNDBUF
, size
);
63 int RecursorControlChannel::listen(const string
& fname
)
65 d_fd
=socket(AF_UNIX
,SOCK_DGRAM
,0);
69 throw PDNSException("Creating UNIX domain socket: "+stringerror());
72 if(setsockopt(d_fd
, SOL_SOCKET
, SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0)
73 throw PDNSException("Setsockopt failed: "+stringerror());
75 int err
=unlink(fname
.c_str());
76 if(err
< 0 && errno
!=ENOENT
)
77 throw PDNSException("Can't remove (previous) controlsocket '"+fname
+"': "+stringerror() + " (try --socket-dir)");
79 if(makeUNsockaddr(fname
, &d_local
))
80 throw PDNSException("Unable to bind to controlsocket, path '"+fname
+"' is not a valid UNIX socket path.");
82 if(bind(d_fd
, (sockaddr
*)&d_local
,sizeof(d_local
))<0)
83 throw PDNSException("Unable to bind to controlsocket '"+fname
+"': "+stringerror());
85 // receive buf should be size of max datagram plus address size
86 setSocketReceiveBuffer(d_fd
, 60 * 1024);
87 setSocketSendBuffer(d_fd
, 64 * 1024);
92 void RecursorControlChannel::connect(const string
& path
, const string
& fname
)
94 struct sockaddr_un remote
;
96 d_fd
=socket(AF_UNIX
,SOCK_DGRAM
,0);
100 throw PDNSException("Creating UNIX domain socket: "+stringerror());
104 if(setsockopt(d_fd
, SOL_SOCKET
, SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0)
105 throw PDNSException("Setsockopt failed: "+stringerror());
107 string localname
=path
+"/lsockXXXXXX";
109 if (makeUNsockaddr(localname
, &d_local
))
110 throw PDNSException("Unable to bind to local temporary file, path '"+localname
+"' is not a valid UNIX socket path.");
112 if(mkstemp(d_local
.sun_path
) < 0)
113 throw PDNSException("Unable to generate local temporary file in directory '"+path
+"': "+stringerror());
115 int err
=unlink(d_local
.sun_path
);
116 if(err
< 0 && errno
!=ENOENT
)
117 throw PDNSException("Unable to remove local controlsocket: "+stringerror());
119 if(bind(d_fd
, (sockaddr
*)&d_local
,sizeof(d_local
))<0)
120 throw PDNSException("Unable to bind to local temporary file: "+stringerror());
122 if(chmod(d_local
.sun_path
,0666)<0) // make sure that pdns can reply!
123 throw PDNSException("Unable to chmod local temporary socket: "+stringerror());
125 string remotename
=path
+"/"+fname
;
126 if (makeUNsockaddr(remotename
, &remote
))
127 throw PDNSException("Unable to connect to controlsocket, path '"+remotename
+"' is not a valid UNIX socket path.");
129 if(::connect(d_fd
, (sockaddr
*)&remote
, sizeof(remote
)) < 0) {
130 if(*d_local
.sun_path
)
131 unlink(d_local
.sun_path
);
132 throw PDNSException("Unable to connect to remote '"+string(remote
.sun_path
)+"': "+stringerror());
135 // receive buf should be size of max datagram plus address size
136 setSocketReceiveBuffer(d_fd
, 60 * 1024);
137 setSocketSendBuffer(d_fd
, 64 * 1024);
142 d_local
.sun_path
[0]=0;
147 void RecursorControlChannel::send(const std::string
& msg
, const std::string
* remote
, unsigned int timeout
)
149 int ret
= waitForRWData(d_fd
, false, timeout
, 0);
151 throw PDNSException("Timeout sending message over control channel");
154 throw PDNSException("Error sending message over control channel:" + stringerror());
158 struct sockaddr_un remoteaddr
;
159 memset(&remoteaddr
, 0, sizeof(remoteaddr
));
161 remoteaddr
.sun_family
=AF_UNIX
;
162 strncpy(remoteaddr
.sun_path
, remote
->c_str(), sizeof(remoteaddr
.sun_path
)-1);
163 remoteaddr
.sun_path
[sizeof(remoteaddr
.sun_path
)-1] = '\0';
165 if(::sendto(d_fd
, msg
.c_str(), msg
.length(), 0, (struct sockaddr
*) &remoteaddr
, sizeof(remoteaddr
) ) < 0)
166 throw PDNSException("Unable to send message over control channel '"+string(remoteaddr
.sun_path
)+"': "+stringerror());
168 else if(::send(d_fd
, msg
.c_str(), msg
.length(), 0) < 0)
169 throw PDNSException("Unable to send message over control channel: "+stringerror());
172 string
RecursorControlChannel::recv(std::string
* remote
, unsigned int timeout
)
176 struct sockaddr_un remoteaddr
;
177 socklen_t addrlen
=sizeof(remoteaddr
);
179 int ret
=waitForData(d_fd
, timeout
, 0);
181 throw PDNSException("Timeout waiting for answer from control channel");
183 if( ret
< 0 || (len
=::recvfrom(d_fd
, buffer
, sizeof(buffer
), 0, (struct sockaddr
*)&remoteaddr
, &addrlen
)) < 0)
184 throw PDNSException("Unable to receive message over control channel: "+stringerror());
187 *remote
=remoteaddr
.sun_path
;
189 return string(buffer
, buffer
+len
);