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