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