I created a Chat application in Android and using Smack API (4.1.7) to communicate Chat Server.
In android device, If I switched to Airplane Mode or Connection Dropped, getting SocketException
Please guide me to prevent from this exception
W/AbstractXMPPConnection: Connection closed with error
java.net.SocketException: recvfrom failed: ETIMEDOUT (Connection timed out)
at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:592)
at libcore.io.IoBridge.recvfrom(IoBridge.java:556)
at java.net.PlainSocketImpl.read(PlainSocketImpl.java:485)
at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
at java.io.InputStreamReader.read(InputStreamReader.java:231)
at java.io.BufferedReader.read(BufferedReader.java:325)
at org.jivesoftware.smack.util.ObservableReader.read(ObservableReader.java:41)
at org.kxml2.io.KXmlParser.fillBuffer(KXmlParser.java:1515)
at org.kxml2.io.KXmlParser.peekType(KXmlParser.java:992)
at org.kxml2.io.KXmlParser.next(KXmlParser.java:349)
at org.kxml2.io.KXmlParser.next(KXmlParser.java:313)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1173)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:952)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:967)
at java.lang.Thread.run(Thread.java:818)
Caused by: android.system.ErrnoException: recvfrom failed: ETIMEDOUT (Connection timed out)
at libcore.io.Posix.recvfromBytes(Native Method)
at libcore.io.Posix.recvfrom(Posix.java:185)
at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:250)
at libcore.io.IoBridge.recvfrom(IoBridge.java:553)
This is my connection code
XMPPTCPConnectionConfiguration.Builder configBuilder = XMPPTCPConnectionConfiguration.builder();
configBuilder.setServiceName(UserController.getHost());
configBuilder.setHost(UserController.getHost());
configBuilder.setPort(UserController.getPort());
configBuilder.setSendPresence(true);
configBuilder.setDebuggerEnabled(true);
configBuilder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
connection = new XMPPTCPConnection(configBuilder.build());
// XMPP Connection Listener monitor
connection.addConnectionListener(new ConnectionListener() {
#Override
public void connected(XMPPConnection connection) {
service.sendConnectionUpdate(WhatTimeGlobal.SERVER_CONNECTED);
}
#Override
public void authenticated(XMPPConnection connection, boolean resumed) {
service.sendConnectionUpdate(WhatTimeGlobal.SERVER_CONNECTED);
}
#Override
public void connectionClosed() {
}
#Override
public void connectionClosedOnError(Exception e) {
if (CommonUtils.isInternetAvailable() && connection != null) {
XMPPService.getInstance().loginIntoServer();
}
}
#Override
public void reconnectionSuccessful() {
Log.i("", "Successfully reconnected to the XMPP server.");
}
#Override
public void reconnectingIn(int seconds) {
Log.i("", "Reconnecting in " + seconds + " seconds.");
}
#Override
public void reconnectionFailed(Exception e) {
XMPPService.getInstance().loginIntoServer();
}
});
// Configure the Auth Mechanism - Current moment set it as PLAIN
configureAuthMethod();
connection.setUseStreamManagement(true);
XMPPTCPConnection.setUseStreamManagementResumptionDefault(true);
XMPPTCPConnection.setUseStreamManagementDefault(true);
connection.setPacketReplyTimeout(100000);
Roster roster = Roster.getInstanceFor(connection);
roster.setRosterLoadedAtLogin(false);
connection.connect();
You can not prevent this exception. You should handle it (e.g. schedule a reconnect).
Related
How can I set the comet event timeout on NIO2 protocol?
How to well handle the socket connection on NIO2 protocol?(e.g., close connection)
We have a simple servlet which implements Apache CometEvent for long polling connection on tomcat8. It works well when we used org.apache.coyote.http11.Http11NioProtocol, however, we have now change to using org.apache.coyote.http11.Http11Nio2Protocol and it will not work properly.
On NIO, the client can make a comet connection to a Connect servlet by POST and the other client can send message by POST to Trigger servlet. Every 300 seconds we will timeout the comet and the client app will make comet connection again.
The Connect servlet as below
public class Connect extends HttpServlet implements CometProcessor {
...
public void event(CometEvent event) throws IOException, ServletException {
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
if (event.getEventType() == CometEvent.EventType.BEGIN) {
String deviceid = request.getParameter("id");
MessageSender.getInstance().addConnection(deviceid, event);
request.setAttribute("org.apache.tomcat.comet.timeout", 300 * 1000);
event.setTimeout(300 * 1000);
} else if (event.getEventType() == CometEvent.EventType.ERROR) {
MessageSender.getInstance().removeConnection(event);
event.close();
} else if (event.getEventType() == CometEvent.EventType.END) {
MessageSender.getInstance().removeConnection(event);
event.close();
} else if (event.getEventType() == CometEvent.EventType.READ) {
throw new UnsupportedOperationException("This servlet does not accept data");
}
}
}
And we have another Trigger servlet for sending message to client:
public class Trigger extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
byte[] receieveByteArray = ByteUtil.getHttpServletRequestBody(req);
sendTrigger(req, resp, receieveByteArray);
}
private void sendTrigger(HttpServletRequest req, HttpServletResponse resp, byte[] trigger) throws IOException, ServletException
{
try
{
MessageSender.getInstance().sendTrigger(deviceId, trigger);
} catch (Exception e)
{
logger.error("Send trigger has thrown exception: ", e);
}
}
}
And the MessageSender class as below
public class MessageSender
{
private static final Map<String, CometEvent> connections = new ConcurrentHashMap<String, CometEvent>();
public void addConnection(String deviceId, CometEvent event) {
connections.put(deviceId, event);
}
public void removeConnection(CometEvent event) {
while (connections.values().remove(event)) {
}
public static MessageSender getInstance() {
return instance;
}
public void sendTrigger(String deviceId, byte[] triggerMessage) throws IOException, ConnectionNotFoundException {
CometEvent comet = connections.get(deviceId);
HttpServletResponse response = comet.getHttpServletResponse();
response.addHeader("Content-Length", Integer.toString(triggerMessage.length));
response.addHeader("Content-Language", "en-US");
ServletOutputStream servletOutputStream = response.getOutputStream();
servletOutputStream.write(triggerMessage);
servletOutputStream.flush();
servletOutputStream.close();
comet.close(); // add for NIO2
connections.remove(deviceId);
}
}
After we have changed the connector setting of tomcat http protocol to NIO2 as below
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" connectionTimeout="60000"
keystoreFile="D:\localhost.jks" keystorePass="******" />
The timeout of event will not work as we have set it to 300 seconds, the comet connection will be disconnected after 60 seconds which I believe is the connector connection timeout. And there will have thrown an exception as below
28-Oct-2016 15:04:33.748 SEVERE [http-nio2-8443-exec-5] org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process Error reading request, ignored
java.lang.IllegalStateException: Reading not allowed due to timeout or cancellation
at sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:249)
at sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297)
at org.apache.tomcat.util.net.SecureNio2Channel.read(SecureNio2Channel.java:792)
at org.apache.tomcat.util.net.Nio2Endpoint.awaitBytes(Nio2Endpoint.java:871)
at org.apache.coyote.http11.Http11Nio2Protocol$Http11ConnectionHandler.release(Http11Nio2Protocol.java:180)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:722)
at org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.doRun(Nio2Endpoint.java:1073)
at org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.run(Nio2Endpoint.java:1032)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
If the client make the comet connection again after this, and the other client try to send message to Trigger servlet. The comet will be END immediately and connection disconnected.
Any help is appreciated
I am running Netty 4.2 socket communication code with ssl (self signed certificate).
My Problem:
When client tries to connect to server with SSL, server immediately drops the connection. Server triggers channelUnregistered() method immediately.
One point I noticed is, very first time once the server started, client connection holds and works fine. But when client disconnects and try to connect to Server again, it drops the connection immediately.
But without SSL it works fine without any issues.
Client Code:
public Channel initializeNettySocket()
{
group = new NioEventLoopGroup();
try
{
ClientAdapterInitializer clientAdapterInitializer = null;
if (ServerSettings.isUseSSL())
{
// SSLEngine engine = SSLContextFactory.getClientContext().createSSLEngine();
SSLEngine engine = SSLContext.getDefault().createSSLEngine(host,port);
engine.setUseClientMode(true);
clientAdapterInitializer = new ClientAdapterInitializer(engine);
}
else
{
clientAdapterInitializer = new ClientAdapterInitializer();
}
Bootstrap bootstrap = new Bootstrap().group(group).channel(NioSocketChannel.class).handler(clientAdapterInitializer);
channel = bootstrap.connect(host,port).sync().channel();
Thread.sleep(3000);
setChannel(channel);
}
catch (Exception e)
{
System.out.println(e.getMessage());
e.printStackTrace();
}
return channel;
}
public class ClientAdapterInitializer extends ChannelInitializer<SocketChannel>
{
private SSLEngine sslCtx = null;
public ClientAdapterInitializer(SSLEngine sslCtx)
{
this.sslCtx = sslCtx;
}
public ClientAdapterInitializer()
{
}
#Override
protected void initChannel(SocketChannel channel) throws Exception
{
ChannelPipeline pipeline = channel.pipeline();
if (ServerSettings.isUseSSL())
{
// Add SSL handler first to encrypt and decrypt everything.
// In this example, we use a bogus certificate in the server side
// and accept any invalid certificates in the client side.
// You will need something more complicated to identify both
// and server in the real world.
//pipeline.addLast(sslCtx.newHandler(ch.alloc(), SecureChatClient.HOST, SecureChatClient.PORT));
pipeline.addLast(new SslHandler(sslCtx));
}
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new ClientAdapterHandler());
}
Server side code
public class ServerAdapterInitializer extends ChannelInitializer<SocketChannel>
{
private SSLEngine sslEngine;
public ServerAdapterInitializer(SSLEngine sslEngine)
{
this.sslEngine = sslEngine;
}
public ServerAdapterInitializer()
{
}
#Override
protected void initChannel(SocketChannel channel) throws Exception
{
ChannelPipeline pipeline = channel.pipeline();
if (sslEngine != null)
{
pipeline.addLast(new SslHandler(sslEngine));
}
Listeners.getInstance().getAllListeners().size();
RTReceiverAdapterHandler rtReceiverAdapterHandler = new RTReceiverAdapterHandler();
pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, 10)); // add
// with
// name
pipeline.addLast("decoder", new MyStringDecoder(rtReceiverAdapterHandler));
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", rtReceiverAdapterHandler);
}
}
public class RTReceiverAdapterHandler extends ChannelInboundHandlerAdapter
{
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
if (ServerSettings.isUseSSL())
{
// Once session is secured, send a greeting and register the channel
// to the global channel
// list so the channel received the messages from others.
ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(new GenericFutureListener<Future<Channel>>()
{
#Override
public void operationComplete(Future<Channel> future) throws Exception
{
ctx.writeAndFlush("Welcome!\n");
ctx.writeAndFlush("Your session is protected by " + ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite()
+ " cipher suite.\n");
channels.add(ctx.channel());
}
});
}
else
{
super.channelActive(ctx);
}
}
}
The problem was not with the code at all. We have nginx web server configured with SSL before my application. This entry in nginx 'ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL;' was the culprit which was not allowing to access the netty server.
I commented the above entry in ngnix and my problem was resolved.
I have tried to establish chat connection between two users using xmpp and OpenFire. But i am not able to send and receive message. I have pasted my code below for reference. Any help will be very helpful.
I established a connection with Smack by
XMPPTCPConnectionConfiguration.Builder config = XMPPTCPConnectionConfiguration.builder();
config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
config.setUsernameAndPassword("admin", "admin");
config.setServiceName("172.21.4.199");
config.setHost("172.21.4.199");
config.setPort(5222);
config.setDebuggerEnabled(true);
config.setConnectTimeout(50000);
XMPPTCPConnection connection = new XMPPTCPConnection(config.build());
XMPPTCPConnection.setUseStreamManagementResumptiodDefault(true);
XMPPTCPConnection.setUseStreamManagementDefault(true);
try {
connection.setPacketReplyTimeout(50000);
connection.connect();
Log.d(TAG, "SetupDefaults -- Connected");
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "SetupDefaults -- Connection failed exc: "+e);
}
and its gets succesfully connected. And i try to send a chat by using
ChatManager chatManager = ChatManager.getInstanceFor(connection);
Chat chat = chatManager.createChat("user2#server.local", new ChatMessageListener() {
#Override
public void processMessage(Chat chat, Message message) {
System.out.println("processMessage -- Sent message: " + message);
}
});
try {
chat.sendMessage("Hai.. Lets we chat!");
}catch (Exception e){
Log.d(TAG, "sendChat Exc: "+e.toString());
}
But i couldn't find that processMessage gets triggered. Because that S.O.P doesn't gets triggered. But i gets
SMACK: SENT (0): Hai.. Lets we chat!
SMACK: RECV (0): Hai.. Lets we chat!
in my console while sending a chat.
Simillarly i use,
PacketListener packetListener = new PacketListener() {
#Override
public void processPacket(Stanza packet) throws SmackException.NotConnectedException {
Message message = (Message)packet;
String from = message.getFrom();
String body = message.getBody();
System.out.println("Message from: " + from + " " + body);
}
};
connection.addPacketListener(packetListener, filter);
to receive the chat. But processPacket also doesn't gets triggered.
PacketListner it's something much more general to handle stanzas, it's not what you really need. You just need a ChatMessageListner
ChatManager chatManager;
chatManager = ChatManager.getInstanceFor(connection);
chatManager.addChatListener(
**new ChatManagerListener() {
#Override
public void chatCreated(Chat chat, boolean createdLocally)
{
if (!createdLocally)
{
chat.addMessageListener(new IncomingMessageListener());;
}
}
})**;
Basic implementation:
class IncomingMessageListener implements ChatMessageListener {
#Override
public void processMessage(Chat arg0, Message message) {
String from = message.getFrom();
String body = message.getBody();
if (body != null)
{
System.out.println(String.format("============ Received message '%1$s' from %2$s\n============", body, from));
guiUpdate.displayMessage(body); /* custom method */
}
else
{
System.out.println("SYSTEM: ping");
}
}
I have search every for the method used in enabling stream management in smack and nothing is working for me
This function isSmAvailable() always return false, am using prosody as the XMPP server in which the smacks[mod_smacks] is installed and enabled below is my code
XMPPTCPConnectionConfiguration.Builder configureBuilder = XMPPTCPConnectionConfiguration.builder();
configureBuilder.setServiceName(Config.XMPP_HOST);
configureBuilder.setHost(HOST);
//configureBuilder.allowEmptyOrNullUsernames();
configureBuilder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
//configureBuilder.setDebuggerEnabled(true);
SmackConfiguration.DEBUG = true;
xmppConnection = new XMPPTCPConnection(configureBuilder.build());
Roster.setDefaultSubscriptionMode(Roster.SubscriptionMode.accept_all);
XMPPTCPConnection.setUseStreamManagementResumptiodDefault(true);
//PingManager
xmppConnection.setUseStreamManagement(true);
xmppConnection.setUseStreamManagementResumption(true);
ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(xmppConnection);
reconnectionManager.enableAutomaticReconnection();
try {
MyLog.w("Connecting to xmpp server");
xmppConnection.setPacketReplyTimeout(100000);
xmppConnection.connect();
//xmppConnection.sendSmAcknowledgement();
if (xmppConnection.isSmEnabled()) {
MyLog.w("stream M is enabled");
} else {
MyLog.w("stream M is not enabled");
}
if (xmppConnection.isSmAvailable()) {
MyLog.w("stream M available");
} else {
MyLog.w("stream M is not available");
}
//xmppConnection.
xmppConnection.addConnectionListener(new ConnectionListener() {
#Override
public void connected(XMPPConnection xmppConnection) {
//logger.warning("Connected to server successfully");
MyLog.w("Connected to server");
}
#Override
public void authenticated(XMPPConnection xmppConnect, boolean b) {
//logger.warning("Nice it is authenticated too");
MyLog.w("Finally logged into the server");
}
#Override
public void connectionClosed() {
//logger.warning("Connected to server failed");
}
#Override
public void connectionClosedOnError(Exception e) {
//logger.warning(e.getMessage());
MyLog.w("Connection close on error" + e.getMessage());
}
#Override
public void reconnectionSuccessful() {
//I think here we need to relogin the user
MyLog.w("Reconnected successfully ....thanks to RC");
}
#Override
public void reconnectingIn(int i) {
}
#Override
public void reconnectionFailed(Exception e) {
MyLog.w("Reconnection Failed " + e.getMessage());
}
});
} catch (Exception e) {
MyLog.w("connected-error" + e.getMessage());
}
I tried adding streamFeature for stream management using
xmppConnection.addStreamFeature() but it tells me that the function is private
and also through ProviderManager.addStreamFeature(element, namespace, provider) is also not working
Can you please help me to figure this out or there is something am doing wrong here
Thanks
Check your ejabbered config file for stream management is enable or not.
stream_management: true
resend_on_timeout: true
resume_timeout: 300
In android code you just add to below line to enable stream management in your app.
static{
XMPPTCPConnection.setUseStreamManagementDefault(true);
XMPPTCPConnection.setUseStreamManagementResumptionDefault(true);
}
This piece of code is working for me having ejabbered on server side--
XMPPTCPConnectionConfiguration connConfig = XMPPTCPConnectionConfiguration.builder()
.setHost(HOST)
.setPort(PORT)
.setDebuggerEnabled(true)
.setSecurityMode(SecurityMode.disabled)
.setUsernameAndPassword(USERNAME, PASSWORD)
.setServiceName(SERVICE).build();
XMPPTCPConnection connection = new XMPPTCPConnection(connConfig);
connection.setUseStreamManagement(true);
connection.setPacketReplyTimeout(TIME_OUT);
connection.connect();
connection.login();
javax.microedition.io.ConnectionNotFoundException: error 10061 in socket::open
I have this error with j2me - in execution.
I tried searching, but it didn't help.
Code:
Connector.open("socket://127.0.0.1:7777")
According to ConnectionNotFoundException documentation "This class is used to signal that a connection target cannot be found, or the protocol type is not supported".
socket is a supported protocol, so the connection target cannot be found. Be sure that 127.0.0.1:7777 is up, running and that is does support receiving a Socket connection.
You may try below Java code:
public class Server {
static boolean done = false;
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(7777);
while (!done) {
final Socket socket = server.accept();
new Thread() {
public void run() {
treatSocket(socket);
}
}.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
static void treatSocket(Socket socket) {
// treat socket data
}
}