ccnd_stats.c

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