File: rec_channel.cc

package info (click to toggle)
pdns-recursor 3.3-3%2Bdeb7u1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 1,256 kB
  • sloc: cpp: 13,251; ansic: 2,647; sh: 510; makefile: 87
file content (140 lines) | stat: -rw-r--r-- 4,197 bytes parent folder | download
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);
}