]>
Commit | Line | Data |
---|---|---|
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 |
20 | RecursorControlChannel::RecursorControlChannel() |
21 | { | |
22 | d_fd=-1; | |
23 | *d_local.sun_path=0; | |
34c513f9 | 24 | d_local.sun_family=0; |
a254e9b6 BH |
25 | } |
26 | ||
27 | RecursorControlChannel::~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 |
35 | static 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 | ||
51 | static void setSocketReceiveBuffer(int fd, uint32_t size) | |
52 | { | |
53 | setSocketBuffer(fd, SO_RCVBUF, size); | |
54 | } | |
55 | ||
56 | static void setSocketSendBuffer(int fd, uint32_t size) | |
57 | { | |
58 | setSocketBuffer(fd, SO_SNDBUF, size); | |
59 | } | |
60 | ||
f6f016d1 BH |
61 | int 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 | 90 | void 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 | 145 | void 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 | 170 | string 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 |