]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/rec_channel.cc
implement LocalState/GlobalState
[thirdparty/pdns.git] / pdns / rec_channel.cc
CommitLineData
f6f016d1
BH
1#include "rec_channel.hh"
2#include <sys/socket.h>
f6f016d1 3#include <cerrno>
10ecdfc2 4#include "misc.hh"
eb4e3090 5#include <string.h>
5b09a29b 6#include <cstdlib>
1d5b3ce6
BH
7#include <unistd.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <iostream>
11
5c409fa2 12#include "pdnsexception.hh"
f6f016d1 13
10f4eea8 14#include "namespaces.hh"
f6f016d1 15
a254e9b6
BH
16RecursorControlChannel::RecursorControlChannel()
17{
18 d_fd=-1;
19 *d_local.sun_path=0;
20}
21
22RecursorControlChannel::~RecursorControlChannel()
23{
24 if(d_fd > 0)
25 close(d_fd);
815099b2 26 if(*d_local.sun_path)
a254e9b6
BH
27 unlink(d_local.sun_path);
28}
29
f6f016d1
BH
30int RecursorControlChannel::listen(const string& fname)
31{
f6f016d1 32 d_fd=socket(AF_UNIX,SOCK_DGRAM,0);
42c235e5
PD
33 Utility::setCloseOnExec(d_fd);
34
f6f016d1 35 if(d_fd < 0)
76cb4593 36 throw PDNSException("Creating UNIX domain socket: "+stringerror());
f6f016d1
BH
37
38 int tmp=1;
39 if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
76cb4593 40 throw PDNSException("Setsockopt failed: "+stringerror());
f6f016d1
BH
41
42 int err=unlink(fname.c_str());
43 if(err < 0 && errno!=ENOENT)
76cb4593 44 throw PDNSException("Can't remove (previous) controlsocket '"+fname+"': "+stringerror() + " (try --socket-dir)");
f6f016d1 45
76cb4593
CH
46 if(makeUNsockaddr(fname, &d_local))
47 throw PDNSException("Unable to bind to controlsocket, path '"+fname+"' is not a valid UNIX socket path.");
f6f016d1 48
87a5ea63 49 if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0)
76cb4593 50 throw PDNSException("Unable to bind to controlsocket '"+fname+"': "+stringerror());
f6f016d1 51
1d5b3ce6
BH
52 return d_fd;
53}
54
aaacf7f2 55void RecursorControlChannel::connect(const string& path, const string& fname)
1d5b3ce6 56{
a2bfc3ff 57 struct sockaddr_un remote;
1d5b3ce6
BH
58
59 d_fd=socket(AF_UNIX,SOCK_DGRAM,0);
42c235e5
PD
60 Utility::setCloseOnExec(d_fd);
61
1d5b3ce6 62 if(d_fd < 0)
3f81d239 63 throw PDNSException("Creating UNIX domain socket: "+string(strerror(errno)));
76cb4593
CH
64
65 try {
66 int tmp=1;
67 if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
68 throw PDNSException("Setsockopt failed: "+stringerror());
1d5b3ce6 69
76cb4593 70 string localname=path+"/lsockXXXXXX";
524e4f4d 71 *d_local.sun_path=0;
76cb4593
CH
72 if (makeUNsockaddr(localname, &d_local))
73 throw PDNSException("Unable to bind to local temporary file, path '"+localname+"' is not a valid UNIX socket path.");
aaacf7f2 74
76cb4593
CH
75 if(mkstemp(d_local.sun_path) < 0)
76 throw PDNSException("Unable to generate local temporary file in directory '"+path+"': "+stringerror());
1d5b3ce6 77
76cb4593
CH
78 int err=unlink(d_local.sun_path);
79 if(err < 0 && errno!=ENOENT)
80 throw PDNSException("Unable to remove local controlsocket: "+stringerror());
1d5b3ce6 81
76cb4593
CH
82 if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0)
83 throw PDNSException("Unable to bind to local temporary file: "+stringerror());
1d5b3ce6 84
76cb4593
CH
85 if(chmod(d_local.sun_path,0666)<0) // make sure that pdns can reply!
86 throw PDNSException("Unable to chmod local temporary socket: "+stringerror());
1d5b3ce6 87
76cb4593
CH
88 string remotename=path+"/"+fname;
89 if (makeUNsockaddr(remotename, &remote))
90 throw PDNSException("Unable to connect to controlsocket, path '"+remotename+"' is not a valid UNIX socket path.");
1d5b3ce6 91
524e4f4d 92 if(::connect(d_fd, (sockaddr*)&remote, sizeof(remote)) < 0) {
93 if(*d_local.sun_path)
94 unlink(d_local.sun_path);
76cb4593 95 throw PDNSException("Unable to connect to remote '"+string(remote.sun_path)+"': "+stringerror());
524e4f4d 96 }
76cb4593
CH
97
98 } catch (...) {
99 close(d_fd);
100 d_fd=-1;
101 d_local.sun_path[0]=0;
102 throw;
1d5b3ce6 103 }
f6f016d1 104}
1d5b3ce6
BH
105
106void RecursorControlChannel::send(const std::string& msg, const std::string* remote)
107{
108 if(remote) {
109 struct sockaddr_un remoteaddr;
110 memset(&remoteaddr, 0, sizeof(remoteaddr));
111
112 remoteaddr.sun_family=AF_UNIX;
113 strcpy(remoteaddr.sun_path, remote->c_str());
114
115 if(::sendto(d_fd, msg.c_str(), msg.length(), 0, (struct sockaddr*) &remoteaddr, sizeof(remoteaddr) ) < 0)
3f81d239 116 throw PDNSException("Unable to send message over control channel '"+*remote+"': "+string(strerror(errno)));
1d5b3ce6
BH
117 }
118 else if(::send(d_fd, msg.c_str(), msg.length(), 0) < 0)
3f81d239 119 throw PDNSException("Unable to send message over control channel: "+string(strerror(errno)));
1d5b3ce6
BH
120}
121
61203240 122string RecursorControlChannel::recv(std::string* remote, unsigned int timeout)
1d5b3ce6
BH
123{
124 char buffer[16384];
125 ssize_t len;
126 struct sockaddr_un remoteaddr;
127 socklen_t addrlen=sizeof(remoteaddr);
12997e9d 128
129 int ret=waitForData(d_fd, timeout, 0);
130 if(ret==0)
131 throw PDNSException("Timeout waiting for answer from control channel");
132
133 if( ret < 0 || (len=::recvfrom(d_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&remoteaddr, &addrlen)) < 0)
3f81d239 134 throw PDNSException("Unable to receive message over control channel: "+string(strerror(errno)));
1d5b3ce6
BH
135
136 if(remote)
137 *remote=remoteaddr.sun_path;
138
139 return string(buffer, buffer+len);
140}
141