]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rec_channel.cc
Various fixes from clang static analyzer, coverity and cppcheck
[thirdparty/pdns.git] / pdns / rec_channel.cc
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include "rec_channel.hh"
5 #include "utility.hh"
6 #include <sys/socket.h>
7 #include <cerrno>
8 #include "misc.hh"
9 #include <string.h>
10 #include <cstdlib>
11 #include <unistd.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <iostream>
15
16 #include "pdnsexception.hh"
17
18 #include "namespaces.hh"
19
20 RecursorControlChannel::RecursorControlChannel()
21 {
22 d_fd=-1;
23 *d_local.sun_path=0;
24 d_local.sun_family=0;
25 }
26
27 RecursorControlChannel::~RecursorControlChannel()
28 {
29 if(d_fd > 0)
30 close(d_fd);
31 if(*d_local.sun_path)
32 unlink(d_local.sun_path);
33 }
34
35 int RecursorControlChannel::listen(const string& fname)
36 {
37 d_fd=socket(AF_UNIX,SOCK_DGRAM,0);
38 setCloseOnExec(d_fd);
39
40 if(d_fd < 0)
41 throw PDNSException("Creating UNIX domain socket: "+stringerror());
42
43 int tmp=1;
44 if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
45 throw PDNSException("Setsockopt failed: "+stringerror());
46
47 int err=unlink(fname.c_str());
48 if(err < 0 && errno!=ENOENT)
49 throw PDNSException("Can't remove (previous) controlsocket '"+fname+"': "+stringerror() + " (try --socket-dir)");
50
51 if(makeUNsockaddr(fname, &d_local))
52 throw PDNSException("Unable to bind to controlsocket, path '"+fname+"' is not a valid UNIX socket path.");
53
54 if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0)
55 throw PDNSException("Unable to bind to controlsocket '"+fname+"': "+stringerror());
56
57 return d_fd;
58 }
59
60 void RecursorControlChannel::connect(const string& path, const string& fname)
61 {
62 struct sockaddr_un remote;
63
64 d_fd=socket(AF_UNIX,SOCK_DGRAM,0);
65 setCloseOnExec(d_fd);
66
67 if(d_fd < 0)
68 throw PDNSException("Creating UNIX domain socket: "+string(strerror(errno)));
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());
74
75 string localname=path+"/lsockXXXXXX";
76 *d_local.sun_path=0;
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.");
79
80 if(mkstemp(d_local.sun_path) < 0)
81 throw PDNSException("Unable to generate local temporary file in directory '"+path+"': "+stringerror());
82
83 int err=unlink(d_local.sun_path);
84 if(err < 0 && errno!=ENOENT)
85 throw PDNSException("Unable to remove local controlsocket: "+stringerror());
86
87 if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0)
88 throw PDNSException("Unable to bind to local temporary file: "+stringerror());
89
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());
92
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.");
96
97 if(::connect(d_fd, (sockaddr*)&remote, sizeof(remote)) < 0) {
98 if(*d_local.sun_path)
99 unlink(d_local.sun_path);
100 throw PDNSException("Unable to connect to remote '"+string(remote.sun_path)+"': "+stringerror());
101 }
102
103 } catch (...) {
104 close(d_fd);
105 d_fd=-1;
106 d_local.sun_path[0]=0;
107 throw;
108 }
109 }
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;
118 strncpy(remoteaddr.sun_path, remote->c_str(), sizeof(remoteaddr.sun_path));
119 remoteaddr.sun_path[sizeof(remoteaddr.sun_path)-1] = '\0';
120
121 if(::sendto(d_fd, msg.c_str(), msg.length(), 0, (struct sockaddr*) &remoteaddr, sizeof(remoteaddr) ) < 0)
122 throw PDNSException("Unable to send message over control channel '"+string(remoteaddr.sun_path)+"': "+string(strerror(errno)));
123 }
124 else if(::send(d_fd, msg.c_str(), msg.length(), 0) < 0)
125 throw PDNSException("Unable to send message over control channel: "+string(strerror(errno)));
126 }
127
128 string RecursorControlChannel::recv(std::string* remote, unsigned int timeout)
129 {
130 char buffer[16384];
131 ssize_t len;
132 struct sockaddr_un remoteaddr;
133 socklen_t addrlen=sizeof(remoteaddr);
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)
140 throw PDNSException("Unable to receive message over control channel: "+string(strerror(errno)));
141
142 if(remote)
143 *remote=remoteaddr.sun_path;
144
145 return string(buffer, buffer+len);
146 }
147