]>
Commit | Line | Data |
---|---|---|
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 |
16 | RecursorControlChannel::RecursorControlChannel() |
17 | { | |
18 | d_fd=-1; | |
19 | *d_local.sun_path=0; | |
20 | } | |
21 | ||
22 | RecursorControlChannel::~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 |
30 | int 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 | 55 | void 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 | |
106 | void 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 | 122 | string 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 |