Currently I am trying to communicate with a Parallel port via Java, but this has proven to be troublesome. I am currently doing a brain research using EEG and I want to send simple "event markers" to the EEG system, which must happen via Parallel Port. I have used both javax.comm and RXTX but for some reason I cannot manage to write output to the port. The test-code is as follows:
import gnu.io.*; // RXTX
// import javax.comm.*; // javax.comm
public class PrlCom {
private String msg= "1";
private OutputStream outputStream;
private InputStream inputStream;
private ParallelPort parallelPort; // can be both Rxtx or javax.comm
private CommPortIdentifier port;
// CONSTANTS
public final String PARALLEL_PORT = "LPT1";
public final String[] PORT_TYPE = { "Serial Port", "Parallel Port" };
public static void main(String[] args) {
new PrlCom();
}
public PrlCom(){
openParPort();
}
public void openParPort() {
try {
// get the parallel port connected to the EEG-system (used to be printer)
port = CommPortIdentifier.getPortIdentifier(PARALLEL_PORT);
System.out.println("\nport.portType = " + port.getPortType());
System.out.println("port type = " + PORT_TYPE[port.getPortType() - 1]);
System.out.println("port.name = " + port.getName());
// open the parallel port -- open(App name, timeout)
parallelPort = (ParallelPort) port.open("CommTest", 50);
outputStream = parallelPort.getOutputStream();
inputStream = parallelPort.getInputStream();
System.out.println("Write...");
outputStream.write(toBytes(msg.toCharArray()));
System.out.println("Flush...");
outputStream.flush();
} catch (NoSuchPortException nspe) {
System.out.println("\nPrinter Port LPT1 not found : " + "NoSuchPortException.\nException:\n" + nspe + "\n");
} catch (PortInUseException piue) {
System.out.println("\nPrinter Port LPT1 is in use : " + "PortInUseException.\nException:\n" + piue + "\n");
} catch (IOException ioe) {
System.out.println("\nPrinter Port LPT1 failed to write : " + "IOException.\nException:\n" + ioe + "\n");
} catch (Exception e) {
System.out.println("\nFailed to open Printer Port LPT1 with exeception : " + e + "\n");
} finally {
if (port != null && port.isCurrentlyOwned()) {
parallelPort.close();
}
System.out.println("Closed all resources.\n");
}
}
I got the toBytes() function from Converting char[] to byte[] . I also directly tried spam.getBytes(), which made no difference.
After running this code with the javax.comm package, the parallel port is not recognized. If I run the code with RXTX(gnu.io), I get an IOException. The entire printed output is then as follows
Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version = RXTX-2.1-7
port.portType = 2
port type = Parallel Port
port.name = LPT1
Output stream opened
Write...
Printer Port LPT1 failed to write : IOException.
Exception:
java.io.IOException: The device is not connected.
in writeByte
Closed all resources.
With Rxtx, the code can make a connection with the Parallel Port thus. However, it is unable to write a byte to the output stream. Can someone please tell me how to resolve this?
I have read in many of the other topics how outdated a parallel port is and that I should use USB. However, I am working with an EEG-system (BioSemi ActiveTwo with ActiView software) to measure brain activity and, sadly, I don't have the possibility to change this. A Parallel port-USB converter is also no option. (Odd though, that something so technologically advanced uses such outdated hardware).
Thank you so much!
I have accepted that Rxtx and javax.comm do not work anymore. Instead, I found a workaround via Python. For the answer, see
Parallel Port Communication with jnpout32pkg / jnpout32reg
Related
I have to create a program that sniff a local network for school. I chose to work with Java and found out that you can capture packets with jpcap.
So I wanted to follow one of the example provided in jpcap's github and it seems like I can only find my own packets.
Like I said, I've looked at the code and chose my wifi interface. The program is capturing packets and I put all the source ip addresses in a text file to run some tests. I have also created a hashmap the ip addresses I've finded when I did a arp -a. From what I've read online, this command shows you ip addresses in your network.I created a boolean set to false and I then proceeded to run a loop that goes through the textfile and looked if the ip address was in the hashMap : if one of the addresses appeared in the hashmap, the boolean would be change to true and it would mean that I've managed to catch something.
After running the test, the boolean came out false.
Here's the example code
``public class PacketCaptor {
private static final int INFINITE = -1;
private static final int PACKET_COUNT = INFINITE;
/*
private static final String HOST = "203.239.110.20";
private static final String FILTER =
"host " + HOST + " and proto TCP and port 23";
*/
private static final String FILTER =
// "port 23";
"";
public static void main(String[] args) {
try {
if(args.length == 1){
PacketCaptor sniffer = new PacketCaptor(args[0]);
} else {
System.out.println("Usage: java Sniffer [device name]");
System.out.println("Available network devices on your machine:");
String[] devs = PacketCapture.lookupDevices();
for(int i = 0; i < devs.length ; i++)
System.out.println("\t" + devs[i]);
}
} catch(Exception e) {
e.printStackTrace();
}
}
public PacketCaptor(String device) throws Exception {
// Initialize jpcap
PacketCapture pcap = new PacketCapture();
System.out.println("Using device '" + device + "'");
pcap.open(device, true);
//pcap.setFilter(FILTER, true);
pcap.addPacketListener(new PacketHandler());
System.out.println("Capturing packets...");
pcap.capture(PACKET_COUNT);
}
}
class PacketHandler implements PacketListener
{
WritingClass writing = new WritingClass();
public void packetArrived(Packet packet) {
try {
// only handle TCP packets
if(packet instanceof TCPPacket) {
TCPPacket tcpPacket = (TCPPacket)packet;
byte[] data = tcpPacket.getTCPData();
String srcHost = tcpPacket.getSourceAddress();
String dstHost = tcpPacket.getDestinationAddress();
String isoData = new String(data, "ISO-8859-1");
System.out.println(srcHost+" -> " + dstHost + ": " + isoData);
String datas = srcHost+"|"+dstHost+"|";
writing.write(datas, this.writing.getFileName());
}
} catch( Exception e ) {
e.printStackTrace();
}
}
Can anyone help me figure out why It doesn't work ?
Thank you so much for your help
The reason why you aren't able to capture more packets is because you need an interface in promisc or raw mode, I advice you to use a proper sniffer like wireshark to check if other packets that aren't addressed to you can be captured. If not, means you need apply a mitm method because you are in a commuted network. For use that code on wifi should be enough an interface in monitor mode (check aircrack-ng suite).
In GNU/Linux Debian based systems may use the command iw dev wlan0 interface add mon0 type monitor (from package wireless-tools)
This question already has answers here:
java.lang.UnsatisfiedLinkError
(6 answers)
Closed 6 years ago.
I am tring to connect to IBM websphere Client with a Java Programme
the Following are the code:=
import com.ibm.mq.MQException;
import com.ibm.mq.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
/**
* Simple example program
*/
public class MQSample {
// code identifier
static final String sccsid = "#(#) MQMBID sn=p750-002-131001_DE su=_FswqMCqGEeOZ3ui-rZDONA pn=MQJavaSamples/wmqjava/MQSample.java";
// define the name of the QueueManager
private static final String qManager = "QM_ORANGE";
// and define the name of the Queue
private static final String qName = "SYSTEM.DEFAULT.LOCAL.QUEUE";
// private static final String qName = "QM_APPLE";
public static void main(String args[]) {
try {
System.out.println("Connecting to queue manager: " + qManager);
MQQueueManager qMgr = new MQQueueManager(qManager);
int openOptions =1| 16;
System.out.println("Accessing queue: " + qName);
MQQueue queue = qMgr.accessQueue(qName, openOptions);
MQMessage msg = new MQMessage();
msg.writeUTF("Hello, World!");
MQPutMessageOptions pmo = new MQPutMessageOptions();
System.out.println("Sending a message...");
queue.put(msg, pmo);
// Now get the message back again. First define a WebSphere MQ
// message
// to receive the data
// MQMessage rcvMessage = new MQMessage();
// Specify default get message options
// MQGetMessageOptions gmo = new MQGetMessageOptions();
// Get the message off the queue.
// System.out.println("...and getting the message back again");
// queue.get(rcvMessage, gmo);
// And display the message text...
//String msgText = rcvMessage.readUTF();
// System.out.println("The message is: " + msgText);
// Close the queue
System.out.println("Closing the queue");
queue.close();
// Disconnect from the QueueManager
System.out.println("Disconnecting from the Queue Manager");
qMgr.disconnect();
System.out.println("Done!");
}
catch (MQException ex) {
System.out.println("A WebSphere MQ Error occured : Completion Code " + ex.completionCode
+ " Reason Code " + ex.reasonCode);
ex.printStackTrace();
for (Throwable t = ex.getCause(); t != null; t = t.getCause()) {
System.out.println("... Caused by ");
t.printStackTrace();
}
}
catch (java.io.IOException ex) {
System.out.println("An IOException occured whilst writing to the message buffer: " + ex);
}
return;
}
}
but right now i am getting following error
Exception in thread "main" java.lang.UnsatisfiedLinkError: no mqjbnd05 in java.library.path
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.loadLibrary0(Unknown Source)
at java.lang.System.loadLibrary(Unknown Source)
at com.ibm.mq.MQSESSION.loadLib(MQSESSION.java:872)
at com.ibm.mq.server.MQSESSION$1.run(MQSESSION.java:228)
at java.security.AccessController.doPrivileged(Native Method)
at com.ibm.mq.server.MQSESSION.<clinit>(MQSESSION.java:222)
at com.ibm.mq.MQSESSIONServer.getMQSESSION(MQSESSIONServer.java:70)
at com.ibm.mq.MQSESSION.getSession(MQSESSION.java:492)
at com.ibm.mq.MQManagedConnectionJ11.<init>(MQManagedConnectionJ11.java:168)
at com.ibm.mq.MQBindingsManagedConnectionFactoryJ11._createManagedConnection(MQBindingsManagedConnectionFactoryJ11.java:179)
at com.ibm.mq.MQBindingsManagedConnectionFactoryJ11.createManagedConnection(MQBindingsManagedConnectionFactoryJ11.java:215)
at com.ibm.mq.StoredManagedConnection.<init>(StoredManagedConnection.java:84)
at com.ibm.mq.MQSimpleConnectionManager.allocateConnection(MQSimpleConnectionManager.java:168)
at com.ibm.mq.MQQueueManagerFactory.obtainBaseMQQueueManager(MQQueueManagerFactory.java:772)
at com.ibm.mq.MQQueueManagerFactory.procure(MQQueueManagerFactory.java:697)
at com.ibm.mq.MQQueueManagerFactory.constructQueueManager(MQQueueManagerFactory.java:657)
at com.ibm.mq.MQQueueManagerFactory.createQueueManager(MQQueueManagerFactory.java:153)
at com.ibm.mq.MQQueueManager.<init>(MQQueueManager.java:451)
at MQSample.main(MQSample.java:30)
when i refered about this everyone saying to put mqjbnd.dll in java.library i put that file in that path also still not working
IBM MQ CLIENT java.lang.UnsatisfiedLinkError: no mqjbnd05 in
java.library.path exception
Your title pretty much says it all. 'MQ Client' generally means that the queue manager is REMOTE to where you are running your application. But 'no mqjbnd05' means that you are attempting to connect to the queue manager in bindings mode, queue manager is running on the same server as your queue manager.
99% of the time an application gets that errors is because the application and queue manager are running on separate servers and the application is not specifying: channel name, hostname/IP address & port #.
Note: An application can connect in 2 ways to a queue manager:
(1) client mode - meaning the application and queue manager are running on separate servers and the application is not specifying: channel name, hostname/IP address & port #.
(2) bindings mode - meaning the application and queue manager are running on the same servers (no networking information is specified).
Note: Don't use MQEnvironment class but rather put the connection information in a Hashtable and pass it to the MQQueueManager class. MQEnvironment is NOT thread safe.
Here's a working sample MQ application that will connect (client mode) to a remote queue manager:
import java.io.IOException;
import java.util.Hashtable;
import com.ibm.mq.*;
import com.ibm.mq.constants.CMQC;
/**
* Java class to connect to MQ. Post and Retrieve messages.
*
* Sample Command Line Parameters
* -h 127.0.0.1 -p 1414 -c TEST.CHL -m MQA1 -q TEST.Q1 -u userid -x password
*/
public class MQClientTest
{
private Hashtable<String, String> params = null;
private Hashtable<String, Object> mqht = null;
private String qManager;
private String inputQName;
/**
* The constructor
*/
public MQClientTest()
{
super();
}
/**
* Make sure the required parameters are present.
*
* #return true/false
*/
private boolean allParamsPresent()
{
boolean b = params.containsKey("-h") && params.containsKey("-p") &&
params.containsKey("-c") && params.containsKey("-m") &&
params.containsKey("-u") && params.containsKey("-x") &&
params.containsKey("-q");
if (b)
{
try
{
Integer.parseInt((String) params.get("-p"));
}
catch (NumberFormatException e)
{
b = false;
}
}
return b;
}
/**
* Extract the command-line parameters and initialize the MQ variables.
*
* #param args
* #throws IllegalArgumentException
*/
private void init(String[] args) throws IllegalArgumentException
{
params = new Hashtable<String, String>();
if (args.length > 0 && (args.length % 2) == 0)
{
for (int i = 0; i < args.length; i += 2)
{
params.put(args[i], args[i + 1]);
}
}
else
{
throw new IllegalArgumentException();
}
if (allParamsPresent())
{
qManager = (String) params.get("-m");
inputQName = (String) params.get("-q");
mqht = new Hashtable<String, Object>();
mqht.put(CMQC.CHANNEL_PROPERTY, params.get("-c"));
mqht.put(CMQC.HOST_NAME_PROPERTY, params.get("-h"));
try
{
mqht.put(CMQC.PORT_PROPERTY, new Integer(params.get("-p")));
}
catch (NumberFormatException e)
{
mqht.put(CMQC.PORT_PROPERTY, new Integer(1414));
}
mqht.put(CMQC.USER_ID_PROPERTY, params.get("-u"));
mqht.put(CMQC.PASSWORD_PROPERTY, params.get("-x"));
// I don't want to see MQ exceptions at the console.
MQException.log = null;
}
else
{
throw new IllegalArgumentException();
}
}
/**
* Method to put then get a message to/from a queue.
*/
public void putAndGetMessage()
{
MQQueueManager qMgr = null;
MQQueue queue = null;
MQMessage putMessage = null;
MQMessage getMessage = null;
int openOptions = CMQC.MQOO_INPUT_AS_Q_DEF | CMQC.MQOO_OUTPUT + CMQC.MQOO_FAIL_IF_QUIESCING;
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.options = CMQC.MQGMO_NO_WAIT + CMQC.MQGMO_FAIL_IF_QUIESCING;
MQPutMessageOptions pmo = new MQPutMessageOptions();
pmo.options = CMQC.MQPMO_FAIL_IF_QUIESCING;
String msg = "Hello World, WelCome to MQ.";
try
{
qMgr = new MQQueueManager(qManager, mqht);
queue = qMgr.accessQueue(inputQName, openOptions);
putMessage = new MQMessage();
putMessage.writeUTF(msg);
// put the message on the queue
queue.put(putMessage, pmo);
System.out.println("Message is put on MQ.");
// get message from MQ.
getMessage = new MQMessage();
// assign message id to get message.
getMessage.messageId = putMessage.messageId;
/*
* Tell the queue manager that we want a message with a specific MsgID.
*/
gmo.matchOptions = CMQC.MQMO_MATCH_MSG_ID;
// get message options.
queue.get(getMessage, gmo);
String retreivedMsg = getMessage.readUTF();
System.out.println("Message got from MQ: " + retreivedMsg);
}
catch (MQException e)
{
System.err.println("CC=" + e.completionCode + " : RC=" + e.reasonCode);
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if (queue != null)
queue.close();
}
catch (MQException e)
{
System.err.println("MQCLOSE CC=" + e.completionCode + " : RC="
+ e.reasonCode);
}
try
{
if (qMgr != null)
qMgr.disconnect();
}
catch (MQException e2)
{
System.err.println("MQDISC CC=" + e2.completionCode + " : RC="
+ e2.reasonCode);
}
}
}
public static void main(String[] args)
{
System.out.println("Processing Main...");
MQClientTest clientTest = new MQClientTest();
try
{
// initialize MQ.
clientTest.init(args);
// put and retrieve message from MQ.
clientTest.putAndGetMessage();
}
catch (IllegalArgumentException e)
{
System.out.println("Usage: java MQClientTest -h host -p port -c channel -m QueueManagerName -q QueueName -u userid -x password");
System.exit(1);
}
System.out.println("Done!");
}
}
There is nothing in the question to indicate which version of MQ client is being used, how it was installed, whether the IBM-provided code works, or whether the environment was set correctly. That makes this more of a "how do I configure and test MQ client?" kind of question so I'll answer it that way.
Back-level MQ clients were always installed using IBM's full-client install media. Newer clients can be installed using IBM's Java-only install media. It is always recommended to use one of these methods.
The one thing to not do (which coincidentally is the thing done most often) is to simply grab the jar files from the MQ Server installation. The reasons for this include:
The IBM installer lays down a known-good set of files.
Maintenance can be applied to an installation made using IBM's installer.
When using IBM's install methods, things like trace directories and the location of the MQClient.ini file are predictable.
So first thing is to make sure you are running from the latest IBM-provided full client or Java-only install media. Alternatively, install IBM MQ Advanced for Developers which delivers a full MQ install to the desktop, including all the client support. MQ Advanced for Developers is free for individual use.
Prior to launching code, set the environment. See:
Environment variables relevant to IBM MQ classes for Java
Environment variables used by IBM MQ classes for JMS
Per the docs:
On Windows, all the environment variables are set automatically during
installation. On any other platform, you must set them yourself. On a
UNIX system, you can use the script setjmsenv (if you are using a
32-bit JVM) or setjmsenv64 (if you are using a 64-bit JVM) to set the
environment variables. On AIX, HP-UX, Linux, and Solaris, these
scripts are in the MQ_INSTALLATION_PATH/java/bin directory.
IBM provides lots of sample code. On *nix systems this is in /opt/mqm/samp/. On windows it's in the [MQ install directory]\tools. If the full client is installed try the compiled C code first, like amqsgetc. This establishes whether basic connectivity is in place. Once you know the channel connectivity works, try the Java or JMS samples.
Getting back to the original post, before we can help we'd need to know which of the above steps had already been completed and something about the configuration. Otherwise what you get back generally leads you down a path to a setup in which configuration is almost guaranteed to be hosed: "Try adding this library here," or "try mucking about with your CLASSPATH like this..." Such trial-and-error approaches often work but
are unsupportable and lead to problems over time.
I am trying to build a port scanner which not only scans for port numbers but, also list the services running on the respective port .I am new to java-programming and As you can see i have the code for scanning the status of ports on the local machine. I don't know where to start when it comes to list services running on each port. I would appreciate if anyone can suggest me any code/links to list those services. Thanks for the help.....
public class port {
public static void main(String[] args) throws Exception {
String host = "localhost";
InetAddress inetAddress = InetAddress.getByName(host);
String hostName = inetAddress.getHostName();
for (int port = 0; port <= 200; port++) {
try {
Socket socket = new Socket(hostName, port);
String text = hostName + " is listening on port " + port;
System.out.println(text);
socket.close();
}
catch (IOException e)
{
String s = hostName + " is not listening on port " + port;
System.out.println(s);
}
}
}
}
The code seems fine if you want to check for open ports, but identifying services... well, that's tricky.
It's a bit like identifying the type of file by reading the first few bytes. An easy solution is to compare the port number with the list of well known ports. So if port 80 is open, you just assume it's HTTP and move on.
This method assumes that services actually listen on their assigned ports. This is like assuming that a file that ends with "zip" is always a zip file. It's correct most of the time, but only because it's a convention. Not because it has to be this way. If you want to actually fingerprint services - determine the type of service by "talking to it", then it's a serious undertaking, not something that can be explained in a few lines. I suggest you take a look at Nmap, as it's an existing tool that does just that. You might be able to use it instead of writing your own.
So, you are looking for something like Nmap?
Your code seems good to me, although I would do something like
public class PortScanner {
public static void main(String[] args) throws Exception {
final String host = "localhost";
final InetAddress inetAddress = InetAddress.getByName(host);
final String hostName = inetAddress.getHostName();
final List<int> openPorts = new ArrayList();
// we begin at port 1 because port 0 is never used
for (int port = 1; port <= 200; port++) {
try {
Socket socket = new Socket(hostName, port);
openPorts.add(port);
} catch (IOException) {
} finally {
socket.close();
}
}
}
}
You cannot easily know what service is running on the port, you can only simply assume what service is running on that port using this list. But beware, a web server can use custom ports instead of default ones.
If you do have the requirement to know exactly what service is running on what port, I suggest you use Nmap and make a bash script out of it which in turn outputs it's findings in a .txt file. That .txt file can then be read by Java. This approach saves tons of work.
I want to detect list of USB Ports which are free (not occupied) in system to while I checked with CommPortIdentifier.getPortIdentifiers() while this returns me Enumeration with 0 elements
I'd add librxtxcomm.jar too in classpath.
This should return each Port detail
Enumeration pList = CommPortIdentifier.getPortIdentifiers();
System.out.println(pList.hasMoreElements());
this returns 0 mean no List/Enumeration.
Rest Code :
public class CommPortLister{
/** Simple test program. */
public static void main(String[] ap) {
new CommPortLister().list();
}
/** Ask the Java Communications API * what ports it thinks it has. */
protected void list() {
// get list of ports available on this particular computer, by calling static method in CommPortIdentifier.
System.out.println("");
Enumeration pList = CommPortIdentifier.getPortIdentifiers();
System.out.println("Before While");
// CommPortIdentifier.getPortIdentifiers();
// Process the list.
System.out.println(pList.hasMoreElements());
while (pList.hasMoreElements()) {
System.out.println("While Loop");
CommPortIdentifier cpi = (CommPortIdentifier) pList.nextElement();
System.out.print("Port " + cpi.getName() + " ");
if (cpi.getPortType() == CommPortIdentifier.PORT_SERIAL) {
System.out.println("is a Serial Port: " + cpi);
} else if (cpi.getPortType() == CommPortIdentifier.PORT_PARALLEL) {
System.out.println("is a Parallel Port: " + cpi);
} else {
System.out.println("is an Unknown Port: " + cpi);
}
}
System.out.println("After While");
}
}
Code to detect USB port while i am unable to detect USB Port
Please try using ServerSocket(portNo). If there is an service running in the port, it will error so catch the exception and try the next port.
A port number is a 16-bit unsigned integer, thus ranging from 1 to 65535.
If you need to know which ports are occupied, you may call the system command "netstat" from java.
================Edited===========================
The above information is for transport layer logical ports.If you are looking for hardware ports for peripheral devices, then you need to check the COM ports. I found the following tutorial, maybe you can give it a try, so find another tutorial that suits your need.
http://www.java-samples.com/showtutorial.php?tutorialid=11
You will need javax.comm api for this. You can grab it from http://www.java2s.com/Code/Jar/c/Downloadcomm20jar.htm or http://www.oracle.com/technetwork/java/index-jsp-141752.html
Well here the thing using that u can have available ports u can scan it.
public class GettingAvaliable {
public static void main(String args[]) {
int startPortRange = 0;
int stopPortRange = 65365;
int usedport = 0;
int unusedports = 0;
for (int i = startPortRange; i <= stopPortRange; i++) {
try {
Socket ServerSok = new Socket("127.0.0.1", i);
System.out.println("Port in use: " + i);
usedport++;
ServerSok.close();
} catch (Exception e) {
//e.printStackTrace();
}
System.out.println("Port not in use: " + i);
unusedports++;
if (i == stopPortRange) {
System.out.println("Number of Used Ports In Your Machine: "+usedport);
System.out.println("Number of Unused Ports In Your Machine: "+unusedports);
}
}
}
}
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.