ccnr_io.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnr_io.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 "ccnr_private.h"
00056 
00057 #include "ccnr_io.h"
00058 
00059 #include "ccnr_forwarding.h"
00060 #include "ccnr_internal_client.h"
00061 #include "ccnr_link.h"
00062 #include "ccnr_msg.h"
00063 #include "ccnr_sendq.h"
00064 #include "ccnr_stats.h"
00065 
00066 /**
00067  * Looks up a fdholder based on its filedesc (private).
00068  */
00069 PUBLIC struct fdholder *
00070 r_io_fdholder_from_fd(struct ccnr_handle *h, unsigned filedesc)
00071 {
00072     unsigned slot = filedesc;
00073     struct fdholder *fdholder = NULL;
00074     if (slot < h->face_limit) {
00075         fdholder = h->fdholder_by_fd[slot];
00076         if (fdholder != NULL && fdholder->filedesc != filedesc)
00077             fdholder = NULL;
00078     }
00079     return(fdholder);
00080 }
00081 
00082 /**
00083  * Looks up a fdholder based on its filedesc.
00084  */
00085 PUBLIC struct fdholder *
00086 ccnr_r_io_fdholder_from_fd(struct ccnr_handle *h, unsigned filedesc)
00087 {
00088     return(r_io_fdholder_from_fd(h, filedesc));
00089 }
00090 
00091 /**
00092  * Assigns the filedesc for a nacent fdholder,
00093  * calls r_io_register_new_face() if successful.
00094  */
00095 PUBLIC int
00096 r_io_enroll_face(struct ccnr_handle *h, struct fdholder *fdholder)
00097 {
00098     unsigned i = fdholder->filedesc;
00099     unsigned n = h->face_limit;
00100     struct fdholder **a = h->fdholder_by_fd;
00101     if (i < n && a[i] == NULL) {
00102         if (a[i] == NULL)
00103             goto use_i;
00104         abort();
00105     }
00106     if (i > 65535)
00107         abort();
00108     a = realloc(a, (i + 1) * sizeof(struct fdholder *));
00109     if (a == NULL)
00110         return(-1); /* ENOMEM */
00111     h->face_limit = i + 1;
00112     while (n < h->face_limit)
00113         a[n++] = NULL;
00114     h->fdholder_by_fd = a;
00115 use_i:
00116     a[i] = fdholder;
00117     if (i == 0)
00118         h->face0 = fdholder; /* This one is special */
00119     fdholder->filedesc = i;
00120     fdholder->meter[FM_BYTI] = ccnr_meter_create(h, "bytein");
00121     fdholder->meter[FM_BYTO] = ccnr_meter_create(h, "byteout");
00122     fdholder->meter[FM_INTI] = ccnr_meter_create(h, "intrin");
00123     fdholder->meter[FM_INTO] = ccnr_meter_create(h, "introut");
00124     fdholder->meter[FM_DATI] = ccnr_meter_create(h, "datain");
00125     fdholder->meter[FM_DATO] = ccnr_meter_create(h, "dataout");
00126     r_io_register_new_face(h, fdholder);
00127     return (fdholder->filedesc);
00128 }
00129 
00130 /**
00131  * Close an open file descriptor quietly.
00132  */
00133 static void
00134 close_fd(int *pfd)
00135 {
00136     if (*pfd != -1) {
00137         close(*pfd);
00138         *pfd = -1;
00139     }
00140 }
00141 
00142 /**
00143  * Close an open file descriptor, and grumble about it.
00144  */
00145 /* unused */ void
00146 ccnr_close_fd(struct ccnr_handle *h, unsigned filedesc, int *pfd)
00147 {
00148     int res;
00149     
00150     if (*pfd != -1) {
00151         int linger = 0;
00152         setsockopt(*pfd, SOL_SOCKET, SO_LINGER,
00153                    &linger, sizeof(linger));
00154         res = close(*pfd);
00155         if (res == -1)
00156             ccnr_msg(h, "close failed for fdholder %u fd=%d: %s (errno=%d)",
00157                      filedesc, *pfd, strerror(errno), errno);
00158         else if (CCNSHOULDLOG(h, io, CCNL_FINE))
00159             ccnr_msg(h, "closing fd %d while finalizing fdholder %u", *pfd, filedesc);
00160         *pfd = -1;
00161     }
00162 }
00163 
00164 
00165 /**
00166  * Initialize the fdholder flags based upon the addr information
00167  * and the provided explicit setflags.
00168  */
00169 static void
00170 init_face_flags(struct ccnr_handle *h, struct fdholder *fdholder, int setflags)
00171 {
00172     const struct sockaddr *addr;
00173     
00174     if ((setflags & (CCNR_FACE_REPODATA)) != 0) {
00175         fdholder->flags |= setflags;
00176         return;
00177     }
00178     addr = (void *)fdholder->name->buf;
00179     if (addr->sa_family == AF_INET6) {
00180         const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
00181         fdholder->flags |= CCNR_FACE_INET6;
00182 #ifdef IN6_IS_ADDR_LOOPBACK
00183         if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr))
00184             fdholder->flags |= CCNR_FACE_LOOPBACK;
00185 #endif
00186     }
00187     else if (addr->sa_family == AF_INET) {
00188         const struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
00189         const unsigned char *rawaddr;
00190         rawaddr = (const unsigned char *)&addr4->sin_addr.s_addr;
00191         fdholder->flags |= CCNR_FACE_INET;
00192         if (rawaddr[0] == 127)
00193             fdholder->flags |= CCNR_FACE_LOOPBACK;
00194         else {
00195             /* If our side and the peer have the same address, consider it loopback */
00196             /* This is the situation inside of FreeBSD jail. */
00197             struct sockaddr_in myaddr;
00198             socklen_t myaddrlen = sizeof(myaddr);
00199             if (0 == getsockname(fdholder->filedesc, (struct sockaddr *)&myaddr, &myaddrlen)) {
00200                 if (addr4->sin_addr.s_addr == myaddr.sin_addr.s_addr)
00201                     fdholder->flags |= CCNR_FACE_LOOPBACK;
00202             }
00203         }
00204     }
00205     else if (addr->sa_family == AF_UNIX)
00206         fdholder->flags |= (CCNR_FACE_GG | CCNR_FACE_LOCAL);
00207     fdholder->flags |= setflags;
00208 }
00209 
00210 /**
00211  * Make a new fdholder corresponding to the fd
00212  */
00213 PUBLIC struct fdholder *
00214 r_io_record_fd(struct ccnr_handle *h, int fd,
00215                   void *who, socklen_t wholen,
00216                   int setflags)
00217 {
00218     int res;
00219     struct fdholder *fdholder = NULL;
00220     
00221     res = fcntl(fd, F_SETFL, O_NONBLOCK);
00222     if (res == -1)
00223         ccnr_msg(h, "fcntl: %s", strerror(errno));
00224     fdholder = calloc(1, sizeof(*fdholder));
00225     
00226     
00227     if (fdholder == NULL)
00228         return(fdholder);
00229     fdholder->name = ccn_charbuf_create();
00230     if (fdholder->name == NULL)
00231         abort();
00232     if (who != NULL)
00233         ccn_charbuf_append(fdholder->name, who, wholen);
00234     fdholder->filedesc = fd;
00235     init_face_flags(h, fdholder, setflags);
00236     res = r_io_enroll_face(h, fdholder);
00237     if (res == -1) {
00238         ccn_charbuf_destroy(&fdholder->name);
00239         free(fdholder);
00240         fdholder = NULL;
00241     }
00242     return(fdholder);
00243 }
00244 
00245 /**
00246  * Accept an incoming DGRAM_STREAM connection, creating a new fdholder.
00247  * @returns fd of new socket, or -1 for an error.
00248  */
00249 PUBLIC int
00250 r_io_accept_connection(struct ccnr_handle *h, int listener_fd)
00251 {
00252     struct sockaddr_storage who;
00253     socklen_t wholen = sizeof(who);
00254     int fd;
00255     struct fdholder *fdholder;
00256 
00257     fd = accept(listener_fd, (struct sockaddr *)&who, &wholen);
00258     if (fd == -1) {
00259         ccnr_msg(h, "accept: %s", strerror(errno));
00260         return(-1);
00261     }
00262     fdholder = r_io_record_fd(h, fd,
00263                             (struct sockaddr *)&who, wholen,
00264                             CCNR_FACE_UNDECIDED);
00265     if (fdholder == NULL)
00266         close_fd(&fd);
00267     else if (CCNSHOULDLOG(h, io, CCNL_INFO))
00268         ccnr_msg(h, "accepted client fd=%d id=%u", fd, fdholder->filedesc);
00269     return(fd);
00270 }
00271 
00272 PUBLIC int
00273 r_io_open_repo_data_file(struct ccnr_handle *h, const char *name, int output)
00274 {
00275     struct ccn_charbuf *temp = NULL;
00276     int fd = -1;
00277     struct fdholder *fdholder = NULL;
00278 
00279     temp = ccn_charbuf_create();
00280     ccn_charbuf_putf(temp, "%s/%s", h->directory, name);
00281     fd = open(ccn_charbuf_as_string(temp), output ? (O_CREAT | O_WRONLY | O_APPEND) : O_RDONLY, 0666);
00282     if (fd == -1) {
00283         if (CCNSHOULDLOG(h, sdf, CCNL_FINE))
00284             ccnr_msg(h, "open(%s): %s", ccn_charbuf_as_string(temp), strerror(errno));
00285         ccn_charbuf_destroy(&temp);
00286         return(-1);
00287     }
00288     fdholder = r_io_record_fd(h, fd,
00289                             temp->buf, temp->length,
00290                             CCNR_FACE_REPODATA | (output ? CCNR_FACE_NORECV : CCNR_FACE_NOSEND));
00291     if (fdholder == NULL)
00292         close_fd(&fd);
00293     else {
00294         if (!output) {
00295             /* Use a larger buffer for indexing an existing repo file */
00296             if (fdholder->inbuf == NULL) {
00297                 fdholder->inbuf = ccn_charbuf_create();
00298                 fdholder->bufoffset = 0;
00299             }
00300             if (fdholder->inbuf != NULL)
00301                 ccn_charbuf_reserve(fdholder->inbuf, 256 * 1024);
00302         }
00303         if (CCNSHOULDLOG(h, sdf, CCNL_INFO))
00304             ccnr_msg(h, "opened fd=%d file=%s", fd, ccn_charbuf_as_string(temp));
00305     }
00306     ccn_charbuf_destroy(&temp);
00307     return(fd);
00308 }
00309 
00310 
00311 PUBLIC int
00312 r_io_repo_data_file_fd(struct ccnr_handle *h, unsigned repofile, int output)
00313 {
00314     if (repofile != 1)
00315         return(-1);
00316     if (output)
00317         return(-1);
00318     if (h->repofile1_fd > 0)
00319         return(h->repofile1_fd);
00320     h->repofile1_fd = r_io_open_repo_data_file(h, "repoFile1", 0);
00321     return(h->repofile1_fd);
00322 }
00323 
00324 PUBLIC void
00325 r_io_shutdown_client_fd(struct ccnr_handle *h, int fd)
00326 {
00327     struct fdholder *fdholder = NULL;
00328     enum cq_delay_class c;
00329     int m;
00330     int res;
00331     
00332     fdholder = r_io_fdholder_from_fd(h, fd);
00333     if (fdholder == NULL) {
00334         ccnr_msg(h, "no fd holder for fd %d", fd);
00335         return;
00336     }
00337     if (fdholder == h->face0)
00338         (res = 0, h->face0 = NULL);
00339     else if ((fdholder->flags & CCNR_FACE_CCND))
00340         res = ccn_disconnect(h->direct_client);
00341     else
00342         res = close(fd);
00343     if (CCNSHOULDLOG(h, sdfdf, CCNL_INFO))
00344         ccnr_msg(h, "shutdown client fd=%d", fd);
00345     ccn_charbuf_destroy(&fdholder->inbuf);
00346     ccn_charbuf_destroy(&fdholder->outbuf);
00347     for (c = 0; c < CCN_CQ_N; c++)
00348         r_sendq_content_queue_destroy(h, &(fdholder->q[c]));
00349     for (m = 0; m < CCNR_FACE_METER_N; m++)
00350         ccnr_meter_destroy(&fdholder->meter[m]);
00351     if (h->fdholder_by_fd[fd] != fdholder) abort();
00352     h->fdholder_by_fd[fd] = NULL;
00353     ccn_charbuf_destroy(&fdholder->name);
00354     free(fdholder);
00355     if (h->active_in_fd == fd)
00356         h->active_in_fd = -1;
00357     if (h->active_out_fd == fd)
00358         h->active_out_fd = -1;
00359     if (h->repofile1_fd == fd)
00360         h->repofile1_fd = -1;
00361     // r_fwd_reap_needed(h, 250000);
00362 }
00363 
00364 /**
00365  * Destroys the fdholder identified by filedesc.
00366  * @returns 0 for success, -1 for failure.
00367  */
00368 PUBLIC int
00369 r_io_destroy_face(struct ccnr_handle *h, unsigned filedesc)
00370 {
00371     r_io_shutdown_client_fd(h, filedesc);
00372     return(0);
00373 }
00374 
00375 /**
00376  * Called when a fdholder is first created, and (perhaps) a second time in the case
00377  * that a fdholder transitions from the undecided state.
00378  */
00379 PUBLIC void
00380 r_io_register_new_face(struct ccnr_handle *h, struct fdholder *fdholder)
00381 {
00382     if (fdholder->filedesc != 0 && (fdholder->flags & (CCNR_FACE_UNDECIDED | CCNR_FACE_PASSIVE)) == 0) {
00383         ccnr_face_status_change(h, fdholder->filedesc);
00384     }
00385 }
00386 
00387 /**
00388  * Handle errors after send() or sendto().
00389  * @returns -1 if error has been dealt with, or 0 to defer sending.
00390  */
00391 static int
00392 handle_send_error(struct ccnr_handle *h, int errnum, struct fdholder *fdholder,
00393                   const void *data, size_t size)
00394 {
00395     int res = -1;
00396     if (errnum == EAGAIN) {
00397         res = 0;
00398     }
00399     else if (errnum == EPIPE) {
00400         fdholder->flags |= CCNR_FACE_NOSEND;
00401         fdholder->outbufindex = 0;
00402         ccn_charbuf_destroy(&fdholder->outbuf);
00403     }
00404     else {
00405         ccnr_msg(h, "send to fd %u failed: %s (errno = %d)",
00406                  fdholder->filedesc, strerror(errnum), errnum);
00407         if (errnum == EISCONN)
00408             res = 0;
00409     }
00410     return(res);
00411 }
00412 
00413 static int
00414 sending_fd(struct ccnr_handle *h, struct fdholder *fdholder)
00415 {
00416     return(fdholder->filedesc);
00417 }
00418 
00419 /**
00420  * Send data to the fdholder.
00421  *
00422  * No direct error result is provided; the fdholder state is updated as needed.
00423  */
00424 PUBLIC void
00425 r_io_send(struct ccnr_handle *h,
00426           struct fdholder *fdholder,
00427           const void *data, size_t size,
00428           off_t *offsetp)
00429 {
00430     ssize_t res;
00431     off_t offset;
00432     
00433     if (offsetp != NULL)
00434         *offsetp = (off_t)-1;
00435     if ((fdholder->flags & CCNR_FACE_NOSEND) != 0)
00436         return;
00437     if (fdholder->outbuf != NULL) {
00438         ccn_charbuf_append(fdholder->outbuf, data, size);
00439         return;
00440     }
00441     if (fdholder == h->face0) {
00442         ccnr_meter_bump(h, fdholder->meter[FM_BYTO], size);
00443         ccn_dispatch_message(h->internal_client, (void *)data, size);
00444         r_dispatch_process_internal_client_buffer(h);
00445         return;
00446     }
00447     if ((fdholder->flags & CCNR_FACE_CCND) != 0) {
00448         /* Writes here need to go via the direct client's handle. */
00449         ccnr_meter_bump(h, fdholder->meter[FM_BYTO], size);
00450         res = ccn_put(h->direct_client, data, size);
00451         if (res < 0 && CCNSHOULDLOG(h, r_io_send, CCNL_WARNING))
00452             ccnr_msg(h, "ccn_put failed");
00453         if (res == 1 && CCNSHOULDLOG(h, r_io_send, CCNL_FINEST))
00454             ccnr_msg(h, "ccn_put deferred output for later send");
00455         return;
00456     }
00457     if ((fdholder->flags & CCNR_FACE_REPODATA) != 0) {
00458         offset = lseek(fdholder->filedesc, 0, SEEK_END);
00459         if (offset == (off_t)-1) {
00460             ccnr_msg(h, "lseek(%d): %s", fdholder->filedesc, strerror(errno));
00461             return;
00462         }
00463         if (offsetp != NULL)
00464             *offsetp = offset;
00465         if (fdholder->filedesc == h->active_out_fd) {
00466             if (offset != h->stable && h->stable != 0)
00467                 ccnr_msg(h, "expected file size %ju, found %ju",
00468                     (uintmax_t)h->stable,
00469                     (uintmax_t)offset);
00470             h->stable = offset + size;
00471         }
00472     }
00473     if ((fdholder->flags & CCNR_FACE_DGRAM) == 0)
00474         res = write(fdholder->filedesc, data, size);
00475     else
00476         res = sendto(sending_fd(h, fdholder), data, size, 0,
00477                      (struct sockaddr *)fdholder->name->buf,
00478                      fdholder->name->length);
00479     if (res > 0)
00480         ccnr_meter_bump(h, fdholder->meter[FM_BYTO], res);
00481     if (res == size)
00482         return;
00483     if (res == -1) {
00484         res = handle_send_error(h, errno, fdholder, data, size);
00485         if (res == -1)
00486             return;
00487     }
00488     if ((fdholder->flags & CCNR_FACE_DGRAM) != 0) {
00489         ccnr_msg(h, "sendto short");
00490         return;
00491     }
00492     fdholder->outbufindex = 0;
00493     fdholder->outbuf = ccn_charbuf_create();
00494     if (fdholder->outbuf == NULL) {
00495         ccnr_msg(h, "do_write: %s", strerror(errno));
00496         return;
00497     }
00498     ccn_charbuf_append(fdholder->outbuf,
00499                        ((const unsigned char *)data) + res, size - res);
00500 }
00501 /**
00502  * Set up the array of fd descriptors for the poll(2) call.
00503  *
00504  */
00505 PUBLIC void
00506 r_io_prepare_poll_fds(struct ccnr_handle *h)
00507 {
00508     int i, j, nfds;
00509     
00510     for (i = 1, nfds = 0; i < h->face_limit; i++)
00511         if (r_io_fdholder_from_fd(h, i) != NULL)
00512             nfds++;
00513     
00514     if (nfds != h->nfds) {
00515         h->nfds = nfds;
00516         h->fds = realloc(h->fds, h->nfds * sizeof(h->fds[0]));
00517         memset(h->fds, 0, h->nfds * sizeof(h->fds[0]));
00518     }
00519     for (i = 1, j = 0; i < h->face_limit; i++) {
00520         struct fdholder *fdholder = r_io_fdholder_from_fd(h, i);
00521         if (fdholder != NULL) {
00522             h->fds[j].fd = fdholder->filedesc;
00523             h->fds[j].events = 0;
00524             if ((fdholder->flags & (CCNR_FACE_NORECV|CCNR_FACE_REPODATA)) == 0)
00525                 h->fds[j].events |= POLLIN;
00526             if (fdholder->filedesc == h->active_in_fd)
00527                 h->fds[j].events |= POLLIN;
00528             if ((fdholder->outbuf != NULL || (fdholder->flags & CCNR_FACE_CLOSING) != 0))
00529                 h->fds[j].events |= POLLOUT;
00530              if ((fdholder->flags & CCNR_FACE_CCND) != 0) {
00531                  if (ccn_output_is_pending(h->direct_client)) {
00532                      if (CCNSHOULDLOG(h, xxx, CCNL_FINEST))
00533                         ccnr_msg(h, "including direct client in poll set");
00534                      h->fds[j].events |= POLLOUT;
00535                 }
00536              }
00537             j++;
00538         }
00539     }
00540 }
00541 
00542 /**
00543  * Shutdown all open fds.
00544  */
00545 PUBLIC void
00546 r_io_shutdown_all(struct ccnr_handle *h)
00547 {
00548     int i;
00549     for (i = 1; i < h->face_limit; i++) {
00550         if (r_io_fdholder_from_fd(h, i) != NULL)
00551             r_io_shutdown_client_fd(h, i);
00552     }
00553     ccnr_internal_client_stop(h);
00554     r_io_shutdown_client_fd(h, 0);
00555 }

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