如何从 Eclipse 插件提供 Flash 策略文件?

Posted

技术标签:

【中文标题】如何从 Eclipse 插件提供 Flash 策略文件?【英文标题】:How do I serve Flash policy files from an Eclipse plugin? 【发布时间】:2012-11-26 05:02:22 【问题描述】:

我有一个 Eclipse 插件,它需要为在本地机器上运行的 Flash 应用程序打开一对套接字。 Flash 需要一个策略文件(XML 块)来授予访问相关端口的权限。 Flash 更喜欢通过端口 843 获取此策略文件,Java 将端口

/**
  * Connecting to some port to communicate with the debugger. We initiate the
  * connection because Flex doesn't allow us to listen to any ports.
  */
private function initSockets():void

    requestSocket = new Socket();
    requestSocket.addEventListener(Event.CONNECT, requestConnected);
    requestSocket.addEventListener(Event.CLOSE, closed);
    requestSocket.addEventListener(ProgressEvent.SOCKET_DATA, processRequestData);
    requestSocket.addEventListener(IOErrorEvent.IO_ERROR, ioError);
    requestSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError);
    requestSocket.connect("localhost", SCConstants.DEBUG_LESSON_REQUEST_PORT);

    eventSocket = new Socket();
    eventSocket.addEventListener(Event.CONNECT, eventConnected);
    eventSocket.addEventListener(Event.CLOSE, closed);
    eventSocket.addEventListener(ProgressEvent.SOCKET_DATA, processEventData);
    eventSocket.addEventListener(IOErrorEvent.IO_ERROR, ioError);
    eventSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError);
    eventSocket.connect("localhost", SCConstants.DEBUG_LESSON_EVENT_PORT);

在 Eclipse 插件方面,我继承了一些大部分时间都可以在 OS X 上运行,但有时在 Windows 上会失败的代码。在 Wi-Fi 而不是有线以太网上运行也往往会失败,尽管我不知道为什么这很重要。

public Boolean connect() throws DebugException 
    try 
        try 
            // connection code
            fRequestServerSocket = new ServerSocket(requestPort);
            fRequestServerSocket.setSoTimeout(ACCEPT_TIMEOUT);
            fEventServerSocket = new ServerSocket(eventPort);
            fEventServerSocket.setSoTimeout(ACCEPT_TIMEOUT);

            TWBLogger.logInfo("Open socket request server:" + fRequestServerSocket);
            TWBLogger.logInfo("Open socket event server:" + fEventServerSocket);

            String policy = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<cross-domain-policy>\n" +
                "<allow-access-from domain=\"*\" to-ports=\"5000,5001\" secure=\"false\" />\n" +
                "</cross-domain-policy>\0";

            // Because of the Flash security policy the first thing
            // that will accept on the socket will be the Flash Player 
            // trying to verify us. The Flash player will request security 
            // policy file with the following string: <policy-file-request/>\0
            // We will serve back the above policy file and then close the socket
            // The next thing to accept is our process in the VM.
            fRequestSocket = fRequestServerSocket.accept();

            fRequestWriter = new PrintWriter(fRequestSocket.getOutputStream());
            fRequestReader = new BufferedReader(new InputStreamReader(fRequestSocket.getInputStream()));

            // Wait some time before giving flash the policy file. Otherwise they don't get it. ;(
            // 3 is too much ... ;(
            Thread.sleep(100);

            fRequestWriter.print(policy);
            fRequestWriter.flush();
            fRequestSocket.close();

            // this should be the real connection
            fRequestSocket = fRequestServerSocket.accept();
            TWBLogger.logInfo("Open socket request:" + fRequestSocket);

            fRequestWriter = new PrintWriter(fRequestSocket.getOutputStream());
            fRequestReader = new BufferedReader(new InputStreamReader(fRequestSocket.getInputStream()));

            // the same situation for the EventSocket 
            fEventSocket = fEventServerSocket.accept();
            fEventReader = new BufferedReader(new InputStreamReader(fEventSocket.getInputStream()));
            TWBLogger.logInfo("Open socket event:" + fEventSocket);
         catch (SocketTimeoutException e) 
            TWBLogger.logWaring("Connection to the Client Timed out.");
            cleanSockets();
            return false;
            requestFailed("Connection to the VM timed out. Please close any other running lessons that you debug and try again", e);
         catch (SocketSecurityException e) 
            requestFailed("Security error occured when connecting to the VM", e);
         catch (Exception e) 
            if (!fTerminated)
            requestFailed("Error occured when connecting to the VM. Please close any other running lessons that you debug.", e);
         
     catch (DebugException e) 
        // close the sockets so that we can debug another application
        cleanSockets();
        throw e;
    

    // our VM is single threaded
    fThread = new TWBThread(this);
    fThreads = new IThread[] fThread;

    // start listening for events from the VM
    fEventDispatch = new EventDispatchJob();
    fEventDispatch.schedule();

    // start listening for breakpoints
    IBreakpointManager breakpointManager = getBreakpointManager();
    breakpointManager.addBreakpointListener(this);

    breakpointManager.addBreakpointManagerListener(this);
    return true;

这段代码看起来不对。它不等待来自 Flash 的消息,而只是将策略响应塞入端口。正如我所说,它大部分时间都可以工作,但有时会失败并且似乎不符合 Adob​​e 的文档。

我尝试在每个端口上侦听请求数据包并发送特定于端口的响应。我在环回接口 (Mac OS X) 上使用 WireShark 观察了套接字流量。我看到收到了策略请求并发送了响应,但 Flash 仍然在两个端口上都给了我安全沙盒违规。

我也尝试在上面显示的 initSockets 开头添加这一行:

Security.loadPolicyFile("xmlsocket://localhost:5002");

然后我在插件中添加了代码来监听端口 5002 并发送以下主策略文件内容:

private final static String FLASH_POLICY_RESPONSE = 
    "<?xml version=\"1.0\"?>\n" +
    "<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\n" +
    "<cross-domain-policy>\n" +
    "<site-control permitted-cross-domain-policies=\"master-only\"/>\n" +
    "<allow-access-from domain=\"*\" to-ports=\"5000,5001\"/>\n" +
    "</cross-domain-policy>\0";         

我再次看到请求进来和响应出去,但 Flash 似乎没有响应它。我没有收到 Security Sandbox Violation 错误,但端口上也没有流量。

谁能告诉我在 Java 和 Flash 之间打开套接字的正确方法?

【问题讨论】:

【参考方案1】:

我找到了解决方案。我很早就犯了一个错误,并使用BufferedReader.readLine 来阅读策略请求。这是不合适的,因为策略请求是空终止的,而不是新行终止的。这很令人困惑,因为它会在底层流关闭时返回。因此我收到了请求并发送了响应,但是在 ActionScript 代码已经确定请求失败之后才发送响应。

在 Java 端,我使用以下代码在端口上建立通信:

// Create server sockets.
fRequestServerSocket = new ServerSocket(REQUEST_PORT);
fRequestServerSocket.setSoTimeout(ACCEPT_TIMEOUT);
TWBLogger.logInfo("Open socket request server:" + fRequestServerSocket);

fEventServerSocket = new ServerSocket(EVENT_PORT);
fEventServerSocket.setSoTimeout(ACCEPT_TIMEOUT);
TWBLogger.logInfo("Open socket event server:" + fEventServerSocket);

// Serve up the Flash policy file.
serveFlashPolicy();

// Connect request socket.
fRequestSocket = fRequestServerSocket.accept();
TWBLogger.logInfo("Open socket request:" + fRequestSocket);

fRequestWriter = new PrintWriter(fRequestSocket.getOutputStream());
fRequestReader = new BufferedReader(new InputStreamReader(fRequestSocket.getInputStream()));

// Connect event socket.
fEventSocket = fEventServerSocket.accept();
TWBLogger.logInfo("Open socket event:" + fEventSocket);

fEventReader = new BufferedReader(new InputStreamReader(fEventSocket.getInputStream()));                

提供策略文件的处理如下:

private void serveFlashPolicy() 
    ServerSocket serverSocket = null;
    Socket socket = null;
    TWBLogger.logInfo("Waiting for flash policy request on port " + FLASH_POLICY_PORT);
    try 
        serverSocket = new ServerSocket(FLASH_POLICY_PORT);
        serverSocket.setSoTimeout(ACCEPT_TIMEOUT);

        socket = serverSocket.accept();

        PrintWriter writer = new PrintWriter(socket.getOutputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        StringBuilder request = new StringBuilder();
        int c;
        while (0 < (c = reader.read())) 
            request.append((char) c);
        

        String policyRequest = request.toString();
        if (policyRequest.startsWith(FLASH_POLICY_REQUEST)) 
            writer.print(FLASH_POLICY_RESPONSE);
            writer.print("\0");
            writer.flush();
        
     catch (IOException e) 
        TWBLogger.logWaring("IOException on port " + FLASH_POLICY_PORT + ": " + e.toString());
        e.printStackTrace();
     finally 
        if (null != socket) 
            try 
                socket.close();
             catch (Exception e) 
                // Ignore
            
        

        if (null != serverSocket) 
            try 
                serverSocket.close();
             catch (Exception e) 
                // Ignore
            
        
    

    TWBLogger.logInfo("Flash policy complete on port " + FLASH_POLICY_PORT);

Flash 政策响应如下所示:

private final static String FLASH_POLICY_RESPONSE = 
    "<?xml version=\"1.0\"?>\n" +
    "<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\n" +
    "<cross-domain-policy>\n" +
    "<allow-access-from domain=\"*\" to-ports=\"5000,5001\"/>\n" +
    "</cross-domain-policy>";           

我之前发送的site-control 标签只允许在从端口 843 提供的主策略文件中。

【讨论】:

以上是关于如何从 Eclipse 插件提供 Flash 策略文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Eclipse下安装SVN插件

如何使用Eclipse插件

如何安装WindowsBuilder插件

如何安装WindowsBuilder插件

Eclise怎么安装JavaEE插件

如何从插件访问 Eclipse Java 调试器?