"Fossies" - the Fresh Open Source Software Archive

Member "etherape-0.9.18/src/names/thread_resolve.c" (14 Apr 2018, 8710 Bytes) of package /linux/privat/etherape-0.9.18.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "thread_resolve.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.9.17_vs_0.9.18.

    1 /*
    2    Etherape
    3    Copyright (C) 2005 R.Ghetta
    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., 675 Mass Ave, Cambridge, MA 02139, USA.
   18  */
   19 /*
   20    These routines use multiple threads to call gethostbyaddr() and resolve
   21    names. All thread handling is internal.
   22 */
   23 
   24 
   25 #ifdef HAVE_CONFIG_H
   26 #include <config.h>
   27 #endif
   28 
   29 #include <sys/types.h>
   30 #include <time.h>
   31 #include <sys/time.h>
   32 #include <sys/select.h>
   33 #include <sys/stat.h>
   34 #include <sys/errno.h>
   35 #include <sys/socket.h>
   36 #include <netinet/in.h>
   37 #include <arpa/inet.h>
   38 #if defined(__MACH__) && defined(__APPLE__)
   39 #include <arpa/nameser_compat.h>
   40 #else
   41 #include <arpa/nameser.h>
   42 #endif
   43 #include <netdb.h>
   44 #include <resolv.h>
   45 #include <unistd.h>
   46 #include <fcntl.h>
   47 #include <ctype.h>
   48 #include <string.h>
   49 #include <stdio.h>
   50 #include <stdlib.h>
   51 #include <errno.h>
   52 #include <pthread.h>
   53 #include "common.h"
   54 #include "ip-cache.h"
   55 #include "thread_resolve.h"
   56 #include "stats/util.h"
   57 
   58 #define ETHERAPE_THREAD_POOL_SIZE 6
   59 static pthread_t resolver_threads[ETHERAPE_THREAD_POOL_SIZE];
   60 static int resolver_threads_num = 0;
   61 
   62 /* to-resolve-items linked list */
   63 struct ipresolve_link
   64 {
   65   struct ipcache_item *itemToResolve;
   66   struct ipresolve_link *next;   
   67 };
   68 static struct ipresolve_link *resolveListHead=NULL;  
   69 static struct ipresolve_link *resolveListTail=NULL;  
   70 
   71 static int request_stop_thread = 0; /* stop thread flag */
   72 
   73 /* mutexes */
   74 
   75 static pthread_mutex_t resolvemtx; /* resolve mutex */
   76 static pthread_cond_t resolvecond; /* resolve condition var */
   77 
   78 static int open_mutex(void)
   79 {
   80     if (!pthread_mutex_init (&resolvemtx, NULL) &&
   81         !pthread_cond_init (&resolvecond, NULL))
   82       return 0; /* ok*/
   83     else
   84       return 1; 
   85 }
   86 
   87 static void
   88 close_mutex(void)
   89 {
   90     pthread_mutex_destroy(&resolvemtx);
   91     pthread_cond_destroy(&resolvecond);
   92 }
   93 
   94 /* thread routine */
   95 static void *thread_pool_routine(void *dt)
   96 {
   97    struct ipcache_item *curitem;
   98    struct ipresolve_link *el;   
   99    struct hostent *resultptr;
  100    struct sockaddr_in sa;
  101    struct sockaddr_in6 sa6;
  102    struct sockaddr *saptr;
  103    socklen_t salen;
  104    
  105    char extrabuf[4096];
  106    int result;
  107 
  108    while (!request_stop_thread)
  109    {
  110       pthread_mutex_lock(&resolvemtx);
  111 
  112       if (!request_stop_thread && !resolveListHead)
  113       {
  114          /* list empty, wait on condition releasing mutex */
  115          pthread_cond_wait (&resolvecond, &resolvemtx);
  116       }
  117 
  118       /* from now on, mutex is locked */
  119 
  120       if (request_stop_thread)
  121       {
  122          /* must exit */
  123          pthread_mutex_unlock(&resolvemtx);
  124          break;
  125       }
  126 
  127       /* if we come here head should be filled, but a check doesn't hurt ... */
  128       if (resolveListHead)
  129       {
  130          /* there is something to resolve, take out from head */
  131          el = resolveListHead;
  132          resolveListHead = el->next;
  133          curitem = el->itemToResolve;
  134          
  135          /* ok, release mutex and resolve */
  136          pthread_mutex_unlock(&resolvemtx);
  137 
  138          free(el); /* item saved, link elem now useless, freeing */
  139 
  140 #ifdef FORCE_SINGLE_THREAD
  141          /* if forced single thread, uses gethostbyaddr */
  142          result=0;
  143          resultptr = gethostbyaddr (&curitem->ip.addr8, 
  144                           address_len(curitem->ip.type), curitem->ip.type);
  145          if (request_stop_thread)
  146             break;
  147 
  148          /* resolving completed or failed, lock again and notify ip-cache */
  149          pthread_mutex_lock(&resolvemtx);
  150          if (result || !resultptr)
  151             ipcache_request_failed(curitem); 
  152          else
  153             ipcache_request_succeeded(curitem, 3600L*24L, resultptr->h_name);
  154 #else
  155          /* full multithreading, use thread safe getnameinfo */
  156          if (curitem->ip.type == AF_INET) {
  157            memset(&sa, 0, sizeof sa);
  158            sa.sin_family = curitem->ip.type;
  159            g_assert(sizeof(sa.sin_addr) == sizeof(curitem->ip.addr_v4));
  160            memmove(&sa.sin_addr, curitem->ip.addr_v4, sizeof sa.sin_addr);
  161            saptr = (struct sockaddr *)&sa;
  162            salen = sizeof sa;
  163          } else {
  164            memset(&sa6, 0, sizeof sa6);
  165            sa6.sin6_family = curitem->ip.type;
  166            g_assert(sizeof(sa6.sin6_addr) == sizeof(curitem->ip.addr_v6));
  167            memmove(&sa6.sin6_addr, curitem->ip.addr_v6, sizeof sa6.sin6_addr);
  168            saptr = (struct sockaddr *)&sa6;
  169            salen = sizeof sa6;
  170          }
  171          
  172          result = getnameinfo(saptr, salen, 
  173                               extrabuf,  sizeof(extrabuf), 
  174                               NULL, 0,
  175                               0);
  176          if (result != 0 && result != EAI_AGAIN) {
  177            g_my_critical("getnameinfo error %d (%s)\n", 
  178                          result, gai_strerror(result));
  179          }
  180          if (request_stop_thread)
  181             break;
  182 
  183          /* resolving completed or failed, lock again and notify ip-cache */
  184          pthread_mutex_lock(&resolvemtx);
  185          if (result)
  186             ipcache_request_failed(curitem); 
  187          else
  188             ipcache_request_succeeded(curitem, 3600L*24L, extrabuf);
  189 #endif
  190       }
  191 
  192       pthread_mutex_unlock(&resolvemtx);
  193    }
  194    return NULL;
  195 }
  196 
  197 static void start_threads()
  198 {
  199    pthread_t curth;
  200    int i;
  201    int maxth = ETHERAPE_THREAD_POOL_SIZE;
  202    pthread_attr_t attr;
  203 
  204    /* reset stop flag */
  205    request_stop_thread = 0;
  206 
  207    if (pthread_attr_init(&attr) ||
  208        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
  209      {
  210        g_critical("pthread_attr_init failed, resolver will not be available\n");
  211        return; 
  212      }
  213   
  214   /* if single thread resolving is forced, then start only a single thread,
  215      else start ETHERAPE_THREAD_POOL_SIZE threads */
  216 #ifdef FORCE_SINGLE_THREAD
  217    maxth = 1;
  218 #endif
  219    for (i=0; i<maxth ; ++i)
  220    {
  221      if (pthread_create ( &curth, NULL, thread_pool_routine, NULL))
  222      {
  223        // error, stop creating threads
  224        g_critical("pthread_create failed, resolver has only %d threads\n", i);
  225        break;
  226      }
  227      resolver_threads[i] = curth;
  228    }
  229 
  230    resolver_threads_num = i;
  231 }
  232 
  233 static void stop_threads()
  234 {
  235   int i;
  236 
  237   /* take mutex, to make sure other thread will be waiting */
  238   pthread_mutex_lock(&resolvemtx);
  239 
  240   /* activate variable */
  241   request_stop_thread = 1;
  242   pthread_cond_broadcast(&resolvecond); /* wake all threads */
  243   pthread_mutex_unlock(&resolvemtx);
  244 
  245   /* Now wait for them to actually finish */
  246   for (i = 0; i < resolver_threads_num; i++)
  247     pthread_join(resolver_threads[i], NULL);
  248 
  249   resolver_threads_num = 0;
  250 }
  251 
  252 /* creates a request, placing in the queue 
  253    NOTE: mutex locked!
  254 */
  255 static void
  256 sendrequest_inverse (address_t *ip)
  257 {
  258   struct ipcache_item *rp = NULL;
  259 
  260   if (!ip)
  261       return;
  262 
  263   /* allocate a new request */
  264   rp = ipcache_prepare_request(ip);
  265 
  266   /* prepare resolve item */
  267   struct ipresolve_link *newitm= (struct ipresolve_link *)malloc( sizeof(struct ipresolve_link));
  268   newitm->itemToResolve = rp;
  269   newitm->next= NULL;
  270 
  271   /* items placed on list tail and consumed from head (this gives a FIFO strategy) */
  272   if (NULL == resolveListHead)
  273   {
  274      /* first item, we put head=tail */
  275      resolveListTail = resolveListHead = newitm;
  276   }
  277   else
  278   {
  279      resolveListTail->next = newitm;
  280      resolveListTail = newitm;
  281   }
  282   
  283   /* signal the condition and release the mux */
  284   pthread_cond_signal(&resolvecond);
  285 
  286   g_my_debug("Resolver: queued request \"%s\".", address_to_str(&rp->ip));
  287 }
  288 
  289 /* called to activate the resolver */
  290 int 
  291 thread_open (void)
  292 {
  293   /* mutex creation */ 
  294   if (open_mutex())
  295     return 1;
  296 
  297   /* cache activation */  
  298   ipcache_init();
  299 
  300   /* thread pool activation */ 
  301   start_threads();
  302 
  303   return 0;
  304 }
  305 
  306 /* called to close the resolver */
  307 void
  308 thread_close(void)
  309 {
  310   /* thread pool shutdown */ 
  311   stop_threads();
  312    
  313   /* close mutex */ 
  314   close_mutex();
  315 }
  316 
  317 const char *
  318 thread_lookup (address_t *ip)
  319 {
  320   const char *ipname;
  321 
  322   if (!ip)
  323       return "";
  324 
  325   /* locks mutex */
  326   pthread_mutex_lock(&resolvemtx);
  327 
  328   /* asks cache */
  329   ipname = ipcache_lookup(ip);
  330 
  331   if (!ipname)
  332       sendrequest_inverse (ip); /* request needed */
  333 
  334   /* release mutex and exit */
  335   pthread_mutex_unlock(&resolvemtx);
  336   return ipname;
  337 }