]>
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 | ||
f6f016d1 BH |
35 | int RecursorControlChannel::listen(const string& fname) |
36 | { | |
f6f016d1 | 37 | d_fd=socket(AF_UNIX,SOCK_DGRAM,0); |
3897b9e1 | 38 | setCloseOnExec(d_fd); |
42c235e5 | 39 | |
f6f016d1 | 40 | if(d_fd < 0) |
76cb4593 | 41 | throw PDNSException("Creating UNIX domain socket: "+stringerror()); |
f6f016d1 BH |
42 | |
43 | int tmp=1; | |
44 | if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) | |
76cb4593 | 45 | throw PDNSException("Setsockopt failed: "+stringerror()); |
f6f016d1 BH |
46 | |
47 | int err=unlink(fname.c_str()); | |
48 | if(err < 0 && errno!=ENOENT) | |
76cb4593 | 49 | throw PDNSException("Can't remove (previous) controlsocket '"+fname+"': "+stringerror() + " (try --socket-dir)"); |
f6f016d1 | 50 | |
76cb4593 CH |
51 | if(makeUNsockaddr(fname, &d_local)) |
52 | throw PDNSException("Unable to bind to controlsocket, path '"+fname+"' is not a valid UNIX socket path."); | |
f6f016d1 | 53 | |
87a5ea63 | 54 | if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0) |
76cb4593 | 55 | throw PDNSException("Unable to bind to controlsocket '"+fname+"': "+stringerror()); |
f6f016d1 | 56 | |
1d5b3ce6 BH |
57 | return d_fd; |
58 | } | |
59 | ||
aaacf7f2 | 60 | void RecursorControlChannel::connect(const string& path, const string& fname) |
1d5b3ce6 | 61 | { |
a2bfc3ff | 62 | struct sockaddr_un remote; |
1d5b3ce6 BH |
63 | |
64 | d_fd=socket(AF_UNIX,SOCK_DGRAM,0); | |
3897b9e1 | 65 | setCloseOnExec(d_fd); |
42c235e5 | 66 | |
1d5b3ce6 | 67 | if(d_fd < 0) |
3f81d239 | 68 | throw PDNSException("Creating UNIX domain socket: "+string(strerror(errno))); |
76cb4593 CH |
69 | |
70 | try { | |
71 | int tmp=1; | |
72 | if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) | |
73 | throw PDNSException("Setsockopt failed: "+stringerror()); | |
1d5b3ce6 | 74 | |
76cb4593 | 75 | string localname=path+"/lsockXXXXXX"; |
524e4f4d | 76 | *d_local.sun_path=0; |
76cb4593 CH |
77 | if (makeUNsockaddr(localname, &d_local)) |
78 | throw PDNSException("Unable to bind to local temporary file, path '"+localname+"' is not a valid UNIX socket path."); | |
aaacf7f2 | 79 | |
76cb4593 CH |
80 | if(mkstemp(d_local.sun_path) < 0) |
81 | throw PDNSException("Unable to generate local temporary file in directory '"+path+"': "+stringerror()); | |
1d5b3ce6 | 82 | |
76cb4593 CH |
83 | int err=unlink(d_local.sun_path); |
84 | if(err < 0 && errno!=ENOENT) | |
85 | throw PDNSException("Unable to remove local controlsocket: "+stringerror()); | |
1d5b3ce6 | 86 | |
76cb4593 CH |
87 | if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0) |
88 | throw PDNSException("Unable to bind to local temporary file: "+stringerror()); | |
1d5b3ce6 | 89 | |
76cb4593 CH |
90 | if(chmod(d_local.sun_path,0666)<0) // make sure that pdns can reply! |
91 | throw PDNSException("Unable to chmod local temporary socket: "+stringerror()); | |
1d5b3ce6 | 92 | |
76cb4593 CH |
93 | string remotename=path+"/"+fname; |
94 | if (makeUNsockaddr(remotename, &remote)) | |
95 | throw PDNSException("Unable to connect to controlsocket, path '"+remotename+"' is not a valid UNIX socket path."); | |
1d5b3ce6 | 96 | |
524e4f4d | 97 | if(::connect(d_fd, (sockaddr*)&remote, sizeof(remote)) < 0) { |
98 | if(*d_local.sun_path) | |
99 | unlink(d_local.sun_path); | |
76cb4593 | 100 | throw PDNSException("Unable to connect to remote '"+string(remote.sun_path)+"': "+stringerror()); |
524e4f4d | 101 | } |
76cb4593 CH |
102 | |
103 | } catch (...) { | |
104 | close(d_fd); | |
105 | d_fd=-1; | |
106 | d_local.sun_path[0]=0; | |
107 | throw; | |
1d5b3ce6 | 108 | } |
f6f016d1 | 109 | } |
1d5b3ce6 BH |
110 | |
111 | void RecursorControlChannel::send(const std::string& msg, const std::string* remote) | |
112 | { | |
113 | if(remote) { | |
114 | struct sockaddr_un remoteaddr; | |
115 | memset(&remoteaddr, 0, sizeof(remoteaddr)); | |
116 | ||
117 | remoteaddr.sun_family=AF_UNIX; | |
b841314c RG |
118 | strncpy(remoteaddr.sun_path, remote->c_str(), sizeof(remoteaddr.sun_path)); |
119 | remoteaddr.sun_path[sizeof(remoteaddr.sun_path)-1] = '\0'; | |
1d5b3ce6 BH |
120 | |
121 | if(::sendto(d_fd, msg.c_str(), msg.length(), 0, (struct sockaddr*) &remoteaddr, sizeof(remoteaddr) ) < 0) | |
8effb50c | 122 | throw PDNSException("Unable to send message over control channel '"+string(remoteaddr.sun_path)+"': "+string(strerror(errno))); |
1d5b3ce6 BH |
123 | } |
124 | else if(::send(d_fd, msg.c_str(), msg.length(), 0) < 0) | |
3f81d239 | 125 | throw PDNSException("Unable to send message over control channel: "+string(strerror(errno))); |
1d5b3ce6 BH |
126 | } |
127 | ||
61203240 | 128 | string RecursorControlChannel::recv(std::string* remote, unsigned int timeout) |
1d5b3ce6 BH |
129 | { |
130 | char buffer[16384]; | |
131 | ssize_t len; | |
132 | struct sockaddr_un remoteaddr; | |
133 | socklen_t addrlen=sizeof(remoteaddr); | |
12997e9d | 134 | |
135 | int ret=waitForData(d_fd, timeout, 0); | |
136 | if(ret==0) | |
137 | throw PDNSException("Timeout waiting for answer from control channel"); | |
138 | ||
139 | if( ret < 0 || (len=::recvfrom(d_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&remoteaddr, &addrlen)) < 0) | |
3f81d239 | 140 | throw PDNSException("Unable to receive message over control channel: "+string(strerror(errno))); |
1d5b3ce6 BH |
141 | |
142 | if(remote) | |
143 | *remote=remoteaddr.sun_path; | |
144 | ||
145 | return string(buffer, buffer+len); | |
146 | } | |
147 |