diff options
author | eutarass | 2009-03-04 01:58:27 +0000 |
---|---|---|
committer | eutarass | 2009-03-04 01:58:27 +0000 |
commit | 88caf8c9c877b34d651b15e963d9f666c8027fdc (patch) | |
tree | 5eaf883a57061fa05844f8c674fff4ae844edd79 /plugins/org.eclipse.tm.tcf/src | |
parent | 72723936ad2c9e203c577fa9f2645c564bdef0d3 (diff) | |
download | org.eclipse.tcf-88caf8c9c877b34d651b15e963d9f666c8027fdc.tar.gz org.eclipse.tcf-88caf8c9c877b34d651b15e963d9f666c8027fdc.tar.xz org.eclipse.tcf-88caf8c9c877b34d651b15e963d9f666c8027fdc.zip |
Implemented better handling of unrecognized commands in TCF protocol: instead of terminating a connection, peers now can send special "command is not recognized" message.
Added TCF error code "command is not recognized".
Fixed agent build error on CygWin.
Diffstat (limited to 'plugins/org.eclipse.tm.tcf/src')
9 files changed, 162 insertions, 42 deletions
diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/DiagnosticsService.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/DiagnosticsService.java index e77eefadc..76f4dcc94 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/DiagnosticsService.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/DiagnosticsService.java @@ -51,7 +51,7 @@ public class DiagnosticsService implements IDiagnostics { channel.sendResult(token, JSON.toJSONSequence(new Object[]{ null, new String[0] })); } else { - throw new Exception("Illegal command: " + name); + channel.rejectCommand(token); } } } @@ -144,4 +144,14 @@ public class DiagnosticsService implements IDiagnostics { }); return token; } + + public IToken not_implemented_command(final DoneNotImplementedCommand done) { + final IToken token = new Token(); + Protocol.invokeLater(new Runnable() { + public void run() { + done.doneNotImplementedCommand(token, new Exception("Not implemented")); + } + }); + return token; + } } diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/LocatorService.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/LocatorService.java index 97093cb27..9dea9b0f9 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/LocatorService.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/LocatorService.java @@ -314,7 +314,7 @@ public class LocatorService implements ILocator { channel.sendResult(token, JSON.toJSONSequence(new Object[]{ null, arr })); } else { - channel.terminate(new Exception("Illegal command: " + name)); + channel.rejectCommand(token); } } catch (Throwable x) { diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/DiagnosticsProxy.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/DiagnosticsProxy.java index 8fbb7b927..e3a5dd8cb 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/DiagnosticsProxy.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/DiagnosticsProxy.java @@ -196,6 +196,15 @@ public class DiagnosticsProxy implements IDiagnostics { }.token; } + public IToken not_implemented_command(final DoneNotImplementedCommand done) { + return new Command(channel, this, "not implemented command", null) { + @Override + public void done(Exception error, Object[] args) { + done.doneNotImplementedCommand(token, error); + } + }.token; + } + @SuppressWarnings("unchecked") private String[] toStringArray(Object o) { if (o == null) return null; diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/AbstractChannel.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/AbstractChannel.java index 3070c8896..1c5d575ba 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/AbstractChannel.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/AbstractChannel.java @@ -23,6 +23,7 @@ import org.eclipse.tm.internal.tcf.core.TransportManager; import org.eclipse.tm.internal.tcf.services.local.LocatorService; import org.eclipse.tm.internal.tcf.services.remote.GenericProxy; import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IErrorReport; import org.eclipse.tm.tcf.protocol.IPeer; import org.eclipse.tm.tcf.protocol.IService; import org.eclipse.tm.tcf.protocol.IToken; @@ -159,6 +160,7 @@ public abstract class AbstractChannel implements IChannel { inp_thread = new Thread() { + final byte[] empty_byte_array = new byte[0]; byte[] buf = new byte[1024]; byte[] eos; @@ -170,8 +172,11 @@ public abstract class AbstractChannel implements IChannel { int len = 0; for (;;) { int n = read(); - if (n == end) break; - if (n < 0) throw new IOException("Communication channel is closed by remote peer"); + if (n <= 0) { + if (n == end) break; + if (n == EOM) throw new IOException("Unexpected end of message"); + if (n < 0) throw new IOException("Communication channel is closed by remote peer"); + } if (len >= buf.length) { byte[] tmp = new byte[buf.length * 2]; System.arraycopy(buf, 0, tmp, 0, len); @@ -179,13 +184,29 @@ public abstract class AbstractChannel implements IChannel { } buf[len++] = (byte)n; } + if (len == 0) return empty_byte_array; byte[] res = new byte[len]; System.arraycopy(buf, 0, res, 0, len); return res; } private String readString() throws IOException { - return new String(readBytes(0), "UTF8"); + int len = 0; + for (;;) { + int n = read(); + if (n <= 0) { + if (n == 0) break; + if (n == EOM) throw new IOException("Unexpected end of message"); + if (n < 0) throw new IOException("Communication channel is closed by remote peer"); + } + if (len >= buf.length) { + byte[] tmp = new byte[buf.length * 2]; + System.arraycopy(buf, 0, tmp, 0, len); + buf = tmp; + } + buf[len++] = (byte)n; + } + return new String(buf, 0, len, "UTF8"); } public void run() { @@ -206,7 +227,9 @@ public abstract class AbstractChannel implements IChannel { msg.name = readString(); msg.data = readBytes(EOM); break; + case 'P': case 'R': + case 'N': msg.token = new Token(readBytes(0)); msg.data = readBytes(EOM); break; @@ -711,6 +734,14 @@ public abstract class AbstractChannel implements IChannel { addToOutQueue(msg); } + public void rejectCommand(IToken token) { + assert Protocol.isDispatchThread(); + if (state != STATE_OPEN) throw new Error("Channel is closed"); + Message msg = new Message('N'); + msg.token = (Token)token; + addToOutQueue(msg); + } + public void sendEvent(IService service, String name, byte[] args) { assert Protocol.isDispatchThread(); if (!(state == STATE_OPEN || state == STATE_OPENNING && service instanceof ILocator)) { @@ -756,7 +787,7 @@ public abstract class AbstractChannel implements IChannel { cmds.command(token, msg.name, msg.data); } else { - throw new IOException("Unknown command " + msg.service + "." + msg.name); + rejectCommand(token); } } break; @@ -770,6 +801,11 @@ public abstract class AbstractChannel implements IChannel { token.getListener().result(token, msg.data); sendCongestionLevel(); break; + case 'N': + token = out_tokens.remove(msg.token.getID()).token; + token.getListener().terminated(token, new ErrorReport( + "Command is not recognized", IErrorReport.TCF_ERROR_INV_COMMAND)); + break; case 'E': boolean hello = msg.service.equals(ILocator.NAME) && msg.name.equals("Hello"); if (hello) { diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/Command.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/Command.java index 593f1a036..7748e15c7 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/Command.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/Command.java @@ -68,39 +68,6 @@ public abstract class Command implements IChannel.ICommandListener { private static final SimpleDateFormat timestamp_format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - private class ErrorReport extends Exception implements IErrorReport { - - private static final long serialVersionUID = 3687543884858739977L; - private final Map<String,Object> attrs; - - ErrorReport(String msg, Map<String,Object> attrs) { - super(msg); - this.attrs = attrs; - Object caused_by = attrs.get(IErrorReport.ERROR_CAUSED_BY); - if (caused_by != null) initCause(toError(caused_by, false)); - } - - public int getErrorCode() { - Number n = (Number)attrs.get(ERROR_CODE); - if (n == null) return 0; - return n.intValue(); - } - - public int getAltCode() { - Number n = (Number)attrs.get(ERROR_ALT_CODE); - if (n == null) return 0; - return n.intValue(); - } - - public String getAltOrg() { - return (String)attrs.get(ERROR_ALT_ORG); - } - - public Map<String, Object> getAttributes() { - return attrs; - } - } - public Command(IChannel channel, IService service, String command, Object[] args) { this.service = service; this.command = command; @@ -196,7 +163,7 @@ public abstract class Command implements IChannel.ICommandListener { return "Invalid error report format"; } - private static void appendErrorProps(StringBuffer bf, Map<String,Object> map) { + static void appendErrorProps(StringBuffer bf, Map<String,Object> map) { Number time = (Number)map.get(IErrorReport.ERROR_TIME); Number code = (Number)map.get(IErrorReport.ERROR_CODE); String service = (String)map.get(IErrorReport.ERROR_SERVICE); diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/ErrorReport.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/ErrorReport.java new file mode 100644 index 000000000..56dbca80e --- /dev/null +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/ErrorReport.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2007-2009 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.tcf.core; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.tm.tcf.protocol.IErrorReport; + +class ErrorReport extends Exception implements IErrorReport { + + private static final long serialVersionUID = 3687543884858739977L; + private final Map<String,Object> attrs; + + @SuppressWarnings("unchecked") + ErrorReport(String msg, Map<String,Object> attrs) { + super(msg); + this.attrs = attrs; + Object caused_by = attrs.get(IErrorReport.ERROR_CAUSED_BY); + if (caused_by != null) { + Map<String,Object> map = (Map<String,Object>)caused_by; + StringBuffer bf = new StringBuffer(); + bf.append("TCF error report:"); + bf.append('\n'); + Command.appendErrorProps(bf, map); + initCause(new ErrorReport(bf.toString(), map)); + } + } + + ErrorReport(String msg, int code) { + super(msg); + attrs = new HashMap<String,Object>(); + attrs.put(ERROR_CODE, code); + attrs.put(ERROR_TIME, System.currentTimeMillis()); + attrs.put(ERROR_FORMAT, msg); + attrs.put(ERROR_SEVERITY, SEVERITY_ERROR); + } + + public int getErrorCode() { + Number n = (Number)attrs.get(ERROR_CODE); + if (n == null) return 0; + return n.intValue(); + } + + public int getAltCode() { + Number n = (Number)attrs.get(ERROR_ALT_CODE); + if (n == null) return 0; + return n.intValue(); + } + + public String getAltOrg() { + return (String)attrs.get(ERROR_ALT_ORG); + } + + public Map<String, Object> getAttributes() { + return attrs; + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IChannel.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IChannel.java index 92168ec43..23f6e59b7 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IChannel.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IChannel.java @@ -73,7 +73,8 @@ public interface IChannel { void result(IToken token, byte[] data); /** - * Called when communication channel was closed while command was waiting for result. + * Called when command is terminated because communication channel was closed or + * command is not recognized by remote peer. * @param token - command handle * @param error - exception that forced the channel to close */ @@ -91,6 +92,18 @@ public interface IChannel { void sendResult(IToken token, byte[] results); /** + * Reject a command by sending "N" result message to remote peer. + * Clients should reject commands that they don't recognize. + * Messages can be queued locally before + * transmission. Sending messages too fast can fill up communication channel + * buffers. Calling thread will be blocked until enough buffer space is + * freed up by transmitting pending messages. + * @param token - command handle + * @param results - result message arguments encoded into array of bytes + */ + void rejectCommand(IToken token); + + /** * Get current level of out-bound traffic congestion. * * @return integer value in range –100..100, where –100 means no pending diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IErrorReport.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IErrorReport.java index fe6eedfcc..86b85a1f9 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IErrorReport.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IErrorReport.java @@ -86,7 +86,8 @@ public interface IErrorReport { TCF_ERROR_INV_DWARF = 21, TCF_ERROR_SYM_NOT_FOUND = 22, TCF_ERROR_UNSUPPORTED = 23, - TCF_ERROR_INV_DATA_TYPE = 24; + TCF_ERROR_INV_DATA_TYPE = 24, + TCF_ERROR_INV_COMMAND = 25; public int getErrorCode(); diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IDiagnostics.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IDiagnostics.java index 04f433519..52694f303 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IDiagnostics.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IDiagnostics.java @@ -224,4 +224,22 @@ public interface IDiagnostics extends IService { */ void doneDisposeTestStream(IToken token, Throwable error); } + + /** + * Send a command that is not implemented by peer. + * Used to test handling of 'N' messages by communication channel. + * @param done - command result call back object. + * @return - pending command handle. + */ + IToken not_implemented_command(DoneNotImplementedCommand done); + + interface DoneNotImplementedCommand { + + /** + * Called when 'not_implemented_command' command is done. + * @param token - command handle. + * @param error - error object. + */ + void doneNotImplementedCommand(IToken token, Throwable error); + } } |