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 int _setSocketOptions(AthenaTransportLinkModule *athenaTransportLinkModule, int fd) { int on = 1; #ifdef BSD_IGNORESIGPIPE int result = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *) &on, sizeof(on)); if (result) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "setsockopt failed to set SO_NOSIGPIPE (%s)", strerror(errno)); return -1; } #endif return 0; }
static AthenaTransportLink * _UDPOpen(AthenaTransportLinkModule *athenaTransportLinkModule, PARCURI *connectionURI) { AthenaTransportLink *result = 0; const char *authorityString = parcURI_GetAuthority(connectionURI); if (authorityString == NULL) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Unable to parse connection authority %s", authorityString); errno = EINVAL; return NULL; } PARCURIAuthority *authority = parcURIAuthority_Parse(authorityString); const char *URIAddress = parcURIAuthority_GetHostName(authority); in_port_t port = parcURIAuthority_GetPort(authority); // Normalize the provided hostname struct sockaddr_in *addr = (struct sockaddr_in *) parcNetwork_SockAddress(URIAddress, port); char *address = inet_ntoa(addr->sin_addr); parcMemory_Deallocate(&addr); parcURIAuthority_Release(&authority); if (address == NULL) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Unable to lookup hostname %s", address); errno = EINVAL; return NULL; } if (port == 0) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Invalid address specification, port == 0"); errno = EINVAL; return NULL; } bool listener = false; char name[MAXPATHLEN] = { 0 }; char srcAddress[NI_MAXHOST] = "0.0.0.0"; size_t mtu = 0; uint16_t srcPort = 0; char localFlag[MAXPATHLEN] = { 0 }; int forceLocal = 0; char *linkName = NULL; PARCURIPath *remainder = parcURI_GetPath(connectionURI); size_t segments = parcURIPath_Count(remainder); for (int i = 0; i < segments; i++) { PARCURISegment *segment = parcURIPath_Get(remainder, i); const char *token = parcURISegment_ToString(segment); if (strcasecmp(token, UDP_LISTENER_FLAG) == 0) { listener = true; parcMemory_Deallocate(&token); continue; } if (strncasecmp(token, SRC_LINK_SPECIFIER, strlen(SRC_LINK_SPECIFIER)) == 0) { if (sscanf(token, "%*[^%%]%%3D%[^%%]%%3A%hd", srcAddress, &srcPort) != 2) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper connection source specification (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } // Normalize the provided hostname struct sockaddr_in *addr = (struct sockaddr_in *) parcNetwork_SockAddress(srcAddress, srcPort); char *hostname = inet_ntoa(addr->sin_addr); parcMemory_Deallocate(&addr); memcpy(srcAddress, hostname, strlen(hostname) + 1); parcMemory_Deallocate(&token); continue; } if (strncasecmp(token, LINK_MTU_SIZE, strlen(LINK_MTU_SIZE)) == 0) { if (sscanf(token, "%*[^%%]%%3D%zd", &mtu) != 1) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper MTU specification (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } parcMemory_Deallocate(&token); continue; } if (strncasecmp(token, LINK_NAME_SPECIFIER, strlen(LINK_NAME_SPECIFIER)) == 0) { if (sscanf(token, "%*[^%%]%%3D%s", name) != 1) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper connection name specification (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } linkName = name; parcMemory_Deallocate(&token); continue; } if (strncasecmp(token, LOCAL_LINK_FLAG, strlen(LOCAL_LINK_FLAG)) == 0) { if (sscanf(token, "%*[^%%]%%3D%s", localFlag) != 1) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper local specification (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } if (strncasecmp(localFlag, "false", strlen("false")) == 0) { forceLocal = AthenaTransportLink_ForcedNonLocal; } else if (strncasecmp(localFlag, "true", strlen("true")) == 0) { forceLocal = AthenaTransportLink_ForcedLocal; } else { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper local state specification (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } parcMemory_Deallocate(&token); continue; } parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Unknown connection parameter (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } struct sockaddr_in *destination = parcNetwork_SockInet4Address(address, port); struct sockaddr_in *source = parcNetwork_SockInet4Address(srcAddress, srcPort); if (listener) { result = _UDPOpenListener(athenaTransportLinkModule, linkName, destination, mtu); } else { result = _UDPOpenConnection(athenaTransportLinkModule, linkName, source, destination, mtu); } parcMemory_Deallocate(&destination); parcMemory_Deallocate(&source); // forced IsLocal/IsNotLocal, mainly for testing if (result && forceLocal) { athenaTransportLink_ForceLocal(result, forceLocal); } return result; }
// // Open a listener which will create new links when messages arrive and queue them appropriately. // Listeners are inherently insecure, as an adversary could easily create many connections that are never closed. // static AthenaTransportLink * _UDPOpenListener(AthenaTransportLinkModule *athenaTransportLinkModule, const char *linkName, struct sockaddr_in *destination, size_t mtu) { const char *derivedLinkName; _UDPLinkData *linkData = _UDPLinkData_Create(); linkData->multiplexTable = parcHashCodeTable_Create(_connectionEquals, _connectionHashCode, NULL, _closeConnection); assertNotNull(linkData->multiplexTable, "Could not create multiplex table for new listener"); linkData->link.myAddress = *destination; linkData->link.myAddressLength = sizeof(struct sockaddr_in); linkData->link.mtu = mtu; linkData->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (linkData->fd < 0) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "socket error (%s)", strerror(errno)); _UDPLinkData_Destroy(&linkData); return NULL; } int result = _setSocketOptions(athenaTransportLinkModule, linkData->fd); if (result) { close(linkData->fd); _UDPLinkData_Destroy(&linkData); return NULL; } // Set non-blocking flag int flags = fcntl(linkData->fd, F_GETFL, NULL); if (flags < 0) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "fcntl failed to get non-blocking flag (%s)", strerror(errno)); close(linkData->fd); _UDPLinkData_Destroy(&linkData); return NULL; } result = fcntl(linkData->fd, F_SETFL, flags | O_NONBLOCK); if (result) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "fcntl failed to set non-blocking flag (%s)", strerror(errno)); close(linkData->fd); _UDPLinkData_Destroy(&linkData); return NULL; } // bind to listen on requested address result = bind(linkData->fd, (struct sockaddr *) &linkData->link.myAddress, linkData->link.myAddressLength); if (result) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "bind error (%s)", strerror(errno)); close(linkData->fd); _UDPLinkData_Destroy(&linkData); return NULL; } derivedLinkName = _createNameFromLinkData(&linkData->link); if (linkName == NULL) { linkName = derivedLinkName; } // Listener doesn't require a send method. The receive method is used to establish new connections. AthenaTransportLink *athenaTransportLink = athenaTransportLink_Create(linkName, NULL, _UDPReceiveListener, _UDPClose); if (athenaTransportLink == NULL) { parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "athenaTransportLink_Create failed"); parcMemory_Deallocate(&derivedLinkName); close(linkData->fd); _UDPLinkData_Destroy(&linkData); return athenaTransportLink; } athenaTransportLink_SetPrivateData(athenaTransportLink, linkData); athenaTransportLink_SetEventFd(athenaTransportLink, linkData->fd); // Links established for listening are not used to route messages. // They can be kept in a listener list that doesn't consume a linkId. athenaTransportLink_SetRoutable(athenaTransportLink, false); parcLog_Info(athenaTransportLink_GetLogger(athenaTransportLink), "new listener established: Name=\"%s\" (%s)", linkName, derivedLinkName); parcMemory_Deallocate(&derivedLinkName); return athenaTransportLink; }
// // Open a UDP point to point connection. // static AthenaTransportLink * _UDPOpenConnection(AthenaTransportLinkModule *athenaTransportLinkModule, const char *linkName, struct sockaddr_in *source, struct sockaddr_in *destination, size_t mtu) { const char *derivedLinkName; _UDPLinkData *linkData = _UDPLinkData_Create(); linkData->link.peerAddress = *((struct sockaddr_in *) destination); linkData->link.peerAddressLength = sizeof(struct sockaddr_in); linkData->link.mtu = mtu; linkData->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (linkData->fd < 0) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "socket error (%s)", strerror(errno)); _UDPLinkData_Destroy(&linkData); return NULL; } int result = _setSocketOptions(athenaTransportLinkModule, linkData->fd); if (result) { close(linkData->fd); _UDPLinkData_Destroy(&linkData); return NULL; } // bind the local endpoint so we can know our allocated port if it was wildcarded result = bind(linkData->fd, (struct sockaddr *) source, sizeof(struct sockaddr_in)); if (result) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "bind error (%s)", strerror(errno)); close(linkData->fd); _UDPLinkData_Destroy(&linkData); return NULL; } // Retrieve the local endpoint data, used to create the derived name. linkData->link.myAddressLength = sizeof(struct sockaddr_in); result = getsockname(linkData->fd, (struct sockaddr *) &linkData->link.myAddress, &linkData->link.myAddressLength); if (result != 0) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Failed to obtain endpoint information from getsockname."); _UDPLinkData_Destroy(&linkData); return NULL; } derivedLinkName = _createNameFromLinkData(&linkData->link); if (linkName == NULL) { linkName = derivedLinkName; } AthenaTransportLink *athenaTransportLink = athenaTransportLink_Create(linkName, _UDPSend, _UDPReceive, _UDPClose); if (athenaTransportLink == NULL) { parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "athenaTransportLink_Create failed"); parcMemory_Deallocate(&derivedLinkName); _UDPLinkData_Destroy(&linkData); return NULL; } _setConnectLinkState(athenaTransportLink, linkData); // Enable Send? XXX athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Send); parcLog_Info(athenaTransportLink_GetLogger(athenaTransportLink), "new link established: Name=\"%s\" (%s)", linkName, derivedLinkName); parcMemory_Deallocate(&derivedLinkName); return athenaTransportLink; return NULL; }
static AthenaTransportLink * _TemplateOpen(AthenaTransportLinkModule *athenaTransportLinkModule, PARCURI *connectionURI) { // Parse the URI contents to determine the link specific parameters const char *authorityString = parcURI_GetAuthority(connectionURI); if (authorityString == NULL) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Unable to parse connection authority %s", authorityString); errno = EINVAL; return NULL; } // // This template link module doesn't use the authority fields. // The access methods are here for use by derived link modules, if needed. // PARCURIAuthority *authority = parcURIAuthority_Parse(authorityString); //const char *URIAddress = parcURIAuthority_GetHostName(authority); //in_port_t port = parcURIAuthority_GetPort(authority); parcURIAuthority_Release(&authority); int forceLocal = 0; char specifiedLinkName[MAXPATHLEN] = { 0 }; const char *linkName = NULL; // Parse connection segment parameters, Name and Local PARCURIPath *remainder = parcURI_GetPath(connectionURI); size_t segments = parcURIPath_Count(remainder); for (int i = 0; i < segments; i++) { PARCURISegment *segment = parcURIPath_Get(remainder, i); const char *token = parcURISegment_ToString(segment); if (strncasecmp(token, LINK_NAME_SPECIFIER, strlen(LINK_NAME_SPECIFIER)) == 0) { if (_parseLinkName(token, specifiedLinkName) != 0) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper connection name specification (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } linkName = specifiedLinkName; parcMemory_Deallocate(&token); continue; } if (strncasecmp(token, LOCAL_LINK_FLAG, strlen(LOCAL_LINK_FLAG)) == 0) { forceLocal = _parseLocalFlag(token); if (forceLocal == 0) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper local specification (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } parcMemory_Deallocate(&token); continue; } parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Unknown connection parameter (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } _TemplateLinkData *linkData = _TemplateLinkData_Create(); const char *derivedLinkName = _createNameFromLinkData(linkData); if (linkName == NULL) { linkName = derivedLinkName; } AthenaTransportLink *athenaTransportLink = athenaTransportLink_Create(linkName, _TemplateSend, _TemplateReceive, _TemplateClose); if (athenaTransportLink == NULL) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "athenaTransportLink_Create failed"); parcMemory_Deallocate(&derivedLinkName); _TemplateLinkData_Destroy(&linkData); return athenaTransportLink; } athenaTransportLink_SetPrivateData(athenaTransportLink, linkData); athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Send); parcLog_Info(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "new link established: Name=\"%s\" (%s)", linkName, derivedLinkName); parcMemory_Deallocate(&derivedLinkName); // forced IsLocal/IsNotLocal, mainly for testing if (athenaTransportLink && forceLocal) { athenaTransportLink_ForceLocal(athenaTransportLink, forceLocal); } return athenaTransportLink; }
static AthenaTransportLink * _ETHOpen(AthenaTransportLinkModule *athenaTransportLinkModule, PARCURI *connectionURI) { AthenaTransportLink *result = 0; char device[NI_MAXHOST]; const char *authorityString = parcURI_GetAuthority(connectionURI); if (authorityString == NULL) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Unable to parse connection authority %s", authorityString); errno = EINVAL; return NULL; } PARCURIAuthority *authority = parcURIAuthority_Parse(authorityString); const char *URIHostname = parcURIAuthority_GetHostName(authority); strcpy(device, URIHostname); bool srcMACSpecified = false; struct ether_addr srcMAC = { { 0 } }; struct ether_addr destMAC = { { 0 } }; if (_parseAddress(authorityString, &destMAC) != 0) { parcURIAuthority_Release(&authority); errno = EINVAL; return NULL; } parcURIAuthority_Release(&authority); bool isListener = false; char *linkName = NULL; char specifiedLinkName[MAXPATHLEN] = { 0 }; size_t mtu = 0; int forceLocal = 0; PARCURIPath *remainder = parcURI_GetPath(connectionURI); size_t segments = parcURIPath_Count(remainder); for (int i = 0; i < segments; i++) { PARCURISegment *segment = parcURIPath_Get(remainder, i); const char *token = parcURISegment_ToString(segment); if (strcasecmp(token, ETH_LISTENER_FLAG) == 0) { // Packet source for listener is destination parameter, unless told otherwise if (srcMACSpecified == false) { memcpy(&srcMAC, &destMAC, sizeof(struct ether_addr)); } isListener = true; parcMemory_Deallocate(&token); continue; } if (strncasecmp(token, SRC_LINK_SPECIFIER, strlen(SRC_LINK_SPECIFIER)) == 0) { if (_parseSrc(athenaTransportLinkModule, token, &srcMAC) != 0) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper connection source specification (%s)", token); parcMemory_Deallocate(&token); return NULL; } srcMACSpecified = true; parcMemory_Deallocate(&token); continue; } if (strncasecmp(token, LINK_MTU_SIZE, strlen(LINK_MTU_SIZE)) == 0) { if (_parseMTU(token, &mtu) == -1) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper MTU specification (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } parcMemory_Deallocate(&token); continue; } if (strncasecmp(token, LINK_NAME_SPECIFIER, strlen(LINK_NAME_SPECIFIER)) == 0) { if (_parseLinkName(token, specifiedLinkName) != 0) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper connection name specification (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } linkName = specifiedLinkName; parcMemory_Deallocate(&token); continue; } if (strncasecmp(token, LOCAL_LINK_FLAG, strlen(LOCAL_LINK_FLAG)) == 0) { forceLocal = _parseLocalFlag(token); if (forceLocal == 0) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Improper local specification (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } parcMemory_Deallocate(&token); continue; } parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "Unknown connection parameter (%s)", token); parcMemory_Deallocate(&token); errno = EINVAL; return NULL; } if (isListener) { result = _ETHOpenListener(athenaTransportLinkModule, linkName, device, &srcMAC, mtu); } else { if (srcMACSpecified) { result = _ETHOpenConnection(athenaTransportLinkModule, linkName, device, &srcMAC, &destMAC, mtu); } else { result = _ETHOpenConnection(athenaTransportLinkModule, linkName, device, NULL, &destMAC, mtu); } } // forced IsLocal/IsNotLocal, mainly for testing if (result && forceLocal) { athenaTransportLink_ForceLocal(result, forceLocal); } return result; }
// // Open a listener which will create new links when messages arrive and queue them appropriately. // Listeners are inherently insecure, as an adversary could easily create many connections that are never closed. // static AthenaTransportLink * _ETHOpenListener(AthenaTransportLinkModule *athenaTransportLinkModule, const char *linkName, const char *device, struct ether_addr *source, size_t mtu) { const char *derivedLinkName; _ETHLinkData *linkData = _ETHLinkData_Create(); linkData->multiplexTable = parcHashCodeTable_Create(_connectionEquals, _connectionHashCode, NULL, _closeConnection); assertNotNull(linkData->multiplexTable, "Could not create multiplex table for new listener"); linkData->athenaEthernet = athenaEthernet_Create(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), device, CCNX_ETHERTYPE); if (linkData->athenaEthernet == NULL) { _ETHLinkData_Destroy(&linkData); return NULL; } // Use specified source MAC address, or default to device MAC if (source) { memcpy(&(linkData->link.myAddress), source, sizeof(struct ether_addr)); } else { athenaEthernet_GetMAC(linkData->athenaEthernet, &(linkData->link.myAddress)); } linkData->link.myAddressLength = ETHER_ADDR_LEN; if (linkData->athenaEthernet == NULL) { parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), "athenaEthernet_Create error"); _ETHLinkData_Destroy(&linkData); return NULL; } derivedLinkName = _createNameFromLinkData(&linkData->link, true); if (linkName == NULL) { linkName = derivedLinkName; } // Listener doesn't require a send method. The receive method is used to establish new connections. AthenaTransportLink *athenaTransportLink = athenaTransportLink_Create(linkName, NULL, _ETHReceiveListener, _ETHClose); if (athenaTransportLink == NULL) { parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "athenaTransportLink_Create failed"); parcMemory_Deallocate(&derivedLinkName); _ETHLinkData_Destroy(&linkData); return athenaTransportLink; } athenaTransportLink_SetPrivateData(athenaTransportLink, linkData); athenaTransportLink_SetEventFd(athenaTransportLink, athenaEthernet_GetDescriptor(linkData->athenaEthernet)); // Links established for listening are not used to route messages. // They can be kept in a listener list that doesn't consume a linkId. athenaTransportLink_SetRoutable(athenaTransportLink, false); parcLog_Info(athenaTransportLink_GetLogger(athenaTransportLink), "new listener established: Name=\"%s\" (%s)", linkName, derivedLinkName); parcMemory_Deallocate(&derivedLinkName); return athenaTransportLink; }
// // Open a point to point connection. // static AthenaTransportLink * _ETHOpenConnection(AthenaTransportLinkModule *athenaTransportLinkModule, const char *linkName, const char *device, struct ether_addr *source, struct ether_addr *destination, size_t mtu) { const char *derivedLinkName; _ETHLinkData *linkData = _ETHLinkData_Create(); linkData->athenaEthernet = athenaEthernet_Create(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule), device, CCNX_ETHERTYPE); if (linkData->athenaEthernet == NULL) { _ETHLinkData_Destroy(&linkData); return NULL; } // Use our default MAC address if none specified. if (source == NULL) { athenaEthernet_GetMAC(linkData->athenaEthernet, &(linkData->link.myAddress)); linkData->link.myAddressLength = ETHER_ADDR_LEN; } else { memcpy(&(linkData->link.myAddress), source, sizeof(struct ether_addr)); } // If there's no destination specified, drop the request. if (destination == NULL) { _ETHLinkData_Destroy(&linkData); return NULL; } // Copy the peer destination address into our link data memcpy(&(linkData->link.peerAddress), destination, sizeof(struct ether_addr)); derivedLinkName = _createNameFromLinkData(&linkData->link, false); if (linkName == NULL) { linkName = derivedLinkName; } AthenaTransportLink *athenaTransportLink = athenaTransportLink_Create(linkName, _ETHSend, _ETHReceive, _ETHClose); if (athenaTransportLink == NULL) { parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "athenaTransportLink_Create failed"); parcMemory_Deallocate(&derivedLinkName); _ETHLinkData_Destroy(&linkData); return NULL; } _setConnectLinkState(athenaTransportLink, linkData); // Enable Sends athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Send); parcLog_Info(athenaTransportLink_GetLogger(athenaTransportLink), "new link established: Name=\"%s\" (%s)", linkName, derivedLinkName); parcMemory_Deallocate(&derivedLinkName); return athenaTransportLink; return NULL; }