How do I serve Flash policy files from an Eclipse plugin? - java

I have an Eclipse plugin that needs to open a pair of sockets to a flash application running on the local machine. Flash requires a policy file (blob of XML) giving permissions to access the ports in question. Flash prefers to get this policy file over port 843, Java treats ports < 1024 as privileged ports and Mac OS X and Linux similarly restrict access to ports < 1024. I don't want to run my Eclipse plugin with root permissions, so serving up the policy file on port 843 is not an option. According to Adobe documentation, if Flash can't get the policy file on port 843, it falls back to requesting the policy file on the port to which it's trying to connect. The ActionScript code looks like this:
/**
* 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);
}
On the Eclipse plugin side I've inherited some code that works most of the time on OS X, but sometimes fails on Windows. Running on Wi-Fi rather than wired ethernet also tends to fail, although I have no idea why this should matter.
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;
}
This code looks wrong. It doesn't wait for the message from Flash and instead just jams the policy response into the port. As I said, it works most of the time, but it fails sometimes and doesn't seem to comply with Adobe's documentation.
I tried listening for request packets on each port and sending a port specific response. I watched socket traffic using WireShark on the loopback interface (Mac OS X). I saw policy requests coming in and responses getting sent, but Flash still gave me Security Sandbox Violation on both ports.
I also tried adding this line at the beginning of initSockets shown above:
Security.loadPolicyFile("xmlsocket://localhost:5002");
Then I added code in my plugin to listen on port 5002 and send the following master policy file content:
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";
Again I saw the request come in and the response go out, but Flash didn't seem to respond to it. I didn't get the Security Sandbox Violation errors, but there was also no traffic over the ports.
Can anyone enlighten me on the correct approach to opening sockets between Java and Flash?

I found the solution to this. I made a mistake early on and used BufferedReader.readLine to read the policy request. This isn't appropriate since policy requests are null terminated, not new line terminated. This was confusing since it does return when the underlying stream closes. Thus I got the request and sent a response, but the response was sent after the ActionScript code had already decided that the request had failed.
On the Java side I used the following code to establish communication on the ports:
// 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()));
Serving up the policy file is handled as follows:
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);
}
The Flash policy response looks like this:
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>";
The site-control tag I had previously been sending is only allowed in master policy files served from port 843.

Related

Java [Peer-To-Peer]: Runnable stops/blocks unexpectedly

I am developing a simple distributed ledger. I want to be able to start nodes on different ports, that could communicate with eachother. Each programme then would have a file, where it would write newly discovered nodes.
At first, only the most reliable nodes are hardcoded into that file.
Here is procedurally what happens:
1) I start a new node, which starts a HTTP server (I use com.sun.HttpServer). The server has a GetAddress handler, which listens to requests that go to the specified URI. It then gets the IP and PORT (which is specified in URI query params), acquires a semaphore for a known_nodes.txt file, and writes the newly received peer address to that file, if it's not already there, and send the contents of newly updated file as a json list back to the requester.
2) Within my Node class (which, as mentioned earlier, starts a HTTPServer on a separate thread), I create a ScheduledExecutorService and give it a runnable to be run every few seconds, whose job will be to connect to the URLs present in the known_nodes.txt file, and ask them for their known_nodes. If we received nodes that were not previously present in our known_nodes file, we overwrite our file.
NOW!
If I start a node, and try to request it from the browser, everything goes as planned - we receive a request, write it to our file, then our runnable will try to connect to the address specified in request. If we caught a SocketTimeoutException, we remove the address from our known_nodes.txt file.
The problem arises, when I start two nodes, running let's say on port 8001 and 8002. Please note, that each node has its own known_nodes file.
What happens, is that one of the nodes will stop running the DiscoverAddresses task, the other one won't. So effectively, one nodes stopped receiving requests.
NB! The node that will stop its scheduledtask will STILL send at least ONE discovering request, and then will die/block(?).
Here is the code for the runnable task:
#Override
public void run() {
log.info("still running ");
PeerAddressesHolder inactiveNodes = new PeerAddressesHolder();
ApplicationConfiguration appConf = ApplicationConfiguration.getInstance();
for (PeerAddress peerAddress : knownNodes.getAddresses()) {
if (isSameNode(peerAddress)) {
continue;
}
String urlString = String.format("http://%s:%s%s?myport=%d", peerAddress.getIP(), peerAddress.getPort(), Constants.GET_ADDRESS, myPort);
try {
StringBuilder result = new StringBuilder();
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
try (InputStream connInputStream = conn.getInputStream();
InputStreamReader ir = new InputStreamReader(connInputStream);
BufferedReader br = new BufferedReader(ir)){
String line;
while ((line = br.readLine()) != null) {
result.append(line).append('\n');
}
} catch (Exception e) {
log.warn("Couldn't read from connection input stream",e);
}
PeerAddressesHolder peerAddressesHolder = gson.fromJson(result.toString(), PeerAddressesHolder.class);
boolean fetchedNew = false;
for (PeerAddress fetchedAddress : peerAddressesHolder.getAddresses()) {
if (!isValidAddress(peerAddress)) {
log.warn("Peer has sent us a null-address. It will be ignored.");
return;
}
if (!knownNodes.contains(fetchedAddress)) {
knownNodes.addAddress(fetchedAddress);
fetchedNew = true;
}
}
if (fetchedNew) {
FileUtils.writeToFile(appConf.getKnownNodesFilePath(), gson.toJson(knownNodes), false);
}
} catch (SocketTimeoutException e) {
if (appConf.getMostReliableNodes().contains(peerAddress)) {
log.warn("Most reliable node not available: " + peerAddress);
} else {
inactiveNodes.addAddress(peerAddress);
log.warn("Connection timeout from " + peerAddress + ". It will be removed.");
}
} catch (Exception e) {
log.warn("Couldn't discover new addresses." + e);
}
}
try {
knownNodes.removeAll(inactiveNodes.getAddresses());
FileUtils.writeToFile(appConf.getKnownNodesFilePath(), gson.toJson(knownNodes), false);
} catch (IOException ioe) {
log.warn("Couldn't write to file after deleting dead node", ioe);
}
}
And here is how I start it upon Node creation.
public NetworkNode(int port) {
this.appConf = ApplicationConfiguration.getInstance();
this.port = port;
log.info("Starting a new node on port " + port);
try {
this.knownNodes = FileUtils.createPeerAddressesList(appConf.getKnownNodesFilePath());
} catch (Exception e) {
log.error("Error while trying to construct a list of peer addresses from file content on path: " + appConf.getKnownNodesFilePath());
}
scheduledExecutorService = Executors.newScheduledThreadPool(4);
scheduledExecutorService.scheduleAtFixedRate(new DiscoverAddressesTask(knownNodes, this.port), 3, 4, TimeUnit.SECONDS);
Methods dealing with file reading/writing are all done using try-with-resources construct, so my initial idea that the runnable stops because of some unclosed streams is probably not valid.

Communicate with server and client websockets in java properly

I have developed a simply video game and I want to update it with the multiplayer functionality using websockets. I want to have two versions of the game. The first one to work as server and the other version as a client. I want to initialize the game from the server and to wait for the reaction of the client. My first question: is it possible to run server and client in the same machine (give as an input the same ip)? Secondly I am using the following code in order to create the sockets from the server side:
try {
serverSocket = new ServerSocket(10007);
}
catch (IOException e)
{
System.err.println("Could not listen on port: 10007.");
System.exit(1);
}
System.out.println ("Waiting for connection.....");
try {
clientSocket = serverSocket.accept();
}
catch (IOException e)
{
System.err.println("Accept failed.");
System.exit(1);
}
System.out.println ("Connection successful");
When I am trying to connect from the client it seems that the whole thing its not working as i am receiving the message waiting for connection.... My code for connecting the client is the following:
String serverHostname = new String("ip");
if (args.length > 0)
serverHostname = args[0];
System.out.println("Attemping to connect to host " +
serverHostname + " on port 10007.");
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
echoSocket = new Socket(serverHostname, 10007);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: " + serverHostname);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for "
+ "the connection to: " + serverHostname);
System.exit(1);
}
What can it be the issue here?
Your Server Side Code is fine. just a little note here, the ServerSocket.accept(); method is ablocking call, meaning that program execution will halt there until a client connects to it.
Secondly i can see an issue from the first line of your client code below
if (args.length > 0)
serverHostname = args[0];
args[0] may not be an ip address, i'm not too sure about how java command line applications behave but in c++ for instance, args[0] in the right context is always the absolute path of the program executable. this may be the case in java too.
So you may be passing an ip address but will actually be passed in as args[1].

Creating an echo-server: Connected client gets IO-exception

I'm trying to create a single-threaded echo-server, but I can't figure out how to send the input from the client back to the client again from the server. The client connects to the server alright, but it's when it's waiting for a response that it throws an IOException. I have tried connecting my chat client to other chat servers, hence I'm sure the fault is in the chat server implementation.
I'm guessing the "villain of the piece" is this method presented below that takes the input from the connected client and sends it back, but I'm not sure why it doesn't work.
private void processClientRequest(Socket clientSocket) throws IOException {
InputStream in = clientSocket.getInputStream();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream());
long time = System.currentTimeMillis();
out.write("Server - " + time + ": " + in);
out.close();
in.close();
}
Please tell me if this method isn't the issue and you need other parts of my code instead.
Thanks in advance!
Edit: I have now managed to get my server to respond to the client. I did this by changing the processClientRequest method to this:
try {
BufferedReader in =
new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream());
long time = System.currentTimeMillis();
out.write("Server - " + time + ": " + in.readLine());
out.close();
try {
in.close();
} catch (IOException e) {
System.err.println("Couldn't close input stream");
}
} catch(IOException e) {
System.err.println("Got an IOException error while reading or writing from/to client");
}
But as of now my server can only respond the client once. If the client writes to the server a second time it does get a response, but instead of the clients message, it's "null". And since I want my echo server to be able to answer the client until the client shuts down or something like that, I need to figure out how to change that. I figure I'm going to need some kind of while loop to make this happen, but I have tried for example putting the whole try statement into an infinite while loop, but that just gave me loads of IOExceptions.
You're not reading the clients input. You're just passing the toString to your out. You need to make a while loop and read from in. Maybe in a seperate thread unless you're sure the input is short. In test code should be okay:
private void processClientRequest(Socket clientSocket) throws IOException {
InputStream in = clientSocket.getInputStream();//wrap this in a object stream or other to read lines/ utf
int i = 0;
while(i++ < 1000 && in.available() > 0){
int read = in.read();//use it if u want, like to a string builder declared out of loop and echo it back after u read input
}
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream());
long time = System.currentTimeMillis();
out.write("Server - " + time + ": " + in);
out.close();//should be in seperate try catches so if 1 close fails u still close other and finally close socket in 3rd try catch
in.close();
}
Socket server with working echo server, mini web server and helpful in many more ways.

file transfer between server and client input stream

I'm working on a java server-client based file transfer over socket project, I'll sum up the project shortly, I have text files related to server and client, server related text contains which ports are going to be opened and client text contains the IP and port to be connected on(server side is like 4444 and client side is like 4444 localhost) The file transfer on a single client is running pretty ok, now I'm working on second client connection and transfer, what I'm trying to do is; when a second client is run, it will read the first line of the text file (which is already in use by the first client), I thought a recursion will solve the problem but seems I couldn't figure out what I've done wrong, below are the code snippet from client side
boolean connected = false;
private void connection() {
while (!connected) {
try {
FileReader fr = new FileReader("c_input.txt");
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
String delims = "[ ]";
String[] elements = new String[8];
elements = line.split(delims);
serverPort = Integer.parseInt(elements[portIndex]);
hostIP = elements[ipIndex];
clientSocket = new Socket(hostIP, serverPort);
is = clientSocket.getInputStream();
if (is != null) {
connected = true;
System.out.println("connected to " + hostIP + " from port "
+ serverPort);
br.close();
fr.close();
} else {
System.out.println("The port " + serverPort
+ " is occupied, now trying another port.");
portIndex = portIndex + 2;
ipIndex = ipIndex + 2;
connection();
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
System.exit(0);
}
}
}
I used recursion there, because if a port is bound by another client it has to read another line from text file and split and retry connection with the new line's inputs.(in terms short the whole method will run again) But when it comes to running, the first client connects and when second one tries to connect from same port with client1 the code still gets in if loop instead of getting in else block (I get the message from the if check's println on the console and by the way is in the if check stands for InputStream) which means there is a stream coming from server, is this normal? if so how can I achieve the whole thing connection method does all over again if the port is bound by another client?

Detecting port availability in Java fails

I try to check if port 80 is available using the following method :
Sockets: Discover port availability using Java
I have a Java application that checks if port 80 is available, if so, it runs a small web server listening on port 80. It works great to detect if another Java application listens on port 80, e.g. if I run my application two times, the second instance will correctly tell me that the port 80 is being used.
The problem is that I have WAMP running and listening on port 80, and that if I run my Java application after I started WAMP, it won't tell me that the port 80 is busy. It seems that it only tells me if another Java application uses the port 80.
That goes beyond my understanding ... any help is greatly appreciated!
Code snippet:
int port = 80;
if(!Connection.isPortAvailable(port)) {
logger.info("Port " + port + " is already in use");
}
// in Connection class
public static boolean isPortAvailable(int port) {
ServerSocket ss = null;
DatagramSocket ds = null;
try {
ss = new ServerSocket(port);
ss.setReuseAddress(true);
ds = new DatagramSocket(port);
ds.setReuseAddress(true);
return true;
} catch (IOException e) {
} finally {
if (ds != null) {
ds.close();
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
/* should not be thrown */
}
}
}
return false;
}
The correct answer to all questions of this nature is to try to use it and catch the exception. Not try to see if it's available and then try to use it and still have to handle the exception, which has several obvious problems:
There is a timing window between 'see' and 'try' during which the situation can change (both ways).
You still have to catch failures in the 'use' part anyway.
It is basically just trying to predict the future. This is supposed to be computer science, not fortune-telling.
This applies to most values of 'it', including network ports, files, any resource really.
I was able to reproduce your problem by running WampServer (verified that it was running by visiting localhost:80) and running a minimal java program given your example code.
The code in the try block did not throw an exception when WampServer was running. However, modify the first few lines of the try block like this
ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1", port));
and isPortAvailable will properly detect when WampServer is running and when it is not. Using "0.0.0.0" instead of "127.0.0.1" didn't work with WampServer, but did properly detect when IIS was running. You can check both by closing the first socket
ss = new ServerSocket();
ss.bind(new InetSocketAddress("0.0.0.0", port));
ss.close();
ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1", port));

Categories

Resources