ccnr_dispatch.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnr_dispatch.c
00003  * 
00004  * Part of ccnr -  CCNx Repository Daemon.
00005  *
00006  */
00007 
00008 /*
00009  * Copyright (C) 2011 Palo Alto Research Center, Inc.
00010  *
00011  * This work is free software; you can redistribute it and/or modify it under
00012  * the terms of the GNU General Public License version 2 as published by the
00013  * Free Software Foundation.
00014  * This work is distributed in the hope that it will be useful, but WITHOUT ANY
00015  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00017  * for more details. You should have received a copy of the GNU General Public
00018  * License along with this program; if not, write to the
00019  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022  
00023 #include <errno.h>
00024 #include <fcntl.h>
00025 #include <limits.h>
00026 #include <netdb.h>
00027 #include <poll.h>
00028 #include <signal.h>
00029 #include <stddef.h>
00030 #include <stdint.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <time.h>
00035 #include <unistd.h>
00036 #include <arpa/inet.h>
00037 #include <sys/time.h>
00038 #include <sys/socket.h>
00039 #include <sys/stat.h>
00040 #include <sys/types.h>
00041 #include <sys/un.h>
00042 #include <netinet/in.h>
00043 
00044 #include <ccn/bloom.h>
00045 #include <ccn/ccn.h>
00046 #include <ccn/ccn_private.h>
00047 #include <ccn/charbuf.h>
00048 #include <ccn/face_mgmt.h>
00049 #include <ccn/hashtb.h>
00050 #include <ccn/indexbuf.h>
00051 #include <ccn/schedule.h>
00052 #include <ccn/reg_mgmt.h>
00053 #include <ccn/uri.h>
00054 
00055 #include <sync/SyncBase.h>
00056 
00057 #include "ccnr_private.h"
00058 
00059 #include "ccnr_dispatch.h"
00060 
00061 #include "ccnr_forwarding.h"
00062 #include "ccnr_io.h"
00063 #include "ccnr_link.h"
00064 #include "ccnr_match.h"
00065 #include "ccnr_msg.h"
00066 #include "ccnr_proto.h"
00067 #include "ccnr_sendq.h"
00068 #include "ccnr_stats.h"
00069 #include "ccnr_store.h"
00070 #include "ccnr_sync.h"
00071 #include "ccnr_util.h"
00072 
00073 static void
00074 process_input_message(struct ccnr_handle *h, struct fdholder *fdholder,
00075                       unsigned char *msg, size_t size, int pdu_ok,
00076                       off_t *offsetp)
00077 {
00078     struct ccn_skeleton_decoder decoder = {0};
00079     struct ccn_skeleton_decoder *d = &decoder;
00080     ssize_t dres;
00081     enum ccn_dtag dtag;
00082     struct content_entry *content = NULL;
00083     
00084     if ((fdholder->flags & CCNR_FACE_UNDECIDED) != 0) {
00085         fdholder->flags &= ~CCNR_FACE_UNDECIDED;
00086         if ((fdholder->flags & CCNR_FACE_LOOPBACK) != 0)
00087             fdholder->flags |= CCNR_FACE_GG;
00088         /* YYY This is the first place that we know that an inbound stream fdholder is speaking CCNx protocol. */
00089         r_io_register_new_face(h, fdholder);
00090     }
00091     d->state |= CCN_DSTATE_PAUSE;
00092     dres = ccn_skeleton_decode(d, msg, size);
00093     if (d->state < 0)
00094         abort(); /* cannot happen because of checks in caller */
00095     if (CCN_GET_TT_FROM_DSTATE(d->state) != CCN_DTAG) {
00096         ccnr_msg(h, "discarding unknown message; size = %lu", (unsigned long)size);
00097         // XXX - keep a count?
00098         return;
00099     }
00100     dtag = d->numval;
00101     switch (dtag) {
00102 //        case CCN_DTAG_Interest:
00103 //            process_incoming_interest(h, fdholder, msg, size);
00104 //            return;
00105         case CCN_DTAG_ContentObject:
00106             content = process_incoming_content(h, fdholder, msg, size);
00107             if (content != NULL && offsetp != NULL)
00108                 r_store_set_accession_from_offset(h, content, fdholder, *offsetp);
00109             return;
00110         default:
00111             break;
00112     }
00113     ccnr_msg(h, "discarding unknown message; dtag=%u, size = %lu",
00114              (unsigned)dtag,
00115              (unsigned long)size);
00116 }
00117 
00118 /**
00119  * Break up data in a face's input buffer buffer into individual messages,
00120  * and call process_input_message on each one.
00121  *
00122  * This is used to handle things originating from the internal client -
00123  * its output is input for fdholder 0.
00124  */
00125 static void
00126 process_input_buffer(struct ccnr_handle *h, struct fdholder *fdholder)
00127 {
00128     unsigned char *msg;
00129     size_t size;
00130     ssize_t dres;
00131     struct ccn_skeleton_decoder *d;
00132 
00133     if (fdholder == NULL || fdholder->inbuf == NULL)
00134         return;
00135     d = &fdholder->decoder;
00136     msg = fdholder->inbuf->buf;
00137     size = fdholder->inbuf->length;
00138     while (d->index < size) {
00139         dres = ccn_skeleton_decode(d, msg + d->index, size - d->index);
00140         if (d->state != 0)
00141             break;
00142         process_input_message(h, fdholder, msg + d->index - dres, dres, 0, NULL);
00143     }
00144     if (d->index != size) {
00145         ccnr_msg(h, "protocol error on fdholder %u (state %d), discarding %d bytes",
00146                      fdholder->filedesc, d->state, (int)(size - d->index));
00147         // XXX - perhaps this should be a fatal error.
00148     }
00149     fdholder->inbuf->length = 0;
00150     memset(d, 0, sizeof(*d));
00151 }
00152 
00153 /**
00154  * Process the input from a socket or file.
00155  *
00156  * The fd has been found ready for input by the poll call.
00157  * Decide what fdholder it corresponds to, and after checking for exceptional
00158  * cases, receive data, parse it into ccnb-encoded messages, and call
00159  * process_input_message for each one.
00160  */
00161 PUBLIC void
00162 r_dispatch_process_input(struct ccnr_handle *h, int fd)
00163 {
00164     struct fdholder *fdholder = NULL;
00165     struct fdholder *source = NULL;
00166     ssize_t res;
00167     ssize_t dres;
00168     ssize_t msgstart;
00169     unsigned char *buf;
00170     struct ccn_skeleton_decoder *d;
00171     struct sockaddr_storage sstor;
00172     socklen_t addrlen = sizeof(sstor);
00173     struct sockaddr *addr = (struct sockaddr *)&sstor;
00174     
00175     fdholder = r_io_fdholder_from_fd(h, fd);
00176     if (fdholder == NULL)
00177         return;
00178     if ((fdholder->flags & (CCNR_FACE_DGRAM | CCNR_FACE_PASSIVE)) == CCNR_FACE_PASSIVE) {
00179         r_io_accept_connection(h, fd);
00180         return;
00181     }
00182     if ((fdholder->flags & CCNR_FACE_CCND) != 0) {
00183         res = ccn_run(h->direct_client, 0);
00184         if (res < 0) {
00185             // Deal with it somehow.  Probably means ccnd went away.
00186             // Should schedule reconnection.
00187             ccnr_msg(h, "ccn_run returned error, shutting down direct client");
00188             r_io_shutdown_client_fd(h, fd);
00189         }
00190         return;
00191     }
00192     d = &fdholder->decoder;
00193     if (fdholder->inbuf == NULL) {
00194         fdholder->inbuf = ccn_charbuf_create();
00195         fdholder->bufoffset = 0;
00196     }
00197     if (fdholder->inbuf->length == 0)
00198         memset(d, 0, sizeof(*d));
00199     buf = ccn_charbuf_reserve(fdholder->inbuf, 8800);
00200     memset(&sstor, 0, sizeof(sstor));
00201     if ((fdholder->flags & CCNR_FACE_SOCKMASK) != 0) {
00202         res = recvfrom(fdholder->filedesc, buf, fdholder->inbuf->limit - fdholder->inbuf->length,
00203             /* flags */ 0, addr, &addrlen);
00204     }
00205     else {
00206         res = read(fdholder->filedesc, buf, fdholder->inbuf->limit - fdholder->inbuf->length);
00207     }
00208     if (res == -1)
00209         ccnr_msg(h, "read %u :%s (errno = %d)",
00210                     fdholder->filedesc, strerror(errno), errno);
00211     else if (res == 0 && (fdholder->flags & CCNR_FACE_DGRAM) == 0) {
00212         if (fd == h->active_in_fd && h->stable == 0) {
00213             h->stable = lseek(fd, 0, SEEK_END);
00214             ccnr_msg(h, "read %ju bytes", (uintmax_t)h->stable);
00215         }
00216         r_io_shutdown_client_fd(h, fd);
00217     }
00218     else {
00219         off_t offset = (off_t)-1;
00220         off_t *offsetp = NULL;
00221         if ((fdholder->flags & CCNR_FACE_REPODATA) != 0)
00222             offsetp = &offset;
00223         source = fdholder;
00224         ccnr_meter_bump(h, source->meter[FM_BYTI], res);
00225         source->recvcount++;
00226         fdholder->inbuf->length += res;
00227         msgstart = 0;
00228         if ((fdholder->flags & CCNR_FACE_UNDECIDED) != 0) {
00229             ccnr_stats_handle_http_connection(h, fdholder);
00230             return;
00231         }
00232         dres = ccn_skeleton_decode(d, buf, res);
00233         while (d->state == 0) {
00234             if (offsetp != NULL)
00235                 *offsetp = fdholder->bufoffset + msgstart;
00236             process_input_message(h, source,
00237                                   fdholder->inbuf->buf + msgstart,
00238                                   d->index - msgstart,
00239                                   (fdholder->flags & CCNR_FACE_LOCAL) != 0,
00240                                   offsetp);
00241             msgstart = d->index;
00242             if (msgstart == fdholder->inbuf->length) {
00243                 fdholder->inbuf->length = 0;
00244                 fdholder->bufoffset += msgstart;
00245                 return;
00246             }
00247             dres = ccn_skeleton_decode(d,
00248                     fdholder->inbuf->buf + msgstart,
00249                     fdholder->inbuf->length - msgstart);
00250         }
00251         fdholder->bufoffset += msgstart;
00252         if ((fdholder->flags & CCNR_FACE_DGRAM) != 0) {
00253             ccnr_msg(h, "protocol error on fdholder %u, discarding %u bytes",
00254                 source->filedesc,
00255                 (unsigned)(fdholder->inbuf->length - msgstart));
00256             fdholder->inbuf->length = 0;
00257             /* XXX - should probably ignore this source for a while */
00258             return;
00259         }
00260         else if (d->state < 0) {
00261             ccnr_msg(h, "protocol error on fdholder %u", source->filedesc);
00262             r_io_shutdown_client_fd(h, fd);
00263             return;
00264         }
00265         if (msgstart < fdholder->inbuf->length && msgstart > 0) {
00266             /* move partial message to start of buffer */
00267             memmove(fdholder->inbuf->buf, fdholder->inbuf->buf + msgstart,
00268                 fdholder->inbuf->length - msgstart);
00269             fdholder->inbuf->length -= msgstart;
00270             d->index -= msgstart;
00271         }
00272     }
00273 }
00274 
00275 PUBLIC void
00276 r_dispatch_process_internal_client_buffer(struct ccnr_handle *h)
00277 {
00278     struct fdholder *fdholder = h->face0;
00279     if (fdholder == NULL)
00280         return;
00281     fdholder->inbuf = ccn_grab_buffered_output(h->internal_client);
00282     if (fdholder->inbuf == NULL)
00283         return;
00284     ccnr_meter_bump(h, fdholder->meter[FM_BYTI], fdholder->inbuf->length);
00285     process_input_buffer(h, fdholder);
00286     ccn_charbuf_destroy(&(fdholder->inbuf));
00287 }
00288 /**
00289  * Run the main loop of the ccnr
00290  */
00291 PUBLIC void
00292 r_dispatch_run(struct ccnr_handle *h)
00293 {
00294     int i;
00295     int res;
00296     int timeout_ms = -1;
00297     int prev_timeout_ms = -1;
00298     int usec;
00299     int usec_direct;
00300     
00301     if (h->running < 0) {
00302         ccnr_msg(h, "Fatal error during initialization");
00303         return;
00304     }
00305     for (h->running = 1; h->running;) {
00306         r_dispatch_process_internal_client_buffer(h);
00307         usec = ccn_schedule_run(h->sched);
00308         usec_direct = ccn_process_scheduled_operations(h->direct_client);
00309         if (usec_direct < usec)
00310             usec = usec_direct;
00311         if (1) {
00312             /* If so requested, shut down when ccnd goes away. */
00313             if (ccn_get_connection_fd(h->direct_client) == -1) {
00314                 /* XXX - since we cannot reasonably recover, always go away. */
00315                 ccnr_msg(h, "lost connection to ccnd");
00316                 h->running = 0;
00317                 break;
00318             }
00319         }
00320         timeout_ms = (usec < 0) ? -1 : ((usec + 960) / 1000);
00321         if (timeout_ms == 0 && prev_timeout_ms == 0)
00322             timeout_ms = 1;
00323         r_dispatch_process_internal_client_buffer(h);
00324         r_store_trim(h, h->cob_limit);
00325         r_io_prepare_poll_fds(h);
00326         res = poll(h->fds, h->nfds, timeout_ms);
00327         prev_timeout_ms = ((res == 0) ? timeout_ms : 1);
00328         if (-1 == res) {
00329             if (errno == EINTR)
00330                 continue;
00331             ccnr_msg(h, "poll: %s (errno = %d)", strerror(errno), errno);
00332             sleep(1);
00333             continue;
00334         }
00335         for (i = 0; res > 0 && i < h->nfds; i++) {
00336             if (h->fds[i].revents != 0) {
00337                 res--;
00338                 if (h->fds[i].revents & (POLLERR | POLLNVAL | POLLHUP)) {
00339                     if (h->fds[i].revents & (POLLIN))
00340                         r_dispatch_process_input(h, h->fds[i].fd);
00341                     else
00342                         r_io_shutdown_client_fd(h, h->fds[i].fd);
00343                     continue;
00344                 }
00345                 if (h->fds[i].revents & (POLLOUT))
00346                     r_link_do_deferred_write(h, h->fds[i].fd);
00347                 else if (h->fds[i].revents & (POLLIN))
00348                     r_dispatch_process_input(h, h->fds[i].fd);
00349                 else
00350                     ccnr_msg(h, "poll: UNHANDLED");
00351             }
00352         }
00353     }
00354 }

Generated on Thu Feb 16 00:43:58 2012 for Content-Centric Networking in C by  doxygen 1.5.6