/** * <p> * Starts using stream compression that will compress network traffic. Traffic can be * reduced up to 90%. Therefore, stream compression is ideal when using a slow speed network * connection. However, the server and the client will need to use more CPU time in order to * un/compress network data so under high load the server performance might be affected. * </p> * <p> * Stream compression has to have been previously offered by the server. Currently only the * zlib method is supported by the client. Stream compression negotiation has to be done * before authentication took place. * </p> * * @throws NotConnectedException * @throws SmackException * @throws NoResponseException * @throws InterruptedException */ private void maybeEnableCompression() throws NotConnectedException, NoResponseException, SmackException, InterruptedException { if (!config.isCompressionEnabled()) { return; } maybeCompressFeaturesReceived.checkIfSuccessOrWait(); Compress.Feature compression = getFeature(Compress.Feature.ELEMENT, Compress.NAMESPACE); if (compression == null) { // Server does not support compression return; } // If stream compression was offered by the server and we want to use // compression then send compression request to the server if ((compressionHandler = maybeGetCompressionHandler(compression)) != null) { compressSyncPoint.sendAndWaitForResponseOrThrow(new Compress(compressionHandler.getCompressionMethod())); } else { LOGGER.warning("Could not enable compression because no matching handler/method pair was found"); } }
/** * Returns the compression handler that can be used for one compression methods offered by the server. * * @return a instance of XMPPInputOutputStream or null if no suitable instance was found * */ private XMPPInputOutputStream maybeGetCompressionHandler() { Compress.Feature compression = getFeature(Compress.Feature.ELEMENT, Compress.NAMESPACE); if (compression == null) { // Server does not support compression return null; } for (XMPPInputOutputStream handler : SmackConfiguration.getCompresionHandlers()) { String method = handler.getCompressionMethod(); if (compression.getMethods().contains(method)) return handler; } return null; }
/** * Parse the Compression Feature reported from the server. * * @param parser the XML parser, positioned at the start of the compression stanza. * @return The CompressionFeature stream element * @throws XmlPullParserException if an exception occurs while parsing the stanza. */ public static Compress.Feature parseCompressionFeature(XmlPullParser parser) throws IOException, XmlPullParserException { assert (parser.getEventType() == XmlPullParser.START_TAG); String name; final int initialDepth = parser.getDepth(); List<String> methods = new LinkedList<String>(); outerloop: while (true) { int eventType = parser.next(); switch (eventType) { case XmlPullParser.START_TAG: name = parser.getName(); switch (name) { case "method": methods.add(parser.nextText()); break; } break; case XmlPullParser.END_TAG: name = parser.getName(); switch (name) { case Compress.Feature.ELEMENT: if (parser.getDepth() == initialDepth) { break outerloop; } } } } assert (parser.getEventType() == XmlPullParser.END_TAG); assert (parser.getDepth() == initialDepth); return new Compress.Feature(methods); }
/** * Returns the compression handler that can be used for one compression methods offered by the server. * * @return a instance of XMPPInputOutputStream or null if no suitable instance was found * */ private static XMPPInputOutputStream maybeGetCompressionHandler(Compress.Feature compression) { for (XMPPInputOutputStream handler : SmackConfiguration.getCompresionHandlers()) { String method = handler.getCompressionMethod(); if (compression.getMethods().contains(method)) return handler; } return null; }
protected final void parseFeatures(XmlPullParser parser) throws XmlPullParserException, IOException, SmackException { streamFeatures.clear(); final int initialDepth = parser.getDepth(); while (true) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG && parser.getDepth() == initialDepth + 1) { ExtensionElement streamFeature = null; String name = parser.getName(); String namespace = parser.getNamespace(); switch (name) { case StartTls.ELEMENT: streamFeature = PacketParserUtils.parseStartTlsFeature(parser); break; case Mechanisms.ELEMENT: streamFeature = new Mechanisms(PacketParserUtils.parseMechanisms(parser)); break; case Bind.ELEMENT: streamFeature = Bind.Feature.INSTANCE; break; case Session.ELEMENT: streamFeature = PacketParserUtils.parseSessionFeature(parser); break; case Compress.Feature.ELEMENT: streamFeature = PacketParserUtils.parseCompressionFeature(parser); break; default: ExtensionElementProvider<ExtensionElement> provider = ProviderManager.getStreamFeatureProvider(name, namespace); if (provider != null) { streamFeature = provider.parse(parser); } break; } if (streamFeature != null) { // 将特性放入列表中 addStreamFeature(streamFeature); } } else if (eventType == XmlPullParser.END_TAG && parser.getDepth() == initialDepth) { break; } } if (hasFeature(Mechanisms.ELEMENT, Mechanisms.NAMESPACE)) { // Only proceed with SASL auth if TLS is disabled or if the server doesn't announce it if (!hasFeature(StartTls.ELEMENT, StartTls.NAMESPACE) || config.getSecurityMode() == SecurityMode.disabled) { // connecting算事完成了 saslFeatureReceived.reportSuccess(); } } // If the server reported the bind feature then we are that that we did SASL and maybe // STARTTLS. We can then report that the last 'stream:features' have been parsed if (hasFeature(Bind.ELEMENT, Bind.NAMESPACE)) { if (!hasFeature(Compress.Feature.ELEMENT, Compress.NAMESPACE) || !config.isCompressionEnabled()) { // This was was last features from the server is either it did not contain // compression or if we disabled it lastFeaturesReceived.reportSuccess(); } } afterFeaturesReceived(); }
/** * <p> * Starts using stream compression that will compress network traffic. Traffic can be * reduced up to 90%. Therefore, stream compression is ideal when using a slow speed network * connection. However, the server and the client will need to use more CPU time in order to * un/compress network data so under high load the server performance might be affected. * </p> * <p> * Stream compression has to have been previously offered by the server. Currently only the * zlib method is supported by the client. Stream compression negotiation has to be done * before authentication took place. * </p> * * @throws NotConnectedException * @throws XMPPException * @throws NoResponseException */ private void useCompression() throws NotConnectedException, NoResponseException, XMPPException { maybeCompressFeaturesReceived.checkIfSuccessOrWait(); // If stream compression was offered by the server and we want to use // compression then send compression request to the server if ((compressionHandler = maybeGetCompressionHandler()) != null) { compressSyncPoint.sendAndWaitForResponseOrThrow(new Compress(compressionHandler.getCompressionMethod())); } else { LOGGER.warning("Could not enable compression because no matching handler/method pair was found"); } }