udplink.c

Go to the documentation of this file.
00001 /**
00002  * @file udplink.c
00003  * @brief A CCNx link adaptor for UDP.
00004  *
00005  * @note Normally ccnd handles UDP directly, so this module is not used.
00006  *
00007  * A CCNx program.
00008  *
00009  * Copyright (C) 2008, 2009 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 #include <stdio.h>
00023 #include <unistd.h>
00024 #include <stdlib.h>
00025 #include <stdarg.h>
00026 #include <errno.h>
00027 #include <poll.h>
00028 #include <string.h>
00029 #include <signal.h>
00030 #include <sys/types.h>
00031 #include <sys/time.h>
00032 #include <sys/socket.h>
00033 #include <netinet/in.h>
00034 #include <arpa/inet.h>
00035 #include <net/if.h>
00036 #include <netdb.h>
00037 
00038 #if defined(NEED_GETADDRINFO_COMPAT)
00039     #include "getaddrinfo.h"
00040     #include "dummyin6.h"
00041 #endif
00042 #ifndef AI_ADDRCONFIG
00043 #define AI_ADDRCONFIG 0 /*IEEE Std 1003.1-2001/Cor 1-2002, item XSH/TC1/D6/20*/
00044 #endif
00045 
00046 #include <ccn/ccn.h>
00047 #include <ccn/ccnd.h>
00048 
00049 void udplink_fatal(int line, char *format, ...);
00050 
00051 #define UDPMAXBUF 8800
00052 
00053 #ifdef __CYGWIN__
00054 /* if_nametoindex() is unsupported on cygwin */
00055 unsigned if_nametoindex(const char *ifname) { 
00056     udplink_fatal(__LINE__, "interface name unsupported on cygwin");
00057     return 0; 
00058 }
00059 #endif
00060 
00061 static struct options {
00062     const char *localsockname;
00063     const char *remotehostname;
00064     struct addrinfo *localif_for_mcast_addrinfo;
00065     char remoteport[8];
00066     char localport[8];
00067     unsigned int remoteifindex;
00068     int multicastttl;
00069     int logging;
00070 } options = {NULL, NULL, NULL, "", "", 0, 0, 0};
00071 
00072 /*
00073  * logging levels:
00074  *  0 - print very little
00075  *  1 - informational and sparse warnings
00076  *  2 - one line per packet
00077  *  3 - packet dumps
00078  */
00079 
00080 void
00081 usage(char *name) {
00082     fprintf(stderr, "Usage: %s [-d(ebug)] [-c ccnsocket] -h remotehost -r remoteport [-l localport] [-m multicastlocaladdress] [-t multicastttl]\n", name);
00083 }
00084 
00085 void
00086 udplink_fatal(int line, char *format, ...)
00087 {
00088     struct timeval t;
00089     va_list ap;
00090     va_start(ap, format);
00091     gettimeofday(&t, NULL);
00092     fprintf(stderr, "%d.%06d udplink[%d] line %d: ", (int)t.tv_sec, (unsigned)t.tv_usec, getpid(), line);
00093     vfprintf(stderr, format, ap);
00094     va_end(ap);
00095     exit(1);
00096 }
00097 
00098 void
00099 udplink_note(char *format, ...)
00100 {
00101     struct timeval t;
00102     va_list ap;
00103     va_start(ap, format);
00104     gettimeofday(&t, NULL);
00105     fprintf(stderr, "%d.%06d udplink[%d]: ", (int)t.tv_sec, (unsigned)t.tv_usec, getpid());
00106     vfprintf(stderr, format, ap);
00107     va_end(ap);
00108 }
00109 
00110 void
00111 udplink_print_data(char *source, unsigned char *data, int start, int length, int logging)
00112 {
00113     int i;
00114     
00115     udplink_note("%d bytes from %s", length, source);
00116     if (logging > 2) {
00117         fprintf(stderr, ":");
00118         for (i = 0; i < length; i++) {
00119             if ((i % 20) == 0) fprintf(stderr, "\n%4d: ", i);
00120             if (((i + 10) % 20) == 0) fprintf(stderr, "| ");
00121             fprintf(stderr, "%02x ", data[i + start]);
00122         }
00123     }
00124     fprintf(stderr, "\n");
00125 }
00126 
00127 ssize_t
00128 send_remote_unencapsulated(int s, struct addrinfo *r, unsigned char *buf, size_t start, size_t length) {
00129     ssize_t result;
00130 
00131     if (memcmp(&buf[start], CCN_EMPTY_PDU, CCN_EMPTY_PDU_LENGTH - 1) != 0) {
00132         return (-2);
00133     }
00134     result = sendto(s, buf + CCN_EMPTY_PDU_LENGTH - 1 + start, length - CCN_EMPTY_PDU_LENGTH,
00135                     0, r->ai_addr, r->ai_addrlen);
00136     return (result);
00137 }
00138 
00139 void process_options(int argc, char * const argv[], struct options *opt) {
00140     int c;
00141     char *cp = NULL;
00142     char *rportstr = NULL;
00143     char *lportstr = NULL;
00144     char *mcastoutstr = NULL;
00145     char *ttlstr = NULL;
00146     struct addrinfo hints = {0};
00147     int result;
00148     int n;
00149 
00150     while ((c = getopt(argc, argv, "dc:h:r:l:m:t:")) != -1) {
00151         switch (c) {
00152         case 'd':
00153             opt->logging++;
00154             break;
00155         case 'c':
00156             opt->localsockname = optarg;
00157             break;
00158         case 'h':
00159             opt->remotehostname = optarg;
00160             break;
00161         case 'r':
00162             rportstr = optarg;
00163             break;
00164         case 'l':
00165             lportstr = optarg;
00166             break;
00167         case 'm':
00168             mcastoutstr = optarg;
00169             break;
00170         case 't':
00171             ttlstr = optarg;
00172             break;
00173         }
00174     }
00175     
00176     /* the remote end of the connection must be specified */
00177     if (opt->remotehostname == NULL || rportstr == NULL) {
00178         usage(argv[0]);
00179         exit(1);
00180     }
00181 
00182     if (strspn(rportstr, "0123456789") != strlen(rportstr)) {
00183         usage(argv[0]);
00184         exit(1);
00185     }
00186     
00187     n = atoi(rportstr);
00188     if (n <= 0 || n >= 65536) {
00189         usage(argv[0]);
00190         exit(1);
00191     }
00192     sprintf(opt->remoteport, "%d", n);
00193 
00194     if (lportstr != NULL) {
00195         if (strspn(lportstr, "0123456789") != strlen(lportstr)) {
00196             usage(argv[0]);
00197             exit(1);
00198         }
00199         n = atoi(lportstr);
00200         if (n <= 0 || n >= 65536) {
00201             usage(argv[0]);
00202             exit(1);
00203         }
00204     }
00205     sprintf(opt->localport, "%d", n);
00206 
00207     if (mcastoutstr != NULL) {
00208         hints.ai_family = PF_INET;
00209         hints.ai_socktype = SOCK_DGRAM;
00210         hints.ai_flags =  AI_NUMERICHOST;
00211 #ifdef AI_NUMERICSERV
00212         hints.ai_flags |= AI_NUMERICSERV;
00213 #endif
00214         udplink_note("interface %s requested (port %s)\n", mcastoutstr, opt->localport);
00215         result = getaddrinfo(mcastoutstr, opt->localport, &hints, &opt->localif_for_mcast_addrinfo);
00216         if (result != 0 || opt->localif_for_mcast_addrinfo == NULL) {
00217             udplink_fatal(__LINE__, "getaddrinfo(\"%s\", ...): %s\n", mcastoutstr, gai_strerror(result));
00218         }
00219     }
00220 
00221     if (ttlstr != NULL) {
00222         if (strspn(ttlstr, "0123456789") != strlen(ttlstr)) {
00223             usage(argv[0]);
00224             exit(1);
00225         }
00226         opt->multicastttl = atoi(ttlstr);
00227         if (opt->multicastttl < 1 || opt->multicastttl > 255) {
00228             usage(argv[0]);
00229             exit(1);
00230         }
00231     }
00232 
00233     cp = strchr(opt->remotehostname, '%');
00234     if (cp != NULL) {
00235         cp++;
00236         errno = 0;
00237         opt->remoteifindex = atoi(cp);
00238         if (opt->remoteifindex == 0) {
00239             opt->remoteifindex = if_nametoindex(cp);
00240             if (opt->remoteifindex == 0 && errno != 0) {
00241                 udplink_fatal(__LINE__, "Invalid interface name %s\n", cp);
00242             }
00243         }
00244     }
00245 }
00246 
00247 void
00248 set_multicast_sockopt(int socket_r, int socket_w, struct addrinfo *ai, struct options *opt)
00249 {
00250     struct addrinfo hints;
00251     struct ip_mreq mreq;
00252 #ifdef IPV6_JOIN_GROUP
00253     struct ipv6_mreq mreq6;
00254 #endif
00255     unsigned char csockopt;
00256     unsigned int isockopt;
00257     int result;
00258 
00259     memset((void *)&hints, 0, sizeof(hints));
00260     memset((void *)&mreq, 0, sizeof(mreq));
00261 #ifdef IPV6_JOIN_GROUP
00262     memset((void *)&mreq6, 0, sizeof(mreq6));
00263 #endif
00264 
00265     if (ai->ai_family == PF_INET && IN_MULTICAST(ntohl(((struct sockaddr_in *)(ai->ai_addr))->sin_addr.s_addr))) {
00266         if (opt->logging > 0) udplink_note("IPv4 multicast\n");
00267 #ifdef IP_ADD_MEMBERSHIP
00268         memcpy((void *)&mreq.imr_multiaddr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, sizeof(mreq.imr_multiaddr));
00269         if (opt->localif_for_mcast_addrinfo != NULL) {
00270             memcpy((void *)&mreq.imr_interface.s_addr, &((struct sockaddr_in *)opt->localif_for_mcast_addrinfo->ai_addr)->sin_addr, sizeof(mreq.imr_interface.s_addr));
00271         }
00272         result = setsockopt(socket_r, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
00273         if (result == -1) udplink_fatal(__LINE__, "setsockopt(..., IP_ADD_MEMBERSHIP, ...): %s\n", strerror(errno));
00274 #endif
00275 #ifdef IP_MULTICAST_LOOP
00276         csockopt = 0;
00277         result = setsockopt(socket_w, IPPROTO_IP, IP_MULTICAST_LOOP, &csockopt, sizeof(csockopt));
00278         if (result == -1) udplink_fatal(__LINE__, "setsockopt(..., IP_MULTICAST_LOOP, ...): %s\n", strerror(errno));
00279 #endif
00280 #ifdef IP_MULTICAST_TTL
00281         if (opt->multicastttl > 0) {
00282             csockopt = opt->multicastttl;
00283             result = setsockopt(socket_w, IPPROTO_IP, IP_MULTICAST_TTL, &csockopt, sizeof(csockopt));
00284             if (result == -1) {
00285                 udplink_fatal(__LINE__, "setsockopt(..., IP_MULTICAST_TTL, ...): %s\n", strerror(errno));
00286             }
00287         }
00288 #endif
00289     } else if (ai->ai_family == PF_INET6 && IN6_IS_ADDR_MULTICAST((&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr))) {
00290         if (opt->logging > 0) udplink_note("IPv6 multicast\n");
00291 #ifdef IPV6_JOIN_GROUP
00292         memcpy((void *)&mreq6.ipv6mr_multiaddr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, sizeof(mreq6.ipv6mr_multiaddr));
00293         if (opt->remoteifindex > 0) {
00294             mreq6.ipv6mr_interface = opt->remoteifindex;
00295         }
00296         result = setsockopt(socket_r, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6));
00297         if (result == -1) {
00298             udplink_fatal(__LINE__, "setsockopt(..., IPV6_JOIN_GROUP, ...): %s\n", strerror(errno));
00299         }
00300 #endif
00301 #ifdef IPV6_MULTICAST_LOOP
00302         isockopt = 0;
00303         result = setsockopt(socket_w, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &isockopt, sizeof(isockopt));
00304         if (result == -1) {
00305             udplink_fatal(__LINE__, "setsockopt(..., IPV6_MULTICAST_LOOP, ...): %s\n", strerror(errno));
00306         }
00307 #endif
00308 #ifdef IPV6_MULTICAST_HOPS
00309         if (opt->multicastttl > 0) {
00310             isockopt = opt->multicastttl;
00311             result = setsockopt(socket_w, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &isockopt, sizeof(isockopt));
00312             if (result == -1) {
00313                 udplink_fatal(__LINE__, "setsockopt(..., IPV6_MULTICAST_LOOP, ...): %s\n", strerror(errno));
00314             }
00315         }
00316 #endif
00317     }
00318 }
00319 
00320 void
00321 changeloglevel(int s) {
00322     switch (s) {
00323     case SIGUSR1:
00324         options.logging = 0;
00325         udplink_note("logging disabled\n");
00326         break;
00327     case SIGUSR2:
00328         if (options.logging < 10) options.logging++;
00329         udplink_note("log level %d\n", options.logging);
00330         break;
00331     }
00332     return;
00333 }
00334 
00335 int
00336 main (int argc, char * const argv[]) {
00337     int result;
00338     int localsock_rw = 0;
00339     int remotesock_w = 0;
00340     int remotesock_r = 0;
00341     char canonical_remote[NI_MAXHOST] = "";
00342     struct addrinfo *raddrinfo = NULL;
00343     struct addrinfo *laddrinfo = NULL;
00344     struct addrinfo hints = {0};
00345     struct pollfd fds[2];
00346     struct ccn *ccn;
00347     struct ccn_skeleton_decoder ldecoder = {0};
00348     struct ccn_skeleton_decoder *ld = &ldecoder;
00349     struct ccn_skeleton_decoder rdecoder = {0};
00350     struct ccn_skeleton_decoder *rd = &rdecoder;
00351     unsigned char rbuf[UDPMAXBUF];
00352     struct ccn_charbuf *charbuf;
00353     ssize_t msgstart = 0;
00354     ssize_t dres;
00355     struct sigaction sigact_changeloglevel;
00356     unsigned char *deferredbuf = NULL;
00357     size_t deferredlen = 0;
00358     int dropped_count = 0;
00359     size_t dropped_bytes = 0;
00360     const int one = 1;
00361 
00362     process_options(argc, argv, &options);
00363 
00364     /* connect up signals for log level controls */
00365     memset(&sigact_changeloglevel, 0, sizeof(sigact_changeloglevel));
00366     sigact_changeloglevel.sa_handler = changeloglevel;
00367     sigaction(SIGUSR1, &sigact_changeloglevel, NULL);
00368     sigaction(SIGUSR2, &sigact_changeloglevel, NULL);
00369 
00370     /* connect to the local ccn socket */
00371     ccn = ccn_create();
00372     localsock_rw = ccn_connect(ccn, options.localsockname);
00373     if (localsock_rw == -1) {
00374         udplink_fatal(__LINE__, "ccn_connect: %s\n", strerror(errno));
00375     }
00376 
00377     hints.ai_family = AF_UNSPEC;
00378     hints.ai_socktype = SOCK_DGRAM;
00379     hints.ai_flags = AI_ADDRCONFIG;
00380 #ifdef AI_NUMERICSERV
00381     hints.ai_flags |= AI_NUMERICSERV;
00382 #endif
00383 
00384     /* data we need for later */
00385     result = getaddrinfo(options.remotehostname, options.remoteport, &hints, &raddrinfo);
00386     if (result != 0 || raddrinfo == NULL) {
00387         udplink_fatal(__LINE__, "getaddrinfo(\"%s\", \"%s\", ...): %s\n", options.remotehostname, options.remoteport, gai_strerror(result));
00388     }
00389 
00390     getnameinfo(raddrinfo->ai_addr, raddrinfo->ai_addrlen, canonical_remote, sizeof(canonical_remote), NULL, 0, 0);
00391 
00392 
00393     hints.ai_family = raddrinfo->ai_family;
00394     hints.ai_flags = AI_PASSIVE;
00395 #ifdef AI_NUMERICSERV
00396     hints.ai_flags |= AI_NUMERICSERV;
00397 #endif
00398 
00399     result = getaddrinfo(NULL, options.localport, &hints, &laddrinfo);
00400     if (result != 0 || laddrinfo == NULL) {
00401         udplink_fatal(__LINE__, "getaddrinfo(NULL, %s, ...): %s\n", options.localport, gai_strerror(result));
00402     }
00403 
00404     /* set up the remote side */
00405 
00406     /* Linux systems work if you do things in this order:
00407      *
00408      * socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4      WRITER
00409      * socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 5      READER
00410      * setsockopt(5, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0   READER
00411      * bind(5, {sa_family=AF_INET, sin_port=htons(19649), sin_addr=inet_addr("224.18.14.21")}, 16) = 0    READER
00412      * setsockopt(4, SOL_IP, IP_MULTICAST_TTL, [5], 4) = 0      WRITER
00413      * setsockopt(5, SOL_IP, IP_ADD_MEMBERSHIP, "\340\22\16\25\r\2t[", 8) = 0    READER
00414      * fcntl64(5, F_SETFD, 0x802) = 0
00415      * bind(4, {sa_family=AF_INET, sin_port=htons(19649), sin_addr=inet_addr("13.2.116.91")}, 16) = 0   WRITER
00416      */
00417 
00418     remotesock_w = socket(raddrinfo->ai_family, raddrinfo->ai_socktype, 0);
00419     if (remotesock_w == -1) {
00420         udplink_fatal(__LINE__, "socket: %s\n", strerror(errno));
00421     }
00422     remotesock_r = remotesock_w;
00423 
00424     if (options.localif_for_mcast_addrinfo != NULL) {
00425         /* We have a specific interface to bind to.  localif_for_mcast_addrinfo
00426            is actually the unicast ipv4 address of this interface. */
00427 
00428         remotesock_r = socket(raddrinfo->ai_family, raddrinfo->ai_socktype, 0);
00429         if (remotesock_r == -1) {
00430             udplink_fatal(__LINE__, "socket: %s\n", strerror(errno));
00431         }
00432         result = setsockopt(remotesock_r, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
00433         if (result == -1) udplink_fatal(__LINE__, "setsockopt(remotesock_r, ..., SO_REUSEADDR, ...)");
00434 
00435         /* bind the listener to the multicast address */
00436         result = bind(remotesock_r, raddrinfo->ai_addr, raddrinfo->ai_addrlen);
00437         if (result == -1) {
00438             udplink_fatal(__LINE__, "bind(remotesock_r, local...): %s\n", strerror(errno));
00439         }
00440     }
00441 
00442     set_multicast_sockopt(remotesock_r, remotesock_w, raddrinfo, &options);
00443 
00444     if (options.localif_for_mcast_addrinfo != NULL) {
00445         result = bind(remotesock_w, options.localif_for_mcast_addrinfo->ai_addr, options.localif_for_mcast_addrinfo->ai_addrlen);
00446     } else {
00447         result = bind(remotesock_w, laddrinfo->ai_addr, laddrinfo->ai_addrlen);
00448     }
00449     if (result == -1) {
00450         udplink_fatal(__LINE__, "bind(remotesock_w, local...): %s\n", strerror(errno));
00451     }
00452 
00453     udplink_note("connected to %s:%s\n", canonical_remote, options.remoteport);
00454 
00455 
00456     /* announce our presence to ccnd and request CCNx PDU encapsulation */
00457     result = send(localsock_rw, CCN_EMPTY_PDU, CCN_EMPTY_PDU_LENGTH, 0);
00458     if (result == -1) {
00459         udplink_fatal(__LINE__, "initial send: %s\n", strerror(errno));
00460     }
00461 
00462     charbuf = ccn_charbuf_create();
00463 
00464     fds[0].fd = localsock_rw;
00465     fds[0].events = POLLIN;
00466     fds[1].fd = remotesock_r;
00467     fds[1].events = POLLIN;
00468 
00469     for (;;) {
00470         if (0 == (result = poll(fds, 2, -1))) continue;
00471         if (-1 == result) {
00472             if (errno == EINTR) continue;
00473             udplink_fatal(__LINE__, "poll: %s\n", strerror(errno));
00474         }
00475         /* process deferred send to local */
00476         if (fds[0].revents & (POLLOUT)) {
00477             fds[1].events |= POLLIN;
00478             fds[0].events &= ~POLLOUT;
00479             if (deferredlen > 0) {
00480                 result = send(localsock_rw, deferredbuf, deferredlen, 0);
00481                 if (result == -1 && (options.logging > 1 || errno != EAGAIN))
00482                     udplink_note("sendto(local, deferredbuf, %ld):"
00483                                  " %s (sending deferred)\n",
00484                                  (long) deferredlen, strerror(errno));
00485                 if (result == deferredlen) {
00486                     /* success, but report drops at this point */
00487                     if (dropped_count != 0 && options.logging > 0) {
00488                         udplink_note("dropped %d from remote (%ld bytes)\n",
00489                                      dropped_count, (long)dropped_bytes);
00490                         dropped_count = 0;
00491                         dropped_bytes = 0;
00492                     }
00493                     deferredlen = 0;
00494                 }
00495                 else if (result > 0) {
00496                     memmove(deferredbuf,
00497                             deferredbuf + result,
00498                             deferredlen - result);
00499                     deferredlen -= result;
00500                     fds[0].events |= POLLOUT;
00501                 }
00502                 else
00503                     deferredlen = 0;
00504             }
00505         }
00506 
00507         /* process local data */
00508         if (fds[0].revents & (POLLIN)) {
00509             unsigned char *lbuf = ccn_charbuf_reserve(charbuf, 32);
00510             ssize_t recvlen;
00511             int tries;
00512             if (charbuf->length == 0) {
00513                 memset(ld, 0, sizeof(*ld));
00514             }
00515             recvlen = recv(localsock_rw, lbuf , charbuf->limit - charbuf->length, 0);
00516             if (recvlen == -1) {
00517                 if (errno == EAGAIN) continue;
00518                 udplink_fatal(__LINE__, "recv(localsock_rw, ...): %s\n", strerror(errno));
00519             }
00520             if (recvlen == 0) {
00521                 break;
00522             }
00523             charbuf->length += recvlen;
00524             dres = ccn_skeleton_decode(ld, lbuf, recvlen);
00525             tries = 0;
00526             while (ld->state == 0 && ld->nest == 0) {
00527                 if (options.logging > 1)
00528                     udplink_print_data("local", charbuf->buf, msgstart, ld->index - msgstart, options.logging);
00529                 result = send_remote_unencapsulated(remotesock_w, raddrinfo, charbuf->buf, msgstart, ld->index - msgstart);
00530                 if (result == -1) {
00531                     if (errno == EAGAIN) continue;
00532                     if (errno == EPERM && (tries++ < 3)) {
00533                         /* don't die right away on this, it may be because the local firewall was set to drop some of the packets */
00534                         if (options.logging > 0)
00535                             udplink_note("sendto(remotesock_w, rbuf, %ld): %s (will retry)\n", (long) ld->index - msgstart, strerror(errno));
00536                         continue;
00537                     }
00538                     if (errno == ENOBUFS) {
00539                         /* If the O.S. is kind enough to tell us the output buffers are full, we'll just drop this packet ourselves. */
00540                         if (options.logging > 0)
00541                             udplink_note("sendto(remotesock_w, rbuf, %ld): %s (message dropped)\n", (long) ld->index - msgstart, strerror(errno));
00542                     }
00543                     else
00544                         udplink_fatal(__LINE__, "sendto(remotesock_w, rbuf, %ld): %s\n", (long)ld->index - msgstart, strerror(errno));
00545                 }
00546                 else if (result == -2) {
00547                     udplink_note("protocol error, missing CCNx PDU encapsulation. Message dropped\n");
00548                 }
00549 
00550                 msgstart = ld->index;
00551                 if (msgstart == charbuf->length) {
00552                     charbuf->length = 0;
00553                     msgstart = 0;
00554                     break;
00555                 }
00556                 recvlen = charbuf->length - msgstart;
00557                 dres = ccn_skeleton_decode(ld, charbuf->buf + msgstart, recvlen);
00558             }
00559             if (ld->state < 0) {
00560                 udplink_fatal(__LINE__, "local data protocol error\n");
00561             }
00562             /* move partial message to start of buffer */
00563             if (msgstart < charbuf->length && msgstart > 0) {
00564                 memmove(charbuf->buf, charbuf->buf + msgstart, charbuf->length - msgstart);
00565                 charbuf->length -= msgstart;
00566                 ld->index -= msgstart;
00567                 msgstart = 0;
00568             }
00569         }
00570 
00571         /* process remote data */
00572         if (fds[1].revents & (POLLIN)) {
00573             struct sockaddr from = {0};
00574             socklen_t fromlen = sizeof(from);
00575             ssize_t recvlen;
00576             unsigned char *recvbuf;
00577             char addrbuf[128];
00578 
00579             memmove(rbuf, CCN_EMPTY_PDU, CCN_EMPTY_PDU_LENGTH - 1);
00580             recvbuf = &rbuf[CCN_EMPTY_PDU_LENGTH - 1];
00581             recvlen = recvfrom(remotesock_r, recvbuf, sizeof(rbuf) - CCN_EMPTY_PDU_LENGTH,
00582                                0, &from, &fromlen);
00583             if (options.logging > 1) {
00584                 if (from.sa_family == AF_INET) {
00585                     inet_ntop(AF_INET, &((struct sockaddr_in *)&from)->sin_addr, addrbuf, sizeof(addrbuf));
00586                 } else {
00587                     inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&from)->sin6_addr, addrbuf, sizeof(addrbuf));
00588                 }
00589                 udplink_print_data(addrbuf, recvbuf, 0, recvlen, options.logging);
00590             }
00591             if (recvlen == sizeof(rbuf) - CCN_EMPTY_PDU_LENGTH) {
00592                 udplink_note("remote packet too large, discarded\n");
00593                 continue;
00594             }
00595             if (deferredlen != 0) {
00596                 dropped_count++;
00597                 dropped_bytes += recvlen;
00598                 continue;
00599             }
00600             /* encapsulate, and send the packet out on the local side */
00601             recvbuf[recvlen] = CCN_EMPTY_PDU[CCN_EMPTY_PDU_LENGTH - 1];
00602             memset(rd, 0, sizeof(*rd));
00603             dres = ccn_skeleton_decode(rd, rbuf, recvlen + CCN_EMPTY_PDU_LENGTH);
00604             if (rd->state != 0 || dres != (recvlen + CCN_EMPTY_PDU_LENGTH)) {
00605                 if (recvlen == 1)
00606                     udplink_note("remote data protocol error (1 byte recv): likely heartbeat from app sending to wrong port\n");
00607                 else
00608                     udplink_note("remote data protocol error\n");
00609                 continue;
00610             }
00611 
00612             result = send(localsock_rw, rbuf, recvlen + CCN_EMPTY_PDU_LENGTH, 0);
00613             if (result == -1) {
00614                 if (errno == EAGAIN) {
00615                     // XXX if we clear POLLIN the kernel may drop packets
00616                     // when it runs out of udp buffer space. It's not clear
00617                     // whether that is preferable to dropping them ourselves.
00618                     //fds[1].events &= ~POLLIN;
00619                     fds[1].events &= ~POLLIN;
00620                     fds[0].events |= POLLOUT;
00621                     deferredbuf = realloc(deferredbuf, recvlen + CCN_EMPTY_PDU_LENGTH);
00622                     deferredlen = recvlen + CCN_EMPTY_PDU_LENGTH;
00623                     memcpy(deferredbuf, rbuf, deferredlen);
00624                     if (options.logging > 1)
00625                         udplink_note("sendto(localsock_rw, rbuf, %ld): %s (deferred)\n", (long) deferredlen, strerror(errno));
00626                     continue;
00627                 } else {
00628                     udplink_fatal(__LINE__, "sendto(localsock_rw, rbuf, %ld): %s\n", (long) recvlen + CCN_EMPTY_PDU_LENGTH, strerror(errno));
00629                 }
00630             }
00631             if (result != recvlen + CCN_EMPTY_PDU_LENGTH) {
00632                 //fds[1].events &= ~POLLIN;
00633                 fds[0].events |= POLLOUT;
00634                 deferredlen = recvlen + CCN_EMPTY_PDU_LENGTH - result;
00635                 deferredbuf = realloc(deferredbuf, deferredlen);
00636                 memcpy(deferredbuf, rbuf + result, deferredlen);
00637                 if (options.logging > 0)
00638                     udplink_note("sendto(localsock_rw, rbuf, %ld): %s (deferred partial)\n", (long) deferredlen, strerror(errno));
00639                 continue;
00640             }
00641         }
00642     }
00643 
00644     udplink_note("disconnected\n");
00645     ccn_destroy(&ccn);
00646     freeaddrinfo(raddrinfo);
00647     freeaddrinfo(laddrinfo);
00648     if (deferredbuf != NULL) {
00649         free(deferredbuf);
00650         deferredbuf = NULL;
00651     }
00652     exit(0);
00653 }
Generated on Fri May 13 16:27:03 2011 for Content-Centric Networking in C by  doxygen 1.6.3