From 5ed19cd93b9fb138b20820c6e7bee7141b32f995 Mon Sep 17 00:00:00 2001 From: Emil Ivov Date: Mon, 28 Sep 2009 10:10:28 +0000 Subject: [PATCH] Moves incoming SIP BYE processing to CallSipImpl --- .../impl/protocol/sip/CallSipImpl.java | 165 ++++++++++++++++-- .../impl/protocol/sip/DialogUtils.java | 131 +++++++------- .../OperationSetBasicTelephonySipImpl.java | 142 ++------------- .../impl/protocol/sip/SipMessageFactory.java | 2 +- 4 files changed, 234 insertions(+), 206 deletions(-) diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java index 99bc3307e..65ae7f5b6 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java @@ -203,7 +203,7 @@ public void peerDisplayNameChanged(CallPeerChangeEvent evt) * Verifies whether the call peer has entered a state. * * @param evt The CallPeerChangeEvent instance containing - * the source event as well as its previous and its new status. + * the source event as well as its previous and its new status. */ public void peerStateChanged(CallPeerChangeEvent evt) { @@ -226,10 +226,10 @@ else if ((newState == CallPeerState.CONNECTED * Returns true if dialog matches the jain sip dialog * established with one of the peers in this call. * - * @param dialog the dialog whose corresponding peer we're looking - * for. + * @param dialog the dialog whose corresponding peer we're looking for. + * * @return true if this call contains a call peer whose jain sip - * dialog is the same as the specified and false otherwise. + * dialog is the same as the specified and false otherwise. */ public boolean contains(Dialog dialog) { @@ -240,10 +240,10 @@ public boolean contains(Dialog dialog) * Returns the call peer whose associated jain sip dialog matches * dialog. * - * @param dialog the jain sip dialog whose corresponding peer we're - * looking for. - * @return the call peer whose jain sip dialog is the same as the - * specified or null if no such call peer was found. + * @param dialog the jain sip dialog whose corresponding peer we're looking + * for. + * @return the call peer whose jain sip dialog is the same as the specified + * or null if no such call peer was found. */ public CallPeerSipImpl findCallPeer(Dialog dialog) { @@ -280,7 +280,7 @@ public CallPeerSipImpl findCallPeer(Dialog dialog) * call. * * @param callSession the CallSession that the media service has - * created for this call. + * created for this call. */ public void setMediaCallSession(CallSession callSession) { @@ -393,11 +393,9 @@ private void attachSdpOffer(Request invite, CallPeerSipImpl callPeer) { try { - CallSession callSession = - SipActivator.getMediaService().createCallSession( - callPeer.getCall()); - ((CallSipImpl) callPeer.getCall()) - .setMediaCallSession(callSession); + CallSession callSession = SipActivator.getMediaService() + .createCallSession(callPeer.getCall()); + callPeer.getCall().setMediaCallSession(callSession); callSession.setSessionCreatorCallback(callPeer); @@ -405,6 +403,7 @@ private void attachSdpOffer(Request invite, CallPeerSipImpl callPeer) // that the media service can choose the most proper local // address to advertise. URI calleeURI = callPeer.getJainSipAddress().getURI(); + if (calleeURI.isSipURI()) { // content type should be application/sdp (not applications) @@ -1252,4 +1251,142 @@ public void processSessionProgress(ClientTransaction tran, // change status peer.setState(CallPeerState.CONNECTING_WITH_EARLY_MEDIA); } + + /** + * Sets the state of the specifies call peer as DISCONNECTED. + * + * @param serverTransaction the transaction that the cancel was received in. + * @param cancelRequest the Request that we've just received. + * @param callPeer the peer that sent the CANCEL request. + */ + public void processCancel(ServerTransaction serverTransaction, + Request cancelRequest, + CallPeerSipImpl callPeer) + { + // Cancels should be OK-ed and the initial transaction - terminated + // (report and fix by Ranga) + try + { + Response ok = messageFactory.createResponse(Response.OK, + cancelRequest); + serverTransaction.sendResponse(ok); + + logger.debug("sent an ok response to a CANCEL request:\n" + ok); + } + catch (ParseException ex) + { + CallSipImpl.logAndFailCallPeer( + "Failed to create an OK Response to an CANCEL request.", ex, + callPeer); + return; + } + catch (Exception ex) + { + CallSipImpl.logAndFailCallPeer( + "Failed to send an OK Response to an CANCEL request.", ex, + callPeer); + return; + } + try + { + // stop the invite transaction as well + Transaction tran = callPeer.getFirstTransaction(); + // should be server transaction and misplaced cancels should be + // filtered by the stack but it doesn't hurt checking anyway + if (!(tran instanceof ServerTransaction)) + { + logger.error("Received a misplaced CANCEL request!"); + return; + } + + ServerTransaction inviteTran = (ServerTransaction) tran; + Request invite = callPeer.getFirstTransaction().getRequest(); + Response requestTerminated = messageFactory + .createResponse(Response.REQUEST_TERMINATED, invite); + + inviteTran.sendResponse(requestTerminated); + if (logger.isDebugEnabled()) + logger.debug("sent request terminated response:\n" + + requestTerminated); + } + catch (ParseException ex) + { + logger.error("Failed to create a REQUEST_TERMINATED Response to " + + "an INVITE request.", ex); + } + catch (Exception ex) + { + logger.error("Failed to send an REQUEST_TERMINATED Response to " + + "an INVITE request.", ex); + } + + // change status + callPeer.setState(CallPeerState.DISCONNECTED); + } + + /** + * Sets the state of the corresponding call peer to DISCONNECTED and + * sends an OK response. + * + * @param tran the ServerTransaction the the BYE request + * arrived in. + * @param byeRequest the BYE request to process + * @param callPeer the peer that sent the BYE request + */ + public void processBye(ServerTransaction tran, + Request byeRequest, + CallPeerSipImpl callPeer) + { + // Send OK + Response ok = null; + try + { + ok = messageFactory.createResponse(Response.OK, byeRequest); + } + catch (ParseException ex) + { + logger.error("Error while trying to send a response to a bye", ex); + // no need to let the user know about the error since it doesn't + // affect them + return; + } + + try + { + tran.sendResponse(ok); + logger.debug("sent response " + ok); + } + catch (Exception ex) + { + // This is not really a problem according to the RFC + // so just dump to stdout should someone be interested + logger.error("Failed to send an OK response to BYE request," + + "exception was:\n", ex); + } + + // change status + boolean dialogIsAlive; + try + { + dialogIsAlive = DialogUtils.processByeThenIsDialogAlive(tran.getDialog()); + } + catch (SipException ex) + { + dialogIsAlive = false; + + logger + .error( + "Failed to determine whether the dialog should stay alive.", + ex); + } + if (dialogIsAlive) + { + ((CallSipImpl) callPeer.getCall()).getMediaCallSession() + .stopStreaming(); + } + else + { + callPeer.setState(CallPeerState.DISCONNECTED); + } + } } diff --git a/src/net/java/sip/communicator/impl/protocol/sip/DialogUtils.java b/src/net/java/sip/communicator/impl/protocol/sip/DialogUtils.java index bf75da3c2..b67a0b396 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/DialogUtils.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/DialogUtils.java @@ -12,44 +12,43 @@ /** * Implements utility methods to aid the manipulation of {@link Dialog} * instances and extend the mentioned type with additional functionality. - * + * * @author Lubomir Marinov */ public final class DialogUtils { /** - * Associates a specific subscription with the a given Dialog + * Associates a specific subscription with the a given Dialog * in order to allow it to keep the dialog in question alive even after a * BYE request. - * - * @param dialog the Dialog to associate the subscription with - * and to be kept alive after a BYE request because of the - * subscription + * + * @param dialog the Dialog to associate the subscription with + * and to be kept alive after a BYE request because of the subscription * @param subscription the subscription to be associated with - * dialog and keep it alive after a BYE request + * dialog and keep it alive after a BYE request + * * @return true if the specified subscription was associated with - * the given dialog; false if no changes were applied - * @throws SipException + * the given dialog; false if no changes were applied + * + * @throws SipException if the dialog is already terminated. */ public static boolean addSubscription(Dialog dialog, Object subscription) throws SipException { synchronized (dialog) { - DialogApplicationData applicationData = + DialogApplicationData appData = (DialogApplicationData) SipApplicationData.getApplicationData( dialog, SipApplicationData.KEY_SUBSCRIPTIONS); - if (applicationData == null) + if (appData == null) { - applicationData = new DialogApplicationData(); + appData = new DialogApplicationData(); SipApplicationData.setApplicationData( - dialog, - SipApplicationData.KEY_SUBSCRIPTIONS, - applicationData); + dialog, SipApplicationData.KEY_SUBSCRIPTIONS, appData); } - if (applicationData.addSubscription(subscription)) + if (appData.addSubscription(subscription)) { try { @@ -58,12 +57,11 @@ public static boolean addSubscription(Dialog dialog, Object subscription) } catch (SipException ex) { - /* * Since the subscription didn't quite register, undo the * part of the registration which did succeed. */ - applicationData.removeSubscription(subscription); + appData.removeSubscription(subscription); throw ex; } } @@ -73,13 +71,14 @@ public static boolean addSubscription(Dialog dialog, Object subscription) /** * Determines whether a BYE request has already been processed in a specific - * Dialog and thus allows determining whether the dialog in + * Dialog and thus allows determining whether the dialog in * question should be terminated when the last associated subscription is * terminated. - * - * @param dialog the Dialog to be examined + * + * @param dialog the Dialog to be examined + * * @return true if a BYE request has already been processed in the - * specified dialog; false, otherwise + * specified dialog; false, otherwise */ public static boolean isByeProcessed(Dialog dialog) { @@ -94,17 +93,19 @@ public static boolean isByeProcessed(Dialog dialog) } /** - * Processes a BYE request in a specific Dialog for the + * Processes a BYE request in a specific Dialog for the * purposes of subscription associations and returns an indicator which * determines whether the specified dialog should still be considered alive * after the processing of the BYE request. - * - * @param dialog the Dialog in which a BYE request has arrived - * @return true if dialog should still be considered - * alive after processing the mentioned BYE request; false - * if dialog is to be expected to die after processing - * the request in question - * @throws SipException + * + * @param dialog the Dialog in which a BYE request has arrived + * + * @return true if dialog should still be considered + * alive after processing the mentioned BYE request; false if + * dialog is to be expected to die after processing the request in + * question + * + * @throws SipException if the dialog is already terminated. */ public static boolean processByeThenIsDialogAlive(Dialog dialog) throws SipException @@ -129,22 +130,22 @@ public static boolean processByeThenIsDialogAlive(Dialog dialog) } /** - * Dissociates a specific subscription with a given Dialog in + * Dissociates a specific subscription with a given Dialog in * order to no longer allow it to keep the dialog in question alive even * after a BYE request, deletes the dialog if there are no other * subscriptions associated with it and a BYE request has already been * received and returns an indicator which determines whether the specified * dialog is still alive after the dissociation of the given subscription. - * - * @param dialog the Dialog to dissociate the subscription with - * and to no longer be kept alive after a BYE request because of - * the subscription + * + * @param dialog the Dialog to dissociate the subscription with + * and to no longer be kept alive after a BYE request because of the + * subscription * @param subscription the subscription to be dissociated with - * dialog and to no longer be kept alive after a BYE - * request because of the subscription + * dialog and to no longer be kept alive after a BYE request + * because of the subscription * @return true if the dialog is still alive after the - * dissociation; false if the dialog was terminated because - * of the dissociation + * dissociation; false if the dialog was terminated because of the + * dissociation */ public static boolean removeSubscriptionThenIsDialogAlive(Dialog dialog, Object subscription) @@ -167,7 +168,7 @@ public static boolean removeSubscriptionThenIsDialogAlive(Dialog dialog, } /** - * Prevents the creation of DialogUtils instances. + * Prevents the creation of DialogUtils instances. */ private DialogUtils() { @@ -178,7 +179,7 @@ private DialogUtils() * associates with {@link #Dialog} instances. *

* The implementation at the time of this writing allows tracking - * subscriptions in a specific Dialog in order to make it + * subscriptions in a specific Dialog in order to make it * possible to determine whether a BYE request should terminate the * respective dialog. *

@@ -188,7 +189,7 @@ private static class DialogApplicationData /** * The indicator which determines whether a BYE request has already been - * processed in the owning Dialog and thus allows + * processed in the owning Dialog and thus allows * determining whether the dialog in question should be terminated when * the last associated subscription is terminated. */ @@ -196,21 +197,21 @@ private static class DialogApplicationData /** * The set of subscriptions not yet terminated in the owning - * Dialog i.e. keeping it alive even after a BYE request. + * Dialog i.e. keeping it alive even after a BYE request. */ private final List subscriptions = new ArrayList(); /** * Associates a specific subscription with the owning - * Dialog in order to allow it to keep the dialog in + * Dialog in order to allow it to keep the dialog in * question alive even after a BYE request. - * + * * @param subscription the subscription with no specific type of - * interest to this implementation to be associated with the - * owning Dialog + * interest to this implementation to be associated with the + * owning Dialog * @return true if the specified subscription caused a - * modification of the list of associated subscriptions; - * false if no change to the mentioned list was applied + * modification of the list of associated subscriptions; false + * if no change to the mentioned list was applied */ public boolean addSubscription(Object subscription) { @@ -223,12 +224,12 @@ public boolean addSubscription(Object subscription) /** * Determines whether a BYE request has already been processed in the - * owning Dialog and thus allows determining whether the + * owning Dialog and thus allows determining whether the * dialog in question should be terminated when the last associated * subscription is terminated. - * + * * @return true if a BYE request has already been processed in - * the owning Dialog; false, otherwise + * the owning Dialog; false, otherwise */ public boolean isByeProcessed() { @@ -237,11 +238,10 @@ public boolean isByeProcessed() /** * Determines the number of subscriptions associated with the owning - * Dialog i.e. keeping it alive even after a BYE request. - * + * Dialog i.e. keeping it alive even after a BYE request. + * * @return the number of subscriptions associated with the owning - * Dialog i.e. keeping it alive even after a BYE - * request + * Dialog i.e. keeping it alive even after a BYE request */ public int getSubscriptionCount() { @@ -250,15 +250,15 @@ public int getSubscriptionCount() /** * Dissociates a specific subscription with the owning - * Dialog in order to no longer allow it to keep the dialog + * Dialog in order to no longer allow it to keep the dialog * in question alive even after a BYE request. - * + * * @param subscription the subscription with no specific type of - * interest to this implementation to be dissociated with the - * owning Dialog + * interest to this implementation to be dissociated with the owning + * Dialog * @return true if the specified subscription caused a - * modification of the list of associated subscriptions; - * false if no change to the mentioned list was applied + * modification of the list of associated subscriptions; false + * if no change to the mentioned list was applied */ public boolean removeSubscription(Object subscription) { @@ -267,13 +267,12 @@ public boolean removeSubscription(Object subscription) /** * Sets the indicator which determines whether a BYE request has already - * been processed in the owning Dialog and thus allows + * been processed in the owning Dialog and thus allows * determining whether the dialog in question should be terminated when * the last associated subscription is terminated. - * + * * @param byeIsProcessed true if a BYE request has already been - * processed in the owning Dialog; - * false, otherwise + * processed in the owning Dialog; false, otherwise */ public void setByeProcessed(boolean byeIsProcessed) { diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java index 00d02981e..ceca5bc5b 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java @@ -571,16 +571,16 @@ private void processReferAccepted(ClientTransaction clientTransaction, * Updates the call state of the corresponding call peer. * * @param clientTransaction the transaction in which the response was - * received. + * received. * @param response the trying response. */ private void processTrying(ClientTransaction clientTransaction, - Response response) + Response response) { Dialog dialog = clientTransaction.getDialog(); + // find the call peer - CallPeerSipImpl callPeer = - activeCallsRepository.findCallPeer(dialog); + CallPeerSipImpl callPeer = activeCallsRepository.findCallPeer(dialog); if (callPeer == null) { @@ -592,7 +592,9 @@ private void processTrying(ClientTransaction clientTransaction, CallPeerState callPeerState = callPeer.getState(); if (!CallPeerState.CONNECTED.equals(callPeerState) && !CallPeerState.isOnHold(callPeerState)) + { callPeer.setState(CallPeerState.CONNECTING); + } } /** @@ -601,7 +603,7 @@ private void processTrying(ClientTransaction clientTransaction, * presentation and that we didn't have when establishing the call. * * @param clientTransaction the transaction in which the response was - * received. + * received. * @param response the Trying response. */ private void processRinging(ClientTransaction clientTransaction, @@ -949,16 +951,15 @@ private void processInvite(SipProvider sourceProvider, * sends an OK response. * * @param serverTransaction the ServerTransaction the the BYE request - * arrived in. + * arrived in. * @param byeRequest the BYE request to process */ private void processBye(ServerTransaction serverTransaction, - Request byeRequest) + Request byeRequest) { // find the call Dialog dialog = serverTransaction.getDialog(); - CallPeerSipImpl callPeer = - activeCallsRepository.findCallPeer(dialog); + CallPeerSipImpl callPeer = activeCallsRepository.findCallPeer(dialog); if (callPeer == null) { @@ -966,72 +967,21 @@ private void processBye(ServerTransaction serverTransaction, return; } - // Send OK - Response ok = null; - try - { - ok = messageFactory.createResponse(Response.OK, byeRequest); - } - catch (ParseException ex) - { - logger.error("Error while trying to send a response to a bye", ex); - // no need to let the user know about the error since it doesn't - // affect them - return; - } - - try - { - serverTransaction.sendResponse(ok); - logger.debug("sent response " + ok); - } - catch (Exception ex) - { - // This is not really a problem according to the RFC - // so just dump to stdout should someone be interested - logger.error("Failed to send an OK response to BYE request," - + "exception was:\n", ex); - } - - // change status - boolean dialogIsAlive; - try - { - dialogIsAlive = DialogUtils.processByeThenIsDialogAlive(dialog); - } - catch (SipException ex) - { - dialogIsAlive = false; - - logger - .error( - "Failed to determine whether the dialog should stay alive.", - ex); - } - if (dialogIsAlive) - { - ((CallSipImpl) callPeer.getCall()).getMediaCallSession() - .stopStreaming(); - } - else - { - callPeer.setState(CallPeerState.DISCONNECTED); - } + callPeer.getCall().processBye(serverTransaction, byeRequest, callPeer); } /** * Updates the session description and sends the state of the corresponding * call peer to CONNECTED. * - * @param serverTransaction the transaction that the Ack was received in. - * @param ackRequest Request + * @param serverTransaction the transaction that the ACK was received in. + * @param ackRequest the ACK Request we need to process */ private void processAck(ServerTransaction serverTransaction, Request ackRequest) { // find the call - CallPeerSipImpl peer - = activeCallsRepository.findCallPeer( + CallPeerSipImpl peer = activeCallsRepository.findCallPeer( serverTransaction.getDialog()); if (peer == null) @@ -1044,8 +994,7 @@ private void processAck(ServerTransaction serverTransaction, ContentLengthHeader contentLength = ackRequest.getContentLength(); if ((contentLength != null) && (contentLength.getContentLength() > 0)) { - peer.setSdpDescription( - new String(ackRequest.getRawContent())); + peer.setSdpDescription( new String(ackRequest.getRawContent())); } // change status @@ -1093,65 +1042,8 @@ private void processCancel(ServerTransaction serverTransaction, return; } - // Cancels should be OK-ed and the initial transaction - terminated - // (report and fix by Ranga) - try - { - Response ok - = messageFactory.createResponse(Response.OK, cancelRequest); - serverTransaction.sendResponse(ok); - - logger.debug("sent an ok response to a CANCEL request:\n" + ok); - } - catch (ParseException ex) - { - CallSipImpl.logAndFailCallPeer( - "Failed to create an OK Response to an CANCEL request.", ex, - callPeer); - return; - } - catch (Exception ex) - { - CallSipImpl.logAndFailCallPeer( - "Failed to send an OK Response to an CANCEL request.", ex, - callPeer); - return; - } - try - { - // stop the invite transaction as well - Transaction tran = callPeer.getFirstTransaction(); - // should be server transaction and misplaced cancels should be - // filtered by the stack but it doesn't hurt checking anyway - if (!(tran instanceof ServerTransaction)) - { - logger.error("Received a misplaced CANCEL request!"); - return; - } - - ServerTransaction inviteTran = (ServerTransaction) tran; - Request invite = callPeer.getFirstTransaction().getRequest(); - Response requestTerminated = protocolProvider.getMessageFactory() - .createResponse(Response.REQUEST_TERMINATED, invite); - - inviteTran.sendResponse(requestTerminated); - if (logger.isDebugEnabled()) - logger.debug("sent request terminated response:\n" - + requestTerminated); - } - catch (ParseException ex) - { - logger.error("Failed to create a REQUEST_TERMINATED Response to " - + "an INVITE request.", ex); - } - catch (Exception ex) - { - logger.error("Failed to send an REQUEST_TERMINATED Response to " - + "an INVITE request.", ex); - } - - // change status - callPeer.setState(CallPeerState.DISCONNECTED); + callPeer.getCall().processCancel(serverTransaction, + cancelRequest, callPeer); } /** diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipMessageFactory.java b/src/net/java/sip/communicator/impl/protocol/sip/SipMessageFactory.java index 518fb3f12..50209ca41 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/SipMessageFactory.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/SipMessageFactory.java @@ -430,7 +430,7 @@ private Message attachContactHeader(Message message) * synchronized: needed for access to 'rand', else risk to generate same tag * twice */ - private synchronized String generateLocalTag() + public static synchronized String generateLocalTag() { if(localTagGenerator == null) localTagGenerator = new Random();