int iottlv_mkRequest(struct ccnl_prefix_s *name, int *dummy, unsigned char *out, int outlen) { (void) dummy; int offset, hoplim = 16; offset = outlen; if (ccnl_iottlv_prependRequest(name, &hoplim, &offset, out) < 0 || ccnl_switch_prependCoding(CCNL_ENC_IOT2014, &offset, out) < 0) return -1; memmove(out, out + offset, outlen - offset); return outlen - offset; }
int main(int argc, char *argv[]) { // char *private_key_path = 0; // char *witness = 0; unsigned char out[65*1024]; char *publisher = 0; char *infname = 0, *outdirname = 0, *outfname; int f, fout, contentlen = 0, opt, plen; // int suite = CCNL_SUITE_DEFAULT; int suite = CCNL_SUITE_CCNTLV; int chunk_size = CCNL_MAX_CHUNK_SIZE; struct ccnl_prefix_s *name; while ((opt = getopt(argc, argv, "hc:f:i:o:p:k:w:s:v:")) != -1) { switch (opt) { case 'c': chunk_size = atoi(optarg); if (chunk_size > CCNL_MAX_CHUNK_SIZE) { DEBUGMSG(WARNING, "max chunk size is %d (%d is to large), using max chunk size\n", CCNL_MAX_CHUNK_SIZE, chunk_size); chunk_size = CCNL_MAX_CHUNK_SIZE; } break; case 'f': outfname = optarg; break; case 'i': infname = optarg; break; case 'o': outdirname = optarg; break; /* case 'k': private_key_path = optarg; break; case 'w': witness = optarg; break; */ case 'p': publisher = optarg; plen = unescape_component(publisher); if (plen != 32) { DEBUGMSG(ERROR, "publisher key digest has wrong length (%d instead of 32)\n", plen); exit(-1); } break; case 's': suite = ccnl_str2suite(optarg); break; case 'v': #ifdef USE_LOGGING if (isdigit(optarg[0])) debug_level = atoi(optarg); else debug_level = ccnl_debug_str2level(optarg); #endif break; case 'h': default: Usage: fprintf(stderr, "Creates a chunked content object stream for the input data and writes them to stdout.\n" "usage: %s [options] URL\n" " -c SIZE size for each chunk (max %d)\n" " -f FNAME filename of the chunks when using -o\n" " -i FNAME input file (instead of stdin)\n" " -o DIR output dir (instead of stdout), filename default is cN, otherwise specify -f\n" " -p DIGEST publisher fingerprint\n" " -s SUITE (ccnb, ccnx2015, cisco2015, iot2014, ndn2013)\n" #ifdef USE_LOGGING " -v DEBUG_LEVEL (fatal, error, warning, info, debug, verbose, trace)\n" #endif , argv[0], CCNL_MAX_CHUNK_SIZE); exit(1); } } if (!ccnl_isSuite(suite)) goto Usage; // mandatory url if (!argv[optind]) goto Usage; char *url_orig = argv[optind]; char url[strlen(url_orig)]; optind++; // optional nfn char *nfnexpr = argv[optind]; int status; struct stat st_buf; if(outdirname) { // Check if outdirname is a directory and open it as a file status = stat(outdirname, &st_buf); if (status != 0) { // DEBUGMSG (ERROR, "Error (%d) when opening file %s\n", errno, outdirname); DEBUGMSG(ERROR, "Error (%d) when opening output dir %s (probaby does not exist)\n", errno, outdirname); goto Usage; } if (S_ISREG (st_buf.st_mode)) { // DEBUGMSG (ERROR, "Error: %s is a file and not a directory.\n", argv[optind]); DEBUGMSG(ERROR, "Error: output dir %s is a file and not a directory.\n", outdirname); goto Usage; } } if(infname) { // Check if outdirname is a directory and open it as a file status = stat(infname, &st_buf); if (status != 0) { // DEBUGMSG (ERROR, "Error (%d) when opening file %s\n", errno, outdirname); DEBUGMSG(ERROR, "Error (%d) when opening input file %s (probaby does not exist)\n", errno, infname); goto Usage; } if (S_ISDIR (st_buf.st_mode)) { // DEBUGMSG (ERROR, "Error: %s is a file and not a directory.\n", argv[optind]); DEBUGMSG(ERROR, "Error: input file %s is a directory and not a file.\n", infname); goto Usage; } f = open(infname, O_RDONLY); if (f < 0) { perror("file open:"); } } else { f = 0; } char default_file_name[2] = "c"; if (!outfname) { outfname = default_file_name; } else if(!outdirname) { DEBUGMSG(WARNING, "filename -f without -o output dir does nothing\n"); } char *chunk_buf; chunk_buf = ccnl_malloc(chunk_size * sizeof(unsigned char)); int chunk_len, is_last = 0, offs = -1; unsigned int chunknum = 0; char outpathname[255]; char fileext[10]; switch (suite) { case CCNL_SUITE_CCNB: strcpy(fileext, "ccnb"); break; case CCNL_SUITE_CCNTLV: strcpy(fileext, "ccntlv"); break; case CCNL_SUITE_CISTLV: strcpy(fileext, "cistlv"); break; case CCNL_SUITE_IOTTLV: strcpy(fileext, "iottlv"); break; case CCNL_SUITE_NDNTLV: strcpy(fileext, "ndntlv"); break; default: DEBUGMSG(ERROR, "fileext for suite %d not implemented\n", suite); } chunk_len = 1; chunk_len = read(f, chunk_buf, chunk_size); while (!is_last && chunk_len > 0) { if (chunk_len < chunk_size) { is_last = 1; } strcpy(url, url_orig); offs = CCNL_MAX_PACKET_SIZE; name = ccnl_URItoPrefix(url, suite, nfnexpr, &chunknum); switch (suite) { case CCNL_SUITE_CCNTLV: contentlen = ccnl_ccntlv_prependContentWithHdr(name, (unsigned char *)chunk_buf, chunk_len, is_last ? &chunknum : NULL, NULL, // int *contentpos &offs, out); break; case CCNL_SUITE_CISTLV: contentlen = ccnl_cistlv_prependContentWithHdr(name, (unsigned char *)chunk_buf, chunk_len, is_last ? &chunknum : NULL, &offs, NULL, // int *contentpos out); break; case CCNL_SUITE_IOTTLV: ccnl_iottlv_prependReply(name, (unsigned char *) chunk_buf, chunk_len, &offs, NULL, is_last ? &chunknum : NULL, out); ccnl_switch_prependCoding(CCNL_ENC_IOT2014, &offs, out); contentlen = CCNL_MAX_PACKET_SIZE - offs; break; case CCNL_SUITE_NDNTLV: contentlen = ccnl_ndntlv_prependContent(name, (unsigned char *) chunk_buf, chunk_len, NULL, is_last ? &chunknum : NULL, &offs, out); break; default: DEBUGMSG(ERROR, "produce for suite %i is not implemented\n", suite); goto Error; break; } if (outdirname) { sprintf(outpathname, "%s/%s%d.%s", outdirname, outfname, chunknum, fileext); // DEBUGMSG(INFO, "%s/%s%d.%s\n", outdirname, outfname, chunknum, fileext); DEBUGMSG(INFO, "writing chunk %d to file %s\n", chunknum, outpathname); fout = creat(outpathname, 0666); write(fout, out + offs, contentlen); close(fout); } else { DEBUGMSG(INFO, "writing chunk %d\n", chunknum); fwrite(out + offs, sizeof(unsigned char),contentlen, stdout); } chunknum++; if (!is_last) { chunk_len = read(f, chunk_buf, chunk_size); } } close(f); ccnl_free(chunk_buf); return 0; Error: close(f); ccnl_free(chunk_buf); return -1; }
// produces a full FRAG packet. It does not write, just read the fields in *fr struct ccnl_buf_s* ccnl_iottlv_mkFrag(struct ccnl_frag_s *fr, unsigned int *consumed) { unsigned char test[20]; int offset, hdrlen, len, len2; unsigned int datalen; struct ccnl_buf_s *buf; uint16_t tmp = 0; // test size, first datalen = fr->bigpkt->datalen - fr->sendoffs - 9; if (datalen > fr->mtu) datalen = fr->mtu; offset = sizeof(test); len = datalen + ccnl_iottlv_prependTL(IOT_TLV_F_Data, datalen, &offset, test); len += ccnl_iottlv_prependTL(IOT_TLV_F_FlagsAndSeq, 2, &offset, test) + 2; ccnl_iottlv_prependTL(IOT_TLV_Fragment, len, &offset, test); hdrlen = sizeof(test) - offset + 2 + 2; // adj for flagAndSeq, switch code // with real values: datalen = fr->bigpkt->datalen - fr->sendoffs; if (datalen > (fr->mtu - hdrlen)) datalen = fr->mtu - hdrlen; buf = ccnl_buf_new(NULL, hdrlen + datalen); // 2 bytes for switch code if (!buf) return 0; offset = buf->datalen; len = ccnl_iottlv_prependBlob(IOT_TLV_F_Data, fr->bigpkt->data + fr->sendoffs, datalen, &offset, buf->data); if (len <= 0) { ccnl_free(buf); return NULL; } // flags and sequence number if (datalen >= fr->bigpkt->datalen) { // single tmp |= CCNL_DTAG_FRAG_FLAG_SINGLE << 14; } else if (fr->sendoffs == 0) // start tmp |= CCNL_DTAG_FRAG_FLAG_FIRST << 14; else if(datalen >= (fr->bigpkt->datalen - fr->sendoffs)) { // end tmp |= CCNL_DTAG_FRAG_FLAG_LAST << 14; } else tmp |= CCNL_DTAG_FRAG_FLAG_MID << 14; tmp |= fr->sendseq & 0x07ff; tmp = htons(tmp); len2 = ccnl_iottlv_prependBlob(IOT_TLV_F_FlagsAndSeq, (unsigned char*) &tmp, sizeof(tmp), &offset, buf->data); if (len2 <= 0) { ccnl_free(buf); return NULL; } len += len2; // main header len2 = ccnl_iottlv_prependTL(IOT_TLV_Fragment, len, &offset, buf->data); if (len2 <= 0) { ccnl_free(buf); return NULL; } len += len2; // encoding switch: len2 = ccnl_switch_prependCoding(CCNL_ENC_IOT2014, &offset, buf->data); if (len2 < 0) { DEBUGMSG(ERROR, " prending code should not return -1\n"); ccnl_free(buf); return NULL; } len += len2; if (offset > 0) { DEBUGMSG(TRACE, " iottlv fragment: shift by %d bytes\n", offset); memmove(buf->data, buf->data + offset, len); buf->datalen = len; } *consumed = datalen; return buf; }
// we use one extraction routine for both request and reply pkts struct ccnl_pkt_s* ccnl_iottlv_bytes2pkt(int pkttype, unsigned char *start, unsigned char **data, int *datalen) { struct ccnl_pkt_s *pkt; unsigned char *cp, tmp[10]; int cplen, len2; unsigned int typ, len, state; DEBUGMSG_PIOT(DEBUG, "ccnl_iottlv_extract len=%d\n", *datalen); /* { int fd = open("s.bin", O_WRONLY|O_CREAT|O_TRUNC); write(fd, *data, *datalen); close(fd); } */ pkt = (struct ccnl_pkt_s*) ccnl_calloc(1, sizeof(*pkt)); if (!pkt) return NULL; pkt->suite = CCNL_SUITE_IOTTLV; pkt->val.final_block_id = -1; pkt->s.iottlv.ttl = -1; #define IOTPS(C,L) (((C)<<4)|(L)) // parse state: combines current state while (*datalen) { if (ccnl_iottlv_dehead(data, datalen, &typ, &len)) goto Bail; state = IOTPS(pkttype, typ); DEBUGMSG_CFWD(TRACE, " state = 0x%04x\n", state); switch (state) { case IOTPS(IOT_TLV_Request, IOT_TLV_R_OptHeader): case IOTPS(IOT_TLV_Reply, IOT_TLV_R_OptHeader): { cp = *data; cplen = len; while (cplen > 0 && !ccnl_iottlv_dehead(&cp, &cplen, &typ, (unsigned int *)&len2)) { if (typ == IOT_TLV_H_HopLim && len2 == 1) { if (*cp > 0) *cp -= 1; pkt->s.iottlv.ttl = *cp; } cp += len2; cplen -= len2; } break; } case IOTPS(IOT_TLV_Request, IOT_TLV_R_Name): case IOTPS(IOT_TLV_Reply, IOT_TLV_R_Name): cp = *data; cplen = len; while (cplen > 0 && !ccnl_iottlv_dehead(&cp, &cplen, &typ, (unsigned int *)&len2)) { if (typ == IOT_TLV_N_PathName) { if (!pkt->pfx) pkt->pfx = ccnl_iottlv_parseHierarchicalName(cp, len2); if (!pkt->pfx) goto Bail; } cp += len2; cplen -= len2; } break; case IOTPS(IOT_TLV_Fragment, IOT_TLV_F_FlagsAndSeq): { uint16_t fragFields; if (len < 2) { DEBUGMSG_CFWD(DEBUG, " no flags and seqno found (%d)\n", typ); goto Bail; } fragFields = ntohs(*(uint16_t*) *data); pkt->val.seqno = fragFields & 0x7ff; pkt->flags |= (fragFields >> 14) << 2; break; } case IOTPS(IOT_TLV_Request, IOT_TLV_R_Payload): case IOTPS(IOT_TLV_Reply, IOT_TLV_R_Payload): cp = *data; cplen = len; if (!ccnl_iottlv_dehead(&cp, &cplen, &typ, (unsigned int *)&len2)) { if (typ == IOT_TLV_PL_Data) { pkt->content = cp; pkt->contlen = len2; } } break; case IOTPS(IOT_TLV_Fragment, IOT_TLV_F_Data): pkt->content = *data; pkt->contlen = len; break; /* #ifdef USE_FRAG if (ccnl_iottlv_peekType(*data, *datalen) == IOT_TLV_Fragment) { uint16_t tmp; unsigned int payloadlen; if (ccnl_iottlv_dehead(data, datalen, &typ, &len)) // IOT_TLV_Fragment return -1; if (ccnl_iottlv_dehead(data, datalen, &typ, &len)) return -1; if (typ == IOT_TLV_F_OptFragHdr) { // skip it for the time being *data += len; *datalen -= len; if (ccnl_iottlv_dehead(data, datalen, &typ, &len)) return -1; } if (typ != IOT_TLV_F_FlagsAndSeq || len < 2) { DEBUGMSG_CFWD(DEBUG, " no flags and seqrn found (%d)\n", typ); return -1; } tmp = ntohs(*(uint16_t*) *data); *data += len; *datalen -= len; if (ccnl_iottlv_dehead(data, datalen, &typ, &payloadlen)) return -1; if (typ != IOT_TLV_F_Payload) { DEBUGMSG_CFWD(DEBUG, " no payload (%d)\n", typ); return -1; } *datalen -= payloadlen; ccnl_frag_RX_Sequenced2015(ccnl_iottlv_forwarder, relay, from, relay->ifs[from->ifndx].mtu, tmp >> 14, tmp & 0x7ff, data, (int*) &payloadlen); *datalen += payloadlen; DEBUGMSG_CFWD(TRACE, " returning after fragment: %d bytes\n", *datalen); return 0; } else #endif */ default: fprintf(stderr, " iottlv unknown state 0x%04x\n", state); break; } *data += len; *datalen -= len; } if (*datalen > 0) goto Bail; // if we received a naked packet (without switch code), we need to add // a switch code when creating the packet buffer if (*start != 0x80) { len = sizeof(tmp); len2 = ccnl_switch_prependCoding(CCNL_ENC_IOT2014, (int*) &len, tmp); if (len2 < 0) { DEBUGMSG(ERROR, "prending code should not return -1\n"); len2 = 0; } start -= len2; } else len2 = 0; pkt->buf = ccnl_buf_new(start, *data - start); if (!pkt->buf) goto Bail; if (pkt->buf && len2) memcpy(pkt->buf->data, tmp + len, len2); // carefully rebase ptrs to new buf because of 64bit pointers: if (pkt->content) pkt->content = pkt->buf->data + (pkt->content - start); if (pkt->pfx) { int i; for (i = 0; i < pkt->pfx->compcnt; i++) pkt->pfx->comp[i] = pkt->buf->data + (pkt->pfx->comp[i] - start); if (pkt->pfx->nameptr) pkt->pfx->nameptr = pkt->buf->data + (pkt->pfx->nameptr - start); } return pkt; Bail: free_packet(pkt); return NULL; }