Как я могу обслуживать файлы политик Flash из подключаемого модуля Eclipse?

У меня есть плагин Eclipse, которому нужно открыть пару сокетов для флэш-приложения, запущенного на локальном компьютере. Flash требует файл политики (большой двоичный объект XML), дающий разрешения на доступ к рассматриваемым портам. Flash предпочитает получать этот файл политики через порт 843, Java рассматривает порты ‹1024 как привилегированные порты, а Mac OS X и Linux аналогичным образом ограничивают доступ к портам‹ 1024. Я не хочу запускать свой плагин Eclipse с правами root, поэтому обслуживаю файл политики на порту 843 не подходит. Согласно документации Adobe, если Flash не может получить файл политики через порт 843, он возвращается к запросу файла политики через порт, к которому пытается подключиться. Код ActionScript выглядит так:

/**
  * 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, а не по проводному Ethernet, также имеет тенденцию к сбою, хотя я понятия не имею, почему это должно иметь значение.

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";         

Я снова увидел, что запрос пришел и ответ ушел, но Флэш, похоже, не ответил на него. Я не получал ошибок нарушения безопасной песочницы, но также не было трафика через порты.

Может ли кто-нибудь просветить меня о правильном подходе к открытию сокетов между Java и Flash?


person rich    schedule 07.12.2012    source источник


Ответы (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.

person rich    schedule 13.12.2012