home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / samba-1.9.18p7.tar.gz / samba-1.9.18p7.tar / samba-1.9.18p7 / source / asyncdns.c < prev    next >
C/C++ Source or Header  |  1998-05-04  |  10KB  |  350 lines

  1. /*
  2.    Unix SMB/Netbios implementation.
  3.    a async DNS handler
  4.    Copyright (C) Andrew Tridgell 1997-1998
  5.    
  6.    This program is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2 of the License, or
  9.    (at your option) any later version.
  10.    
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.    
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.    */
  20.  
  21. #include "includes.h"
  22.  
  23. extern int DEBUGLEVEL;
  24.  
  25. /***************************************************************************
  26.   Add a DNS result to the name cache.
  27. ****************************************************************************/
  28.  
  29. static struct name_record *add_dns_result(struct nmb_name *question, struct in_addr addr)
  30. {
  31.   int name_type = question->name_type;
  32.   char *qname = question->name;
  33.   
  34.   
  35.   if (!addr.s_addr) {
  36.     /* add the fail to WINS cache of names. give it 1 hour in the cache */
  37.     DEBUG(3,("add_dns_result: Negative DNS answer for %s\n", qname));
  38.     add_name_to_subnet(wins_server_subnet,qname,name_type,
  39.                        NB_ACTIVE, 60*60, DNSFAIL_NAME, 1, &addr);
  40.     return NULL;
  41.   }
  42.  
  43.   /* add it to our WINS cache of names. give it 2 hours in the cache */
  44.   DEBUG(3,("add_dns_result: DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));
  45.  
  46.   return add_name_to_subnet(wins_server_subnet,qname,name_type,
  47.                             NB_ACTIVE, 2*60*60, DNS_NAME, 1, &addr);
  48. }
  49.  
  50.  
  51.  
  52. #ifndef SYNC_DNS
  53.  
  54. static int fd_in = -1, fd_out = -1;
  55. static int child_pid = -1;
  56. static int in_dns;
  57.  
  58. /* this is the structure that is passed between the parent and child */
  59. struct query_record {
  60.     struct nmb_name name;
  61.     struct in_addr result;
  62. };
  63.  
  64. /* a queue of pending requests waiting to be sent to the DNS child */
  65. static struct packet_struct *dns_queue;
  66.  
  67. /* the packet currently being processed by the dns child */
  68. static struct packet_struct *dns_current;
  69.  
  70.  
  71. /***************************************************************************
  72.   return the fd used to gather async dns replies. This is added to the select
  73.   loop
  74.   ****************************************************************************/
  75. int asyncdns_fd(void)
  76. {
  77.     return fd_in;
  78. }
  79.  
  80. /***************************************************************************
  81.   handle DNS queries arriving from the parent
  82.   ****************************************************************************/
  83. static void asyncdns_process(void)
  84. {
  85.     struct query_record r;
  86.     fstring qname;
  87.  
  88.     DEBUGLEVEL = -1;
  89.  
  90.     while (1) {
  91.         if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r)) 
  92.             break;
  93.  
  94.         fstrcpy(qname, r.name.name);
  95.  
  96.         r.result.s_addr = interpret_addr(qname);
  97.  
  98.         if (write_data(fd_out, (char *)&r, sizeof(r)) != sizeof(r))
  99.             break;
  100.     }
  101.  
  102.     _exit(0);
  103. }
  104.  
  105. /**************************************************************************** **
  106.   catch a sigterm (in the child process - the parent has a different handler
  107.   see nmbd.c for details).
  108.   We need a separate term handler here so we don't release any 
  109.   names that our parent is going to release, or overwrite a 
  110.   WINS db that our parent is going to write.
  111.  **************************************************************************** */
  112.  
  113. static int sig_term(void)
  114. {
  115.   _exit(0);
  116.   /* Keep compiler happy.. */
  117.   return 0;
  118. }
  119.  
  120. /***************************************************************************
  121.  Called by the parent process when it receives a SIGTERM - also kills the
  122.  child so we don't get child async dns processes lying around, causing trouble.
  123.   ****************************************************************************/
  124.  
  125. void kill_async_dns_child(void)
  126. {
  127.   if(child_pid != 0 && child_pid != -1)
  128.     kill(child_pid, SIGTERM);
  129. }
  130.  
  131. /***************************************************************************
  132.   create a child process to handle DNS lookups
  133.   ****************************************************************************/
  134. void start_async_dns(void)
  135. {
  136.     int fd1[2], fd2[2];
  137.  
  138.     signal(SIGCLD, SIG_IGN);
  139.  
  140.     if (pipe(fd1) || pipe(fd2)) {
  141.         return;
  142.     }
  143.  
  144.     child_pid = fork();
  145.  
  146.     if (child_pid) {
  147.         fd_in = fd1[0];
  148.         fd_out = fd2[1];
  149.         close(fd1[1]);
  150.         close(fd2[0]);
  151.         return;
  152.     }
  153.  
  154.     fd_in = fd2[0];
  155.     fd_out = fd1[1];
  156.  
  157.     signal(SIGUSR2, SIG_IGN);
  158.     signal(SIGUSR1, SIG_IGN);
  159.     signal(SIGHUP, SIG_IGN);
  160.         signal(SIGTERM, SIGNAL_CAST sig_term );
  161.  
  162.     asyncdns_process();
  163. }
  164.  
  165.  
  166. /***************************************************************************
  167. check if a particular name is already being queried
  168.   ****************************************************************************/
  169. static BOOL query_current(struct query_record *r)
  170. {
  171.     return dns_current &&
  172.         nmb_name_equal(&r->name, 
  173.                &dns_current->packet.nmb.question.question_name);
  174. }
  175.  
  176.  
  177. /***************************************************************************
  178.   write a query to the child process
  179.   ****************************************************************************/
  180. static BOOL write_child(struct packet_struct *p)
  181. {
  182.     struct query_record r;
  183.  
  184.     r.name = p->packet.nmb.question.question_name;
  185.  
  186.     return write_data(fd_out, (char *)&r, sizeof(r)) == sizeof(r);
  187. }
  188.  
  189. /***************************************************************************
  190.   check the DNS queue
  191.   ****************************************************************************/
  192. void run_dns_queue(void)
  193. {
  194.     struct query_record r;
  195.     struct packet_struct *p, *p2;
  196.     struct name_record *namerec;
  197.     int size;
  198.  
  199.     if (fd_in == -1)
  200.         return;
  201.  
  202.         /* Allow SIGTERM to kill us. */
  203.         BlockSignals(False, SIGTERM);
  204.  
  205.     if (!process_exists(child_pid)) {
  206.         close(fd_in);
  207.         start_async_dns();
  208.     }
  209.  
  210.     if ((size=read_data(fd_in, (char *)&r, sizeof(r))) != sizeof(r)) {
  211.         if (size) {
  212.             DEBUG(0,("Incomplete DNS answer from child!\n"));
  213.             fd_in = -1;
  214.         }
  215.                 BlockSignals(True, SIGTERM);
  216.         return;
  217.     }
  218.  
  219.         BlockSignals(True, SIGTERM);
  220.  
  221.     namerec = add_dns_result(&r.name, r.result);
  222.  
  223.     if (dns_current) {
  224.         if (query_current(&r)) {
  225.             DEBUG(3,("DNS calling send_wins_name_query_response\n"));
  226.             in_dns = 1;
  227.                         if(namerec == NULL)
  228.                           send_wins_name_query_response(NAM_ERR, dns_current, NULL);
  229.                         else
  230.               send_wins_name_query_response(0,dns_current,namerec);
  231.             in_dns = 0;
  232.         }
  233.  
  234.         dns_current->locked = False;
  235.         free_packet(dns_current);
  236.         dns_current = NULL;
  237.     }
  238.  
  239.     /* loop over the whole dns queue looking for entries that
  240.        match the result we just got */
  241.     for (p = dns_queue; p;) {
  242.         struct nmb_packet *nmb = &p->packet.nmb;
  243.         struct nmb_name *question = &nmb->question.question_name;
  244.  
  245.         if (nmb_name_equal(question, &r.name)) {
  246.             DEBUG(3,("DNS calling send_wins_name_query_response\n"));
  247.             in_dns = 1;
  248.                         if(namerec == NULL)
  249.               send_wins_name_query_response(NAM_ERR, p, NULL);
  250.                         else
  251.                           send_wins_name_query_response(0,p,namerec);
  252.             in_dns = 0;
  253.             p->locked = False;
  254.  
  255.             if (p->prev)
  256.                 p->prev->next = p->next;
  257.             else
  258.                 dns_queue = p->next;
  259.             if (p->next)
  260.                 p->next->prev = p->prev;
  261.             p2 = p->next;
  262.             free_packet(p);
  263.             p = p2;
  264.         } else {
  265.             p = p->next;
  266.         }
  267.     }
  268.  
  269.     if (dns_queue) {
  270.         dns_current = dns_queue;
  271.         dns_queue = dns_queue->next;
  272.         if (dns_queue) dns_queue->prev = NULL;
  273.         dns_current->next = NULL;
  274.  
  275.         if (!write_child(dns_current)) {
  276.             DEBUG(3,("failed to send DNS query to child!\n"));
  277.             return;
  278.         }
  279.     }
  280.  
  281. }
  282.  
  283. /***************************************************************************
  284. queue a DNS query
  285.   ****************************************************************************/
  286. BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
  287.              struct name_record **n)
  288. {
  289.     if (in_dns || fd_in == -1)
  290.         return False;
  291.  
  292.     if (!dns_current) {
  293.         if (!write_child(p)) {
  294.             DEBUG(3,("failed to send DNS query to child!\n"));
  295.             return False;
  296.         }
  297.         dns_current = p;
  298.         p->locked = True;
  299.     } else {
  300.         p->locked = True;
  301.         p->next = dns_queue;
  302.         p->prev = NULL;
  303.         if (p->next)
  304.             p->next->prev = p;
  305.         dns_queue = p;
  306.     }
  307.  
  308.     DEBUG(3,("added DNS query for %s\n", namestr(question)));
  309.     return True;
  310. }
  311.  
  312. #else
  313.  
  314.  
  315. /***************************************************************************
  316.   we use this then we can't do async DNS lookups
  317.   ****************************************************************************/
  318. BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
  319.              struct name_record **n)
  320. {
  321.     char *qname = question->name;
  322.     struct in_addr dns_ip;
  323.  
  324.     DEBUG(3,("DNS search for %s - ", namestr(question)));
  325.  
  326.         /* Unblock TERM signal so we can be killed in DNS lookup. */
  327.         BlockSignals(False, SIGTERM);
  328.  
  329.     dns_ip.s_addr = interpret_addr(qname);
  330.  
  331.         /* Re-block TERM signal. */
  332.         BlockSignals(True, SIGTERM);
  333.  
  334.     *n = add_dns_result(question, dns_ip);
  335.         if(*n == NULL)
  336.           send_wins_name_query_response(NAM_ERR, p, NULL);
  337.         else
  338.           send_wins_name_query_response(0, p, *n);
  339.     return False;
  340. }
  341.  
  342. /***************************************************************************
  343.  With sync dns there is no child to kill on SIGTERM.
  344.   ****************************************************************************/
  345. void kill_async_dns_child(void)
  346. {
  347.   return;
  348. }
  349. #endif
  350.