Closed tuxedo0801 closed 9 years ago
I further analyzed the situation:
The problem with "don't allow (client side)" in TransportLayerImpl:
Now I understand what this means: Calimero can of course act as a server (--> receive connection requests and handle them) and as client (send connection request). What I don't understand: Why is there no check for the target-address? Why does calimero handle its connection request? Would it not make sense to filter for the target-address: If calimero uses 1.1.250 and wants to connect to 1.1.251... then it should not react on it's own connect-telegram (if sender == me then ignore) ?!!
IIRC, the cause of this is the multicast behaviour of the local interface. In KNXnetIPRouting, see the call to init
in the constructor. Currently multicast loopback is requested (true
). You can check it with usesMulticastLoopback()
. Disabling the loopback should provide the expected behaviour, leaving it disabled is a better default anyway.
So for now I subclass KNXnetIPRouting and disable multicastloopback by myself and you will change the default behavior with a code-change?
Subclassing of KNXnetIPRouting is not a problem. But I usually use KNXNetworkLinkIP and parametrize it and then internally KNXnetIPRouting is choosen.
If I have to use my own KNXnetIPRouting-class, how to I use it right?
[update] Disabling loopbackmode via reflection works :-)
InetAddress hostadr = InetAddress.getByName("224.0.23.12");
int port = 3671;
// setup knx connection
KNXNetworkLinkIP netlink = new KNXNetworkLinkIP(KNXNetworkLinkIP.ROUTING, null, new InetSocketAddress(hostadr, port), false, new TPSettings(false));
try {
Field connField = KNXNetworkLinkIP.class.getDeclaredField("conn");
connField.setAccessible(true);
KNXnetIPConnection conn = (KNXnetIPConnection) connField.get(netlink);
if (conn instanceof KNXnetIPRouting) {
KNXnetIPRouting knxnetiprouting = (KNXnetIPRouting) conn;
Field socketField = KNXnetIPRouting.class.getSuperclass().getDeclaredField("socket");
socketField.setAccessible(true);
MulticastSocket socket = (MulticastSocket) socketField.get(knxnetiprouting);
socket.setLoopbackMode(true);
System.out.println("loopback enabled: "+knxnetiprouting.usesMulticastLoopback());
}
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException | SocketException ex) {
ex.printStackTrace();
}
netlink.getKNXMedium().setDeviceAddress(new IndividualAddress("1.1.250"));
IndividualAddress remote = new IndividualAddress("1.1.14");
RemotePropertyServiceAdapter rpsa = new RemotePropertyServiceAdapter(netlink, remote, null, true);
PropertyClient pc = new PropertyClient(rpsa);
byte[] property = pc.getProperty(0 /* obj-index */, 56 /* prop-id */, 1 /* start */, 1 /* elements*/);
System.out.println(Arrays.toString(property));
I see the output "loopback enabled: false" and busmonitor does no longer show wron disconnects.
But it would be better to have a clean way to solve this. Either change default-behavior, or make it possible to set the flag at init (or at least after init with a setter or so).
From my current understanding subclassing KNXnetIPRouting would also need to subclass/copy KNXNetworkLinkIP. Or is there a way around (without reflection), without wrinting lots of code?
Good to hear it works! I was guessing based on the behaviour you observed, but didn't know for sure ;) A "clean" way (not clean from a networking perspective, but high-level/user-space perspective) is currently only done in the server part (calimero-server), similar in eibd. It involves datagram filter lists if loopback on the local outgoing interface is requested.
I actually don't remember why I set the loopback as is, without filtering (except the dumb justification that I needed it back then :/ ). In general, my prioritized way to go for least code change would be: a) if you compile everything from source, change the init argument b) subclass routing if you don't need network links c) extend the KNX network link for routing (not much change, but requires a copy) d) stay with your solution for now e) I have long-waiting commits for the embd8 branch which use an abstract network link, which allows that kind of stuff. Because initialization is an issue as you showed, I will back-port those to master.
For the stable (2.2.1) of the current beta, I will simply disable the loopback, which should work without problems for most things.
Thanks for the feedback. Solution e) would be the best. b+c would be too much I guess, so i went for extending KNXNetworkLInkIP and adding my reflection-solution to override the default after init.
So part one of my problem is solved: unwanted disconnects. Part two of my problem (Calimero does not recognize the property-read-answer from arduino) might still exist. I have to check when I'm back home. Maybe the unwanted disconnects "disturbed" the receiveing of the answer (state change of destination or so). I will check and report back about the new situation.
Last night I was able to properly answer propertyread-requests send from calimero with my arduino code. It was just missing a Transport-Data-Ack-PDU after the propread-request ...
Now it seems to work fine.
Is there an estimation when 2.2.1 stable will be available?
v2.2.1 stable is available. Multicast loopback on client-side is disabled by default.
Hi there,
I'm trying to extend an existing KNX Library for arduino microcontroller to be able to read/write properties and read/write memory on the arduino, using KNX and Calimero.
One thing upfront: Is must not necessarily be knx-spec-conform. The important point is: it must just work somehow ;-)
So, what I'm trying to do is the following:
Using calimero with a KNX IP Router to read property of arduino knx device with individual address 1.1.251.
I already setup the arduino so that it responds with a propertyread-answer. But calimero does not recognise it. So i stepped through the calimero code to get an idea what is missing from arduino code and stumbled on something I don't understand:
While the main-thread is busy with sending the T_CONNECT_REQ_PDU (which, according to calimero code does not need to be ack'ed due to routing mode), the connect from calimero 1.1.250 to arduino 1.1.251 is received on calimero on "Link notifier" thread, which does send's a "disconnect" to the source, means: Calimero sends a disconnect three times to itself ...???!
... while arduino is answering the propertyread-request.
So my questions are:
1) Why is calimero doing a disconnect? In source (2.2.1-beta) TransportLayerImpl I found at line 478:
What does this mean? Dont allow client side? Is this a kind of bug?
2) Is calimero able to do property read/write as well as mem read/write in such a way (without too much code-overhead)? 3) If question nr.2 can be answered with "yes": How should a really simple code-snippet look like? Keep in mind: Is must not be knx-spec-conform. It's sufficient if the arduino can be programmed with a special-calimero-powered-tool. 4) If question nr.2 can be answered with "yes": Do you already see something missing from arduino side? any ACK message? Something else? Or do you see something else that hinders calimero from getting the response properly? It's really hard for me to get through all the documents and find the correct workflow... So I appreciate any hint on what else is missing.
br, Alex