00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00051
00052 struct ccnd_meter {
00053 uintmax_t total;
00054 char what[8];
00055 unsigned rate;
00056 unsigned lastupdate;
00057 };
00058
00059 struct ccnd_stats {
00060 long total_interest_counts;
00061 long total_flood_control;
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
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
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
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 = ⅇ
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
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
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 = ⅇ
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 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
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
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 = ⅇ
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 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
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
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
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;
00641
00642
00643
00644
00645
00646 void
00647 ccnd_meter_bump(struct ccnd_handle *h, struct ccnd_meter *m, unsigned amt)
00648 {
00649 unsigned now;
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;
00659 else {
00660
00661 for (r = m->rate; t != now && r != 0; t++)
00662 r = r - ((r + 7U) / 8U);
00663 m->rate = r + amt;
00664 }
00665 m->lastupdate = now;
00666 }
00667
00668
00669
00670
00671
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
00687
00688
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 }