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, offsetp);
00107             if (content != NULL)
00108                 r_store_commit_content(h, content);
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              fdholder->inbuf->length >= 6 &&
00230              0 == memcmp(fdholder->inbuf->buf, "GET ", 4))) {
00231             ccnr_stats_handle_http_connection(h, fdholder);
00232             return;
00233         }
00234         dres = ccn_skeleton_decode(d, buf, res);
00235         while (d->state == 0) {
00236             if (offsetp != NULL)
00237                 *offsetp = fdholder->bufoffset + msgstart;
00238             process_input_message(h, source,
00239                                   fdholder->inbuf->buf + msgstart,
00240                                   d->index - msgstart,
00241                                   (fdholder->flags & CCNR_FACE_LOCAL) != 0,
00242                                   offsetp);
00243             msgstart = d->index;
00244             if (msgstart == fdholder->inbuf->length) {
00245                 fdholder->inbuf->length = 0;
00246                 fdholder->bufoffset += msgstart;
00247                 return;
00248             }
00249             dres = ccn_skeleton_decode(d,
00250                     fdholder->inbuf->buf + msgstart,
00251                     fdholder->inbuf->length - msgstart);
00252         }
00253         fdholder->bufoffset += msgstart;
00254         if ((fdholder->flags & CCNR_FACE_DGRAM) != 0) {
00255             ccnr_msg(h, "protocol error on fdholder %u, discarding %u bytes",
00256                 source->filedesc,
00257                 (unsigned)(fdholder->inbuf->length - msgstart));
00258             fdholder->inbuf->length = 0;
00259             /* XXX - should probably ignore this source for a while */
00260             return;
00261         }
00262         else if (d->state < 0) {
00263             ccnr_msg(h, "protocol error on fdholder %u", source->filedesc);
00264             r_io_shutdown_client_fd(h, fd);
00265             return;
00266         }
00267         if (msgstart < fdholder->inbuf->length && msgstart > 0) {
00268             /* move partial message to start of buffer */
00269             memmove(fdholder->inbuf->buf, fdholder->inbuf->buf + msgstart,
00270                 fdholder->inbuf->length - msgstart);
00271             fdholder->inbuf->length -= msgstart;
00272             d->index -= msgstart;
00273         }
00274     }
00275 }
00276 
00277 PUBLIC void
00278 r_dispatch_process_internal_client_buffer(struct ccnr_handle *h)
00279 {
00280     struct fdholder *fdholder = h->face0;
00281     if (fdholder == NULL)
00282         return;
00283     fdholder->inbuf = ccn_grab_buffered_output(h->internal_client);
00284     if (fdholder->inbuf == NULL)
00285         return;
00286     ccnr_meter_bump(h, fdholder->meter[FM_BYTI], fdholder->inbuf->length);
00287     process_input_buffer(h, fdholder);
00288     ccn_charbuf_destroy(&(fdholder->inbuf));
00289 }
00290 /**
00291  * Run the main loop of the ccnr
00292  */
00293 PUBLIC void
00294 r_dispatch_run(struct ccnr_handle *h)
00295 {
00296     int i;
00297     int res;
00298     int timeout_ms = -1;
00299     int prev_timeout_ms = -1;
00300     int usec;
00301     int usec_direct;
00302     
00303     if (h->running < 0) {
00304         ccnr_msg(h, "Fatal error during initialization");
00305         return;
00306     }
00307     for (h->running = 1; h->running;) {
00308         r_dispatch_process_internal_client_buffer(h);
00309         usec = ccn_schedule_run(h->sched);
00310         usec_direct = ccn_process_scheduled_operations(h->direct_client);
00311         if (usec_direct < usec)
00312             usec = usec_direct;
00313         if (1) {
00314             /* If so requested, shut down when ccnd goes away. */
00315             if (ccn_get_connection_fd(h->direct_client) == -1) {
00316                 /* XXX - since we cannot reasonably recover, always go away. */
00317                 ccnr_msg(h, "lost connection to ccnd");
00318                 h->running = 0;
00319                 break;
00320             }
00321         }
00322         timeout_ms = (usec < 0) ? -1 : ((usec + 960) / 1000);
00323         if (timeout_ms == 0 && prev_timeout_ms == 0)
00324             timeout_ms = 1;
00325         r_dispatch_process_internal_client_buffer(h);
00326         r_store_trim(h, h->cob_limit);
00327         r_io_prepare_poll_fds(h);
00328         res = poll(h->fds, h->nfds, timeout_ms);
00329         prev_timeout_ms = ((res == 0) ? timeout_ms : 1);
00330         if (-1 == res) {
00331             if (errno == EINTR)
00332                 continue;
00333             ccnr_msg(h, "poll: %s (errno = %d)", strerror(errno), errno);
00334             sleep(1);
00335             continue;
00336         }
00337         for (i = 0; res > 0 && i < h->nfds; i++) {
00338             if (h->fds[i].revents != 0) {
00339                 res--;
00340                 if (h->fds[i].revents & (POLLERR | POLLNVAL | POLLHUP)) {
00341                     if (h->fds[i].revents & (POLLIN))
00342                         r_dispatch_process_input(h, h->fds[i].fd);
00343                     else
00344                         r_io_shutdown_client_fd(h, h->fds[i].fd);
00345                     continue;
00346                 }
00347                 if (h->fds[i].revents & (POLLOUT))
00348                     r_link_do_deferred_write(h, h->fds[i].fd);
00349                 else if (h->fds[i].revents & (POLLIN))
00350                     r_dispatch_process_input(h, h->fds[i].fd);
00351                 else
00352                     ccnr_msg(h, "poll: UNHANDLED");
00353             }
00354         }
00355     }
00356 }
Generated on Tue Aug 21 14:54:15 2012 for Content-Centric Networking in C by  doxygen 1.6.3