"Fossies" - the Fresh Open Source Software Archive

Member "etherape-0.9.18/src/datastructs.c" (3 Jun 2018, 13094 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 "datastructs.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 /* EtherApe
    2  * Copyright (C) 2001 Juan Toledo, Riccardo Ghetta
    3  *
    4  * This program is free software; you can redistribute it and/or modify
    5  * it under the terms of the GNU General Public License as published by
    6  * the Free Software Foundation; either version 2 of the License, or
    7  * (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
   16  */
   17 
   18 #ifdef HAVE_CONFIG_H
   19 #include <config.h>
   20 #endif
   21 
   22 #include <glib.h>
   23 #include <gtk/gtk.h>
   24 #include <netdb.h>
   25 #include "datastructs.h"
   26 #include "appdata.h"
   27 #include "stats/util.h"
   28 
   29 #define LINESIZE 1024
   30 
   31 
   32 /************************************************************************
   33  *
   34  * services and port_service_t data and functions
   35  *
   36  ************************************************************************/
   37 static GTree *service_names = NULL;
   38 static GTree *tcp_services = NULL;
   39 static GTree *udp_services = NULL;
   40 static void services_fill_preferred(void);
   41 static port_service_t *port_service_new(port_type_t port, const gchar *name);
   42 static void port_service_free(port_service_t *);
   43 
   44 /************************************************************************
   45  *
   46  * proto->color hash table support functions
   47  *
   48  ************************************************************************/
   49 static GHashTable *protohash = NULL; /* the hash table containing proto,color pairs*/
   50 static GList *cycle_color_list = NULL; /* the list of colors without protocol */
   51 static GList *current_cycle = NULL; /* current ptr to free color */
   52 
   53 /* adds or replaces the protoname item */
   54 static gboolean protohash_set(gchar *protoname, const GdkRGBA *protocolor);
   55 
   56 static void freehash(gpointer data)
   57 {
   58   g_free(data);
   59 }
   60 
   61 static gboolean
   62 protohash_init(void)
   63 {
   64    if (protohash)
   65       return TRUE; /* already ok */
   66 
   67    protohash = g_hash_table_new_full(g_str_hash,
   68                                      g_str_equal,
   69                                      freehash,
   70                                      freehash);
   71    return protohash != NULL;
   72 }
   73 
   74 /* clears the proto hash */
   75 void
   76 protohash_clear(void)
   77 {
   78    if (protohash)
   79    {
   80       g_hash_table_destroy(protohash);
   81       protohash=NULL;
   82    }
   83 
   84    while (cycle_color_list)
   85      {
   86        g_free(cycle_color_list->data);
   87        cycle_color_list = g_list_delete_link(cycle_color_list,cycle_color_list);
   88      }
   89   current_cycle = NULL;
   90 }
   91 
   92 /* adds or replaces the protoname item */
   93 static gboolean
   94 protohash_set(gchar *protoname, const GdkRGBA *protocolor)
   95 {
   96   ColorHashItem item;
   97 
   98   g_assert(protocolor);
   99   if (!protohash && ! protohash_init())
  100     return FALSE;
  101 
  102   item.color = *protocolor;
  103 
  104   /* if a protocol is specified, we put the pair (proto,color) in the hash,
  105    * marking it as preferred (a color obtained from user mappings) */
  106   if (protoname && *protoname)
  107     {
  108       item.preferred = TRUE;
  109       g_hash_table_insert(protohash, g_strdup(protoname),
  110                        g_memdup(&item, sizeof(ColorHashItem)));
  111     }
  112 
  113   /* Without protocols defined we add the color to the cycle list. Cycle colors
  114      aren't preferred */
  115    if (!protoname || !*protoname)
  116      {
  117        item.preferred = FALSE;
  118        cycle_color_list = g_list_prepend(cycle_color_list,
  119                             g_memdup(&item, sizeof(ColorHashItem)));
  120        current_cycle = cycle_color_list;
  121      }
  122 
  123    return TRUE;
  124 }
  125 
  126 /* resets the cycle color to start of list */
  127 void protohash_reset_cycle(void)
  128 {
  129   current_cycle = cycle_color_list;
  130 }
  131 
  132 /* returns the colorhash item from the named protocol, creating a new entry if
  133    needed.  Internal use only */
  134 static const ColorHashItem *protohash_itemproto(const gchar *protoname)
  135 {
  136   const ColorHashItem *item;
  137   g_assert(protoname); /* proto must be valid - note: empty IS valid, NULL no*/
  138   g_assert(protohash);
  139 
  140   item = (ColorHashItem *)g_hash_table_lookup(protohash, protoname);
  141   if (!item)
  142     {
  143       /* color not found, take from cycle list */
  144       item = (ColorHashItem *)current_cycle->data;
  145 
  146       /* add to hash */
  147       g_hash_table_insert(protohash, g_strdup(protoname),
  148                          g_memdup(item, sizeof(ColorHashItem)));
  149 
  150       /* advance cycle */
  151       current_cycle = current_cycle->next;
  152       if (!current_cycle)
  153         current_cycle = cycle_color_list;
  154     }
  155 /*  g_my_debug ("Protocol %s in color 0x%2.2x%2.2x%2.2x",
  156               protoname, color->red, color->green, color->blue); */
  157   return item;
  158 }
  159 
  160 const GdkRGBA *protohash_color(const gchar *protoname)
  161 {
  162   g_assert(protoname); /* proto must be valid - note: empty IS valid, NULL no*/
  163   g_assert(protohash);
  164   return &(protohash_itemproto(protoname)->color);
  165 }
  166 
  167 /* returns the preferred flag */
  168 gboolean protohash_is_preferred(const gchar *protoname)
  169 {
  170   const ColorHashItem *item;
  171   g_assert(protoname); /* proto must be valid - note: empty IS valid, NULL no*/
  172   g_assert(protohash);
  173 
  174   item = (ColorHashItem *)g_hash_table_lookup(protohash, protoname);
  175   if (!item)
  176     return FALSE;
  177 
  178   return item->preferred;
  179 }
  180 
  181 /* fills the hash from a pref vector */
  182 gboolean
  183 protohash_read_prefvect(gchar **colors)
  184 {
  185   int i;
  186   GdkRGBA color;
  187 
  188   protohash_clear();
  189 
  190   /* fills with colors */
  191   for (i = 0; colors[i]; ++i)
  192     {
  193       gchar **colors_protocols, **protos;
  194       int j;
  195 
  196       colors_protocols = g_strsplit_set(colors[i], "; \t\n", 0);
  197       if (!colors_protocols[0])
  198     continue;
  199 
  200       /* converting color */
  201       gdk_rgba_parse(&color, colors_protocols[0]);
  202 
  203       if (!colors_protocols[1] || !strlen(colors_protocols[1]))
  204         protohash_set(colors_protocols[1], &color);
  205       else
  206         {
  207           /* multiple protos, split them */
  208           protos = g_strsplit_set(colors_protocols[1], ", \t\n", 0);
  209           for (j = 0 ; protos[j] ; ++j)
  210             if (protos[j] && *protos[j])
  211               protohash_set(protos[j], &color);
  212           g_strfreev(protos);
  213         }
  214       g_strfreev(colors_protocols);
  215     }
  216 
  217   if (!cycle_color_list)
  218     {
  219       /* the list of color available for unmapped protocols is empty,
  220        * so we add a grey */
  221       gdk_rgba_parse(&color, "#7f7f7f");
  222       protohash_set(NULL, &color);
  223     }
  224   else
  225     cycle_color_list = g_list_reverse(cycle_color_list); /* list was reversed */
  226 
  227   /* update preferred flag on services tree */
  228   services_fill_preferred();
  229   return TRUE;
  230 }
  231 
  232 
  233 
  234 /* compacts the array of colors/protocols mappings by collapsing identical
  235  * colors - frees the input array */
  236 gchar **protohash_compact(gchar **colors)
  237 {
  238    int i;
  239    gchar **compacted;
  240    GList *work;
  241    GList *el;
  242 
  243    /* constructs a list with unique colors. We use a list to maintain the
  244       fill order of the dialog. This is less surprising for the user. */
  245    work = NULL;
  246    for (i = 0; colors[i] ; ++i)
  247     {
  248       gchar **colors_protocols;
  249 
  250       colors_protocols = g_strsplit_set(colors[i], "; \t\n", 0);
  251       if (!colors_protocols[0])
  252     continue;
  253 
  254       colors_protocols[1] = remove_spaces(colors_protocols[1]);
  255 
  256       for (el = g_list_first(work) ; el ; el = g_list_next(el) )
  257         {
  258           gchar **col=(gchar **)(el->data);
  259       if (!col || !col[0])
  260         continue;
  261           if (!g_ascii_strcasecmp(col[0], colors_protocols[0]))
  262             {
  263               /* found same color, append protocol */
  264               gchar *old = col[1];
  265               if (colors_protocols[1] && *colors_protocols[1])
  266                 {
  267                   if (old)
  268                     col[1] = g_strjoin(",", old, colors_protocols[1], NULL);
  269                   else
  270                     col[1] = g_strdup(colors_protocols[1]);
  271                   g_free(old);
  272                 }
  273               break;
  274             }
  275         }
  276 
  277       if (el)
  278         g_strfreev(colors_protocols); /* found, free temporary */
  279       else
  280         {
  281           /* color not found, adds to list - no need to free here */
  282           work = g_list_prepend(work, colors_protocols);
  283         }
  284     }
  285 
  286   /* reverse list to match original order (with GList, prepend+reverse is more
  287      efficient than append */
  288   work = g_list_reverse(work);
  289 
  290   /* now scans the list filling the protostring */
  291   compacted = malloc( sizeof(gchar *) * (g_list_length(work) + 1) );
  292   i = 0;
  293   for (el = g_list_first(work) ; el ; el = g_list_next(el) )
  294     {
  295       gchar **col=(gchar **)(el->data);
  296       compacted[i++] = g_strjoin(";", col[0], col[1], NULL);
  297       g_strfreev(col);
  298     }
  299   compacted[i] = NULL;
  300   g_list_free(work);
  301   g_strfreev(colors);
  302   return compacted;
  303 }
  304 
  305 /*
  306  ***********************************************************************
  307  *
  308  * compacting function
  309  *
  310  ***********************************************************************
  311 */
  312 gchar *remove_spaces(gchar *str)
  313 {
  314   char *out = str;
  315   char *cur = str;
  316   if (str)
  317     {
  318       for (cur = str ; *cur ; ++cur)
  319         if ( !g_ascii_isspace((guchar)(*cur)))
  320           *out++ = *cur;
  321       *out = '\0';
  322     }
  323   return str;
  324 }
  325 
  326 
  327 /************************************************************************
  328  *
  329  * proto name mappers
  330  *
  331  ************************************************************************/
  332 
  333 /* Comparison function to sort tcp/udp services by port number */
  334 static gint services_port_cmp(gconstpointer a, gconstpointer b, gpointer unused)
  335 {
  336   port_type_t port_a, port_b;
  337 
  338   port_a = *(port_type_t *) a;
  339   port_b = *(port_type_t *) b;
  340 
  341   if (port_a > port_b)
  342     return 1;
  343   if (port_a < port_b)
  344     return -1;
  345   return 0;
  346 }               /* services_port_cmp */
  347 
  348 /* Comparison function to sort service names */
  349 static gint services_name_cmp(gconstpointer a, gconstpointer b, gpointer unused)
  350 {
  351   return g_ascii_strcasecmp((const gchar *)a, (const gchar *)b);
  352 }
  353 
  354 static void services_tree_free(gpointer p)
  355 {
  356   port_service_free( (port_service_t *)p);
  357 }
  358 
  359 /* traverse function to map names to ports */
  360 static gboolean services_port_trv(gpointer key, gpointer value, gpointer data)
  361 {
  362   const port_service_t *svc = (const port_service_t *)value;
  363   GTree *tree = (GTree *)data;
  364   port_service_t *new_el;
  365 
  366   new_el = port_service_new(svc->port, svc->name);
  367   g_tree_replace(tree, new_el->name, new_el);
  368   return FALSE;
  369 }
  370 
  371 /* traverse function to fill preferred field */
  372 static gboolean services_pref_trv(gpointer key, gpointer value, gpointer data)
  373 {
  374   port_service_t *svc = (port_service_t *)value;
  375   svc->preferred = protohash_is_preferred(svc->name);
  376   return FALSE;
  377 }
  378 static void services_fill_preferred(void)
  379 {
  380   if (udp_services)
  381     g_tree_foreach(udp_services, services_pref_trv, NULL);
  382   if (tcp_services)
  383     g_tree_foreach(tcp_services, services_pref_trv, NULL);
  384 }
  385 
  386 void services_init(void)
  387 {
  388   struct servent *ent;
  389   port_service_t *port_service;
  390 
  391   g_assert(!service_names && !tcp_services && !udp_services);
  392 
  393   service_names = g_tree_new_full(services_name_cmp, NULL, NULL, services_tree_free);
  394   tcp_services = g_tree_new_full(services_port_cmp, NULL, NULL, services_tree_free);
  395   udp_services = g_tree_new_full(services_port_cmp, NULL, NULL, services_tree_free);
  396 
  397   while ((ent = getservent()))
  398     {
  399       if (g_ascii_strcasecmp(ent->s_proto, "tcp")
  400           && g_ascii_strcasecmp(ent->s_proto, "udp"))
  401         g_my_info(_("%s protocol not supported"), ent->s_proto);
  402       else
  403         {
  404           port_service = port_service_new(ntohs(ent->s_port), ent->s_name);
  405           g_tree_replace(ent->s_proto[0] == 't' ? tcp_services : udp_services,
  406                          &port_service->port, port_service);
  407         }
  408     }
  409 
  410   endservent();
  411 
  412   /* now traverse port->name trees to fill the name->port tree */
  413   g_tree_foreach(udp_services, services_port_trv, service_names);
  414   g_tree_foreach(tcp_services, services_port_trv, service_names);
  415 
  416   /* and finally assign preferred services */
  417   services_fill_preferred();
  418 }
  419 
  420 void services_clear(void)
  421 {
  422   g_tree_destroy(service_names);
  423   g_tree_destroy(tcp_services);
  424   g_tree_destroy(udp_services);
  425 }
  426 
  427 const port_service_t *services_tcp_find(port_type_t port)
  428 {
  429   if (tcp_services)
  430       return (port_service_t *)g_tree_lookup (tcp_services, &port);
  431   else
  432     return NULL;
  433 }
  434 
  435 const port_service_t *services_udp_find(port_type_t port)
  436 {
  437   if (udp_services)
  438       return (port_service_t *)g_tree_lookup (udp_services, &port);
  439   else
  440     return NULL;
  441 }
  442 
  443 /************************************************************************
  444  *
  445  * port_service_t functions
  446  *
  447  ************************************************************************/
  448 port_service_t *port_service_new(port_type_t port, const gchar *name)
  449 {
  450   port_service_t *p;
  451   p = g_malloc (sizeof (port_service_t));
  452   g_assert(p);
  453 
  454   p->port = port;
  455   p->name = g_ascii_strup(name, -1);
  456   p->preferred = FALSE;
  457   return p;
  458 }
  459 
  460 void port_service_free(port_service_t *p)
  461 {
  462   if (p)
  463     g_free(p->name);
  464   g_free(p);
  465 }
  466 
  467 const port_service_t *services_port_find(const gchar *name)
  468 {
  469   if (!name || !service_names)
  470     return NULL;
  471 
  472   return (const port_service_t *)g_tree_lookup (service_names, name);
  473 }