void add_conversation (address_t * src_address, address_t * dst_address, guint16 src_port, guint16 dst_port, const gchar * data) { conversation_t *conv = NULL; const gchar *old_data = NULL; if (!src_address || !dst_address) { g_my_critical("NULL ptr in add_conversation"); return; } /* Make sure there is not one such conversation */ if ((old_data = find_conversation (src_address, dst_address, src_port, dst_port))) { if (!strcmp (old_data, data)) g_my_critical ("Conflicting conversations %s:%d-%s:%d in add_conversation", address_to_str (src_address), src_port, address_to_str (dst_address), dst_port); else g_my_debug ("Conversation %s:%d-%s:%d %s already exists in add_conversation", address_to_str (src_address), src_port, address_to_str (dst_address), dst_port, data); return; } g_my_debug ("Adding new conversation %s:%d-%s:%d %s", address_to_str (src_address), src_port, address_to_str (dst_address), dst_port, data); conv = g_malloc (sizeof (conversation_t)); g_assert(conv); address_copy(&conv->src_address, src_address); address_copy(&conv->dst_address, dst_address); conv->src_port = src_port; conv->dst_port = dst_port; conv->data = g_strdup (data); conversations = g_list_prepend (conversations, conv); n_conversations++; } /* add_conversation */
static gint add_ordered_node (node_id_t * node_id, canvas_node_t * node, GTree * ordered_nodes) { g_tree_insert (ordered_nodes, node, node); g_my_debug ("Adding ordered node. Number of nodes: %d", g_tree_nnodes (ordered_nodes)); return FALSE; /* keep on traversing */ } /* add_ordered_node */
/* This function is called to discard packets from the list * of packets beloging to a node or a link, and to calculate * the average traffic for that node or link */ gboolean node_update(node_id_t * node_id, node_t *node, gpointer delete_list_ptr) { double diffms; g_assert(delete_list_ptr); if (traffic_stats_update(&node->node_stats, pref.averaging_time, pref.proto_node_timeout_time)) { /* packet(s) active, update the most used protocols for this link */ guint i = STACK_SIZE; while (i + 1) { if (node->main_prot[i]) g_free (node->main_prot[i]); node->main_prot[i] = protocol_stack_sort_most_used(&node->node_stats.stats_protos, i); i--; } node_name_update (node); } else { /* no packets remaining on node - if node expiration active, see if the * node is expired */ if (pref.node_timeout_time) { diffms = substract_times_ms(&appdata.now, &node->node_stats.stats.last_time); if (diffms >= pref.node_timeout_time) { /* node expired, remove */ GList **delete_list = (GList **)delete_list_ptr; if (DEBUG_ENABLED) { gchar *msg = node_id_dump(&node->node_id); g_my_debug(_("Queuing node '%s' for remove"), msg); g_free(msg); } /* First thing we do is delete the node from the list of new_nodes, * if it's there */ new_nodes_remove(node); /* adds current to list of nodes to be delete */ *delete_list = g_list_prepend( *delete_list, node_id); } } } return FALSE; }
/* Calls update_node for every node. This is actually a function that shouldn't be called often, because it might take a very long time to complete */ void nodes_catalog_update_all(void) { GList *delete_list = NULL; if (!all_nodes) return; /* we can't delete nodes while traversing the catalog, so while updating we * fill a list with the node_id's to remove */ nodes_catalog_foreach((GTraverseFunc) node_update, &delete_list); /* after, remove all nodes on the list from catalog * WARNING: after this call, the list items are also destroyed */ g_list_foreach(delete_list, gfunc_remove_node, NULL); /* free the list - list items are already destroyed */ g_list_free(delete_list); g_my_debug(_("Updated nodes. Active nodes %d"), nodes_catalog_size()); } /* update_nodes */
void delete_conversations (void) { GList *item = conversations; conversation_t *conv = NULL; while (item) { conv = item->data; g_my_debug ("Removing conversation %s:%d-%s:%d %s", address_to_str (&conv->src_address), conv->src_port, address_to_str (&conv->dst_address), conv->dst_port, conv->data); g_free (conv->data); g_free (conv); item = item->next; n_conversations--; } g_list_free (conversations); conversations = NULL; } /* delete_conversations */
/* Called for every event a node receives. Right now it's used to * set a message in the statusbar and launch the popup timeout */ static gint node_item_event (GnomeCanvasItem * item, GdkEvent * event, canvas_node_t * canvas_node) { gdouble item_x, item_y; const node_t *node = NULL; /* This is not used yet, but it will be. */ item_x = event->button.x; item_y = event->button.y; gnome_canvas_item_w2i (item->parent, &item_x, &item_y); switch (event->type) { case GDK_2BUTTON_PRESS: if (canvas_node) node = nodes_catalog_find(&canvas_node->canvas_node_id); if (node) { node_protocols_window_create( &canvas_node->canvas_node_id ); g_my_info ("Nodes: %d (shown %u)", nodes_catalog_size(), displayed_nodes); if (DEBUG_ENABLED) { gchar *msg = node_dump(node); g_my_debug("%s", msg); g_free(msg); } } break; default: break; } return FALSE; } /* node_item_event */
/* Returns a node from the list of new nodes or NULL if there are no more * new nodes */ node_t * new_nodes_pop(void) { node_t *node = NULL; GList *old_item = NULL; if (!new_nodes) return NULL; node = new_nodes->data; old_item = new_nodes; /* We make sure now that the node hasn't been deleted since */ /* TODO Sometimes when I get here I have a node, but a null * node->node_id. What gives? */ while (node && !nodes_catalog_find(&node->node_id)) { g_my_debug ("Already deleted node in list of new nodes, in new_nodes_pop"); /* Remove this node from the list of new nodes */ new_nodes = g_list_remove_link (new_nodes, new_nodes); g_list_free_1 (old_item); if (new_nodes) node = new_nodes->data; else node = NULL; old_item = new_nodes; } if (!new_nodes) return NULL; /* Remove this node from the list of new nodes */ new_nodes = g_list_remove_link (new_nodes, new_nodes); g_list_free_1 (old_item); return node; }
static void set_debug_level (void) { const gchar *env_debug; env_debug = g_getenv("APE_DEBUG"); appdata.debug_mask = (G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO)); if (env_debug) { if (!g_ascii_strcasecmp(env_debug, "INFO")) appdata.debug_mask = (G_LOG_LEVEL_MASK & ~G_LOG_LEVEL_DEBUG); else if (!g_ascii_strcasecmp(env_debug, "DEBUG")) appdata.debug_mask = G_LOG_LEVEL_MASK; } if (quiet) appdata.debug_mask = 0; g_log_set_handler (NULL, G_LOG_LEVEL_MASK, (GLogFunc) log_handler, NULL); g_my_debug ("debug_mask %d", appdata.debug_mask); }
/* removes all conversations with the specified addresses */ void delete_conversation_link(address_t * src_address, address_t * dst_address) { GList *item; if (!src_address || !dst_address) { g_my_critical("NULL ptr in delete_conversation_link"); return; } while ( (item = find_conversation_ptr(src_address, dst_address, 0, 0)) ) { conversation_t *conv = NULL; conv = item->data; g_my_debug ("Removing conversation %s:%d-%s:%d %s", address_to_str (&conv->src_address), conv->src_port, address_to_str (&conv->dst_address), conv->dst_port, conv->data); g_free (conv->data); g_free (conv); conversations = g_list_delete_link(conversations, item); n_conversations--; } }
/* TODO this is probably this single piece of code I am most ashamed of. * I should learn how to use flex or yacc and do this The Right Way (TM)*/ void services_init(void) { FILE *services = NULL; gchar *line; gchar **t1 = NULL, **t2 = NULL; gchar *str; port_service_t *port_service; guint i; char filename[PATH_MAX]; port_type_t port_number; /* udp and tcp are the same */ if (tcp_services) return; /* already loaded */ safe_strncpy(filename, CONFDIR "/services", sizeof(filename)); if (!(services = fopen (filename, "r"))) { safe_strncpy(filename, "/etc/services", sizeof(filename)); if (!(services = fopen (filename, "r"))) { g_my_critical (_ ("Failed to open %s. No TCP or UDP services will be recognized"), filename); return; } } g_my_info (_("Reading TCP and UDP services from %s"), filename); service_names = g_tree_new_full(services_name_cmp, NULL, NULL, services_tree_free); tcp_services = g_tree_new_full(services_port_cmp, NULL, NULL, services_tree_free); udp_services = g_tree_new_full(services_port_cmp, NULL, NULL, services_tree_free); line = g_malloc (LINESIZE); g_assert(line); while (fgets (line, LINESIZE, services)) { if (line[0] != '#' && line[0] != ' ' && line[0] != '\n' && line[0] != '\t') { gboolean error = FALSE; if (!g_strdelimit (line, " \t\n", ' ')) error = TRUE; if (error || !(t1 = g_strsplit (line, " ", 0))) error = TRUE; if (!error && t1[0]) { gchar *told = t1[0]; t1[0] = g_ascii_strup (told, -1); g_free(told); } for (i = 1; t1[i] && !strcmp ("", t1[i]); i++) ; if (!error && (str = t1[i])) if (!(t2 = g_strsplit (str, "/", 0))) error = TRUE; if (error || !t2 || !t2[0]) error = TRUE; /* TODO The h here is not portable */ if (error || !sscanf (t2[0], "%hd", &port_number) || (port_number < 1)) error = TRUE; if (error || !t2[1]) error = TRUE; if (error || (g_ascii_strcasecmp ("udp", t2[1]) && g_ascii_strcasecmp ("tcp", t2[1]) && g_ascii_strcasecmp ("ddp", t2[1]) && g_ascii_strcasecmp ("sctp", t2[1]) )) error = TRUE; if (error) g_warning (_("Unable to parse line %s"), line); else { #if DEBUG g_my_debug ("Loading service %s %s %d", t2[1], t1[0], port_number); #endif if (!g_ascii_strcasecmp ("ddp", t2[1])) g_my_info (_("DDP protocols not supported in %s"), line); else if (!g_ascii_strcasecmp ("sctp", t2[1])) g_my_info (_("SCTP protocols not supported in %s"), line); else { /* map port to name, to two trees */ port_service = port_service_new(port_number, t1[0]); if (!g_ascii_strcasecmp ("tcp", t2[1])) g_tree_replace(tcp_services, &(port_service->port), port_service); else if (!g_ascii_strcasecmp ("udp", t2[1])) g_tree_replace(udp_services, &(port_service->port), port_service); } } g_strfreev (t2); t2 = NULL; g_strfreev (t1); t1 = NULL; } } fclose (services); g_free (line); /* now traverse port->name trees to fill the name->port tree */ g_tree_foreach(udp_services, services_port_trv, service_names); g_tree_foreach(tcp_services, services_port_trv, service_names); /* and finally assign preferred services */ services_fill_preferred(); } /* services_init */
/* - updates sizes, names, etc */ static gint canvas_node_update(node_id_t * node_id, canvas_node_t * canvas_node, GList **delete_list) { node_t *node; gdouble node_size; static clock_t start = 0; clock_t end; gdouble cpu_time_used; char *nametmp = NULL; node = nodes_catalog_find(node_id); /* Remove node if node is too old or if capture is stopped */ if (!node || !display_node (node)) { /* adds current to list of canvas nodes to delete */ *delete_list = g_list_prepend( *delete_list, node_id); g_my_debug ("Queing canvas node to remove."); need_reposition = TRUE; return FALSE; } switch (pref.node_size_variable) { case INST_TOTAL: node_size = get_node_size (node->node_stats.stats.average); break; case INST_INBOUND: node_size = get_node_size (node->node_stats.stats_in.average); break; case INST_OUTBOUND: node_size = get_node_size (node->node_stats.stats_out.average); break; case INST_PACKETS: node_size = get_node_size (node->node_stats.pkt_list.length); break; case ACCU_TOTAL: node_size = get_node_size (node->node_stats.stats.accumulated); break; case ACCU_INBOUND: node_size = get_node_size (node->node_stats.stats_in.accumulated); break; case ACCU_OUTBOUND: node_size = get_node_size (node->node_stats.stats_out.accumulated); break; case ACCU_PACKETS: node_size = get_node_size (node->node_stats.stats.accu_packets); break; case ACCU_AVG_SIZE: node_size = get_node_size (node->node_stats.stats.avg_size); break; default: node_size = get_node_size (node->node_stats.stats_out.average); g_warning (_("Unknown value or node_size_variable")); } /* limit the maximum size to avoid overload */ if (node_size > MAX_NODE_SIZE) node_size = MAX_NODE_SIZE; if (node->main_prot[pref.stack_level]) { canvas_node->color = protohash_color(node->main_prot[pref.stack_level]); gnome_canvas_item_set (canvas_node->node_item, "x1", -node_size / 2, "x2", node_size / 2, "y1", -node_size / 2, "y2", node_size / 2, "fill_color_gdk", &(canvas_node->color), NULL); } else { guint32 black = 0x000000ff; gnome_canvas_item_set (canvas_node->node_item, "x1", -node_size / 2, "x2", node_size / 2, "y1", -node_size / 2, "y2", node_size / 2, "fill_color_rgba", black, NULL); } /* We check the name of the node, and update the canvas node name * if it has changed (useful for non blocking dns resolving) */ /*TODO why is it exactly that sometimes it is NULL? */ if (canvas_node->text_item) { g_object_get (G_OBJECT (canvas_node->text_item), "text", &nametmp, NULL); if (strcmp (nametmp, node->name->str)) { gnome_canvas_item_set (canvas_node->text_item, "text", node->name->str, NULL); gnome_canvas_item_request_update (canvas_node->text_item); } g_free (nametmp); } /* Processor time check. If too much time has passed, update the GUI */ end = clock (); cpu_time_used = ((gdouble) (end - start)) / CLOCKS_PER_SEC; if (cpu_time_used > 0.05) { /* Force redraw */ while (gtk_events_pending ()) gtk_main_iteration (); start = end; } return FALSE; /* False means keep on calling the function */ } /* update_canvas_nodes */
/* Checks whether there is already a legend entry for each known * protocol. If not, create it */ static void check_new_protocol (GtkWidget *prot_table, const protostack_t *pstk) { const GList *protocol_item; const protocol_t *protocol; GdkColor color; GtkStyle *style; GtkLabel *lab; GtkWidget *newlab; GList *childlist; if (!pstk) return; /* nothing to do */ childlist = gtk_container_get_children(GTK_CONTAINER(prot_table)); protocol_item = pstk->protostack[pref.stack_level]; while (protocol_item) { const GList *cur; protocol = protocol_item->data; /* prepare next */ protocol_item = protocol_item->next; /* First, we check whether the diagram already knows about this protocol, * checking whether it is shown on the legend. */ cur = childlist; while (cur) { lab = GTK_LABEL(cur->data); if (lab && !strcmp(protocol->name, gtk_label_get_label(lab))) break; /* found */ cur = cur->next; } if (cur) continue; /* found, skip to next */ g_my_debug ("Protocol '%s' not found. Creating legend item", protocol->name); /* It's not, so we build a new entry on the legend */ /* we add the new label widgets */ newlab = gtk_label_new (protocol->name); gtk_widget_show (newlab); gtk_misc_set_alignment(GTK_MISC(newlab), 0, 0); color = protohash_color(protocol->name); if (!gdk_colormap_alloc_color (gdk_colormap_get_system(), &color, FALSE, TRUE)) g_warning (_("Unable to allocate color for new protocol %s"), protocol->name); style = gtk_style_new (); style->fg[GTK_STATE_NORMAL] = color; gtk_widget_set_style (newlab, style); g_object_unref (style); gtk_container_add(GTK_CONTAINER(prot_table), newlab); known_protocols++; } g_list_free(childlist); } /* check_new_protocol */
/* Refreshes the diagram. Called each refresh_period ms * 1. Checks for new protocols and displays them * 2. Updates nodes looks * 3. Updates links looks */ guint update_diagram(GtkWidget * canvas) { static struct timeval last_refresh_time = { 0, 0 }; double diffms; enum status_t status; /* if requested and enabled, dump to xml */ if (appdata.request_dump && appdata.export_file_signal) { g_warning (_("SIGUSR1 received: exporting to %s"), appdata.export_file_signal); dump_xml(appdata.export_file_signal); appdata.request_dump = FALSE; } status = get_capture_status(); if (status == PAUSE) return FALSE; if (status == CAP_EOF) { gui_eof_capture (); return FALSE; } /* * It could happen that during an intensive calculation, in order * to update the GUI and make the application responsive gtk_main_iteration * is called. But that could also trigger this very function's timeout. * If we let it run twice many problems could come up. Thus, * we are preventing it with the already_updating variable */ if (already_updating) { g_my_debug ("update_diagram called while already updating"); return FALSE; } already_updating = TRUE; gettimeofday (&appdata.now, NULL); /* update nodes */ diagram_update_nodes(canvas); /* update links */ diagram_update_links(canvas); /* Update protocol information */ protocol_summary_update_all(); /* update proto legend */ update_legend(); /* Now update info windows */ update_info_windows (); /* With this we make sure that we don't overload the * CPU with redraws */ if ((last_refresh_time.tv_sec == 0) && (last_refresh_time.tv_usec == 0)) last_refresh_time = appdata.now; /* Force redraw */ while (gtk_events_pending ()) gtk_main_iteration (); gettimeofday (&appdata.now, NULL); diffms = substract_times_ms(&appdata.now, &last_refresh_time); last_refresh_time = appdata.now; already_updating = FALSE; if (!is_idle) { if (diffms > pref.refresh_period * 1.2) return FALSE; /* Removes the timeout */ } else { if (diffms < pref.refresh_period) return FALSE; /* removes the idle */ } if (stop_requested) gui_stop_capture(); return TRUE; /* Keep on calling this function */ } /* update_diagram */
/* - calls update_links, so that the related link updates its average * traffic and main protocol, and old links are deleted * - caculates link size and color fading */ static gint canvas_link_update(link_id_t * link_id, canvas_link_t * canvas_link, GList **delete_list) { const link_t *link; const canvas_node_t *canvas_dst; const canvas_node_t *canvas_src; guint32 scaledColor; double xs, ys, xd, yd, scale; /* We used to run update_link here, but that was a major performance penalty, * and now it is done in update_diagram */ link = links_catalog_find(link_id); if (!link) { *delete_list = g_list_prepend( *delete_list, link_id); g_my_debug ("Queing canvas link to remove."); return FALSE; } /* If either source or destination has disappeared, we hide the link * until it can be show again */ /* We get coords for the destination node */ canvas_dst = g_tree_lookup (canvas_nodes, &link_id->dst); if (!canvas_dst || !canvas_dst->shown) { gnome_canvas_item_hide (canvas_link->src_item); gnome_canvas_item_hide (canvas_link->dst_item); return FALSE; } /* We get coords from source node */ canvas_src = g_tree_lookup (canvas_nodes, &link_id->src); if (!canvas_src || !canvas_src->shown) { gnome_canvas_item_hide (canvas_link->src_item); gnome_canvas_item_hide (canvas_link->dst_item); return FALSE; } /* What if there never is a protocol? * I have to initialize canvas_link->color to a known value */ if (link->main_prot[pref.stack_level]) { double diffms; canvas_link->color = protohash_color(link->main_prot[pref.stack_level]); /* scale color down to 10% at link timeout */ diffms = substract_times_ms(&appdata.now, &link->link_stats.stats.last_time); scale = pow(0.10, diffms / pref.gui_link_timeout_time); scaledColor = (((int) (scale * canvas_link->color.red) & 0xFF00) << 16) | (((int) (scale * canvas_link->color.green) & 0xFF00) << 8) | ((int) (scale * canvas_link->color.blue) & 0xFF00) | 0xFF; } else { guint32 black = 0x000000ff; scaledColor = black; } /* retrieve coordinates of node centers */ g_object_get (G_OBJECT (canvas_src->group_item), "x", &xs, "y", &ys, NULL); g_object_get (G_OBJECT (canvas_dst->group_item), "x", &xd, "y", &yd, NULL); /* first draw triangle for src->dst */ draw_oneside_link(xs, ys, xd, yd, &(link->link_stats.stats_out), scaledColor, canvas_link->src_item); /* then draw triangle for dst->src */ draw_oneside_link(xd, yd, xs, ys, &(link->link_stats.stats_in), scaledColor, canvas_link->dst_item); return FALSE; } /* update_canvas_links */
static void set_node_name (node_t * node, const name_decode_t *sequence) { const name_decode_t *iter; gboolean cont; if (DEBUG_ENABLED) { gchar *msgid = node_id_dump(&node->node_id); g_my_debug("set_node_name: node id [%s]", msgid); g_free(msgid); } cont = TRUE; for (iter = sequence; iter->protocol && cont; ++iter) { const GList *name_item; const name_t *name; const protocol_t *protocol; guint j; /* We don't do level 0, which has the topmost prot */ for (j = STACK_SIZE; j && cont; j--) { g_my_debug(" Searching %s at stack level %d", iter->protocol, j); protocol = protocol_stack_find(&node->node_stats.stats_protos, j, iter->protocol); if (!protocol || strcmp (protocol->name, iter->protocol)) continue; /* protocol found, we take the first name (i.e. the most used one) */ name_item = protocol->node_names; if (!name_item) { g_my_debug(" found protocol without names, ignore"); continue; } name = (const name_t *) (name_item->data); if (DEBUG_ENABLED) { gchar *msgname = node_name_dump(name); if (name->res_name || !iter->must_resolve || !pref.name_res) g_my_debug(" found protocol with name [%s]", msgname); else g_my_debug(" found protocol with UNRESOLVED name [%s], ignored", msgname); g_free(msgname); } /* If we require this protocol to be solved and it's not, * the we have to go on */ if (name->res_name || !iter->must_resolve || !pref.name_res) { if (name->res_name) { if (!node->name || strcmp (node->name->str, name->res_name->str)) { g_my_debug (" set node name from %s to %s", (node->name) ? node->name->str : "<none>", name->res_name->str); g_string_assign (node->name, name->res_name->str); } } if (!node->numeric_name || strcmp(node->numeric_name->str, name->numeric_name->str)) { g_my_debug (" set node numeric_name from %s to %s", (node->numeric_name) ? node->numeric_name->str : "none", name->numeric_name->str); g_string_assign (node->numeric_name,name->numeric_name->str); } cont = FALSE; } } } g_my_debug("set_node_name END --"); } /* set_node_name */