From f083d85578fbc2bbf57ae9b62efaa417aa82ea8d Mon Sep 17 00:00:00 2001 From: Benoit Pradelle Date: Wed, 25 Jul 2007 13:39:56 +0000 Subject: [PATCH] - add the support of Allow Events header in OPTIONS responses - add the automatic 489 / bad event response - fix a message storm when a client try to resubscribe us --- .../impl/protocol/sip/ClientCapabilities.java | 17 +++- .../sip/OperationSetPresenceSipImpl.java | 12 +-- .../sip/ProtocolProviderServiceSipImpl.java | 97 +++++++++++++++++++ 3 files changed, 115 insertions(+), 11 deletions(-) diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ClientCapabilities.java b/src/net/java/sip/communicator/impl/protocol/sip/ClientCapabilities.java index 590b4db96..94ee5f6de 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/ClientCapabilities.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/ClientCapabilities.java @@ -63,10 +63,21 @@ public void processRequest(RequestEvent requestEvent) optionsOK.addHeader( provider.getHeaderFactory().createAllowHeader(method)); - - //add a user agent header. - optionsOK.setHeader( provider.getSipCommUserAgentHeader()); } + + Iterator events = provider.getKnownEventsList().iterator(); + + synchronized (provider.getKnownEventsList()) { + while (events.hasNext()) { + String event = (String) events.next(); + + optionsOK.addHeader(provider.getHeaderFactory() + .createAllowEventsHeader(event)); + } + } + + //add a user agent header. + optionsOK.setHeader(provider.getSipCommUserAgentHeader()); } catch (ParseException ex) { diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java index 33dc0658b..6882f67c5 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java @@ -39,7 +39,7 @@ public class OperationSetPresenceSipImpl implements OperationSetPersistentPresence, SipListener { private static final Logger logger = - Logger.getLogger(OperationSetPersistentPresenceSipImpl.class); + Logger.getLogger(OperationSetPresenceSipImpl.class); /** * A list of listeners registered for SubscriptionEvents. */ @@ -101,12 +101,6 @@ public class OperationSetPresenceSipImpl * Content : String */ private Vector waitedCallIds = new Vector(); - - /** - * Hashtable of the pending NOTIFY requests (NOTIFY received before a OK) - * index : String, Content : RequestEvent - */ - private Hashtable pendingNotify = new Hashtable(); /** * Do we have to use a distant presence agent (default initial value) @@ -255,6 +249,8 @@ public OperationSetPresenceSipImpl(ProtocolProviderServiceSipImpl provider, this.parentProvider.registerMethodProcessor(Request.NOTIFY, this); this.parentProvider.registerMethodProcessor(Request.PUBLISH, this); + this.parentProvider.registerEvent("presence"); + logger.debug("presence initialized with :" + isPresenceEnabled + ", " + forceP2PMode + ", " + pollingPeriod + ", " + subscriptionExpiration + " for " @@ -2703,7 +2699,7 @@ public void processRequest(RequestEvent requestEvent) getPidfPresenceStatus((ContactSipImpl) getLocalContact()), SubscriptionStateHeader.TERMINATED, - SubscriptionStateHeader.DEACTIVATED); + SubscriptionStateHeader.REJECTED); } catch (OperationFailedException e) { logger.error("failed to create the new notify", e); return; diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java index f2d0693bf..bdf390a5f 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java @@ -59,6 +59,11 @@ public class ProtocolProviderServiceSipImpl * RegistrationStateChangeEvents. */ private List registrationListeners = new ArrayList(); + + /** + * A list of all events registered for this provider. + */ + private List registeredEvents = new ArrayList(); /** * The SipFactory instance used to create the SipStack and the Address @@ -381,6 +386,30 @@ public String getProtocolName() { return ProtocolNames.SIP; } + + /** + * Register a new event taken in account by this provider. This is usefull + * to generate the Allow-Events header of the OPTIONS responses and to + * generate 489 responses. + * + * @param event The event to register + */ + public void registerEvent(String event) { + synchronized (this.registeredEvents) { + if (!this.registeredEvents.contains(event)) { + this.registeredEvents.add(event); + } + } + } + + /** + * Returns the list of all the registered events for this provider. + * + * @return The list of all the registered events + */ + public List getKnownEventsList() { + return this.registeredEvents; + } /** * Indicates whether or not this provider is registered @@ -1160,6 +1189,74 @@ public void processRequest(RequestEvent requestEvent) logger.debug("received request=\n" + requestEvent.getRequest()); Request request = requestEvent.getRequest(); + + // test if an Event header is present and known + EventHeader eventHeader = (EventHeader) + request.getHeader(EventHeader.NAME); + + if (eventHeader != null) { + boolean eventKnown; + + synchronized (this.registeredEvents) { + eventKnown = this.registeredEvents.contains( + eventHeader.getEventType()); + } + + if (!eventKnown) { + // send a 489 / Bad Event response + ServerTransaction serverTransaction = requestEvent + .getServerTransaction(); + SipProvider jainSipProvider = (SipProvider) + requestEvent.getSource(); + + if (serverTransaction == null) + { + try + { + serverTransaction = jainSipProvider + .getNewServerTransaction(request); + } + catch (TransactionAlreadyExistsException ex) + { + //let's not scare the user and only log a message + logger.error("Failed to create a new server" + + "transaction for an incoming request\n" + + "(Next message contains the request)" + , ex); + return; + } + catch (TransactionUnavailableException ex) + { + //let's not scare the user and only log a message + logger.error("Failed to create a new server" + + "transaction for an incoming request\n" + + "(Next message contains the request)" + , ex); + return; + } + } + + Response response = null; + try { + response = this.getMessageFactory().createResponse( + Response.BAD_EVENT, request); + } catch (ParseException e) { + logger.error("failed to create the 489 response", e); + return; + } + + try { + serverTransaction.sendResponse(response); + } catch (SipException e) { + logger.error("failed to send the response", e); + } catch (InvalidArgumentException e) { + // should not happen + logger.error("invalid argument provided while trying" + + " to send the response", e); + } + } + } + String method = request.getMethod();