akmhoque | 5b39a43 | 2013-02-11 09:49:06 -0600 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <netinet/in.h> |
| 4 | #include <netdb.h> |
| 5 | #include <sys/time.h> |
| 6 | #include <sys/types.h> |
| 7 | #include <unistd.h> |
| 8 | #include <stdarg.h> |
| 9 | #include <string.h> |
| 10 | |
| 11 | #include <ccn/ccn.h> |
| 12 | #include <ccn/uri.h> |
| 13 | #include <ccn/face_mgmt.h> |
| 14 | #include <ccn/reg_mgmt.h> |
| 15 | #include <ccn/charbuf.h> |
| 16 | |
| 17 | |
| 18 | |
| 19 | #include "nlsr_face.h" |
| 20 | |
| 21 | static void |
| 22 | ccn_fib_warn(int lineno, const char *format, ...) |
| 23 | { |
| 24 | struct timeval t; |
| 25 | va_list ap; |
| 26 | va_start(ap, format); |
| 27 | gettimeofday(&t, NULL); |
| 28 | fprintf(stderr, "%d.%06d ccn_fib[%d]:%d: ", (int)t.tv_sec, (unsigned)t.tv_usec, (int)getpid(), lineno); |
| 29 | vfprintf(stderr, format, ap); |
| 30 | va_end(ap); |
| 31 | } |
| 32 | |
| 33 | static void |
| 34 | ccn_fib_fatal(int lineno, const char *format, ...) |
| 35 | { |
| 36 | struct timeval t; |
| 37 | va_list ap; |
| 38 | va_start(ap, format); |
| 39 | gettimeofday(&t, NULL); |
| 40 | fprintf(stderr, "%d.%06d ccn_fib[%d]:%d: ", (int)t.tv_sec, (unsigned)t.tv_usec, (int)getpid(), lineno); |
| 41 | vfprintf(stderr, format, ap); |
| 42 | va_end(ap); |
| 43 | exit(1); |
| 44 | } |
| 45 | |
| 46 | #define ON_ERROR_EXIT(resval, msg) on_error_exit((resval), __LINE__, msg) |
| 47 | |
| 48 | static void |
| 49 | on_error_exit(int res, int lineno, const char *msg) |
| 50 | { |
| 51 | if (res >= 0) |
| 52 | return; |
| 53 | ccn_fib_fatal(lineno, "fatal error, res = %d, %s\n", res, msg); |
| 54 | } |
| 55 | |
| 56 | #define ON_ERROR_CLEANUP(resval) \ |
| 57 | { \ |
| 58 | if ((resval) < 0) { \ |
| 59 | ccn_fib_warn (__LINE__, "OnError cleanup\n"); \ |
| 60 | goto cleanup; \ |
| 61 | } \ |
| 62 | } |
| 63 | |
| 64 | #define ON_NULL_CLEANUP(resval) \ |
| 65 | { \ |
| 66 | if ((resval) == NULL) { \ |
| 67 | ccn_fib_warn(__LINE__, "OnNull cleanup\n"); \ |
| 68 | goto cleanup; \ |
| 69 | } \ |
| 70 | } |
| 71 | |
| 72 | |
| 73 | /** |
| 74 | * |
| 75 | * Bind a prefix to a face |
| 76 | * |
| 77 | */ |
| 78 | static int |
| 79 | register_unregister_prefix(struct ccn *h, struct ccn_charbuf *local_scope_template, |
| 80 | struct ccn_charbuf *no_name, struct ccn_charbuf *name_prefix, |
| 81 | struct ccn_face_instance *face_instance, int operation) |
| 82 | { |
| 83 | struct ccn_charbuf *temp = NULL; |
| 84 | struct ccn_charbuf *resultbuf = NULL; |
| 85 | struct ccn_charbuf *signed_info = NULL; |
| 86 | struct ccn_charbuf *name = NULL; |
| 87 | struct ccn_charbuf *prefixreg = NULL; |
| 88 | struct ccn_parsed_ContentObject pcobuf = {0}; |
| 89 | struct ccn_forwarding_entry forwarding_entry_storage = {0}; |
| 90 | struct ccn_forwarding_entry *forwarding_entry = &forwarding_entry_storage; |
| 91 | struct ccn_forwarding_entry *new_forwarding_entry; |
| 92 | const unsigned char *ptr = NULL; |
| 93 | size_t length = 0; |
| 94 | int res; |
| 95 | |
| 96 | /* Register or unregister the prefix */ |
| 97 | forwarding_entry->action = (operation == OP_REG) ? "prefixreg" : "unreg"; |
| 98 | forwarding_entry->name_prefix = name_prefix; |
| 99 | forwarding_entry->ccnd_id = face_instance->ccnd_id; |
| 100 | forwarding_entry->ccnd_id_size = face_instance->ccnd_id_size; |
| 101 | forwarding_entry->faceid = face_instance->faceid; |
| 102 | forwarding_entry->flags = -1; |
| 103 | forwarding_entry->lifetime = 2100; |
| 104 | |
| 105 | prefixreg = ccn_charbuf_create(); |
| 106 | ccnb_append_forwarding_entry(prefixreg, forwarding_entry); |
| 107 | temp = ccn_charbuf_create(); |
| 108 | res = ccn_sign_content(h, temp, no_name, NULL, prefixreg->buf, prefixreg->length); |
| 109 | resultbuf = ccn_charbuf_create(); |
| 110 | |
| 111 | /* construct Interest containing prefixreg request */ |
| 112 | name = ccn_charbuf_create(); |
| 113 | ccn_name_init(name); |
| 114 | ccn_name_append_str(name, "ccnx"); |
| 115 | ccn_name_append(name, face_instance->ccnd_id, face_instance->ccnd_id_size); |
| 116 | ccn_name_append_str(name, (operation == OP_REG) ? "prefixreg" : "unreg"); |
| 117 | ccn_name_append(name, temp->buf, temp->length); |
| 118 | |
| 119 | /* send Interest, get Data */ |
| 120 | res = ccn_get(h, name, local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0); |
| 121 | ON_ERROR_CLEANUP(res); |
| 122 | |
| 123 | res = ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length); |
| 124 | ON_ERROR_CLEANUP(res); |
| 125 | |
| 126 | /* extract new forwarding entry from Data */ |
| 127 | new_forwarding_entry = ccn_forwarding_entry_parse(ptr, length); |
| 128 | ON_NULL_CLEANUP(new_forwarding_entry); |
| 129 | |
| 130 | res = new_forwarding_entry->faceid; |
| 131 | |
| 132 | ccn_forwarding_entry_destroy(&new_forwarding_entry); |
| 133 | ccn_charbuf_destroy(&signed_info); |
| 134 | ccn_charbuf_destroy(&temp); |
| 135 | ccn_charbuf_destroy(&resultbuf); |
| 136 | ccn_charbuf_destroy(&name); |
| 137 | ccn_charbuf_destroy(&prefixreg); |
| 138 | |
| 139 | return res; |
| 140 | |
| 141 | cleanup: |
| 142 | ccn_forwarding_entry_destroy(&new_forwarding_entry); |
| 143 | ccn_charbuf_destroy(&signed_info); |
| 144 | ccn_charbuf_destroy(&temp); |
| 145 | ccn_charbuf_destroy(&resultbuf); |
| 146 | ccn_charbuf_destroy(&name); |
| 147 | ccn_charbuf_destroy(&prefixreg); |
| 148 | |
| 149 | return -1; |
| 150 | } |
| 151 | |
| 152 | /** |
| 153 | * |
| 154 | * Create new face by sending out a request Interest |
| 155 | * The actual new face instance is returned |
| 156 | * |
| 157 | */ |
| 158 | static |
| 159 | struct ccn_face_instance *create_face(struct ccn *h, struct ccn_charbuf *local_scope_template, |
| 160 | struct ccn_charbuf *no_name, struct ccn_face_instance *face_instance) |
| 161 | { |
| 162 | struct ccn_charbuf *newface = NULL; |
| 163 | struct ccn_charbuf *signed_info = NULL; |
| 164 | struct ccn_charbuf *temp = NULL; |
| 165 | struct ccn_charbuf *name = NULL; |
| 166 | struct ccn_charbuf *resultbuf = NULL; |
| 167 | struct ccn_parsed_ContentObject pcobuf = {0}; |
| 168 | struct ccn_face_instance *new_face_instance = NULL; |
| 169 | const unsigned char *ptr = NULL; |
| 170 | size_t length = 0; |
| 171 | int res = 0; |
| 172 | |
| 173 | /* Encode the given face instance */ |
| 174 | newface = ccn_charbuf_create(); |
| 175 | ccnb_append_face_instance(newface, face_instance); |
| 176 | |
| 177 | temp = ccn_charbuf_create(); |
| 178 | res = ccn_sign_content(h, temp, no_name, NULL, newface->buf, newface->length); |
| 179 | resultbuf = ccn_charbuf_create(); |
| 180 | |
| 181 | /* Construct the Interest name that will create the face */ |
| 182 | name = ccn_charbuf_create(); |
| 183 | ccn_name_init(name); |
| 184 | ccn_name_append_str(name, "ccnx"); |
| 185 | ccn_name_append(name, face_instance->ccnd_id, face_instance->ccnd_id_size); |
| 186 | ccn_name_append_str(name, face_instance->action); |
| 187 | ccn_name_append(name, temp->buf, temp->length); |
| 188 | |
| 189 | /* send Interest to retrieve Data that contains the newly created face */ |
| 190 | res = ccn_get(h, name, local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0); |
| 191 | ON_ERROR_CLEANUP(res); |
| 192 | |
| 193 | /* decode Data to get the actual face instance */ |
| 194 | res = ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length); |
| 195 | ON_ERROR_CLEANUP(res); |
| 196 | |
| 197 | new_face_instance = ccn_face_instance_parse(ptr, length); |
| 198 | |
| 199 | ccn_charbuf_destroy(&newface); |
| 200 | ccn_charbuf_destroy(&signed_info); |
| 201 | ccn_charbuf_destroy(&temp); |
| 202 | ccn_charbuf_destroy(&resultbuf); |
| 203 | ccn_charbuf_destroy(&name); |
| 204 | |
| 205 | return new_face_instance; |
| 206 | |
| 207 | cleanup: |
| 208 | ccn_charbuf_destroy(&newface); |
| 209 | ccn_charbuf_destroy(&signed_info); |
| 210 | ccn_charbuf_destroy(&temp); |
| 211 | ccn_charbuf_destroy(&resultbuf); |
| 212 | ccn_charbuf_destroy(&name); |
| 213 | |
| 214 | return NULL; |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | * |
| 219 | * Get ccnd id |
| 220 | * |
| 221 | */ |
| 222 | static int |
| 223 | get_ccndid(struct ccn *h, struct ccn_charbuf *local_scope_template, |
| 224 | unsigned char *ccndid) |
| 225 | { |
| 226 | struct ccn_charbuf *name = NULL; |
| 227 | struct ccn_charbuf *resultbuf = NULL; |
| 228 | struct ccn_parsed_ContentObject pcobuf = {0}; |
| 229 | char ccndid_uri[] = "ccnx:/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY"; |
| 230 | const unsigned char *ccndid_result; |
| 231 | static size_t ccndid_result_size; |
| 232 | int res; |
| 233 | |
| 234 | name = ccn_charbuf_create(); |
| 235 | resultbuf = ccn_charbuf_create(); |
| 236 | |
| 237 | res = ccn_name_from_uri(name, ccndid_uri); |
| 238 | ON_ERROR_EXIT(res, "Unable to parse service locator URI for ccnd key\n"); |
| 239 | |
| 240 | /* get Data */ |
| 241 | res = ccn_get(h, name, local_scope_template, 4500, resultbuf, &pcobuf, NULL, 0); |
| 242 | ON_ERROR_EXIT(res, "Unable to get key from ccnd\n"); |
| 243 | |
| 244 | /* extract from Data */ |
| 245 | res = ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest, |
| 246 | resultbuf->buf, |
| 247 | pcobuf.offset[CCN_PCO_B_PublisherPublicKeyDigest], |
| 248 | pcobuf.offset[CCN_PCO_E_PublisherPublicKeyDigest], |
| 249 | &ccndid_result, &ccndid_result_size); |
| 250 | ON_ERROR_EXIT(res, "Unable to parse ccnd response for ccnd id\n"); |
| 251 | |
| 252 | memcpy((void *)ccndid, ccndid_result, ccndid_result_size); |
| 253 | |
| 254 | ccn_charbuf_destroy(&name); |
| 255 | ccn_charbuf_destroy(&resultbuf); |
| 256 | |
| 257 | return (ccndid_result_size); |
| 258 | } |
| 259 | |
| 260 | /** |
| 261 | * Construct a new face instance based on the given address and port |
| 262 | * This face instance is only used to send new face request |
| 263 | */ |
| 264 | static struct |
| 265 | ccn_face_instance *construct_face(const unsigned char *ccndid, size_t ccndid_size, |
| 266 | const char *address, const char *port, unsigned int tunnel_proto) |
| 267 | { |
| 268 | struct ccn_face_instance *fi = calloc(1, sizeof(*fi)); |
| 269 | char rhostnamebuf[NI_MAXHOST]; |
| 270 | char rhostportbuf[NI_MAXSERV]; |
| 271 | struct addrinfo hints = {.ai_family = AF_UNSPEC, .ai_flags = (AI_ADDRCONFIG), |
| 272 | .ai_socktype = SOCK_DGRAM}; |
| 273 | struct addrinfo *raddrinfo = NULL; |
| 274 | struct ccn_charbuf *store = ccn_charbuf_create(); |
| 275 | int host_off = -1; |
| 276 | int port_off = -1; |
| 277 | int res; |
| 278 | |
| 279 | res = getaddrinfo(address, port, &hints, &raddrinfo); |
| 280 | if (res != 0 || raddrinfo == NULL) |
| 281 | { |
| 282 | fprintf(stderr, "Error: getaddrinfo\n"); |
| 283 | return NULL; |
| 284 | } |
| 285 | |
| 286 | res = getnameinfo(raddrinfo->ai_addr, raddrinfo->ai_addrlen, |
| 287 | rhostnamebuf, sizeof(rhostnamebuf), |
| 288 | rhostportbuf, sizeof(rhostportbuf), |
| 289 | NI_NUMERICHOST | NI_NUMERICSERV); |
| 290 | freeaddrinfo(raddrinfo); |
| 291 | if (res != 0) |
| 292 | { |
| 293 | fprintf(stderr, "Error: getnameinfo\n"); |
| 294 | return NULL; |
| 295 | } |
| 296 | |
| 297 | fi->store = store; |
| 298 | fi->descr.ipproto = tunnel_proto; |
| 299 | fi->descr.mcast_ttl = CCN_FIB_MCASTTTL; |
| 300 | fi->lifetime = CCN_FIB_LIFETIME; |
| 301 | |
| 302 | ccn_charbuf_append(store, "newface", strlen("newface") + 1); |
| 303 | host_off = store->length; |
| 304 | ccn_charbuf_append(store, rhostnamebuf, strlen(rhostnamebuf) + 1); |
| 305 | port_off = store->length; |
| 306 | ccn_charbuf_append(store, rhostportbuf, strlen(rhostportbuf) + 1); |
| 307 | |
| 308 | char *b = (char *)store->buf; |
| 309 | fi->action = b; |
| 310 | fi->descr.address = b + host_off; |
| 311 | fi->descr.port = b + port_off; |
| 312 | fi->descr.source_address = NULL; |
| 313 | fi->ccnd_id = ccndid; |
| 314 | fi->ccnd_id_size = ccndid_size; |
| 315 | |
| 316 | return fi; |
| 317 | } |
| 318 | |
| 319 | /** |
| 320 | * initialize local data |
| 321 | */ |
| 322 | static void |
| 323 | init_data(struct ccn_charbuf *local_scope_template, |
| 324 | struct ccn_charbuf *no_name) |
| 325 | { |
| 326 | ccn_charbuf_append_tt(local_scope_template, CCN_DTAG_Interest, CCN_DTAG); |
| 327 | ccn_charbuf_append_tt(local_scope_template, CCN_DTAG_Name, CCN_DTAG); |
| 328 | ccn_charbuf_append_closer(local_scope_template); /* </Name> */ |
| 329 | ccnb_tagged_putf(local_scope_template, CCN_DTAG_Scope, "1"); |
| 330 | ccn_charbuf_append_closer(local_scope_template); /* </Interest> */ |
| 331 | |
| 332 | ccn_name_init(no_name); |
| 333 | } |
| 334 | |
| 335 | static int |
| 336 | add_delete_ccn_face(struct ccn *h, const char *uri, const char *address, const unsigned int p, int operation,unsigned int tunnel_proto) |
| 337 | { |
| 338 | struct ccn_charbuf *prefix; |
| 339 | char port[6]; |
| 340 | struct ccn_charbuf *local_scope_template = ccn_charbuf_create(); |
| 341 | struct ccn_charbuf *no_name = ccn_charbuf_create(); |
| 342 | unsigned char ccndid_storage[32] = {0}; |
| 343 | unsigned char *ccndid = ccndid_storage; |
| 344 | size_t ccndid_size = 0; |
| 345 | struct ccn_face_instance *fi; |
| 346 | struct ccn_face_instance *nfi; |
| 347 | int res; |
| 348 | |
| 349 | prefix = ccn_charbuf_create(); |
| 350 | res = ccn_name_from_uri(prefix, uri); |
| 351 | ON_ERROR_CLEANUP(res); |
| 352 | memset(port, 0, 6); |
| 353 | sprintf(port, "%d", p); |
| 354 | |
| 355 | init_data(local_scope_template, no_name); |
| 356 | |
| 357 | ccndid_size = get_ccndid(h, local_scope_template, ccndid); |
| 358 | if (ccndid_size != sizeof(ccndid_storage)) |
| 359 | { |
| 360 | fprintf(stderr, "Incorrect size for ccnd id in response\n"); |
| 361 | ON_ERROR_CLEANUP(-1); |
| 362 | } |
| 363 | |
| 364 | /* construct a face instance for new face request */ |
| 365 | fi = construct_face(ccndid, ccndid_size, address, port,tunnel_proto); |
| 366 | ON_NULL_CLEANUP(fi); |
| 367 | |
| 368 | /* send new face request to actually create a new face */ |
| 369 | nfi = create_face(h, local_scope_template, no_name, fi); |
| 370 | ON_NULL_CLEANUP(nfi); |
| 371 | |
| 372 | |
| 373 | res = register_unregister_prefix(h, local_scope_template, no_name, prefix, nfi, operation); |
| 374 | ON_ERROR_CLEANUP(res); |
| 375 | |
| 376 | int faceid=nfi->faceid; |
| 377 | |
| 378 | ccn_charbuf_destroy(&local_scope_template); |
| 379 | ccn_charbuf_destroy(&no_name); |
| 380 | ccn_face_instance_destroy(&fi); |
| 381 | ccn_face_instance_destroy(&nfi); |
| 382 | ccn_charbuf_destroy(&prefix); |
| 383 | |
| 384 | |
| 385 | return faceid; |
| 386 | |
| 387 | cleanup: |
| 388 | ccn_charbuf_destroy(&prefix); |
| 389 | ccn_charbuf_destroy(&local_scope_template); |
| 390 | ccn_charbuf_destroy(&no_name); |
| 391 | ccn_face_instance_destroy(&fi); |
| 392 | ccn_face_instance_destroy(&nfi); |
| 393 | |
| 394 | return -1; |
| 395 | } |
| 396 | |
| 397 | |
| 398 | int |
| 399 | add_ccn_face(struct ccn *h, const char *uri, const char *address, const unsigned int port, unsigned int tunnel_proto) |
| 400 | { |
| 401 | return add_delete_ccn_face(h, uri, address, port, OP_REG,tunnel_proto); |
| 402 | } |
| 403 | |
| 404 | |
| 405 | int |
| 406 | delete_ccn_face(struct ccn *h, const char *uri, const char *address, const unsigned int port,unsigned int tunnel_proto) |
| 407 | { |
| 408 | return add_delete_ccn_face(h, uri, address, port, OP_UNREG,tunnel_proto); |
| 409 | } |
| 410 | |