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