]>
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 RecursorControlChannel::RecursorControlChannel()
27 RecursorControlChannel::~RecursorControlChannel()
32 unlink(d_local
.sun_path
);
35 static void setSocketBuffer(int fd
, int optname
, uint32_t size
)
38 socklen_t len
=sizeof(psize
);
40 if (getsockopt(fd
, SOL_SOCKET
, optname
, (void*)&psize
, &len
))
41 throw PDNSException("Unable to getsocket buffer size: "+stringerror());
46 // failure to raise is not fatal
47 setsockopt(fd
, SOL_SOCKET
, optname
, (const void*)&size
, sizeof(size
));
51 static void setSocketReceiveBuffer(int fd
, uint32_t size
)
53 setSocketBuffer(fd
, SO_RCVBUF
, size
);
56 static void setSocketSendBuffer(int fd
, uint32_t size
)
58 setSocketBuffer(fd
, SO_SNDBUF
, size
);
61 int RecursorControlChannel::listen(const string
& fname
)
63 d_fd
=socket(AF_UNIX
,SOCK_DGRAM
,0);
67 throw PDNSException("Creating UNIX domain socket: "+stringerror());
70 if(setsockopt(d_fd
, SOL_SOCKET
, SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0)
71 throw PDNSException("Setsockopt failed: "+stringerror());
73 int err
=unlink(fname
.c_str());
74 if(err
< 0 && errno
!=ENOENT
)
75 throw PDNSException("Can't remove (previous) controlsocket '"+fname
+"': "+stringerror() + " (try --socket-dir)");
77 if(makeUNsockaddr(fname
, &d_local
))
78 throw PDNSException("Unable to bind to controlsocket, path '"+fname
+"' is not a valid UNIX socket path.");
80 if(bind(d_fd
, (sockaddr
*)&d_local
,sizeof(d_local
))<0)
81 throw PDNSException("Unable to bind to controlsocket '"+fname
+"': "+stringerror());
83 // receive buf should be size of max datagram plus address size
84 setSocketReceiveBuffer(d_fd
, 60 * 1024);
85 setSocketSendBuffer(d_fd
, 64 * 1024);
90 void RecursorControlChannel::connect(const string
& path
, const string
& fname
)
92 struct sockaddr_un remote
;
94 d_fd
=socket(AF_UNIX
,SOCK_DGRAM
,0);
98 throw PDNSException("Creating UNIX domain socket: "+string(strerror(errno
)));
102 if(setsockopt(d_fd
, SOL_SOCKET
, SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0)
103 throw PDNSException("Setsockopt failed: "+stringerror());
105 string localname
=path
+"/lsockXXXXXX";
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.");
110 if(mkstemp(d_local
.sun_path
) < 0)
111 throw PDNSException("Unable to generate local temporary file in directory '"+path
+"': "+stringerror());
113 int err
=unlink(d_local
.sun_path
);
114 if(err
< 0 && errno
!=ENOENT
)
115 throw PDNSException("Unable to remove local controlsocket: "+stringerror());
117 if(bind(d_fd
, (sockaddr
*)&d_local
,sizeof(d_local
))<0)
118 throw PDNSException("Unable to bind to local temporary file: "+stringerror());
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());
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.");
127 if(::connect(d_fd
, (sockaddr
*)&remote
, sizeof(remote
)) < 0) {
128 if(*d_local
.sun_path
)
129 unlink(d_local
.sun_path
);
130 throw PDNSException("Unable to connect to remote '"+string(remote
.sun_path
)+"': "+stringerror());
133 // receive buf should be size of max datagram plus address size
134 setSocketReceiveBuffer(d_fd
, 60 * 1024);
135 setSocketSendBuffer(d_fd
, 64 * 1024);
140 d_local
.sun_path
[0]=0;
145 void RecursorControlChannel::send(const std::string
& msg
, const std::string
* remote
, unsigned int timeout
)
147 int ret
= waitForRWData(d_fd
, false, timeout
, 0);
149 throw PDNSException("Timeout sending message over control channel");
152 throw PDNSException("Error sending message over control channel:" + string(strerror(errno
)));
156 struct sockaddr_un remoteaddr
;
157 memset(&remoteaddr
, 0, sizeof(remoteaddr
));
159 remoteaddr
.sun_family
=AF_UNIX
;
160 strncpy(remoteaddr
.sun_path
, remote
->c_str(), sizeof(remoteaddr
.sun_path
)-1);
161 remoteaddr
.sun_path
[sizeof(remoteaddr
.sun_path
)-1] = '\0';
163 if(::sendto(d_fd
, msg
.c_str(), msg
.length(), 0, (struct sockaddr
*) &remoteaddr
, sizeof(remoteaddr
) ) < 0)
164 throw PDNSException("Unable to send message over control channel '"+string(remoteaddr
.sun_path
)+"': "+string(strerror(errno
)));
166 else if(::send(d_fd
, msg
.c_str(), msg
.length(), 0) < 0)
167 throw PDNSException("Unable to send message over control channel: "+string(strerror(errno
)));
170 string
RecursorControlChannel::recv(std::string
* remote
, unsigned int timeout
)
174 struct sockaddr_un remoteaddr
;
175 socklen_t addrlen
=sizeof(remoteaddr
);
177 int ret
=waitForData(d_fd
, timeout
, 0);
179 throw PDNSException("Timeout waiting for answer from control channel");
181 if( ret
< 0 || (len
=::recvfrom(d_fd
, buffer
, sizeof(buffer
), 0, (struct sockaddr
*)&remoteaddr
, &addrlen
)) < 0)
182 throw PDNSException("Unable to receive message over control channel: "+string(strerror(errno
)));
185 *remote
=remoteaddr
.sun_path
;
187 return string(buffer
, buffer
+len
);