Esempio n. 1
0
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;
}