2012-12-07 46 views
0

我有需要打開一個組插座到本地機器上運行的Flash應用程序的Eclipse插件。 Flash需要一個策略文件(XML blob)來授予訪問相關端口的權限。閃存更喜歡得到這個策略文件通過端口843,爪哇把港口< 1024個作爲特權端口和Mac OS X和Linux類似的限制訪問,我不希望運行我的root權限Eclipse插件端口< 1024,因此服務起來端口843上的策略文件不是一個選項。據Adobe稱,文檔,如果Flash不能得到端口843的策略文件,它回落到請求的端口上的政策文件,它嘗試連接。 ActionScript代碼看起來是這樣的:如何從Eclipse插件提供Flash策略文件?

/** 
    * 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); 
} 

在我繼承了一些代碼,作品在OS X上的時間大部分Eclipse插件的一面,但有時會失敗在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的消息,而只是將策略響應阻塞到端口中。正如我所說,它大部分時間都在運行,但它有時會失敗,似乎不符合Adobe的文檔。

我嘗試偵聽每個端口上請求數據包和發送端口特定響應。我使用WireShark在環回接口(Mac OS X)上觀察套接字通信量。我看到了策略請求和收到的響應,但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似乎並未對此作出迴應。我沒有收到安全沙箱違例錯誤,但也沒有通過端口的流量。

任何人都可以啓發我在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); 
} 

閃存政策迴應的樣子這樣的:

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標籤我以前有b只有在從端口843提供的主策略文件中才允許發送。