| /******************************************************************************* |
| * Copyright (c) 2000, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdi.internal.spy; |
| |
| |
| import java.io.BufferedInputStream; |
| import java.io.BufferedOutputStream; |
| import java.io.DataInputStream; |
| import java.io.DataOutputStream; |
| import java.io.EOFException; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.InetAddress; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| import java.net.SocketException; |
| import com.ibm.icu.text.MessageFormat; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| * This class can be used to spy all JDWP packets. It should be configured 'in between' the debugger |
| * application and the VM (or J9 debug proxy). |
| * Its parameters are: |
| * 1) The port number to which the debugger application connects; |
| * 2) The name of the host on which the VM or proxy waits for a JDWP connection; |
| * 3) The port number on which the VM or proxy waits for a JDWP connection; |
| * 4) The file where the trace is written to. |
| * |
| * Note that if this program is used for tracing JDWP activity of Leapfrog, the |
| * 'debug remote program' option must be used, and the J9 proxy must first be started up by hand |
| * on the port to which Leapfrog will connect. |
| * The J9 proxy that is started up by Leapfrog is not used and will return immediately. |
| */ |
| public class TcpipSpy extends Thread { |
| |
| private static final byte[] handshakeBytes= "JDWP-Handshake".getBytes(); //$NON-NLS-1$ |
| private boolean fVMtoDebugger; |
| private DataInputStream fDataIn; |
| private DataOutputStream fDataOut; |
| |
| private static VerbosePacketStream out= new VerbosePacketStream(System.out); |
| private static Map fPackets= new HashMap(); |
| |
| private static int fFieldIDSize; |
| private static int fMethodIDSize; |
| private static int fObjectIDSize; |
| private static int fReferenceTypeIDSize; |
| private static int fFrameIDSize; |
| private static boolean fHasSizes; |
| |
| public TcpipSpy(boolean VMtoDebugger, InputStream in, OutputStream out) { |
| fVMtoDebugger= VMtoDebugger; |
| fDataIn= new DataInputStream(new BufferedInputStream(in)); |
| fDataOut= new DataOutputStream(new BufferedOutputStream(out)); |
| fHasSizes= false; |
| } |
| |
| public static void main(String[] args) { |
| int inPort= 0; |
| String serverHost= null; |
| int outPort= 0; |
| String outputFile= null; |
| try { |
| inPort= Integer.parseInt(args[0]); |
| serverHost= args[1]; |
| outPort= Integer.parseInt(args[2]); |
| if (args.length > 3) { |
| outputFile= args[3]; |
| } |
| } catch (Exception e) { |
| out.println(TcpIpSpyMessages.TcpipSpy_usage__TcpipSpy__client_port___server_host___server_port____output_file___1); |
| System.exit(-1); |
| } |
| |
| if (outputFile != null) { |
| File file= new File(outputFile); |
| out.println(MessageFormat.format(TcpIpSpyMessages.TcpipSpy_Writing_output_to__0__2, new String[] {file.getAbsolutePath()})); |
| try { |
| out= new VerbosePacketStream(new BufferedOutputStream(new FileOutputStream(file))); |
| } catch (FileNotFoundException e) { |
| out.println(MessageFormat.format(TcpIpSpyMessages.TcpipSpy_Could_not_open__0____Using_stdout_instead_3, new String[] {file.getAbsolutePath()})); |
| } |
| } |
| out.println(); |
| try { |
| ServerSocket serverSock= new ServerSocket(inPort); |
| Socket inSock= serverSock.accept(); |
| Socket outSock= new Socket(InetAddress.getByName(serverHost), outPort); |
| new TcpipSpy(false, inSock.getInputStream(), outSock.getOutputStream()).start(); |
| new TcpipSpy(true, outSock.getInputStream(), inSock.getOutputStream()).start(); |
| } catch (Exception e) { |
| out.println(e); |
| } |
| } |
| |
| public void run() { |
| try { |
| // Skip handshake. |
| int handshakeLength; |
| |
| handshakeLength= handshakeBytes.length; |
| while (handshakeLength-- > 0) { |
| int b= fDataIn.read(); |
| fDataOut.write(b); |
| } |
| fDataOut.flush(); |
| |
| // Print all packages. |
| while (true) { |
| JdwpPacket p= JdwpPacket.read(fDataIn); |
| // we need to store conversation only for command send by the debugger, |
| // as there is no answer from the debugger to VM commands. |
| if (!(fVMtoDebugger && (p.getFlags() & JdwpPacket.FLAG_REPLY_PACKET) == 0)) { |
| store(p); |
| } |
| out.print(p, fVMtoDebugger); |
| out.flush(); |
| p.write(fDataOut); |
| fDataOut.flush(); |
| } |
| } catch (EOFException e) { |
| } catch (SocketException e) { |
| } catch (IOException e) { |
| out.println(MessageFormat.format(TcpIpSpyMessages.TcpipSpy_Caught_exception___0__5, new String[] {e.toString()})); |
| e.printStackTrace(out); |
| } finally { |
| try { |
| fDataIn.close(); |
| fDataOut.close(); |
| } catch (IOException e) { |
| } |
| out.flush(); |
| } |
| } |
| |
| public static JdwpCommandPacket getCommand(int id) { |
| JdwpConversation conversation= (JdwpConversation) fPackets.get(new Integer(id)); |
| if (conversation != null) |
| return conversation.getCommand(); |
| return null; |
| } |
| |
| protected static void store(JdwpPacket packet) { |
| int id= packet.getId(); |
| JdwpConversation conversation= (JdwpConversation) fPackets.get(new Integer(id)); |
| if (conversation == null) { |
| conversation= new JdwpConversation(id); |
| fPackets.put(new Integer(id), conversation); |
| } |
| |
| if ((packet.getFlags() & JdwpPacket.FLAG_REPLY_PACKET) != 0) { |
| conversation.setReply((JdwpReplyPacket) packet); |
| } else { |
| conversation.setCommand((JdwpCommandPacket) packet); |
| } |
| } |
| |
| public static int getCommand(JdwpPacket packet) throws UnableToParseDataException { |
| JdwpCommandPacket command= null; |
| if (packet instanceof JdwpCommandPacket) { |
| command= (JdwpCommandPacket) packet; |
| } else { |
| command= getCommand(packet.getId()); |
| if (command == null) { |
| throw new UnableToParseDataException(TcpIpSpyMessages.TcpIpSpy_This_packet_is_marked_as_reply__but_there_is_no_command_with_the_same_id__1, null); |
| } |
| } |
| return command.getCommand(); |
| } |
| |
| public static boolean hasSizes() { |
| return fHasSizes; |
| } |
| |
| public static void setHasSizes(boolean value) { |
| fHasSizes= value; |
| } |
| |
| public static void setFieldIDSize(int fieldIDSize) { |
| fFieldIDSize= fieldIDSize; |
| } |
| |
| public static int getFieldIDSize() { |
| return fFieldIDSize; |
| } |
| |
| public static void setMethodIDSize(int methodIDSize) { |
| fMethodIDSize= methodIDSize; |
| } |
| |
| public static int getMethodIDSize() { |
| return fMethodIDSize; |
| } |
| |
| public static void setObjectIDSize(int objectIDSize) { |
| fObjectIDSize= objectIDSize; |
| } |
| |
| public static int getObjectIDSize() { |
| return fObjectIDSize; |
| } |
| |
| public static void setReferenceTypeIDSize(int referenceTypeIDSize) { |
| fReferenceTypeIDSize= referenceTypeIDSize; |
| } |
| |
| public static int getReferenceTypeIDSize() { |
| return fReferenceTypeIDSize; |
| } |
| |
| public static void setFrameIDSize(int frameIDSize) { |
| fFrameIDSize= frameIDSize; |
| } |
| |
| public static int getFrameIDSize() { |
| return fFrameIDSize; |
| } |
| } |