00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00058
00059 struct ccnr_meter {
00060 uintmax_t total;
00061 char what[8];
00062 unsigned rate;
00063 unsigned lastupdate;
00064 };
00065
00066 struct ccnr_stats {
00067 long total_interest_counts;
00068 long total_flood_control;
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
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
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
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 = ⅇ
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
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
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
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 = ⅇ
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
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),
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
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
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 = ⅇ
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),
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
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
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
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;
00639
00640
00641
00642
00643
00644 void
00645 ccnr_meter_bump(struct ccnr_handle *h, struct ccnr_meter *m, unsigned amt)
00646 {
00647 unsigned now;
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;
00657 else {
00658
00659 for (r = m->rate; t != now && r != 0; t++)
00660 r = r - ((r + 7U) / 8U);
00661 m->rate = r + amt;
00662 }
00663 m->lastupdate = now;
00664 }
00665
00666
00667
00668
00669
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
00685
00686
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 }