]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dynlistener.cc
Initial revision
[thirdparty/pdns.git] / pdns / dynlistener.cc
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 PowerDNS.COM BV
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 // $Id: dynlistener.cc,v 1.1 2002/11/27 15:18:33 ahu Exp $
20 /* (C) Copyright 2002 PowerDNS.COM BV */
21 #include <cstring>
22 #include <string>
23 #include <map>
24 #include <sys/types.h>
25 #include <sys/un.h>
26 #include <dlfcn.h>
27 #include <pthread.h>
28 #include <unistd.h>
29
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <errno.h>
33 #include <iostream>
34 #include <sstream>
35 #include <sys/types.h>
36 #include <signal.h>
37
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41
42 #include "misc.hh"
43 #include "dns.hh"
44 #include "arguments.hh"
45 #include "dnsbackend.hh"
46 #include "dynlistener.hh"
47 #include "dnspacket.hh"
48 #include "logger.hh"
49 #include "statbag.hh"
50
51
52
53 extern StatBag S;
54
55 DynListener::DynListener(const string &pname)
56 {
57 d_restfunc=0;
58 string programname=pname;
59
60 if(!programname.empty()) {
61 struct sockaddr_un local;
62 d_s=socket(AF_UNIX,SOCK_DGRAM,0);
63
64 if(d_s<0) {
65 L<<Logger::Error<<"creating socket for dynlistener: "<<strerror(errno)<<endl;;
66 exit(1);
67 }
68
69 int tmp=1;
70 if(setsockopt(d_s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
71 throw AhuException(string("Setsockopt failed: ")+strerror(errno));
72
73 string socketname=arg()["socket-dir"]+"/";
74 cleanSlashes(socketname);
75
76 if(!mkdir(socketname.c_str(),0700)) // make /var directory, if needed
77 L<<Logger::Warning<<"Created local state directory '"<<socketname<<"'"<<endl;
78 else if(errno!=EEXIST) {
79 L<<Logger::Critical<<"FATAL: Unable to create socket directory ("<<socketname<<") and it does not exist yet"<<endl;
80 exit(1);
81 }
82
83 socketname+=programname+".controlsocket";
84 unlink(socketname.c_str());
85 memset(&local,0,sizeof(local));
86 local.sun_family=AF_UNIX;
87 strcpy(local.sun_path,socketname.c_str());
88
89 if(bind(d_s, (sockaddr*)&local,sizeof(local))<0) {
90 L<<Logger::Critical<<"binding to dynlistener '"<<socketname<<"': "<<strerror(errno)<<endl;
91 exit(1);
92 }
93
94 if(!arg()["setgid"].empty()) {
95 if(chown(socketname.c_str(),static_cast<uid_t>(-1),Utility::makeGidNumeric(arg()["setgid"]))<0)
96 L<<Logger::Error<<"Unable to change group ownership of controlsocket: "<<strerror(errno)<<endl;
97 if(chmod(socketname.c_str(),0660)<0)
98 L<<Logger::Error<<"Unable to change group access mode of controlsocket: "<<strerror(errno)<<endl;
99 }
100
101
102 L<<Logger::Warning<<"Listening on controlsocket in '"<<socketname<<"'"<<endl;
103 d_udp=true;
104 }
105 else
106 d_udp=false;
107
108
109 }
110
111 void DynListener::go()
112 {
113 d_ppid=getpid();
114 pthread_create(&d_tid,0,&DynListener::theListenerHelper,this);
115 }
116
117 void *DynListener::theListenerHelper(void *p)
118 {
119 DynListener *us=static_cast<DynListener *>(p);
120 us->theListener();
121 return 0;
122 }
123
124 string DynListener::getLine()
125 {
126 char mesg[512];
127 memset(mesg,0,sizeof(mesg));
128 int len;
129
130 if(d_udp) {
131 d_addrlen=sizeof(d_remote);
132
133 if((len=recvfrom(d_s,mesg,512,0,(sockaddr*) &d_remote, &d_addrlen))<0) {
134 L<<Logger::Error<<"Unable to receive packet from controlsocket ("<<d_s<<") - exiting: "<<strerror(errno)<<endl;
135 exit(1);
136 }
137 }
138 else {
139 if(isatty(0))
140 write(1, "% ", 2);
141 if((len=read(0,mesg,512))<0)
142 throw AhuException("Reading from the control pipe: "+stringerror());
143 else if(len==0)
144 throw AhuException("Guardian exited - going down as well");
145 }
146
147 return mesg;
148 }
149
150 void DynListener::sendLine(const string &l)
151 {
152 if(d_udp)
153 sendto(d_s,l.c_str(),l.length()+1,0,(struct sockaddr *)&d_remote,d_addrlen);
154 else {
155 string line=l;
156 line.append("\n");
157 write(1,line.c_str(),line.length());
158 }
159 }
160
161 void DynListener::registerFunc(const string &name, g_funk_t *gf)
162 {
163 d_funcdb[name]=gf;
164 }
165
166 void DynListener::registerRestFunc(g_funk_t *gf)
167 {
168 d_restfunc=gf;
169 }
170
171 void DynListener::theListener()
172 {
173 try {
174 map<string,string> parameters;
175
176 for(;;) {
177 string line=getLine();
178 chomp(line,"\n");
179
180 vector<string>parts;
181 stringtok(parts,line," ");
182 if(parts.empty()) {
183 sendLine("Empty line");
184 continue;
185 }
186 upperCase(parts[0]);
187 if(!d_funcdb[parts[0]]) {
188 if(d_restfunc)
189 sendLine((*d_restfunc)(parts,d_ppid));
190 else
191 sendLine("Unknown command: '"+parts[0]+"'");
192 continue;
193 }
194
195 sendLine((*d_funcdb[parts[0]])(parts,d_ppid));
196 }
197 }
198 catch(AhuException &AE)
199 {
200 L<<Logger::Error<<"Fatal: "<<AE.reason<<endl;
201 }
202 catch(string &E)
203 {
204 L<<Logger::Error<<"Fatal: "<<E<<endl;
205 }
206 catch(...)
207 {
208 L<<Logger::Error<<"Fatal: unknown exception occured"<<endl;
209 }
210 }
211