/** * Common parts of setting up a MetisTlvName after the backing memory has been allocated and copied in to. * * PRECONDITIONS: name->memory and name->memoryLength set */ static void _setup(MetisTlvName *name) { name->refCountPtr = parcMemory_Allocate(sizeof(unsigned)); assertNotNull(name->refCountPtr, "parcMemory_Allocate(%zu) returned NULL", sizeof(unsigned)); *name->refCountPtr = 1; metisTlv_NameSegments(name->memory, name->memoryLength, &name->segmentArray, &name->segmentArrayLength); name->segmentCumulativeHashArray = parcMemory_Allocate(name->segmentArrayLength * sizeof(uint32_t)); assertNotNull(name->segmentCumulativeHashArray, "parcMemory_Allocate(%zu) returned NULL", name->segmentArrayLength * sizeof(uint32_t)); name->segmentCumulativeHashArrayLengthPtr = parcMemory_Allocate(sizeof(size_t)); assertNotNull(name->segmentCumulativeHashArrayLengthPtr, "parcMemory_Allocate(%zu) returned NULL", sizeof(size_t)); *name->segmentCumulativeHashArrayLengthPtr = 1; name->segmentCumulativeHashArrayLimit = name->segmentArrayLength; if (name->segmentArrayLength > 0) { // always hash the 1st name component. This is needed as the initial case // to do the cumulative hashes in metisTlvName_HashCode name->segmentCumulativeHashArray[0] = parcHash32_Data(&name->memory[name->segmentArray[0].offset], name->segmentArray[0].length); } }
TransportContext * Transport_Create(TransportTypes type) { if (the_context == NULL) { switch (type) { case TRANSPORT_RTA: the_context = parcMemory_Allocate(sizeof(TransportContext)); assertNotNull(the_context, "TransportContext could not be allocated, parcMemory_Allocate(%zu) returned NULL", sizeof(TransportContext)); the_context->references = 0; the_context->ops = rta_ops; the_context->transport_data = the_context->ops.Create(); the_context->transport_type = type; break; default: fprintf(stderr, "%s unknown transport type %d\n", __func__, type); abort(); break; } } if (the_context->transport_type == type) { the_context->references++; return the_context; } fprintf(stderr, "%s transport type %d not of request type %d\n", __func__, the_context->transport_type, type); abort(); }
/** * Given a CCNxName, a directory path, a file name, and a requested chunk number, return a new CCNxContentObject * with that CCNxName and containing the specified chunk of the file. The new CCNxContentObject will also * contain the number of the last chunk required to transfer the complete file. Note that the last chunk of the * file being retrieved is calculated each time we retrieve a chunk so the file can be growing in size as we * transfer it. * The new CCnxContentObject must eventually be released by calling ccnxContentObject_Release(). * * @param [in] name The CCNxName to use when creating the new CCNxContentObject. * @param [in] directoryPath The directory in which to find the specified file. * @param [in] fileName The name of the file. * @param [in] requestedChunkNumber The number of the requested chunk from the file. * * @return A new CCNxContentObject instance containing the request chunk of the specified file, or NULL if * the file did not exist or was otherwise unavailable. */ static CCNxContentObject * _createFetchResponse(const CCNxName *name, const char *directoryPath, const char *fileName, uint64_t requestedChunkNumber) { CCNxContentObject *result = NULL; uint64_t finalChunkNumber = 0; // Combine the directoryPath and fileName into the full path name of the desired file size_t filePathBufferSize = strlen(fileName) + strlen(directoryPath) + 2; // +2 for '/' and trailing null. char *fullFilePath = parcMemory_Allocate(filePathBufferSize); assertNotNull(fullFilePath, "parcMemory_Allocate(%zu) returned NULL", filePathBufferSize); snprintf(fullFilePath, filePathBufferSize, "%s/%s", directoryPath, fileName); // Make sure the file exists and is accessible before creating a ContentObject response. if (tutorialFileIO_IsFileAvailable(fullFilePath)) { // Since the file's length can change (e.g. if it is being written to while we're fetching // it), the final chunk number can change between requests for content chunks. So, update // it each time this function is called. finalChunkNumber = _getFinalChunkNumberOfFile(fullFilePath, tutorialCommon_ChunkSize); // Get the actual contents of the specified chunk of the file. PARCBuffer *payload = tutorialFileIO_GetFileChunk(fullFilePath, tutorialCommon_ChunkSize, requestedChunkNumber); if (payload != NULL) { result = _createContentObject(name, payload, finalChunkNumber); parcBuffer_Release(&payload); } } parcMemory_Deallocate((void **) &fullFilePath); return result; // Could be NULL if there was no payload }
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; }
static void * _ccnxManifestHashGroupIterator_Init(CCNxManifestHashGroup *group) { _HashgroupIteratorState *state = parcMemory_Allocate(sizeof(_HashgroupIteratorState)); state->pointerNumber = 0; state->atEnd = false; return state; }
void * valueNewInt(int value) { int *newValue = parcMemory_Allocate(sizeof(int)); assertNotNull(newValue, "parcMemory_Allocate(%zu) returned NULL", sizeof(int)); *newValue = value; return newValue; }
void * keyNewInt(int key) { int *newKey = parcMemory_Allocate(sizeof(int)); assertNotNull(newKey, "parcMemory_Allocate(%zu) returned NULL", sizeof(int)); *newKey = key; return newKey; }
/* * Small size allocator for creating a network buffer */ static size_t _allocator(void *userarg, size_t bytes, void **output) { const size_t allocationSize = *(size_t *) userarg; void *allocated = parcMemory_Allocate(allocationSize); *output = allocated; return allocationSize; }
static void * _InitForward(_DummyChunker *chunker) { _DummyChunkerState *state = parcMemory_Allocate(sizeof(_DummyChunkerState)); state->val = 0; state->dir = 1; state->atEnd = false; return state; }
static inline struct parc_deque_node * _parcDequeNode_Create(void *element, struct parc_deque_node *previous, struct parc_deque_node *next) { struct parc_deque_node *result = parcMemory_Allocate(sizeof(struct parc_deque_node)); if (result != NULL) { result->element = element; result->next = next; result->previous = previous; } return result; }
char * parcBuffer_ToString(const PARCBuffer *buffer) { size_t remaining = parcBuffer_Remaining(buffer); char *result = parcMemory_Allocate(remaining + 1); if (remaining > 0) { assertNotNull(result, "parcMemory_Allocate returned NULL"); if (result != NULL) { memcpy(result, parcBuffer_Overlay((PARCBuffer *) buffer, 0), remaining); } } result[remaining] = 0; return result; }
MetisTlvName * metisTlvName_Create(const uint8_t *memory, size_t memoryLength) { MetisTlvName *name = parcMemory_AllocateAndClear(sizeof(MetisTlvName)); assertNotNull(name, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(MetisTlvName)); name->memory = parcMemory_Allocate(memoryLength); assertNotNull(name->memory, "parcMemory_Allocate(%zu) returned NULL", memoryLength); memcpy(name->memory, memory, memoryLength); name->memoryLength = memoryLength; _setup(name); return name; }
MetisTlvName * metisTlvName_CreateFromCCNxName(const CCNxName *ccnxName) { // to avoid reallocs, calculate the exact size we need size_t memoryLength = 0; for (size_t i = 0; i < ccnxName_GetSegmentCount(ccnxName); i++) { CCNxNameSegment *segment = ccnxName_GetSegment(ccnxName, i); memoryLength += 4 + ccnxNameSegment_Length(segment); } MetisTlvName *name = parcMemory_AllocateAndClear(sizeof(MetisTlvName)); assertNotNull(name, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(MetisTlvName)); name->memoryLength = memoryLength; name->memory = parcMemory_Allocate(memoryLength); assertNotNull(name->memory, "parcMemory_Allocate(%zu) returned NULL", memoryLength); uint8_t *p = name->memory; uint8_t *end = p + memoryLength; for (size_t i = 0; i < ccnxName_GetSegmentCount(ccnxName); i++) { CCNxNameSegment *segment = ccnxName_GetSegment(ccnxName, i); uint16_t type = ccnxNameSegment_GetType(segment); uint16_t length = ccnxNameSegment_Length(segment); *(uint16_t *) p = htons(type); p += 2; *(uint16_t *) p = htons(length); p += 2; if (length >0) { PARCBuffer *buffer = ccnxNameSegment_GetValue(segment); uint8_t *overlay = parcBuffer_Overlay(buffer, 0); memcpy(p, overlay, length); p += length; } // sanity check assertTrue(p <= end, "Wrote past the end of buffer, now at %p end at %p", p, end); } _setup(name); return name; }
static void * _InitForward(PARCBufferChunker *chunker) { _ChunkerState *state = parcMemory_Allocate(sizeof(_ChunkerState)); state->chunkNumber = 0; state->direction = 0; state->position = 0; state->atEnd = false; if (parcBuffer_Remaining(chunker->data) < chunker->chunkSize) { state->nextChunkSize = parcBuffer_Remaining(chunker->data); } else { state->nextChunkSize = chunker->chunkSize; } return state; }
static void * _hmacCreate(void *env) { _PARCAesSignerFileStore *keystore = (_PARCAesSignerFileStore *) env; // HMAC_Init_ex seems to overrun the size of HMAC_CTX, so make it bigger HMAC_CTX *ctx = parcMemory_Allocate(sizeof(HMAC_CTX) * 2); assertNotNull(ctx, "parcMemory_Allocate(%zu) returned NULL for HMAC_CTX", sizeof(HMAC_CTX) * 2); HMAC_CTX_init(ctx); // Now initialize it with our digest and key, so in hmac_init we can avoid using those assertTrue(parcBuffer_Remaining(keystore->secretKey) < INT_MAX, "The keystore secret key cannot be longer than %d", INT_MAX); HMAC_Init_ex(ctx, parcByteArray_Array(parcBuffer_Array(keystore->secretKey)), (int) parcBuffer_Remaining(keystore->secretKey), keystore->opensslMd, NULL); return ctx; }
MetisHopByHopFragmenter * metisHopByHopFragmenter_Create(MetisLogger *logger, unsigned mtu) { MetisHopByHopFragmenter *fragmenter = parcMemory_Allocate(sizeof(MetisHopByHopFragmenter)); if (fragmenter) { fragmenter->nextReceiveFragSequenceNumber = 0; fragmenter->nextSendFragSequenceNumber = 0; fragmenter->logger = metisLogger_Acquire(logger); fragmenter->mtu = mtu; fragmenter->receiveQueueCapacity = 128; // this is a many-to-one queue, so not too big fragmenter->sendQueueCapacity = 2048; // this is a one-to-many queue, so bigger (e.g. 64 KB in to 1KB payloads) fragmenter->receiveQueue = parcRingBuffer1x1_Create(fragmenter->receiveQueueCapacity, _ringBufferDestroyer); fragmenter->sendQueue = parcRingBuffer1x1_Create(fragmenter->sendQueueCapacity, _ringBufferDestroyer); fragmenter->currentReceiveBuffer = parcEventBuffer_Create(); fragmenter->parserState = _ParserState_Idle; } return fragmenter; }
static void * _hmacCreate(void *env) { PARCSymmetricKeySigner *signer = (PARCSymmetricKeySigner *) env; // HMAC_Init_ex seems to overrun the size of HMAC_CTX, so make it bigger HMAC_CTX *ctx = parcMemory_Allocate(sizeof(HMAC_CTX) * 2); assertNotNull(ctx, "parcMemory_Allocate(%zu) returned NULL for HMAC_CTX", sizeof(HMAC_CTX) * 2); HMAC_CTX_init(ctx); // Now initialize it with our digest and key, so in hmac_init we can avoid using those PARCBuffer *secretKey = parcSymmetricKeyStore_GetKey(signer->keyStore); assertTrue(parcBuffer_Remaining(secretKey) < 512, "The keystore secret key cannot be longer than %d", 512); HMAC_Init_ex(ctx, parcByteArray_Array(parcBuffer_Array(secretKey)), (int) parcBuffer_Remaining(secretKey), signer->opensslMd, NULL); return ctx; }
static void * _InitReverse(PARCFileChunker *chunker) { _ChunkerState *state = parcMemory_Allocate(sizeof(_ChunkerState)); state->chunkNumber = 0; state->direction = 1; state->atEnd = false; state->totalSize = parcFile_GetFileSize(chunker->file); if (state->totalSize < chunker->chunkSize) { state->position = 0; state->nextChunkSize = state->totalSize; } else { state->position = state->totalSize - chunker->chunkSize; state->nextChunkSize = chunker->chunkSize; } return state; }
LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_PutGetIoVec) { uint8_t *data = parcMemory_Allocate(64); memset(data, 0, 64); PARCBuffer *buffer = parcBuffer_Allocate(1); CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data); CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); ccnxWireFormatMessage_PutIoVec((CCNxWireFormatMessage *) packet, iovec); CCNxCodecNetworkBufferIoVec *test = ccnxWireFormatMessage_GetIoVec((CCNxWireFormatMessage *) packet); assertTrue(test == iovec, "Failed to get iovec from dictionary, expected %p got %p", (void *) iovec, (void *) test); ccnxTlvDictionary_Release(&packet); parcBuffer_Release(&buffer); ccnxCodecNetworkBufferIoVec_Release(&iovec); ccnxCodecNetworkBuffer_Release(&netbuff); }
PARCEventSignal * parcEventSignal_Create(PARCEventScheduler *eventScheduler, int signal, PARCEventType flags, PARCEvent_Callback *callback, void *callbackArgs) { PARCEventSignal *parcEventSignal = parcMemory_Allocate(sizeof(PARCEventSignal)); assertNotNull(parcEventSignal, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEventSignal)); parcEventSignal->eventScheduler = eventScheduler; parcEventSignal->callback = callback; parcEventSignal->callbackUserData = callbackArgs; parcEventSignal->event = event_new(parcEventScheduler_GetEvBase(eventScheduler), signal, internal_PARCEventType_to_libevent_type(flags), _parc_event_signal_callback, parcEventSignal); assertNotNull(parcEventSignal->event, "Could not create a new event!"); parcEventSignal_LogDebug(parcEventSignal, "parcEventSignal_Create(base=%p,signal=%x,flags=%x,cb=%p,args=%p) = %p\n", parcEventScheduler_GetEvBase(eventScheduler), signal, flags, callback, callbackArgs, parcEventSignal); return parcEventSignal; }
char * parcMemory_Format(const char *format, ...) { va_list ap; va_start(ap, format); va_list copy; va_copy(copy, ap); int length = vsnprintf(NULL, 0, format, copy); va_end(copy); char *result = NULL; if (length >= 0) { result = parcMemory_Allocate(length + 1); if (result != NULL) { vsprintf(result, format, ap); } } return result; }
/** * Creates a client-specific session * * <#Discussion#> * * @param <#param1#> * @return <#return#> * * Example: * @code * <#example#> * @endcode */ static _MetisCommandLineInterface_Session * metisCliSession_Create(MetisCommandLineInterface *cli, MetisSocketType clientSocket, struct sockaddr *clientAddress, int clientAddressLength) { _MetisCommandLineInterface_Session *session = parcMemory_AllocateAndClear(sizeof(_MetisCommandLineInterface_Session)); assertNotNull(session, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_MetisCommandLineInterface_Session)); session->parentCli = cli; session->clientAddress = parcMemory_Allocate(clientAddressLength); assertNotNull(session->clientAddress, "parcMemory_Allocate(%d) returned NULL", clientAddressLength); session->clientAddressLength = clientAddressLength; session->clientSocket = clientSocket; memcpy(session->clientAddress, clientAddress, clientAddressLength); MetisDispatcher *dispatcher = metisForwarder_GetDispatcher(cli->metis); PARCEventScheduler *eventBase = metisDispatcher_GetEventScheduler(dispatcher); session->streamBuffer = parcEventQueue_Create(eventBase, clientSocket, PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks); parcEventQueue_SetCallbacks(session->streamBuffer, _metisCliSession_ReadCallback, NULL, _metisCliSession_EventCallback, session); parcEventQueue_Enable(session->streamBuffer, PARCEventType_Read); return session; }
PARCHashMap * parcHashMap_Copy(const PARCHashMap *original) { parcHashMap_OptionalAssertValid(original); PARCHashMap *result = parcObject_CreateInstance(PARCHashMap); result->capacity = original->capacity; result->minCapacity = original->minCapacity; result->maxLoadFactor = original->maxLoadFactor; result->minLoadFactor = original->minLoadFactor; result->size = original->size; result->buckets = parcMemory_Allocate(result->capacity * sizeof(PARCLinkedList*)); for (unsigned int i = 0; i < result->capacity; i++) { result->buckets[i] = NULL; if (original->buckets[i] != NULL) { result->buckets[i] = parcLinkedList_Copy(original->buckets[i]); } } return result; }
LONGBOW_TEST_CASE(CreateRelease, CreateRelease) { CCNxPortalFactory *factory = (CCNxPortalFactory *) longBowTestCase_GetClipBoardData(testCase); CCNxPortalAttributes *attributes = NULL; CCNxPortalStack *actual = ccnxPortalStack_Create(factory, attributes, _mockStart, _mockStop, _mockRead, _mockSend, _mockListen, _mockIgnore, _mockGetFileId, _mockSetAttributes, _mockGetAttributes, parcMemory_Allocate(10), parcMemory_DeallocateImpl); parcObjectTesting_AssertAcquire(actual); ccnxPortalStack_Release(&actual); }
return 1; } } static uint32_t _dummy_HashCode(const _DummyObject *obj) { _DummyObject *dummy = (_DummyObject *) obj; dummy->calledCount++; return 1337; } static char * _dummy_ToString(const _DummyObject *x __attribute__((unused))) { char *str = (char *) parcMemory_Allocate(6); char *test = "dummy"; sprintf(str, "%s", test); return str; } static PARCJSON * _dummy_ToJSON(const _DummyObject *x __attribute__((unused))) { PARCJSON *json = parcJSON_ParseString("{ \"type\" : \"dummy\" }"); return json; } parcObject_ExtendPARCObject(_DummyObject, _dummy_Destroy, _dummy_Copy, _dummy_ToString, _dummy_Equals, _dummy_Compare, _dummy_HashCode, _dummy_ToJSON);
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; }