int athenaTransportLinkAdapter_CloseByName(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, const char *linkName) { if (athenaTransportLinkAdapter->listenerList) { for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->listenerList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->listenerList, index); if (strcmp(athenaTransportLink_GetName(athenaTransportLink), linkName) == 0) { athenaTransportLink_Close(athenaTransportLink); return 0; } } } if (athenaTransportLinkAdapter->instanceList) { for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->instanceList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->instanceList, index); if (athenaTransportLink) { if (strcmp(athenaTransportLink_GetName(athenaTransportLink), linkName) == 0) { athenaTransportLink_Close(athenaTransportLink); return 0; } } } } errno = ENOENT; return -1; }
/** * @abstract add a new link instance to the AthenaTransportLinkAdapter instance list * @discussion * * When athenaTransportLinkAdapter_Open is called on a link specific module, the module instantiates * the link and then creates a new AthenaTransportLink to interface with the AthenaTransportLinkAdapter. * The AthenaTransportLinkModule passes the new AthenaTransportLink to the AthenaTransportLinkAdapter by * calling AthenaTransportLinkAdapter_AddLink with the new link AthenaTransportLink data. The AthenaTransportLinkAdapter * then places the new link instance on its internal instance list in a pending state until it has been verified and ensures * that the new link doesn't collide (i.e. by name) with any currently registered link before returning success. * * New routable links are placed into instanceList slots that have previously been vacated before being added * to the end of the instanceList. This is in order to keep bit vectors that are based on the instanceList as * small as is necessary. * * @param [in] athenaTransportLinkAdapter link adapter instance * @param [in] linkInstance instance structure created by the link specific module * @return 0 on success, -1 with errno set to indicate the error * * Example: * @code * { * } * @endcode */ static int _athenaTransportLinkAdapter_AddLink(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, AthenaTransportLink *newTransportLink) { int linkId = -1; // Check for existing linkName in listenerList if (athenaTransportLinkAdapter->listenerList) { for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->listenerList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->listenerList, index); if (strcmp(athenaTransportLink_GetName(athenaTransportLink), athenaTransportLink_GetName(newTransportLink)) == 0) { errno = EADDRINUSE; // name is already in listenerList return -1; } } } // Check for existing linkName in the instanceList if (athenaTransportLinkAdapter->instanceList) { for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->instanceList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->instanceList, index); if (athenaTransportLink) { if (strcmp(athenaTransportLink_GetName(athenaTransportLink), athenaTransportLink_GetName(newTransportLink)) == 0) { errno = EADDRINUSE; // name is already in instanceList return -1; } } else { // remember the first available index found along the way if (linkId == -1) { linkId = index; } } } } // Add to listenerList or instanceList athenaTransportLink_Acquire(newTransportLink); if (athenaTransportLink_IsNotRoutable(newTransportLink)) { // listener bool result = parcArrayList_Add(athenaTransportLinkAdapter->listenerList, newTransportLink); assertTrue(result, "parcArrayList_Add failed to add new listener"); } else { // routable link, add to instances using the last available id if one was seen if (linkId != -1) { parcArrayList_Set(athenaTransportLinkAdapter->instanceList, linkId, newTransportLink); } else { bool result = parcArrayList_Add(athenaTransportLinkAdapter->instanceList, newTransportLink); assertTrue(result, "parcArrayList_Add failed to add new link instance"); } } // If any transport link has a registered file descriptor add it to the general polling list. int eventFd = athenaTransportLink_GetEventFd(newTransportLink); if (eventFd != -1) { _add_to_pollfdList(athenaTransportLinkAdapter, newTransportLink, eventFd); } return 0; }
/** * @abstract called from below the link adapter to coordinate termination of a link instance * @discussion * * This is called exclusively from the Transport Link Module to instigate the removal of * an active link. The link has been flagged closing by the originator. This method * must ensure that all references to the link have been removed and then call the * instance close method to finish the operation. * * @param [in] athenaTransportLinkAdapter link adapter instance * @param [in] athenaTransportLink link instance to remove * * Example: * @code * { * * } * @endcode */ static void _athenaTransportLinkAdapter_RemoveLink(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, AthenaTransportLink *athenaTransportLink) { int linkId = -1; // if this is a listener it can simply be removed if (athenaTransportLink_IsNotRoutable(athenaTransportLink)) { if (athenaTransportLinkAdapter->listenerList) { for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->listenerList); index++) { AthenaTransportLink *transportLink = parcArrayList_Get(athenaTransportLinkAdapter->listenerList, index); if (athenaTransportLink == transportLink) { parcArrayList_RemoveAtIndex(athenaTransportLinkAdapter->listenerList, index); _remove_from_pollfdList(athenaTransportLinkAdapter, athenaTransportLink); parcLog_Debug(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter), "listener removed: %s", athenaTransportLink_GetName(athenaTransportLink)); athenaTransportLink_Release(&athenaTransportLink); return; } } } } // Remove from our internal instance list. // The index entry remains to be reused by links that are added in the future. if (athenaTransportLinkAdapter->instanceList) { for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->instanceList); index++) { AthenaTransportLink *transportLink = parcArrayList_Get(athenaTransportLinkAdapter->instanceList, index); if (athenaTransportLink == transportLink) { parcArrayList_Set(athenaTransportLinkAdapter->instanceList, index, NULL); _remove_from_pollfdList(athenaTransportLinkAdapter, athenaTransportLink); linkId = index; break; } } } assertFalse(linkId == -1, "Attempt to remove link not found in link adapter lists"); // Callback to notify that the link has been removed and references need to be dropped. PARCBitVector *linkVector = parcBitVector_Create(); parcBitVector_Set(linkVector, linkId); athenaTransportLinkAdapter->removeLink(athenaTransportLinkAdapter->removeLinkContext, linkVector); parcBitVector_Release(&linkVector); // we assume all references to the linkId associated with this instance have been // cleared from the PIT and FIB when removeLink returns. parcLog_Debug(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter), "link removed: %s", athenaTransportLink_GetName(athenaTransportLink)); athenaTransportLink_Release(&athenaTransportLink); }
const char * athenaTransportLinkAdapter_Open(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, PARCURI *connectionURI) { AthenaTransportLinkModule *athenaTransportLinkModule; const char *moduleName = parcURI_GetScheme(connectionURI); if (moduleName == NULL) { errno = EINVAL; return NULL; } athenaTransportLinkModule = _LookupModule(athenaTransportLinkAdapter, moduleName); if (athenaTransportLinkModule == NULL) { athenaTransportLinkModule = _LoadModule(athenaTransportLinkAdapter, moduleName); if (athenaTransportLinkModule == NULL) { errno = ENOENT; return NULL; } } AthenaTransportLink *athenaTransportLink = athenaTransportLinkModule_Open(athenaTransportLinkModule, connectionURI); if (athenaTransportLink == NULL) { return NULL; } return athenaTransportLink_GetName(athenaTransportLink); }
AthenaTransportLink * athenaTransportLinkModule_Open(AthenaTransportLinkModule *athenaTransportLinkModule, PARCURI *connectionURI) { AthenaTransportLink *athenaTransportLink = athenaTransportLinkModule->openMethod(athenaTransportLinkModule, connectionURI); if (athenaTransportLink) { athenaTransportLink_SetAddLinkCallback(athenaTransportLink, (AthenaTransportLink_AddLinkCallback *) _athenaTransportLinkModule_AddLink, athenaTransportLinkModule); int result = _athenaTransportLinkModule_AddLink(athenaTransportLinkModule, athenaTransportLink); if (result == -1) { int addLinkError = errno; parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Adding link %s failed: %s", athenaTransportLink_GetName(athenaTransportLink), strerror(errno)); athenaTransportLink_Close(athenaTransportLink); errno = addLinkError; return NULL; } athenaTransportLink_SetRemoveLinkCallback(athenaTransportLink, (AthenaTransportLink_RemoveLinkCallback *) _athenaTransportLinkModule_RemoveLink, athenaTransportLinkModule); } return athenaTransportLink; }
static void _TemplateClose(AthenaTransportLink *athenaTransportLink) { parcLog_Info(athenaTransportLink_GetLogger(athenaTransportLink), "link %s closed", athenaTransportLink_GetName(athenaTransportLink)); _TemplateLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink); _TemplateLinkData_Destroy(&linkData); }
const char * athenaTransportLinkAdapter_LinkIdToName(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, int linkId) { if (athenaTransportLinkAdapter->instanceList == NULL) { return NULL; } if (linkId < parcArrayList_Size(athenaTransportLinkAdapter->instanceList)) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->instanceList, linkId); if (athenaTransportLink) { return athenaTransportLink_GetName(athenaTransportLink); } } return NULL; }
int athenaTransportLinkAdapter_LinkNameToId(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, const char *linkName) { if (athenaTransportLinkAdapter->instanceList == NULL) { return -1; } for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->instanceList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->instanceList, index); if (athenaTransportLink) { if (strcmp(athenaTransportLink_GetName(athenaTransportLink), linkName) == 0) { return index; } } } return -1; }
static AthenaTransportLink * _newLink(AthenaTransportLink *athenaTransportLink, _UDPLinkData *newLinkData) { // Accept a new tunnel connection. // Clone a new link from the current listener. const char *derivedLinkName = _createNameFromLinkData(&newLinkData->link); AthenaTransportLink *newTransportLink = athenaTransportLink_Clone(athenaTransportLink, derivedLinkName, _UDPSend, _UDPReceiveProxy, _UDPClose); if (newTransportLink == NULL) { parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "athenaTransportLink_Clone failed"); parcMemory_Deallocate(&derivedLinkName); _UDPLinkData_Destroy(&newLinkData); return NULL; } _setConnectLinkState(newTransportLink, newLinkData); // Send the new link up to be added. int result = athenaTransportLink_AddLink(athenaTransportLink, newTransportLink); if (result == -1) { parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "athenaTransportLink_AddLink failed: %s", strerror(errno)); _UDPLinkData_Destroy(&newLinkData); athenaTransportLink_Release(&newTransportLink); } else { parcLog_Info(athenaTransportLink_GetLogger(athenaTransportLink), "new link accepted by %s: %s %s", athenaTransportLink_GetName(athenaTransportLink), derivedLinkName, athenaTransportLink_IsNotLocal(athenaTransportLink) ? "" : "(Local)"); } parcMemory_Deallocate(&derivedLinkName); // Could pass a message back here regarding the new link. return newTransportLink; }
static bool _linkIsEOF(AthenaTransportLink *athenaTransportLink) { struct _UDPLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink); // If poll indicates there's a read event and a subsequent read returns zero our peer has hungup. struct pollfd pollfd = { .fd = linkData->fd, .events = POLLIN }; int events = poll(&pollfd, 1, 0); if (events == -1) { parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "poll error (%s)", strerror(errno)); return true; // poll error, close the link } else if (events == 0) { // there are no pending events, was truly a zero read return false; } if (pollfd.revents & POLLIN) { char peekBuffer; ssize_t readCount = recv(linkData->fd, (void *) &peekBuffer, 1, MSG_PEEK); if (readCount == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { // read blocked linkData->_stats.receive_ReadWouldBlock++; return false; } return true; // read error } if (readCount == 0) { // EOF return true; } } return false; } static void _UDPClose(AthenaTransportLink *athenaTransportLink) { parcLog_Info(athenaTransportLink_GetLogger(athenaTransportLink), "link %s closed", athenaTransportLink_GetName(athenaTransportLink)); _UDPLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink); close(linkData->fd); _UDPLinkData_Destroy(&linkData); }
static CCNxMetaMessage * _create_linkList_response(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, CCNxName *ccnxName) { PARCJSONArray *jsonLinkList = parcJSONArray_Create(); for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->listenerList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->listenerList, index); const char *linkName = athenaTransportLink_GetName(athenaTransportLink); bool notLocal = athenaTransportLink_IsNotLocal(athenaTransportLink); bool localForced = athenaTransportLink_IsForceLocal(athenaTransportLink); PARCJSON *jsonItem = parcJSON_Create(); parcJSON_AddString(jsonItem, "linkName", linkName); parcJSON_AddInteger(jsonItem, "index", -1); parcJSON_AddBoolean(jsonItem, "notLocal", notLocal); parcJSON_AddBoolean(jsonItem, "localForced", localForced); PARCJSONValue *jsonItemValue = parcJSONValue_CreateFromJSON(jsonItem); parcJSON_Release(&jsonItem); parcJSONArray_AddValue(jsonLinkList, jsonItemValue); parcJSONValue_Release(&jsonItemValue); if (notLocal) { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link listener%s: %s", localForced ? " (forced remote)" : "", linkName); } else { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link listener%s: %s", localForced ? " (forced local)" : "", linkName); } } for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->instanceList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->instanceList, index); if (athenaTransportLink) { const char *linkName = athenaTransportLink_GetName(athenaTransportLink); bool notLocal = athenaTransportLink_IsNotLocal(athenaTransportLink); bool localForced = athenaTransportLink_IsForceLocal(athenaTransportLink); PARCJSON *jsonItem = parcJSON_Create(); parcJSON_AddString(jsonItem, "linkName", linkName); parcJSON_AddInteger(jsonItem, "index", index); parcJSON_AddBoolean(jsonItem, "notLocal", notLocal); parcJSON_AddBoolean(jsonItem, "localForced", localForced); PARCJSONValue *jsonItemValue = parcJSONValue_CreateFromJSON(jsonItem); parcJSON_Release(&jsonItem); parcJSONArray_AddValue(jsonLinkList, jsonItemValue); parcJSONValue_Release(&jsonItemValue); if (notLocal) { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link instance [%d] %s: %s", index, localForced ? "(forced remote)" : "(remote)", linkName); } else { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link instance [%d] %s: %s", index, localForced ? "(forced local)" : "(local)", linkName); } } } char *jsonString = parcJSONArray_ToString(jsonLinkList); parcJSONArray_Release(&jsonLinkList); PARCBuffer *payload = parcBuffer_CreateFromArray(jsonString, strlen(jsonString)); CCNxContentObject *contentObject = ccnxContentObject_CreateWithDataPayload(ccnxName, parcBuffer_Flip(payload)); struct timeval tv; gettimeofday(&tv, NULL); uint64_t nowInMillis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); ccnxContentObject_SetExpiryTime(contentObject, nowInMillis + 100); // this response is good for 100 millis CCNxMetaMessage *result = ccnxMetaMessage_CreateFromContentObject(contentObject); ccnxContentObject_Release(&contentObject); parcBuffer_Release(&payload); parcMemory_Deallocate(&jsonString); athena_EncodeMessage(result); return result; }