ccndc.c

Go to the documentation of this file.
00001 /**
00002  * @file ccndc.c
00003  * @brief Bring up a link to another ccnd.
00004  *
00005  * A CCNx program.
00006  *
00007  * Copyright (C) 2009-2010 Palo Alto Research Center, Inc.
00008  *
00009  * This work is free software; you can redistribute it and/or modify it under
00010  * the terms of the GNU General Public License version 2 as published by the
00011  * Free Software Foundation.
00012  * This work is distributed in the hope that it will be useful, but WITHOUT ANY
00013  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00015  * for more details. You should have received a copy of the GNU General Public
00016  * License along with this program; if not, write to the
00017  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <stdarg.h>
00023 #include <limits.h>
00024 #include <string.h>
00025 #include <strings.h>
00026 #include <unistd.h>
00027 #include <sys/socket.h>
00028 #include <sys/time.h>
00029 #include <netdb.h>
00030 #include <netinet/in.h>
00031 #define BIND_8_COMPAT
00032 #include <arpa/nameser.h>
00033 #include <resolv.h>
00034 #include <errno.h>
00035 #include <ccn/bloom.h>
00036 #include <ccn/ccn.h>
00037 #include <ccn/ccnd.h>
00038 #include <ccn/charbuf.h>
00039 #include <ccn/uri.h>
00040 #include <ccn/face_mgmt.h>
00041 #include <ccn/reg_mgmt.h>
00042 #include <ccn/sockcreate.h>
00043 #include <ccn/signing.h>
00044 
00045 #if defined(NEED_GETADDRINFO_COMPAT)
00046 #include "getaddrinfo.h"
00047 #include "dummyin6.h"
00048 #endif
00049 
00050 #ifndef AI_ADDRCONFIG
00051 #define AI_ADDRCONFIG 0 /*IEEE Std 1003.1-2001/Cor 1-2002, item XSH/TC1/D6/20*/
00052 #endif
00053 
00054 #ifndef NS_MAXMSG
00055 #define NS_MAXMSG 65535
00056 #endif
00057 
00058 #ifndef NS_MAXDNAME
00059 #ifdef MAXDNAME
00060 #define NS_MAXDNAME MAXDNAME
00061 #endif
00062 #endif
00063 
00064 #ifndef T_SRV
00065 #define T_SRV 33
00066 #endif
00067 
00068 #define OP_REG  0
00069 #define OP_UNREG 1
00070 
00071 /*
00072  * private types
00073  */
00074 struct prefix_face_list_item {
00075     struct ccn_charbuf *prefix;
00076     struct ccn_face_instance *fi;
00077     int flags;
00078     struct prefix_face_list_item *next;
00079 };
00080 
00081 /*
00082  * global constant (but not staticly initializable) data
00083  */
00084 static struct ccn_charbuf *local_scope_template = NULL;
00085 static struct ccn_charbuf *no_name = NULL;
00086 static unsigned char ccndid_storage[32] = {0};
00087 static const unsigned char *ccndid = ccndid_storage;
00088 static size_t ccndid_size = 0;
00089 
00090 /*
00091  * Global data
00092  */
00093 int verbose = 0;
00094 
00095 
00096 static void
00097 usage(const char *progname)
00098 {
00099     fprintf(stderr,
00100             "%s [-d] [-v] (-f configfile | (add|del) uri (udp|tcp) host [port [flags [mcastttl [mcastif]]]])\n"
00101             "   -d enter dynamic mode and create FIB entries based on DNS SRV records\n"
00102             "   -f configfile add or delete FIB entries based on contents of configfile\n"
00103             "   -v increase logging level\n"
00104             "   add|del add or delete FIB entry based on parameters\n",
00105             progname);
00106     exit(1);
00107 }
00108 
00109 void
00110 ccndc_warn(int lineno, const char *format, ...)
00111 {
00112     struct timeval t;
00113     va_list ap;
00114     va_start(ap, format);
00115     gettimeofday(&t, NULL);
00116     fprintf(stderr, "%d.%06d ccndc[%d]:%d: ", (int)t.tv_sec, (unsigned)t.tv_usec, (int)getpid(), lineno);
00117     vfprintf(stderr, format, ap);
00118     va_end(ap);
00119 }
00120 
00121 void
00122 ccndc_fatal(int line, const char *format, ...)
00123 {
00124     struct timeval t;
00125     va_list ap;
00126     va_start(ap, format);
00127     gettimeofday(&t, NULL);
00128     fprintf(stderr, "%d.%06d ccndc[%d]:%d: ", (int)t.tv_sec, (unsigned)t.tv_usec, (int)getpid(), line);
00129     vfprintf(stderr, format, ap);
00130     va_end(ap);
00131     exit(1);
00132 }
00133 
00134 #define ON_ERROR_EXIT(resval, msg) on_error_exit((resval), __LINE__, msg)
00135 
00136 static void
00137 on_error_exit(int res, int lineno, const char *msg)
00138 {
00139     if (res >= 0)
00140         return;
00141     ccndc_fatal(lineno, "fatal error, res = %d, %s\n", res, msg);
00142 }
00143 
00144 #define ON_ERROR_CLEANUP(resval) \
00145 {                       \
00146 if ((resval) < 0) { \
00147 if (verbose > 0) ccndc_warn (__LINE__, "OnError cleanup\n"); \
00148 goto Cleanup; \
00149 } \
00150 }
00151 
00152 #define ON_NULL_CLEANUP(resval) \
00153 {                       \
00154 if ((resval) == NULL) { \
00155 if (verbose > 0) ccndc_warn(__LINE__, "OnNull cleanup\n"); \
00156 goto Cleanup; \
00157 } \
00158 }
00159 
00160 static void
00161 initialize_global_data(void) {
00162     const char *msg = "Unable to initialize global data.";
00163     /* Set up an Interest template to indicate scope 1 (Local) */
00164     local_scope_template = ccn_charbuf_create();
00165     if (local_scope_template == NULL) {
00166         ON_ERROR_EXIT(-1, msg);
00167     }
00168     
00169     ON_ERROR_EXIT(ccn_charbuf_append_tt(local_scope_template, CCN_DTAG_Interest, CCN_DTAG), msg);
00170     ON_ERROR_EXIT(ccn_charbuf_append_tt(local_scope_template, CCN_DTAG_Name, CCN_DTAG), msg);
00171     ON_ERROR_EXIT(ccn_charbuf_append_closer(local_scope_template), msg);        /* </Name> */
00172     ON_ERROR_EXIT(ccnb_tagged_putf(local_scope_template, CCN_DTAG_Scope, "1"), msg);
00173     ON_ERROR_EXIT(ccn_charbuf_append_closer(local_scope_template), msg);        /* </Interest> */
00174     
00175     /* Create a null name */
00176     no_name = ccn_charbuf_create();
00177     if (no_name == NULL) {
00178         ON_ERROR_EXIT(-1, msg);
00179     }
00180     ON_ERROR_EXIT(ccn_name_init(no_name), msg);
00181 }
00182 
00183 /*
00184  * this should eventually be used as the basis for a library function
00185  *    ccn_get_ccndid(...)
00186  * which would retrieve a copy of the ccndid from the
00187  * handle, where it should be cached.
00188  */
00189 static int
00190 get_ccndid(struct ccn *h, const unsigned char *ccndid, size_t ccndid_storage_size)
00191 {
00192     
00193     struct ccn_charbuf *name = NULL;
00194     struct ccn_charbuf *resultbuf = NULL;
00195     struct ccn_parsed_ContentObject pcobuf = {0};
00196     char ccndid_uri[] = "ccnx:/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY";
00197     const unsigned char *ccndid_result;
00198     static size_t ccndid_result_size;
00199     int res;
00200     
00201     name = ccn_charbuf_create();
00202     if (name == NULL) {
00203         ON_ERROR_EXIT(-1, "Unable to allocate storage for service locator name charbuf");
00204     }
00205     
00206     resultbuf = ccn_charbuf_create();
00207     if (resultbuf == NULL) {
00208         ON_ERROR_EXIT(-1, "Unable to allocate storage for result charbuf");
00209     }
00210     
00211     
00212     ON_ERROR_EXIT(ccn_name_from_uri(name, ccndid_uri), "Unable to parse service locator URI for ccnd key");
00213     ON_ERROR_EXIT(ccn_get(h, name, local_scope_template, 4500, resultbuf, &pcobuf, NULL, 0), "Unable to get key from ccnd");
00214     res = ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest,
00215                               resultbuf->buf,
00216                               pcobuf.offset[CCN_PCO_B_PublisherPublicKeyDigest],
00217                               pcobuf.offset[CCN_PCO_E_PublisherPublicKeyDigest],
00218                               &ccndid_result, &ccndid_result_size);
00219     ON_ERROR_EXIT(res, "Unable to parse ccnd response for ccnd id");
00220     if (ccndid_result_size > ccndid_storage_size)
00221         ON_ERROR_EXIT(-1, "Incorrect size for ccnd id in response");
00222     memcpy((void *)ccndid, ccndid_result, ccndid_result_size);
00223     ccn_charbuf_destroy(&name);
00224     ccn_charbuf_destroy(&resultbuf);
00225     return (ccndid_result_size);
00226 }
00227 
00228 static struct prefix_face_list_item *prefix_face_list_item_create(struct ccn_charbuf *prefix,
00229                                                                   int ipproto,
00230                                                                   int mcast_ttl,
00231                                                                   char *host,
00232                                                                   char *port,
00233                                                                   char *mcastif,
00234                                                                   int lifetime,
00235                                                                   int flags)
00236 {
00237     struct prefix_face_list_item *pfl = calloc(1, sizeof(struct prefix_face_list_item));
00238     struct ccn_face_instance *fi = calloc(1, sizeof(*fi));
00239     struct ccn_charbuf *store = ccn_charbuf_create();
00240     int host_off = -1;
00241     int port_off = -1;
00242     int mcast_off = -1;
00243     
00244     if (pfl == NULL || fi == NULL || store == NULL) {
00245         if (pfl) free(pfl);
00246         if (fi) ccn_face_instance_destroy(&fi);
00247         if (store) ccn_charbuf_destroy(&store);
00248         return (NULL);
00249     }
00250     pfl->fi = fi;
00251     pfl->fi->store = store;
00252     
00253     pfl->prefix = prefix;
00254     pfl->fi->descr.ipproto = ipproto;
00255     pfl->fi->descr.mcast_ttl = mcast_ttl;
00256     pfl->fi->lifetime = lifetime;
00257     pfl->flags = flags;
00258     
00259     ccn_charbuf_append(store, "newface", strlen("newface") + 1);
00260     host_off = store->length;
00261     ccn_charbuf_append(store, host, strlen(host) + 1);
00262     port_off = store->length;
00263     ccn_charbuf_append(store, port, strlen(port) + 1);
00264     if (mcastif != NULL) {
00265         mcast_off = store->length;
00266         ccn_charbuf_append(store, mcastif, strlen(mcastif) + 1);
00267     }
00268     // appending to a charbuf may move it, so we must wait until we have
00269     // finished appending before calculating the pointers into the store.
00270     char *b = (char *)store->buf;
00271     pfl->fi->action = b;
00272     pfl->fi->descr.address = b + host_off;
00273     pfl->fi->descr.port = b + port_off;
00274     pfl->fi->descr.source_address = (mcast_off == -1) ? NULL : b + mcast_off;
00275     
00276     return (pfl);
00277 }
00278 
00279 static void prefix_face_list_destroy(struct prefix_face_list_item **pflpp)
00280 {
00281     struct prefix_face_list_item *pflp = *pflpp;
00282     struct prefix_face_list_item *next;
00283     
00284     if (pflp == NULL) return;
00285     while (pflp) {
00286         ccn_face_instance_destroy(&pflp->fi);
00287         ccn_charbuf_destroy(&pflp->prefix);
00288         next = pflp->next;
00289         free(pflp);
00290         pflp = next;
00291     }
00292     *pflpp = NULL;
00293 }
00294 
00295 /**
00296  *  @brief Create a face based on the face attributes
00297  *  @param h  the ccnd handle
00298  *  @param face_instance  the parameters of the face to be created
00299  *  @param flags
00300  *  @result returns new face_instance representing the face created
00301  */
00302 static struct ccn_face_instance *
00303 create_face(struct ccn *h, struct ccn_face_instance *face_instance)
00304 {
00305     struct ccn_charbuf *newface = NULL;
00306     struct ccn_charbuf *signed_info = NULL;
00307     struct ccn_charbuf *temp = NULL;
00308     struct ccn_charbuf *name = NULL;
00309     struct ccn_charbuf *resultbuf = NULL;
00310     struct ccn_parsed_ContentObject pcobuf = {0};
00311     struct ccn_face_instance *new_face_instance = NULL;
00312     const unsigned char *ptr = NULL;
00313     size_t length = 0;
00314     int res = 0;
00315     
00316     /* Encode the given face instance */
00317     newface = ccn_charbuf_create();
00318     ON_NULL_CLEANUP(newface);
00319     ON_ERROR_CLEANUP(ccnb_append_face_instance(newface, face_instance));
00320 
00321     temp = ccn_charbuf_create();
00322     ON_NULL_CLEANUP(temp);
00323     res = ccn_sign_content(h, temp, no_name, NULL, newface->buf, newface->length);
00324     ON_ERROR_CLEANUP(res);
00325     resultbuf = ccn_charbuf_create();
00326     ON_NULL_CLEANUP(resultbuf);
00327     
00328     /* Construct the Interest name that will create the face */
00329     name = ccn_charbuf_create();
00330     ON_NULL_CLEANUP(name);
00331     ON_ERROR_CLEANUP(ccn_name_init(name));
00332     ON_ERROR_CLEANUP(ccn_name_append_str(name, "ccnx"));
00333     ON_ERROR_CLEANUP(ccn_name_append(name, face_instance->ccnd_id, face_instance->ccnd_id_size));
00334     ON_ERROR_CLEANUP(ccn_name_append_str(name, face_instance->action));
00335     ON_ERROR_CLEANUP(ccn_name_append(name, temp->buf, temp->length));
00336     res = ccn_get(h, name, local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0);
00337     ON_ERROR_CLEANUP(res);
00338     
00339     ON_ERROR_CLEANUP(ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length));
00340     new_face_instance = ccn_face_instance_parse(ptr, length);
00341     ON_NULL_CLEANUP(new_face_instance);
00342     ccn_charbuf_destroy(&newface);
00343     ccn_charbuf_destroy(&signed_info);
00344     ccn_charbuf_destroy(&temp);
00345     ccn_charbuf_destroy(&resultbuf);
00346     ccn_charbuf_destroy(&name);
00347     return (new_face_instance);
00348     
00349 Cleanup:
00350     ccn_charbuf_destroy(&newface);
00351     ccn_charbuf_destroy(&signed_info);
00352     ccn_charbuf_destroy(&temp);
00353     ccn_charbuf_destroy(&resultbuf);
00354     ccn_charbuf_destroy(&name);
00355     ccn_face_instance_destroy(&new_face_instance);
00356     return (NULL);
00357 }
00358 /**
00359  *  @brief Register an interest prefix as being routed to a given face
00360  *  @param h  the ccnd handle
00361  *  @param name_prefix  the prefix to be registered
00362  *  @param face_instance  the face to which the interests with the prefix should be routed
00363  *  @param flags
00364  *  @result returns (positive) faceid on success, -1 on error
00365  */
00366 static int
00367 register_unregister_prefix(struct ccn *h,
00368                            int operation,
00369                            struct ccn_charbuf *name_prefix,
00370                            struct ccn_face_instance *face_instance,
00371                            int flags)
00372 {
00373     struct ccn_charbuf *temp = NULL;
00374     struct ccn_charbuf *resultbuf = NULL;
00375     struct ccn_charbuf *signed_info = NULL;
00376     struct ccn_charbuf *name = NULL;
00377     struct ccn_charbuf *prefixreg = NULL;
00378     struct ccn_parsed_ContentObject pcobuf = {0};
00379     struct ccn_forwarding_entry forwarding_entry_storage = {0};
00380     struct ccn_forwarding_entry *forwarding_entry = &forwarding_entry_storage;
00381     struct ccn_forwarding_entry *new_forwarding_entry;
00382     const unsigned char *ptr = NULL;
00383     size_t length = 0;
00384     int res;
00385     
00386     /* Register or unregister the prefix */
00387     forwarding_entry->action = (operation == OP_REG) ? "prefixreg" : "unreg";
00388     forwarding_entry->name_prefix = name_prefix;
00389     forwarding_entry->ccnd_id = face_instance->ccnd_id;
00390     forwarding_entry->ccnd_id_size = face_instance->ccnd_id_size;
00391     forwarding_entry->faceid = face_instance->faceid;
00392     forwarding_entry->flags = flags;
00393     forwarding_entry->lifetime = (~0U) >> 1;
00394     
00395     prefixreg = ccn_charbuf_create();
00396     ON_NULL_CLEANUP(prefixreg);
00397     ON_ERROR_CLEANUP(ccnb_append_forwarding_entry(prefixreg, forwarding_entry));
00398     temp = ccn_charbuf_create();
00399     ON_NULL_CLEANUP(temp);
00400     res = ccn_sign_content(h, temp, no_name, NULL, prefixreg->buf, prefixreg->length);
00401     ON_ERROR_CLEANUP(res);    
00402     resultbuf = ccn_charbuf_create();
00403     ON_NULL_CLEANUP(resultbuf);
00404     name = ccn_charbuf_create();
00405     ON_ERROR_CLEANUP(ccn_name_init(name));
00406     ON_ERROR_CLEANUP(ccn_name_append_str(name, "ccnx"));
00407     ON_ERROR_CLEANUP(ccn_name_append(name, face_instance->ccnd_id, face_instance->ccnd_id_size));
00408     ON_ERROR_CLEANUP(ccn_name_append_str(name, (operation == OP_REG) ? "prefixreg" : "unreg"));
00409     ON_ERROR_CLEANUP(ccn_name_append(name, temp->buf, temp->length));
00410     res = ccn_get(h, name, local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0);
00411     ON_ERROR_CLEANUP(res);
00412     ON_ERROR_CLEANUP(ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length));
00413     new_forwarding_entry = ccn_forwarding_entry_parse(ptr, length);
00414     ON_NULL_CLEANUP(new_forwarding_entry);
00415     
00416     res = new_forwarding_entry->faceid;
00417 
00418     ccn_forwarding_entry_destroy(&new_forwarding_entry);
00419     ccn_charbuf_destroy(&signed_info);
00420     ccn_charbuf_destroy(&temp);
00421     ccn_charbuf_destroy(&resultbuf);
00422     ccn_charbuf_destroy(&name);
00423     ccn_charbuf_destroy(&prefixreg);
00424     
00425     return (res);
00426     
00427     /* This is where ON_ERROR_CLEANUP sends us in case of an error
00428      * and we must free any storage we allocated before returning.
00429      */
00430 Cleanup:
00431     ccn_charbuf_destroy(&signed_info);
00432     ccn_charbuf_destroy(&temp);
00433     ccn_charbuf_destroy(&resultbuf);
00434     ccn_charbuf_destroy(&name);
00435     ccn_charbuf_destroy(&prefixreg);
00436     
00437     return (-1);
00438 }
00439 
00440 static int
00441 process_command_tokens(struct prefix_face_list_item *pfltail,
00442                        int lineno,
00443                        char *cmd,
00444                        char *uri,
00445                        char *proto,
00446                        char *host,
00447                        char *port,
00448                        char *flags,
00449                        char *mcastttl,
00450                        char *mcastif)
00451 {
00452     int lifetime;
00453     struct ccn_charbuf *prefix;
00454     int ipproto;
00455     int socktype;
00456     int iflags;
00457     int imcastttl;
00458     char rhostnamebuf[NI_MAXHOST];
00459     char rhostportbuf[NI_MAXSERV];
00460     struct addrinfo hints = {.ai_family = AF_UNSPEC, .ai_flags = (AI_ADDRCONFIG)};
00461     struct addrinfo mcasthints = {.ai_family = AF_UNSPEC, .ai_flags = (AI_ADDRCONFIG | AI_NUMERICHOST)};
00462     struct addrinfo *raddrinfo = NULL;
00463     struct addrinfo *mcastifaddrinfo = NULL;
00464     struct prefix_face_list_item *pflp;
00465     int res;
00466     
00467     if (cmd == NULL) {
00468         ccndc_warn(__LINE__, "command error (line %d), missing command\n", lineno);
00469         return (-1);
00470     }   
00471     if (strcasecmp(cmd, "add") == 0)
00472         lifetime = (~0U) >> 1;
00473     else if (strcasecmp(cmd, "del") == 0)
00474         lifetime = 0;
00475     else {
00476         ccndc_warn(__LINE__, "command error (line %d), unrecognized command '%s'\n", lineno, cmd);
00477         return (-1);
00478     }
00479     
00480     if (uri == NULL) {
00481         ccndc_warn(__LINE__, "command error (line %d), missing CCNx URI\n", lineno);
00482         return (-1);
00483     }   
00484     prefix = ccn_charbuf_create();
00485     res = ccn_name_from_uri(prefix, uri);
00486     if (res < 0) {
00487         ccndc_warn(__LINE__, "command error (line %d), bad CCNx URI '%s'\n", lineno, uri);
00488         return (-1);
00489     }
00490     
00491     if (proto == NULL) {
00492         ccndc_warn(__LINE__, "command error (line %d), missing address type\n", lineno);
00493         return (-1);
00494     }
00495     if (strcasecmp(proto, "udp") == 0) {
00496         ipproto = IPPROTO_UDP;
00497         socktype = SOCK_DGRAM;
00498     }
00499     else if (strcasecmp(proto, "tcp") == 0) {
00500         ipproto = IPPROTO_TCP;
00501         socktype = SOCK_STREAM;
00502     }
00503     else {
00504         ccndc_warn(__LINE__, "command error (line %d), unrecognized address type '%s'\n", lineno, proto);
00505         return (-1);
00506     }
00507     
00508     if (host == NULL) {
00509         ccndc_warn(__LINE__, "command error (line %d), missing hostname\n", lineno);
00510         return (-1);
00511     }
00512     
00513     if (port == NULL || port[0] == 0)
00514         port = CCN_DEFAULT_UNICAST_PORT;
00515     
00516     hints.ai_socktype = socktype;
00517     res = getaddrinfo(host, port, &hints, &raddrinfo);
00518     if (res != 0 || raddrinfo == NULL) {
00519         ccndc_warn(__LINE__, "command error (line %d), getaddrinfo: %s\n", lineno, gai_strerror(res));
00520         return (-1);
00521     }
00522     res = getnameinfo(raddrinfo->ai_addr, raddrinfo->ai_addrlen,
00523                       rhostnamebuf, sizeof(rhostnamebuf),
00524                       rhostportbuf, sizeof(rhostportbuf),
00525                       NI_NUMERICHOST | NI_NUMERICSERV);
00526     freeaddrinfo(raddrinfo);
00527     if (res != 0) {
00528         ccndc_warn(__LINE__, "command error (line %d), getnameinfo: %s\n", lineno, gai_strerror(res));
00529         return (-1);
00530     }
00531     
00532     iflags = -1;
00533     if (flags != NULL && flags[0] != 0) {
00534         iflags = atoi(flags);
00535         if ((iflags & ~CCN_FORW_PUBMASK) != 0) {
00536             ccndc_warn(__LINE__, "command error (line %d), invalid flags 0x%x\n", lineno, iflags);
00537             return (-1);
00538         }
00539     }
00540     
00541     imcastttl = -1;
00542     if (mcastttl != NULL) {
00543         imcastttl = atoi(mcastttl);
00544         if (imcastttl < 0 || imcastttl > 255) {
00545             ccndc_warn(__LINE__, "command error (line %d), invalid multicast ttl: %s\n", lineno, mcastttl);
00546             return (-1);
00547         }
00548     }
00549     
00550     if (mcastif != NULL) {
00551         res = getaddrinfo(mcastif, NULL, &mcasthints, &mcastifaddrinfo);
00552         if (res != 0) {
00553             ccndc_warn(__LINE__, "command error (line %d), mcastifaddr getaddrinfo: %s\n", lineno, gai_strerror(res));
00554             return (-1);
00555         }
00556     }
00557     
00558     /* we have successfully parsed a command line */
00559     pflp = prefix_face_list_item_create(prefix, ipproto, imcastttl, rhostnamebuf, rhostportbuf, mcastif, lifetime, iflags);
00560     if (pflp == NULL) {
00561         ccndc_fatal(__LINE__, "Unable to allocate prefix_face_list_item\n");
00562     }
00563     pfltail->next = pflp;
00564     return (0);
00565 }
00566 
00567 static int
00568 read_configfile(const char *filename, struct prefix_face_list_item *pfltail)
00569 {
00570     int configerrors = 0;
00571     int lineno = 0;
00572     char *cmd;
00573     char *uri;
00574     char *proto;
00575     char *host;
00576     char *port;
00577     char *flags;
00578     char *mcastttl;
00579     char *mcastif;
00580     FILE *cfg;
00581     char buf[1024];
00582     const char *seps = " \t\n";
00583     char *cp = NULL;
00584     char *last = NULL;
00585     int res;
00586     
00587     cfg = fopen(filename, "r");
00588     if (cfg == NULL)
00589         ccndc_fatal(__LINE__, "%s (%s)\n", strerror(errno), filename);
00590     
00591     while (fgets((char *)buf, sizeof(buf), cfg)) {
00592         int len;
00593         lineno++;
00594         len = strlen(buf);
00595         if (buf[0] == '#' || len == 0)
00596             continue;
00597         if (buf[len - 1] == '\n')
00598             buf[len - 1] = '\0';
00599         cp = index(buf, '#');
00600         if (cp != NULL)
00601             *cp = '\0';
00602         
00603         cmd = strtok_r(buf, seps, &last);
00604         if (cmd == NULL)        /* blank line */
00605             continue;
00606         uri = strtok_r(NULL, seps, &last);
00607         proto = strtok_r(NULL, seps, &last);
00608         host = strtok_r(NULL, seps, &last);
00609         port = strtok_r(NULL, seps, &last);
00610         flags = strtok_r(NULL, seps, &last);
00611         mcastttl = strtok_r(NULL, seps, &last);
00612         mcastif = strtok_r(NULL, seps, &last);
00613         res = process_command_tokens(pfltail, lineno, cmd, uri, proto, host, port, flags, mcastttl, mcastif);
00614         if (res < 0) {
00615             configerrors--;
00616         } else {
00617             pfltail = pfltail->next;
00618         }
00619     }
00620     fclose(cfg);
00621     return (configerrors);
00622 }
00623 int query_srv(const unsigned char *domain, int domain_size,
00624               char **hostp, int *portp, char **proto)
00625 {
00626     union {
00627         HEADER header;
00628         unsigned char buf[NS_MAXMSG];
00629     } ans;
00630     ssize_t ans_size;
00631     char srv_name[NS_MAXDNAME];
00632     int qdcount, ancount, i;
00633     unsigned char *msg, *msgend;
00634     unsigned char *end;
00635     int type = 0, class = 0, ttl = 0, size = 0, priority = 0, weight = 0, port = 0, minpriority;
00636     char host[NS_MAXDNAME];
00637     
00638     res_init();
00639     
00640     /* Step 1: construct the SRV record name, and see if there's a ccn service gateway.
00641      *         Prefer TCP service over UDP, though this might change.
00642      */
00643     
00644     *proto = "tcp";
00645     snprintf(srv_name, sizeof(srv_name), "_ccnx._tcp.%.*s", (int)domain_size, domain);
00646     ans_size = res_query(srv_name, C_IN, T_SRV, ans.buf, sizeof(ans.buf));
00647     if (ans_size < 0) {
00648         *proto = "udp";
00649         snprintf(srv_name, sizeof(srv_name), "_ccnx._udp.%.*s", (int)domain_size, domain);
00650         ans_size = res_query(srv_name, C_IN, T_SRV, ans.buf, sizeof(ans.buf));
00651         if (ans_size < 0)
00652             return (-1);
00653     }
00654     if (ans_size > sizeof(ans.buf))
00655         return (-1);
00656     
00657     /* Step 2: skip over the header and question sections */
00658     qdcount = ntohs(ans.header.qdcount);
00659     ancount = ntohs(ans.header.ancount);
00660     msg = ans.buf + sizeof(ans.header);
00661     msgend = ans.buf + ans_size;
00662     
00663     for (i = qdcount; i > 0; --i) {
00664         if ((size = dn_skipname(msg, msgend)) < 0)
00665             return (-1);
00666         msg = msg + size + QFIXEDSZ;
00667     }
00668     /* Step 3: process the answer section
00669      *  return only the most desirable entry.
00670      *  TODO: perhaps return a list of the decoded priority/weight/port/target
00671      */
00672     
00673     minpriority = INT_MAX;
00674     for (i = ancount; i > 0; --i) {
00675         size = dn_expand(ans.buf, msgend, msg, srv_name, sizeof (srv_name));
00676         if (size < 0) 
00677             return (CCN_UPCALL_RESULT_ERR);
00678         msg = msg + size;
00679         GETSHORT(type, msg);
00680         GETSHORT(class, msg);
00681         GETLONG(ttl, msg);
00682         GETSHORT(size, msg);
00683         if ((end = msg + size) > msgend)
00684             return (-1);
00685         
00686         if (type != T_SRV) {
00687             msg = end;
00688             continue;
00689         }
00690         
00691         /* if the priority is numerically lower (more desirable) then remember
00692          * everything -- note that priority is destroyed, but we don't use it
00693          * when we register a prefix so it doesn't matter -- only the host
00694          * and port are necessary.
00695          */
00696         GETSHORT(priority, msg);
00697         if (priority < minpriority) {
00698             minpriority = priority;
00699             GETSHORT(weight, msg);
00700             GETSHORT(port, msg);
00701             size = dn_expand(ans.buf, msgend, msg, host, sizeof (host));
00702             if (size < 0)
00703                 return (-1);
00704         }
00705         msg = end;
00706     }
00707     if (hostp) {
00708         size = strlen(host);
00709         *hostp = calloc(1, size);
00710         if (!*hostp)
00711             return (-1);
00712         strncpy(*hostp, host, size);
00713     }
00714     if (portp) {
00715         *portp = port;
00716     }
00717     return (0);
00718 }
00719 
00720 void
00721 process_prefix_face_list_item(struct ccn *h,
00722                               struct prefix_face_list_item *pfl) 
00723 {
00724     struct ccn_face_instance *nfi;
00725     struct ccn_charbuf *temp;
00726     int op;
00727     int res;
00728     
00729     op = (pfl->fi->lifetime > 0) ? OP_REG : OP_UNREG;
00730     pfl->fi->ccnd_id = ccndid;
00731     pfl->fi->ccnd_id_size = ccndid_size;
00732     nfi = create_face(h, pfl->fi);
00733     if (nfi == NULL) {
00734         temp = ccn_charbuf_create();
00735         ccn_uri_append(temp, pfl->prefix->buf, pfl->prefix->length, 1);
00736         ccndc_warn(__LINE__, "Unable to create face for %s %s %s %s %s\n",
00737                    (op == OP_REG) ? "add" : "del", ccn_charbuf_as_string(temp),
00738                    (pfl->fi->descr.ipproto == IPPROTO_UDP) ? "udp" : "tcp",
00739                    pfl->fi->descr.address,
00740                    pfl->fi->descr.port);
00741         ccn_charbuf_destroy(&temp);
00742         return;
00743     }
00744 
00745     res = register_unregister_prefix(h, op, pfl->prefix, nfi, pfl->flags);
00746     if (res < 0) {
00747         temp = ccn_charbuf_create();
00748         ccn_uri_append(temp, pfl->prefix->buf, pfl->prefix->length, 1);
00749         ccndc_warn(__LINE__, "Unable to %sregister prefix on face %d for %s %s %s %s %s\n",
00750                    (op == OP_UNREG) ? "un" : "", nfi->faceid,
00751                    (op == OP_REG) ? "add" : "del",
00752                    ccn_charbuf_as_string(temp),
00753                    (pfl->fi->descr.ipproto == IPPROTO_UDP) ? "udp" : "tcp",
00754                    pfl->fi->descr.address,
00755                    pfl->fi->descr.port);
00756         ccn_charbuf_destroy(&temp);
00757     }
00758 
00759     ccn_face_instance_destroy(&nfi);
00760     return;
00761 }
00762 
00763 enum ccn_upcall_res
00764 incoming_interest(
00765                   struct ccn_closure *selfp,
00766                   enum ccn_upcall_kind kind,
00767                   struct ccn_upcall_info *info)
00768 {
00769     const unsigned char *ccnb = info->interest_ccnb;
00770     struct ccn_indexbuf *comps = info->interest_comps;
00771     const unsigned char *comp0 = NULL;
00772     size_t comp0_size = 0;
00773     struct prefix_face_list_item pfl_storage = {0};
00774     struct prefix_face_list_item *pflhead = &pfl_storage;
00775     struct ccn_charbuf *uri;
00776     int port;
00777     char portstring[10];
00778     char *host;
00779     char *proto;
00780     int res;
00781     
00782     if (kind == CCN_UPCALL_FINAL)
00783         return (CCN_UPCALL_RESULT_OK);
00784     if (kind != CCN_UPCALL_INTEREST)
00785         return (CCN_UPCALL_RESULT_ERR);
00786     if (comps->n < 1)
00787         return (CCN_UPCALL_RESULT_OK);
00788     
00789     
00790     res = ccn_ref_tagged_BLOB(CCN_DTAG_Component, ccnb, comps->buf[0], comps->buf[1],
00791                               &comp0, &comp0_size);
00792     if (res < 0 || comp0_size > (NS_MAXDNAME - 12))
00793         return (CCN_UPCALL_RESULT_OK);
00794     if (memchr(comp0, '.', comp0_size) == NULL)
00795         return (CCN_UPCALL_RESULT_OK);
00796     
00797     host = NULL;
00798     port = 0;
00799     res = query_srv(comp0, comp0_size, &host, &port, &proto);
00800     if (res < 0) {
00801         free(host);
00802         return (CCN_UPCALL_RESULT_ERR);
00803     }
00804     
00805     uri = ccn_charbuf_create();
00806     ccn_charbuf_append_string(uri, "ccnx:/");
00807     ccn_uri_append_percentescaped(uri, comp0, comp0_size);
00808     snprintf(portstring, sizeof(portstring), "%d", port);
00809     
00810     /* now process the results */
00811     /* pflhead, lineno=0, "add" "ccnx:/asdfasdf.com/" "tcp|udp", host, portstring, NULL NULL NULL */
00812     res = process_command_tokens(pflhead, 0,
00813                                  "add",
00814                                  ccn_charbuf_as_string(uri),
00815                                  proto,
00816                                  host,
00817                                  portstring,
00818                                  NULL, NULL, NULL);
00819     if (res < 0)
00820         return (CCN_UPCALL_RESULT_ERR);
00821 
00822     process_prefix_face_list_item(info->h, pflhead->next);
00823     prefix_face_list_destroy(&pflhead->next);
00824     return(CCN_UPCALL_RESULT_OK);
00825 }
00826 
00827 
00828 int
00829 main(int argc, char **argv)
00830 {
00831     struct ccn *h = NULL;
00832     struct ccn_charbuf *temp = NULL;
00833     const char *progname = NULL;
00834     const char *configfile = NULL;
00835     struct prefix_face_list_item pfl_storage = {0};
00836     struct prefix_face_list_item *pflhead = &pfl_storage;
00837     struct prefix_face_list_item *pfl;
00838     int dynamic = 0;
00839     struct ccn_closure interest_closure = {.p=&incoming_interest};
00840     int res;
00841     int opt;
00842     
00843     initialize_global_data();
00844     
00845     progname = argv[0];
00846     while ((opt = getopt(argc, argv, "hf:dv")) != -1) {
00847         switch (opt) {
00848             case 'f':
00849                 configfile = optarg;
00850                 break;
00851             case 'd':
00852                 dynamic = 1;
00853                 break;
00854             case 'v':
00855                 verbose++;
00856                 break;
00857             case 'h':
00858             default:
00859                 usage(progname);
00860         }
00861     }
00862     
00863     if (optind < argc) {
00864         /* config file cannot be combined with command line */
00865         if (configfile != NULL) {
00866             usage(progname);
00867         }
00868         /* (add|delete) uri type host [port [flags [mcast-ttl [mcast-if]]]] */
00869         
00870         if (argc - optind < 4 || argc - optind > 8)
00871             usage(progname);
00872         
00873         res = process_command_tokens(pflhead, 0,
00874                                      argv[optind],
00875                                      argv[optind+1],
00876                                      argv[optind+2],
00877                                      argv[optind+3],
00878                                      (optind + 4) < argc ? argv[optind+4] : NULL,
00879                                      (optind + 5) < argc ? argv[optind+5] : NULL,
00880                                      (optind + 6) < argc ? argv[optind+6] : NULL,
00881                                      (optind + 7) < argc ? argv[optind+7] : NULL);
00882         if (res < 0)
00883             usage(progname);
00884     }
00885     
00886     if (configfile) {
00887         read_configfile(configfile, pflhead);
00888     }
00889     
00890     h = ccn_create();
00891     res = ccn_connect(h, NULL);
00892     if (res < 0) {
00893         ccn_perror(h, "ccn_connect");
00894         exit(1);
00895     }
00896     
00897     if (pflhead->next) {        
00898         ccndid_size = get_ccndid(h, ccndid, sizeof(ccndid_storage));
00899         for (pfl = pflhead->next; pfl != NULL; pfl = pfl->next) {
00900             process_prefix_face_list_item(h, pfl);
00901         }
00902         prefix_face_list_destroy(&pflhead->next);
00903     }
00904     if (dynamic) {
00905         temp = ccn_charbuf_create();
00906         if (ccndid_size == 0) ccndid_size = get_ccndid(h, ccndid, sizeof(ccndid_storage));
00907         /* Set up a handler for interests */
00908         ccn_name_init(temp);
00909         ccn_set_interest_filter_with_flags(h, temp, &interest_closure,
00910                                            CCN_FORW_ACTIVE | CCN_FORW_CHILD_INHERIT | CCN_FORW_LAST);
00911         ccn_charbuf_destroy(&temp);
00912         ccn_run(h, -1);
00913     }
00914     ccn_destroy(&h);
00915     exit(res < 0);
00916 }
Generated on Fri May 13 16:27:03 2011 for Content-Centric Networking in C by  doxygen 1.6.3