]> granicus.if.org Git - pdns/commitdiff
win32 errors
authorBert Hubert <bert.hubert@netherlabs.nl>
Sun, 30 Nov 2003 11:18:49 +0000 (11:18 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Sun, 30 Nov 2003 11:18:49 +0000 (11:18 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@205 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/docs/pdns.sgml
pdns/recursorservice.cc [new file with mode: 0644]
pdns/recursorservice.hh [new file with mode: 0644]
pdns/win32_pdns_recursor.cc [new file with mode: 0644]

index be53bcde4fb873deff9fee4e3660d5ee80c8d59b..2188d0417c09ee2cbc9d01e2eca87657ffd1ddab 100644 (file)
@@ -11,7 +11,7 @@
       </affiliation>
     </author>
     
-    <PubDate>v2.1 $Date: 2003/11/30 10:53:00 $</PubDate>
+    <PubDate>v2.1 $Date: 2003/11/30 11:18:49 $</PubDate>
     
     <Abstract>
        <para>  
 
     <sect2 id="changelog-2-9-13"><title>Version 2.9.13</title>
        <para>
-         Some bugfixes, some small features. Only one big bugfix, it appears we are heading for stability!
+         Big news! Windows is back! Our great friend Michel Stol found the time to update the PowerDNS code so it works 
+         again under windows. 
+       </para>
+       <para>
+         His changes:
+         <itemizedlist>
+           <listitem>
+             <para>
+               Generic SQLite support added
+             </para>
+           </listitem>
+           <listitem>
+             <para>
+               Removed the ODBC backend, replaced it by the Generic ODBC Backend, which has all the cool configurability
+               of the Generic MySQL and PostgreSQL backends.
+             </para>
+           </listitem>
+           <listitem>
+             <para>
+               The PowerDNS Recursor now runs as a Service. It defaults to running on port 5300, PowerDNS itself is configured
+               to expect the Recursor on port 5300 now.
+             </para>
+           </listitem>
+           <listitem>
+             <para>
+               The PowerDNS Service is now known as 'PowerDNS' to Windows.
+             </para>
+           </listitem>
+           <listitem>
+             <para>
+               The Installer was redone, this time with <ulink url="http://nsis.sf.net">NSIS2</ulink>. 
+             </para>
+           </listitem>
+           <listitem>
+             <para>
+               General updates and fixes.
+             </para>
+           </listitem>
+         </itemizedlist>
+       </para>
+       <para>
+         Other news:
        </para>
        <para>
          <note>
diff --git a/pdns/recursorservice.cc b/pdns/recursorservice.cc
new file mode 100644 (file)
index 0000000..2ed812f
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+    PowerDNS Versatile Database Driven Nameserver
+    Copyright (C) 2002  PowerDNS.COM BV
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+\r
+#include "common_startup.hh"\r
+#include "recursorservice.hh"\r
+\r
+extern int serviceMain( int argc, char *argv[] );\r
+\r
+// Control handler.\r
+void RecursorService::ctrlHandler( DWORD controlCode )\r
+{\r
+  if ( m_statusCode == SERVICE_STOPPED )\r
+    exit( 0 );\r
+\r
+  switch ( controlCode )\r
+  {\r
+    case SERVICE_CONTROL_STOP:\r
+      setStatus( SERVICE_STOP_PENDING );\r
+      shutdown();\r
+      setStatus( SERVICE_STOPPED );\r
+      // FIXME: Add a cleaner way to do this:\r
+      break;\r
+\r
+    case SERVICE_CONTROL_INTERROGATE:\r
+      setStatus( m_statusCode, m_errorCode );\r
+      break;\r
+\r
+    case SERVICE_CONTROL_SHUTDOWN:\r
+      setStatus( SERVICE_STOP_PENDING );\r
+      shutdown();\r
+      setStatus( SERVICE_STOPPED );\r
+      // FIXME: Add a cleaner way to do this:\r
+      break;\r
+  }\r
+}\r
+\r
+\r
+// Returns the service name.\r
+std::string RecursorService::getServiceName( void )\r
+{\r
+  return "PowerDNS Recursor";\r
+}\r
+\r
+\r
+// Main procedure.\r
+int RecursorService::main( int argc, char *argv[] )\r
+{\r
+  return serviceMain( argc, argv );\r
+\r
+}\r
diff --git a/pdns/recursorservice.hh b/pdns/recursorservice.hh
new file mode 100644 (file)
index 0000000..128306f
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+    PowerDNS Versatile Database Driven Nameserver
+    Copyright (C) 2002  PowerDNS.COM BV
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+\r
+#ifndef AHUDNSSERVICE_HH\r
+#define AHUDNSSERVICE_HH\r
+\r
+#include <string>\r
+#include "ntservice.hh"\r
+\r
+class RecursorService : public NTService\r
+{\r
+protected:\r
+  //! Main service procedure.\r
+  int main( int argc, char *argv[] );\r
+\r
+  //! Control handler.\r
+  void ctrlHandler( DWORD controlCode );\r
+  \r
+public:\r
+  //! Constructor.\r
+  RecursorService( void ) : NTService()\r
+  {\r
+  }\r
+  \r
+  //! Returns the service name.\r
+  std::string getServiceName( void );\r
+  \r
+};\r
+\r
+#endif // AHUDNSSERVICE_HH\r
diff --git a/pdns/win32_pdns_recursor.cc b/pdns/win32_pdns_recursor.cc
new file mode 100644 (file)
index 0000000..bc5cc58
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+    PowerDNS Versatile Database Driven Nameserver
+    Copyright (C) 2002  PowerDNS.COM BV
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "utility.hh" 
+#include <iostream>
+#include <errno.h>
+#include <map>
+#include <set>\r
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "mtasker.hh"
+#include <utility>
+#include "dnspacket.hh"
+#include "statbag.hh"
+#include "arguments.hh"
+#include "syncres.hh"
+#include <fcntl.h>
+#include <fstream>
+#include "recursorservice.hh"\r
+
+string s_programname="pdns_recursor";
+
+#ifndef WIN32
+extern "C" {
+  int sem_init(sem_t*, int, unsigned int){return 0;}
+  int sem_wait(sem_t*){return 0;}
+  int sem_trywait(sem_t*){return 0;}
+  int sem_post(sem_t*){return 0;}
+  int sem_getvalue(sem_t*, int*){return 0;}
+  pthread_t pthread_self(void){return (pthread_t) 0;}
+  int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr){ return 0; }
+  int pthread_mutex_lock(pthread_mutex_t *mutex){ return 0; }
+  int pthread_mutex_unlock(pthread_mutex_t *mutex) { return 0; }
+
+}
+#endif // WIN32
+
+StatBag S;
+ArgvMap &arg()
+{
+  static ArgvMap theArg;
+  return theArg;
+}
+int d_clientsock;
+int d_serversock;
+int d_tcpserversock;
+
+struct PacketID
+{
+  u_int16_t id;
+  struct sockaddr_in remote;
+};
+
+bool operator<(const PacketID& a, const PacketID& b)
+{
+  if(a.id<b.id)
+    return true;
+
+  if(a.id==b.id) {
+    if(a.remote.sin_addr.s_addr < b.remote.sin_addr.s_addr)
+      return true;
+    if(a.remote.sin_addr.s_addr == b.remote.sin_addr.s_addr)
+      if(a.remote.sin_port < b.remote.sin_port)
+       return true;
+  }
+
+  return false;
+}
+
+MTasker<PacketID,string>* MT;
+
+/* these two functions are used by LWRes */
+int asendto(const char *data, int len, int flags, struct sockaddr *toaddr, int addrlen, int id) 
+{
+  return sendto(d_clientsock, data, len, flags, toaddr, addrlen);
+}
+
+int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, Utility::socklen_t *addrlen, int *d_len, int id)
+{
+  PacketID pident;
+  pident.id=id;
+  memcpy(&pident.remote,toaddr,sizeof(pident.remote));
+
+  string packet;
+  if(!MT->waitEvent(pident,&packet,1)) { // timeout
+    return 0; 
+  }
+
+  *d_len=packet.size();
+  memcpy(data,packet.c_str(),min(len,*d_len));
+
+  return 1;
+}
+
+typedef map<string,set<DNSResourceRecord> > cache_t;
+static cache_t cache;
+int cacheHits, cacheMisses;
+int getCache(const string &qname, const QType& qt, set<DNSResourceRecord>* res)
+{
+  cache_t::const_iterator j=cache.find(toLower(qname)+"|"+qt.getName());
+  if(j!=cache.end() && j->first==toLower(qname)+"|"+qt.getName() && j->second.begin()->ttl>(unsigned int)time(0)) {
+    if(res)
+      *res=j->second;
+
+    return (unsigned int)j->second.begin()->ttl-time(0);
+  }
+
+  return -1;
+}
+
+void replaceCache(const string &qname, const QType& qt,  const set<DNSResourceRecord>& content)
+{
+
+  // bogus code to generate root with very low ttl
+  /*  
+  if((0 && qname.empty()) || qname.rfind(".root-servers.net")==1) {
+    cout<<"qname: '"<<qname<<"'"<<endl;
+    set<DNSResourceRecord> changed;
+    for(set<DNSResourceRecord>::const_iterator i=content.begin();i!=content.end();++i) {
+      DNSResourceRecord j=*i;
+      j.ttl=time(0)+20;
+      changed.insert(j);
+    }
+    cache[qname+"|"+qt.getName()]=changed;
+  }
+  else
+  */
+    cache[toLower(qname)+"|"+qt.getName()]=content;
+}
+
+void doPrune(void)
+{
+  unsigned int names=0, records=0;
+
+  for(cache_t::iterator j=cache.begin();j!=cache.end();){
+    for(set<DNSResourceRecord>::iterator k=j->second.begin();k!=j->second.end();) 
+      if((unsigned int)k->ttl < (unsigned int)time(0)) {
+       j->second.erase(k++);
+       records++;
+      }
+      else
+       ++k;
+
+    if(j->second.empty()) { // everything is gone
+      cache.erase(j++);
+      names++;
+
+    }
+    else {
+      ++j;
+    }
+  }
+}
+
+
+void primeHints(void)
+{
+  // prime root cache
+  static char*ips[]={"198.41.0.4", "128.9.0.107", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241", "192.112.36.4", "128.63.2.53", 
+                    "192.36.148.17","192.58.128.30", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
+  DNSResourceRecord arr, nsrr;
+  arr.qtype=QType::A;
+  arr.ttl=time(0)+3600000;
+  nsrr.qtype=QType::NS;
+  nsrr.ttl=time(0)+3600000;
+  
+  set<DNSResourceRecord>nsset;
+  for(char c='a';c<='m';++c) {
+    static char templ[40];
+    strncpy(templ,"a.root-servers.net", sizeof(templ) - 1);
+    *templ=c;
+    arr.qname=nsrr.content=templ;
+    arr.content=ips[c-'a'];
+    set<DNSResourceRecord>aset;
+    aset.insert(arr);
+    replaceCache(string(templ),QType(QType::A),aset);
+
+    nsset.insert(nsrr);
+  }
+  replaceCache("",QType(QType::NS),nsset);
+}
+
+void startDoResolve(void *p)
+{
+  try {
+    bool quiet=arg().mustDo("quiet");
+    DNSPacket P=*(DNSPacket *)p;
+
+    delete (DNSPacket *)p;
+
+    vector<DNSResourceRecord>ret;
+    DNSPacket *R=P.replyPacket();
+    R->setA(false);
+    R->setRA(true);
+
+    SyncRes sr;
+    if(!quiet)
+      L<<Logger::Error<<"["<<MT->getTid()<<"] question for '"<<P.qdomain<<"|"<<P.qtype.getName()<<"' from "<<P.getRemote()<<endl;
+
+    sr.setId(MT->getTid());
+    if(!P.d.rd)
+      sr.setCacheOnly();
+
+    int res=sr.beginResolve(P.qdomain, P.qtype, ret);
+    if(res<0)
+      R->setRcode(RCode::ServFail);
+    else {
+      R->setRcode(res);
+      for(vector<DNSResourceRecord>::const_iterator i=ret.begin();i!=ret.end();++i)
+       R->addRecord(*i);
+    }
+
+    const char *buffer=R->getData();
+    if(!R->getSocket())
+      sendto(d_serversock,buffer,R->len,0,(struct sockaddr *)(R->remote),R->d_socklen);
+    else {
+      char buf[2];
+      buf[0]=R->len/256;
+      buf[1]=R->len%256;
+      if(send(R->getSocket(),buf,2,0)!=2 || send(R->getSocket(),buffer,R->len,0)!=R->len)
+       L<<Logger::Error<<"Oops, partial answer sent to "<<P.getRemote()<<" - probably would have trouble receiving our answer anyhow (size="<<R->len<<")"<<endl;
+    }
+
+    if(!quiet) {
+      L<<Logger::Error<<"["<<MT->getTid()<<"] answer to "<<(P.d.rd?"":"non-rd ")<<"question '"<<P.qdomain<<"|"<<P.qtype.getName();
+      L<<"': "<<ntohs(R->d.ancount)<<" answers, "<<ntohs(R->d.arcount)<<" additional, took "<<sr.d_outqueries<<" packets, "<<
+       sr.d_throttledqueries<<" throttled, rcode="<<res<<endl;
+    }
+    
+    sr.d_outqueries ? cacheMisses++ : cacheHits++;
+
+    delete R;
+  }
+  catch(AhuException &ae) {
+    L<<Logger::Error<<"startDoResolve problem: "<<ae.reason<<endl;
+  }
+  catch(...) {
+    L<<Logger::Error<<"Any other exception in a resolver context"<<endl;
+  }
+}
+
+void makeClientSocket()
+{
+  d_clientsock=socket(AF_INET, SOCK_DGRAM,0);
+  if(d_clientsock<0) 
+    throw AhuException("Making a socket for resolver: "+stringerror());
+  
+  struct sockaddr_in sin;
+  memset((char *)&sin,0, sizeof(sin));
+  
+  sin.sin_family = AF_INET;
+  sin.sin_addr.s_addr = INADDR_ANY;
+  
+  int tries=10;
+  while(--tries) {
+    u_int16_t port=10000+Utility::random()%10000;
+    sin.sin_port = htons(port); 
+    
+    if (bind(d_clientsock, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 
+      break;
+    
+  }
+  if(!tries)
+    throw AhuException("Resolver binding to local socket: "+stringerror());
+}
+
+void makeTCPServerSocket()
+{
+  d_tcpserversock=socket(AF_INET, SOCK_STREAM,0);
+  if(d_tcpserversock<0) 
+    throw AhuException("Making a server socket for resolver: "+stringerror());
+  
+  struct sockaddr_in sin;
+  memset((char *)&sin,0, sizeof(sin));
+  
+  sin.sin_family = AF_INET;
+
+  if(arg()["local-address"]=="0.0.0.0") {
+    sin.sin_addr.s_addr = INADDR_ANY;
+  }
+  else {
+    if(!IpToU32(arg()["local-address"], &sin.sin_addr.s_addr))
+      throw AhuException("Unable to resolve local address"); 
+  }
+
+  sin.sin_port = htons(arg().asNum("local-port")); 
+    
+  if (bind(d_tcpserversock, (struct sockaddr *)&sin, sizeof(sin))<0) 
+    throw AhuException("TCP Resolver binding to server socket: "+stringerror());
+  
+  int tmp=1;
+  if(setsockopt(d_tcpserversock,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
+    L<<Logger::Error<<"Setsockopt failed"<<endl;
+    exit(1);  
+  }
+
+  listen(d_tcpserversock, 128);
+}
+
+void makeServerSocket()
+{
+  d_serversock=socket(AF_INET, SOCK_DGRAM,0);
+  if(d_serversock<0) 
+    throw AhuException("Making a server socket for resolver: "+stringerror());
+  
+  struct sockaddr_in sin;
+  memset((char *)&sin,0, sizeof(sin));
+  
+  sin.sin_family = AF_INET;
+
+  if(arg()["local-address"]=="0.0.0.0") {
+    L<<Logger::Warning<<"It is advised to bind to explicit addresses with the --local-address option"<<endl;
+    sin.sin_addr.s_addr = INADDR_ANY;
+  }
+  else {
+    
+    if(!IpToU32(arg()["local-address"], &sin.sin_addr.s_addr))
+      throw AhuException("Unable to resolve local address"); 
+
+  }
+
+  sin.sin_port = htons(arg().asNum("local-port")); 
+    
+  if (bind(d_serversock, (struct sockaddr *)&sin, sizeof(sin))<0) 
+    throw AhuException("Resolver binding to server socket: "+stringerror());
+  L<<Logger::Error<<"Incoming query source port: "<<arg().asNum("local-port")<<endl;
+}
+
+int counter, qcounter;
+bool statsWanted;
+
+void usr1Handler(int)
+{
+  statsWanted=true;
+}
+
+
+void doStats(void)
+{
+  if(qcounter) {
+    L<<Logger::Error<<"stats: "<<qcounter<<" questions, "<<cache.size()<<" cache entries, "<<SyncRes::s_negcache.size()<<" negative entries, "
+     <<(int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits";
+    L<<Logger::Error<<", outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%";
+    L<<Logger::Error<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, "
+     <<SyncRes::s_nodelegated<<" no-delegation drops"<<endl;
+  }
+  statsWanted=false;
+}
+
+void houseKeeping(void *)
+{
+  static time_t last_stat, last_rootupdate, last_prune;
+
+  if(time(0)-last_stat>30) { 
+    doPrune();
+    last_prune=time(0);
+  }
+  if(time(0)-last_stat>1800) { 
+    doStats();
+    last_stat=time(0);
+  }
+  if(time(0)-last_rootupdate>7200) {
+    SyncRes sr;
+    vector<DNSResourceRecord>ret;
+
+    sr.setNoCache();
+    int res=sr.beginResolve("", QType(QType::NS), ret);
+    if(!res) {
+      L<<Logger::Error<<"Refreshed . records"<<endl;
+      last_rootupdate=time(0);
+    }
+    else
+      L<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
+  }
+}
+
+struct TCPConnection
+{
+  int fd;
+  enum {BYTE0, BYTE1, GETQUESTION} state;
+  int qlen;
+  int bytesread;
+  struct sockaddr_in remote;
+  char data[65535];
+};
+\r
+//! Console handler.\r
+BOOL WINAPI consoleHandler( DWORD ctrl )\r
+{\r
+  L << Logger::Error << "Recursor shutting down..." << endl;\r
+  exit( 0 );\r
+\r
+  // This will never be reached.\r
+  return true;\r
+} \r
+\r
+\r
+int serviceMain( int argc, char *argv[] )\r
+{\r
+  try\r
+  {\r
+    makeClientSocket();\r
+    makeServerSocket();\r
+    makeTCPServerSocket();\r
+        \r
+    MT=new MTasker<PacketID,string>(100000);\r
+\r
+    char data[1500];\r
+    struct sockaddr_in fromaddr;\r
+    \r
+    PacketID pident;\r
+    primeHints();    \r
+    L<<Logger::Warning<<"Done priming cache with root hints"<<endl;\r
+\r
+    vector<TCPConnection> tcpconnections;\r
+    for(;;) {\r
+      while(MT->schedule()); // housekeeping, let threads do their thing\r
+      \r
+      if(!((counter++)%100)) \r
+       MT->makeThread(houseKeeping,0);\r
+      if(statsWanted)\r
+       doStats();\r
+\r
+      Utility::socklen_t addrlen=sizeof(fromaddr);\r
+      int d_len;\r
+      DNSPacket P;\r
+      \r
+      struct timeval tv;\r
+      tv.tv_sec=0;\r
+      tv.tv_usec=500000;\r
+      \r
+      fd_set readfds;\r
+      FD_ZERO( &readfds );\r
+      FD_SET( d_clientsock, &readfds );\r
+      FD_SET( d_serversock, &readfds );\r
+      FD_SET( d_tcpserversock, &readfds );\r
+      int fdmax=max(d_tcpserversock,max(d_clientsock,d_serversock));\r
+      for(vector<TCPConnection>::const_iterator i=tcpconnections.begin();i!=tcpconnections.end();++i) {\r
+       FD_SET(i->fd, &readfds);\r
+       fdmax=max(fdmax,i->fd);\r
+      }\r
+\r
+\r
+      /* this should listen on a TCP port as well for new connections,  */\r
+      int selret = select(  fdmax + 1, &readfds, NULL, NULL, &tv );\r
+      if(selret<=0) \r
+       if (selret == -1 && errno!=EINTR) \r
+         throw AhuException("Select returned: "+stringerror());\r
+       else\r
+         continue;\r
+\r
+      if(FD_ISSET(d_clientsock,&readfds)) { // do we have a question response?\r
+       d_len=recvfrom(d_clientsock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);    \r
+       if(d_len<0) \r
+         continue;\r
+       \r
+       P.setRemote((struct sockaddr *)&fromaddr, addrlen);\r
+       if(P.parse(data,d_len)<0) {\r
+         L<<Logger::Error<<"Unparseable packet from remote server "<<P.getRemote()<<endl;\r
+       }\r
+       else { \r
+         if(P.d.qr) {\r
+\r
+           pident.remote=fromaddr;\r
+           pident.id=P.d.id;\r
+           string packet;\r
+           packet.assign(data,d_len);\r
+           MT->sendEvent(pident,&packet);\r
+         }\r
+         else \r
+           L<<Logger::Warning<<"Ignoring question on outgoing socket from "<<P.getRemote()<<endl;\r
+       }\r
+      }\r
+      \r
+      if(FD_ISSET(d_serversock,&readfds)) { // do we have a new question on udp?\r
+       d_len=recvfrom(d_serversock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);    \r
+       if(d_len<0) \r
+         continue;\r
+       P.setRemote((struct sockaddr *)&fromaddr, addrlen);\r
+       if(P.parse(data,d_len)<0) {\r
+         L<<Logger::Error<<"Unparseable packet from remote client "<<P.getRemote()<<endl;\r
+       }\r
+       else { \r
+         if(P.d.qr)\r
+           L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;\r
+         else {\r
+           ++qcounter;\r
+           P.setSocket(0);\r
+           MT->makeThread(startDoResolve,(void*)new DNSPacket(P));\r
+\r
+         }\r
+       }\r
+      }\r
+\r
+      if(FD_ISSET(d_tcpserversock,&readfds)) { // do we have a new TCP connection\r
+       struct sockaddr_in addr;\r
+  Utility::socklen_t addrlen=sizeof(addr);\r
+       int newsock=accept(d_tcpserversock, (struct sockaddr*)&addr, &addrlen);\r
+       Utility::setNonBlocking(newsock);\r
+       \r
+       if(newsock>0) {\r
+         TCPConnection tc;\r
+         tc.fd=newsock;\r
+         tc.state=TCPConnection::BYTE0;\r
+         tc.remote=addr;\r
+         L<<Logger::Error<<"TCP Remote "<<sockAddrToString(&tc.remote,sizeof(tc.remote))<<" connected"<<endl;\r
+         tcpconnections.push_back(tc);\r
+       }\r
+      }\r
+\r
+      for(vector<TCPConnection>::iterator i=tcpconnections.begin();i!=tcpconnections.end();++i) {\r
+       if(FD_ISSET(i->fd, &readfds)) {\r
+         if(i->state==TCPConnection::BYTE0) {\r
+           int bytes=recv(i->fd,i->data,2,0);\r
+           if(bytes==1)\r
+             i->state=TCPConnection::BYTE1;\r
+           if(bytes==2) { \r
+             i->qlen=(i->data[0]<<8)+i->data[1];\r
+             i->bytesread=0;\r
+             i->state=TCPConnection::GETQUESTION;\r
+           }\r
+           if(!bytes || bytes < 0) {\r
+             L<<Logger::Error<<"TCP Remote "<<sockAddrToString(&i->remote,sizeof(i->remote))<<" disconnected"<<endl;\r
+        Utility::closesocket(i->fd);\r
+             tcpconnections.erase(i);\r
+             break;\r
+           }\r
+         }\r
+         else if(i->state==TCPConnection::BYTE1) {\r
+           int bytes=recv(i->fd,i->data+1,1,0);\r
+           if(bytes==1) {\r
+             i->state=TCPConnection::GETQUESTION;\r
+             i->qlen=(i->data[0]<<8)+i->data[1];\r
+             i->bytesread=0;\r
+           }\r
+           if(!bytes || bytes < 0) {\r
+             L<<Logger::Error<<"TCP Remote "<<sockAddrToString(&i->remote,sizeof(i->remote))<<" disconnected after first byte"<<endl;\r
+        Utility::closesocket(i->fd);\r
+             tcpconnections.erase(i);\r
+             break;\r
+           }\r
+           \r
+         }\r
+         else if(i->state==TCPConnection::GETQUESTION) {\r
+           int bytes=recv(i->fd,i->data + i->bytesread,i->qlen - i->bytesread,0);\r
+           if(!bytes || bytes < 0) {\r
+             L<<Logger::Error<<"TCP Remote "<<sockAddrToString(&i->remote,sizeof(i->remote))<<" disconnected while reading question body"<<endl;\r
+        Utility::closesocket(i->fd);\r
+             tcpconnections.erase(i);\r
+             break;\r
+           }\r
+           i->bytesread+=bytes;\r
+           if(i->bytesread==i->qlen) {\r
+             i->state=TCPConnection::BYTE0;\r
+\r
+             if(P.parse(i->data,i->qlen)<0) {\r
+               L<<Logger::Error<<"Unparseable packet from remote client "<<P.getRemote()<<endl;\r
+    Utility::closesocket(i->fd);\r
+               tcpconnections.erase(i);\r
+               break;\r
+             }\r
+             else { \r
+               P.setSocket(i->fd);\r
+               P.setRemote((struct sockaddr *)&i->remote,sizeof(i->remote));\r
+               if(P.d.qr)\r
+                 L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;\r
+               else {\r
+                 ++qcounter;\r
+                 MT->makeThread(startDoResolve,(void*)new DNSPacket(P));\r
+               }\r
+             }\r
+           }\r
+         }\r
+       }\r
+      }\r
+    }\r
+  }\r
+  catch(AhuException &ae) {\r
+    L<<Logger::Error<<"Exception: "<<ae.reason<<endl;\r
+  }\r
+  catch(exception &e) {\r
+    L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;\r
+  }\r
+  catch(...) {\r
+    L<<Logger::Error<<"any other exception in main: "<<endl;\r
+  }\r
+  \r
+#ifdef WIN32\r
+  WSACleanup();\r
+#endif // WIN32\r
+\r
+  return 0;\r
+}\r
+
+int main(int argc, char **argv) 
+{
+  RecursorService recursor;\r
+\r
+  // Initialize winsock.\r
+  WSAData wsaData;\r
+\r
+  if ( WSAStartup( MAKEWORD( 2, 0 ), &wsaData ) != 0 )\r
+  {\r
+    cerr << "Could not initialize winsock.dll" << endl;\r
+    return -1;\r
+  }\r
+
+  try {
+\r
+    Utility::srandom(time(0));
+    arg().set("soa-minimum-ttl","Don't change")="0";
+    arg().set("soa-serial-offset","Don't change")="0";
+    arg().set("aaaa-additional-processing","turn on to do AAAA additional processing (slow)")="off";
+    arg().set("local-port","port to listen on")="53";
+    arg().set("local-address","port to listen on")="0.0.0.0";
+    arg().set("trace","if we should output heaps of logging")="off";
+    arg().set("daemon","Operate as a daemon")="yes";
+    arg().set("quiet","Suppress logging of questions and answers")="off";
+    arg().set("delegation-only","Which domains we only accept delegations from")="";
+    arg().setCmd("help","Provide a helpful message");
+    arg().set("config-dir","Location of configuration directory (recursor.conf)")="./";\r
+    arg().setSwitch( "register-service", "Register the service" )= "no";\r
+    arg().setSwitch( "unregister-service", "Unregister the service" )= "no";\r
+    arg().setSwitch( "ntservice", "Run as service" )= "no";\r
+\r
+    arg().setSwitch( "use-ntlog", "Use the NT logging facilities" )= "yes"; \r
+    arg().setSwitch( "use-logfile", "Use a log file" )= "no"; \r
+    arg().setSwitch( "logfile", "Filename of the log file" )= "recursor.log"; \r
+\r
+    L.toConsole(Logger::Warning);
+    arg().laxParse(argc,argv); // do a lax parse
+\r
+    // If we have to run as a nt service change the current directory to the executable directory.\r
+    if ( arg().mustDo( "ntservice" ))\r
+    {\r
+      char    dir[ MAX_PATH ];\r
+      string  newdir;\r
+\r
+      GetModuleFileName( NULL, dir, sizeof( dir ));\r
+\r
+      newdir = dir;\r
+      newdir = newdir.substr( 0, newdir.find_last_of( "\\" ));\r
+\r
+      SetCurrentDirectory( newdir.c_str());\r
+    }\r
+\r
+    string configname=arg()["config-dir"]+"/recursor.conf";
+    cleanSlashes(configname);
+
+    if(!arg().file(configname.c_str())) 
+      L<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl;
+
+    arg().parse(argc,argv);
+
+    if ( arg().mustDo( "register-service" ))\r
+    {\r
+      if ( !recursor.registerService( "The PowerDNS Recursor.", true ))\r
+      {\r
+        cerr << "Could not register service." << endl;\r
+        exit( 99 );\r
+      }\r
+\r
+      // Exit.\r
+      exit( 0 );\r
+    }\r
+\r
+    if ( arg().mustDo( "unregister-service" ))\r
+    {\r
+      recursor.unregisterService();\r
+      exit( 0 );\r
+    }\r
+    \r
+    arg().set("delegation-only")=toLower(arg()["delegation-only"]);
+
+    if(arg().mustDo("help")) {
+      cerr<<"syntax:"<<endl<<endl;
+      cerr<<arg().helpstring(arg()["help"])<<endl;
+      exit(99);
+    }
+
+    L.setName("pdns_recursor");
+
+    if(arg().mustDo("trace"))
+      SyncRes::setLog(true);
+\r
+    if ( arg().mustDo( "use-ntlog" ) && arg().mustDo( "ntservice" ))\r
+      L.toNTLog();\r
+\r
+    if ( arg().mustDo( "use-logfile" ))\r
+      L.toFile( arg()[ "logfile" ] ); \r
+  \r
+    // Register console control hander.\r
+    if ( !arg().mustDo( "ntservice" ))\r
+      SetConsoleCtrlHandler( consoleHandler, true );\r
+  \r
+    RecursorService::instance()->start( argc, argv, arg().mustDo( "ntservice" )); \r
+\r
+  }\r
+  catch(AhuException &ae) {\r
+    L<<Logger::Error<<"Exception: "<<ae.reason<<endl;\r
+  }\r
+  catch(exception &e) {\r
+    L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;\r
+  }\r
+  catch(...) {\r
+    L<<Logger::Error<<"any other exception in main: "<<endl;\r
+  }\r
+    
+  return 0;
+}