static PARCBuffer *
_iovecToParcBuffer(const CCNxCodecNetworkBufferIoVec *iovec)
{
    PARCBuffer *result = NULL;

    size_t iovcnt = ccnxCodecNetworkBufferIoVec_GetCount((CCNxCodecNetworkBufferIoVec *) iovec);
    const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray((CCNxCodecNetworkBufferIoVec *) iovec);

    size_t totalbytes = 0;
    for (int i = 0; i < iovcnt; i++) {
        totalbytes += array[i].iov_len;
    }

    result = parcBuffer_Allocate(totalbytes);
    for (int i = 0; i < iovcnt; i++) {
        parcBuffer_PutArray(result, array[i].iov_len, array[i].iov_base);
    }

    parcBuffer_Flip(result);


    return result;
}
Пример #2
0
PARCBuffer *
athenaTransportLinkModule_CreateMessageBuffer(CCNxMetaMessage *message)
{
    PARCBuffer *buffer = ccnxWireFormatMessage_GetWireFormatBuffer(message);

    // If there is no PARCBuffer present, check for an IO vector and convert that into a contiguous buffer.
    if (buffer == NULL) {
        CCNxCodecNetworkBufferIoVec *iovec = ccnxWireFormatMessage_GetIoVec(message);
        if (iovec == NULL) { // if there's no iovec or buffer, encode the message and return the iovec
            athena_EncodeMessage(message);
            iovec = ccnxWireFormatMessage_GetIoVec(message);
        }
        assertNotNull(iovec, "Null io vector");
        size_t iovcnt = ccnxCodecNetworkBufferIoVec_GetCount((CCNxCodecNetworkBufferIoVec *) iovec);
        const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray((CCNxCodecNetworkBufferIoVec *) iovec);

        // If it's a single vector wrap it in a buffer to avoid a copy
        if (iovcnt == 1) {
            buffer = parcBuffer_Wrap(array[0].iov_base, array[0].iov_len, 0, array[0].iov_len);
        } else {
            size_t totalbytes = 0;
            for (int i = 0; i < iovcnt; i++) {
                totalbytes += array[i].iov_len;
            }
            buffer = parcBuffer_Allocate(totalbytes);
            for (int i = 0; i < iovcnt; i++) {
                parcBuffer_PutArray(buffer, array[i].iov_len, array[i].iov_base);
            }
            parcBuffer_Flip(buffer);
        }
    } else {
        buffer = parcBuffer_Acquire(buffer);
    }

    return buffer;
}
Пример #3
0
static int
_UDPSend(AthenaTransportLink *athenaTransportLink, CCNxMetaMessage *ccnxMetaMessage)
{
    struct _UDPLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink);

    if (ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage) == CCNxTlvDictionary_SchemaVersion_V0) {
        parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink),
                      "sending deprecated version %d message\n", ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage));
    }

    // Get a wire format buffer and write it out.
    PARCBuffer *wireFormatBuffer = ccnxWireFormatMessage_GetWireFormatBuffer(ccnxMetaMessage);

    if (wireFormatBuffer == NULL) {
        CCNxCodecNetworkBufferIoVec *iovec = ccnxWireFormatMessage_GetIoVec(ccnxMetaMessage);
        assertNotNull(iovec, "Null io vector");

        size_t iovcnt = ccnxCodecNetworkBufferIoVec_GetCount((CCNxCodecNetworkBufferIoVec *) iovec);
        const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray((CCNxCodecNetworkBufferIoVec *) iovec);

        // If it's a single vector wrap it in a buffer to avoid a copy
        if (iovcnt == 1) {
            wireFormatBuffer = parcBuffer_Wrap(array[0].iov_base, array[0].iov_len, 0, array[0].iov_len);
        } else {
            size_t totalbytes = 0;
            for (int i = 0; i < iovcnt; i++) {
                totalbytes += array[i].iov_len;
            }
            wireFormatBuffer = parcBuffer_Allocate(totalbytes);
            for (int i = 0; i < iovcnt; i++) {
                parcBuffer_PutArray(wireFormatBuffer, array[i].iov_len, array[i].iov_base);
            }
            parcBuffer_Flip(wireFormatBuffer);
        }
    } else {
        wireFormatBuffer = parcBuffer_Acquire(wireFormatBuffer);
    }

    size_t length = parcBuffer_Limit(wireFormatBuffer);
    char *buffer = parcBuffer_Overlay(wireFormatBuffer, length);

    if (linkData->link.mtu) {
        if (length > linkData->link.mtu) {
            errno = EMSGSIZE;
            parcBuffer_Release(&wireFormatBuffer);
            return -1;
        }
    }

    parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink),
                  "sending message (size=%d)", length);

    ssize_t writeCount = 0;
#ifdef LINUX_IGNORESIGPIPE
    writeCount = sendto(linkData->fd, buffer, length, MSG_NOSIGNAL,
                        (struct sockaddr *) &linkData->link.peerAddress, linkData->link.peerAddressLength);
#else
    writeCount = sendto(linkData->fd, buffer, length, 0,
                        (struct sockaddr *) &linkData->link.peerAddress, linkData->link.peerAddressLength);
#endif

    // on error close the link, else return to retry a zero write
    if (writeCount == -1) {
        if (errno == EPIPE) {
            athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Error);
        }
        parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink),
                      "send error (%s)", strerror(errno));
        parcBuffer_Release(&wireFormatBuffer);
        return -1;
    }

    // Short write
    if (writeCount != length) {
        linkData->_stats.receive_ShortWrite++;
        parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "short write");
        parcBuffer_Release(&wireFormatBuffer);
        return -1;
    }

    parcBuffer_Release(&wireFormatBuffer);
    return 0;
}
static int
_ETHSend(AthenaTransportLink *athenaTransportLink, CCNxMetaMessage *ccnxMetaMessage)
{
    struct _ETHLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink);

    if (ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage) == CCNxTlvDictionary_SchemaVersion_V0) {
        parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink),
                      "sending deprecated version %d message\n", ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage));
    }

    // Construct our header to prepend
    struct ether_header header;
    memcpy(header.ether_shost, &(linkData->link.myAddress), ETHER_ADDR_LEN * sizeof(uint8_t));
    memcpy(header.ether_dhost, &(linkData->link.peerAddress), ETHER_ADDR_LEN * sizeof(uint8_t));
    header.ether_type = htons(athenaEthernet_GetEtherType(linkData->athenaEthernet));

    // An iovec to contain the header and packet data
    struct iovec iov[2];
    struct iovec *array = iov;
    int iovcnt = 2;
    size_t messageLength = 0;

    // If the iovec we're prepending to has more than one element, allocatedIovec holds the
    // allocated IO vector of the right size that we must deallocate before returning.
    struct iovec *allocatedIovec = NULL;

    // Attach the header and populate the iovec

    CCNxCodecNetworkBufferIoVec *iovec = athenaTransportLinkModule_GetMessageIoVector(ccnxMetaMessage);

    iovcnt = ccnxCodecNetworkBufferIoVec_GetCount((CCNxCodecNetworkBufferIoVec *) iovec);
    const struct iovec *networkBufferIovec = ccnxCodecNetworkBufferIoVec_GetArray((CCNxCodecNetworkBufferIoVec *) iovec);

    // Trivial case, single iovec element.
    if (iovcnt == 1) {
        // Header
        array[0].iov_len = sizeof(struct ether_header);
        array[0].iov_base = &header;

        // Message content
        array[1].iov_len = networkBufferIovec->iov_len;
        array[1].iov_base = networkBufferIovec->iov_base;
        messageLength = array[0].iov_len + array[1].iov_len;
    } else {
        // Allocate a new iovec if more than one vector
        allocatedIovec = parcMemory_Allocate(sizeof(struct iovec) * (iovcnt + 1));
        array = allocatedIovec;

        // Header
        array[0].iov_len = sizeof(struct ether_header);
        array[0].iov_base = &header;
        messageLength = array[0].iov_len;

        // Append message content
        for (int i = 0; i < iovcnt; i++) {
            array[i + 1].iov_len = networkBufferIovec[i].iov_len;
            array[i + 1].iov_base = networkBufferIovec[i].iov_base;
            messageLength += array[i + 1].iov_len;
        }
    }
    iovcnt++; // increment for the header

    if (linkData->link.mtu) {
        if (messageLength > linkData->link.mtu) {
            if (allocatedIovec != NULL) {
                parcMemory_Deallocate(&allocatedIovec);
            }
            ccnxCodecNetworkBufferIoVec_Release(&iovec);
            errno = EMSGSIZE;
            return -1;
        }
    }

    parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink),
                  "sending message (size=%d)", messageLength);

    ssize_t writeCount = 0;
    writeCount = athenaEthernet_Send(linkData->athenaEthernet, array, iovcnt);
    ccnxCodecNetworkBufferIoVec_Release(&iovec);

    // Free up any storage allocated for a non-singular iovec
    if (allocatedIovec != NULL) {
        parcMemory_Deallocate(&allocatedIovec);
        array = NULL;
    }

    // on error close the link, else return to retry a zero write
    if (writeCount == -1) {
        if ((errno == EAGAIN) || (errno == EINTR)) {
            parcLog_Info(athenaTransportLink_GetLogger(athenaTransportLink), "send retry");
            linkData->_stats.send_Retry++;
            return -1;
        }
        athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Error);

        parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink),
                      "send error (%s)", strerror(errno));
        linkData->_stats.send_Error++;
        return -1;
    }

    // Short write
    if (writeCount != messageLength) {
        linkData->_stats.send_ShortWrite++;
        parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "short write");
        return -1;
    }

    return 0;
}