/** * Creates a client transaction to handle a new request. Gets the real message channel from the * superclass, and then creates a new client transaction wrapped around this channel. * * @param nextHop Hop to create a channel to contact. */ public MessageChannel createMessageChannel(int sourcePort, Hop nextHop) throws UnknownHostException { synchronized (clientTransactions) { // New client transaction to return SIPTransaction returnChannel; // Create a new client transaction around the // superclass' message channel MessageChannel mc = super.createMessageChannel(sourcePort, nextHop); // Superclass will return null if no message processor // available for the transport. if (mc == null) return null; returnChannel = createClientTransaction(mc); clientTransactions.add(0, (SIPClientTransaction) returnChannel); ((SIPClientTransaction) returnChannel).setViaPort(nextHop.getPort()); ((SIPClientTransaction) returnChannel).setViaHost(nextHop.getHost()); // Add the transaction timer for the state machine. returnChannel.startTransactionTimer(); return returnChannel; } }
/** * Gets invoked by the parser as a callback on successful message parsing (i.e. no parser errors). * * @param sipMessage Message to process (this calls the application for processing the message). * <p>Jvb: note that this code is identical to TCPMessageChannel, refactor some day */ public void processMessage(SIPMessage sipMessage) throws Exception { try { if (sipMessage.getFrom() == null || sipMessage.getTo() == null || sipMessage.getCallId() == null || sipMessage.getCSeq() == null || sipMessage.getViaHeaders() == null) { if (logger.isLoggingEnabled()) { String badmsg = sipMessage.encode(); logger.logError("bad message " + badmsg); logger.logError(">>> Dropped Bad Msg"); } return; } sipMessage.setRemoteAddress(this.peerAddress); sipMessage.setRemotePort(this.getPeerPort()); sipMessage.setLocalAddress(this.getMessageProcessor().getIpAddress()); sipMessage.setLocalPort(this.getPort()); // Issue 3: https://telestax.atlassian.net/browse/JSIP-3 sipMessage.setPeerPacketSourceAddress(this.peerAddress); sipMessage.setPeerPacketSourcePort(this.peerPort); ViaList viaList = sipMessage.getViaHeaders(); // For a request // first via header tells where the message is coming from. // For response, this has already been recorded in the outgoing // message. if (sipMessage instanceof SIPRequest) { Via v = (Via) viaList.getFirst(); // the peer address and tag it appropriately. Hop hop = sipStack.addressResolver.resolveAddress(v.getHop()); this.peerProtocol = v.getTransport(); // if(peerPortAdvertisedInHeaders <= 0) { int hopPort = v.getPort(); if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { logger.logDebug( "hop port = " + hopPort + " for request " + sipMessage + " for this channel " + this + " key " + key); } if (hopPort <= 0) { // if port is 0 we assume the default port for TCP this.peerPortAdvertisedInHeaders = 5060; } else { this.peerPortAdvertisedInHeaders = hopPort; } if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { logger.logDebug( "3.Storing peerPortAdvertisedInHeaders = " + peerPortAdvertisedInHeaders + " for this channel " + this + " key " + key); } // } // may be needed to reconnect, when diff than peer address if (peerAddressAdvertisedInHeaders == null) { peerAddressAdvertisedInHeaders = hop.getHost(); if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { logger.logDebug( "3.Storing peerAddressAdvertisedInHeaders = " + peerAddressAdvertisedInHeaders + " for this channel " + this + " key " + key); } } try { if (mySock != null) { // selfrouting makes socket = null // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=297 this.peerAddress = mySock.getInetAddress(); } // Check to see if the received parameter matches // the peer address and tag it appropriately. // JvB: dont do this. It is both costly and incorrect // Must set received also when it is a FQDN, regardless // whether // it resolves to the correct IP address // InetAddress sentByAddress = // InetAddress.getByName(hop.getHost()); // JvB: if sender added 'rport', must always set received boolean hasRPort = v.hasParameter(Via.RPORT); if (!hasRPort && v.getPort() != peerPort) { // https://github.com/RestComm/jain-sip/issues/79 if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { logger.logDebug( "setting rport since viaPort " + v.getPort() + " different than peerPacketSourcePort " + peerPort + " so that the response can be routed back"); } hasRPort = true; } if (hasRPort || !hop.getHost().equals(this.peerAddress.getHostAddress())) { v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress()); } // @@@ hagai // JvB: technically, may only do this when Via already // contains // rport v.setParameter(Via.RPORT, Integer.toString(this.peerPort)); } catch (java.text.ParseException ex) { InternalErrorHandler.handleException(ex); } // Use this for outgoing messages as well. if (!this.isCached && mySock != null) { // self routing makes // mySock=null // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=297 this.isCached = true; int remotePort = ((java.net.InetSocketAddress) mySock.getRemoteSocketAddress()).getPort(); String key = IOHandler.makeKey(mySock.getInetAddress(), remotePort); if (this.messageProcessor instanceof NioTcpMessageProcessor) { // https://java.net/jira/browse/JSIP-475 don't use iohandler in case of NIO // communications of the socket will leak in the iohandler sockettable ((NioTcpMessageProcessor) this.messageProcessor) .nioHandler.putSocket(key, mySock.getChannel()); } else { sipStack.ioHandler.putSocket(key, mySock); } // since it can close the socket it needs to be after the mySock usage otherwise // it the socket will be disconnected and NPE will be thrown in some edge cases ((ConnectionOrientedMessageProcessor) this.messageProcessor).cacheMessageChannel(this); } } // Foreach part of the request header, fetch it and process it long receptionTime = System.currentTimeMillis(); // if (sipMessage instanceof SIPRequest) { // This is a request - process the request. SIPRequest sipRequest = (SIPRequest) sipMessage; // Create a new sever side request processor for this // message and let it handle the rest. if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { logger.logDebug("----Processing Message---"); } if (logger.isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) { sipStack.serverLogger.logMessage( sipMessage, this.getPeerHostPort().toString(), this.messageProcessor.getIpAddress().getHostAddress() + ":" + this.messageProcessor.getPort(), false, receptionTime); } // Check for reasonable size - reject message // if it is too long. if (sipStack.getMaxMessageSize() > 0 && sipRequest.getSize() + (sipRequest.getContentLength() == null ? 0 : sipRequest.getContentLength().getContentLength()) > sipStack.getMaxMessageSize()) { SIPResponse sipResponse = sipRequest.createResponse(SIPResponse.MESSAGE_TOO_LARGE); byte[] resp = sipResponse.encodeAsBytes(this.getTransport()); this.sendMessage(resp, false); throw new Exception("Message size exceeded"); } String sipVersion = ((SIPRequest) sipMessage).getRequestLine().getSipVersion(); if (!sipVersion.equals("SIP/2.0")) { SIPResponse versionNotSupported = ((SIPRequest) sipMessage) .createResponse(Response.VERSION_NOT_SUPPORTED, "Bad SIP version " + sipVersion); this.sendMessage(versionNotSupported.encodeAsBytes(this.getTransport()), false); throw new Exception("Bad version "); } String method = ((SIPRequest) sipMessage).getMethod(); String cseqMethod = ((SIPRequest) sipMessage).getCSeqHeader().getMethod(); if (!method.equalsIgnoreCase(cseqMethod)) { SIPResponse sipResponse = sipRequest.createResponse(SIPResponse.BAD_REQUEST); byte[] resp = sipResponse.encodeAsBytes(this.getTransport()); this.sendMessage(resp, false); throw new Exception("Bad CSeq method" + sipMessage + " method " + method); } // Stack could not create a new server request interface. // maybe not enough resources. ServerRequestInterface sipServerRequest = sipStack.newSIPServerRequest(sipRequest, this); if (sipServerRequest != null) { try { sipServerRequest.processRequest(sipRequest, this); } finally { if (sipServerRequest instanceof SIPTransaction) { SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest; if (!sipServerTx.passToListener()) ((SIPTransaction) sipServerRequest).releaseSem(); } } } else { if (sipStack.sipMessageValve == null) { // Allow message valves to nullify messages without error SIPResponse response = sipRequest.createResponse(Response.SERVICE_UNAVAILABLE); RetryAfter retryAfter = new RetryAfter(); // Be a good citizen and send a decent response code back. try { retryAfter.setRetryAfter((int) (10 * (Math.random()))); response.setHeader(retryAfter); this.sendMessage(response); } catch (Exception e) { // IGNore } if (logger.isLoggingEnabled()) logger.logWarning("Dropping message -- could not acquire semaphore"); } } } else { SIPResponse sipResponse = (SIPResponse) sipMessage; // JvB: dont do this // if (sipResponse.getStatusCode() == 100) // sipResponse.getTo().removeParameter("tag"); try { sipResponse.checkHeaders(); } catch (ParseException ex) { if (logger.isLoggingEnabled()) logger.logError("Dropping Badly formatted response message >>> " + sipResponse); return; } // This is a response message - process it. // Check the size of the response. // If it is too large dump it silently. if (sipStack.getMaxMessageSize() > 0 && sipResponse.getSize() + (sipResponse.getContentLength() == null ? 0 : sipResponse.getContentLength().getContentLength()) > sipStack.getMaxMessageSize()) { if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) logger.logDebug("Message size exceeded"); return; } ServerResponseInterface sipServerResponse = sipStack.newSIPServerResponse(sipResponse, this); if (sipServerResponse != null) { try { if (sipServerResponse instanceof SIPClientTransaction && !((SIPClientTransaction) sipServerResponse).checkFromTag(sipResponse)) { if (logger.isLoggingEnabled()) logger.logError("Dropping response message with invalid tag >>> " + sipResponse); return; } sipServerResponse.processResponse(sipResponse, this); } finally { if (sipServerResponse instanceof SIPTransaction && !((SIPTransaction) sipServerResponse).passToListener()) { // Note that the semaphore is released in event // scanner if the // request is actually processed by the Listener. ((SIPTransaction) sipServerResponse).releaseSem(); } } } else { logger.logWarning( "Application is blocked -- could not acquire semaphore -- dropping response"); } } } finally { } }
/** * Process an incoming datagram * * @param packet is the incoming datagram packet. */ private void processIncomingDataPacket(DatagramPacket packet) throws Exception { this.peerAddress = packet.getAddress(); int packetLength = packet.getLength(); // Read bytes and put it in a eueue. byte[] bytes = packet.getData(); byte[] msgBytes = new byte[packetLength]; System.arraycopy(bytes, 0, msgBytes, 0, packetLength); // Do debug logging. if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack .getStackLogger() .logDebug( "UDPMessageChannel: processIncomingDataPacket : peerAddress = " + peerAddress.getHostAddress() + "/" + packet.getPort() + " Length = " + packetLength); } SIPMessage sipMessage = null; try { this.receptionTime = System.currentTimeMillis(); sipMessage = myParser.parseSIPMessage(msgBytes, true, false, this); // myParser = null; } catch (ParseException ex) { // myParser = null; // let go of the parser reference. if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack.getStackLogger().logDebug("Rejecting message ! " + new String(msgBytes)); this.sipStack.getStackLogger().logDebug("error message " + ex.getMessage()); this.sipStack.getStackLogger().logException(ex); } // JvB: send a 400 response for requests (except ACK) // Currently only UDP, @todo also other transports String msgString = new String(msgBytes, 0, packetLength); if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) { String badReqRes = createBadReqRes(msgString, ex); if (badReqRes != null) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("Sending automatic 400 Bad Request:"); sipStack.getStackLogger().logDebug(badReqRes); } try { this.sendMessage(badReqRes.getBytes(), peerAddress, packet.getPort(), "UDP", false); } catch (IOException e) { this.sipStack.getStackLogger().logException(e); } } else { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("Could not formulate automatic 400 Bad Request"); } } } return; } // No parse exception but null message - reject it and // march on (or return). // exit this message processor if the message did not parse. if (sipMessage == null) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack.getStackLogger().logDebug("Rejecting message ! + Null message parsed."); } String key = packet.getAddress().getHostAddress() + ":" + packet.getPort(); if (pingBackRecord.get(key) == null && sipStack.getMinKeepAliveInterval() > 0) { byte[] retval = "\r\n\r\n".getBytes(); DatagramPacket keepalive = new DatagramPacket(retval, 0, retval.length, packet.getAddress(), packet.getPort()); PingBackTimerTask task = new PingBackTimerTask(packet.getAddress().getHostAddress(), packet.getPort()); this.pingBackRecord.put(key, task); this.sipStack.getTimer().schedule(task, sipStack.getMinKeepAliveInterval() * 1000); ((UDPMessageProcessor) this.messageProcessor).sock.send(keepalive); } else { sipStack.getStackLogger().logDebug("Not sending ping back"); } return; } Via topMostVia = sipMessage.getTopmostVia(); // Check for the required headers. if (sipMessage.getFrom() == null || sipMessage.getTo() == null || sipMessage.getCallId() == null || sipMessage.getCSeq() == null || topMostVia == null) { String badmsg = new String(msgBytes); if (sipStack.isLoggingEnabled()) { this.sipStack.getStackLogger().logError("bad message " + badmsg); this.sipStack .getStackLogger() .logError( ">>> Dropped Bad Msg " + "From = " + sipMessage.getFrom() + "To = " + sipMessage.getTo() + "CallId = " + sipMessage.getCallId() + "CSeq = " + sipMessage.getCSeq() + "Via = " + sipMessage.getViaHeaders()); } return; } // For a request first via header tells where the message // is coming from. // For response, just get the port from the packet. if (sipMessage instanceof SIPRequest) { Hop hop = sipStack.addressResolver.resolveAddress(topMostVia.getHop()); this.peerPort = hop.getPort(); this.peerProtocol = topMostVia.getTransport(); this.peerPacketSourceAddress = packet.getAddress(); this.peerPacketSourcePort = packet.getPort(); try { this.peerAddress = packet.getAddress(); // Check to see if the received parameter matches // the peer address and tag it appropriately. boolean hasRPort = topMostVia.hasParameter(Via.RPORT); if (hasRPort || !hop.getHost().equals(this.peerAddress.getHostAddress())) { topMostVia.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress()); } if (hasRPort) { topMostVia.setParameter(Via.RPORT, Integer.toString(this.peerPacketSourcePort)); } } catch (java.text.ParseException ex1) { InternalErrorHandler.handleException(ex1); } } else { this.peerPacketSourceAddress = packet.getAddress(); this.peerPacketSourcePort = packet.getPort(); this.peerAddress = packet.getAddress(); this.peerPort = packet.getPort(); this.peerProtocol = topMostVia.getTransport(); } this.processMessage(sipMessage); }
/** * Return addresses for default proxy to forward the request to. The list is organized in the * following priority. If the requestURI refers directly to a host, the host and port information * are extracted from it and made the next hop on the list. If the default route has been * specified, then it is used to construct the next element of the list. <code> * RouteHeader firstRoute = (RouteHeader) req.getHeader( RouteHeader.NAME ); * if (firstRoute!=null) { * URI uri = firstRoute.getAddress().getURI(); * if (uri.isSIPUri()) { * SipURI nextHop = (SipURI) uri; * if ( nextHop.hasLrParam() ) { * // OK, use it * } else { * nextHop = fixStrictRouting( req ); <--- Here, make the modifications as per RFC3261 * } * } else { * // error: non-SIP URI not allowed in Route headers * throw new SipException( "Request has Route header with non-SIP URI" ); * } * } else if (outboundProxy!=null) { * // use outbound proxy for nextHop * } else if ( req.getRequestURI().isSipURI() ) { * // use request URI for nextHop * } * * </code> * * @param request is the sip request to route. */ public Hop getNextHop(Request request) throws SipException { SIPRequest sipRequest = (SIPRequest) request; RequestLine requestLine = sipRequest.getRequestLine(); if (requestLine == null) { return defaultRoute; } javax.sip.address.URI requestURI = requestLine.getUri(); if (requestURI == null) throw new IllegalArgumentException("Bad message: Null requestURI"); RouteList routes = sipRequest.getRouteHeaders(); /* * In case the topmost Route header contains no 'lr' parameter (which * means the next hop is a strict router), the implementation will * perform 'Route Information Postprocessing' as described in RFC3261 * section 16.6 step 6 (also known as "Route header popping"). That is, * the following modifications will be made to the request: * * The implementation places the Request-URI into the Route header field * as the last value. * * The implementation then places the first Route header field value * into the Request-URI and removes that value from the Route header * field. * * Subsequently, the request URI will be used as next hop target */ if (routes != null) { // to send the request through a specified hop the application is // supposed to prepend the appropriate Route header which. Route route = (Route) routes.getFirst(); URI uri = route.getAddress().getURI(); if (uri.isSipURI()) { SipURI sipUri = (SipURI) uri; if (!sipUri.hasLrParam()) { fixStrictRouting(sipRequest); if (sipStack.isLoggingEnabled()) sipStack.getStackLogger().logDebug("Route post processing fixed strict routing"); } Hop hop = createHop(sipUri, request); if (sipStack.isLoggingEnabled()) sipStack.getStackLogger().logDebug("NextHop based on Route:" + hop); return hop; } else { throw new SipException("First Route not a SIP URI"); } } else if (requestURI.isSipURI() && ((SipURI) requestURI).getMAddrParam() != null) { Hop hop = createHop((SipURI) requestURI, request); if (sipStack.isLoggingEnabled()) sipStack .getStackLogger() .logDebug("Using request URI maddr to route the request = " + hop.toString()); // JvB: don't remove it! // ((SipURI) requestURI).removeParameter("maddr"); return hop; } else if (defaultRoute != null) { if (sipStack.isLoggingEnabled()) sipStack .getStackLogger() .logDebug("Using outbound proxy to route the request = " + defaultRoute.toString()); return defaultRoute; } else if (requestURI.isSipURI()) { Hop hop = createHop((SipURI) requestURI, request); if (hop != null && sipStack.isLoggingEnabled()) sipStack.getStackLogger().logDebug("Used request-URI for nextHop = " + hop.toString()); else if (sipStack.isLoggingEnabled()) { sipStack.getStackLogger().logDebug("returning null hop -- loop detected"); } return hop; } else { // The internal router should never be consulted for non-sip URIs. InternalErrorHandler.handleException( "Unexpected non-sip URI", this.sipStack.getStackLogger()); return null; } }
/** * Process an incoming datagram * * @param packet is the incoming datagram packet. */ private void processIncomingDataPacket(DatagramPacket packet) throws Exception { this.peerAddress = packet.getAddress(); int packetLength = packet.getLength(); // Read bytes and put it in a eueue. byte[] bytes = packet.getData(); byte[] msgBytes = new byte[packetLength]; System.arraycopy(bytes, 0, msgBytes, 0, packetLength); // Do debug logging. if (sipStack.isLoggingEnabled()) { this.sipStack.logWriter.logDebug( "UDPMessageChannel: processIncomingDataPacket : peerAddress = " + peerAddress.getHostAddress() + "/" + packet.getPort() + " Length = " + packetLength); } SIPMessage sipMessage = null; try { this.receptionTime = System.currentTimeMillis(); sipMessage = myParser.parseSIPMessage(msgBytes); myParser = null; } catch (ParseException ex) { myParser = null; // let go of the parser reference. if (sipStack.isLoggingEnabled()) { this.sipStack.logWriter.logDebug("Rejecting message ! " + new String(msgBytes)); this.sipStack.logWriter.logDebug("error message " + ex.getMessage()); this.sipStack.logWriter.logException(ex); } // JvB: send a 400 response for requests (except ACK) // Currently only UDP, @todo also other transports String msgString = new String(msgBytes, 0, packetLength); if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) { String badReqRes = createBadReqRes(msgString, ex); if (badReqRes != null) { if (sipStack.isLoggingEnabled()) { sipStack.getLogWriter().logDebug("Sending automatic 400 Bad Request:"); sipStack.getLogWriter().logDebug(badReqRes); } try { this.sendMessage(badReqRes.getBytes(), peerAddress, packet.getPort(), "UDP", false); } catch (IOException e) { this.sipStack.logWriter.logException(e); } } else { if (sipStack.isLoggingEnabled()) { sipStack.getLogWriter().logDebug("Could not formulate automatic 400 Bad Request"); } } } return; } // No parse exception but null message - reject it and // march on (or return). // exit this message processor if the message did not parse. if (sipMessage == null) { if (sipStack.isLoggingEnabled()) { this.sipStack.logWriter.logDebug("Rejecting message ! + Null message parsed."); } return; } ViaList viaList = sipMessage.getViaHeaders(); // Check for the required headers. if (sipMessage.getFrom() == null || sipMessage.getTo() == null || sipMessage.getCallId() == null || sipMessage.getCSeq() == null || sipMessage.getViaHeaders() == null) { String badmsg = new String(msgBytes); if (sipStack.isLoggingEnabled()) { this.sipStack.logWriter.logError("bad message " + badmsg); this.sipStack.logWriter.logError( ">>> Dropped Bad Msg " + "From = " + sipMessage.getFrom() + "To = " + sipMessage.getTo() + "CallId = " + sipMessage.getCallId() + "CSeq = " + sipMessage.getCSeq() + "Via = " + sipMessage.getViaHeaders()); } sipStack.logWriter.logError("BAD MESSAGE!"); return; } // For a request first via header tells where the message // is coming from. // For response, just get the port from the packet. if (sipMessage instanceof SIPRequest) { Via v = (Via) viaList.getFirst(); Hop hop = sipStack.addressResolver.resolveAddress(v.getHop()); this.peerPort = hop.getPort(); this.peerProtocol = v.getTransport(); this.peerPacketSourceAddress = packet.getAddress(); this.peerPacketSourcePort = packet.getPort(); try { this.peerAddress = packet.getAddress(); // Check to see if the received parameter matches // the peer address and tag it appropriately. boolean hasRPort = v.hasParameter(Via.RPORT); if (hasRPort || !hop.getHost().equals(this.peerAddress.getHostAddress())) { v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress()); } if (hasRPort) { v.setParameter(Via.RPORT, Integer.toString(this.peerPacketSourcePort)); } } catch (java.text.ParseException ex1) { InternalErrorHandler.handleException(ex1); } } else { this.peerPacketSourceAddress = packet.getAddress(); this.peerPacketSourcePort = packet.getPort(); this.peerAddress = packet.getAddress(); this.peerPort = packet.getPort(); this.peerProtocol = ((Via) viaList.getFirst()).getTransport(); } this.processMessage(sipMessage); }
/* * (non-Javadoc) * * @see gov.nist.javax.sip.clientauthutils.AuthenticationHelper#handleChallenge(javax.sip.message.Response, * javax.sip.ClientTransaction, javax.sip.SipProvider) */ public ClientTransaction handleChallenge( Response challenge, ClientTransaction challengedTransaction, SipProvider transactionCreator, int cacheTime) throws SipException, NullPointerException { try { if (sipStack.isLoggingEnabled()) { sipStack.getStackLogger().logDebug("handleChallenge: " + challenge); } SIPRequest challengedRequest = ((SIPRequest) challengedTransaction.getRequest()); Request reoriginatedRequest = null; /* * If the challenged request is part of a Dialog and the * Dialog is confirmed the re-originated request should be * generated as an in-Dialog request. */ if (challengedRequest.getToTag() != null || challengedTransaction.getDialog() == null || challengedTransaction.getDialog().getState() != DialogState.CONFIRMED) { reoriginatedRequest = (Request) challengedRequest.clone(); } else { /* * Re-originate the request by consulting the dialog. In particular * the route set could change between the original request and the * in-dialog challenge. */ reoriginatedRequest = challengedTransaction.getDialog().createRequest(challengedRequest.getMethod()); Iterator<String> headerNames = challengedRequest.getHeaderNames(); while (headerNames.hasNext()) { String headerName = headerNames.next(); if (reoriginatedRequest.getHeader(headerName) != null) { ListIterator<Header> iterator = reoriginatedRequest.getHeaders(headerName); while (iterator.hasNext()) { reoriginatedRequest.addHeader(iterator.next()); } } } } // remove the branch id so that we could use the request in a new // transaction removeBranchID(reoriginatedRequest); if (challenge == null || reoriginatedRequest == null) { throw new NullPointerException("A null argument was passed to handle challenge."); } ListIterator authHeaders = null; if (challenge.getStatusCode() == Response.UNAUTHORIZED) { authHeaders = challenge.getHeaders(WWWAuthenticateHeader.NAME); } else if (challenge.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED) { authHeaders = challenge.getHeaders(ProxyAuthenticateHeader.NAME); } else { throw new IllegalArgumentException("Unexpected status code "); } if (authHeaders == null) { throw new IllegalArgumentException( "Could not find WWWAuthenticate or ProxyAuthenticate headers"); } // Remove all authorization headers from the request (we'll re-add them // from cache) reoriginatedRequest.removeHeader(AuthorizationHeader.NAME); reoriginatedRequest.removeHeader(ProxyAuthorizationHeader.NAME); // rfc 3261 says that the cseq header should be augmented for the new // request. do it here so that the new dialog (created together with // the new client transaction) takes it into account. // Bug report - Fredrik Wickstrom CSeqHeader cSeq = (CSeqHeader) reoriginatedRequest.getHeader((CSeqHeader.NAME)); try { cSeq.setSeqNumber(cSeq.getSeqNumber() + 1l); } catch (InvalidArgumentException ex) { throw new SipException("Invalid CSeq -- could not increment : " + cSeq.getSeqNumber()); } /* Resolve this to the next hop based on the previous lookup. If we are not using * lose routing (RFC2543) then just attach hop as a maddr param. */ if (challengedRequest.getRouteHeaders() == null) { Hop hop = ((SIPClientTransaction) challengedTransaction).getNextHop(); SipURI sipUri = (SipURI) reoriginatedRequest.getRequestURI(); sipUri.setMAddrParam(hop.getHost()); if (hop.getPort() != -1) sipUri.setPort(hop.getPort()); } ClientTransaction retryTran = transactionCreator.getNewClientTransaction(reoriginatedRequest); WWWAuthenticateHeader authHeader = null; SipURI requestUri = (SipURI) challengedTransaction.getRequest().getRequestURI(); while (authHeaders.hasNext()) { authHeader = (WWWAuthenticateHeader) authHeaders.next(); String realm = authHeader.getRealm(); AuthorizationHeader authorization = null; String sipDomain; if (this.accountManager instanceof SecureAccountManager) { UserCredentialHash credHash = ((SecureAccountManager) this.accountManager) .getCredentialHash(challengedTransaction, realm); URI uri = reoriginatedRequest.getRequestURI(); sipDomain = credHash.getSipDomain(); authorization = this.getAuthorization( reoriginatedRequest.getMethod(), uri.toString(), (reoriginatedRequest.getContent() == null) ? "" : new String(reoriginatedRequest.getRawContent()), authHeader, credHash); } else { UserCredentials userCreds = ((AccountManager) this.accountManager).getCredentials(challengedTransaction, realm); sipDomain = userCreds.getSipDomain(); if (userCreds == null) throw new SipException("Cannot find user creds for the given user name and realm"); // we haven't yet authenticated this realm since we were // started. authorization = this.getAuthorization( reoriginatedRequest.getMethod(), reoriginatedRequest.getRequestURI().toString(), (reoriginatedRequest.getContent() == null) ? "" : new String(reoriginatedRequest.getRawContent()), authHeader, userCreds); } sipStack .getStackLogger() .logDebug("Created authorization header: " + authorization.toString()); if (cacheTime != 0) cachedCredentials.cacheAuthorizationHeader(sipDomain, authorization, cacheTime); reoriginatedRequest.addHeader(authorization); } if (sipStack.isLoggingEnabled()) { sipStack.getStackLogger().logDebug("Returning authorization transaction." + retryTran); } return retryTran; } catch (SipException ex) { throw ex; } catch (Exception ex) { sipStack.getStackLogger().logError("Unexpected exception ", ex); throw new SipException("Unexpected exception ", ex); } }