WebSocket Server Implementation at Xamarin Studio 5 Android Project - android

I am working on WebSocket server implementation on Xamarin for an Android project, here I have Monoframework MDK 3.10.0.23 and Xamarin.android 4.18 which are latest ones.
For server implementation I'm using HttpListener and HttpListenerContext and evaluating the context.Request.IsWebSocketrequest, which is always getting false, when I run it on a Google Nexus 10.
{
Console.WriteLine("WS Server Started Waiting for connection");
HttpListenerContext httpListenerContext = await httpListener.GetContextAsync();
if (!httpListenerContext.Request.IsWebSocketRequest)
{
WebSocketContext webSocketContext;
Console.WriteLine("Got a Valid WebSocket connection request");
try
{
webSocketContext = await httpListenerContext.AcceptWebSocketAsync(subProtocol:null);
}
catch (Exception e)
{
httpListenerContext.Response.StatusCode = 500;
httpListenerContext.Response.Close();
Console.WriteLine("Exception: {0}", e);
return;
}
WebSocket webSocket = webSocketContext.WebSocket;
if (webSocket == null)
Console.WriteLine ("WebSocket obj is null");
//ProcessRequest(httpListenerContext);
}
else
{
Console.WriteLine("Got a Bad WebSocket connection request");
httpListenerContext.Response.StatusCode = 400;
httpListenerContext.Response.Close();
}
}
Please help and suggest the problem here creating the HttpListener object for http:// local host at 9090

websockets initiates connection via http with the request to upgrade. if the server do not reply with the 101 response code, it is a sign that there is a problem in connection. the request to connect via websockets uses ws://yourdomain.com/nameOfApplicationEndPoint or wss in cases of ssl connection. i used this for my android project org.java-websocket:Java-WebSocket:1.3.0 and you can get a simple example here http://www.elabs.se/blog/66-using-websockets-in-native-ios-and-android-apps

Related

TcpClient.ConnectAsync and TcpClient.BeginConnect always returning true in Xamarin.Forms Android Application

I have made an application in my Xamarin.Forms project where I can connect my Android phone to my Computer using a TCP connection. I have found while using both TcpClient.ConnectAsync and TcpClient.BeginConnect, they both return that client.Connected is true even though the port isn't open. I have verified this because I tried random IPs and random ports and it still says connection was successful.
When using TcpClient.ConnectAsync, it doesn't return true unless I press the button that runs the code under Button_Clicked 2 times, but when using TcpClient.BeginConnect, client.Connected always returns true. I know for a fact that the client isn't connected because I have a detection system that kicks the user to the reconnect page when the connection is lost.
The code I have for my TCPClient in MainPage.xaml.cs:
TcpClient client = new TcpClient();
private async void Button_Clicked(object sender, EventArgs e)
{
await client.ConnectAsync(ipAddress.Text, Convert.ToInt32(Port.Text));
if (client.Connected)
{
await DisplayAlert("Connected", "The client has successfully connected", "OK");
}
else
{
await DisplayAlert("Connection Unsuccessful", "The client couldn't connect!", "OK");
}
}
I have also tried using TcpClient.BeginConnect from How to set the timeout for a TcpClient?:
TcpClient client = new TcpClient();
private async void Button_Clicked(object sender, EventArgs e)
{
var result = client.BeginConnect(ipAddress.Text, Convert.ToInt32(Port.Text), null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (success)
{
await DisplayAlert("Connected", "The client has successfully connected", "OK");
}
else
{
await DisplayAlert("Connection Unsuccessful", "The client couldn't connect!", "OK");
}
}
I tried looking up the issue and the only thing I found was: TcpClient.Connected returns true yet client is not connected, what can I use instead? but, this link is stating that the client.Connected bool remains true after disconnection, while my problem is that it says the client connects even even though the client never gets a true connection to the server.
The project is currently using .NET Standard 2.0
I have found out the reason it would return client.Connected is true is because running the same ConnectAsync/BeginConnect method twice while the client is still trying to connect and hasn't yet timed out will cause the client.Connected value to be true for some reason.
The only way to fix this it to wait for the timeout to complete, or if the timeout is too long, to dispose the client and create a new one.

android client Not able to authorize signalR request using bearer-token

I am trying to connect signalR from the android client. I have already setup signalR hub and its working properly with javascript client on the browser. javascript client able to sent bearer-token and on the server side, I am able to get user identity.
But android java client is not able to send bearer token on. I am using https://github.com/SignalR/java-client library (As I am not using SIgnalR-core so not using latest SIgnalR core library)
connection = new HubConnection(serverUrl);
connection.getHeaders().put("Authorization","Bearer XYZ");
proxy = connection.createHubProxy(hubName);
When I run this code, I got an error
java.lang.InterruptedException: Operation was canceled
But when I don't send AUthorization header with the request then on server-side SIgnalR OnConnected() method called successfully.
The issue seems to be with sending Authorization header with the request.
For reference, the following is code to show how token authentication is implemented on the server-side
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new QueryStringOAuthBearerProvider()
});
var hubConfiguration = new HubConfiguration
{
Resolver = GlobalHost.DependencyResolver,
};
map.RunSignalR(hubConfiguration);
});
ConfigureAuth(app);
I have tried calling it by removing authorization from the server. Then it called successfully. But not works when called with Authorization header.
When I tried connection without Authorization then on server-side OnCOnnected method called but Context. Identity is null.
android Java code for connecting to SignalR client
Platform.loadPlatformComponent(new AndroidPlatformComponent());
// Create Connection
connection = new HubConnection(serverUrl);
connection.getHeaders().put("Authorization","Bearer XYZ");
// Create Proxy
proxy = connection.createHubProxy(hubName);
// Establish Connection
ClientTransport clientTransport = new
ServerSentEventsTransport(connection.getLogger());
SignalRFuture<Void> signalRFuture = connection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException e) {
return false;
} catch (ExecutionException e) {
return false;
}
return true;
If you are using Websocket, try this
https://github.com/doctorcareanywhere/java-client
build signalr-client-sdk and import the jar to your project
eg.
implementation files('libs/signalr-client-sdk.jar')

java.lang.RuntimeException: unkonow schemehttps

I am trying to connect websocket server from Android. It is working successfully when doing request to localhost server via HTTP call with port. However for hosted server with HTTPS it is not working and getting below error.
06-08 12:42:44.055 19985-20130/com.package
E/WebSocketsConnectionProvider: onError
java.lang.RuntimeException: unkonow schemehttps
This code I am using for :
mStompClient = Stomp.over(WebSocket.class, "https://api.testapp.com/sc/websocket/?access_token=" + sessionManager.getAccessToken());
mStompClient.topic("/topic/test/" + patientAppointmentItem.getAppointmentId())
.subscribe(topicMessage -> {
toast(""+ topicMessage.getPayload());
});
mStompClient.send("/app/test/" + patientAppointmentItem.getAppointmentId() + "/chat.addUser", obj.toString()).subscribe();
List<StompHeader> headers = new ArrayList<>();
headers.add(new StompHeader(StompHeader.id, id));
headers.add(newStompHeader(StompHeader.USERROLE,sessionManager.getRole()));
mStompClient.lifecycle().subscribe(lifecycleEvent -> {
switch (lifecycleEvent.getType()) {
case OPENED:
Log.i(TAG, "Stomp connection opened");
break;
case ERROR:
Log.i(TAG, "Stomp connection error");
break;
case CLOSED:
Log.i(TAG, "Stomp connection closed");
break;
}
});
mStompClient.connect(headers);
NOTE : We have Node js application already using this https websocket
service in web application and it is working well. So I believe it's
not any proxy issue or other issue with server.
Working Link on localhost server : http://localhost:8080/sc/websocket
Live server link : https://api.testapp.com/sc/websocket
Please guide if I am doing any mistake.
Thanks in advance.

Incorrect encoding exception when connecting to FCM using Smack Library

I am trying to connect to FCM using the smack library:
Here's what I've tried. It works, but I get an exception when the connection tries to login.
new Thread(new Runnable(){
XMPPTCPConnectionConfiguration.Builder configBuilder = XMPPTCPConnectionConfiguration.builder();
private Handler umm;
#Override
public void run() {
configBuilder.setSecurityMode(XMPPTCPConnectionConfiguration.SecurityMode.disabled );
configBuilder.setServiceName("fcm-xmpp.googleapis.com");
configBuilder.setHost("fcm-xmpp.googleapis.com");//MAYBE PROBLEM HERE??
configBuilder.setPort(5236);
configBuilder.setCompressionEnabled(false);
configBuilder.setSendPresence(true);
configBuilder.setSocketFactory(SSLSocketFactory.getDefault());
InterfaceClass.FCMconnection = new XMPPTCPConnection(configBuilder.build());
umm = yes;
try {
InterfaceClass.FCMconnection.connect();
Log.v("pony", "white horse");
//InterfaceClass.FCMloggin.start();
android.os.Message y4 = android.os.Message.obtain();
y4.what = LOGINTOFCM;
umm.sendMessage(y4);
//the rest of the thread is just exception handling in catch clauses
Once my handler receives the message I attempt to login with the connection
like this:
try { FCMconnection.login("senderId#gcm.googleapis.com","SERVER_KEY");
Log.d("black","r2d2");
} catch (XMPPException e) {//exception thrown here
e.printStackTrace();
Log.d("black","maity "+e);
I get the following excecption:
"smack.sasl.SASLErrorException: SASLError using X-OAUTH2: incorrect- encoding"
Now from the documentation it says clearly to implement SASL plain mechanism,
but I don't know how? Here's what the documentation says:
"The connection has two important requirements:
You must initiate a Transport Layer Security (TLS) connection. Note that CCS doesn't currently support the STARTTLS extension.
CCS requires a SASL PLAIN authentication mechanism using #gcm.googleapis.com (FCM sender ID) and the Server key as the password, where the sender ID and Server key are the values you gathered when configuring your client app. See the client documentation for your platform for information on obtaining these credentials."
Does anybody have any idea what could be causing this exception? How should I connect to FCM with the smack library?
Thank you for any advice.
As per documentation connecting to FCM over XMPP protocol needs:
1) TLS connection in transport layer, to achieve this create SSLContext using TLS protocol extension
2) Plain SASL protocol, make sure "smack-sasl-javax-4.1.8.jar" is integrated into your build setup. This took me lot of time to figure out
3) Host, service name and port number are correct(refer code snippet below)
Below code snippet works perfectly for me:
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
} catch (Exception e) {
//Failed to get default ssl context with TLS enabled... something can't proceed further
}
XMPPTCPConnectionConfiguration.Builder config = XMPPTCPConnectionConfiguration.builder();
config.setConnectTimeout(CONNECTION_TIMEOUT);
config.setSendPresence(true);
config.setCustomSSLContext(sslContext);
config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
config.setServiceName("gcm.googleapis.com");
config.setHost("fcm-xmpp.googleapis.com");
config.setPort(5236);//not production server
config.setDebuggerEnabled(true);
config.setCompressionEnabled(true);
config.setSocketFactory(sslContext.getSocketFactory());
(mConnection = new XMPPTCPConnection(config.build())).addConnectionListener(ConnectionSession.this);
mConnection.setPacketReplyTimeout(REPLY_TIMEOUT);
mConnection.connect();
mConnection.login(userID, password); //use your app server credential here
Smack version 4.8.1 implemented and tested from openfire setup.
Hope this help someone!!

Offline message not retrive from smack api 4.1.6 from xmpp MongooseIM server

I am facing the issue to retrieve offline message in android apps using smack api from XMPP Mongoose server. As per the code flow Try to retrive offline message when user become login in xmpp mongoose server before sending available presence to mongoose server.
Tried with two different way to retrieve offline message still not able to find working solution for the same. Both method which i tried those all things are explain below with detail.
Below Api we are using for the xmpp connection and all other extension :
// Smack (XMPP Client Library)
compile 'org.igniterealtime.smack:smack-android:4.1.6'

compile 'org.igniterealtime.smack:smack-tcp:4.1.6'
compile 'org.igniterealtime.smack:smack-im:4.1.6'
compile 'org.igniterealtime.smack:smack-android-extensions:4.1.6'
Tried retrive offline message Using offlineMessageManager
Below is code which I tried to retrieve offline message after login and before send available presence to server
try {
Boolean isFelxibleRetrievalSupport = offlineMessageManager.supportsFlexibleRetrieval();
Iterator i = (Iterator) offlineMessageManager.getMessages();
while (i.hasNext())
{
 Message msg = i.next();
 System.out.println("Got text [" + msg.getBody() + "] from [" + msg.getFrom() + "]");
} catch (XMPPException e)
{
 System.out.println("Error Offline Message.");
 e.printStackTrace();
 }
catch (SmackException.NotConnectedException e)
{
 System.out.println("Error Offline Message. No connection");
 e.printStackTrace(); 
}
catch (SmackException.NoResponseException e)
{
 System.out.println("Error Offline Message. No Reponse");
 e.printStackTrace();
 }
Issue case 1:
Below is exception detail which generate when above code execute
I got Exception when execute below line of code.
Iterator i = (Iterator) offlineMessageManager.getMessages();
Below is exception description which Generate when above line execute
org.jivesoftware.smack.XMPPException$XMPPErrorException: XMPPError: service-unavailable - cancel
Issue Case 2:
If checking is Flexible offline message supported from android code using smack from xmmp mongoose server so i got false value. Below is code which i used for testing.
Boolean isFelxibleRetrievalSupport = offlineMessageManager.supportsFlexibleRetrieval();
Issue Case 3:
When I try to retrieve supported features using below method using smack code like below.
ServiceDiscoveryManager manager = ServiceDiscoveryManager
.getInstanceFor(connection);
List AllFetures = manager.getFeatures();
Below is features list which i retrived:
http://jabber.org/protocol/bytestreams,
jabber:iq:privacy, urn:xmpp:ping,
http://jabber.org/protocol/commands,
jabber:iq:version,
jabber:iq:last,
http://jabber.org/protocol/xdata-validate,
http://jabber.org/protocol/xhtml-im,
vcard-temp,
http://jabber.org/protocol/chatstates,
urn:xmpp:receipts, urn:xmpp:time,
http://jabber.org/protocol/xdata-layout,
http://jabber.org/protocol/muc,
http://jabber.org/protocol/disco#items,
http://jabber.org/protocol/disco#info,
http://jabber.org/protocol/caps,
jabber:x:data
Tried to retreive offline message Using package listener from XMPP MongooseIM
below is code which i tried using package listener from smack api 4.1.6.
private static final StanzaFilter MESSAGE_PACKET_FILTER= new OrFilter(StanzaTypeFilter.MESSAGE);
configuration = XMPPTCPConnectionConfiguration.builder()
.setServiceName(SERVICE_NAME)
.setHost(KDevelopmentXMPPServer)
.setPort(PORT)
.setSendPresence(false)
.build();
// Create Connection object of xmpp connection with configured detail
connection = new XMPPTCPConnection(configuration);
connection.addAsyncStanzaListener(new StanzaListener() {
#Override
public void processPacket(Stanza packet) throws SmackException.NotConnectedException {
Log.d("CheckPacket", "OfflineMEssage");
Message message = (Message) packet;
if (message != null) {
if (message.getBody() != null) {
Log.i("XMPPClient", "Got text [" + message.getBody()
+ "] from [" + message.getFrom() + "]");
}
}
}
}, MESSAGE_PACKET_FILTER);
connection.login(user, password);
Thanks In Advance, Please anybody help me for best working solution for my critical issue.
The issue is in trying to fetch offline messages before
sending the initial presence. XEP-0160 states:
When the recipient next sends non-negative available presence to the server, the server delivers the message to the resource that has sent that presence. [...]
MongooseIM works with accordance to this recommendation.
You already pointed out what is signaled by isFlexibleRetrievalSupport - the server does not support flexible offline message retrieval.
I know I am writing this too late, but if someone like me who is hunting for same query as in "how to save and get archive messages in android app" can refer this answer :
Note :
this is implemented in the lastest version
Requrirements :
lastest openfire as of now 4.1.4
install Archives plugin in openfire
MamManager mamManager = MamManager.getInstanceFor(connection);
boolean isSupported = mamManager.isSupportedByServer();
if (isSupported) {
MamManager.MamQueryResult mamQueryResult = mamManager.queryArchive(500);
List<Forwarded> forwardedMessages = mamQueryResult.forwardedMessages;
Forwarded d = forwardedMessages.get(0);
}
Please Refer : Documention for MamManager Class

Categories

Resources