/** * Notifies this <tt>ResponseCollector</tt> that a transaction described by the specified * <tt>BaseStunMessageEvent</tt> has failed. The possible reasons for the failure include * timeouts, unreachable destination, etc. * * @param event the <tt>BaseStunMessageEvent</tt> which describes the failed transaction and the * runtime type of which specifies the failure reason * @see AbstractResponseCollector#processFailure(BaseStunMessageEvent) */ @Override protected void processFailure(BaseStunMessageEvent event) { TransactionID transactionID = event.getTransactionID(); logger.finest("A transaction expired: tranid=" + transactionID); logger.finest("localAddr=" + hostCandidate); /* * Clean up for the purposes of the workaround which determines the STUN * Request to which a STUN Response responds. */ Request request; synchronized (requests) { request = requests.remove(transactionID); } if (request == null) { Message message = event.getMessage(); if (message instanceof Request) request = (Request) message; } boolean completedResolvingCandidate = true; try { if (processErrorOrFailure(null, request, transactionID)) completedResolvingCandidate = false; } finally { if (completedResolvingCandidate) completedResolvingCandidate(request, null); } }
/** * Notifies this <tt>ResponseCollector</tt> that a STUN response described by the specified * <tt>StunResponseEvent</tt> has been received. * * @param event the <tt>StunResponseEvent</tt> which describes the received STUN response * @see ResponseCollector#processResponse(StunResponseEvent) */ @Override public void processResponse(StunResponseEvent event) { TransactionID transactionID = event.getTransactionID(); logger.finest("Received a message: tranid= " + transactionID); logger.finest("localCand= " + hostCandidate); /* * Clean up for the purposes of the workaround which determines the STUN * Request to which a STUN Response responds. */ synchronized (requests) { requests.remove(transactionID); } // At long last, do start handling the received STUN Response. Response response = event.getResponse(); Request request = event.getRequest(); boolean completedResolvingCandidate = true; try { if (response.isSuccessResponse()) { // Authentication and Message-Integrity Mechanisms if (request.containsAttribute(Attribute.MESSAGE_INTEGRITY)) { MessageIntegrityAttribute messageIntegrityAttribute = (MessageIntegrityAttribute) response.getAttribute(Attribute.MESSAGE_INTEGRITY); /* * RFC 5389: If MESSAGE-INTEGRITY was absent, the response * MUST be discarded, as if it was never received. */ if (messageIntegrityAttribute == null) return; UsernameAttribute usernameAttribute = (UsernameAttribute) request.getAttribute(Attribute.USERNAME); /* * For a request or indication message, the agent MUST * include the USERNAME and MESSAGE-INTEGRITY attributes in * the message. */ if (usernameAttribute == null) return; if (!harvester .getStunStack() .validateMessageIntegrity( messageIntegrityAttribute, LongTermCredential.toString(usernameAttribute.getUsername()), !request.containsAttribute(Attribute.REALM) && !request.containsAttribute(Attribute.NONCE), event.getRawMessage())) return; } processSuccess(response, request, transactionID); } else { ErrorCodeAttribute errorCodeAttr = (ErrorCodeAttribute) response.getAttribute(Attribute.ERROR_CODE); if ((errorCodeAttr != null) && (errorCodeAttr.getErrorClass() == 4)) { try { switch (errorCodeAttr.getErrorNumber()) { case 1: // 401 Unauthorized if (processUnauthorized(response, request, transactionID)) completedResolvingCandidate = false; break; case 38: // 438 Stale Nonce if (processStaleNonce(response, request, transactionID)) completedResolvingCandidate = false; break; } } catch (StunException sex) { completedResolvingCandidate = true; } } if (completedResolvingCandidate && processErrorOrFailure(response, request, transactionID)) completedResolvingCandidate = false; } } finally { if (completedResolvingCandidate) completedResolvingCandidate(request, response); } }