Exemple #1
0
static PARCBuffer *
_encodeControlPlaneInformation(const CCNxControl *cpiControlMessage)
{
    PARCJSON *json = ccnxControl_GetJson(cpiControlMessage);
    char *str = parcJSON_ToCompactString(json);

    // include +1 because we need the NULL byte
    size_t len = strlen(str) + 1;

    size_t packetLength = sizeof(_MetisTlvFixedHeaderV0) + sizeof(MetisTlvType) + len;
    PARCBuffer *packet = parcBuffer_Allocate(packetLength);

    _MetisTlvFixedHeaderV0 hdr;
    memset(&hdr, 0, sizeof(hdr));
    hdr.version = 0;
    hdr.packetType = METIS_PACKET_TYPE_CONTROL;
    hdr.payloadLength = htons(len + sizeof(MetisTlvType));

    parcBuffer_PutArray(packet, sizeof(hdr), (uint8_t *) &hdr);

    MetisTlvType tlv = { .type = htons(T_CPI), .length = htons(len) };
    parcBuffer_PutArray(packet, sizeof(tlv), (uint8_t *) &tlv);

    parcBuffer_PutArray(packet, len, (uint8_t *) str);

    parcMemory_Deallocate((void **) &str);
    return parcBuffer_Flip(packet);
}
Exemple #2
0
/**
 * If the user specified a device name, set the MAC address in ether->macAddress
 *
 * <#Paragraphs Of Explanation#>
 *
 * @param [in] ether An allocated MetisGenericEther
 * @param [in] devstr A C-String of the device name
 *
 * Example:
 * @code
 * <#example#>
 * @endcode
 */
static void
_darwinEthernet_SetInterfaceAddress(MetisGenericEther *ether, const char *devstr)
{
    if (devstr) {
        struct ifaddrs *ifaddr;
        int failure = getifaddrs(&ifaddr);
        assertFalse(failure, "Error getifaddrs: (%d) %s", errno, strerror(errno));

        struct ifaddrs *next;
        for (next = ifaddr; next != NULL; next = next->ifa_next) {
            if (strcmp(next->ifa_name, devstr) == 0) {
                if (next->ifa_addr->sa_family == AF_LINK) {
                    struct sockaddr_dl *addr_dl = (struct sockaddr_dl *) next->ifa_addr;

                    // addr_dl->sdl_data[12] contains the interface name followed by the MAC address, so
                    // need to offset in to the array past the interface name.
                    PARCBuffer *addr = parcBuffer_Allocate(addr_dl->sdl_alen);
                    parcBuffer_PutArray(addr, addr_dl->sdl_alen, (uint8_t *) &addr_dl->sdl_data[ addr_dl->sdl_nlen]);
                    parcBuffer_Flip(addr);
                    ether->macAddress = addr;

                    // break out of loop and freeifaddrs
                    break;
                }
            }
        }
        freeifaddrs(ifaddr);
    }
}
LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Write)
{
    char *fname = "tmpfile";

    PARCFile *file = parcFile_Create(fname);

    parcFile_CreateNewFile(file);

    uint8_t data[128];
    for (int i = 0; i < 128; i++) {
        data[i] = i;
    }

    PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
    PARCBuffer *buffer = parcBuffer_Allocate(128);
    parcBuffer_PutArray(buffer, 128, data);
    parcBuffer_Flip(buffer);
    size_t numBytes = parcRandomAccessFile_Write(instance, buffer);
    assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes);
    parcBuffer_Release(&buffer);

    parcRandomAccessFile_Close(instance);
    parcRandomAccessFile_Release(&instance);

    uint8_t bytes[128];
    FILE *fp = fopen(fname, "r");
    numBytes = fread(bytes, 1, 128, fp);
    assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes);

    fclose(fp);

    assertTrue(memcmp(data, bytes, 128) == 0, "Expected buffers to be equal");

    parcFile_Release(&file);
}
static PARCBuffer *
_createDerivedKey(const char *key, size_t keylength, unsigned char *salt, unsigned int saltlen)
{
    unsigned char buffer[SHA256_DIGEST_LENGTH];
    HMAC(EVP_sha256(), key, (int) keylength, salt, saltlen, buffer, NULL);
    return parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, buffer);
}
Exemple #5
0
LONGBOW_TEST_CASE(Global, parcSignature_Equals)
{
    PARCBuffer *bits = parcBuffer_Allocate(10); // arbitrary bufer size -- not important
    PARCBuffer *otherBits = parcBuffer_Allocate(strlen("hello"));
    parcBuffer_PutArray(otherBits, strlen("hello"), (uint8_t *) "hello");

    PARCSignature *x = parcSignature_Create(PARCSigningAlgorithm_DSA, PARC_HASH_SHA256, bits);
    PARCSignature *y = parcSignature_Create(PARCSigningAlgorithm_DSA, PARC_HASH_SHA256, bits);
    PARCSignature *z = parcSignature_Create(PARCSigningAlgorithm_DSA, PARC_HASH_SHA256, bits);
    PARCSignature *unequal1 = parcSignature_Create(PARCSigningAlgorithm_HMAC, PARC_HASH_SHA256, bits);
    PARCSignature *unequal2 = parcSignature_Create(PARCSigningAlgorithm_DSA, PARC_HASH_CRC32C, bits);
    PARCSignature *unequal3 = parcSignature_Create(PARCSigningAlgorithm_DSA, PARC_HASH_SHA256, otherBits);

    parcObjectTesting_AssertEqualsFunction(parcSignature_Equals, x, y, z, unequal1, unequal2, unequal3, NULL);

    parcSignature_Release(&x);
    parcSignature_Release(&y);
    parcSignature_Release(&z);
    parcSignature_Release(&unequal1);
    parcSignature_Release(&unequal2);
    parcSignature_Release(&unequal3);

    parcBuffer_Release(&bits);
    parcBuffer_Release(&otherBits);
}
Exemple #6
0
static PARCSignature *
_SignDigest(PARCPublicKeySigner *signer, const PARCCryptoHash *digestToSign)
{
    parcSecurity_AssertIsInitialized();

    assertNotNull(signer, "Parameter must be non-null CCNxFileKeystore");
    assertNotNull(digestToSign, "Buffer to sign must not be null");

    // TODO: what is the best way to expose this?
    PARCKeyStore *keyStore = signer->keyStore;
    PARCBuffer *privateKeyBuffer = parcKeyStore_GetDEREncodedPrivateKey(keyStore);
    EVP_PKEY *privateKey = NULL;
    size_t keySize = parcBuffer_Remaining(privateKeyBuffer);
    uint8_t *bytes = parcBuffer_Overlay(privateKeyBuffer, keySize);
    privateKey = d2i_PrivateKey(EVP_PKEY_RSA, &privateKey, (const unsigned char **) &bytes, keySize);
    parcBuffer_Release(&privateKeyBuffer);

    RSA *rsa = EVP_PKEY_get1_RSA(privateKey);

    int opensslDigestType;

    switch (parcCryptoHash_GetDigestType(digestToSign)) {
        case PARCCryptoHashType_SHA256:
            opensslDigestType = NID_sha256;
            break;
        case PARCCryptoHashType_SHA512:
            opensslDigestType = NID_sha512;
            break;
        default:
            trapUnexpectedState("Unknown digest type: %s",
                                parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(digestToSign)));
    }

    uint8_t *sig = parcMemory_Allocate(RSA_size(rsa));
    assertNotNull(sig, "parcMemory_Allocate(%u) returned NULL", RSA_size(rsa));

    unsigned sigLength = 0;
    PARCBuffer *bb_digest = parcCryptoHash_GetDigest(digestToSign);
    int result = RSA_sign(opensslDigestType,
                          (unsigned char *) parcByteArray_Array(parcBuffer_Array(bb_digest)),
                          (int) parcBuffer_Remaining(bb_digest),
                          sig,
                          &sigLength,
                          rsa);
    assertTrue(result == 1, "Got error from RSA_sign: %d", result);
    RSA_free(rsa);

    PARCBuffer *bbSign = parcBuffer_Allocate(sigLength);
    parcBuffer_Flip(parcBuffer_PutArray(bbSign, sigLength, sig));
    parcMemory_Deallocate((void **) &sig);

    PARCSignature *signature =
    parcSignature_Create(_GetSigningAlgorithm(signer),
                         parcCryptoHash_GetDigestType(digestToSign),
                         bbSign
                         );
    parcBuffer_Release(&bbSign);
    return signature;
}
/**
 * Create a symmetric (secret) key of the given bit length (e.g. 256)
 *
 * Example:
 * @code
 * <#example#>
 * @endcode
 */
PARCBuffer *
parcSymmetricSignerFileStore_CreateKey(unsigned bits)
{
    assertTrue((bits & 0x07) == 0, "bits must be a multiple of 8");

    unsigned keylength = bits / 8;
    uint8_t buffer[keylength];
    RAND_bytes(buffer, keylength);
    return parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(keylength), keylength, buffer));
}
static PARCCryptoHash *
_GetPublickKeyDigest(PARCPkcs12KeyStore *keystore)
{
    parcSecurity_AssertIsInitialized();

    assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");

    if (keystore->public_key_digest == NULL) {
        AUTHORITY_KEYID  *akid = X509_get_ext_d2i(keystore->x509_cert, NID_authority_key_identifier, NULL, NULL);
        if (akid != NULL) {
            ASN1_OCTET_STRING *skid = X509_get_ext_d2i(keystore->x509_cert, NID_subject_key_identifier, NULL, NULL);
            if (skid != NULL) {
                keystore->public_key_digest =
                    parcBuffer_PutArray(parcBuffer_Allocate(skid->length), skid->length, skid->data);
                parcBuffer_Flip(keystore->public_key_digest);
                ASN1_OCTET_STRING_free(skid);
            }
            AUTHORITY_KEYID_free(akid);
        }
    }

    // If we could not load the digest from the certificate, then calculate it from the public key.
    if (keystore->public_key_digest == NULL) {
        uint8_t digestBuffer[SHA256_DIGEST_LENGTH];

        int result = ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY),
                                      EVP_sha256(),
                                      X509_get_X509_PUBKEY(keystore->x509_cert),
                                      digestBuffer,
                                      NULL);
        if (result != 1) {
            assertTrue(0, "Could not compute digest over certificate public key");
        } else {
            keystore->public_key_digest =
                parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, digestBuffer);
            parcBuffer_Flip(keystore->public_key_digest);
        }
    }

    // This stores a reference, so keystore->public_key_digest will remain valid
    // even if the cryptoHasher is destroyed
    return parcCryptoHash_Create(PARC_HASH_SHA256, keystore->public_key_digest);
}
Exemple #9
0
PARCBuffer *
parcBuffer_CreateFromArray(const void *bytes, const size_t length)
{
    assertTrue(length == 0 || bytes != NULL,
               "If the byte array is NULL, then length MUST be zero.");

    PARCBuffer *result = parcBuffer_Allocate(length);
    parcBuffer_PutArray(result, length, bytes);

    return result;
}
CCNxNameSegment *
ccnxNameSegment_CreateTypeValueArray(CCNxNameLabelType type, size_t length, const char array[length])
{
    PARCBuffer *value = parcBuffer_PutArray(parcBuffer_Allocate(length), length, (const uint8_t *) array);
    parcBuffer_Flip(value);

    CCNxNameSegment *result = ccnxNameSegment_CreateTypeValue(type, value);
    parcBuffer_Release(&value);

    return result;
}
Exemple #11
0
LONGBOW_TEST_CASE(Global, parcSignature_GetSignature)
{
    PARCBuffer *expected = parcBuffer_Allocate(strlen("Hello"));
    parcBuffer_PutArray(expected, strlen("Hello"), (uint8_t *) "Hello");
    PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_DSA, PARC_HASH_SHA256, expected);

    PARCBuffer *actual = parcSignature_GetSignature(signature);

    assertTrue(parcBuffer_Equals(expected, actual), "Expected the original signature bits to be equal to the actual bits");
    parcSignature_Release(&signature);
    parcBuffer_Release(&expected);
}
Exemple #12
0
PARCBuffer *
parcBuffer_AllocateCString(const char *string)
{
    size_t length = strlen(string);
    PARCBuffer *buffer = parcBuffer_Allocate(length + 1);
    parcBuffer_PutArray(buffer, length, (const uint8_t *) string);
    parcBuffer_PutUint8(buffer, 0);
    parcBuffer_SetPosition(buffer, buffer->position - 1);
    parcBuffer_Flip(buffer);

    return buffer;
}
static PARCBuffer*
_hmacFinalize(void *ctx)
{
    uint8_t buffer[EVP_MAX_MD_SIZE];
    unsigned length;
    HMAC_Final(ctx, buffer, &length);

    PARCBuffer *output = parcBuffer_Allocate(length);
    parcBuffer_PutArray(output, length, buffer);

    return output;
}
Exemple #14
0
LONGBOW_TEST_CASE(Global, parcSignature_GetHashType)
{
    PARCBuffer *bits = parcBuffer_Allocate(strlen("Hello"));
    parcBuffer_PutArray(bits, strlen("Hello"), (uint8_t *) "Hello");
    PARCCryptoHashType expected = PARC_HASH_SHA256;
    PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_DSA, expected, bits);
    parcBuffer_Release(&bits);

    PARCCryptoHashType actual = parcSignature_GetHashType(signature);

    assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
    parcSignature_Release(&signature);
}
static CCNxTlvDictionary *
createSignedContentObject(void)
{
    CCNxName *name = ccnxName_CreateFromURI("lci:/some/name");
    PARCBuffer *payload = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), 11, (uint8_t *) "the payload"));
    CCNxTlvDictionary *contentObject = ccnxContentObject_CreateWithDataPayload(name, payload);
    parcBuffer_Release(&payload);
    ccnxName_Release(&name);

    PARCBuffer *keyid = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), 5, (uint8_t *) "keyid"));
    ccnxValidationRsaSha256_Set(contentObject, keyid, NULL);
    parcBuffer_Release(&keyid);

    PARCBuffer *sigbits = parcBuffer_WrapCString("the signature");
    PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARC_HASH_SHA256, parcBuffer_Flip(sigbits));
    ccnxContentObject_SetSignature(contentObject, keyid, signature, NULL);

    parcSignature_Release(&signature);
    parcBuffer_Release(&sigbits);

    return contentObject;
}
Exemple #16
0
LONGBOW_TEST_CASE(Global, parcSignature_GetSigningAlgorithm)
{
    PARCBuffer *signatureBits = parcBuffer_Allocate(strlen("Hello"));
    parcBuffer_PutArray(signatureBits, strlen("Hello"), (uint8_t *) "Hello");
    PARCSigningAlgorithm expected = PARCSigningAlgorithm_DSA;
    PARCSignature *signature = parcSignature_Create(expected, PARC_HASH_SHA256, signatureBits);

    PARCSigningAlgorithm actual = parcSignature_GetSigningAlgorithm(signature);

    assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
    parcSignature_Release(&signature);
    parcBuffer_Release(&signatureBits);
}
Exemple #17
0
PARCURISegment *
parcURISegment_Create(size_t length, const unsigned char segment[length])
{
    PARCURISegment *result = NULL;

    PARCBuffer *buffer = parcBuffer_Allocate(length);
    if (buffer != NULL) {
        parcBuffer_PutArray(buffer, length, segment);
        parcBuffer_Flip(buffer);
        result = parcURISegment_CreateFromBuffer(buffer);
        parcBuffer_Release(&buffer);
    }
    return result;
}
Exemple #18
0
LONGBOW_TEST_CASE(Global, parcSignature_ToString)
{
    PARCBuffer *signatureBits = parcBuffer_Allocate(strlen("Hello"));
    parcBuffer_PutArray(signatureBits, strlen("Hello"), (uint8_t *) "Hello");
    PARCSigningAlgorithm expected = PARCSigningAlgorithm_DSA;
    PARCSignature *signature = parcSignature_Create(expected, PARC_HASH_SHA256, signatureBits);

    char *string = parcSignature_ToString(signature);

    assertNotNull(string, "Expected non-NULL result from parcSignature_ToString");

    parcMemory_Deallocate((void **) &string);
    parcSignature_Release(&signature);
    parcBuffer_Release(&signatureBits);
}
static PARCCryptoHash *
_GetCertificateDigest(PARCPkcs12KeyStore *keystore)
{
    parcSecurity_AssertIsInitialized();

    assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");

    if (keystore->certificate_digest == NULL) {
        uint8_t digestBuffer[SHA256_DIGEST_LENGTH];
        int result = X509_digest(keystore->x509_cert, EVP_sha256(), digestBuffer, NULL);
        if (result) {
            keystore->certificate_digest =
                parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, digestBuffer));
        }
    }

    PARCCryptoHash *hash = parcCryptoHash_Create(PARC_HASH_SHA256, keystore->certificate_digest);
    return hash;
}
static PARCBuffer *
_GetDEREncodedPrivateKey(PARCPkcs12KeyStore *keystore)
{
    parcSecurity_AssertIsInitialized();

    assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");

    if (keystore->private_key_der == NULL) {
        uint8_t *der = NULL;

        // this allocates memory for der
        int derLength = i2d_PrivateKey(keystore->private_key, &der);
        if (derLength > 0) {
            keystore->private_key_der =
            parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
        }
        OPENSSL_free(der);
    }

    return parcBuffer_Copy(keystore->private_key_der);
}
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;
}
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;
}
PARCBuffer *
bufferFromString(size_t length, const char string[length])
{
    return parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(length), length, (const uint8_t *) string));
}
Exemple #24
0
PARCBuffer *
parcBuffer_PutCString(PARCBuffer *buffer, const char *string)
{
    return parcBuffer_PutArray(buffer, strlen(string) + 1, (const uint8_t *) string);
}
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;
}