ccnr_stats.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnr_stats.c
00003  * 
00004  * Statistics presentation for ccnr.
00005  *
00006  * Part of ccnr -  CCNx Repository Daemon.
00007  *
00008  */
00009 
00010 /*
00011  * Copyright (C) 2011 Palo Alto Research Center, Inc.
00012  *
00013  * This work is free software; you can redistribute it and/or modify it under
00014  * the terms of the GNU General Public License version 2 as published by the
00015  * Free Software Foundation.
00016  * This work is distributed in the hope that it will be useful, but WITHOUT ANY
00017  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00019  * for more details. You should have received a copy of the GNU General Public
00020  * License along with this program; if not, write to the
00021  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00022  * Boston, MA 02110-1301, USA.
00023  */
00024  
00025 #include <sys/types.h>
00026 #include <errno.h>
00027 #include <fcntl.h>
00028 #include <stdint.h>
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <sys/time.h>
00033 #include <sys/socket.h>
00034 #include <sys/utsname.h>
00035 #include <time.h>
00036 #include <unistd.h>
00037 #include <ccn/ccn.h>
00038 #include <ccn/charbuf.h>
00039 #include <ccn/coding.h>
00040 #include <ccn/indexbuf.h>
00041 #include <ccn/schedule.h>
00042 #include <ccn/sockaddrutil.h>
00043 #include <ccn/hashtb.h>
00044 #include <ccn/uri.h>
00045 
00046 #include "ccnr_private.h"
00047 
00048 #include "ccnr_stats.h"
00049 #include "ccnr_io.h"
00050 #include "ccnr_msg.h"
00051 
00052 
00053 #define CRLF "\r\n"
00054 #define NL   "\n"
00055 
00056 /**
00057  * Provide a way to monitor rates.
00058  */
00059 struct ccnr_meter {
00060     uintmax_t total;
00061     char what[8];
00062     unsigned rate; /** a scale factor applies */
00063     unsigned lastupdate;
00064 };
00065 
00066 struct ccnr_stats {
00067     long total_interest_counts;
00068     long total_flood_control;      /* done propagating, still recorded */
00069 };
00070 
00071 static int ccnr_collect_stats(struct ccnr_handle *h, struct ccnr_stats *ans);
00072 static struct ccn_charbuf *collect_stats_html(struct ccnr_handle *h);
00073 static void send_http_response(struct ccnr_handle *h, struct fdholder *fdholder,
00074                                const char *mime_type,
00075                                struct ccn_charbuf *response);
00076 static struct ccn_charbuf *collect_stats_html(struct ccnr_handle *h);
00077 static struct ccn_charbuf *collect_stats_xml(struct ccnr_handle *h);
00078 
00079 /* HTTP */
00080 
00081 static const char *resp404 =
00082     "HTTP/1.1 404 Not Found" CRLF
00083     "Connection: close" CRLF CRLF;
00084 
00085 static const char *resp405 =
00086     "HTTP/1.1 405 Method Not Allowed" CRLF
00087     "Connection: close" CRLF CRLF;
00088 
00089 static void
00090 ccnr_stats_http_set_debug(struct ccnr_handle *h, struct fdholder *fdholder, int level)
00091 {
00092     struct ccn_charbuf *response = ccn_charbuf_create();
00093     
00094     h->debug = 1;
00095     ccnr_msg(h, "CCNR_DEBUG=%d", level);
00096     h->debug = level;
00097     ccn_charbuf_putf(response, "<title>CCNR_DEBUG=%d</title><tt>CCNR_DEBUG=%d</tt>" CRLF, level, level);
00098     send_http_response(h, fdholder, "text/html", response);
00099     ccn_charbuf_destroy(&response);
00100 }
00101 
00102 int
00103 ccnr_stats_handle_http_connection(struct ccnr_handle *h, struct fdholder *fdholder)
00104 {
00105     struct ccn_charbuf *response = NULL;
00106     char rbuf[16];
00107     int i;
00108     int nspace;
00109     int n;
00110     
00111     if (fdholder->inbuf->length < 4)
00112         return(-1);
00113     if ((fdholder->flags & CCNR_FACE_NOSEND) != 0) {
00114         r_io_destroy_face(h, fdholder->filedesc);
00115         return(-1);
00116     }
00117     n = sizeof(rbuf) - 1;
00118     if (fdholder->inbuf->length < n)
00119         n = fdholder->inbuf->length;
00120     for (i = 0, nspace = 0; i < n && nspace < 2; i++) {
00121         rbuf[i] = fdholder->inbuf->buf[i];
00122         if (rbuf[i] == ' ')
00123             nspace++;
00124     }
00125     rbuf[i] = 0;
00126     if (nspace < 2 && i < sizeof(rbuf) - 1)
00127         return(-1);
00128     if (0 == strcmp(rbuf, "GET / ") ||
00129         0 == strcmp(rbuf, "GET /? ")) {
00130         response = collect_stats_html(h);
00131         send_http_response(h, fdholder, "text/html", response);
00132     }
00133     else if (0 == strcmp(rbuf, "GET /?l=none ")) {
00134         ccnr_stats_http_set_debug(h, fdholder, 0);
00135     }
00136     else if (0 == strcmp(rbuf, "GET /?l=low ")) {
00137         ccnr_stats_http_set_debug(h, fdholder, 1);
00138     }
00139     else if (0 == strcmp(rbuf, "GET /?l=co ")) {
00140         ccnr_stats_http_set_debug(h, fdholder, 4);
00141     }
00142     else if (0 == strcmp(rbuf, "GET /?l=med ")) {
00143         ccnr_stats_http_set_debug(h, fdholder, 71);
00144     }
00145     else if (0 == strcmp(rbuf, "GET /?l=high ")) {
00146         ccnr_stats_http_set_debug(h, fdholder, -1);
00147     }
00148     else if (0 == strcmp(rbuf, "GET /?f=xml ")) {
00149         response = collect_stats_xml(h);
00150         send_http_response(h, fdholder, "text/xml", response);
00151     }
00152     else if (0 == strcmp(rbuf, "GET "))
00153         r_io_send(h, fdholder, resp404, strlen(resp404), NULL);
00154     else
00155         r_io_send(h, fdholder, resp405, strlen(resp405), NULL);
00156     fdholder->flags |= (CCNR_FACE_NOSEND | CCNR_FACE_CLOSING);
00157     ccn_charbuf_destroy(&response);
00158     return(0);
00159 }
00160 
00161 static void
00162 send_http_response(struct ccnr_handle *h, struct fdholder *fdholder,
00163                    const char *mime_type, struct ccn_charbuf *response)
00164 {
00165     struct linger linger = { .l_onoff = 1, .l_linger = 1 };
00166     char buf[128];
00167     int hdrlen;
00168 
00169     /* Set linger to prevent quickly resetting the connection on close.*/
00170     setsockopt(fdholder->filedesc, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
00171     hdrlen = snprintf(buf, sizeof(buf),
00172                       "HTTP/1.1 200 OK" CRLF
00173                       "Content-Type: %s; charset=utf-8" CRLF
00174                       "Connection: close" CRLF
00175                       "Content-Length: %jd" CRLF CRLF,
00176                       mime_type,
00177                       (intmax_t)response->length);
00178     r_io_send(h, fdholder, buf, hdrlen, NULL);
00179     r_io_send(h, fdholder, response->buf, response->length, NULL);
00180 }
00181 
00182 /* Common statistics collection */
00183 
00184 static int
00185 ccnr_collect_stats(struct ccnr_handle *h, struct ccnr_stats *ans)
00186 {
00187     struct hashtb_enumerator ee;
00188     struct hashtb_enumerator *e = &ee;
00189     long sum;
00190     unsigned i;
00191     for (sum = 0, hashtb_start(h->nameprefix_tab, e);
00192          e->data != NULL; hashtb_next(e)) {
00193         struct nameprefix_entry *npe = e->data;
00194         struct propagating_entry *head = &npe->pe_head;
00195         struct propagating_entry *p;
00196         for (p = head->next; p != head; p = p->next) {
00197             if (ccnr_r_io_fdholder_from_fd(h, p->filedesc) != NULL)
00198                 sum += 1;
00199         }
00200     }
00201     ans->total_interest_counts = sum;
00202     hashtb_end(e);
00203     for (sum = 0, hashtb_start(h->propagating_tab, e);
00204          e->data != NULL; hashtb_next(e)) {
00205         struct propagating_entry *pe = e->data;
00206         if (pe->interest_msg == NULL)
00207             sum += 1;
00208     }
00209     ans->total_flood_control = sum;
00210     hashtb_end(e);
00211     /* Do a consistency check on pending interest counts */
00212     for (sum = 0, i = 0; i < h->face_limit; i++) {
00213         struct fdholder *fdholder = h->fdholder_by_fd[i];
00214         if (fdholder != NULL)
00215             sum += fdholder->pending_interests;
00216     }
00217     if (sum != ans->total_interest_counts)
00218         ccnr_msg(h, "ccnr_collect_stats found inconsistency %ld != %ld\n",
00219                  (long)sum, (long)ans->total_interest_counts);
00220     ans->total_interest_counts = sum;
00221     return(0);
00222 }
00223 
00224 /* HTML formatting */
00225 
00226 static void
00227 collect_faces_html(struct ccnr_handle *h, struct ccn_charbuf *b)
00228 {
00229     int i;
00230     struct ccn_charbuf *nodebuf;
00231     int port;
00232     
00233     nodebuf = ccn_charbuf_create();
00234     ccn_charbuf_putf(b, "<h4>Faces</h4>" NL);
00235     ccn_charbuf_putf(b, "<ul>");
00236     for (i = 0; i < h->face_limit; i++) {
00237         struct fdholder *fdholder = h->fdholder_by_fd[i];
00238         if (fdholder != NULL && (fdholder->flags & CCNR_FACE_UNDECIDED) == 0) {
00239             ccn_charbuf_putf(b, " <li>");
00240             ccn_charbuf_putf(b, "<b>fdholder:</b> %u <b>flags:</b> 0x%x",
00241                              fdholder->filedesc, fdholder->flags);
00242             ccn_charbuf_putf(b, " <b>pending:</b> %d",
00243                              fdholder->pending_interests);
00244             if (fdholder->recvcount != 0)
00245                 ccn_charbuf_putf(b, " <b>activity:</b> %d",
00246                                  fdholder->recvcount);
00247             nodebuf->length = 0;
00248             port = 0;
00249 #if 0
00250 // XXX - fix for fdholder->name
00251             port = ccn_charbuf_append_sockaddr(nodebuf, fdholder->addr);
00252             if (port > 0) {
00253                 const char *node = ccn_charbuf_as_string(nodebuf);
00254                 if ((fdholder->flags & CCNR_FACE_PASSIVE) == 0)
00255                     ccn_charbuf_putf(b, " <b>remote:</b> %s:%d",
00256                                      node, port);
00257                 else
00258                     ccn_charbuf_putf(b, " <b>local:</b> %s:%d",
00259                                      node, port);
00260                 if (fdholder->sendface != fdholder->filedesc &&
00261                     fdholder->sendface != CCN_NOFACEID)
00262                     ccn_charbuf_putf(b, " <b>via:</b> %u", fdholder->sendface);
00263             }
00264 #endif
00265             ccn_charbuf_putf(b, "</li>" NL);
00266         }
00267     }
00268     ccn_charbuf_putf(b, "</ul>");
00269     ccn_charbuf_destroy(&nodebuf);
00270 }
00271 
00272 static void
00273 collect_face_meter_html(struct ccnr_handle *h, struct ccn_charbuf *b)
00274 {
00275     int i;
00276     ccn_charbuf_putf(b, "<h4>fdholder Activity Rates</h4>");
00277     ccn_charbuf_putf(b, "<table cellspacing='0' cellpadding='0' class='tbl' summary='fdholder activity rates'>");
00278     ccn_charbuf_putf(b, "<tbody>" NL);
00279     ccn_charbuf_putf(b, " <tr><td>        </td>\t"
00280                         " <td>Bytes/sec In/Out</td>\t"
00281                         " <td>recv data/intr sent</td>\t"
00282                         " <td>sent data/intr recv</td></tr>" NL);
00283     for (i = 0; i < h->face_limit; i++) {
00284         struct fdholder *fdholder = h->fdholder_by_fd[i];
00285         if (fdholder != NULL && (fdholder->flags & (CCNR_FACE_UNDECIDED|CCNR_FACE_PASSIVE)) == 0) {
00286             ccn_charbuf_putf(b, " <tr>");
00287             ccn_charbuf_putf(b, "<td><b>fdholder:</b> %u</td>\t",
00288                              fdholder->filedesc);
00289             ccn_charbuf_putf(b, "<td>%6u / %u</td>\t\t",
00290                                  ccnr_meter_rate(h, fdholder->meter[FM_BYTI]),
00291                                  ccnr_meter_rate(h, fdholder->meter[FM_BYTO]));
00292             ccn_charbuf_putf(b, "<td>%9u / %u</td>\t\t",
00293                                  ccnr_meter_rate(h, fdholder->meter[FM_DATI]),
00294                                  ccnr_meter_rate(h, fdholder->meter[FM_INTO]));
00295             ccn_charbuf_putf(b, "<td>%9u / %u</td>",
00296                                  ccnr_meter_rate(h, fdholder->meter[FM_DATO]),
00297                                  ccnr_meter_rate(h, fdholder->meter[FM_INTI]));
00298             ccn_charbuf_putf(b, "</tr>" NL);
00299         }
00300     }
00301     ccn_charbuf_putf(b, "</tbody>");
00302     ccn_charbuf_putf(b, "</table>");
00303 }
00304 
00305 static void
00306 collect_forwarding_html(struct ccnr_handle *h, struct ccn_charbuf *b)
00307 {
00308     struct hashtb_enumerator ee;
00309     struct hashtb_enumerator *e = &ee;
00310     struct ccn_forwarding *f;
00311     int res;
00312     struct ccn_charbuf *name = ccn_charbuf_create();
00313     
00314     ccn_charbuf_putf(b, "<h4>Forwarding</h4>" NL);
00315     ccn_charbuf_putf(b, "<ul>");
00316     hashtb_start(h->nameprefix_tab, e);
00317     for (; e->data != NULL; hashtb_next(e)) {
00318         struct nameprefix_entry *ipe = e->data;
00319         ccn_name_init(name);
00320         res = ccn_name_append_components(name, e->key, 0, e->keysize);
00321         if (res < 0)
00322             abort();
00323         if (0) {
00324             ccn_charbuf_putf(b, " <li>");
00325             ccn_uri_append(b, name->buf, name->length, 1);
00326             ccn_charbuf_putf(b, "</li>" NL);
00327         }
00328         for (f = ipe->forwarding; f != NULL; f = f->next) {
00329             if ((f->flags & (CCN_FORW_ACTIVE | CCN_FORW_PFXO)) != 0) {
00330                 ccn_name_init(name);
00331                 res = ccn_name_append_components(name, e->key, 0, e->keysize);
00332                 ccn_charbuf_putf(b, " <li>");
00333                 ccn_uri_append(b, name->buf, name->length, 1);
00334                 ccn_charbuf_putf(b,
00335                                  " <b>fdholder:</b> %u"
00336                                  " <b>flags:</b> 0x%x"
00337                                  " <b>expires:</b> %d",
00338                                  f->filedesc,
00339                                  f->flags & CCN_FORW_PUBMASK,
00340                                  f->expires);
00341                 ccn_charbuf_putf(b, "</li>" NL);
00342             }
00343         }
00344     }
00345     hashtb_end(e);
00346     ccn_charbuf_destroy(&name);
00347     ccn_charbuf_putf(b, "</ul>");
00348 }
00349 
00350 static unsigned
00351 ccnr_colorhash(struct ccnr_handle *h)
00352 {
00353     unsigned const char *a = h->ccnr_id;
00354     unsigned v;
00355     
00356     v = (a[0] << 16) + (a[1] << 8) + a[2];
00357     return (v | 0xC0C0C0);
00358 }
00359 
00360 static struct ccn_charbuf *
00361 collect_stats_html(struct ccnr_handle *h)
00362 {
00363     struct ccnr_stats stats = {0};
00364     struct ccn_charbuf *b = ccn_charbuf_create();
00365     int pid;
00366     struct utsname un;
00367     
00368     uname(&un);
00369     pid = getpid();
00370     
00371     ccnr_collect_stats(h, &stats);
00372     ccn_charbuf_putf(b,
00373         "<html xmlns='http://www.w3.org/1999/xhtml'>"
00374         "<head>"
00375         "<title>%s ccnr[%d]</title>"
00376         //"<meta http-equiv='refresh' content='3'>"
00377         "<style type='text/css'>"
00378         "/*<![CDATA[*/"
00379         "p.header {color: white; background-color: blue; width: 100%%} "
00380         "table.tbl {border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: black} "
00381         "td {border-style: solid; "
00382             "border-width: 1.0px 1.0px 1.0px 1.0px; "
00383             "border-color: #808080 #808080 #808080 #808080; "
00384             "padding: 6px 6px 6px 6px; "
00385             "margin-left: auto; margin-right: auto; "
00386             "text-align: center"
00387             "} "
00388         "td.left {text-align: left} "
00389         "/*]]>*/"
00390         "</style>"
00391         "</head>" NL
00392         "<body bgcolor='#%06X'>"
00393         "<p class='header'>%s ccnr[%d] local port %s api %d start %ld.%06u now %ld.%06u</p>" NL
00394         "<div><b>Content items:</b> %llu accessioned,"
00395         " %llu cached, %lu stale, %d sparse, %lu duplicate, %lu sent</div>" NL
00396         "<div><b>Interests:</b> %d names,"
00397         " %ld pending, %ld propagating, %ld noted</div>" NL
00398         "<div><b>Interest totals:</b> %lu accepted,"
00399         " %lu dropped, %lu sent, %lu stuffed</div>" NL,
00400         un.nodename,
00401         pid,
00402         ccnr_colorhash(h),
00403         un.nodename,
00404         pid,
00405         h->portstr,
00406         (int)CCN_API_VERSION,
00407         h->starttime, h->starttime_usec,
00408         h->sec,
00409         h->usec,
00410         (unsigned long long)hashtb_n(h->content_by_accession_tab), // XXXXXX - 
00411         (unsigned long long)(h->cob_count),
00412         h->n_stale,
00413         hashtb_n(h->content_by_accession_tab),
00414         h->content_dups_recvd,
00415         h->content_items_sent,
00416         hashtb_n(h->nameprefix_tab), stats.total_interest_counts,
00417         hashtb_n(h->propagating_tab) - stats.total_flood_control,
00418         stats.total_flood_control,
00419         h->interests_accepted, h->interests_dropped,
00420         h->interests_sent, h->interests_stuffed);
00421     collect_faces_html(h, b);
00422     collect_face_meter_html(h, b);
00423     collect_forwarding_html(h, b);
00424     ccn_charbuf_putf(b,
00425         "</body>"
00426         "</html>" NL);
00427     return(b);
00428 }
00429 
00430 /* XML formatting */
00431 
00432 static void
00433 collect_meter_xml(struct ccnr_handle *h, struct ccn_charbuf *b, struct ccnr_meter *m)
00434 {
00435     uintmax_t total;
00436     unsigned rate;
00437     
00438     if (m == NULL)
00439         return;
00440     total = ccnr_meter_total(m);
00441     rate = ccnr_meter_rate(h, m);
00442     ccn_charbuf_putf(b, "<%s><total>%ju</total><persec>%u</persec></%s>",
00443         m->what, total, rate, m->what);
00444 }
00445 
00446 static void
00447 collect_faces_xml(struct ccnr_handle *h, struct ccn_charbuf *b)
00448 {
00449     int i;
00450     int m;
00451     int port;
00452     struct ccn_charbuf *nodebuf;
00453     
00454     nodebuf = ccn_charbuf_create();
00455     ccn_charbuf_putf(b, "<faces>");
00456     for (i = 0; i < h->face_limit; i++) {
00457         struct fdholder *fdholder = h->fdholder_by_fd[i];
00458         if (fdholder != NULL && (fdholder->flags & CCNR_FACE_UNDECIDED) == 0) {
00459             ccn_charbuf_putf(b, "<fdholder>");
00460             ccn_charbuf_putf(b,
00461                              "<filedesc>%u</filedesc>"
00462                              "<faceflags>%04x</faceflags>",
00463                              fdholder->filedesc, fdholder->flags);
00464             ccn_charbuf_putf(b, "<pending>%d</pending>",
00465                              fdholder->pending_interests);
00466             ccn_charbuf_putf(b, "<recvcount>%d</recvcount>",
00467                              fdholder->recvcount);
00468             nodebuf->length = 0;
00469             port = 0;
00470 #if 0
00471 // XXX - fix this to know about fdholder->name
00472             port = ccn_charbuf_append_sockaddr(nodebuf, fdholder->addr);
00473             if (port > 0) {
00474                 const char *node = ccn_charbuf_as_string(nodebuf);
00475                 ccn_charbuf_putf(b, "<ip>%s:%d</ip>", node, port);
00476             }
00477             if (fdholder->sendface != fdholder->filedesc &&
00478                 fdholder->sendface != CCN_NOFACEID)
00479                 ccn_charbuf_putf(b, "<via>%u</via>", fdholder->sendface);
00480 #endif
00481             if (fdholder != NULL && (fdholder->flags & CCNR_FACE_PASSIVE) == 0) {
00482                 ccn_charbuf_putf(b, "<meters>");
00483                 for (m = 0; m < CCNR_FACE_METER_N; m++)
00484                     collect_meter_xml(h, b, fdholder->meter[m]);
00485                 ccn_charbuf_putf(b, "</meters>");
00486             }
00487             ccn_charbuf_putf(b, "</fdholder>" NL);
00488         }
00489     }
00490     ccn_charbuf_putf(b, "</faces>");
00491     ccn_charbuf_destroy(&nodebuf);
00492 }
00493 
00494 static void
00495 collect_forwarding_xml(struct ccnr_handle *h, struct ccn_charbuf *b)
00496 {
00497     struct hashtb_enumerator ee;
00498     struct hashtb_enumerator *e = &ee;
00499     struct ccn_forwarding *f;
00500     int res;
00501     struct ccn_charbuf *name = ccn_charbuf_create();
00502     
00503     ccn_charbuf_putf(b, "<forwarding>");
00504     hashtb_start(h->nameprefix_tab, e);
00505     for (; e->data != NULL; hashtb_next(e)) {
00506         struct nameprefix_entry *ipe = e->data;
00507         for (f = ipe->forwarding, res = 0; f != NULL && !res; f = f->next) {
00508             if ((f->flags & (CCN_FORW_ACTIVE | CCN_FORW_PFXO)) != 0)
00509                 res = 1;
00510         }
00511         if (res) {
00512             ccn_name_init(name);
00513             res = ccn_name_append_components(name, e->key, 0, e->keysize);
00514             ccn_charbuf_putf(b, "<fentry>");
00515             ccn_charbuf_putf(b, "<prefix>");
00516             ccn_uri_append(b, name->buf, name->length, 1);
00517             ccn_charbuf_putf(b, "</prefix>");
00518             for (f = ipe->forwarding; f != NULL; f = f->next) {
00519                 if ((f->flags & (CCN_FORW_ACTIVE | CCN_FORW_PFXO)) != 0) {
00520                     ccn_charbuf_putf(b,
00521                                      "<dest>"
00522                                      "<filedesc>%u</filedesc>"
00523                                      "<flags>%x</flags>"
00524                                      "<expires>%d</expires>"
00525                                      "</dest>",
00526                                      f->filedesc,
00527                                      f->flags & CCN_FORW_PUBMASK,
00528                                      f->expires);
00529                 }
00530             }
00531             ccn_charbuf_putf(b, "</fentry>");
00532         }
00533     }
00534     hashtb_end(e);
00535     ccn_charbuf_destroy(&name);
00536     ccn_charbuf_putf(b, "</forwarding>");
00537 }
00538 
00539 static struct ccn_charbuf *
00540 collect_stats_xml(struct ccnr_handle *h)
00541 {
00542     struct ccnr_stats stats = {0};
00543     struct ccn_charbuf *b = ccn_charbuf_create();
00544     int i;
00545         
00546     ccnr_collect_stats(h, &stats);
00547     ccn_charbuf_putf(b,
00548         "<ccnr>"
00549         "<identity>"
00550         "<ccnrid>");
00551     for (i = 0; i < sizeof(h->ccnr_id); i++)
00552         ccn_charbuf_putf(b, "%02X", h->ccnr_id[i]);
00553     ccn_charbuf_putf(b, "</ccnrid>"
00554         "<apiversion>%d</apiversion>"
00555         "<starttime>%ld.%06u</starttime>"
00556         "<now>%ld.%06u</now>"
00557         "</identity>",
00558         (int)CCN_API_VERSION,
00559         h->starttime, h->starttime_usec,
00560         h->sec,
00561         h->usec);
00562     ccn_charbuf_putf(b,
00563         "<cobs>"
00564         "<accessioned>%llu</accessioned>"
00565         "<cached>%llu</cached>"
00566         "<stale>%lu</stale>"
00567         "<sparse>%d</sparse>"
00568         "<duplicate>%lu</duplicate>"
00569         "<sent>%lu</sent>"
00570         "</cobs>"
00571         "<interests>"
00572         "<names>%d</names>"
00573         "<pending>%ld</pending>"
00574         "<propagating>%ld</propagating>"
00575         "<noted>%ld</noted>"
00576         "<accepted>%lu</accepted>"
00577         "<dropped>%lu</dropped>"
00578         "<sent>%lu</sent>"
00579         "<stuffed>%lu</stuffed>"
00580         "</interests>",
00581         (unsigned long long)hashtb_n(h->content_by_accession_tab), // XXXXXX -
00582         (unsigned long long)(h->cob_count),
00583         h->n_stale,
00584         hashtb_n(h->content_by_accession_tab),
00585         h->content_dups_recvd,
00586         h->content_items_sent,
00587         hashtb_n(h->nameprefix_tab), stats.total_interest_counts,
00588         hashtb_n(h->propagating_tab) - stats.total_flood_control,
00589         stats.total_flood_control,
00590         h->interests_accepted, h->interests_dropped,
00591         h->interests_sent, h->interests_stuffed);
00592     collect_faces_xml(h, b);
00593     collect_forwarding_xml(h, b);
00594     ccn_charbuf_putf(b, "</ccnr>" NL);
00595     return(b);
00596 }
00597 
00598 /**
00599  * create and initialize separately allocated meter.
00600  */
00601 struct ccnr_meter *
00602 ccnr_meter_create(struct ccnr_handle *h, const char *what)
00603 {
00604     struct ccnr_meter *m;
00605     m = calloc(1, sizeof(*m));
00606     if (m == NULL)
00607         return(NULL);
00608     ccnr_meter_init(h, m, what);
00609     return(m);
00610 }
00611 
00612 /**
00613  * Destroy a separately allocated meter.
00614  */
00615 void
00616 ccnr_meter_destroy(struct ccnr_meter **pm)
00617 {
00618     if (*pm != NULL) {
00619         free(*pm);
00620         *pm = NULL;
00621     }
00622 }
00623 
00624 /**
00625  * Initialize a meter.
00626  */
00627 void
00628 ccnr_meter_init(struct ccnr_handle *h, struct ccnr_meter *m, const char *what)
00629 {
00630     if (m == NULL)
00631         return;
00632     memset(m, 0, sizeof(m));
00633     if (what != NULL)
00634         strncpy(m->what, what, sizeof(m->what)-1);
00635     ccnr_meter_bump(h, m, 0);
00636 }
00637 
00638 static const unsigned meterHz = 7; /* 1/ln(8/7) would give RC const of 1 sec */
00639 
00640 /**
00641  * Count something (messages, packets, bytes), and roll up some kind of
00642  * statistics on it.
00643  */
00644 void
00645 ccnr_meter_bump(struct ccnr_handle *h, struct ccnr_meter *m, unsigned amt)
00646 {
00647     unsigned now; /* my ticks, wrap OK */
00648     unsigned t;
00649     unsigned r;
00650     if (m == NULL)
00651         return;
00652     now = (((unsigned)(h->sec)) * meterHz) + (h->usec * meterHz / 1000000U);
00653     t = m->lastupdate;
00654     m->total += amt;
00655     if (now - t > 166U)
00656         m->rate = amt; /* history has decayed away */
00657     else {
00658         /* Decay the old rate exponentially based on time since last sample. */
00659         for (r = m->rate; t != now && r != 0; t++)
00660             r = r - ((r + 7U) / 8U); /* multiply by 7/8, truncating */
00661         m->rate = r + amt;
00662     }
00663     m->lastupdate = now;
00664 }
00665 
00666 /**
00667  * Return the average rate (units per second) of a metered quantity.
00668  *
00669  * m may be NULL.
00670  */
00671 unsigned
00672 ccnr_meter_rate(struct ccnr_handle *h, struct ccnr_meter *m)
00673 {
00674     unsigned denom = 8;
00675     if (m == NULL)
00676         return(0);
00677     ccnr_meter_bump(h, m, 0);
00678     if (m->rate > 0x0FFFFFFF)
00679         return(m->rate / denom * meterHz);
00680     return ((m->rate * meterHz + (denom - 1)) / denom);
00681 }
00682 
00683 /**
00684  * Return the grand total for a metered quantity.
00685  *
00686  * m may be NULL.
00687  */
00688 uintmax_t
00689 ccnr_meter_total(struct ccnr_meter *m)
00690 {
00691     if (m == NULL)
00692         return(0);
00693     return (m->total);
00694 }

Generated on Thu Feb 16 00:43:58 2012 for Content-Centric Networking in C by  doxygen 1.5.6