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 ielinks *head = &npe->ie_head;
00188 struct ielinks *ll;
00189 for (ll = head->next; ll != head; ll = ll->next) {
00190 struct interest_entry *ie = (struct interest_entry *)ll;
00191 struct pit_face_item *p;
00192 for (p = ie->pfl; p != NULL; p = p->next)
00193 if ((p->pfi_flags & CCND_PFI_PENDING) != 0)
00194 if (ccnd_face_from_faceid(h, p->faceid) != NULL)
00195 sum += 1;
00196 }
00197 }
00198 ans->total_interest_counts = sum;
00199 hashtb_end(e);
00200 ans->total_flood_control = 0;
00201
00202 for (sum = 0, i = 0; i < h->face_limit; i++) {
00203 struct face *face = h->faces_by_faceid[i];
00204 if (face != NULL)
00205 sum += face->pending_interests;
00206 }
00207 if (sum != ans->total_interest_counts)
00208 ccnd_msg(h, "ccnd_collect_stats found inconsistency %ld != %ld\n",
00209 (long)sum, (long)ans->total_interest_counts);
00210 ans->total_interest_counts = sum;
00211 return(0);
00212 }
00213
00214
00215
00216 static void
00217 collect_faces_html(struct ccnd_handle *h, struct ccn_charbuf *b)
00218 {
00219 int i;
00220 struct ccn_charbuf *nodebuf;
00221 int port;
00222
00223 nodebuf = ccn_charbuf_create();
00224 ccn_charbuf_putf(b, "<h4>Faces</h4>" NL);
00225 ccn_charbuf_putf(b, "<ul>");
00226 for (i = 0; i < h->face_limit; i++) {
00227 struct face *face = h->faces_by_faceid[i];
00228 if (face != NULL && (face->flags & CCN_FACE_UNDECIDED) == 0) {
00229 ccn_charbuf_putf(b, " <li>");
00230 ccn_charbuf_putf(b, "<b>face:</b> %u <b>flags:</b> 0x%x",
00231 face->faceid, face->flags);
00232 ccn_charbuf_putf(b, " <b>pending:</b> %d",
00233 face->pending_interests);
00234 if (face->recvcount != 0)
00235 ccn_charbuf_putf(b, " <b>activity:</b> %d",
00236 face->recvcount);
00237 nodebuf->length = 0;
00238 port = ccn_charbuf_append_sockaddr(nodebuf, face->addr);
00239 if (port > 0) {
00240 const char *node = ccn_charbuf_as_string(nodebuf);
00241 int chk = CCN_FACE_MCAST | CCN_FACE_UNDECIDED |
00242 CCN_FACE_NOSEND | CCN_FACE_GG | CCN_FACE_PASSIVE;
00243 if ((face->flags & chk) == 0)
00244 ccn_charbuf_putf(b,
00245 " <b>remote:</b> "
00246 "<a href='http://%s:%s/'>"
00247 "%s:%d</a>",
00248 node, CCN_DEFAULT_UNICAST_PORT,
00249 node, port);
00250 else if ((face->flags & CCN_FACE_PASSIVE) == 0)
00251 ccn_charbuf_putf(b, " <b>remote:</b> %s:%d",
00252 node, port);
00253 else
00254 ccn_charbuf_putf(b, " <b>local:</b> %s:%d",
00255 node, port);
00256 if (face->sendface != face->faceid &&
00257 face->sendface != CCN_NOFACEID)
00258 ccn_charbuf_putf(b, " <b>via:</b> %u", face->sendface);
00259 }
00260 ccn_charbuf_putf(b, "</li>" NL);
00261 }
00262 }
00263 ccn_charbuf_putf(b, "</ul>");
00264 ccn_charbuf_destroy(&nodebuf);
00265 }
00266
00267 static void
00268 collect_face_meter_html(struct ccnd_handle *h, struct ccn_charbuf *b)
00269 {
00270 int i;
00271 ccn_charbuf_putf(b, "<h4>Face Activity Rates</h4>");
00272 ccn_charbuf_putf(b, "<table cellspacing='0' cellpadding='0' class='tbl' summary='face activity rates'>");
00273 ccn_charbuf_putf(b, "<tbody>" NL);
00274 ccn_charbuf_putf(b, " <tr><td> </td>\t"
00275 " <td>Bytes/sec In/Out</td>\t"
00276 " <td>recv data/intr sent</td>\t"
00277 " <td>sent data/intr recv</td></tr>" NL);
00278 for (i = 0; i < h->face_limit; i++) {
00279 struct face *face = h->faces_by_faceid[i];
00280 if (face != NULL && (face->flags & (CCN_FACE_UNDECIDED|CCN_FACE_PASSIVE)) == 0) {
00281 ccn_charbuf_putf(b, " <tr>");
00282 ccn_charbuf_putf(b, "<td><b>face:</b> %u</td>\t",
00283 face->faceid);
00284 ccn_charbuf_putf(b, "<td>%6u / %u</td>\t\t",
00285 ccnd_meter_rate(h, face->meter[FM_BYTI]),
00286 ccnd_meter_rate(h, face->meter[FM_BYTO]));
00287 ccn_charbuf_putf(b, "<td>%9u / %u</td>\t\t",
00288 ccnd_meter_rate(h, face->meter[FM_DATI]),
00289 ccnd_meter_rate(h, face->meter[FM_INTO]));
00290 ccn_charbuf_putf(b, "<td>%9u / %u</td>",
00291 ccnd_meter_rate(h, face->meter[FM_DATO]),
00292 ccnd_meter_rate(h, face->meter[FM_INTI]));
00293 ccn_charbuf_putf(b, "</tr>" NL);
00294 }
00295 }
00296 ccn_charbuf_putf(b, "</tbody>");
00297 ccn_charbuf_putf(b, "</table>");
00298 }
00299
00300 static void
00301 collect_forwarding_html(struct ccnd_handle *h, struct ccn_charbuf *b)
00302 {
00303 struct hashtb_enumerator ee;
00304 struct hashtb_enumerator *e = ⅇ
00305 struct ccn_forwarding *f;
00306 int res;
00307 struct ccn_charbuf *name = ccn_charbuf_create();
00308
00309 ccn_charbuf_putf(b, "<h4>Forwarding</h4>" NL);
00310 ccn_charbuf_putf(b, "<ul>");
00311 hashtb_start(h->nameprefix_tab, e);
00312 for (; e->data != NULL; hashtb_next(e)) {
00313 struct nameprefix_entry *ipe = e->data;
00314 ccn_name_init(name);
00315 res = ccn_name_append_components(name, e->key, 0, e->keysize);
00316 if (res < 0)
00317 abort();
00318 if (0) {
00319 ccn_charbuf_putf(b, " <li>");
00320 ccn_uri_append(b, name->buf, name->length, 1);
00321 ccn_charbuf_putf(b, "</li>" NL);
00322 }
00323 for (f = ipe->forwarding; f != NULL; f = f->next) {
00324 if ((f->flags & (CCN_FORW_ACTIVE | CCN_FORW_PFXO)) != 0) {
00325 ccn_name_init(name);
00326 ccn_name_append_components(name, e->key, 0, e->keysize);
00327 ccn_charbuf_putf(b, " <li>");
00328 ccn_uri_append(b, name->buf, name->length, 1);
00329 ccn_charbuf_putf(b,
00330 " <b>face:</b> %u"
00331 " <b>flags:</b> 0x%x"
00332 " <b>expires:</b> %d",
00333 f->faceid,
00334 f->flags & CCN_FORW_PUBMASK,
00335 f->expires);
00336 ccn_charbuf_putf(b, "</li>" NL);
00337 }
00338 }
00339 }
00340 hashtb_end(e);
00341 ccn_charbuf_destroy(&name);
00342 ccn_charbuf_putf(b, "</ul>");
00343 }
00344
00345 static unsigned
00346 ccnd_colorhash(struct ccnd_handle *h)
00347 {
00348 unsigned const char *a = h->ccnd_id;
00349 unsigned v;
00350
00351 v = (a[0] << 16) + (a[1] << 8) + a[2];
00352 return (v | 0xC0C0C0);
00353 }
00354
00355 static struct ccn_charbuf *
00356 collect_stats_html(struct ccnd_handle *h)
00357 {
00358 struct ccnd_stats stats = {0};
00359 struct ccn_charbuf *b = ccn_charbuf_create();
00360 int pid;
00361 struct utsname un;
00362 const char *portstr;
00363
00364 portstr = getenv(CCN_LOCAL_PORT_ENVNAME);
00365 if (portstr == NULL || portstr[0] == 0 || strlen(portstr) > 10)
00366 portstr = CCN_DEFAULT_UNICAST_PORT;
00367 uname(&un);
00368 pid = getpid();
00369
00370 ccnd_collect_stats(h, &stats);
00371 ccn_charbuf_putf(b,
00372 "<html xmlns='http://www.w3.org/1999/xhtml'>"
00373 "<head>"
00374 "<title>%s ccnd[%d]</title>"
00375
00376 "<style type='text/css'>"
00377 "/*<![CDATA[*/"
00378 "p.header {color: white; background-color: blue; width: 100%%} "
00379 "table.tbl {border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: black} "
00380 "td {border-style: solid; "
00381 "border-width: 1.0px 1.0px 1.0px 1.0px; "
00382 "border-color: #808080 #808080 #808080 #808080; "
00383 "padding: 6px 6px 6px 6px; "
00384 "margin-left: auto; margin-right: auto; "
00385 "text-align: center"
00386 "} "
00387 "td.left {text-align: left} "
00388 "/*]]>*/"
00389 "</style>"
00390 "</head>" NL
00391 "<body bgcolor='#%06X'>"
00392 "<p class='header'>%s ccnd[%d] local port %s api %d start %ld.%06u now %ld.%06u</p>" NL
00393 "<div><b>Content items:</b> %llu accessioned,"
00394 " %d stored, %lu stale, %d sparse, %lu duplicate, %lu sent</div>" NL
00395 "<div><b>Interests:</b> %d names,"
00396 " %ld pending, %ld propagating, %ld noted</div>" NL
00397 "<div><b>Interest totals:</b> %lu accepted,"
00398 " %lu dropped, %lu sent, %lu stuffed</div>" NL,
00399 un.nodename,
00400 pid,
00401 ccnd_colorhash(h),
00402 un.nodename,
00403 pid,
00404 portstr,
00405 (int)CCN_API_VERSION,
00406 h->starttime, h->starttime_usec,
00407 h->sec,
00408 h->usec,
00409 (unsigned long long)h->accession,
00410 hashtb_n(h->content_tab),
00411 h->n_stale,
00412 hashtb_n(h->sparse_straggler_tab),
00413 h->content_dups_recvd,
00414 h->content_items_sent,
00415 hashtb_n(h->nameprefix_tab), stats.total_interest_counts,
00416 hashtb_n(h->interest_tab) - stats.total_flood_control,
00417 stats.total_flood_control,
00418 h->interests_accepted, h->interests_dropped,
00419 h->interests_sent, h->interests_stuffed);
00420 if (0)
00421 ccn_charbuf_putf(b,
00422 "<div><b>Active faces and listeners:</b> %d</div>" NL,
00423 hashtb_n(h->faces_by_fd) + hashtb_n(h->dgram_faces));
00424 collect_faces_html(h, b);
00425 collect_face_meter_html(h, b);
00426 collect_forwarding_html(h, b);
00427 ccn_charbuf_putf(b,
00428 "</body>"
00429 "</html>" NL);
00430 return(b);
00431 }
00432
00433
00434
00435 static void
00436 collect_meter_xml(struct ccnd_handle *h, struct ccn_charbuf *b, struct ccnd_meter *m)
00437 {
00438 uintmax_t total;
00439 unsigned rate;
00440
00441 if (m == NULL)
00442 return;
00443 total = ccnd_meter_total(m);
00444 rate = ccnd_meter_rate(h, m);
00445 ccn_charbuf_putf(b, "<%s><total>%ju</total><persec>%u</persec></%s>",
00446 m->what, total, rate, m->what);
00447 }
00448
00449 static void
00450 collect_faces_xml(struct ccnd_handle *h, struct ccn_charbuf *b)
00451 {
00452 int i;
00453 int m;
00454 int port;
00455 struct ccn_charbuf *nodebuf;
00456
00457 nodebuf = ccn_charbuf_create();
00458 ccn_charbuf_putf(b, "<faces>");
00459 for (i = 0; i < h->face_limit; i++) {
00460 struct face *face = h->faces_by_faceid[i];
00461 if (face != NULL && (face->flags & CCN_FACE_UNDECIDED) == 0) {
00462 ccn_charbuf_putf(b, "<face>");
00463 ccn_charbuf_putf(b,
00464 "<faceid>%u</faceid>"
00465 "<faceflags>%04x</faceflags>",
00466 face->faceid, face->flags);
00467 ccn_charbuf_putf(b, "<pending>%d</pending>",
00468 face->pending_interests);
00469 ccn_charbuf_putf(b, "<recvcount>%d</recvcount>",
00470 face->recvcount);
00471 nodebuf->length = 0;
00472 port = ccn_charbuf_append_sockaddr(nodebuf, face->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 (face->sendface != face->faceid &&
00478 face->sendface != CCN_NOFACEID)
00479 ccn_charbuf_putf(b, "<via>%u</via>", face->sendface);
00480 if (face != NULL && (face->flags & CCN_FACE_PASSIVE) == 0) {
00481 ccn_charbuf_putf(b, "<meters>");
00482 for (m = 0; m < CCND_FACE_METER_N; m++)
00483 collect_meter_xml(h, b, face->meter[m]);
00484 ccn_charbuf_putf(b, "</meters>");
00485 }
00486 ccn_charbuf_putf(b, "</face>" NL);
00487 }
00488 }
00489 ccn_charbuf_putf(b, "</faces>");
00490 ccn_charbuf_destroy(&nodebuf);
00491 }
00492
00493 static void
00494 collect_forwarding_xml(struct ccnd_handle *h, struct ccn_charbuf *b)
00495 {
00496 struct hashtb_enumerator ee;
00497 struct hashtb_enumerator *e = ⅇ
00498 struct ccn_forwarding *f;
00499 int res;
00500 struct ccn_charbuf *name = ccn_charbuf_create();
00501
00502 ccn_charbuf_putf(b, "<forwarding>");
00503 hashtb_start(h->nameprefix_tab, e);
00504 for (; e->data != NULL; hashtb_next(e)) {
00505 struct nameprefix_entry *ipe = e->data;
00506 for (f = ipe->forwarding, res = 0; f != NULL && !res; f = f->next) {
00507 if ((f->flags & (CCN_FORW_ACTIVE | CCN_FORW_PFXO)) != 0)
00508 res = 1;
00509 }
00510 if (res) {
00511 ccn_name_init(name);
00512 ccn_name_append_components(name, e->key, 0, e->keysize);
00513 ccn_charbuf_putf(b, "<fentry>");
00514 ccn_charbuf_putf(b, "<prefix>");
00515 ccn_uri_append(b, name->buf, name->length, 1);
00516 ccn_charbuf_putf(b, "</prefix>");
00517 for (f = ipe->forwarding; f != NULL; f = f->next) {
00518 if ((f->flags & (CCN_FORW_ACTIVE | CCN_FORW_PFXO)) != 0) {
00519 ccn_charbuf_putf(b,
00520 "<dest>"
00521 "<faceid>%u</faceid>"
00522 "<flags>%x</flags>"
00523 "<expires>%d</expires>"
00524 "</dest>",
00525 f->faceid,
00526 f->flags & CCN_FORW_PUBMASK,
00527 f->expires);
00528 }
00529 }
00530 ccn_charbuf_putf(b, "</fentry>");
00531 }
00532 }
00533 hashtb_end(e);
00534 ccn_charbuf_destroy(&name);
00535 ccn_charbuf_putf(b, "</forwarding>");
00536 }
00537
00538 static struct ccn_charbuf *
00539 collect_stats_xml(struct ccnd_handle *h)
00540 {
00541 struct ccnd_stats stats = {0};
00542 struct ccn_charbuf *b = ccn_charbuf_create();
00543 int i;
00544
00545 ccnd_collect_stats(h, &stats);
00546 ccn_charbuf_putf(b,
00547 "<ccnd>"
00548 "<identity>"
00549 "<ccndid>");
00550 for (i = 0; i < sizeof(h->ccnd_id); i++)
00551 ccn_charbuf_putf(b, "%02X", h->ccnd_id[i]);
00552 ccn_charbuf_putf(b, "</ccndid>"
00553 "<apiversion>%d</apiversion>"
00554 "<starttime>%ld.%06u</starttime>"
00555 "<now>%ld.%06u</now>"
00556 "</identity>",
00557 (int)CCN_API_VERSION,
00558 h->starttime, h->starttime_usec,
00559 h->sec,
00560 h->usec);
00561 ccn_charbuf_putf(b,
00562 "<cobs>"
00563 "<accessioned>%llu</accessioned>"
00564 "<stored>%d</stored>"
00565 "<stale>%lu</stale>"
00566 "<sparse>%d</sparse>"
00567 "<duplicate>%lu</duplicate>"
00568 "<sent>%lu</sent>"
00569 "</cobs>"
00570 "<interests>"
00571 "<names>%d</names>"
00572 "<pending>%ld</pending>"
00573 "<propagating>%ld</propagating>"
00574 "<noted>%ld</noted>"
00575 "<accepted>%lu</accepted>"
00576 "<dropped>%lu</dropped>"
00577 "<sent>%lu</sent>"
00578 "<stuffed>%lu</stuffed>"
00579 "</interests>",
00580 (unsigned long long)h->accession,
00581 hashtb_n(h->content_tab),
00582 h->n_stale,
00583 hashtb_n(h->sparse_straggler_tab),
00584 h->content_dups_recvd,
00585 h->content_items_sent,
00586 hashtb_n(h->nameprefix_tab), stats.total_interest_counts,
00587 hashtb_n(h->interest_tab) - stats.total_flood_control,
00588 stats.total_flood_control,
00589 h->interests_accepted, h->interests_dropped,
00590 h->interests_sent, h->interests_stuffed);
00591 collect_faces_xml(h, b);
00592 collect_forwarding_xml(h, b);
00593 ccn_charbuf_putf(b, "</ccnd>" NL);
00594 return(b);
00595 }
00596
00597
00598
00599
00600 struct ccnd_meter *
00601 ccnd_meter_create(struct ccnd_handle *h, const char *what)
00602 {
00603 struct ccnd_meter *m;
00604 m = calloc(1, sizeof(*m));
00605 if (m == NULL)
00606 return(NULL);
00607 ccnd_meter_init(h, m, what);
00608 return(m);
00609 }
00610
00611
00612
00613
00614 void
00615 ccnd_meter_destroy(struct ccnd_meter **pm)
00616 {
00617 if (*pm != NULL) {
00618 free(*pm);
00619 *pm = NULL;
00620 }
00621 }
00622
00623
00624
00625
00626 void
00627 ccnd_meter_init(struct ccnd_handle *h, struct ccnd_meter *m, const char *what)
00628 {
00629 if (m == NULL)
00630 return;
00631 memset(m, 0, sizeof(m));
00632 if (what != NULL)
00633 strncpy(m->what, what, sizeof(m->what)-1);
00634 ccnd_meter_bump(h, m, 0);
00635 }
00636
00637 static const unsigned meterHz = 7;
00638
00639
00640
00641
00642
00643 void
00644 ccnd_meter_bump(struct ccnd_handle *h, struct ccnd_meter *m, unsigned amt)
00645 {
00646 unsigned now;
00647 unsigned t;
00648 unsigned r;
00649 if (m == NULL)
00650 return;
00651 now = (((unsigned)(h->sec)) * meterHz) + (h->usec * meterHz / 1000000U);
00652 t = m->lastupdate;
00653 m->total += amt;
00654 if (now - t > 166U)
00655 m->rate = amt;
00656 else {
00657
00658 for (r = m->rate; t != now && r != 0; t++)
00659 r = r - ((r + 7U) / 8U);
00660 m->rate = r + amt;
00661 }
00662 m->lastupdate = now;
00663 }
00664
00665
00666
00667
00668
00669
00670 unsigned
00671 ccnd_meter_rate(struct ccnd_handle *h, struct ccnd_meter *m)
00672 {
00673 unsigned denom = 8;
00674 if (m == NULL)
00675 return(0);
00676 ccnd_meter_bump(h, m, 0);
00677 if (m->rate > 0x0FFFFFFF)
00678 return(m->rate / denom * meterHz);
00679 return ((m->rate * meterHz + (denom - 1)) / denom);
00680 }
00681
00682
00683
00684
00685
00686
00687 uintmax_t
00688 ccnd_meter_total(struct ccnd_meter *m)
00689 {
00690 if (m == NULL)
00691 return(0);
00692 return (m->total);
00693 }