예제 #1
0
/*
 * We've reach the END fragment of the reassembly buffer.
 * 1) Make a metis message out of the reassembly buffer,
 * 2) put the message in the receive queue (discard if queue full)
 * 3) allocate a new reassembly buffer
 * 4) reset the parser
 */
static void
_finalizeReassemblyBuffer(MetisHopByHopFragmenter *fragmenter)
{
    // This takes ownership of fragmenter->currentReceiveBuffer
    MetisMessage *reassembled = metisMessage_CreateFromBuffer(fragmenter->currentReceiveBufferIngressId,
                                                              fragmenter->currentReceiveBufferStartTicks,
                                                              fragmenter->currentReceiveBuffer,
                                                              fragmenter->logger);

    if (reassembled) {
        bool success = parcRingBuffer1x1_Put(fragmenter->receiveQueue, reassembled);
        if (success) {
            metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                            "Fragmenter %p putting reassembed message %p in receive queue",
                            (void *) fragmenter, (void *) reassembled);
        } else {
            metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Error, __func__,
                            "Fragmenter %p failed to put reassembled message in receive queue, dropping",
                            (void *) fragmenter);

            metisMessage_Release(&reassembled);
        }

        fragmenter->currentReceiveBuffer = parcEventBuffer_Create();
    } else {
        metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__,
                        "Fragmenter %p failed to parse reassembled packet to MetisMessage, dropping",
                        (void *) fragmenter);
    }

    _resetParser(fragmenter);
}
예제 #2
0
static bool
_symbolicRegisterPrefix(MetisConfiguration *config, CPIRouteEntry *route)
{
    bool success = false;

    const char *symbolic = cpiRouteEntry_GetSymbolicName(route);
    unsigned ifidx = metisSymbolicNameTable_Get(config->symbolicNameTable, symbolic);
    if (ifidx != UINT32_MAX) {
        cpiRouteEntry_SetInterfaceIndex(route, ifidx);
        if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug)) {
            metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug, __func__,
                            "Add route resolve name '%s' to connid %u",
                            symbolic, ifidx);
        }

        success = metisForwarder_AddOrUpdateRoute(config->metis, route);
    } else {
        if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Warning)) {
            metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Warning, __func__,
                            "Add route symbolic name '%s' could not be resolved", symbolic);
        }
        // this is a failure
    }
    return success;
}
예제 #3
0
/**
 * Add an IP-based tunnel.
 *
 * The call cal fail if the symbolic name is a duplicate.  It could also fail if there's an problem creating
 * the local side of the tunnel (i.e. the local socket address is not usable).
 *
 * @return true Tunnel added
 * @return false Tunnel not added (an error)
 */
static CCNxControl *
metisConfiguration_ProcessCreateTunnel(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
{
    bool success = false;

    CPIInterfaceIPTunnel *iptun = cpiLinks_CreateIPTunnelFromControlMessage(control);

    const char *symbolicName = cpiInterfaceIPTunnel_GetSymbolicName(iptun);

    if (!metisSymbolicNameTable_Exists(config->symbolicNameTable, symbolicName)) {
        const CPIAddress *source = cpiInterfaceIPTunnel_GetSourceAddress(iptun);
        const CPIAddress *destination = cpiInterfaceIPTunnel_GetDestinationAddress(iptun);

        MetisIoOperations *ops = NULL;
        switch (cpiInterfaceIPTunnel_GetTunnelType(iptun)) {
            case IPTUN_TCP:
                ops = metisTcpTunnel_Create(config->metis, source, destination);
                break;
            case IPTUN_UDP:
                ops = metisUdpTunnel_Create(config->metis, source, destination);
                break;
            case IPTUN_GRE:
                metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
                                "Unsupported tunnel protocol: GRE");
                break;
            default:
                metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
                                "Unsupported tunnel protocol: %d",
                                cpiInterfaceIPTunnel_GetTunnelType(iptun));
                break;
        }


        if (ops != NULL) {
            MetisConnection *conn = metisConnection_Create(ops);
            metisConnectionTable_Add(metisForwarder_GetConnectionTable(config->metis), conn);
            metisSymbolicNameTable_Add(config->symbolicNameTable, symbolicName, metisConnection_GetConnectionId(conn));

            success = true;

            _logProcessCreateTunnelMessage(config, iptun, PARCLogLevel_Info, "success");
        } else {
            _logProcessCreateTunnelMessage(config, iptun, PARCLogLevel_Warning, "failed, could not create IoOperations");
        }
    } else {
        _logProcessCreateTunnelMessage(config, iptun, PARCLogLevel_Warning, "failed, symbolic name exists");
    }

    // send the ACK or NACK
    CCNxControl *response;
    if (success) {
        response = _createAck(config, control, ingressId);
    } else {
        response = _createNack(config, control, ingressId);
    }

    cpiInterfaceIPTunnel_Release(&iptun);

    return response;
}
예제 #4
0
/*
 * Parser is in Idle state.  We can only accept a B or BE frame.
 * 1) If B frame:
 * 1a) append to current receive buffer
 * 1b) set parser state to Busy
 * 1c) set the currentReceiveBufferStartTicks
 * 1d) set the currentReceiveBufferIngressId
 * 2) If BE frame, do B actions and finalize it (side effect: will reset state to Idle)
 * 3) Otherwise ignore it
 *
 * Precondition: You know that the parser is in the Idle state
 */
static void
_receiveInIdleState(MetisHopByHopFragmenter *fragmenter, const MetisMessage *message, const _HopByHopHeader *fixedHeader)
{
    trapUnexpectedStateIf(fragmenter->parserState != _ParserState_Idle,
                          "Parser in wrong state, expected %d got %d",
                          _ParserState_Idle, fragmenter->parserState);

    if (_hopByHopHeader_GetBFlag(fixedHeader)) {
        // start a new packet
        fragmenter->currentReceiveBufferStartTicks = metisMessage_GetReceiveTime(message);
        fragmenter->currentReceiveBufferIngressId = metisMessage_GetIngressConnectionId(message);
        fragmenter->parserState = _ParserState_Busy;

        _appendFragmentToReassemblyBuffer(fragmenter, message);

        if (_hopByHopHeader_GetEFlag(fixedHeader)) {
            // it is also the last fragment
            _finalizeReassemblyBuffer(fragmenter);
        }
    } else if (_hopByHopHeader_GetIFlag(fixedHeader)) {
        // nothing to do
        metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                        "Fragmenter %p idle frame, ignorning",
                        (void *) fragmenter);
    } else {
        // nothing we can do with this frame
        metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__,
                        "Fragmenter %p received bad header flags (0x%02X), ignorning",
                        (void *) fragmenter, _hopByHopHeader_GetFlags(fixedHeader));
    }
}
예제 #5
0
bool
metisHopByHopFragmenter_Send(MetisHopByHopFragmenter *fragmenter, MetisMessage *message)
{
    bool success = false;

    // If the packet will fit in the MTU without fragmentation, do not use fragmentation
    if (metisMessage_Length(message) > fragmenter->mtu) {
        success = _sendFragments(fragmenter, message);
    } else {
        MetisMessage *copy = metisMessage_Acquire(message);
        success = parcRingBuffer1x1_Put(fragmenter->sendQueue, copy);
        if (!success) {
            metisMessage_Release(&copy);
            metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__,
                            "Failed to add message %p to send queue", (void *) message);
        } else {
            if (metisLogger_IsLoggable(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) {
                metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                                "Add message %p to send queue", (void *) message);
            }
        }
    }

    return success;
}
예제 #6
0
/**
 * Reads from the socket to fill in the work buffer
 *
 * Reads one or more packets from the socket to the work buffer  It will append to the work buffer.
 * The BFP socket is non-blocking.  The BPF interface may return multiple packets in one read
 * that need to be parsed as in _darwinEthernet_ReadWorkBuffer().
 *
 * @param [in] ether The Darwin ethernet interface
 *
 * @retval true We added something to the work buffer
 * @retval false Nothing was read
 *
 * Example:
 * @code
 * <#example#>
 * @endcode
 */
static bool
_darwinEthernet_ReadSocket(MetisGenericEther *ether)
{
    bool success = false;

    if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) {
        metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                        "%s reading fd %d bufferLength %u", __func__, ether->etherSocket, ether->etherBufferLength);
    }

    // The buffer we're reading must be exactly ether->etherBufferLength
    // TODO: Fix the parcEventBuffer_ReadFromFileDescriptor call to reserve that space so it's all there.

    uint8_t tempBuffer[ether->etherBufferLength];
    ssize_t read_length = read(ether->etherSocket, tempBuffer, ether->etherBufferLength);
    if (read_length > 0) {
        parcEventBuffer_Append(ether->workBuffer, tempBuffer, read_length);
        if (read_length > 0) {
            if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) {
                metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                                "%s read %zd bytes from fd %d",
                                __func__,
                                read_length,
                                ether->etherSocket);
            }
            success = true;
        }
    }

    return success;
}
예제 #7
0
/**
 * Apply the sequence number rules
 *
 * a) If the sequence number is in order, no action.
 * b) If the sequence number is out of order, reset the parser.
 * c) Update the next expected sequence number to be this packet's seqnum + 1.
 *
 * @param [in] fragmenter An allocated MetisHopByHopFragmenter
 * @param [in] fixedHeader The packet's fixed header
 *
 * Example:
 * @code
 * <#example#>
 * @endcode
 */
static void
_applySequenceNumberRules(MetisHopByHopFragmenter *fragmenter, const _HopByHopHeader *fixedHeader)
{
    uint32_t segnum = _hopByHopHeader_GetSeqnum(fixedHeader);

    int compare = _compareSequenceNumbers(segnum, fragmenter->nextReceiveFragSequenceNumber);

    if (compare == 0) {
        // In order
        metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                        "Fragmenter %p in-order seqnum %u",
                        (void *) fragmenter, segnum);
    } else if (compare < 0) {
        // it is an old sequence number
        metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__,
                        "Fragmenter %p out-of-order seqnum %u expecting %u",
                        (void *) fragmenter, segnum, fragmenter->nextReceiveFragSequenceNumber);
        _resetParser(fragmenter);
    } else if (compare > 0) {
        // lost packets
        metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__,
                        "Fragmenter %p out-of-order seqnum %u expecting %u",
                        (void *) fragmenter, segnum, fragmenter->nextReceiveFragSequenceNumber);
        _resetParser(fragmenter);
    }

    // the next seqnum we expect will be 1 after what we just received.  For example, if we lost packets
    // this will put us back in line with the new series.
    fragmenter->nextReceiveFragSequenceNumber = _incrementSequenceNumber(segnum, SEQNUM_MASK);
}
예제 #8
0
static bool
_metisConfiguration_AddConnectionEthernet(MetisConfiguration *config, CPIConnectionEthernet *etherConn, CPIAddress *linkAddress, MetisListenerOps *listenerOps)
{
    bool success = false;

    const char *symbolic = cpiConnectionEthernet_GetSymbolicName(etherConn);
    if (!metisSymbolicNameTable_Exists(config->symbolicNameTable, symbolic)) {
        const CPIAddress *remote = cpiConnectionEthernet_GetPeerLinkAddress(etherConn);
        MetisAddressPair *pair = metisAddressPair_Create(linkAddress, remote);

        MetisGenericEther *ether = metisEtherListener_GetGenericEtherFromListener(listenerOps);

        if (ether) {
            MetisIoOperations *ops = metisEtherConnection_Create(config->metis, ether, pair);

            if (ops) {
                MetisConnection *conn = metisConnection_Create(ops);
                assertNotNull(conn, "Failed to create connection");

                metisConnectionTable_Add(metisForwarder_GetConnectionTable(config->metis), conn);
                metisSymbolicNameTable_Add(config->symbolicNameTable, symbolic, metisConnection_GetConnectionId(conn));

                success = true;

                if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug)) {
                    char *peerAddressString = cpiAddress_ToString(remote);
                    metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug, __func__,
                                    "Add connection %s on %s to %s, connid %u",
                                    symbolic,
                                    cpiConnectionEthernet_GetInterfaceName(etherConn),
                                    peerAddressString,
                                    metisConnection_GetConnectionId(conn));
                    parcMemory_Deallocate((void **) &peerAddressString);
                }
            }
        } else {
            metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
                            "Could not get MetisGenericEther for listener %p",
                            listenerOps);
        }

        metisAddressPair_Release(&pair);
    } else {
        if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Warning)) {
            const CPIAddress *remote = cpiConnectionEthernet_GetPeerLinkAddress(etherConn);
            char *peerAddressString = cpiAddress_ToString(remote);
            metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Warning, __func__,
                            "Add connection %s on %s to %s failed, symbolic name exists",
                            symbolic,
                            cpiConnectionEthernet_GetInterfaceName(etherConn),
                            peerAddressString);
            parcMemory_Deallocate((void **) &peerAddressString);
        }
    }

    return success;
}
예제 #9
0
/**
 * Fragments a message and puts all the fragments in the send queue
 *
 * Splits up the message in to fragments.  The frist fragment will have the B flag and
 * the last fragment will have the E flag.  If the message fits in one fragment, it will
 * have both the BE flags.  Middle messages have no flags.
 *
 * @param [in] fragmenter An allocated MetisHopByHopFragmenter
 * @param [in] message The message to fragment down to MTU size
 *
 * @return true Message was fragmented and all fragments put on send queue
 * @return false Error durring fragmentation (likley full send queue)
 *
 * Example:
 * @code
 * {
 *     <#example#>
 * }
 * @endcode
 */
static bool
_sendFragments(MetisHopByHopFragmenter *fragmenter, const MetisMessage *message)
{
    const size_t length = metisMessage_Length(message);
    size_t offset = 0;

    const size_t maxPayload = fragmenter->mtu - sizeof(_HopByHopHeader);

    _HopByHopHeader header;
    memset(&header, 0, sizeof(header));
    _hopByHopHeader_SetBFlag(&header);

    while (offset < length) {
        size_t payloadLength = maxPayload;
        const size_t remaining = length - offset;

        if (remaining < maxPayload) {
            payloadLength = remaining;
            _hopByHopHeader_SetEFlag(&header);
        }

        const size_t packetLength = sizeof(_HopByHopHeader) + payloadLength;

        header.version = 1;
        header.packetType = METIS_PACKET_TYPE_HOPFRAG;
        header.packetLength = htons(packetLength);
        header.headerLength = 8;
        header.tlvType = htons(T_HOPFRAG_PAYLOAD);
        header.tlvLength = htons(payloadLength);

        uint32_t seqnum = _nextSendSequenceNumber(fragmenter);
        _hopByHopHeader_SetSeqnum(&header, seqnum);

        MetisMessage *fragment = metisMessage_Slice(message, offset, payloadLength, sizeof(header), (uint8_t *) &header);
        bool goodput = parcRingBuffer1x1_Put(fragmenter->sendQueue, fragment);
        if (!goodput) {
            metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__,
                            "Fragmenter %p message %p send queue full offset %zu length %zu",
                            (void *) fragmenter, (void *) message, offset, payloadLength);
            metisMessage_Release(&fragment);
            break;
        }

        metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                        "Fragmenter %p message %p send queue fragment %p offset %zu length %zu",
                        (void *) fragmenter, (void *) message, (void *) fragment, offset, payloadLength);

        offset += payloadLength;

        memset(&header, 0, sizeof(header));
    }

    return (offset == length);
}
예제 #10
0
// There's a bit too much going on in this function, need to break it
// apart for testability and style.
static MetisPITVerdict
_metisStandardPIT_ReceiveInterest(MetisPIT *generic, MetisMessage *interestMessage)
{
    assertNotNull(generic, "Parameter pit must be non-null");
    assertNotNull(interestMessage, "Parameter interestMessage must be non-null");

    MetisStandardPIT *pit = metisPIT_Closure(generic);

    MetisPitEntry *pitEntry = metisMatchingRulesTable_Get(pit->table, interestMessage);

    if (pitEntry) {
        // has it expired?
        MetisTicks now = metisForwarder_GetTicks(pit->metis);
        if (now < metisPitEntry_GetExpiryTime(pitEntry)) {
            // what should we do about extending the lifetime? (case 819)

            _metisPIT_ExtendLifetime(pit, pitEntry, interestMessage);

            // Is the reverse path already in the PIT entry?
            if (_metisPIT_IngressSetContains(pitEntry, metisMessage_GetIngressConnectionId(interestMessage))) {
                // It is already in the PIT entry, so this is a retransmission, so forward it.

                if (metisLogger_IsLoggable(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
                    metisLogger_Log(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
                                    "Message %p existing entry (expiry %" PRIu64 ") and reverse path, forwarding",
                                    (void *) interestMessage,
                                    metisPitEntry_GetExpiryTime(pitEntry));
                }

                return MetisPITVerdict_Forward;
            }

            // It is in the PIT but this is the first interest for the reverse path
            metisPitEntry_AddIngressId(pitEntry, metisMessage_GetIngressConnectionId(interestMessage));

            if (metisLogger_IsLoggable(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
                metisLogger_Log(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
                                "Message %p existing entry (expiry %" PRIu64 ") and reverse path is new, aggregate",
                                (void *) interestMessage,
                                metisPitEntry_GetExpiryTime(pitEntry));
            }

            return MetisPITVerdict_Aggregate;
        }

        // it's an old entry, remove it
        metisMatchingRulesTable_RemoveFromBest(pit->table, interestMessage);
    }

    _metisPIT_StoreInTable(pit, interestMessage);

    return MetisPITVerdict_Forward;
}
예제 #11
0
static void
_conn_eventcb(PARCEventQueue *event, PARCEventQueueEventType events, void *ioOpsVoid)
{
    MetisIoOperations *ops = (MetisIoOperations *) ioOpsVoid;
    _MetisStreamState *stream = (_MetisStreamState *) metisIoOperations_GetClosure(ops);

    if (events & PARCEventQueueEventType_Connected) {
        if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info)) {
            metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__,
                            "Connection %u is connected", stream->id);
        }

        // if the stream was closed, do not transition to an UP state
        if (!stream->isClosed) {
            _setConnectionState(stream, true);
        }
    } else
    if (events & PARCEventQueueEventType_EOF) {
        if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info)) {
            metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__,
                            "connid %u closed.",
                            stream->id);
        }

        parcEventQueue_Disable(stream->bufferEventVector, PARCEventType_Read);

        _setConnectionState(stream, false);

        if (!stream->isClosed) {
            stream->isClosed = true;
            // this will cause the connection manager to destroy the connection later
            metisMessenger_Send(metisForwarder_GetMessenger(stream->metis), metisMissive_Create(MetisMissiveType_ConnectionClosed, stream->id));
        }
    } else
    if (events & PARCEventQueueEventType_Error) {
        if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Error)) {
            metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Error, __func__,
                            "Got an error on the connection %u: %s", stream->id, strerror(errno));
        }

        parcEventQueue_Disable(stream->bufferEventVector, PARCEventType_Read | PARCEventType_Write);

        _setConnectionState(stream, false);

        if (!stream->isClosed) {
            stream->isClosed = true;
            // this will cause the connection manager to destroy the connection later
            metisMessenger_Send(metisForwarder_GetMessenger(stream->metis), metisMissive_Create(MetisMissiveType_ConnectionClosed, stream->id));
        }
    }
    /* None of the other events can happen here, since we haven't enabled
     * timeouts */
}
예제 #12
0
MetisGenericEther *
metisGenericEther_Create(MetisForwarder *metis, const char *deviceName, uint16_t etherType)
{
    assertNotNull(metis, "Parameter metis must be non-null");

    // The Darwin generic ether allows a NULL device name, it is used in the unit tests.

    MetisGenericEther *ether = NULL;

    if (metisEthernet_IsValidEthertype(etherType)) {
        ether = parcObject_CreateInstance(MetisGenericEther);
        ether->ethertype = etherType;
        ether->logger = metisLogger_Acquire(metisForwarder_GetLogger(metis));
        ether->etherSocket = -1; // invalid valid
        ether->workBuffer = parcEventBuffer_Create();
        ether->macAddress = NULL;
        ether->mtu = metisSystem_InterfaceMtu(metis, deviceName);

        _darwinEthernet_SetInterfaceAddress(ether, deviceName);

        bool success = _darwinEthernet_SetupReceive(ether, deviceName);

        if (success) {
            if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Info)) {
                char *str = parcBuffer_ToHexString(ether->macAddress);
                metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__,
                                "GenericEther %p created on device %s (%s) for ethertype 0x%04x fd %d bufferLength %u mtu %u",
                                (void *) ether, deviceName, str, etherType, ether->etherSocket, ether->etherBufferLength, ether->mtu);
                parcMemory_Deallocate((void **) &str);
            }
        } else {
            if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Error)) {
                metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Error, __func__,
                                "GenericEther failed to created on device %s for ethertype 0x%04x",
                                deviceName, etherType);
            }

            // this will also null ether
            metisGenericEther_Release(&ether);
        }

        assertTrue(ether->etherBufferLength < 65536, "Buffer length way too big, expected less than 65536 got %u", ether->etherBufferLength);
    } else {
        if (metisLogger_IsLoggable(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Error)) {
            metisLogger_Log(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Error, __func__,
                            "GenericEther failed to created on device %s for ethertype 0x%04x, invalid ethertype",
                            deviceName, etherType);
        }
    }

    return ether;
}
예제 #13
0
static MetisMessage *
_metisLRUContentStore_MatchInterest(MetisContentStoreInterface *storeImpl, MetisMessage *interest)
{
    MetisMessage *result = NULL;

    _MetisLRUContentStore *store = (_MetisLRUContentStore *) metisContentStoreInterface_GetPrivateData(storeImpl);

    assertNotNull(store, "Parameter store must be non-null");
    assertNotNull(interest, "Parameter interestMessage must be non-null");
    assertTrue(metisMessage_GetType(interest) == MetisMessagePacketType_Interest,
               "Parameter interestMessage must be an Interest");

    // This will do the most restrictive lookup.
    // a) If the interest has a ContentObjectHash restriction, it will look only in the ByNameAndObjectHash table.
    // b) If it has a KeyId, it will look only in the ByNameAndKeyId table.
    // c) otherwise, it looks only in the ByName table.

    PARCHashCodeTable *table;
    if (metisMessage_HasContentObjectHash(interest)) {
        table = store->storageByNameAndObjectHashHash;
    } else if (metisMessage_HasKeyId(interest)) {
        table = store->indexByNameAndKeyIdHash;
    } else {
        table = store->indexByNameHash;
    }

    MetisContentStoreEntry *storeEntry = parcHashCodeTable_Get(table, interest);

    if (storeEntry) {
        metisContentStoreEntry_MoveToHead(storeEntry);
        result = metisContentStoreEntry_GetMessage(storeEntry);

        store->stats.countHits++;

        if (metisLogger_IsLoggable(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
            metisLogger_Log(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
                            "LRUContentStore %p matched interest %p (hits %" PRIu64 ", misses %" PRIu64 ")",
                            (void *) store, (void *) interest, store->stats.countHits, store->stats.countMisses);
        }
    } else {
        store->stats.countMisses++;

        if (metisLogger_IsLoggable(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
            metisLogger_Log(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
                            "LRUContentStore %p missed interest %p (hits %" PRIu64 ", misses %" PRIu64 ")",
                            (void *) store, (void *) interest, store->stats.countHits, store->stats.countMisses);
        }
    }

    return result;
}
예제 #14
0
static CCNxControl *
metisConfiguration_ProcessAddConnectionEthernet(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
{
    bool success = false;

    CPIConnectionEthernet *etherConn = cpiConnectionEthernet_FromControl(control);
    assertNotNull(etherConn, "Control message did not parse to CPIConnectionEthernet");

    if (cpiConnectionEthernet_GetEthertype(etherConn) == ETHERTYPE) {
        CPIAddress *linkAddress = metisSystem_GetMacAddressByName(config->metis, cpiConnectionEthernet_GetInterfaceName(etherConn));
        if (linkAddress != NULL) {
            MetisListenerSet *listenerSet = metisForwarder_GetListenerSet(config->metis);
            MetisListenerOps *listenerOps = metisListenerSet_Find(listenerSet, METIS_ENCAP_ETHER, linkAddress);

            if (listenerOps) {
                // Now add the connection
                success = _metisConfiguration_AddConnectionEthernet(config, etherConn, linkAddress, listenerOps);
            } else {
                char *str = cpiAddress_ToString(linkAddress);
                metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
                                "Could not find listener for interface '%s' addr %s ethertype 0x%04x",
                                cpiConnectionEthernet_GetInterfaceName(etherConn),
                                str,
                                cpiConnectionEthernet_GetEthertype(etherConn));
                parcMemory_Deallocate((void **) &str);
            }


            cpiAddress_Destroy(&linkAddress);
        } else {
            metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
                            "Could not resolve interface '%s' to a MAC address",
                            cpiConnectionEthernet_GetInterfaceName(etherConn));
        }
    } else {
        metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
                        "Control message asked for ethertype %04x, only %04x supported",
                        cpiConnectionEthernet_GetEthertype(etherConn), ETHERTYPE);
    }

    CCNxControl *response;
    if (success) {
        response = _createAck(config, control, ingressId);
    } else {
        response = _createNack(config, control, ingressId);
    }

    cpiConnectionEthernet_Release(&etherConn);
    return response;
}
예제 #15
0
/**
 * Receives a fragment and applies the protocol algorithm
 *
 * 1) A receiver maintains one reassembly queue per peer.
 * 2) Discard Idle fragments.
 * 3) Discard fragments until a 'B' fragment is received.  Store the received sequence number for this sender.
 * 4) If an out-of-order fragment is received next, discard the reassembly buffer and go to step (2).
 * 5) Continue receiving in-order fragments until the first 'E’ fragment.  At this time, the fragmented
 *    packet is fully re-assembled and may be passed on to the next layer.
 * 6) The receiver cannot assume it will receive the 'E' fragment or a subsequence 'I' frame, so it should
 *    use a timeout mechanism appropriate to the link to release allocated memory resources.
 *
 * @param [in] fragmenter An allocated MetisHopByHopFragmenter
 * @param [in] message The fragment packet
 *
 * Example:
 * @code
 * {
 *     <#example#>
 * }
 * @endcode
 */
static void
_receiveFragment(MetisHopByHopFragmenter *fragmenter, const MetisMessage *message)
{
    const _HopByHopHeader *fixedHeader = (const _HopByHopHeader *) metisMessage_FixedHeader(message);

    _applySequenceNumberRules(fragmenter, fixedHeader);

    // ======
    // Now apply the receiver rules


    switch (fragmenter->parserState) {
        case _ParserState_Idle:
            _receiveInIdleState(fragmenter, message, fixedHeader);
            break;

        case _ParserState_Busy:
            _receiveInBusyState(fragmenter, message, fixedHeader);
            break;

        default:
            metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Error, __func__,
                            "Fragmenter %p Invalid parser state, discarding current buffer and resetting to Idle: %d",
                            (void *) fragmenter, fragmenter->parserState);
            break;
    }
}
예제 #16
0
/*
 * In the Busy state, we can only accept a packet with no flag (middle) or end flag (end of packet).
 * Anything else is an error and will cause the parser to be reset.
 *
 * 1) If no flags
 * 1a) append to reassembly buffer
 * 2) If E flag
 * 2a) append to reassembly buffer
 * 2b) finalize the buffer (side effect: will reset the parser and place in receive queue)
 * 3) Otherwise, its an error, reset the parser
 *
 * PRECONDITION: you know the packet is in-order relative to the assembly buffer.
 * This is handled by calling _applySequenceNumberRules() before this function.
 * PRECONDITION: you know the parser is in the Busy state.
 */
static void
_receiveInBusyState(MetisHopByHopFragmenter *fragmenter, const MetisMessage *message, const _HopByHopHeader *fixedHeader)
{
    trapUnexpectedStateIf(fragmenter->parserState != _ParserState_Busy,
                          "Parser in wrong state, expected %d got %d",
                          _ParserState_Busy, fragmenter->parserState);

    if (_hopByHopHeader_GetFlags(fixedHeader) == 0) {
        // It's a middle packet

        _appendFragmentToReassemblyBuffer(fragmenter, message);
    } else if (_hopByHopHeader_GetEFlag(fixedHeader)) {
        // It is the last fragment

        _appendFragmentToReassemblyBuffer(fragmenter, message);

        _finalizeReassemblyBuffer(fragmenter);
    } else {
        // nothing we can do with this frame, and it's a state machine error

        metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__,
                        "Fragmenter %p received invalid headers (0x%02X) in Busy state, resetting",
                        (void *) fragmenter, _hopByHopHeader_GetFlags(fixedHeader));
        _resetParser(fragmenter);
    }
}
예제 #17
0
void
metisConfiguration_Receive(MetisConfiguration *config, MetisMessage *message)
{
    assertNotNull(config, "Parameter config must be non-null");
    assertNotNull(message, "Parameter message must be non-null");
    assertTrue(metisMessage_GetType(message) == MetisMessagePacketType_Control,
               "Message must be type CPI, expected %02x got %02x",
               MetisMessagePacketType_Control, metisMessage_GetType(message));

    CCNxControl *control = metisMessage_CreateControlMessage(message);
    unsigned ingressId = metisMessage_GetIngressConnectionId(message);

    if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug)) {
        char *str = parcJSON_ToCompactString(ccnxControl_GetJson(control));
        metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug, __func__,
                        "%s received %s\n", __func__, str);
        parcMemory_Deallocate((void **) &str);
    }

    CCNxControl *response = _processControl(config, control, ingressId);
    metisConfiguration_SendResponse(config, response, ingressId);
    ccnxControl_Release(&response);

    ccnxControl_Release(&control);
    metisMessage_Release(&message);
}
예제 #18
0
static void
_metisStreamConnection_DestroyOperations(MetisIoOperations **opsPtr)
{
    assertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer");
    assertNotNull(*opsPtr, "Parameter opsPtr must dereference to non-null pointer");

    MetisIoOperations *ops = *opsPtr;
    assertNotNull(metisIoOperations_GetClosure(ops), "ops->context must not be null");

    _MetisStreamState *stream = (_MetisStreamState *) metisIoOperations_GetClosure(ops);

    parcEventQueue_Destroy(&stream->bufferEventVector);

    metisAddressPair_Release(&stream->addressPair);

    if (!stream->isClosed) {
        stream->isClosed = true;
        metisMessenger_Send(metisForwarder_GetMessenger(stream->metis), metisMissive_Create(MetisMissiveType_ConnectionClosed, stream->id));
    }

    metisMessenger_Send(metisForwarder_GetMessenger(stream->metis), metisMissive_Create(MetisMissiveType_ConnectionDestroyed, stream->id));

    if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info)) {
        metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__,
                        "StreamConnection %p destroyed", (void *) stream);
    }

    metisLogger_Release(&stream->logger);
    parcMemory_Deallocate((void **) &stream);
    parcMemory_Deallocate((void **) &ops);

    *opsPtr = NULL;
}
예제 #19
0
bool
metisTlvSkeleton_Parse(MetisTlvSkeleton *opaque, uint8_t *packet, MetisLogger *logger)
{
    // do not assert invariants here.  Parse will setup the invariants.
    _InternalSkeleton *skeleton = (_InternalSkeleton *) opaque;
    uint8_t version = packet[0];

    switch (version) {
        case 0:
            _initialize(skeleton, &MetisTlvSchemaV0_Ops, packet, logger);
            return MetisTlvSchemaV0_Ops.parse(opaque);

        case 1:
            _initialize(skeleton, &MetisTlvSchemaV1_Ops, packet, logger);
            return MetisTlvSchemaV1_Ops.parse(opaque);

        default:
            if (metisLogger_IsLoggable(logger, MetisLoggerFacility_Message, PARCLogLevel_Warning)) {
                metisLogger_Log(logger, MetisLoggerFacility_Message, PARCLogLevel_Warning, __func__,
                                "Parsing unknown packet version %u", version);
            }
            break;
    }
    return false;
}
예제 #20
0
MetisPIT *
metisStandardPIT_Create(MetisForwarder *metis)
{
    assertNotNull(metis, "Parameter must be non-null");

    size_t allocation = sizeof(MetisPIT) + sizeof(MetisStandardPIT);

    MetisPIT *generic = parcMemory_AllocateAndClear(allocation);
    assertNotNull(generic, "parcMemory_AllocateAndClear(%zu) returned NULL", allocation);
    generic->closure = (uint8_t *) generic + sizeof(MetisPIT);

    MetisStandardPIT *pit = metisPIT_Closure(generic);
    pit->metis = metis;
    pit->logger = metisLogger_Acquire(metisForwarder_GetLogger(metis));
    pit->table = metisMatchingRulesTable_Create(_metisPIT_PitEntryDestroyer);

    if (metisLogger_IsLoggable(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
        metisLogger_Log(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
                        "PIT %p created",
                        (void *) pit);
    }

    generic->getPitEntry = _metisStandardPIT_GetPitEntry;
    generic->receiveInterest = _metisStandardPIT_ReceiveInterest;
    generic->release = _metisStandardPIT_Destroy;
    generic->removeInterest = _metisStandardPIT_RemoveInterest;
    generic->satisfyInterest = _metisStandardPIT_SatisfyInterest;

    return generic;
}
예제 #21
0
static void
_appendFragmentToReassemblyBuffer(MetisHopByHopFragmenter *fragmenter, const MetisMessage *message)
{
    size_t length = metisMessage_AppendFragmentPayload(message, fragmenter->currentReceiveBuffer);
    metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                    "Fragmenter %p append %zu bytes to reassembly buffer",
                    (void *) fragmenter, length);
}
예제 #22
0
/**
 * @function metisStreamConnection_Send
 * @abstract Non-destructive send of the message.
 * @discussion
 *   Send uses metisMessage_CopyToStreamBuffer, which is a non-destructive write.
 *   The send may fail if there's no buffer space in the output queue.
 *
 * @param dummy is ignored.  A stream has only one peer.
 * @return <#return#>
 */
static bool
_metisStreamConnection_Send(MetisIoOperations *ops, const CPIAddress *dummy, MetisMessage *message)
{
    assertNotNull(ops, "Parameter ops must be non-null");
    assertNotNull(message, "Parameter message must be non-null");
    _MetisStreamState *stream = (_MetisStreamState *) metisIoOperations_GetClosure(ops);

    bool success = false;
    if (stream->isUp) {
        PARCEventBuffer *buffer = parcEventBuffer_GetQueueBufferOutput(stream->bufferEventVector);
        size_t buffer_backlog = parcEventBuffer_GetLength(buffer);
        parcEventBuffer_Destroy(&buffer);

        if (buffer_backlog < OUTPUT_QUEUE_BYTES) {
            if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) {
                metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                                "connid %u Writing %zu bytes to buffer with backlog %zu bytes",
                                stream->id,
                                metisMessage_Length(message),
                                buffer_backlog);
            }

            int failure = metisMessage_Write(stream->bufferEventVector, message);
            if (failure == 0) {
                success = true;
            }
        } else {
            if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning)) {
                metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__,
                                "connid %u Writing to buffer backlog %zu bytes DROP MESSAGE",
                                stream->id,
                                buffer_backlog);
            }
        }
    } else {
        if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Error)) {
            metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Error, __func__,
                            "connid %u tried to send to down connection (isUp %d isClosed %d)",
                            stream->id,
                            stream->isUp,
                            stream->isClosed);
        }
    }

    return success;
}
예제 #23
0
static void
_evictByStorePolicy(_MetisLRUContentStore *store, uint64_t currentTimeInMetisTicks)
{
    // We need to make room. Here's the plan:
    //  1) Check to see if anything has expired. If so, remove it and we're done. If not,
    //  2) Check to see if anything has exceeded it's recommended cache time. If so, remove it and we're done. If not,
    //  3) Remove the least recently used item.

    MetisContentStoreEntry *entry = metisTimeOrderedList_GetOldest(store->indexByExpirationTime);
    if (entry
        && metisContentStoreEntry_HasExpiryTimeTicks(entry)
        && (currentTimeInMetisTicks > metisContentStoreEntry_GetExpiryTimeTicks(entry))) {
        // Found an expired entry. Remove it, and we're done.

        store->stats.countExpiryEvictions++;
        if (metisLogger_IsLoggable(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
            metisLogger_Log(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
                            "ContentStore %p evict message %p by ExpiryTime (ExpiryTime evictions %" PRIu64 ")",
                            (void *) store, (void *) metisContentStoreEntry_GetMessage(entry),
                            store->stats.countExpiryEvictions);
        }

        _metisLRUContentStore_PurgeStoreEntry(store, entry);
    } else {
        // Check for entries that have exceeded RCT
        entry = metisTimeOrderedList_GetOldest(store->indexByRecommendedCacheTime);
        if (entry
            && metisContentStoreEntry_HasRecommendedCacheTimeTicks(entry)
            && (currentTimeInMetisTicks > metisContentStoreEntry_GetRecommendedCacheTimeTicks(entry))) {
            // Found an entry passed it's RCT. Remove it, and we're done.

            store->stats.countRCTEvictions++;
            if (metisLogger_IsLoggable(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
                metisLogger_Log(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
                                "ContentStore %p evict message %p by RCT (RCT evictions %" PRIu64 ")",
                                (void *) store, (void *) metisContentStoreEntry_GetMessage(entry),
                                store->stats.countRCTEvictions);
            }

            _metisLRUContentStore_PurgeStoreEntry(store, entry);
        } else {
            store->stats.countLruEvictions++;
            _metisLRUContentStore_RemoveLeastUsed(store);
        }
    }
}
예제 #24
0
MetisConfigurationFile *
metisConfigurationFile_Create(MetisForwarder *metis, const char *filename)
{
    assertNotNull(metis, "Parameter metis must be non-null");
    assertNotNull(filename, "Parameter filename must be non-null");

    MetisConfigurationFile *configFile = parcObject_CreateInstance(MetisConfigurationFile);

    if (configFile) {
        configFile->linesRead = 0;
        configFile->metis = metis;
        configFile->filename = parcMemory_StringDuplicate(filename, strlen(filename));
        assertNotNull(configFile->filename, "Could not copy string '%s'", filename);

        // setup the control state for the command parser
        configFile->controlState = metisControlState_Create(configFile, _writeRead);

        // we do not register Help commands
        metisControlState_RegisterCommand(configFile->controlState, metisControlRoot_Create(configFile->controlState));

        // open the file and make sure we can read it
        configFile->fh = fopen(configFile->filename, "r");

        if (configFile->fh) {
            if (metisLogger_IsLoggable(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug)) {
                metisLogger_Log(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug, __func__,
                                "Open config file %s",
                                configFile->filename);
            }
        } else {
            if (metisLogger_IsLoggable(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Error)) {
                metisLogger_Log(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
                                "Could not open config file %s: (%d) %s",
                                configFile->filename,
                                errno,
                                strerror(errno));
            }

            // failure cleanup the object -- this nulls it so final return null be NULL
            metisConfigurationFile_Release(&configFile);
        }
    }
    return configFile;
}
예제 #25
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;
}
예제 #26
0
void
metisTlvSkeleton_SetFragmentPayload(MetisTlvSkeleton *opaque, size_t offset, size_t length)
{
    _InternalSkeleton *skeleton = (_InternalSkeleton *) opaque;
    skeleton->array[INDEX_FRAGMENTPAYLOAD].offset = offset;
    skeleton->array[INDEX_FRAGMENTPAYLOAD].length = length;

    if (metisLogger_IsLoggable(skeleton->logger, MetisLoggerFacility_Message, PARCLogLevel_Debug)) {
        metisLogger_Log(skeleton->logger, MetisLoggerFacility_Message, PARCLogLevel_Debug, __func__,
                        "Set fragment payload extent {%u, %u}", offset, length);
    }
}
예제 #27
0
void
metisTlvSkeleton_SetCPI(MetisTlvSkeleton *opaque, size_t offset, size_t length)
{
    _InternalSkeleton *skeleton = (_InternalSkeleton *) opaque;
    skeleton->array[INDEX_CPI].offset = offset;
    skeleton->array[INDEX_CPI].length = length;

    if (metisLogger_IsLoggable(skeleton->logger, MetisLoggerFacility_Message, PARCLogLevel_Debug)) {
        metisLogger_Log(skeleton->logger, MetisLoggerFacility_Message, PARCLogLevel_Debug, __func__,
                        "Set cpi extent {%u, %u}", offset, length);
    }
}
예제 #28
0
/**
 * @function single_read
 * @abstract Read at most 1 message from the network
 * @discussion
 *   If a complete message is ready on the input buffer, will allocate and return it.
 *
 *   This function manipulates the stream->nextMessageLength.  (1) Initializes with nextMessageLength = 0,
 *   which means we have not started parsing a packet.  (2) After reading a FixedHeader, set nextMessageLength
 *   to the total length of the message.  (3) After reading nextMessageLength bytes, return the outputBuffer
 *   and reset nextMessageLength to 0.
 *
 * @param input is the PARCEventBuffer to read
 * @param stream is the related stream state for the input
 * @return true if there's more to read after this message.
 */
static MetisMessage *
_single_read(PARCEventBuffer *input, _MetisStreamState *stream)
{
    size_t bytesAvailable = parcEventBuffer_GetLength(input);

    assertTrue(bytesAvailable >= metisTlv_FixedHeaderLength(), "Called with too short an input: %zu", bytesAvailable);

    if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) {
        metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                        "connid %u read %zu bytes",
                        stream->id, bytesAvailable);
    }

    if (stream->nextMessageLength == 0) {
        _startNewMessage(stream, input, bytesAvailable);
    }

    // This is not an ELSE statement.  We can both start a new message then
    // check if there's enough bytes to read the whole thing.

    if (bytesAvailable >= stream->nextMessageLength) {
        MetisMessage *message = _readMessage(stream, metisForwarder_GetTicks(stream->metis), input);

        if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) {
            metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                            "connid %u msg_length %zu read_length %zu, resetting parser",
                            stream->id,
                            stream->nextMessageLength,
                            bytesAvailable);
        }

        // now reset message length for next packet
        stream->nextMessageLength = 0;

        return message;
    }

    return NULL;
}
예제 #29
0
bool
metisHopByHopFragmenter_Receive(MetisHopByHopFragmenter *fragmenter, const MetisMessage *message)
{
    if (metisMessage_GetType(message) == MetisMessagePacketType_HopByHopFrag) {
        _receiveFragment(fragmenter, message);
    } else {
        // put the whole thing on the output queue
        MetisMessage *copy = metisMessage_Acquire(message);
        bool putSuccess = parcRingBuffer1x1_Put(fragmenter->receiveQueue, copy);
        if (!putSuccess) {
            metisMessage_Release(&copy);
            metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__,
                            "Failed to add message %p to receive queue", (void *) message);
        } else {
            if (metisLogger_IsLoggable(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) {
                metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__,
                                "Add message %p to receive queue", (void *) message);
            }
        }
    }

    // the maximum remaining is its capacity - 1
    return (parcRingBuffer1x1_Remaining(fragmenter->receiveQueue) < fragmenter->receiveQueueCapacity - 1);
}
예제 #30
0
static void
_metisStandardPIT_RemoveInterest(MetisPIT *generic, const MetisMessage *interestMessage)
{
    assertNotNull(generic, "Parameter pit must be non-null");
    assertNotNull(interestMessage, "Parameter interestMessage must be non-null");

    MetisStandardPIT *pit = metisPIT_Closure(generic);

    if (metisLogger_IsLoggable(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
        metisLogger_Log(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
                        "Message %p removed from PIT",
                        (void *) interestMessage);
    }

    metisMatchingRulesTable_RemoveFromBest(pit->table, interestMessage);
}