Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2009-03-04 01:58:27 +0000
committereutarass2009-03-04 01:58:27 +0000
commit88caf8c9c877b34d651b15e963d9f666c8027fdc (patch)
tree5eaf883a57061fa05844f8c674fff4ae844edd79 /plugins/org.eclipse.tm.tcf/src
parent72723936ad2c9e203c577fa9f2645c564bdef0d3 (diff)
downloadorg.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')
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/DiagnosticsService.java12
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/LocatorService.java2
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/DiagnosticsProxy.java9
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/AbstractChannel.java44
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/Command.java35
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/ErrorReport.java66
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IChannel.java15
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IErrorReport.java3
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IDiagnostics.java18
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);
+ }
}

Back to the top