summaryrefslogtreecommitdiffstats
AgeCommit message (Collapse)Author
2016-04-20Remove use of Java 7 SocketChannel.getRemoteAddress()Alan Young
Not supported on Android. Change-Id: I55551ceeed06ab1ff4ce9e5995f809466d0e69bd
2016-03-15Add getRemoteAddress() method to Connection.Alex Clayton
Added a getRemoteAddress() method to connection as per patch 'Listen to IPv6 any address instead of only IPv4' (13801557b6664426cac26384441ab0b19ff9abb5). Also some modifications to SOCKS5BytestreamServerManager to use IPv6 address. Test-information: Unit tests pass ok. Change-Id: Ic0536745db9052ec1c5fc0832ed90eb5ec609429
2015-09-11Add JavaConnection.ActivityWatcher for watching connection activity.Alan Young
If a JavaConnection is supplied with a JavaConnection.ActivityWatcher at creation time, then each of its Worker threads will signal when they become active and when they potentially go to sleep (on select()). This allows clients to manage a device's power state or any other suitable subsystem. Change-Id: I3c83cb8ce5a087dd6fc5d402c75f830f5deca282
2015-09-11Improve efficiency of JavaConnection reads.Alan Young
Given that doRead() ends up populating a SafeByteArray as part of the result is is more efficient to pass an empty SafeByteArray to doRead() and push each chunk of data read directly to the it rather than use an intermediate ByteArrayOutputStream. SafeByteArray.getData() will do any concatenation necessary. It is unnecessarily inefficient to use a class instance to return the connection status from doRead. Remove JavaConnection.ReadResult. Change-Id: I6c8dc000d9030d3929c71444eb5b489df93f1987
2015-09-11Make JavaConnection fully event driven - no 100ms spinAlan Young
Refactor JavaConnection to make it fully event-driven via select for both reads and writes. Remove the 100ms spin when there are pending writes. Encapslate all the management of the select mask and the write queue within Worker and protect via a common lock. Change-Id: I1a709f9b12a949448923f51c2d434746c9190c9d
2015-07-28Fixed CancelledKeyException in JavaConnectionPeter Ballard
If synchroniseReads was enabled then if was possible for CancelledKeyExceptions to occur if the channel closed, whilst data was being procsessed on the event loop. I have also made the selectorKey_ reference volatile as this is used by both threads since my previous change 1afab8c1f2c417b08371bc12569e03171851d785 Change-Id: I48edcab9ef090b8a4561331d6aecc7f95cb8924d
2015-07-28Complete StreamStack and add tests.Tarun Gupta
TLSLayer could not be updated because it requires TLS to be ported first. Updates other classes, only for having compatibility with SafeByteArray because of updates in Stream Stack. License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details. Test-Information: Tests added for StreamStack and XMPPLayer, which passes. Change-Id: I8707fc1f16d622d2a90f6f39f671b7e7c46aa170
2015-07-08Add option to only read from TCP socket when previous read has been processedPeter Ballard
By default this option is disabled, existing usages will function as normal. This option stops the JavaConnection from reading data if the previous read has not been processed by the event loop. Previously constrained devices were seeing OutOfMemoryErrors, if they were not able to process the incoming data quick enough. This change does not affect the write behavour. Change-Id: I47bc0eafba32336f5bf250ccb1fea530f51d328e
2015-05-13Make sure Stroke clears write buffer before disconnectingAlex Clayton
There was a bug with stroke where if I sent a large amount of messgaes (cica 1000) and then disconnected, not all the messages would be sent before storke handled the disconnect. It seems it did not fully lear the write buffer before closing the stream. This patch shoudl fix the error. It now only closses if the disconnecting flag is closed and the write buffer is closed. This should bring it into line with Swiften behaviour. Test-information: I had a simple stroke application that sent 1000 messages and then disconnected. Before the patch it would only send abut 80 or so of the messages before it got disconnected. After the patch it now sends all the messages before disconnecting. Change-Id: I6f56b25dcbabd16ee860dbf353f39559a77d6830 Signed-off-by: Alex Clayton <alex.clayton@isode.com>
2015-05-01Revisit handling of JavaConnection race conditions.Alan Young
JavaConnection.disconnect() can be called at any time when opening or using the connection. Its use can interfere with tests for selector_.isOpen(). Protect relevant code by synchronization blocks. This should not cause any contended synchronization issue as contention can only occur while disconnecting. This reverts the relevant part of 7d2101b9. Move selector_.select() call to end of Worker.run() while loop so that any write that is done while still connecting (if that is permitted and possible), and before selector_ first become non-null, is still picked up. Remove redundant checks on disconnecting_ and calls to handleDisconnected(null). Move a couple of fields which are only used in Worker nested class into Worker. Update copyright. Change-Id: I2eabad79c69fe4e9206942c8025e0ac012bffdb0
2015-04-10Checkpoint - A bunch of initial stuff for AndroidAlan Young
MemoryStorages, Storages NickManager, NickResolver CryptoProvider, Hash, SafeByteArray, JavaCryptoProvider CapsInfoGenerator, CapsManager, CapsMemoryStorage, CapsProvider, CapsStorage, CapsInfo CapsInfoSerializer, CapsInfoParser ClientDiscoManager, DiscoInfoResponder, EntityCapsManager, EntityCapsProvider GetDiscoInfoRequest ChatState, Idle Presence, PayloadAddingPresenceSender, PresenceOracle, SubscriptionManager StatusSerializer, StatusShowSerializer, StatusParser, StatusShowParser, Replace, ReplaceParser, ReplaceSerializer SecurityLabel, SecurityLabelsCatalog, GetSecurityLabelsCatalogRequest VCard, GetVCardRequest, SetVCardRequest, VCardManager, VCardMemoryStorage, VCardStorage RosterMemoryStorage, RosterPushResponder, RosterStorage, SetRosterRequest XMPPRoster, XMPPRosterController, XMPPRosterImpl, XMPPRosterItem GetRosterRequest, SetResponder Add parsers and serializers for Idle, VCard, PrivateStorage & Stroage. Add parser for Subject. Add impromptu flag to MUCInvitation. Update copyrights. Change-Id: I9949f506b70e60b3a64f1dadde8f9b235b322e1d
2015-01-13Don't call wakeup on closed selectorsNick Hudson
This operation should be valid according to Javadocs, but triggers a crash on Android Lollipop: https://code.google.com/p/android/issues/detail?id=80785 This workaround avoids the crash, and should not affect behaviour for all other versions. Test-information: Forced disconnect on Lollipop, didn't see crash. Tested MLC with deliberately dropped connections; seems to work as expected. Change-Id: Ia08476266dd92c40bea04076b3c3d8750737c309 Reviewer: Nick Hudson <nick.hudson@isode.com>
2014-10-24Don't disregard data that arrives on network just prior to socket closingNick Hudson
The JavaConnection code which reads from a socket detects a socket closure and emits a disconnected signal. It was noticed that on some occasions, data was arriving on the socket just before it was closed, and this data was never passed to the application. This happens when the server writes e.g. a "BYE" message and closes the socket straight away: when JavaConnection is woken to read the message, it does so and then goes on to notice that the connection has been closed and throws an IOException without passing the message back to the application. This patch fixes the problem by making sure that any data read prior to the close being noticed is sent to the application before the closed signal is emitted Test-information: It was possible to provoke the problem by deliberately breaking socket connections - if you do this often enough you see cases where data read from the socket is lost. After this patch, such cases do not result in data loss. Also tested with email client and verified that connections to icloud.com which previously had provoked this problem when authentication failed now seem to return all data reliably. Change-Id: Ieba0f4186b7c91e55f5f1a4b3b64bc923006b933
2014-10-24Fix JavaConnection to emit onDataWritten when it writes data to the socketNick Hudson
The java code was never emitting the onDataWritten signal, although the corresponding C++ code in Swiften does do this. This change causes the signal to be emitted whenever a data is successfully written to the socket. Test-information: Tested using an application which was registering for the signal; previously it never saw "onDataWritten"; now it does. Tested using an application which doesn't register for the signal; it works as before. Change-Id: I1399af0721ef8226c0c4d2420bbe23f53ad3494f
2013-10-15Revert "synchronized" patch and fix use of ByteArray inside JavaConnectionNick Hudson
Some discussion followed the "Fix synchronization problem in ByteArray" patch, and that led us to believe that it would be better to change the JavaConnection class so that it does not rely on being able to pass ByteArrays around in a way that makes them vulnerable to the problems that had been seen. The JavaConnection class accepts a ByteArray in its "write()" method, and emits a ByteArray when it has read data. ByteArrays are not the ideal way for the JavaConnection class to manipulate data and so this patch changes the implementation so that: a) the "write()" method extracts the byte[] from the supplied ByteArray and uses these objects, rather than keeping references to the ByteArray objects (which might lead to synchronisation issues). b) the "doRead()" method uses a ByteArrayOutputStream to hold incoming data, and only constructs a ByteArray out of it when it is ready to return the data to the application. These changes make the class more efficient, since in the case of (a), the need to create temporary ByteArrays is removed, and in (b) the code no longer creates ByteArrays by iterating through the network data one byte at a time and appending it to a ByteArray. It also means that the "synchronized" patch (which would fix the problem) is no longer necessary, and so that code is reverted. Test-information: I patched the code to emulate the situation that would occur when a buffer is only partially written, and verified that in this case it correctly re-inserted the unwritten portion of the buffer at the front of the pending queue. Ran MLC to various servers, all seems to work OK. Tested in Harrier, seems to work OK, and does not exhibit problems that we had seen previously which led us to investigate this issue. Change-Id: Ifcda547402430c87da45ba7d692518b5af285763 Signed-off-by: Nick Hudson <nick.hudson@isode.com>
2013-08-12Null check for selector before trying to close itGurmeen Bindra
It is possible to have a null selector if socketchannel open failed so adding a null check in this patch. Test-information: sanity tested on linux by connecting/reconnecting on an xmpp service on linux Change-Id: Idee180ca4aefd1f743705da674b486dd8acc4922 Reviewer: Nick Hudson <nick.hudson@isode.com> Reviewer: Kevin Smith <kevin.smith@isode.com>
2013-08-09Close selector with socketchannelGurmeen Bindra
I left MLC which is an XMPP Client running overnight and noticed "Too many open files" error when trying to stop/start xmpp server. On doing an "lsof | grep java", I noticed a large number of open sockets which was presumably the cause of this error. After this patch, the lsof command shows a constant number of open sockets. Test-information: tested on centos vm by doing "lsof | grep java " wc-l"-open sockets do not increase. Change-Id: I7ddff78a1efb005177427fda21f1d0b92d8ed7cc Reviewer: Kevin Smith <kevin.smith@isode.com>
2013-07-26Re-implement JavaConnection to use SelectorNick Hudson
When investigating problems on Solaris, attention focused on the JavaConnection class, whose implementation appeared to be non-optimal. The original implementation had a loop which operated on a non-blocking socket, and looked something like this: while (!disconnecting) { while (something to write) { write data to socket; if write failed { sleep(100); // and try again } } try reading data from socket if (any data was read) { process data from socket; } sleep(100); } Because the socket is non-blocking, the reads/writes return straight away. This means that even when no data is being transferred, the loop is executing around ten times a second checking for any data to read/write. In one case (Solaris client talking to Solaris server on the same VM) we were consistently able to get into a state where a write fails to write any data, so that the "something to write" subloop never exits. This in turn means that the "try reading data" section of the main loop is never reached. Investigation failed to uncover why this problem occurs. The underlying socket appears to be returning EAGAIN (equivalent to EWOULDBLOCK), suggesting that the write fails because the client's local buffer is full. This in turn implies that the server isn't reading data quickly enough, leading to the buffers on the client side being full up. But this doesn't explain why, once things have got into this state, they never free up. At any rate, it was felt that the implementation above is not ideal because it is relying on a polling mechanism that is not efficient, rather than being event driven. So this change re-implements JavaConnection to use a Selector, which means that the main loop is event-driven. The new implementation looks like this while (!disconnected) { wait for selector if (disconnected) { break; } if something to write { try to write data; } if something to read { try to read data; } if still something to write { sleep(100); post wake event; // so that next wait completes straight away } } Test-information: Testing appears to show that the problems we saw on Solaris are no longer seen with this patch (Solaris tests still fail, but later on, which appears to be due to a separate problem). Testing shows that this leads to the thread spending much more time idle, and only being active when data is being read/written (unlike the original implementation which was looping ten times a second regardless of whether any data was being read/written). Testing using MLC seems to show the new implementation works OK. I was unable to provoke the "write buffer not completely written" case, so faked it by making the doWrite() method constrain its maximum write size to 200 bytes. By doing this I verified that the "leftOver" section of code was working properly (and incidentally fixed a problem with the the initial implementation of the patch that had been passing the wrong parameter to System.arrayCopy). Change-Id: I5a6191567ba7e9afdb9a26febf00eae72b00f6eb Signed-off-by: Nick Hudson <nick.hudson@isode.com>
2012-08-20Close socketChannel in finally blockGurmeen Bindra
In one of my testing scenario, socket was not getting closed. This was happening when an XMPP client was connecting to a domain which was different from the domain in the jabber ID of the connection user. Moving the close call to a finally block ensures that socket gets closed in all scenarios. Test-information: I created an IM domain j.com on my XMPP Server and then added a user with that domain (user@j.com). Then I tried connecting to my Primary domain using this new user. After removing j.com, I could an increase in number of sockets after every poll (coreclient.connect()) but not after this patch.
2012-04-20Also emit onDisconnected after a manual disconnectKevin Smith
2012-03-13Fix up mistakes in previous patchNick Hudson
I broke the "getLocalAddress()" method. This fixes it. Test-information: By debugging and looking at "JavaConnection.toString()" output
2012-03-13Update JavaConnection to use SocketChannel rather than SocketNick Hudson
The initial implementation of JavaConnection used the "Socket" class, from which it derived InputStream and OutputStream objects to read/write data. In order to avoid blocking, the "read" loop would only attempt to read data if the InputStream.available() method indicated that there was data ready to be read. However, in order to determine that an InputStream has been closed, you have to read from it and have it return -1 to indicate "end-of-stream". There was no explicit test for a -1 return, but even if there had been, it wouldn't have tripped, because of the "available()" test. So this change makes JavaConnection use "SocketChannel" rather than Socket, which allows (when you configure the SocketChannel to be non-blocking) you to issue non-blocking reads which *can* return -1 when the input stream has finished. Test-information: Tested with test program and MLC, using both TLS and non-TLS connections. Applications still work as expected. Observed that when I deliberately stop the server, or break the socket connection, the client almost immediately gets a "disconnected" signal. Prior to this change, stopping the server results in the client getting a disconnected signal only when it next tries to write something.
2012-02-13Tidying up based on feedback from patch for initial TLS implementationNick Hudson
Hopefully the changes speak for themselves. Some feedback relating to JavaCertificate has not been addressed; that will be done in a separate patch Test-information: Can still establish sessions with / without TLS
2012-02-13Initial implementation of TLS supportNick Hudson
Note that TLS won't be enabled with this patch unless you uncomment the change in PlatformTLSFactories. With that comment removed, then a new CoreClient session will attempt to negotiate TLS if the server supports it. Further changes are required to support this properly, as there appears not to be comprehensive support in the CoreClient class for dealing with situations when the server's certificate is not acceptable. There's also no support yet for setting up client certificates. Further changes will also be needed (see below) to support full parsing of subjectAltNames from server certificates. Significant changes are as follows - TLSProceed - FIXME comments removed - JavaConnection - changed so that it reads bytes from the socket's InputStream, rather than reading chars and then constructing a String out of them from which a byte array is then extracted. While this seemed to work for non-binary data (e.g. non-encrypted XMPP sessions), it breaks when you start sending binary (i.e. TLS) data. - JavaTLSConnectionFactory - implemented - PlatformTLSFactories - By having this return a JSSEContextFactory, then this will cause the client to try TLS if possible. But because other changes are needed to make this work properly, the current code still returns null. - JSSEContext - new class which uses an SSLEngine to handle TLS handshake and subsequent encryption/decryption. This is the main substance of the SSL implementation Note the "hack" in here to cope with SSLEngine requiring that some data be sent from the application before it will do a TLS handshake - JSSEContextFactory - just creates JSSEContexts - JavaCertificate - this wraps an X509Certificate and does *some* of the parsing of a certificate to look for stuff that is expected when verifying an XMPP server certificate (RFC 6120 and RFC 6125). Note that the JDK classes for parsing certificates don't provide an easy way to decode "OTHER" subjectAltNames, and so this implementation does not find XMPP or SRV subjectaltnames from the server certificate. This will need extra work. - JavaTrustManager - obtains the server certificate from the TLS handshake and verifies it. Currently the only verification done is to check that it's in date. More work will be needed to perform proper validation - Where necessary, Remko's copyright comments were changed from GNU to "All rights reserved". Isode copyright notices updated to "2012" Test-information: Set up XMPP server with its own certificate, and checked that TLS gets negotiated and starts OK (provided the server cert contains e.g. a DNS subjectAltName matching its own name). Subsequent operation appears to be as expected.
2012-01-18Add toString to some more classesNick Hudson
Also made "Stanza" be an abstract class and had its ".toString()" include the name of the subclass which is involved, so that the subclasses don't have to do that themselves. Also added null check to existing HostAddress.toString() method Also fixed Remko copyright in Connector class Test-information: Stuff is displayed as expected in debugger.
2011-10-31Fix utf-8 encoding on Remko's name throughout. Now compiles with Java 7Kevin Smith
2011-07-01Initial importKevin Smith