Exemplo n.º 1
0
LONGBOW_TEST_CASE(Global, metisMessage_ReadFromBuffer)
{
    char message_str[] = "\x00Once upon a time, in a stack far away, a dangling pointer found its way to the top of the heap.";

    PARCEventBuffer *buff = parcEventBuffer_Create();
    parcEventBuffer_Append(buff, message_str, sizeof(message_str));

    PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
    MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
    parcLogReporter_Release(&reporter);
    MetisMessage *message = metisMessage_ReadFromBuffer(1, 2, buff, sizeof(message_str), logger);
    metisLogger_Release(&logger);

    assertNotNull(message, "Got null from metisMessage_CreateFromBuffer");

    assertTrue(parcEventBuffer_GetLength(message->messageBytes) == sizeof(message_str),
               "Length of internal buffer wrong, expected %zu got %zu",
               sizeof(message_str),
               parcEventBuffer_GetLength(message->messageBytes));

    uint8_t *p = parcEventBuffer_Pullup(message->messageBytes, sizeof(message_str));
    assertTrue(memcmp(p, message_str, sizeof(message_str)) == 0, "Internal buffer contents does not match test");
    assertTrue(message->ingressConnectionId == 1, "IngressConnectionId wrong, expected %d got %u", 1, message->ingressConnectionId);
    assertTrue(message->receiveTime == 2, "receiveTime wrong, expected %u got %" PRIu64, 2, message->receiveTime);
    assertTrue(parcEventBuffer_GetLength(buff) == 0, "Origin buffer not drained, expected 0, got %zu", parcEventBuffer_GetLength(buff));

    metisMessage_Release(&message);
    parcEventBuffer_Destroy(&buff);
}
Exemplo n.º 2
0
/**
 * Parses the work buffer to extract packets
 *
 * The work buffer should be filled in with a set of tuples (bh_hdrlen, frame, pad).
 * The pad extends each packet out to BPF_WORDALIGN.
 *
 * If the CCNxMessage PacketLength says it is larger than the read capture length (caplen),
 * then this is an invalid packet and it will be discarded.  This error will result in a
 * ReadWorkBufferResult_TryAgain condition.
 *
 * struct bpf_hdr {
 *    struct BPF_TIMEVAL bh_tstamp;	 // time stamp
 *    bpf_u_int32        bh_caplen;	 // length of captured portion
 *    bpf_u_int32        bh_datalen; // original length of packet
 *    u_short		     bh_hdrlen;	 // length of bpf header (this struct plus alignment padding)
 * }
 *
 * @param [in] ether An allocated Darwin ethernet.
 * @param [in] readbuffer A user-provided read buffer.
 *
 * @retval ReadWorkBufferResult_Ok A frame was moved from workbuffer to readbuffer
 * @retval ReadWorkBufferResult_Empty There's not enough bytes in the workbuffer
 * @retval ReadWorkBufferResult_TryAgain (likely discard) caused this call to fail, but you should try again
 *
 * Example:
 * @code
 * <#example#>
 * @endcode
 */
static _ReadWorkBufferResult
_darwinEthernet_ReadWorkBuffer(MetisGenericEther *ether, PARCEventBuffer *readbuffer)
{
    _ReadWorkBufferResult result = ReadWorkBufferResult_Empty;

    // Make sure we have linear memory for the BPF header
    struct bpf_hdr *bpfHeader = (struct bpf_hdr *) parcEventBuffer_Pullup(ether->workBuffer, sizeof(struct bpf_hdr));

    // make sure we have enough bytes to process the frame
    // bpfHeader may be NULL if there are not sizeof(struct bpf_hdr) bytes available.
    if (bpfHeader && parcEventBuffer_GetLength(ether->workBuffer) >= bpfHeader->bh_hdrlen + bpfHeader->bh_caplen) {
        // (0) Save the needed fields from the bpf header
        // (1) pop off the bpf header
        // (2) move the iovec from work buffer to readBuffer.
        // (3) remove any BPF_WORDALIGN padding to the start of the next packet

        // (0) Save the needed fields from the bpf header
        uint16_t hdrlen = bpfHeader->bh_hdrlen;
        uint32_t caplen = bpfHeader->bh_caplen;

        // (1) pop off the bpf header
        parcEventBuffer_Read(ether->workBuffer, NULL, hdrlen);

        // (1a) Determine the packet length from the fixed header and only transfer that many bytes
        uint16_t packetlen = _getFrameLengthFromWorkBuffer(ether);

        if (packetlen <= caplen) {
            // (2) move the iovec from work buffer to readBuffer.
            parcEventBuffer_ReadIntoBuffer(ether->workBuffer, readbuffer, packetlen);

            // (2a) drain off any trailer (i.e. FCS)
            parcEventBuffer_Read(ether->workBuffer, NULL, caplen - packetlen);

            result = ReadWorkBufferResult_Ok;
        } else {
            if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning)) {
                metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__,
                                "%s reading fd %d discard packetlen %u greater than caplen %u",
                                __func__, ether->etherSocket, packetlen, caplen);
            }

            // discard all of caplen
            parcEventBuffer_Read(ether->workBuffer, NULL, caplen);

            // tell the caller that this read failed, but they could try again.
            result = ReadWorkBufferResult_TryAgain;
        }

        // (3) remove any BPF_WORDALIGN padding to the start of the next packet
        size_t alignedLength = BPF_WORDALIGN(hdrlen + caplen);
        size_t pad = alignedLength - hdrlen - caplen;
        parcEventBuffer_Read(ether->workBuffer, NULL, pad);
    }
    return result;
}
Exemplo n.º 3
0
/**
 * @function startNewMessage
 * @abstract Peek at the fixed header and set the stream->nextMessageLength
 * @discussion
 *   This function manipulates the stream->nextMessageLength. After reading a FixedHeader, set nextMessageLength
 *   to the total length of the message.
 *
 *   PRECONDITION: stream->nextMessageLength == 0
 *   PRECONDITION: inputBytesAvailable >= FIXED_HEADER_LEN
 *
 * @param stream is the stream begin parsed.
 * @param input is the input PARCEventBuffer (corresponds to the buffer event's input)
 * @param inputBytesAvailable is the number of bytes available in the input PARCEventBuffer.
 * @return <#return#>
 */
static void
_startNewMessage(_MetisStreamState *stream, PARCEventBuffer *input, size_t inputBytesAvailable)
{
    assertTrue(stream->nextMessageLength == 0, "Invalid state, nextMessageLength not zero: %zu", stream->nextMessageLength);
    assertTrue(inputBytesAvailable >= metisTlv_FixedHeaderLength(), "read_length not a whole fixed header!: %zd", inputBytesAvailable);

    // this linearizes the first FIXED_HEADER_LEN bytes of the input buffer's iovecs and
    // returns a pointer to it.
    uint8_t *fh = parcEventBuffer_Pullup(input, metisTlv_FixedHeaderLength());

    // Calculate the total message size based on the fixed header
    stream->nextMessageLength = metisTlv_TotalPacketLength(fh);
}
Exemplo n.º 4
0
/*
 * Returns the total legth of the good data: the ethernet header plus ccnx packet.
 * If there is a FCS, it will be excluded.
 *
 * PRECONDITION: You have drained off any BPF headers and the first byte
 * of the work buffer points to the first byte of the Ethernet header
 */
static uint16_t
_getFrameLengthFromWorkBuffer(MetisGenericEther *ether)
{
    uint16_t frameLength = 0;

    // read the fixed header
    uint8_t *etherHeader = parcEventBuffer_Pullup(ether->workBuffer, ETHER_HDR_LEN + metisTlv_FixedHeaderLength());

    if (etherHeader) {
        uint8_t *fixedHeader = etherHeader + ETHER_HDR_LEN;
        frameLength = metisTlv_TotalPacketLength(fixedHeader) + ETHER_HDR_LEN;
    }

    return frameLength;
}