aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamian Minkov <damencho@jitsi.org>2010-12-03 08:53:04 +0000
committerDamian Minkov <damencho@jitsi.org>2010-12-03 08:53:04 +0000
commita21b3d7353c9fc9ed47288333d3f793b01ab5689 (patch)
tree5b8210d76dc28c82998188252958e6c6beaec96a
parent4785e35f694e73a65b6163f31c9aac4f58aa925f (diff)
downloadjitsi-a21b3d7353c9fc9ed47288333d3f793b01ab5689.zip
jitsi-a21b3d7353c9fc9ed47288333d3f793b01ab5689.tar.gz
jitsi-a21b3d7353c9fc9ed47288333d3f793b01ab5689.tar.bz2
Introduce Packet Logging Service with its configuration form and implementation for sip,jabber and rtp.
-rw-r--r--build.xml13
-rw-r--r--lib/felix.client.run.properties1
-rw-r--r--lib/felix.unit.test.properties1
-rw-r--r--lib/installer-exclude/jain-sdp.jarbin859982 -> 894330 bytes
-rw-r--r--lib/installer-exclude/jain-sip-api.jarbin53814 -> 53813 bytes
-rw-r--r--lib/installer-exclude/jain-sip-ri.jarbin714757 -> 749090 bytes
-rw-r--r--resources/languages/resources.properties10
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java30
-rwxr-xr-xsrc/net/java/sip/communicator/impl/neomedia/RTPConnectorInputStream.java28
-rwxr-xr-xsrc/net/java/sip/communicator/impl/neomedia/RTPConnectorOutputStream.java47
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/neomedia.manifest.mf1
-rw-r--r--src/net/java/sip/communicator/impl/packetlogging/PacketLoggingActivator.java392
-rw-r--r--src/net/java/sip/communicator/impl/packetlogging/PacketLoggingConfigForm.java301
-rw-r--r--src/net/java/sip/communicator/impl/packetlogging/PacketLoggingServiceImpl.java844
-rw-r--r--src/net/java/sip/communicator/impl/packetlogging/packetlogging.manifest.mf20
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java23
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java14
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/debugger/SmackPacketDebugger.java150
-rwxr-xr-xsrc/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf1
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/SipActivator.java22
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/SipLogger.java75
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/SipStackSharing.java12
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf1
-rw-r--r--src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java23
-rw-r--r--src/net/java/sip/communicator/service/packetlogging/PacketLoggingService.java101
25 files changed, 2077 insertions, 33 deletions
diff --git a/build.xml b/build.xml
index c098e52..5b16a0c 100644
--- a/build.xml
+++ b/build.xml
@@ -920,7 +920,7 @@
bundle-replacement,bundle-youtube,bundle-dailymotion,bundle-smiley,
bundle-vimeo,bundle-vbox7,bundle-metacafe,bundle-flickr,bundle-hulu,
bundle-twitpic,bundle-directimage,bundle-bliptv,bundle-viddler,
- bundle-plugin-chatconfig,bundle-certificate,
+ bundle-plugin-chatconfig,bundle-certificate,bundle-packetlogging,
bundle-provdisc,bundle-provdisc-dhcp,bundle-provdisc-mdns,
bundle-provisioning"/>
@@ -2584,4 +2584,15 @@ org.apache.http.util"/>
prefix="net/java/sip/communicator/impl/certificate" />
</jar>
</target>
+
+
+ <target name="bundle-packetlogging">
+ <jar compress="false" destfile="${bundles.dest}/packetlogging.jar"
+ manifest="${src}/net/java/sip/communicator/impl/packetlogging/packetlogging.manifest.mf">
+ <zipfileset dir="${dest}/net/java/sip/communicator/service/packetlogging"
+ prefix="net/java/sip/communicator/service/packetlogging" />
+ <zipfileset dir="${dest}/net/java/sip/communicator/impl/packetlogging"
+ prefix="net/java/sip/communicator/impl/packetlogging" />
+ </jar>
+ </target>
</project>
diff --git a/lib/felix.client.run.properties b/lib/felix.client.run.properties
index 21d80cf..1812171 100644
--- a/lib/felix.client.run.properties
+++ b/lib/felix.client.run.properties
@@ -47,6 +47,7 @@ felix.auto.start.40= \
felix.auto.start.42= \
reference:file:sc-bundles/credentialsstorage.jar \
+ reference:file:sc-bundles/packetlogging.jar \
reference:file:sc-bundles/defaultresources.jar
felix.auto.start.45= \
diff --git a/lib/felix.unit.test.properties b/lib/felix.unit.test.properties
index a614912..04dbb47 100644
--- a/lib/felix.unit.test.properties
+++ b/lib/felix.unit.test.properties
@@ -73,6 +73,7 @@ felix.auto.start.5= \
reference:file:sc-bundles/protocol-media.jar \
reference:file:sc-bundles/httpcore.jar \
reference:file:sc-bundles/httpclient.jar \
+ reference:file:sc-bundles/packetlogging.jar \
reference:file:sc-bundles/certificate.jar
felix.auto.start.6= \
diff --git a/lib/installer-exclude/jain-sdp.jar b/lib/installer-exclude/jain-sdp.jar
index bd45263..60eb511 100644
--- a/lib/installer-exclude/jain-sdp.jar
+++ b/lib/installer-exclude/jain-sdp.jar
Binary files differ
diff --git a/lib/installer-exclude/jain-sip-api.jar b/lib/installer-exclude/jain-sip-api.jar
index 06c2587..3ed1a74 100644
--- a/lib/installer-exclude/jain-sip-api.jar
+++ b/lib/installer-exclude/jain-sip-api.jar
Binary files differ
diff --git a/lib/installer-exclude/jain-sip-ri.jar b/lib/installer-exclude/jain-sip-ri.jar
index a887d0a..1011fd5 100644
--- a/lib/installer-exclude/jain-sip-ri.jar
+++ b/lib/installer-exclude/jain-sip-ri.jar
Binary files differ
diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties
index d1dafc3..682694d 100644
--- a/resources/languages/resources.properties
+++ b/resources/languages/resources.properties
@@ -1094,3 +1094,13 @@ plugin.provisioning.DNS=DNS
plugin.provisioning.BONJOUR=Bonjour
plugin.provisioning.MANUAL=Manually specify a provisioning URI
plugin.provisioning.URI=URI
+
+# packet logging service
+impl.packetlogging.PACKET_LOGGING_CONFIG=Packet Logging
+impl.packetlogging.ENABLE_DISABLE=Enable Packet Logging
+impl.packetlogging.PACKET_LOGGING_RTP=RTP
+impl.packetlogging.PACKET_LOGGING_RTP_DESCRIPTION=Will save only few initial packets and one on every 5000.
+impl.packetlogging.PACKET_LOGGING_DESCRIPTION=<html>Prints debug packets of various protocols in the <br>log folder using pcap format (tcpdump/wireshark).</html>
+impl.packetlogging.PACKET_LOGGING_FILE_COUNT=Number of log files
+impl.packetlogging.PACKET_LOGGING_FILE_SIZE=Maximum file size (in KB)
+
diff --git a/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java b/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java
index 9acd772..346b28d 100644
--- a/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java
+++ b/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java
@@ -14,6 +14,7 @@ import net.java.sip.communicator.service.fileaccess.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.service.packetlogging.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
@@ -85,6 +86,12 @@ public class NeomediaActivator
private ServiceRegistration mediaServiceRegistration;
/**
+ * The OSGi <tt>PacketLoggingService</tt> of {@link #mediaServiceImpl} in
+ * {@link #bundleContext} and used for debugging.
+ */
+ private static PacketLoggingService packetLoggingService = null;
+
+ /**
* Starts the execution of the neomedia bundle in the specified context.
*
* @param bundleContext the context in which the neomedia bundle is to start
@@ -328,4 +335,27 @@ public class NeomediaActivator
= ResourceManagementServiceUtils.getService(bundleContext);
return resources;
}
+
+ /**
+ * Returns a reference to the <tt>PacketLoggingService</tt> implementation
+ * currently registered in the bundle context or null if no such
+ * implementation was found.
+ *
+ * @return a reference to a <tt>PacketLoggingService</tt> implementation
+ * currently registered in the bundle context or null if no such
+ * implementation was found.
+ */
+ public static PacketLoggingService getPacketLogging()
+ {
+ if (packetLoggingService == null)
+ {
+ ServiceReference plReference
+ = bundleContext.getServiceReference(
+ PacketLoggingService.class.getName());
+
+ packetLoggingService
+ = (PacketLoggingService)bundleContext.getService(plReference);
+ }
+ return packetLoggingService;
+ }
} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/neomedia/RTPConnectorInputStream.java b/src/net/java/sip/communicator/impl/neomedia/RTPConnectorInputStream.java
index 25f7f53..70cfd25 100755
--- a/src/net/java/sip/communicator/impl/neomedia/RTPConnectorInputStream.java
+++ b/src/net/java/sip/communicator/impl/neomedia/RTPConnectorInputStream.java
@@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.impl.neomedia;
+import net.java.sip.communicator.service.packetlogging.*;
+
import java.io.*;
import java.net.*;
@@ -19,7 +21,6 @@ public class RTPConnectorInputStream
implements PushSourceStream,
Runnable
{
-
/**
* The value of the property <tt>controls</tt> of
* <tt>RTPConnectorInputStream</tt> when there are no controls. Explicitly
@@ -70,6 +71,12 @@ public class RTPConnectorInputStream
private Thread receiverThread = null;
/**
+ * Used for debugging. As we don't log every packet
+ * we must count them and decide which to log.
+ */
+ private long numberOfPackets = 0;
+
+ /**
* Initializes a new <tt>RTPConnectorInputStream</tt> which is to receive
* packet data from a specific UDP socket.
*
@@ -246,6 +253,7 @@ public class RTPConnectorInputStream
try
{
socket.receive(p);
+ numberOfPackets++;
}
catch (IOException e)
{
@@ -253,6 +261,24 @@ public class RTPConnectorInputStream
break;
}
+ if(RTPConnectorOutputStream.logPacket(numberOfPackets)
+ && NeomediaActivator.getPacketLogging().isLoggingEnabled(
+ PacketLoggingService.ProtocolName.RTP))
+ {
+ NeomediaActivator.getPacketLogging()
+ .logPacket(
+ PacketLoggingService.ProtocolName.RTP,
+ p.getAddress().getAddress(),
+ p.getPort(),
+ socket.getLocalAddress().getAddress(),
+ socket.getLocalPort(),
+ PacketLoggingService.TransportName.UDP,
+ false,
+ p.getData(),
+ p.getOffset(),
+ p.getLength());
+ }
+
pkt = createRawPacket(p);
/*
diff --git a/src/net/java/sip/communicator/impl/neomedia/RTPConnectorOutputStream.java b/src/net/java/sip/communicator/impl/neomedia/RTPConnectorOutputStream.java
index 2c1eac6..4d1c2de 100755
--- a/src/net/java/sip/communicator/impl/neomedia/RTPConnectorOutputStream.java
+++ b/src/net/java/sip/communicator/impl/neomedia/RTPConnectorOutputStream.java
@@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.impl.neomedia;
+import net.java.sip.communicator.service.packetlogging.*;
+
import java.io.*;
import java.net.*;
import java.util.*;
@@ -60,6 +62,12 @@ public class RTPConnectorOutputStream
= new LinkedBlockingQueue<RawPacket>();
/**
+ * Used for debugging. As we don't log every packet
+ * we must count them and decide which to log.
+ */
+ private long numberOfPackets = 0;
+
+ /**
* Initializes a new <tt>RTPConnectorOutputStream</tt> which is to send
* packet data out through a specific UDP socket.
*
@@ -158,6 +166,26 @@ public class RTPConnectorOutputStream
}
/**
+ * We don't log every rtp traffic.
+ * We log only first then 300,500 and 1000 packets and
+ * then every 5000 packet.
+ *
+ * @param numOfPacket current packet number.
+ * @return wether we should log the current packet.
+ */
+ static boolean logPacket(long numOfPacket)
+ {
+ if(numOfPacket == 1
+ || numOfPacket == 300
+ || numOfPacket == 500
+ || numOfPacket == 1000
+ || numOfPacket%5000 == 0)
+ return true;
+ else
+ return false;
+ }
+
+ /**
* Sends a specific RTP packet through the <tt>DatagramSocket</tt> of this
* <tt>OutputDataSource</tt>.
*
@@ -168,6 +196,7 @@ public class RTPConnectorOutputStream
*/
private boolean send(RawPacket packet)
{
+ numberOfPackets++;
for (InetSocketAddress target : targets)
{
try
@@ -179,6 +208,24 @@ public class RTPConnectorOutputStream
packet.getLength(),
target.getAddress(),
target.getPort()));
+
+ if(logPacket(numberOfPackets)
+ && NeomediaActivator.getPacketLogging().isLoggingEnabled(
+ PacketLoggingService.ProtocolName.RTP))
+ {
+ NeomediaActivator.getPacketLogging()
+ .logPacket(
+ PacketLoggingService.ProtocolName.RTP,
+ socket.getLocalAddress().getAddress(),
+ socket.getLocalPort(),
+ target.getAddress().getAddress(),
+ target.getPort(),
+ PacketLoggingService.TransportName.UDP,
+ true,
+ packet.getBuffer(),
+ packet.getOffset(),
+ packet.getLength());
+ }
}
catch (IOException ex)
{
diff --git a/src/net/java/sip/communicator/impl/neomedia/neomedia.manifest.mf b/src/net/java/sip/communicator/impl/neomedia/neomedia.manifest.mf
index fd5cbb2..68e373a 100644
--- a/src/net/java/sip/communicator/impl/neomedia/neomedia.manifest.mf
+++ b/src/net/java/sip/communicator/impl/neomedia/neomedia.manifest.mf
@@ -23,6 +23,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.fileaccess,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.netaddr,
+ net.java.sip.communicator.service.packetlogging,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.event,
net.java.sip.communicator.service.resources,
diff --git a/src/net/java/sip/communicator/impl/packetlogging/PacketLoggingActivator.java b/src/net/java/sip/communicator/impl/packetlogging/PacketLoggingActivator.java
new file mode 100644
index 0000000..9edcf2b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/packetlogging/PacketLoggingActivator.java
@@ -0,0 +1,392 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.packetlogging;
+
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.service.fileaccess.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.neomedia.*;
+import net.java.sip.communicator.service.packetlogging.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.Logger;
+import org.osgi.framework.*;
+
+import java.util.*;
+
+import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.*;
+
+/**
+ * Creates and registers Packet Logging service into OSGi.
+ * Also handles saving and retrieving configuration options for
+ * the service and is used from the configuration form.
+ *
+ * @author Damian Minkov
+ */
+public class PacketLoggingActivator
+ implements BundleActivator
+{
+ /**
+ * Our logging.
+ */
+ private static Logger logger =
+ Logger.getLogger(PacketLoggingActivator.class);
+
+ /**
+ * The OSGI bundle context.
+ */
+ private static BundleContext bundleContext = null;
+
+ /**
+ * Our packet logging service instance.
+ */
+ private static PacketLoggingServiceImpl packetLoggingService = null;
+
+ /**
+ * The configuration service.
+ */
+ private static ConfigurationService configurationService = null;
+
+ /**
+ * The service giving access to files.
+ */
+ private static FileAccessService fileAccessService;
+
+ /**
+ * The resource service.
+ */
+ private static ResourceManagementService resourceService;
+
+ /**
+ * Configuration property for packet logging enabled/disabled.
+ */
+ private final static String PACKET_LOGGING_ENABLED_PROPERTY_NAME
+ = "net.java.sip.communicator.packetlogging.PACKET_LOGGING_ENABLED";
+
+ /**
+ * Configuration property for packet logging for
+ * sip protocol enabled/disabled.
+ */
+ private final static String PACKET_LOGGING_SIP_ENABLED_PROPERTY_NAME
+ = "net.java.sip.communicator.packetlogging.PACKET_LOGGING_SIP_ENABLED";
+
+ /**
+ * Configuration property for packet logging for
+ * jabber protocol enabled/disabled.
+ */
+ private final static String PACKET_LOGGING_JABBER_ENABLED_PROPERTY_NAME
+ = "net.java.sip.communicator.packetlogging.PACKET_LOGGING_JABBER_ENABLED";
+
+ /**
+ * Configuration property for packet logging for
+ * RTP enabled/disabled.
+ */
+ private final static String PACKET_LOGGING_RTP_ENABLED_PROPERTY_NAME
+ = "net.java.sip.communicator.packetlogging.PACKET_LOGGING_RTP_ENABLED";
+
+ /**
+ * Configuration property for packet logging file count.
+ */
+ final static String PACKET_LOGGING_FILE_COUNT_PROPERTY_NAME
+ = "net.java.sip.communicator.packetlogging.PACKET_LOGGING_FILE_COUNT";
+
+ /**
+ * Configuration property for packet logging file size.
+ */
+ final static String PACKET_LOGGING_FILE_SIZE_PROPERTY_NAME
+ = "net.java.sip.communicator.packetlogging.PACKET_LOGGING_FILE_SIZE";
+
+ /**
+ * Is Packet Logging Service enabled.
+ */
+ private static boolean globalLoggingEnabled = false;
+
+ /**
+ * Is Packet Logging Service enabled for sip protocol.
+ */
+ private static boolean sipLoggingEnabled = false;
+
+ /**
+ * Is Packet Logging Service enabled for jabber protocol.
+ */
+ private static boolean jabberLoggingEnabled = false;
+
+ /**
+ * Is Packet Logging Service enabled for rtp.
+ */
+ private static boolean rtpLoggingEnabled = false;
+
+ /**
+ * Creates a PacketLoggingServiceImpl, starts it, and registers it as a
+ * PacketLoggingService.
+ *
+ * @param bundleContext OSGI bundle context
+ * @throws Exception if starting the PacketLoggingServiceImpl.
+ */
+ public void start(BundleContext bundleContext)
+ throws
+ Exception
+ {
+ PacketLoggingActivator.bundleContext = bundleContext;
+
+ packetLoggingService = new PacketLoggingServiceImpl();
+
+ getPacketLoggingService().start();
+
+ loadConfig();
+
+ bundleContext.registerService(PacketLoggingService.class.getName(),
+ getPacketLoggingService(), null);
+
+ if (logger.isInfoEnabled())
+ logger.info("Packet Logging Service ...[REGISTERED]");
+
+ // Config Form
+ Dictionary<String, String> packetLoggingProps
+ = new Hashtable<String, String>();
+ packetLoggingProps.put(
+ ConfigurationForm.FORM_TYPE,
+ ConfigurationForm.ADVANCED_TYPE);
+ bundleContext.registerService(
+ ConfigurationForm.class.getName(),
+ new LazyConfigurationForm(
+ PacketLoggingConfigForm.class.getName(),
+ getClass().getClassLoader(),
+ null,
+ "impl.packetlogging.PACKET_LOGGING_CONFIG",
+ 1200,
+ true),
+ packetLoggingProps);
+ }
+
+ /**
+ * Stops the Packet Logging bundle
+ *
+ * @param bundleContext the OSGI bundle context
+ */
+ public void stop(BundleContext bundleContext)
+ throws
+ Exception
+ {
+ if(getPacketLoggingService() != null)
+ getPacketLoggingService().stop();
+ if (logger.isInfoEnabled())
+ logger.info("Packet Logging Service ...[STOPPED]");
+ }
+
+ /**
+ * Reads the configurations and loads them.
+ */
+ private void loadConfig()
+ {
+ globalLoggingEnabled = getConfigurationService().getBoolean(
+ PACKET_LOGGING_ENABLED_PROPERTY_NAME, false);
+
+ sipLoggingEnabled = getConfigurationService().getBoolean(
+ PACKET_LOGGING_SIP_ENABLED_PROPERTY_NAME, false);
+
+ jabberLoggingEnabled = getConfigurationService().getBoolean(
+ PACKET_LOGGING_JABBER_ENABLED_PROPERTY_NAME, false);
+
+ rtpLoggingEnabled = getConfigurationService().getBoolean(
+ PACKET_LOGGING_RTP_ENABLED_PROPERTY_NAME, false);
+ }
+
+ /**
+ * Returns a reference to a ConfigurationService implementation currently
+ * registered in the bundle context or null if no such implementation was
+ * found.
+ *
+ * @return a currently valid implementation of the ConfigurationService.
+ */
+ public static ConfigurationService getConfigurationService()
+ {
+ if (configurationService == null)
+ {
+ ServiceReference confReference
+ = bundleContext.getServiceReference(
+ ConfigurationService.class.getName());
+ configurationService
+ = (ConfigurationService) bundleContext.getService(confReference);
+ }
+ return configurationService;
+ }
+
+ /**
+ * Returns the <tt>FileAccessService</tt> obtained from the bundle context.
+ *
+ * @return the <tt>FileAccessService</tt> obtained from the bundle context
+ */
+ public static FileAccessService getFileAccessService()
+ {
+ if (fileAccessService == null)
+ {
+ fileAccessService
+ = ServiceUtils.getService(
+ bundleContext,
+ FileAccessService.class);
+ }
+ return fileAccessService;
+ }
+
+ /**
+ * Returns the <tt>ResourceManagementService</tt> obtained from the
+ * bundle context.
+ *
+ * @return the <tt>ResourceManagementService</tt> obtained from the
+ * bundle context
+ */
+ public static ResourceManagementService getResourceService()
+ {
+ if (resourceService == null)
+ {
+ ServiceReference resourceReference
+ = bundleContext.getServiceReference(
+ ResourceManagementService.class.getName());
+
+ resourceService =
+ (ResourceManagementService) bundleContext
+ .getService(resourceReference);
+ }
+
+ return resourceService;
+ }
+
+ /**
+ * Checks whether packet logging is enabled in the configuration.
+ * @return <tt>true</tt> if packet logging is enabled.
+ */
+ public static boolean isGlobalLoggingEnabled()
+ {
+ return globalLoggingEnabled;
+ }
+
+ /**
+ * Checks whether packet logging is enabled in the configuration
+ * for sip protocol.
+ * @return <tt>true</tt> if packet logging is enabled for sip protocol.
+ */
+ public static boolean isSipLoggingEnabled()
+ {
+ return sipLoggingEnabled;
+ }
+
+ /**
+ * Checks whether packet logging is enabled in the configuration
+ * for jabber protocol.
+ * @return <tt>true</tt> if packet logging is enabled for jabber protocol.
+ */
+ public static boolean isJabberLoggingEnabled()
+ {
+ return jabberLoggingEnabled;
+ }
+
+ /**
+ * Checks whether packet logging is enabled in the configuration
+ * for RTP.
+ * @return <tt>true</tt> if packet logging is enabled for RTP.
+ */
+ public static boolean isRTPLoggingEnabled()
+ {
+ return rtpLoggingEnabled;
+ }
+
+ /**
+ * Change whether packet logging is enabled and save it in configuration.
+ * @param enabled <tt>true</tt> if we enable it.
+ */
+ static void setGlobalLoggingEnabled(boolean enabled)
+ {
+ if(enabled)
+ {
+ getConfigurationService().setProperty(
+ PACKET_LOGGING_ENABLED_PROPERTY_NAME, Boolean.TRUE);
+ }
+ else
+ {
+ getConfigurationService().removeProperty(
+ PACKET_LOGGING_ENABLED_PROPERTY_NAME);
+
+ // as we are globbally off, set it and to services
+ sipLoggingEnabled = false;
+ jabberLoggingEnabled = false;
+ rtpLoggingEnabled = false;
+ }
+ }
+
+ /**
+ * Change whether packet logging for sip protocol is enabled
+ * and save it in configuration.
+ * @param enabled <tt>true</tt> if we enable it.
+ */
+ public static void setSipLoggingEnabled(boolean enabled)
+ {
+ if(enabled)
+ {
+ getConfigurationService().setProperty(
+ PACKET_LOGGING_SIP_ENABLED_PROPERTY_NAME, Boolean.TRUE);
+ }
+ else
+ {
+ getConfigurationService().removeProperty(
+ PACKET_LOGGING_SIP_ENABLED_PROPERTY_NAME);
+ }
+
+ sipLoggingEnabled = enabled;
+ }
+
+ /**
+ * Change whether packet logging for jabber protocol is enabled
+ * and save it in configuration.
+ * @param enabled <tt>true</tt> if we enable it.
+ */
+ public static void setJabberLoggingEnabled(boolean enabled)
+ {
+ if(enabled)
+ {
+ getConfigurationService().setProperty(
+ PACKET_LOGGING_JABBER_ENABLED_PROPERTY_NAME, Boolean.TRUE);
+ }
+ else
+ {
+ getConfigurationService().removeProperty(
+ PACKET_LOGGING_JABBER_ENABLED_PROPERTY_NAME);
+ }
+
+ jabberLoggingEnabled = enabled;
+ }
+
+ /**
+ * Change whether packet logging for RTP is enabled
+ * and save it in configuration.
+ * @param enabled <tt>true</tt> if we enable it.
+ */
+ public static void setRTPLoggingEnabled(boolean enabled)
+ {
+ if(enabled)
+ {
+ getConfigurationService().setProperty(
+ PACKET_LOGGING_RTP_ENABLED_PROPERTY_NAME, Boolean.TRUE);
+ }
+ else
+ {
+ getConfigurationService().removeProperty(
+ PACKET_LOGGING_RTP_ENABLED_PROPERTY_NAME);
+ }
+
+ rtpLoggingEnabled = true;
+ }
+
+ /**
+ * Our packet logging service instance.
+ */
+ public static PacketLoggingServiceImpl getPacketLoggingService()
+ {
+ return packetLoggingService;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/packetlogging/PacketLoggingConfigForm.java b/src/net/java/sip/communicator/impl/packetlogging/PacketLoggingConfigForm.java
new file mode 100644
index 0000000..b268c3b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/packetlogging/PacketLoggingConfigForm.java
@@ -0,0 +1,301 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.packetlogging;
+
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.util.swing.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import java.awt.*;
+import java.awt.event.*;
+
+/**
+ * The Packet Logging Service configuration form.
+ * @author Damian Minkov
+ */
+public class PacketLoggingConfigForm
+ extends TransparentPanel
+ implements ActionListener,
+ DocumentListener
+{
+ /**
+ * The enable packet logging check box.
+ */
+ private JCheckBox enableCheckBox;
+
+ /**
+ * Check box to enable/disable packet debug of sip protocol.
+ */
+ private JCheckBox sipProtocolCheckBox;
+
+ /**
+ * Check box to enable/disable packet debug of jabber protocol.
+ */
+ private JCheckBox jabberProtocolCheckBox;
+
+ /**
+ * Check box to enable/disable packet debug of media protocol/RTP.
+ */
+ private JCheckBox rtpProtocolCheckBox;
+
+ /**
+ * The file count label.
+ */
+ private JLabel fileCountLabel;
+
+ /**
+ * The filed for file count value.
+ */
+ private JTextField fileCountField = new JTextField();
+
+ /**
+ * The file size label.
+ */
+ private JLabel fileSizeLabel;
+
+ /**
+ * The filed for file size value.
+ */
+ private JTextField fileSizeField = new JTextField();
+
+
+ /**
+ * Creates Packet Logging Config form.
+ */
+ public PacketLoggingConfigForm()
+ {
+ super(new BorderLayout());
+
+ init();
+ loadValues();
+ }
+
+ /**
+ * Creating the configuration form
+ */
+ private void init()
+ {
+ ResourceManagementService resources =
+ PacketLoggingActivator.getResourceService();
+
+ enableCheckBox = new JCheckBox(
+ resources.getI18NString("impl.packetlogging.ENABLE_DISABLE"));
+ enableCheckBox.addActionListener(this);
+
+ sipProtocolCheckBox = new JCheckBox(
+ resources.getI18NString("plugin.sipaccregwizz.PROTOCOL_NAME"));
+ sipProtocolCheckBox.addActionListener(this);
+
+ jabberProtocolCheckBox = new JCheckBox(
+ resources.getI18NString("plugin.jabberaccregwizz.PROTOCOL_NAME"));
+ jabberProtocolCheckBox.addActionListener(this);
+
+ rtpProtocolCheckBox = new JCheckBox(
+ resources.getI18NString("impl.packetlogging.PACKET_LOGGING_RTP"));
+ rtpProtocolCheckBox.addActionListener(this);
+ rtpProtocolCheckBox.setToolTipText(resources.getI18NString(
+ "impl.packetlogging.PACKET_LOGGING_RTP_DESCRIPTION"));
+
+ JPanel mainPanel = new TransparentPanel();
+
+ add(mainPanel, BorderLayout.NORTH);
+
+ mainPanel.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+
+ enableCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1.0;
+ c.gridx = 0;
+ c.gridy = 0;
+ mainPanel.add(enableCheckBox, c);
+
+ String label = resources.getI18NString(
+ "impl.packetlogging.PACKET_LOGGING_DESCRIPTION");
+ JLabel descriptionLabel = new JLabel(label);
+ descriptionLabel.setToolTipText(label);
+ enableCheckBox.setToolTipText(label);
+ descriptionLabel.setForeground(Color.GRAY);
+ descriptionLabel.setFont(descriptionLabel.getFont().deriveFont(8));
+ c.gridy = 1;
+ c.insets = new Insets(0, 40, 10, 0);
+ mainPanel.add(descriptionLabel, c);
+
+ final JPanel loggersButtonPanel
+ = new TransparentPanel(new GridLayout(0, 1));
+
+ loggersButtonPanel.setBorder(BorderFactory.createTitledBorder(
+ resources.getI18NString("service.gui.PROTOCOL")));
+
+ loggersButtonPanel.add(sipProtocolCheckBox);
+ loggersButtonPanel.add(jabberProtocolCheckBox);
+ loggersButtonPanel.add(rtpProtocolCheckBox);
+
+ c.insets = new Insets(0, 20, 10, 0);
+ c.gridy = 2;
+ mainPanel.add(loggersButtonPanel, c);
+
+ final JPanel advancedPanel
+ = new TransparentPanel(new GridLayout(0, 2));
+
+ advancedPanel.setBorder(BorderFactory.createTitledBorder(
+ resources.getI18NString("service.gui.ADVANCED")));
+
+ fileCountField.getDocument().addDocumentListener(this);
+ fileSizeField.getDocument().addDocumentListener(this);
+
+ fileCountLabel = new JLabel(resources.getI18NString(
+ "impl.packetlogging.PACKET_LOGGING_FILE_COUNT"));
+ advancedPanel.add(fileCountLabel);
+ advancedPanel.add(fileCountField);
+ fileSizeLabel = new JLabel(resources.getI18NString(
+ "impl.packetlogging.PACKET_LOGGING_FILE_SIZE"));
+ advancedPanel.add(fileSizeLabel);
+ advancedPanel.add(fileSizeField);
+
+ c.gridy = 3;
+ mainPanel.add(advancedPanel, c);
+
+ }
+
+ /**
+ * Loading the values stored into configuration form
+ */
+ private void loadValues()
+ {
+ enableCheckBox.setSelected(
+ PacketLoggingActivator.isGlobalLoggingEnabled());
+ sipProtocolCheckBox.setSelected(
+ PacketLoggingActivator.isSipLoggingEnabled());
+ jabberProtocolCheckBox.setSelected(
+ PacketLoggingActivator.isJabberLoggingEnabled());
+ rtpProtocolCheckBox.setSelected(
+ PacketLoggingActivator.isRTPLoggingEnabled());
+ fileCountField.setText(String.valueOf(PacketLoggingActivator
+ .getPacketLoggingService().getLogfileCount()));
+ fileSizeField.setText(String.valueOf(PacketLoggingActivator
+ .getPacketLoggingService().getLimit()/1000));
+
+ updateButtonsState();
+ }
+
+ /**
+ * Update button enable/disable state according enableCheckBox.
+ */
+ private void updateButtonsState()
+ {
+ sipProtocolCheckBox.setEnabled(enableCheckBox.isSelected());
+ jabberProtocolCheckBox.setEnabled(enableCheckBox.isSelected());
+ rtpProtocolCheckBox.setEnabled(enableCheckBox.isSelected());
+ fileCountField.setEnabled(enableCheckBox.isSelected());
+ fileSizeField.setEnabled(enableCheckBox.isSelected());
+ fileSizeLabel.setEnabled(enableCheckBox.isSelected());
+ fileCountLabel.setEnabled(enableCheckBox.isSelected());
+ }
+
+ /**
+ * Invoked when an action occurs.
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ Object source = e.getSource();
+
+ if(source.equals(enableCheckBox))
+ {
+ // turn it on/off in activator
+ PacketLoggingActivator.setGlobalLoggingEnabled(
+ enableCheckBox.isSelected());
+ updateButtonsState();
+ }
+ else if(source.equals(sipProtocolCheckBox))
+ {
+ PacketLoggingActivator.setSipLoggingEnabled(
+ sipProtocolCheckBox.isSelected());
+ }
+ else if(source.equals(jabberProtocolCheckBox))
+ {
+ PacketLoggingActivator.setJabberLoggingEnabled(
+ jabberProtocolCheckBox.isSelected());
+ }
+ else if(source.equals(rtpProtocolCheckBox))
+ {
+ PacketLoggingActivator.setRTPLoggingEnabled(
+ rtpProtocolCheckBox.isSelected());
+ }
+ }
+
+ /**
+ * Gives notification that there was an insert into the document. The
+ * range given by the DocumentEvent bounds the freshly inserted region.
+ *
+ * @param e the document event
+ */
+ public void insertUpdate(DocumentEvent e)
+ {
+ documentChanged(e);
+ }
+
+ /**
+ * Gives notification that a portion of the document has been
+ * removed. The range is given in terms of what the view last
+ * saw (that is, before updating sticky positions).
+ *
+ * @param e the document event
+ */
+ public void removeUpdate(DocumentEvent e)
+ {
+ documentChanged(e);
+ }
+
+ /**
+ * Not used.
+ *
+ * @param e the document event
+ */
+ public void changedUpdate(DocumentEvent e)
+ {}
+
+ /**
+ * A change in the text fields.
+ * @param e the document event.
+ */
+ private void documentChanged(DocumentEvent e)
+ {
+ if(e.getDocument().equals(fileCountField.getDocument()))
+ {
+ // set file count only if its un integer
+ try
+ {
+ int newFileCount = Integer.valueOf(fileCountField.getText());
+ fileCountField.setForeground(Color.black);
+ PacketLoggingActivator.getPacketLoggingService()
+ .setLogfileCount(newFileCount);
+ }
+ catch(Throwable t)
+ {
+ fileCountField.setForeground(Color.red);
+ }
+ }
+ else if(e.getDocument().equals(fileSizeField.getDocument()))
+ {
+ // set file size only if its un integer
+ try
+ {
+ int newFileSize = Integer.valueOf(fileSizeField.getText());
+ fileSizeField.setForeground(Color.black);
+ PacketLoggingActivator.getPacketLoggingService()
+ .setLimit(newFileSize * 1000);
+ }
+ catch(Throwable t)
+ {
+ fileSizeField.setForeground(Color.red);
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/packetlogging/PacketLoggingServiceImpl.java b/src/net/java/sip/communicator/impl/packetlogging/PacketLoggingServiceImpl.java
new file mode 100644
index 0000000..924bbdb
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/packetlogging/PacketLoggingServiceImpl.java
@@ -0,0 +1,844 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.packetlogging;
+
+import net.java.sip.communicator.service.packetlogging.*;
+import net.java.sip.communicator.util.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Packet Logging Service implementation dumping logs in
+ * pcap(tcpdump/wireshark) format file.
+ *
+ * @author Damian Minkov
+ */
+public class PacketLoggingServiceImpl
+ implements PacketLoggingService
+{
+ /**
+ * Our Logger.
+ */
+ private static final Logger logger
+ = Logger.getLogger(PacketLoggingServiceImpl.class);
+
+ /**
+ * The OutputStream we are currently writing to.
+ */
+ private FileOutputStream outputStream = null;
+
+ /**
+ * The thread that queues packets and saves them to file.
+ */
+ private SaverThread saverThread = new SaverThread();
+
+ /**
+ * The fake ethernet header we use as template.
+ */
+ private final static byte[] fakeEthernetHeader =
+ new byte[]{
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x08, (byte)0x00
+ };
+
+ /**
+ * The fake ipv4 header we use as template.
+ */
+ private final static byte[] ipHeaderTemplate =
+ new byte[]{
+ (byte)0x45, (byte)0x00,
+ (byte)0x03, (byte)0x48, (byte)0xc9, (byte)0x14,
+ (byte)0x00, (byte)0x00, (byte)0x35,(byte)0x11,
+ (byte)0x00, (byte)0x00, // check sum
+ (byte)0xd5, (byte)0xc0, (byte)0x3b, (byte)0x4b,//src
+ (byte)0xc0, (byte)0xa8, (byte)0x00, (byte)0x34 //dst
+ };
+
+ /**
+ * The fake ipv6 header we use as template.
+ */
+ private final static byte[] ip6HeaderTemplate =
+ new byte[]{
+ (byte)0x60, (byte)0x00, (byte)0x00, (byte)0x00, // version, traffic, flowable
+ (byte)0x00, (byte)0x00, // length
+ (byte)0x11, // next header
+ (byte)0x40, // hop limit
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // src
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // src
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // src
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // src
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // dst
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // dst
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // dst
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 // dst
+ };
+
+ /**
+ * The fake udp header we use as template.
+ */
+ private final static byte[] udpHeaderTemplate =
+ new byte[]{
+ (byte)0x13, (byte)0xc4,
+ (byte)0x13, (byte)0xc4,
+ (byte)0x03, (byte)0x34,
+ (byte)0x00, (byte)0x00// checksum
+
+ };
+
+ /**
+ * The fake tcp header we use as template.
+ */
+ private final static byte[] tcpHeaderTemplate =
+ new byte[]{
+ (byte)0xb7, (byte)0x61, // src port
+ (byte)0x13, (byte)0xc4, // dst port
+ (byte)0x4f, (byte)0x20, (byte)0x37, (byte)0x3b, // seq number
+ (byte)0x11, (byte)0x1d, (byte)0xbc, (byte)0x54, // ack number
+ (byte)0x80, // header length
+ (byte)0x18, // flags
+ (byte)0x00, (byte)0x2e, // windows size
+ (byte)0xac, (byte)0x78, // check sum
+ (byte)0x00, (byte)0x00,
+ (byte)0x01, (byte)0x01, (byte)0x08, (byte)0x0a, // options
+ (byte)0x00, (byte)0x06, (byte)0xd4, (byte)0x48, // options
+ (byte)0x6e, (byte)0xcc, (byte)0x76, (byte)0xbd // options
+ };
+
+ /**
+ * Using this object to lock and protectd the two counters
+ * used for tcp seq and ack numbers.
+ */
+ private Object tcpCounterLock = new Object();
+
+ /**
+ * The seq that the sender will send.
+ */
+ private long srcCount = 1;
+
+ /**
+ * This is the ack number send from the sender.
+ */
+ private long dstCount = 1;
+
+ /**
+ * A counter watching how much has been written to the file.
+ */
+ private long written = 0;
+
+ /**
+ * The limit for the file size.
+ * 0 means no limit.
+ */
+ private long limit = 5000000;
+
+ /**
+ * The counter for number of files.
+ */
+ private int logfileCount = 3;
+
+ /**
+ * All the files we can use for writing.
+ */
+ private File[] files;
+
+ /**
+ * Starting the packet logger. Generating the files we can use,
+ * rotate any previous files and open the current file for writing.
+ */
+ public void start()
+ {
+ limit = PacketLoggingActivator.getConfigurationService().getLong(
+ PacketLoggingActivator.PACKET_LOGGING_FILE_SIZE_PROPERTY_NAME,
+ limit);
+
+ logfileCount = PacketLoggingActivator.getConfigurationService().getInt(
+ PacketLoggingActivator.PACKET_LOGGING_FILE_COUNT_PROPERTY_NAME,
+ logfileCount);
+
+ saverThread.start();
+ }
+
+ /**
+ * Generates the files we will later use for writing.
+ * @throws Exception
+ */
+ private void getFileNames()
+ throws Exception
+ {
+ files = new File[getLogfileCount()];
+ for(int i = 0; i < getLogfileCount(); i++)
+ {
+ files[i] = PacketLoggingActivator.getFileAccessService()
+ .getPrivatePersistentFile("log/sip-communicator" + i + ".pcap");
+ }
+ }
+
+ /**
+ * Rotates any existing files and use the newly created first one
+ * for writing.
+ * @throws IOException
+ */
+ private void rotateFiles()
+ throws IOException
+ {
+ if(outputStream != null)
+ {
+ outputStream.flush();
+ outputStream.close();
+ }
+
+ for (int i = getLogfileCount() -2; i >= 0; i--)
+ {
+ File f1 = files[i];
+ File f2 = files[i+1];
+ if (f1.exists())
+ {
+ if (f2.exists())
+ {
+ f2.delete();
+ }
+ f1.renameTo(f2);
+ }
+ }
+
+ outputStream = new FileOutputStream(files[0]);
+ written = 0;
+ createGlobalHeader();
+ }
+
+ /**
+ * Stops the packet logging.
+ */
+ public void stop()
+ {
+ saverThread.stopRunning();
+
+ if(outputStream != null)
+ {
+ try
+ {
+ outputStream.flush();
+ outputStream.close();
+ }
+ catch(IOException e)
+ {
+ e.printStackTrace();
+ }
+ outputStream = null;
+ }
+ }
+
+ /**
+ * Creates pcap file global header.
+ * @throws IOException
+ */
+ private void createGlobalHeader()
+ throws IOException
+ {
+ /* magic number(swapped) */
+ outputStream.write(0xd4);
+ outputStream.write(0xc3);
+ outputStream.write(0xb2);
+ outputStream.write(0xa1);
+
+ /* major version number */
+ outputStream.write(0x02);
+ outputStream.write(0x00);
+
+ /* minor version number */
+ outputStream.write(0x04);
+ outputStream.write(0x00);
+
+ /* GMT to local correction */
+ outputStream.write(0x00);
+ outputStream.write(0x00);
+ outputStream.write(0x00);
+ outputStream.write(0x00);
+
+ /* accuracy of timestamps */
+ outputStream.write(0x00);
+ outputStream.write(0x00);
+ outputStream.write(0x00);
+ outputStream.write(0x00);
+
+ /* max length of captured packets, in octets */
+ outputStream.write(0xff);
+ outputStream.write(0xff);
+ outputStream.write(0x00);
+ outputStream.write(0x00);
+
+ /* data link type(ethernet) */
+ outputStream.write(0x01);
+ outputStream.write(0x00);
+ outputStream.write(0x00);
+ outputStream.write(0x00);
+ }
+
+ /**
+ * Checks is logging globally enabled for the service.
+ *
+ * @return is logging enabled.
+ */
+ public boolean isLoggingEnabled()
+ {
+ return PacketLoggingActivator.isGlobalLoggingEnabled();
+ }
+
+ /**
+ * Checks is logging globally enabled for and is it currently
+ * available fo the given service.
+ *
+ * @param protocol that is checked.
+ * @return is logging enabled.
+ */
+ public boolean isLoggingEnabled(ProtocolName protocol)
+ {
+ switch(protocol)
+ {
+ case SIP:
+ return PacketLoggingActivator.isGlobalLoggingEnabled()
+ && PacketLoggingActivator.isSipLoggingEnabled();
+ case JABBER:
+ return PacketLoggingActivator.isGlobalLoggingEnabled()
+ && PacketLoggingActivator.isJabberLoggingEnabled();
+ case RTP:
+ return PacketLoggingActivator.isGlobalLoggingEnabled()
+ && PacketLoggingActivator.isRTPLoggingEnabled();
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Log a packet with all the required information.
+ *
+ * @param protocol the source protocol that logs this packet.
+ * @param sourceAddress the source address of the packet.
+ * @param sourcePort the source port of the packet.
+ * @param destinationAddress the destination address.
+ * @param destinationPort the destination port.
+ * @param transport the transport this packet uses.
+ * @param sender are we the sender of the packet or not.
+ * @param packetContent the packet content.
+ */
+ public void logPacket(
+ ProtocolName protocol,
+ byte[] sourceAddress, int sourcePort,
+ byte[] destinationAddress, int destinationPort,
+ TransportName transport,
+ boolean sender,
+ byte[] packetContent)
+ {
+ this.logPacket(protocol, sourceAddress, sourcePort,
+ destinationAddress, destinationPort,
+ transport, sender,
+ packetContent, 0, packetContent.length);
+ }
+
+ /**
+ * Log a packet with all the required information.
+ *
+ * @param protocol the source protocol that logs this packet.
+ * @param sourceAddress the source address of the packet.
+ * @param sourcePort the source port of the packet.
+ * @param destinationAddress the destination address.
+ * @param destinationPort the destination port.
+ * @param transport the transport this packet uses.
+ * @param sender are we the sender of the packet or not.
+ * @param packetContent the packet content.
+ * @param packetOffset the packet content offset.
+ * @param packetLength the packet content length.
+ */
+ public void logPacket(
+ ProtocolName protocol,
+ byte[] sourceAddress,
+ int sourcePort,
+ byte[] destinationAddress,
+ int destinationPort,
+ TransportName transport,
+ boolean sender,
+ byte[] packetContent,
+ int packetOffset,
+ int packetLength)
+ {
+ saverThread.queuePacket(
+ new Packet(protocol,
+ sourceAddress,
+ sourcePort,
+ destinationAddress,
+ destinationPort,
+ transport,
+ sender,
+ packetContent,
+ packetOffset,
+ packetLength));
+ }
+
+ /**
+ * Dump the packet to the output file stream.
+ *
+ * @param packet the packet ot save.
+ * @throws Exception when error occurs saving to file stream or when
+ * rotating files.
+ */
+ private void savePacket(Packet packet)
+ throws Exception
+ {
+ // if one of the addresses is ipv4 we are using ipv4,
+ // local udp addresses come as 0.0.0.0.0....0.0.0 when
+ // ipv6 is enabled in the underlying os
+ boolean isIPv4 = packet.sourceAddress.length == 4
+ || packet.destinationAddress.length == 4;
+
+ byte[] ipHeader;
+
+ if(isIPv4)
+ {
+ ipHeader = new byte[ipHeaderTemplate.length];
+ System.arraycopy(
+ ipHeaderTemplate, 0, ipHeader, 0, ipHeader.length);
+ System.arraycopy(packet.sourceAddress,
+ 0,
+ ipHeader,
+ 12,
+ 4);
+ System.arraycopy(packet.destinationAddress,
+ 0,
+ ipHeader,
+ 16,
+ 4);
+ }
+ else
+ {
+ ipHeader = new byte[ip6HeaderTemplate.length];
+ System.arraycopy(
+ ip6HeaderTemplate, 0, ipHeader, 0, ipHeader.length);
+ System.arraycopy(packet.sourceAddress,
+ 0,
+ ipHeader,
+ 8,
+ 16);
+
+ System.arraycopy(packet.destinationAddress,
+ 0,
+ ipHeader,
+ 24,
+ 16);
+ }
+
+ byte[] transportHeader;
+ short len;
+ if(packet.transport == TransportName.UDP)
+ {
+ byte[] udpHeader = new byte[udpHeaderTemplate.length];
+ transportHeader = udpHeader;
+ System.arraycopy(udpHeaderTemplate, 0,
+ udpHeader, 0, udpHeader.length);
+
+ writeShort(packet.sourcePort, udpHeader, 0);
+ writeShort(packet.destinationPort, udpHeader, 2);
+ len = (short)(packet.packetLength + udpHeader.length);
+ writeShort(len, udpHeader, 4);
+ }
+ else
+ {
+ transportHeader = new byte[tcpHeaderTemplate.length];
+ System.arraycopy(tcpHeaderTemplate, 0, transportHeader,
+ 0, transportHeader.length);
+
+ writeShort(packet.sourcePort, transportHeader, 0);
+ writeShort(packet.destinationPort, transportHeader, 2);
+
+ len = (short)(packet.packetLength + transportHeader.length);
+
+ if(packet.sender)
+ {
+ long seqnum;
+ long acknum;
+ synchronized(tcpCounterLock)
+ {
+ seqnum = srcCount;
+ srcCount += packet.packetLength;
+ acknum = dstCount;
+ }
+
+ intToBytes((int)(seqnum & 0xffffffff),
+ transportHeader, 4);
+ intToBytes((int)(acknum & 0xffffffff),
+ transportHeader, 8);
+ }
+ else
+ {
+ long seqnum;
+ long acknum;
+ synchronized(tcpCounterLock)
+ {
+ seqnum = dstCount;
+ dstCount += packet.packetLength;
+ acknum = srcCount;
+ }
+
+ intToBytes((int)(seqnum & 0xffffffff),
+ transportHeader, 4);
+ intToBytes((int)(acknum & 0xffffffff),
+ transportHeader, 8);
+ }
+ }
+
+ // now set ip header total length
+ if(isIPv4)
+ {
+ short ipTotalLen = (short)(len + ipHeader.length);
+ writeShort(ipTotalLen, ipHeader, 2);
+
+ if(packet.transport == TransportName.UDP)
+ ipHeader[9] = (byte)0x11;
+ else
+ ipHeader[9] = (byte)0x06;
+
+ int chk2 = computeChecksum(ipHeader);
+ ipHeader[10] = (byte) (chk2 >> 8);
+ ipHeader[11] = (byte) (chk2 & 0xff);
+ }
+ else
+ {
+ writeShort(len, ipHeader, 4);
+
+ if(packet.transport == TransportName.UDP)
+ ipHeader[6] = (byte)0x11;
+ else
+ ipHeader[6] = (byte)0x06;
+ }
+
+ long current = System.currentTimeMillis();
+ int tsSec = (int)(current/1000);
+ int tsUsec = (int)((current%1000) * 1000);
+ int feakHeaderLen = fakeEthernetHeader.length +
+ ipHeader.length + transportHeader.length;
+ int inclLen = packet.packetLength + feakHeaderLen;
+ int origLen = inclLen;
+
+ synchronized(this)
+ {
+ // open files only if needed
+ if(outputStream == null)
+ {
+ getFileNames();
+ rotateFiles();// this one opens the file for write
+ }
+
+ if(getLimit() > 0 && written > getLimit())
+ rotateFiles();
+
+ addInt(tsSec);
+ addInt(tsUsec);
+ addInt(inclLen);
+ addInt(origLen);
+
+ outputStream.write(fakeEthernetHeader);
+ outputStream.write(ipHeader);
+ outputStream.write(transportHeader);
+ outputStream.write(
+ packet.packetContent,
+ packet.packetOffset,
+ packet.packetLength);
+ outputStream.flush();
+
+ written += inclLen + 16;
+ }
+ }
+
+ /**
+ * Writes int to the file. Used for packet headers.
+ * @param d the value to write.
+ * @throws IOException
+ */
+ private void addInt(int d)
+ throws IOException
+ {
+ outputStream.write ((d & 0xff));
+ outputStream.write(((d & 0xff00) >> 8));
+ outputStream.write(((d & 0xff0000) >> 16));
+ outputStream.write(((d & 0xff000000) >> 24));
+ }
+
+ /**
+ * Converts a 32-bit word representation of an IPv4 address to a
+ * byte array.
+ *
+ * @param address The 32-bit word representation of the IPv4 address.
+ * @param data The byte array in which to store the IPv4 data.
+ * @param offset The offset into the array where the data start.
+ */
+ private static final void intToBytes(int address, byte[] data,
+ int offset)
+ {
+ data[offset] = (byte)(0xff & (address >>> 24));
+ data[offset + 1] = (byte)(0xff & (address >>> 16));
+ data[offset + 2] = (byte)(0xff & (address >>> 8));
+ data[offset + 3] = (byte)(0xff & address);
+ }
+
+ /**
+ * Puts the short value to the array.
+ * @param value value to convert to bytes.
+ * @param data destination data
+ * @param offset offset in the data
+ */
+ private static void writeShort(int value, byte[] data, int offset)
+ {
+ data[offset] = (byte) (value >> 8);
+ data[offset + 1] = (byte) value;
+ }
+
+ /**
+ * Calculates checksums assuming the checksum is a 16-bit header field.
+ */
+ private int computeChecksum(byte[] data)
+ {
+ int total = 0;
+ int i = 0;
+
+ // Don't Skip existing checksum cause its set to 0000
+ int imax = data.length - (data.length % 2);
+
+ while(i < imax)
+ total+=(((data[i++] & 0xff) << 8) | (data[i++] & 0xff));
+
+ if(i < data.length)
+ total+=((data[i] & 0xff) << 8);
+
+ // Fold to 16 bits
+ while((total & 0xffff0000) != 0)
+ total = (total & 0xffff) + (total >>> 16);
+
+ total = (~total & 0xffff);
+
+ return total;
+ }
+
+ /**
+ * The limit for the file size. 0 means no limit.
+ * @return the file size limit.
+ */
+ public long getLimit()
+ {
+ return limit;
+ }
+
+ /**
+ * Changes the file size limit.
+ * @param limit the new limit size.
+ */
+ public void setLimit(long limit)
+ {
+ this.limit = limit;
+
+ PacketLoggingActivator.getConfigurationService().setProperty(
+ PacketLoggingActivator.PACKET_LOGGING_FILE_SIZE_PROPERTY_NAME,
+ limit);
+ }
+
+ /**
+ * The counter for number of files.
+ * @return the number of file counts.
+ */
+ public int getLogfileCount()
+ {
+ return logfileCount;
+ }
+
+ /**
+ * Changes file count.
+ * @param logfileCount the new file count.
+ */
+ public void setLogfileCount(int logfileCount)
+ {
+ this.logfileCount = logfileCount;
+
+ PacketLoggingActivator.getConfigurationService().setProperty(
+ PacketLoggingActivator.PACKET_LOGGING_FILE_COUNT_PROPERTY_NAME,
+ logfileCount);
+ }
+
+ /**
+ * The data we receive and that we will dump in a file.
+ */
+ private class Packet
+ {
+ /**
+ * The protocol logging this packet.
+ */
+ ProtocolName protocol;
+
+ /**
+ * The source address of the packet.
+ */
+ byte[] sourceAddress;
+
+ /**
+ * The source port of the packet.
+ */
+ int sourcePort;
+
+ /**
+ * The destination address of the packet.
+ */
+ byte[] destinationAddress;
+
+ /**
+ * The destination port of the packet.
+ */
+ int destinationPort;
+
+ /**
+ * Is the packet a udp one.
+ */
+ TransportName transport;
+
+ /**
+ * Are we sending the packet, or false if we are receiving.
+ */
+ boolean sender;
+
+ /**
+ * Array containing packet content.
+ */
+ byte[] packetContent;
+
+ /**
+ * The offset in the packetContent where packet content is.
+ */
+ int packetOffset;
+
+ /**
+ * The length of the packet content.
+ */
+ int packetLength;
+
+ /**
+ * Creates a packet with the needed data.
+ * @param protocol the source protocol that logs this packet.
+ * @param sourceAddress The source address of the packet.
+ * @param sourcePort The source port of the packet.
+ * @param destinationAddress The destination address of the packet.
+ * @param destinationPort The destination port of the packet.
+ * @param transport the transport this packet uses.
+ * @param sender Are we sending the packet,
+ * or false if we are receiving.
+ * @param packetContent Array containing packet content.
+ * @param packetOffset The offset in the packetContent
+ * where packet content is.
+ * @param packetLength The length of the packet content.
+ */
+ private Packet(ProtocolName protocol,
+ byte[] sourceAddress,
+ int sourcePort,
+ byte[] destinationAddress,
+ int destinationPort,
+ TransportName transport,
+ boolean sender,
+ byte[] packetContent,
+ int packetOffset,
+ int packetLength)
+ {
+ this.protocol = protocol;
+ this.sourceAddress = sourceAddress;
+ this.sourcePort = sourcePort;
+ this.destinationAddress = destinationAddress;
+ this.destinationPort = destinationPort;
+ this.transport = transport;
+ this.sender = sender;
+ this.packetContent = packetContent;
+ this.packetOffset = packetOffset;
+ this.packetLength = packetLength;
+ }
+ }
+
+ /**
+ * Dumps packet in separate thread so we don't block
+ * our calling thread.
+ */
+ private class SaverThread
+ extends Thread
+ {
+ /**
+ * start/stop indicator.
+ */
+ private boolean stopped = true;
+
+ /**
+ * List of packets queued to be written in the file.
+ */
+ private List<Packet> packetsToDump = new ArrayList<Packet>();
+
+ /**
+ * Sends instant messages in separate thread so we don't block
+ * our calling thread.
+ */
+ public void run()
+ {
+ stopped = false;
+
+ while(!stopped)
+ {
+ Packet pktToSave = null;
+
+ synchronized(this)
+ {
+ if(packetsToDump.isEmpty())
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException iex)
+ {
+ }
+ }
+
+ if(!packetsToDump.isEmpty())
+ pktToSave = packetsToDump.remove(0);
+ }
+
+ if(pktToSave != null)
+ {
+ try
+ {
+ savePacket(pktToSave);
+ }
+ catch(Throwable t)
+ {
+ logger.error("Error writing packet to file", t);
+ }
+ }
+ }
+ }
+
+ /**
+ * Interrupts this sender so that it would no longer send messages.
+ */
+ public synchronized void stopRunning()
+ {
+ stopped = true;
+ notifyAll();
+ }
+
+ /**
+ * Schedule new packet for save.
+ * @param packet new packet to save.
+ */
+ public synchronized void queuePacket(Packet packet)
+ {
+ packetsToDump.add(packet);
+ notifyAll();
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/packetlogging/packetlogging.manifest.mf b/src/net/java/sip/communicator/impl/packetlogging/packetlogging.manifest.mf
new file mode 100644
index 0000000..593c203
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/packetlogging/packetlogging.manifest.mf
@@ -0,0 +1,20 @@
+Bundle-Activator: net.java.sip.communicator.impl.packetlogging.PacketLoggingActivator
+Bundle-Name: Packet Logging service
+Bundle-Description: A bundle that provides packet logging in pcap file format
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+System-Bundle: yes
+Import-Package: org.osgi.framework,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.fileaccess,
+ net.java.sip.communicator.service.gui,
+ net.java.sip.communicator.service.neomedia,
+ net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.service.resources,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.util.swing,
+ javax.swing,
+ javax.swing.border,
+ javax.swing.event,
+ javax.swing.text
+Export-Package: net.java.sip.communicator.service.packetlogging
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java b/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java
index 94181b6..552c8be 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java
@@ -13,6 +13,7 @@ import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.hid.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.service.packetlogging.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
@@ -83,6 +84,8 @@ public class JabberActivator
*/
private static HIDService hidService = null;
+ private static PacketLoggingService packetLoggingService = null;
+
/**
* Called when this bundle is started so the Framework can perform the
* bundle-specific activities necessary to start this bundle.
@@ -300,4 +303,24 @@ public class JabberActivator
}
return hidService;
}
+
+ /**
+ * Returns a reference to the PacketLoggingService implementation
+ * currently registered in the bundle context or null if no such
+ * implementation was found.
+ *
+ * @return a reference to a PacketLoggingService implementation
+ * currently registered in the bundle context or null if no such
+ * implementation was found.
+ */
+ public static PacketLoggingService getPacketLogging()
+ {
+ if (packetLoggingService == null)
+ {
+ packetLoggingService
+ = ServiceUtils.getService(
+ bundleContext, PacketLoggingService.class);
+ }
+ return packetLoggingService;
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
index b2396c7..a2bdae5 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
@@ -13,6 +13,7 @@ import java.text.*;
import java.util.*;
import javax.net.ssl.*;
+import net.java.sip.communicator.impl.protocol.jabber.debugger.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.service.protocol.jabberconstants.*;
@@ -231,6 +232,11 @@ public class ProtocolProviderServiceJabberImpl
}
/**
+ * The debugger who logs packets.
+ */
+ private SmackPacketDebugger debugger = null;
+
+ /**
* Returns the state of the registration of this protocol provider
* @return the <tt>RegistrationState</tt> that this provider is
* currently in or null in case it is in a unknown state.
@@ -744,6 +750,14 @@ public class ProtocolProviderServiceJabberImpl
logger.error("Error creating custom trust manager", e);
}
+ if(debugger == null)
+ debugger = new SmackPacketDebugger();
+
+ // setts the debugger
+ debugger.setConnection(connection);
+ connection.addPacketListener(debugger, null);
+ connection.addPacketInterceptor(debugger, null);
+
connection.connect();
registerServiceDiscoveryManager();
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/debugger/SmackPacketDebugger.java b/src/net/java/sip/communicator/impl/protocol/jabber/debugger/SmackPacketDebugger.java
new file mode 100644
index 0000000..72a0b75
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/debugger/SmackPacketDebugger.java
@@ -0,0 +1,150 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.debugger;
+
+import net.java.sip.communicator.impl.protocol.jabber.*;
+import net.java.sip.communicator.service.packetlogging.*;
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.packet.*;
+
+import java.net.*;
+
+/**
+ * The jabber packet listener that logs the packets to the packet logging
+ * service.
+ * @author Damian Minkov
+ */
+public class SmackPacketDebugger
+ implements PacketListener,
+ PacketInterceptor
+{
+ /**
+ * The current jabber connection.
+ */
+ private Connection connection = null;
+
+ /**
+ * Local address for the connection.
+ */
+ private byte[] localAddress = new byte[4];
+
+ /**
+ * The local port we are using for the connection.
+ * As currently we don't have information for this
+ * we use this static value.
+ */
+ private int localPort = 5222;
+
+ /**
+ * Remote address for the connection.
+ */
+ private byte[] remoteAddress = new byte[4];
+
+ /**
+ * Instance for the packet logging service.
+ */
+ private PacketLoggingService packetLogging = null;
+
+ /**
+ * Creates the SmackPacketDebugger instance.
+ */
+ public SmackPacketDebugger()
+ {
+ packetLogging = JabberActivator.getPacketLogging();
+ }
+
+ /**
+ * Sets current connection.
+ * @param connection the connection.
+ */
+ public void setConnection(Connection connection)
+ {
+ this.connection = connection;
+
+ try
+ {
+ remoteAddress = InetAddress.getByName(connection.getHost()).getAddress();
+
+ // to create empty ipv6 address default is ipv4
+ if(remoteAddress.length != localAddress.length)
+ localAddress = new byte[remoteAddress.length];
+ }
+ catch(Throwable t)
+ {
+ t.printStackTrace();
+ }
+ }
+
+ /**
+ * Process the packet that is about to be sent to the server. The intercepted
+ * packet can be modified by the interceptor.<p>
+ * <p/>
+ * Interceptors are invoked using the same thread that requested the packet
+ * to be sent, so it's very important that implementations of this method
+ * not block for any extended period of time.
+ *
+ * @param packet the packet to is going to be sent to the server.
+ */
+ public void interceptPacket(Packet packet)
+ {
+ try
+ {
+ if(packetLogging.isLoggingEnabled(
+ PacketLoggingService.ProtocolName.JABBER))
+ {
+ packetLogging.logPacket(
+ PacketLoggingService.ProtocolName.JABBER,
+ localAddress,
+ localPort,
+ remoteAddress,
+ connection.getPort(),
+ PacketLoggingService.TransportName.TCP,
+ true,
+ packet.toXML().getBytes("UTF-8")
+ );
+ }
+ }
+ catch(Throwable t)
+ {
+ t.printStackTrace();
+ }
+ }
+
+ /**
+ * Process the next packet sent to this packet listener.<p>
+ * <p/>
+ * A single thread is responsible for invoking all listeners, so
+ * it's very important that implementations of this method not block
+ * for any extended period of time.
+ *
+ * @param packet the packet to process.
+ */
+ public void processPacket(Packet packet)
+ {
+ try
+ {
+ if(packetLogging.isLoggingEnabled(
+ PacketLoggingService.ProtocolName.JABBER))
+ {
+ packetLogging.logPacket(
+ PacketLoggingService.ProtocolName.JABBER,
+ remoteAddress,
+ connection.getPort(),
+ localAddress,
+ localPort,
+ PacketLoggingService.TransportName.TCP,
+ false,
+ packet.toXML().getBytes("UTF-8")
+ );
+ }
+ }
+ catch(Throwable t)
+ {
+ t.printStackTrace();
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
index eb93379..4370577 100755
--- a/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
@@ -31,6 +31,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
+ net.java.sip.communicator.service.packetlogging,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.jabberconstants,
net.java.sip.communicator.service.protocol.event,
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipActivator.java b/src/net/java/sip/communicator/impl/protocol/sip/SipActivator.java
index f1c9ebb..fe3e749 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/SipActivator.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/SipActivator.java
@@ -8,6 +8,7 @@ package net.java.sip.communicator.impl.protocol.sip;
import java.util.*;
+import net.java.sip.communicator.service.packetlogging.*;
import org.osgi.framework.*;
import net.java.sip.communicator.service.configuration.*;
@@ -38,6 +39,7 @@ public class SipActivator
private static VersionService versionService = null;
private static UIService uiService = null;
private static HIDService hidService = null;
+ private static PacketLoggingService packetLoggingService = null;
/**
* The resource service. Used for checking for default values
@@ -249,6 +251,26 @@ public class SipActivator
}
/**
+ * Returns a reference to the <tt>PacketLoggingService</tt> implementation
+ * currently registered in the bundle context or null if no such
+ * implementation was found.
+ *
+ * @return a reference to a <tt>PacketLoggingService</tt> implementation
+ * currently registered in the bundle context or null if no such
+ * implementation was found.
+ */
+ public static PacketLoggingService getPacketLogging()
+ {
+ if (packetLoggingService == null)
+ {
+ packetLoggingService
+ = ServiceUtils.getService(
+ bundleContext, PacketLoggingService.class);
+ }
+ return packetLoggingService;
+ }
+
+ /**
* Called when this bundle is stopped so the Framework can perform the
* bundle-specific activities necessary to stop the bundle.
*
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipLogger.java b/src/net/java/sip/communicator/impl/protocol/sip/SipLogger.java
index 9511b3e..b61c406 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/SipLogger.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/SipLogger.java
@@ -9,8 +9,10 @@ package net.java.sip.communicator.impl.protocol.sip;
import gov.nist.core.*;
import gov.nist.javax.sip.message.*;
import javax.sip.*;
+import java.io.*;
import java.util.*;
+import net.java.sip.communicator.service.packetlogging.*;
import net.java.sip.communicator.util.*;
/**
@@ -129,10 +131,12 @@ public class SipLogger
*/
public boolean isLoggingEnabled(int logLevel)
{
+ // always enable trace messages so we can receive packets
+ // and log them to packet logging service
if (logLevel == TRACE_DEBUG)
return logger.isDebugEnabled();
if (logLevel == TRACE_MESSAGES) // same as TRACE_INFO
- return logger.isInfoEnabled();
+ return true;
if (logLevel == TRACE_NONE)
return false;
@@ -218,19 +222,7 @@ public class SipLogger
public void logMessage(SIPMessage message, String from, String to,
boolean sender, long time)
{
- if (!logger.isInfoEnabled())
- return;
-
- String msgHeader;
-
- if(sender)
- msgHeader = "JAIN-SIP sent a message from=\"";
- else
- msgHeader = "JAIN-SIP received a message from=\"";
-
- if (logger.isInfoEnabled())
- logger.info( msgHeader + from + "\" to=\"" + to + "\" at=" + time
- + ":\n" + message);
+ logMessage(message, from, to, null, sender, time);
}
/**
@@ -246,6 +238,8 @@ public class SipLogger
public void logMessage(SIPMessage message, String from, String to,
String status, boolean sender, long time)
{
+ logPacket(message, sender);
+
if (!logger.isInfoEnabled())
return;
@@ -262,6 +256,59 @@ public class SipLogger
}
/**
+ * Logs the specified message and details to the packet logging service
+ * if enabled.
+ *
+ * @param message the message to log
+ * @param sender determines whether we are the origin of this message.
+ */
+ public void logPacket(SIPMessage message, boolean sender)
+ {
+ try
+ {
+ if(!SipActivator.getPacketLogging().isLoggingEnabled(
+ PacketLoggingService.ProtocolName.SIP))
+ return;
+
+ boolean isTransportUDP = message.getTopmostVia().getTransport()
+ .equalsIgnoreCase("UDP");
+
+ byte[] srcAddr;
+ int srcPort;
+ byte[] dstAddr;
+ int dstPort;
+
+ if(sender)
+ {
+ srcAddr = message.getLocalAddress().getAddress();
+ srcPort = message.getLocalPort();
+ dstAddr = message.getRemoteAddress().getAddress();
+ dstPort = message.getRemotePort();
+ }
+ else
+ {
+ dstPort = message.getLocalPort();
+ dstAddr = message.getLocalAddress().getAddress();
+ srcAddr = message.getRemoteAddress().getAddress();
+ srcPort = message.getRemotePort();
+ }
+
+ byte[] msg = message.toString().getBytes("UTF-8");
+ SipActivator.getPacketLogging().logPacket(
+ PacketLoggingService.ProtocolName.SIP,
+ srcAddr, srcPort,
+ dstAddr, dstPort,
+ isTransportUDP ? PacketLoggingService.TransportName.UDP :
+ PacketLoggingService.TransportName.TCP,
+ sender, msg);
+ }
+ catch(UnsupportedEncodingException e)
+ {
+ logger.error("Cannot obtain message body", e);
+ }
+ }
+
+ /**
* Logs the specified message and details.
*
* @param message the message to log
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipStackSharing.java b/src/net/java/sip/communicator/impl/protocol/sip/SipStackSharing.java
index 95c0fc4..0636df2 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/SipStackSharing.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/SipStackSharing.java
@@ -1046,7 +1046,7 @@ public class SipStackSharing
* @return the SocketAddress that this handler would use when connecting to
* the specified destination address and port.
*
- * @throws IOException !!!!!!!!!!!!!!!!!!!!!!! FILL IN !!!!!!!!!!!!!!
+ * @throws IOException if we fail binding the local socket
*/
public java.net.InetSocketAddress getLocalAddressForDestination(
java.net.InetAddress dst,
@@ -1055,12 +1055,12 @@ public class SipStackSharing
String transport)
throws IOException
{
-// if(ListeningPoint.TLS.equalsIgnoreCase(transport))
-// return (java.net.InetSocketAddress)(((SipStackImpl)this.stack)
-// .getLocalTLSAddressForDestination(dst, dstPort, localAddress));
-// else
+ if(ListeningPoint.TLS.equalsIgnoreCase(transport))
return (java.net.InetSocketAddress)(((SipStackImpl)this.stack)
- .obtainLocalAddress(dst, dstPort, localAddress, 0));
+ .getLocalAddressForTlsDst(dst, dstPort, localAddress));
+ else
+ return (java.net.InetSocketAddress)(((SipStackImpl)this.stack)
+ .getLocalAddressForTcpDst(dst, dstPort, localAddress, 0));
}
/**
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
index 5bd8275..4aa9575 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
+++ b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
@@ -44,6 +44,7 @@ Import-Package: org.apache.log4j,
net.java.sip.communicator.service.neomedia.format,
net.java.sip.communicator.service.hid,
net.java.sip.communicator.service.netaddr,
+ net.java.sip.communicator.service.packetlogging,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.event,
net.java.sip.communicator.service.protocol.media,
diff --git a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java
index 3fa6b31..26a5986 100644
--- a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java
+++ b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java
@@ -595,7 +595,18 @@ public class GeneralConfigurationPanel
}
}
});
- localeConfigPanel.add(localesConfigComboBox);
+ localeConfigPanel.add(localesConfigComboBox, BorderLayout.CENTER);
+
+ String label = "* " +
+ Resources.getString(
+ "plugin.generalconfig.DEFAULT_LANGUAGE_RESTART_WARN");
+ JLabel warnLabel = new JLabel(label);
+ warnLabel.setToolTipText(label);
+ warnLabel.setForeground(Color.GRAY);
+ warnLabel.setFont(warnLabel.getFont().deriveFont(8));
+ warnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 8, 0));
+ warnLabel.setHorizontalAlignment(JLabel.RIGHT);
+ localeConfigPanel.add(warnLabel, BorderLayout.SOUTH);
return localeConfigPanel;
}
@@ -724,16 +735,6 @@ public class GeneralConfigurationPanel
}
});
- String label = "* " +
- Resources.getString(
- "plugin.generalconfig.DEFAULT_LANGUAGE_RESTART_WARN");
- JLabel warnLabel = new JLabel(label);
- warnLabel.setToolTipText(label);
- warnLabel.setForeground(Color.GRAY);
- warnLabel.setFont(warnLabel.getFont().deriveFont(8));
- warnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 8, 0));
- valuePanel.add(warnLabel);
-
return callConfigPanel;
}
diff --git a/src/net/java/sip/communicator/service/packetlogging/PacketLoggingService.java b/src/net/java/sip/communicator/service/packetlogging/PacketLoggingService.java
new file mode 100644
index 0000000..bdf4103
--- /dev/null
+++ b/src/net/java/sip/communicator/service/packetlogging/PacketLoggingService.java
@@ -0,0 +1,101 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.packetlogging;
+
+/**
+ * A Packet Logging Service to log packets that were send/received
+ * by protocols or any other network related services in various formats.
+ * Its for debugging purposes.
+ *
+ * @author Damian Minkov
+ */
+public interface PacketLoggingService
+{
+ /**
+ * These are the services that this packet logging service
+ * cab handle.
+ */
+ public enum ProtocolName
+ {
+ SIP,
+ JABBER,
+ RTP,
+ ICE4J
+ }
+
+ /**
+ * The transport names.
+ */
+ public enum TransportName
+ {
+ UDP,
+ TCP
+ }
+
+ /**
+ * Checks is logging globally enabled for the service.
+ * @return is logging enabled.
+ */
+ public boolean isLoggingEnabled();
+
+ /**
+ * Checks is logging globally enabled for and is it currently
+ * available fo the given protocol.
+ *.
+ * @param protocol that is checked.
+ * @return is logging enabled.
+ */
+ public boolean isLoggingEnabled(ProtocolName protocol);
+
+ /**
+ * Log a packet with all the required information.
+ *
+ * @param protocol the source protocol that logs this packet.
+ * @param sourceAddress the source address of the packet.
+ * @param sourcePort the source port of the packet.
+ * @param destinationAddress the destination address.
+ * @param destinationPort the destination port.
+ * @param transport the transport this packet uses.
+ * @param sender are we the sender of the packet or not.
+ * @param packetContent the packet content.
+ */
+ public void logPacket(
+ ProtocolName protocol,
+ byte[] sourceAddress,
+ int sourcePort,
+ byte[] destinationAddress,
+ int destinationPort,
+ TransportName transport,
+ boolean sender,
+ byte[] packetContent);
+
+ /**
+ * Log a packet with all the required information.
+ *
+ * @param protocol the source protocol that logs this packet.
+ * @param sourceAddress the source address of the packet.
+ * @param sourcePort the source port of the packet.
+ * @param destinationAddress the destination address.
+ * @param destinationPort the destination port.
+ * @param transport the transport this packet uses.
+ * @param sender are we the sender of the packet or not.
+ * @param packetContent the packet content.
+ * @param packetOffset the packet content offset.
+ * @param packetLength the packet content length.
+ */
+ public void logPacket(
+ ProtocolName protocol,
+ byte[] sourceAddress,
+ int sourcePort,
+ byte[] destinationAddress,
+ int destinationPort,
+ TransportName transport,
+ boolean sender,
+ byte[] packetContent,
+ int packetOffset,
+ int packetLength);
+}