/** * @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); }