1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
#include "ip_tree.h"
#include "../../rpc_lookup.h"
/*??? #include "rpc.h" */
/*??? #include "top.h" */
#include "../../timer.h" /* ticks_t */
#include "../../dprint.h"
#include "pike_top.h"
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
// TODO FIXME LCH remove arpa/inet.h after testing
#include <arpa/inet.h>
// IPv6 address is a 16 bytes long
#define MAX_DEPTH 16
static unsigned int g_max_hits = 0;
static void traverse_subtree( struct ip_node *node, int depth, int options )
{
static unsigned char ip_addr[MAX_DEPTH];
struct ip_node *foo;
DBG("pike:rpc traverse_subtree, depth: %d, byte: %d", depth, node->byte);
assert( depth < MAX_DEPTH );
ip_addr[depth] = node->byte;
if ( node->flags & NODE_IPLEAF_FLAG ) {
int ns = node_status(node);
DBG("pike:traverse_subtree: options: 0x%02x, node status: 0x%02x", options, ns);
/* add to the result list if it has requested status */
switch (options) {
case NODE_STATUS_HOT:
if ( ns & NODE_STATUS_HOT )
pike_top_add_entry(ip_addr, depth+1, node->leaf_hits, node->hits, node->expires - get_ticks(), ns);
break;
case NODE_STATUS_ALL:
pike_top_add_entry(ip_addr, depth+1, node->leaf_hits, node->hits, node->expires - get_ticks(), ns);
break;
}
}
else if (! node->kids) { /* TODO non IP leaf of ip_tree - it is possible to report WARM nodes here */
/* if ( options == ns )
pike_top_add_entry(ip_addr, depth+1, node->leaf_hits, node->hits, node->expires - get_ticks(), ns);
*/ }
else { /* not a any kind of leaf - inner node */
DBG("pike:rpc traverse_subtree, not IP leaf, depth: %d, ip: %d.%d.%d.%d hits[%d,%d], expires: %d",
depth, ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3], node->hits[0], node->hits[1], node->expires - get_ticks());
}
foo = node->kids;
while (foo) {
traverse_subtree( foo, depth + 1, options );
foo = foo->next;
}
}
static void collect_data(int options)
{
int i;
g_max_hits = get_max_hits();
DBG("pike: collect_data");
// maybe try_lock first and than do the rest?
for(i=0;i<MAX_IP_BRANCHES;i++) {
if (get_tree_branch(i)==0)
continue;
DBG("pike: collect_data: branch %d", i);
lock_tree_branch(i);
if (get_tree_branch(i))
traverse_subtree( get_tree_branch(i), 0, options );
unlock_tree_branch(i);
}
}
/* do not use static buffer with this function */
static const char *concat_err = "ERROR while concatenating string";
static char *concat(char *buff, size_t buffsize, const char *first, int second)
{
int rv;
size_t size;
while ( (rv = snprintf(buff, buffsize, "%s%d", first, second)) >= buffsize ) {
size = rv > 128 ? rv : 128;
buff = (char *)realloc(buff, size);
if ( buff == 0 )
return (char*)concat_err;
buffsize = size;
DBG("pike:rpc:concat: new buffer size for %s: %d", first,
(int)buffsize);
}
return buff;
}
static void pike_top(rpc_t *rpc, void *c)
{
int i;
void *handle;
struct TopListItem_t *top_list_root;
struct TopListItem_t *ti = 0;
char addr_buff[40];
char *ip_addr = 0;
char *leaf_hits_prev = 0;
char *leaf_hits_curr = 0;
char *expires = 0;
char *status = 0;
size_t ip_addr_size = 0;
size_t leaf_hits_prev_size = 0;
size_t leaf_hits_curr_size = 0;
size_t expires_size = 0;
size_t status_size = 0;
char *stropts;
int options = 0;
DBG("pike: top");
/* obtain params */
if (rpc->scan(c, "s", &stropts) <= 0)
stropts = "HOT";
DBG("pike:top: string options: '%s'", stropts);
if ( strstr(stropts, "ALL") ) {
options = NODE_STATUS_ALL;
} else if ( strstr(stropts, "HOT") ) {
options |= NODE_STATUS_HOT;
} else if ( strstr(stropts, "WARM") ) {
options |= NODE_STATUS_WARM;
}
DBG("pike:top: options: 0x%02x\n", options);
if (options == 0) {
rpc->fault(c, 500, "Bad argument. Select: ALL, HOT or WARM");
return;
}
print_tree( 0 );
collect_data(options);
top_list_root = pike_top_get_root();
DBG("pike_top: top_list_root = %p", top_list_root);
rpc->add(c, "{", &handle);
rpc->struct_add(handle, "d", "max_hits", get_max_hits());
i = 0; // it is passed as number of rows
if ( top_list_root == 0 ) {
DBG("pike_top: no data");
}
else {
for( ti = top_list_root, i = 0; ti != 0; ti = ti->next, ++i ) {
pike_top_print_addr(ti->ip_addr, ti->addr_len, addr_buff, sizeof(addr_buff));
DBG("pike:top: result[%d]: %s leaf_hits[%d,%d] hits[%d,%d] expires: %d status: 0x%02x",
i, addr_buff, ti->leaf_hits[0], ti->leaf_hits[1],
ti->hits[0], ti->hits[1], ti->expires, ti->status);
rpc->struct_add(handle, "sddds",
concat(ip_addr, ip_addr_size, "ip_addr", i), addr_buff,
concat(leaf_hits_prev, leaf_hits_prev_size, "leaf_hits_prev", i), ti->leaf_hits[0],
concat(leaf_hits_curr, leaf_hits_curr_size, "leaf_hits_curr", i), ti->leaf_hits[1],
concat(expires, expires_size, "expires", i), ti->expires,
concat(status, status_size, "status", i), node_status_array[ti->status]);
}
}
rpc->struct_add(handle, "d", "number_of_rows", i);
/* free buffers */
free(ip_addr);
free(leaf_hits_prev);
free(leaf_hits_curr);
free(expires);
free(status);
pike_top_list_clear();
rpc->send(c);
}
/* ----- exported data structure with methods ----- */
// TODO check documentation
static const char* pike_top_doc[] = {
"pike.top Dump parts of the pike table", /* Documentation string */
0 /* Method signature(s) */
};
/*
* RPC Methods exported by this module
*/
rpc_export_t pike_rpc_methods[] = {
{"pike.top", pike_top, pike_top_doc, 0},
{0, 0, 0, 0}
};
|