// ---------------------------------------------------------------------------
// jWebSocket - FlashBridge Plug-In
// Copyright (c) 2010 Innotrade GmbH (http://jWebSocket.org)
// ---------------------------------------------------------------------------
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
// for more details.
// You should have received a copy of the GNU Lesser General Public License along
// with this program; if not, see <http://www.gnu.org/licenses/lgpl.html>.
// ---------------------------------------------------------------------------
package org.jwebsocket.plugins.flashbridge;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import org.apache.log4j.Logger;
import org.jwebsocket.api.PluginConfiguration;
import org.jwebsocket.api.WebSocketEngine;
import org.jwebsocket.logging.Logging;
import org.jwebsocket.plugins.TokenPlugIn;
/**
* This plug-in processes the policy-file-request from the browser side flash
* plug-in. This makes jWebSocket cross-browser-compatible.
*
* @author aschulze
*/
public class FlashBridgePlugIn extends TokenPlugIn {
private static Logger mLog = Logging.getLogger(FlashBridgePlugIn.class);
private ServerSocket mServerSocket = null;
private int mListenerPort = 843;
private boolean mIsRunning = false;
private int mEngineInstanceCount = 0;
private BridgeProcess mBridgeProcess = null;
private Thread mBridgeThread = null;
public FlashBridgePlugIn() {
this(null);
}
public FlashBridgePlugIn(PluginConfiguration configuration) {
super(configuration);
if (mLog.isDebugEnabled()) {
mLog.debug("Starting FlashBridge...");
}
try {
mServerSocket = new ServerSocket(mListenerPort);
mBridgeProcess = new BridgeProcess(this);
mBridgeThread = new Thread(mBridgeProcess);
mBridgeThread.start();
if (mLog.isInfoEnabled()) {
mLog.info("FlashBridge started.");
}
} catch (IOException ex) {
mLog.error("FlashBridge could not be started: " + ex.getMessage());
}
}
private class BridgeProcess implements Runnable {
private final FlashBridgePlugIn mPlugIn;
/**
* creates the server socket bridgeProcess for new incoming socket
* connections.
*
* @param aPlugIn
*/
public BridgeProcess(FlashBridgePlugIn aPlugIn) {
this.mPlugIn = aPlugIn;
}
@Override
public void run() {
if (mLog.isDebugEnabled()) {
mLog.debug("Starting FlashBridge process...");
}
mIsRunning = true;
while (mIsRunning) {
try {
// accept is blocking so here is no need
// to put any sleeps into the loop
if (mLog.isDebugEnabled()) {
mLog.debug("Waiting on flash policy-file-request on port " + mServerSocket.getLocalPort() + "...");
}
Socket clientSocket = mServerSocket.accept();
if (mLog.isDebugEnabled()) {
mLog.debug("Client connected...");
}
try {
// clientSocket.setSoTimeout(TIMEOUT);
InputStream lIS = clientSocket.getInputStream();
OutputStream lOS = clientSocket.getOutputStream();
byte[] ba = new byte[1024];
String lLine = "";
boolean lFoundPolicyFileRequest = false;
int lLen = 0;
while (lLen >= 0 && !lFoundPolicyFileRequest) {
lLen = lIS.read(ba);
if (lLen > 0) {
lLine += new String(ba, 0, lLen, "US-ASCII");
}
if (mLog.isDebugEnabled()) {
mLog.debug("Received " + lLine + "...");
}
lFoundPolicyFileRequest = lLine.indexOf("policy-file-request") >= 0; // "<policy-file-request/>"
}
if (lFoundPolicyFileRequest) {
if (mLog.isDebugEnabled()) {
mLog.debug("Answering on flash policy-file-request (" + lLine + ")...");
}
lOS.write(("<cross-domain-policy>" + "<allow-access-from domain=\"*\" to-ports=\"*\" />" + "</cross-domain-policy>").getBytes());
lOS.flush();
} else {
mLog.warn("Received invalid policy-file-request (" + lLine + ")...");
}
} catch (UnsupportedEncodingException ex) {
mLog.error("(encoding) " + ex.getClass().getSimpleName() + ": " + ex.getMessage());
} catch (IOException ex) {
mLog.error("(io) " + ex.getClass().getSimpleName() + ": " + ex.getMessage());
} catch (Exception ex) {
mLog.error("(other) " + ex.getClass().getSimpleName() + ": " + ex.getMessage());
}
clientSocket.close();
if (mLog.isDebugEnabled()) {
mLog.debug("Client disconnected...");
}
} catch (Exception ex) {
mIsRunning = false;
mLog.error("Socket state: " + ex.getMessage());
}
}
if (mLog.isDebugEnabled()) {
mLog.debug("FlashBridge process stopped.");
}
}
}
@Override
public void engineStarted(WebSocketEngine aEngine) {
if (mLog.isDebugEnabled()) {
mLog.debug("Engine '" + aEngine.getId() + "' started.");
}
// every time an engine starts increment counter
mEngineInstanceCount++;
}
@Override
public void engineStopped(WebSocketEngine aEngine) {
if (mLog.isDebugEnabled()) {
mLog.debug("Engine '" + aEngine.getId() + "' stopped.");
}
// every time an engine starts decrement counter
mEngineInstanceCount--;
// when last engine stopped also stop the FlashBridge
if (mEngineInstanceCount <= 0) {
super.engineStopped(aEngine);
mIsRunning = false;
long lStarted = new Date().getTime();
try {
// when done, close server socket
// closing the server socket should lead to an exception
// at accept in the bridgeProcess thread which terminates the
// bridgeProcess
if (mLog.isDebugEnabled()) {
mLog.debug("Closing FlashBridge server socket...");
}
mServerSocket.close();
if (mLog.isDebugEnabled()) {
mLog.debug("Closed FlashBridge server socket.");
}
} catch (Exception ex) {
mLog.error("(accept) " + ex.getClass().getSimpleName() + ": " + ex.getMessage());
}
try {
mBridgeThread.join(10000);
} catch (Exception ex) {
mLog.error(ex.getClass().getSimpleName() + ": " + ex.getMessage());
}
if (mLog.isDebugEnabled()) {
long lDuration = new Date().getTime() - lStarted;
if (mBridgeThread.isAlive()) {
mLog.warn("FlashBridge did not stopped after " + lDuration + "ms.");
} else {
mLog.debug("FlashBridge stopped after " + lDuration + "ms.");
}
}
}
}
}