// // Peek at the header and derive our total message length // static size_t _messageLengthFromHeader(AthenaTransportLink *athenaTransportLink, _UDPLinkData *linkData) { // Peek at our message header to determine the total length of buffer we need to allocate. size_t fixedHeaderLength = ccnxCodecTlvPacket_MinimalHeaderLength(); PARCBuffer *wireFormatBuffer = parcBuffer_Allocate(fixedHeaderLength); const uint8_t *peekBuffer = parcBuffer_Overlay(wireFormatBuffer, 0); ssize_t readCount = recv(linkData->fd, (void *) peekBuffer, fixedHeaderLength, MSG_PEEK); if (readCount == -1) { parcBuffer_Release(&wireFormatBuffer); if ((errno == EAGAIN) || (errno == EINTR)) { parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "recv retry (%s)", strerror(errno)); linkData->_stats.receive_ReadRetry++; } else { linkData->_stats.receive_ReadError++; parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "recv error (%s)", strerror(errno)); athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Error); } return -1; } // A zero read means no data if (readCount == 0) { parcBuffer_Release(&wireFormatBuffer); return -1; } // Check for a short header read, since we're only peeking here we just return and retry later if (readCount != fixedHeaderLength) { linkData->_stats.receive_ReadHeaderFailure++; parcBuffer_Release(&wireFormatBuffer); return -1; } // Obtain the total size of the message from the header size_t messageLength = ccnxCodecTlvPacket_GetPacketLength(wireFormatBuffer); parcBuffer_Release(&wireFormatBuffer); // Could do more to check the integrity of the message and framing. // If length is greater than our MTU we will find out in the read. if (messageLength < fixedHeaderLength) { linkData->_stats.receive_BadMessageLength++; parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "Framing error, flushing link."); char trash[MAXPATHLEN]; // Flush link to attempt to resync our framing while (read(linkData->fd, trash, sizeof(trash)) == sizeof(trash)) { parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "... flushing link."); } return -1; } return messageLength; }
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 CCNxMetaMessage * _TemplateReceive(AthenaTransportLink *athenaTransportLink) { struct _TemplateLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink); CCNxMetaMessage *ccnxMetaMessage = NULL; PARCBuffer *wireFormatBuffer = _internalRECEIVE(linkData); // On error, just return and retry. if (wireFormatBuffer == NULL) { parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "read error (%s)", strerror(errno)); return NULL; } // Construct, and return a ccnxMetaMessage from the wire format buffer. ccnxMetaMessage = ccnxMetaMessage_CreateFromWireFormatBuffer(wireFormatBuffer); if (ccnxMetaMessage == NULL) { linkData->_stats.receive_DecodeFailed++; parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "Failed to decode message from received packet."); } parcBuffer_Release(&wireFormatBuffer); if (parcDeque_Size(linkData->queue) > 0) { // if there's another message, mark an event. athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Receive); } return ccnxMetaMessage; }
LONGBOW_TEST_CASE(Global, parcLog_Error) { PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase); assertTrue(parcLog_Error(log, "This is a error message"), "Expected message to be logged successfully"); }
LONGBOW_TEST_CASE(Global, parcLog_Error_WrongLevel) { PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase); parcLog_SetLevel(log, PARCLogLevel_Off); assertFalse(parcLog_Error(log, "This is a debug message"), "Expected message to not be logged"); }
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; }
AthenaEthernet * athenaEthernet_Create(PARCLog *log, const char *interface, uint16_t etherType) { AthenaEthernet *athenaEthernet = parcObject_CreateAndClearInstance(AthenaEthernet); athenaEthernet->log = parcLog_Acquire(log); athenaEthernet->etherType = etherType; athenaEthernet->fd = _open_socket(interface); if (athenaEthernet->fd == -1) { parcLog_Error(athenaEthernet->log, "socket: %s", strerror(errno)); athenaEthernet_Release(&athenaEthernet); return NULL; } if (ioctl(athenaEthernet->fd, BIOCGBLEN, &(athenaEthernet->etherBufferLength))) { perror("error getting buffer length"); return NULL; } // Populate the configured physical MAC and MTU by searching ifaddrs struct ifaddrs *ifaddr; int res = getifaddrs(&ifaddr); if (res == -1) { perror("getifaddrs"); return 0; } struct ifaddrs *next; for (next = ifaddr; next != NULL; next = next->ifa_next) { if (strcmp(next->ifa_name, interface) == 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. memcpy(&(athenaEthernet->mac), &addr_dl->sdl_data[addr_dl->sdl_nlen], addr_dl->sdl_alen); struct if_data *ifdata = (struct if_data *) next->ifa_data; athenaEthernet->mtu = ifdata->ifi_mtu; // break out of loop and freeifaddrs break; } } } freeifaddrs(ifaddr); return athenaEthernet; }
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; }
// // Receive a message from the specified link. // static CCNxMetaMessage * _ETHReceiveMessage(AthenaTransportLink *athenaTransportLink, struct ether_addr *peerAddress, socklen_t *peerAddressLength) { struct _ETHLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink); CCNxMetaMessage *ccnxMetaMessage = NULL; AthenaTransportLinkEvent events = 0; PARCBuffer *message = athenaEthernet_Receive(linkData->athenaEthernet, -1, &events); if (message == NULL) { return NULL; } // Mark any pending events if (events) { athenaTransportLink_SetEvent(athenaTransportLink, events); } // Map the header struct ether_header *header = parcBuffer_Overlay(message, sizeof(struct ether_header)); // If the destination does not match my address, drop the message if (memcmp(&linkData->link.myAddress, header->ether_dhost, ETHER_ADDR_LEN * sizeof(uint8_t)) != 0) { linkData->_stats.receive_NoLinkDestination++; parcBuffer_Release(&message); return NULL; } assertTrue(header->ether_type == htons(CCNX_ETHERTYPE), "Unexpected ether type %x", header->ether_type); // Set peerAddress from header source address *peerAddressLength = ETHER_ADDR_LEN * sizeof(uint8_t); memcpy(peerAddress, header->ether_shost, *peerAddressLength); parcBuffer_SetPosition(message, sizeof(struct ether_header)); PARCBuffer *wireFormatBuffer = parcBuffer_Slice(message); parcBuffer_Release(&message); parcBuffer_SetPosition(wireFormatBuffer, 0); // Construct, and return a ccnxMetaMessage from the wire format buffer. ccnxMetaMessage = ccnxMetaMessage_CreateFromWireFormatBuffer(wireFormatBuffer); if (ccnxMetaMessage == NULL) { linkData->_stats.receive_DecodeFailed++; parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "Failed to decode message from received packet."); } else if (ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage) == CCNxTlvDictionary_SchemaVersion_V0) { parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "received deprecated version %d message\n", ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage)); } parcBuffer_Release(&wireFormatBuffer); return ccnxMetaMessage; }
PARCBuffer * athenaEthernet_Receive(AthenaEthernet *athenaEthernet, int timeout, AthenaTransportLinkEvent *events) { // Allocate, and read, a new BPF buffer if no packets are currently pending in an old one if (athenaEthernet->bpfBuffer == NULL) { athenaEthernet->bpfBuffer = parcBuffer_Allocate(athenaEthernet->etherBufferLength); uint8_t *buffer = parcBuffer_Overlay(athenaEthernet->bpfBuffer, 0); athenaEthernet->readCount = read(athenaEthernet->fd, buffer, athenaEthernet->etherBufferLength); if (athenaEthernet->readCount == -1) { if ((errno == EAGAIN) || (errno == EINTR)) { parcLog_Info(athenaEthernet->log, "Ethernet read retry"); return NULL; } parcLog_Error(athenaEthernet->log, "recv: %s", strerror(errno)); *events = AthenaTransportLinkEvent_Error; parcBuffer_Release(&athenaEthernet->bpfBuffer); return NULL; } parcLog_Debug(athenaEthernet->log, "received bpf packet (size=%d)", athenaEthernet->readCount); } // Obtain the current position in the BPF buffer to return a message from size_t position = parcBuffer_Position(athenaEthernet->bpfBuffer); // Read the BPF header and seek past it struct bpf_hdr *bpfhdr = parcBuffer_Overlay(athenaEthernet->bpfBuffer, sizeof(struct bpf_hdr)); parcBuffer_SetLimit(athenaEthernet->bpfBuffer, position + bpfhdr->bh_hdrlen + bpfhdr->bh_datalen); parcBuffer_SetPosition(athenaEthernet->bpfBuffer, position + bpfhdr->bh_hdrlen); parcLog_Debug(athenaEthernet->log, "received message (size=%d)", bpfhdr->bh_datalen); // Slice a new PARCBuffer with the message to send up. PARCBuffer *wireFormatBuffer = parcBuffer_Slice(athenaEthernet->bpfBuffer); // If there's another packet in the buffer, position it and flag a receive event if ((athenaEthernet->readCount - (position + bpfhdr->bh_hdrlen + bpfhdr->bh_datalen)) != 0) { parcBuffer_SetLimit(athenaEthernet->bpfBuffer, athenaEthernet->readCount); parcBuffer_SetPosition(athenaEthernet->bpfBuffer, BPF_WORDALIGN(position + bpfhdr->bh_hdrlen + bpfhdr->bh_datalen)); // Mark a receive event for this packet *events = AthenaTransportLinkEvent_Receive; } else { parcBuffer_Release(&athenaEthernet->bpfBuffer); } return wireFormatBuffer; }
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 * _Control_Command_Spawn(Athena *athena, CCNxName *ccnxName, const char *command, const char *connectionSpecification) { CCNxMetaMessage *responseMessage; // Create a new athena instance Athena *newAthena = athena_Create(AthenaDefaultContentStoreSize); if (newAthena == NULL) { responseMessage = _create_response(athena, ccnxName, "Could not create a new Athena instance"); return responseMessage; } // Add the specified link PARCURI *connectionURI = parcURI_Parse(connectionSpecification); if (athenaTransportLinkAdapter_Open(newAthena->athenaTransportLinkAdapter, connectionURI) == NULL) { parcLog_Error(athena->log, "Unable to configure an interface. Exiting..."); responseMessage = _create_response(athena, ccnxName, "Unable to configure an Athena interface for thread"); parcURI_Release(&connectionURI); athena_Release(&newAthena); return responseMessage; } parcURI_Release(&connectionURI); pthread_t thread; // Passing in a reference that will be released by the new thread as the thread may not // have time to acquire a reference itself before we release our reference. if (pthread_create(&thread, NULL, _start_forwarder_instance, (void *) athena_Acquire(newAthena)) != 0) { responseMessage = _create_response(athena, ccnxName, "Athena process thread creation failed"); return responseMessage; } athena_Release(&newAthena); athenaInterestControl_LogConfigurationChange(athena, ccnxName, "%s", connectionSpecification); responseMessage = _create_response(athena, ccnxName, "Athena process thread started on %s", connectionSpecification); return responseMessage; }
int athenaTransportLinkAdapter_Poll(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, int timeout) { struct pollfd *pollfdReceiveList = athenaTransportLinkAdapter->pollfdReceiveList; struct pollfd *pollfdSendList = athenaTransportLinkAdapter->pollfdSendList; int pollfdListSize = athenaTransportLinkAdapter->pollfdListSize; AthenaTransportLinkModule *athenaTransportLinkModule; int events = 0; // Allow instances which have not registered an eventfd to mark their events if (athenaTransportLinkAdapter->moduleList) { for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->moduleList); index++) { athenaTransportLinkModule = parcArrayList_Get(athenaTransportLinkAdapter->moduleList, index); events += athenaTransportLinkModule_Poll(athenaTransportLinkModule, timeout); } } if (events) { // if we have existing events, poll doesn't need to block timeout = 0; } int result = poll(pollfdReceiveList, pollfdListSize, timeout); if (result < 0) { parcLog_Error(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter), "Receive list poll error: (%d) %s", errno, strerror(errno)); } else { for (int index = 0; index < pollfdListSize; index++) { if (pollfdReceiveList[index].revents) { AthenaTransportLink *athenaTransportLink = athenaTransportLinkAdapter->pollfdTransportLink[index]; if (athenaTransportLink) { if (pollfdReceiveList[index].revents & (POLLERR | POLLHUP)) { athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Error); athenaTransportLink_Close(athenaTransportLink); } if (pollfdReceiveList[index].revents & POLLIN) { athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Receive); } else { athenaTransportLink_ClearEvent(athenaTransportLink, AthenaTransportLinkEvent_Receive); } } } } } result = poll(pollfdSendList, pollfdListSize, 0); if (result < 0) { parcLog_Error(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter), "Send list poll error: (%d) %s", errno, strerror(errno)); } else { for (int index = 0; index < pollfdListSize; index++) { if (pollfdSendList[index].revents) { AthenaTransportLink *athenaTransportLink = athenaTransportLinkAdapter->pollfdTransportLink[index]; if (athenaTransportLink) { if (pollfdSendList[index].revents & (POLLNVAL | POLLHUP | POLLERR)) { continue; } if (pollfdSendList[index].revents & (POLLERR | POLLHUP)) { athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Error); athenaTransportLink_Close(athenaTransportLink); } if (pollfdSendList[index].revents & POLLOUT) { athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Send); } else { athenaTransportLink_ClearEvent(athenaTransportLink, AthenaTransportLinkEvent_Send); } } } } //events += result; // don't register send events } return events; }
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; }
// // Receive a message from the specified link. // static CCNxMetaMessage * _UDPReceiveMessage(AthenaTransportLink *athenaTransportLink, struct sockaddr_in *peerAddress, socklen_t *peerAddressLength) { struct _UDPLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink); CCNxMetaMessage *ccnxMetaMessage = NULL; size_t messageLength; // If an MTU has been set, allocate a buffer of that size to avoid having to peek at the message, // othersize derive the link from the header and allocate a buffer based on the message size. if ((messageLength = linkData->link.mtu) == 0) { messageLength = _messageLengthFromHeader(athenaTransportLink, linkData); if (messageLength <= 0) { return NULL; } } PARCBuffer *wireFormatBuffer = parcBuffer_Allocate(messageLength); char *buffer = parcBuffer_Overlay(wireFormatBuffer, 0); *peerAddressLength = (socklen_t) sizeof(struct sockaddr_in); ssize_t readCount = recvfrom(linkData->fd, buffer, messageLength, 0, (struct sockaddr *) peerAddress, peerAddressLength); // On error, just return and retry. if (readCount == -1) { linkData->_stats.receive_ReadError++; parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "read error (%s)", strerror(errno)); parcBuffer_Release(&wireFormatBuffer); return NULL; } // A zero read means either no more data is currently available or our peer hungup. // Just return to retry as we'll detect EOF when we come back at the top of UDPReceive if (readCount == 0) { parcBuffer_Release(&wireFormatBuffer); return NULL; } // If it was it a short read just return to retry later. while (readCount < messageLength) { linkData->_stats.receive_ShortRead++; parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "short read error (%s)", strerror(errno)); parcBuffer_Release(&wireFormatBuffer); return NULL; } parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "received message (size=%d)", readCount); parcBuffer_SetPosition(wireFormatBuffer, parcBuffer_Position(wireFormatBuffer) + readCount); parcBuffer_Flip(wireFormatBuffer); // Construct, and return a ccnxMetaMessage from the wire format buffer. ccnxMetaMessage = ccnxMetaMessage_CreateFromWireFormatBuffer(wireFormatBuffer); if (ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage) == CCNxTlvDictionary_SchemaVersion_V0) { parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "received deprecated version %d message\n", ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage)); } if (ccnxMetaMessage == NULL) { linkData->_stats.receive_DecodeFailed++; parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "Failed to decode message from received packet."); } parcBuffer_Release(&wireFormatBuffer); return ccnxMetaMessage; }
// // 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; }
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; }
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 = athenaTransportLinkModule_GetMessageBuffer(ccnxMetaMessage); parcBuffer_SetPosition(wireFormatBuffer, 0); 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 == EAGAIN) || (errno == EINTR)) { linkData->_stats.send_SendRetry++; parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "send retry (%s)", strerror(errno)); } else { 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.send_ShortWrite++; parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "short write"); parcBuffer_Release(&wireFormatBuffer); return -1; } parcBuffer_Release(&wireFormatBuffer); return 0; }
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; }
// // 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; }
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; }
static void _processInterest(Athena *athena, CCNxInterest *interest, PARCBitVector *ingressVector) { uint8_t hoplimit; // // * (0) Hoplimit check, exclusively on interest messages // int linkId = parcBitVector_NextBitSet(ingressVector, 0); if (athenaTransportLinkAdapter_IsNotLocal(athena->athenaTransportLinkAdapter, linkId)) { hoplimit = ccnxInterest_GetHopLimit(interest); if (hoplimit == 0) { // We should never receive a message with a hoplimit of 0 from a non-local source. parcLog_Error(athena->log, "Received a message with a hoplimit of zero from a non-local source (%s).", athenaTransportLinkAdapter_LinkIdToName(athena->athenaTransportLinkAdapter, linkId)); return; } ccnxInterest_SetHopLimit(interest, hoplimit - 1); } // // * (1) if the interest is in the ContentStore, reply and return, // assuming that other PIT entries were satisified when the content arrived. // CCNxMetaMessage *content = athenaContentStore_GetMatch(athena->athenaContentStore, interest); if (content) { const char *ingressVectorString = parcBitVector_ToString(ingressVector); parcLog_Debug(athena->log, "Forwarding content from store to %s", ingressVectorString); parcMemory_Deallocate(&ingressVectorString); PARCBitVector *result = athenaTransportLinkAdapter_Send(athena->athenaTransportLinkAdapter, content, ingressVector); if (result) { // failed channels - client will resend interest unless we wish to optimize things here parcBitVector_Release(&result); } return; } // // * (2) add it to the PIT, if it was aggregated or there was an error we're done, otherwise we // forward the interest. The expectedReturnVector is populated with information we get from // the FIB and used to verify content objects ingress ports when they arrive. // PARCBitVector *expectedReturnVector; AthenaPITResolution result; if ((result = athenaPIT_AddInterest(athena->athenaPIT, interest, ingressVector, &expectedReturnVector)) != AthenaPITResolution_Forward) { if (result == AthenaPITResolution_Error) { parcLog_Error(athena->log, "PIT resolution error"); } return; } // Divert interests destined to the forwarder, we assume these are control messages CCNxName *ccnxName = ccnxInterest_GetName(interest); if (ccnxName_StartsWith(ccnxName, athena->athenaName) == true) { _processInterestControl(athena, interest, ingressVector); return; } // // * (3) if it's in the FIB, forward, then update the PIT expectedReturnVector so we can verify // when the returned object arrives that it came from an interface it was expected from. // Interest messages with a hoplimit of 0 will never be sent out by the link adapter to a // non-local interface so we need not check that here. // ccnxName = ccnxInterest_GetName(interest); PARCBitVector *egressVector = athenaFIB_Lookup(athena->athenaFIB, ccnxName); if (egressVector != NULL) { // Remove the link the interest came from if it was included in the FIB entry parcBitVector_ClearVector(egressVector, ingressVector); // If no links remain, send a no route interest return message if (parcBitVector_NumberOfBitsSet(egressVector) == 0) { CCNxInterestReturn *interestReturn = ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoRoute); PARCBitVector *result = athenaTransportLinkAdapter_Send(athena->athenaTransportLinkAdapter, interestReturn, ingressVector); parcBitVector_Release(&result); ccnxInterestReturn_Release(&interestReturn); } else { parcBitVector_SetVector(expectedReturnVector, egressVector); PARCBitVector *result = athenaTransportLinkAdapter_Send(athena->athenaTransportLinkAdapter, interest, egressVector); if (result) { // remove failed channels - client will resend interest unless we wish to optimize here parcBitVector_ClearVector(expectedReturnVector, result); parcBitVector_Release(&result); } } } else { // No FIB entry found, return a NoRoute interest return and remove the entry from the PIT. CCNxInterestReturn *interestReturn = ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoRoute); PARCBitVector *result = athenaTransportLinkAdapter_Send(athena->athenaTransportLinkAdapter, interestReturn, ingressVector); parcBitVector_Release(&result); ccnxInterestReturn_Release(&interestReturn); const char *name = ccnxName_ToString(ccnxName); if (athenaPIT_RemoveInterest(athena->athenaPIT, interest, ingressVector) != true) { parcLog_Error(athena->log, "Unable to remove interest (%s) from the PIT.", name); } parcLog_Debug(athena->log, "Name (%s) not found in FIB and no default route. Message dropped.", name); parcMemory_Deallocate(&name); } }
static AthenaTransportLinkModule * _LoadModule(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, const char *moduleName) { assertTrue(_LookupModule(athenaTransportLinkAdapter, moduleName) == NULL, "attempt to load an already loaded module"); // Derive the entry initialization name from the provided module name const char *moduleEntry; moduleEntry = _moduleNameToInitMethod(moduleName); // Check to see if the module was statically linked in. void *linkModule = RTLD_DEFAULT; ModuleInit _init = dlsym(linkModule, moduleEntry); // If not statically linked in, look for a shared library and load it from there if (_init == NULL) { // Derive the library name from the provided module name const char *moduleLibrary; moduleLibrary = _moduleNameToLibrary(moduleName); void *linkModule = dlopen(moduleLibrary, RTLD_NOW | RTLD_GLOBAL); parcMemory_Deallocate(&moduleLibrary); // If the shared library wasn't found, look for the symbol in our existing image. This // allows a link module to be linked directly into Athena without modifying the forwarder. if (linkModule == NULL) { parcLog_Error(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter), "Unable to dlopen %s: %s", moduleName, dlerror()); parcMemory_Deallocate(&moduleEntry); errno = ENOENT; return NULL; } _init = dlsym(linkModule, moduleEntry); if (_init == NULL) { parcLog_Error(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter), "Unable to find %s module _init method: %s", moduleName, dlerror()); parcMemory_Deallocate(&moduleEntry); dlclose(linkModule); errno = ENOENT; return NULL; } } parcMemory_Deallocate(&moduleEntry); // Call the initialization method. PARCArrayList *moduleList = _init(); if (moduleList == NULL) { // if the init method fails, unload the module if it was loaded parcLog_Error(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter), "Empty module list returned from %s module", moduleName); if (linkModule != RTLD_DEFAULT) { dlclose(linkModule); } errno = ENOENT; return NULL; } // Process each link module instance (typically only one) for (int index = 0; index < parcArrayList_Size(moduleList); index++) { AthenaTransportLinkModule *athenaTransportLinkModule = parcArrayList_Get(moduleList, index); _AddModule(athenaTransportLinkAdapter, athenaTransportLinkModule); } parcArrayList_Destroy(&moduleList); return _LookupModule(athenaTransportLinkAdapter, moduleName); }
static void _parseCommandLine(Athena *athena, int argc, char **argv) { int c; bool interfaceConfigured = false; while ((c = getopt_long(argc, argv, "hs:c:vd", options, NULL)) != -1) { switch (c) { case 's': { int sizeInMB = atoi(optarg); if (athenaContentStore_SetCapacity(athena->athenaContentStore, sizeInMB) != true) { parcLog_Error(athena->log, "Unable to resize content store to %d (MB)", sizeInMB); } _contentStoreSizeInMB = sizeInMB; break; } case 'c': { PARCURI *connectionURI = parcURI_Parse(optarg); const char *result = athenaTransportLinkAdapter_Open(athena->athenaTransportLinkAdapter, connectionURI); if (result == NULL) { parcLog_Error(athena->log, "Unable to configure %s: %s", optarg, strerror(errno)); parcURI_Release(&connectionURI); exit(EXIT_FAILURE); } parcURI_Release(&connectionURI); interfaceConfigured = true; break; } case 'v': printf("%s\n", athenaAbout_Version()); exit(0); case 'd': athenaTransportLinkAdapter_SetLogLevel(athena->athenaTransportLinkAdapter, PARCLogLevel_Debug); parcLog_SetLevel(athena->log, PARCLogLevel_Debug); break; case 'h': default: _usage(); exit(EXIT_FAILURE); break; } } if (argc - optind) { parcLog_Error(athena->log, "Bad arguments"); _usage(); exit(EXIT_FAILURE); } if (interfaceConfigured != true) { PARCURI *connectionURI = parcURI_Parse(_athenaDefaultConnectionURI); if (athenaTransportLinkAdapter_Open(athena->athenaTransportLinkAdapter, connectionURI) == NULL) { parcLog_Error(athena->log, "Unable to configure an interface. Exiting..."); parcURI_Release(&connectionURI); exit(EXIT_FAILURE); } parcURI_Release(&connectionURI); struct utsname name; if (uname(&name) == 0) { char nodeURIspecification[MAXPATHLEN]; sprintf(nodeURIspecification, "tcp://%s:%d/listener", name.nodename, AthenaDefaultListenerPort); PARCURI *nodeURI = parcURI_Parse(nodeURIspecification); if (athenaTransportLinkAdapter_Open(athena->athenaTransportLinkAdapter, nodeURI) == NULL) { parcURI_Release(&nodeURI); } } } }
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; }