00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <sys/select.h>
00017 #include <sys/time.h>
00018 #include <fcntl.h>
00019 #include <pwd.h>
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <sys/socket.h>
00024 #include <unistd.h>
00025 #include <ccn/ccn.h>
00026 #include <ccn/ccn_private.h>
00027 #include <ccn/charbuf.h>
00028 #include <ccn/lned.h>
00029 #include <ccn/uri.h>
00030
00031 #define USAGE \
00032 "[-hdi:nqr:vx:] ccnx:/chat/room - community text chat" "\n" \
00033 " -h - help" "\n" \
00034 " -d - debug mode - no input editing" "\n" \
00035 " -i n - print n bytes of signer's public key digest in hex" "\n" \
00036 " -n - no echo of own output" "\n" \
00037 " -q - no automatic greeting or farwell" "\n" \
00038 " -r command - hook up to input and output of responder command" "\n" \
00039 " -v - verbose trace of what is happening" "\n" \
00040 " -x sec - set freshness"
00041
00042
00043 struct pit_entry {
00044 struct ccn_charbuf *pib;
00045 int consumed;
00046 unsigned short expiry;
00047 };
00048
00049 #define PIT_LIMIT 10
00050
00051
00052 struct cs_entry {
00053 struct ccn_charbuf *cob;
00054 int sent;
00055 int matched;
00056 };
00057
00058 #define CS_LIMIT 3
00059
00060 #define VER_LIMIT 5
00061
00062
00063
00064
00065
00066
00067 struct ccnxchat_state {
00068 struct ccn *h;
00069 int n_pit;
00070 struct pit_entry pit[PIT_LIMIT];
00071 int n_cob;
00072 struct cs_entry cs[CS_LIMIT];
00073 int n_ver;
00074 struct ccn_charbuf *ver[VER_LIMIT];
00075 struct ccn_closure *cc;
00076 struct ccn_charbuf *payload;
00077 struct ccn_charbuf *lineout;
00078 struct ccn_charbuf *luser;
00079
00080 struct ccn_charbuf *basename;
00081 struct ccn_charbuf *name;
00082 struct ccn_charbuf *cob;
00083 struct ccn_charbuf *incob;
00084 int eof;
00085 int ready;
00086 int prefer_newest;
00087 int echo;
00088 int freshness;
00089 int quiet;
00090 int robotname;
00091 int verbose;
00092 };
00093
00094
00095 static enum ccn_upcall_res incoming_interest(struct ccn_closure *,
00096 enum ccn_upcall_kind,
00097 struct ccn_upcall_info *);
00098 static enum ccn_upcall_res incoming_content(struct ccn_closure *,
00099 enum ccn_upcall_kind,
00100 struct ccn_upcall_info *);
00101 static void fatal(int lineno, int val);
00102 static void initialize(struct ccnxchat_state *st, struct ccn_charbuf *);
00103 struct ccn_charbuf *adjust_regprefix(struct ccn_charbuf *);
00104 static int namecompare(const void *, const void *);
00105 static void stampnow(struct ccn_charbuf *);
00106 static void seed_random(void);
00107 static void usage(void);
00108 unsigned short wrappednow(void);
00109
00110 static int wait_for_input_or_timeout(struct ccn *, int );
00111 static void read_input(struct ccnxchat_state *);
00112 static void generate_new_data(struct ccnxchat_state *);
00113 static int matchbox(struct ccnxchat_state *);
00114 static int send_matching_data(struct ccnxchat_state *);
00115 static void toss_in_cs(struct ccnxchat_state *, const unsigned char *, size_t);
00116 static void toss_in_pit(struct ccnxchat_state *,
00117 const unsigned char *, struct ccn_parsed_interest *);
00118 static void age_cs(struct ccnxchat_state *);
00119 static void age_pit(struct ccnxchat_state *);
00120 static void debug_logger(struct ccnxchat_state *, int, struct ccn_charbuf *);
00121 static int append_interest_details(struct ccn_charbuf *c,
00122 const unsigned char *ccnb, size_t size);
00123 static void generate_cob(struct ccnxchat_state *);
00124 static void add_info_exclusion(struct ccnxchat_state *,
00125 struct ccn_upcall_info *);
00126 static void add_uri_exclusion(struct ccnxchat_state *, const char *);
00127 static void add_ver_exclusion(struct ccnxchat_state *, struct ccn_charbuf **);
00128 static void display_the_content(struct ccnxchat_state *,
00129 struct ccn_upcall_info *);
00130 static void express_interest(struct ccnxchat_state *);
00131 static void init_ver_exclusion(struct ccnxchat_state *);
00132 static void prune_oldest_exclusion(struct ccnxchat_state *);
00133 static int append_full_user_name(struct ccn_charbuf *);
00134
00135
00136 #define FATAL(res) fatal(__LINE__, res)
00137
00138
00139 #define DB(st, ccnb) debug_logger(st, __LINE__, ccnb)
00140
00141
00142
00143
00144 static int
00145 chat_main(int argc, char **argv)
00146 {
00147 struct ccn *h = NULL;
00148 struct ccn_charbuf *name = NULL;
00149 struct ccn_charbuf *cob = NULL;
00150 struct ccn_closure in_interest = {0};
00151 struct ccn_closure in_content = {0};
00152 struct ccnxchat_state state = {0};
00153 struct ccnxchat_state *st;
00154 int res;
00155 int timeout_ms;
00156
00157 st = &state;
00158 name = ccn_charbuf_create();
00159 initialize(st, name);
00160 cob = ccn_charbuf_create();
00161
00162 h = ccn_create();
00163 if (ccn_connect(h, NULL) == -1)
00164 FATAL(-1);
00165
00166 in_interest.p = &incoming_interest;
00167 in_interest.data = st;
00168
00169 in_content.p = &incoming_content;
00170 in_content.data = st;
00171 st->h = h;
00172 st->cc = &in_content;
00173 st->basename = name;
00174 st->name = ccn_charbuf_create();
00175 st->payload = ccn_charbuf_create();
00176 st->cob = ccn_charbuf_create();
00177 st->incob = ccn_charbuf_create();
00178 st->lineout = ccn_charbuf_create();
00179 st->luser = ccn_charbuf_create();
00180 append_full_user_name(st->luser);
00181 init_ver_exclusion(st);
00182
00183 res = ccn_set_interest_filter(h, st->basename, &in_interest);
00184 if (res < 0)
00185 FATAL(res);
00186 debug_logger(st, __LINE__, st->basename);
00187 st->prefer_newest = 1;
00188 express_interest(st);
00189
00190 for (;;) {
00191 res = -1;
00192 timeout_ms = 10000;
00193 if (st->ready == 0 && st->eof == 0 && st->n_pit != 0) {
00194 res = wait_for_input_or_timeout(h, 0);
00195 timeout_ms = 10;
00196 }
00197 if (res != 0)
00198 read_input(st);
00199 if (st->eof)
00200 timeout_ms = 100;
00201 else if (st->ready)
00202 timeout_ms = 10;
00203 res = ccn_run(h, timeout_ms);
00204 if (res != 0)
00205 FATAL(res);
00206 generate_new_data(st);
00207 matchbox(st);
00208 res = send_matching_data(st);
00209 if (st->eof && st->eof++ > 3)
00210 exit(0);
00211 if (res > 0 || st->cc->refcount == 0)
00212 express_interest(st);
00213 age_cs(st);
00214 age_pit(st);
00215 }
00216
00217 }
00218
00219
00220
00221
00222 static enum ccn_upcall_res
00223 incoming_interest(struct ccn_closure *selfp,
00224 enum ccn_upcall_kind kind,
00225 struct ccn_upcall_info *info)
00226 {
00227 struct ccnxchat_state *st = selfp->data;
00228
00229 switch (kind) {
00230 case CCN_UPCALL_FINAL:
00231 break;
00232 case CCN_UPCALL_INTEREST:
00233 ccn_set_run_timeout(info->h, 0);
00234 toss_in_pit(st, info->interest_ccnb, info->pi);
00235 if (st->ready)
00236 generate_new_data(st);
00237 if (matchbox(st) != 0)
00238 return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
00239 break;
00240 default:
00241 break;
00242 }
00243 return(CCN_UPCALL_RESULT_OK);
00244 }
00245
00246
00247
00248 static enum ccn_upcall_res
00249 incoming_content(struct ccn_closure *selfp,
00250 enum ccn_upcall_kind kind,
00251 struct ccn_upcall_info *info)
00252 {
00253 struct ccnxchat_state *st = selfp->data;
00254
00255 switch (kind) {
00256 case CCN_UPCALL_FINAL:
00257 return(CCN_UPCALL_RESULT_OK);
00258 case CCN_UPCALL_CONTENT_UNVERIFIED:
00259 DB(st, NULL);
00260 add_info_exclusion(st, info);
00261 return(CCN_UPCALL_RESULT_VERIFY);
00262 case CCN_UPCALL_CONTENT:
00263 display_the_content(st, info);
00264 add_info_exclusion(st, info);
00265 ccn_set_run_timeout(info->h, 0);
00266 return(CCN_UPCALL_RESULT_OK);
00267 case CCN_UPCALL_INTEREST_TIMED_OUT:
00268 prune_oldest_exclusion(st);
00269 if (st->eof == 0)
00270 ccn_set_run_timeout(info->h, 0);
00271 return(CCN_UPCALL_RESULT_OK);
00272 default:
00273
00274 DB(st, NULL);
00275 return(CCN_UPCALL_RESULT_ERR);
00276 }
00277 }
00278
00279
00280
00281 static void
00282 display_the_content(struct ccnxchat_state *st, struct ccn_upcall_info *info)
00283 {
00284 struct ccn_charbuf *cob = st->incob;
00285 struct ccn_charbuf *line = st->lineout;
00286 const unsigned char *keyhash = NULL;
00287 const unsigned char *data = NULL;
00288 size_t size;
00289 size_t ksize;
00290 ssize_t sres;
00291 int i;
00292 int res;
00293
00294
00295 size = info->pco->offset[CCN_PCO_E];
00296 if (size == cob->length && memcmp(cob->buf, info->content_ccnb, size) == 0)
00297 return;
00298 ccn_charbuf_reset(cob);
00299 ccn_charbuf_append(cob, info->content_ccnb, size);
00300 DB(st, cob);
00301 res = ccn_content_get_value(cob->buf, cob->length, info->pco,
00302 &data, &size);
00303 if (res < 0) abort();
00304 res = ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest,
00305 cob->buf,
00306 info->pco->offset[CCN_PCO_B_PublisherPublicKeyDigest],
00307 info->pco->offset[CCN_PCO_E_PublisherPublicKeyDigest],
00308 &keyhash, &ksize);
00309 if (res < 0 || ksize < 32) abort();
00310 ccn_charbuf_reset(line);
00311 for (i = 0; i < st->robotname; i++)
00312 ccn_charbuf_putf(line, "%02x", keyhash[i]);
00313 if (i > 0)
00314 ccn_charbuf_putf(line, " ");
00315 ccn_charbuf_append(line, data, size);
00316 ccn_charbuf_putf(line, "\n");
00317 sres = write(1, line->buf, line->length);
00318 if (sres != line->length)
00319 exit(1);
00320 }
00321
00322
00323 static void
00324 add_ver_exclusion(struct ccnxchat_state *st, struct ccn_charbuf **c)
00325 {
00326 int i;
00327 int j;
00328 int t;
00329
00330 for (i = 0; i < st->n_ver; i++) {
00331 t = namecompare(c, &(st->ver[i]));
00332 if (t == 0)
00333 return;
00334 if (t < 0)
00335 break;
00336 }
00337 if (st->n_ver == VER_LIMIT || st->prefer_newest) {
00338 if (i == 0)
00339 return;
00340 ccn_charbuf_destroy(&st->ver[0]);
00341 for (j = 0; j + 1 < i; j++)
00342 st->ver[j] = st->ver[j + 1];
00343 st->ver[j] = *c;
00344 *c = NULL;
00345 st->prefer_newest = 0;
00346 return;
00347 }
00348 for (j = st->n_ver; j > i; j--)
00349 st->ver[j] = st->ver[j - 1];
00350 st->n_ver++;
00351 st->ver[j] = *c;
00352 *c = NULL;
00353 }
00354
00355 static void
00356 prune_oldest_exclusion(struct ccnxchat_state *st)
00357 {
00358 int j;
00359
00360 if (st->n_ver <= 2)
00361 return;
00362 ccn_charbuf_destroy(&st->ver[0]);
00363 for (j = 0; j + 1 < st->n_ver; j++)
00364 st->ver[j] = st->ver[j + 1];
00365 st->n_ver--;
00366 }
00367
00368 static void
00369 add_info_exclusion(struct ccnxchat_state *st, struct ccn_upcall_info *info)
00370 {
00371 struct ccn_charbuf *c = ccn_charbuf_create();
00372 const unsigned char *ver = NULL;
00373 size_t ver_size = 0;
00374 int res;
00375
00376 if (info->content_comps->n > info->matched_comps + 1) {
00377 ccn_name_init(c);
00378 res = ccn_ref_tagged_BLOB(CCN_DTAG_Component, info->content_ccnb,
00379 info->content_comps->buf[info->matched_comps],
00380 info->content_comps->buf[info->matched_comps + 1],
00381 &ver,
00382 &ver_size);
00383 if (res < 0) abort();
00384 ccn_name_append(c, ver, ver_size);
00385 add_ver_exclusion(st, &c);
00386 }
00387 ccn_charbuf_destroy(&c);
00388 }
00389
00390 static void
00391 add_uri_exclusion(struct ccnxchat_state *st, const char *uri)
00392 {
00393 struct ccn_charbuf *c = ccn_charbuf_create();
00394
00395 ccn_name_from_uri(c, uri);
00396 add_ver_exclusion(st, &c);
00397 ccn_charbuf_destroy(&c);
00398 }
00399
00400 static void
00401 add_cob_exclusion(struct ccnxchat_state *st, struct ccn_charbuf *cob)
00402 {
00403 struct ccn_parsed_ContentObject co;
00404 struct ccn_parsed_ContentObject *pco = &co;
00405 struct ccn_indexbuf *comps;
00406 struct ccn_charbuf *c;
00407 const unsigned char *ver = NULL;
00408 size_t ver_size = 0;
00409 int i;
00410 int res;
00411
00412 i = ccn_name_split(st->basename, NULL);
00413 c = ccn_charbuf_create();
00414 comps = ccn_indexbuf_create();
00415 res = ccn_parse_ContentObject(cob->buf, cob->length, pco, comps);
00416 if (res >= 0 && i + 1 < comps->n) {
00417 res = ccn_ref_tagged_BLOB(CCN_DTAG_Component, cob->buf,
00418 comps->buf[i], comps->buf[i + 1],
00419 &ver, &ver_size);
00420 if (res >= 0) {
00421 ccn_name_init(c);
00422 ccn_name_append(c, ver, ver_size);
00423 add_ver_exclusion(st, &c);
00424 }
00425 }
00426 ccn_indexbuf_destroy(&comps);
00427 ccn_charbuf_destroy(&c);
00428 }
00429
00430 static void
00431 init_ver_exclusion(struct ccnxchat_state *st)
00432 {
00433 add_uri_exclusion(st, "/%FE%00%00%00%00%00%00");
00434 add_uri_exclusion(st, "/%FD%00%FF%FF%FF%FF%FF");
00435 }
00436
00437 static void
00438 express_interest(struct ccnxchat_state *st)
00439 {
00440 struct ccn_charbuf *templ = ccn_charbuf_create();
00441 struct ccn_charbuf *comp = NULL;
00442 int i;
00443
00444 ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
00445 ccn_charbuf_append(templ, st->basename->buf, st->basename->length);
00446 ccnb_tagged_putf(templ, CCN_DTAG_MinSuffixComponents, "%d", 3);
00447 ccnb_tagged_putf(templ, CCN_DTAG_MaxSuffixComponents, "%d", 3);
00448 ccn_charbuf_append_tt(templ, CCN_DTAG_Exclude, CCN_DTAG);
00449 if (st->n_ver > 1)
00450 ccnb_tagged_putf(templ, CCN_DTAG_Any, "");
00451 for (i = 0; i < st->n_ver; i++) {
00452 comp = st->ver[i];
00453 if (comp->length < 4) abort();
00454 ccn_charbuf_append(templ, comp->buf + 1, comp->length - 2);
00455 }
00456 ccnb_tagged_putf(templ, CCN_DTAG_Any, "");
00457 ccn_charbuf_append_closer(templ);
00458 if (st->prefer_newest)
00459 ccnb_tagged_putf(templ, CCN_DTAG_ChildSelector, "%d", 1);
00460 ccn_charbuf_append_closer(templ);
00461 ccn_express_interest(st->h, st->basename, st->cc, templ);
00462 ccn_charbuf_destroy(&templ);
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472 static void
00473 generate_cob(struct ccnxchat_state *st)
00474 {
00475 struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00476 int res;
00477
00478
00479 ccn_charbuf_reset(st->name);
00480 ccn_charbuf_append(st->name, st->basename->buf, st->basename->length);
00481 ccn_create_version(st->h, st->name, CCN_V_NOW, 0, 0);
00482 ccn_name_append_numeric(st->name, CCN_MARKER_SEQNUM, 0);
00483 sp.sp_flags |= CCN_SP_FINAL_BLOCK;
00484 if (st->freshness > 0)
00485 sp.freshness = st->freshness;
00486
00487 ccn_charbuf_reset(st->cob);
00488 res = ccn_sign_content(st->h, st->cob, st->name, &sp,
00489 st->payload->buf, st->payload->length);
00490 if (res < 0)
00491 FATAL(res);
00492 DB(st, st->cob);
00493 }
00494
00495
00496
00497
00498
00499
00500 static int
00501 wait_for_input_or_timeout(struct ccn *h, int fd)
00502 {
00503 fd_set readfds;
00504 struct timeval tv;
00505 int ccnfd;
00506 int maxfd = fd;
00507 int res = -1;
00508
00509 ccnfd = ccn_get_connection_fd(h);
00510 if (ccnfd < 0)
00511 return(-1);
00512 if (maxfd < ccnfd)
00513 maxfd = ccnfd;
00514 FD_ZERO(&readfds);
00515 FD_SET(fd, &readfds);
00516 FD_SET(ccnfd, &readfds);
00517 res = ccn_process_scheduled_operations(h);
00518 if (res >= 0) {
00519 tv.tv_sec = res / 1000000U;
00520 tv.tv_usec = res % 1000000U;
00521 res = select(maxfd + 1, &readfds, 0, 0, &tv);
00522 }
00523 if (res >= 0)
00524 res = FD_ISSET(fd, &readfds);
00525 return(res);
00526 }
00527
00528
00529 static void
00530 read_input(struct ccnxchat_state *st)
00531 {
00532 unsigned char *cp = NULL;
00533 ssize_t res;
00534 int fl;
00535 int fd = 0;
00536
00537 if (st->ready)
00538 return;
00539 if (st->eof) {
00540 if (st->payload->length > 0)
00541 st->ready = 1;
00542 return;
00543 }
00544 fl = fcntl(fd, F_GETFL);
00545 fcntl(fd, F_SETFL, O_NONBLOCK | fl);
00546 while (st->ready == 0) {
00547 cp = ccn_charbuf_reserve(st->payload, 1);
00548 res = read(fd, cp, 1);
00549 if (res == 1) {
00550 if (cp[0] == '\n')
00551 st->ready = 1;
00552 else
00553 st->payload->length++;
00554 }
00555 else if (res == 0) {
00556 if (st->eof == 0 && st->quiet == 0) {
00557 ccn_charbuf_putf(st->payload, "=== ");
00558 ccn_charbuf_append_charbuf(st->payload, st->luser);
00559 ccn_charbuf_putf(st->payload, " leaving chat");
00560 st->freshness = 1;
00561 }
00562 st->eof = 1;
00563 if (st->payload->length > 0)
00564 st->ready = 1;
00565 break;
00566 }
00567 else
00568 break;
00569 }
00570 fcntl(fd, F_SETFL, fl);
00571 }
00572
00573
00574 static void
00575 generate_new_data(struct ccnxchat_state *st)
00576 {
00577 if (st->ready && st->n_pit > 0 && st->n_cob < CS_LIMIT) {
00578 generate_cob(st);
00579 toss_in_cs(st, st->cob->buf, st->cob->length);
00580 if (st->echo == 0)
00581 add_cob_exclusion(st, st->cob);
00582 ccn_charbuf_reset(st->payload);
00583 st->ready = 0;
00584 }
00585 }
00586
00587
00588
00589
00590 static void
00591 toss_in_cs(struct ccnxchat_state *st, const unsigned char *p, size_t size)
00592 {
00593 struct cs_entry *cse;
00594
00595 if (st->n_cob >= CS_LIMIT)
00596 FATAL(st->n_cob);
00597 cse = &(st->cs[st->n_cob++]);
00598 cse->cob = ccn_charbuf_create();
00599 ccn_charbuf_append(cse->cob, p, size);
00600 cse->sent = 0;
00601 cse->matched = 0;
00602 }
00603
00604
00605 static void
00606 toss_in_pit(struct ccnxchat_state *st, const unsigned char *p,
00607 struct ccn_parsed_interest *pi)
00608 {
00609 intmax_t lifetime;
00610 unsigned short lifetime_ms = ((unsigned short)(~0)) >> 1;
00611 struct pit_entry *pie;
00612 size_t size;
00613
00614 size = pi->offset[CCN_PI_E];
00615 lifetime = ccn_interest_lifetime(p, pi);
00616 lifetime = (lifetime * (1000 / 8) + (4096 / 8 - 1)) / (4096 / 8);
00617 if (lifetime_ms > lifetime)
00618 lifetime_ms = lifetime;
00619 if (st->n_pit == PIT_LIMIT)
00620 age_pit(st);
00621 if (st->n_pit == PIT_LIMIT) {
00622
00623 st->pit[0].consumed = 1;
00624 age_pit(st);
00625 }
00626 if (st->n_pit >= PIT_LIMIT)
00627 FATAL(st->n_pit);
00628 pie = &(st->pit[st->n_pit++]);
00629 pie->pib = ccn_charbuf_create();
00630 ccn_charbuf_append(pie->pib, p, size);
00631 pie->consumed = 0;
00632 pie->expiry = wrappednow() + lifetime_ms;
00633 DB(st, pie->pib);
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644 static int
00645 matchbox(struct ccnxchat_state *st)
00646 {
00647 int new_matches;
00648 struct cs_entry *cse;
00649 struct pit_entry *pie;
00650 int i, j;
00651
00652 new_matches = 0;
00653 for (i = 0; i < st->n_pit; i++) {
00654 pie = &(st->pit[i]);
00655 if (pie->consumed)
00656 continue;
00657 for (j = 0; j < st->n_cob; j++) {
00658 cse = &(st->cs[j]);
00659 if (ccn_content_matches_interest(
00660 cse->cob->buf, cse->cob->length, 1, NULL,
00661 pie->pib->buf, pie->pib->length, NULL)) {
00662 if (cse->sent == 0)
00663 new_matches++;
00664 cse->matched = 1;
00665 pie->consumed = 1;
00666 DB(st, pie->pib);
00667 }
00668 }
00669 }
00670 return(new_matches);
00671 }
00672
00673
00674 static int
00675 send_matching_data(struct ccnxchat_state *st)
00676 {
00677 struct cs_entry *cse = NULL;
00678 int i;
00679 int res;
00680 int sent;
00681
00682 sent = 0;
00683 for (i = 0; i < st->n_cob; i++) {
00684 cse = &(st->cs[i]);
00685 if (cse->matched) {
00686 res = ccn_put(st->h, cse->cob->buf, cse->cob->length);
00687 if (res < 0)
00688 FATAL(res);
00689 cse->sent++;
00690 cse->matched = 0;
00691 sent++;
00692 }
00693 }
00694 return(sent);
00695 }
00696
00697
00698 static void
00699 age_cs(struct ccnxchat_state *st)
00700 {
00701 const struct cs_entry empty = {0};
00702 int i;
00703 int j;
00704
00705 for (i = 0, j = 0; i < st->n_cob; i++) {
00706 if (st->cs[i].sent != 0) {
00707
00708 DB(st, st->cs[i].cob);
00709 ccn_charbuf_destroy(&(st->cs[i].cob));
00710 }
00711 else
00712 st->cs[j++] = st->cs[i];
00713 }
00714 st->n_cob = j;
00715
00716 while (i > j)
00717 st->cs[--i] = empty;
00718 }
00719
00720
00721 static void
00722 age_pit(struct ccnxchat_state *st)
00723 {
00724 const struct pit_entry empty = {0};
00725 struct pit_entry *pie;
00726 unsigned short now;
00727 unsigned short delta;
00728 unsigned short deltawrap;
00729 int i;
00730 int j;
00731
00732 deltawrap = ~0;
00733 deltawrap >>= 1;
00734 now = wrappednow();
00735 for (i = 0, j = 0; i < st->n_pit; i++) {
00736 pie = &(st->pit[i]);
00737 delta = now - pie->expiry;
00738 if (delta <= deltawrap) {
00739 DB(st, pie->pib);
00740 pie->consumed = 1;
00741 }
00742 if (pie->consumed)
00743 ccn_charbuf_destroy(&(pie->pib));
00744 else
00745 st->pit[j++] = st->pit[i];
00746 }
00747 st->n_pit = j;
00748
00749 while (i > j)
00750 st->pit[--i] = empty;
00751 }
00752
00753
00754
00755
00756
00757
00758
00759 static int
00760 namecompare(const void *a, const void *b)
00761 {
00762 const struct ccn_charbuf *aa = *(const struct ccn_charbuf **)a;
00763 const struct ccn_charbuf *bb = *(const struct ccn_charbuf **)b;
00764 int ans = ccn_compare_names(aa->buf, aa->length, bb->buf, bb->length);
00765 return (ans);
00766 }
00767
00768
00769
00770
00771 static const char *progname;
00772
00773 static struct {
00774 int debug;
00775 int echo;
00776 int freshness;
00777 int robotname;
00778 int quiet;
00779 int verbose;
00780 const char *basename;
00781 const char *responder;
00782 } option;
00783
00784 static void
00785 parseopts(int argc, char **argv)
00786 {
00787 int opt;
00788
00789 progname = argv[0];
00790 optind = 1;
00791 option.echo = 1;
00792 option.robotname = 3;
00793 option.verbose = 0;
00794 option.quiet = 0;
00795 option.freshness = 30 * 60;
00796 while ((opt = getopt(argc, argv, "hdi:nqr:vx:")) != -1) {
00797 switch (opt) {
00798 case 'd':
00799 option.debug = 1;
00800 break;
00801 case 'i':
00802 option.robotname = atoi(optarg);
00803 if (option.robotname < 0 || option.robotname > 32)
00804 usage();
00805 break;
00806 case 'n':
00807 option.echo = 0;
00808 break;
00809 case 'q':
00810 option.quiet = 1;
00811 break;
00812 case 'r':
00813 option.responder = optarg;
00814 break;
00815 case 'v':
00816 option.verbose++;
00817 break;
00818 case 'x':
00819 option.freshness = atoi(optarg);
00820 break;
00821 case 'h':
00822 default:
00823 usage();
00824 }
00825 }
00826 option.basename = argv[optind];
00827 if (option.basename == NULL || argv[optind + 1] != NULL)
00828 usage();
00829 }
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839 static void
00840 initialize(struct ccnxchat_state *st, struct ccn_charbuf *basename)
00841 {
00842 int res;
00843
00844 res = ccn_name_from_uri(basename, option.basename);
00845 if (res < 0)
00846 usage();
00847 st->echo = option.echo;
00848 st->freshness = option.freshness;
00849 st->verbose = option.verbose;
00850 st->robotname = option.robotname;
00851 st->quiet = option.quiet;
00852 seed_random();
00853 }
00854
00855
00856 struct ccn_charbuf *
00857 adjust_regprefix(struct ccn_charbuf *name)
00858 {
00859 struct ccn_charbuf *c;
00860
00861 c = ccn_charbuf_create();
00862 ccn_charbuf_append(c, name->buf, name->length);
00863 ccn_name_chop(c, NULL, -1);
00864 DB(NULL, c);
00865 return(c);
00866 }
00867
00868
00869 static void
00870 fatal(int lineno, int val)
00871 {
00872 fprintf(stderr, "Error near %s:%d (%d)\n", progname, lineno, val);
00873 exit(1);
00874 }
00875
00876
00877 static void
00878 usage(void)
00879 {
00880 fprintf(stderr, "%s " USAGE "\n", progname);
00881 exit(1);
00882 }
00883
00884
00885 static void
00886 stampnow(struct ccn_charbuf *c)
00887 {
00888 struct timeval tv;
00889 unsigned long sec;
00890 unsigned usec;
00891
00892 gettimeofday(&tv, NULL);
00893 sec = tv.tv_sec;
00894 usec = tv.tv_usec;
00895 ccn_charbuf_putf(c, "%lu.%06u ", sec, usec);
00896 }
00897
00898
00899 unsigned short
00900 wrappednow(void)
00901 {
00902 unsigned short now;
00903 struct timeval tv;
00904
00905 gettimeofday(&tv, NULL);
00906 now = tv.tv_sec * 1000 + tv.tv_usec / 1000;
00907 return(now);
00908 }
00909
00910
00911 static void
00912 seed_random(void)
00913 {
00914 struct timeval tv;
00915
00916 gettimeofday(&tv, NULL);
00917 srandom(getpid() * 31415 + tv.tv_sec + tv.tv_usec);
00918 }
00919
00920
00921
00922
00923
00924
00925
00926 static void
00927 debug_logger(struct ccnxchat_state *st, int lineno, struct ccn_charbuf *ccnb)
00928 {
00929 struct ccn_charbuf *c;
00930
00931 if (st->verbose == 0)
00932 return;
00933 c = ccn_charbuf_create();
00934 stampnow(c);
00935 ccn_charbuf_putf(c, "debug.%d %5d", lineno, wrappednow());
00936 if (st != NULL)
00937 ccn_charbuf_putf(c, " pit=%d pot=%d cob=%d buf=%d",
00938 st->n_pit, st->cc->refcount,
00939 st->n_cob, (int)st->payload->length);
00940 if (ccnb != NULL) {
00941 ccn_charbuf_putf(c, " ");
00942 ccn_uri_append(c, ccnb->buf, ccnb->length, 1);
00943 append_interest_details(c, ccnb->buf, ccnb->length);
00944 }
00945 fprintf(stderr, "%s\n", ccn_charbuf_as_string(c));
00946 ccn_charbuf_destroy(&c);
00947 }
00948
00949 static int
00950 append_interest_details(struct ccn_charbuf *c,
00951 const unsigned char *ccnb, size_t size)
00952 {
00953 struct ccn_parsed_interest interest;
00954 struct ccn_parsed_interest *pi = &interest;
00955 struct ccn_buf_decoder decoder;
00956 struct ccn_buf_decoder *d;
00957 const unsigned char *bloom;
00958 size_t bloom_size = 0;
00959 const unsigned char *comp;
00960 size_t comp_size = 0;
00961 int i;
00962 int l;
00963 int res;
00964
00965 res = ccn_parse_interest(ccnb, size, pi, NULL);
00966 if (res < 0)
00967 return(res);
00968 i = pi->offset[CCN_PI_B_Exclude];
00969 l = pi->offset[CCN_PI_E_Exclude] - i;
00970 if (l > 0) {
00971 d = ccn_buf_decoder_start(&decoder, ccnb + i, l);
00972 ccn_charbuf_append_string(c, " excl: ");
00973 ccn_buf_advance(d);
00974
00975 if (ccn_buf_match_dtag(d, CCN_DTAG_Any)) {
00976 ccn_buf_advance(d);
00977 ccn_charbuf_append_string(c, "* ");
00978 ccn_buf_check_close(d);
00979 }
00980 else if (ccn_buf_match_dtag(d, CCN_DTAG_Bloom)) {
00981 ccn_buf_advance(d);
00982 if (ccn_buf_match_blob(d, &bloom, &bloom_size))
00983 ccn_buf_advance(d);
00984 ccn_charbuf_append_string(c, "? ");
00985 ccn_buf_check_close(d);
00986 }
00987 while (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00988 ccn_buf_advance(d);
00989 comp_size = 0;
00990 if (ccn_buf_match_blob(d, &comp, &comp_size))
00991 ccn_buf_advance(d);
00992 ccn_uri_append_percentescaped(c, comp, comp_size);
00993 ccn_charbuf_append_string(c, " ");
00994 ccn_buf_check_close(d);
00995 if (ccn_buf_match_dtag(d, CCN_DTAG_Any)) {
00996 ccn_buf_advance(d);
00997 ccn_charbuf_append_string(c, "* ");
00998 ccn_buf_check_close(d);
00999 }
01000 else if (ccn_buf_match_dtag(d, CCN_DTAG_Bloom)) {
01001 ccn_buf_advance(d);
01002 if (ccn_buf_match_blob(d, &bloom, &bloom_size))
01003 ccn_buf_advance(d);
01004 ccn_charbuf_append_string(c, "? ");
01005 ccn_buf_check_close(d);
01006 }
01007 }
01008 }
01009 return(0);
01010 }
01011
01012 static int
01013 append_full_user_name(struct ccn_charbuf *c)
01014 {
01015 int res = -1;
01016 #ifndef C_NO_GECOS
01017 struct passwd *pwd;
01018 pwd = getpwuid(getuid());
01019 if (pwd != NULL) {
01020 res = 0;
01021 ccn_charbuf_putf(c, "%s", pwd->pw_gecos);
01022 }
01023 #endif
01024 return(res);
01025 }
01026
01027
01028
01029
01030 static int
01031 robo_chat(int argc, char **argv)
01032 {
01033 pid_t p;
01034 int res;
01035 int io[2] = {-1, -1};
01036 int oi[2] = {-1, -1};
01037
01038 res = socketpair(AF_UNIX, SOCK_STREAM, 0, io);
01039 if (res < 0) exit(1);
01040 res = socketpair(AF_UNIX, SOCK_STREAM, 0, oi);
01041 if (res < 0) exit(1);
01042 p = fork();
01043 if (p < 0) {
01044 perror("fork");
01045 exit(1);
01046 }
01047 if (p == 0) {
01048
01049 dup2(io[1], 0);
01050 dup2(oi[1], 1);
01051 close(io[0]);
01052 close(io[1]);
01053 close(oi[0]);
01054 close(oi[1]);
01055 execlp("sh", "sh", "-c", option.responder, NULL);
01056 perror(option.responder);
01057 exit(1);
01058 }
01059
01060 dup2(io[0], 1);
01061 dup2(oi[0], 0);
01062 close(io[0]);
01063 close(io[1]);
01064 close(oi[0]);
01065 close(oi[1]);
01066
01067 option.echo = 0;
01068 option.quiet = 1;
01069 return(chat_main(argc, argv));
01070 }
01071
01072 int
01073 main(int argc, char **argv)
01074 {
01075 parseopts(argc, argv);
01076 if (option.responder != NULL)
01077 return(robo_chat(argc, argv));
01078 if (option.debug)
01079 return(chat_main(argc, argv));
01080 return(lned_run(argc, argv, "Chat.. ", &chat_main));
01081 }