Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS IoT Android application over MQTT throws MqttException (0) - java.io.IOException: Already connected

I am trying to use 'Authenticate using Cognito-Identity with Cognito user pool' in my Android application. My Cognito user pool authentication works well, when I run that separately and I had seen a JWTToken as well. When I run the the 'PubSub' sample application with Unauthenticated role, it worked as expected. When I integrate these two features in one application, the application threw following error.

W/System.err: MqttException (0) - java.io.IOException: Already connected
W/System.err:     at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:38)
W/System.err:     at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:664)
W/System.err:     at java.lang.Thread.run(Thread.java:761)
W/System.err: Caused by: java.io.IOException: Already connected
W/System.err:     at java.io.PipedOutputStream.connect(PipedOutputStream.java:100)
W/System.err:     at java.io.PipedInputStream.connect(PipedInputStream.java:195)
W/System.err:     at org.eclipse.paho.client.mqttv3.internal.websocket.WebSocketReceiver.<init>(WebSocketReceiver.java:42)
W/System.err:     at org.eclipse.paho.client.mqttv3.internal.websocket.WebSocketSecureNetworkModule.start(WebSocketSecureNetworkModule.java:78)
W/System.err:     at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:650)
W/System.err:   ... 1 more

I have been trying to resolve this issue since last Thursday and still stuck at the same place. Really No idea where should i check.!

I am adding my Authentication(Cognito user pool authentication) activity and Connect activity.

AmazonCognitoIdentityProviderClient identityProviderClient = new 
AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), new ClientConfiguration());
identityProviderClient.setRegion(Region.getRegion(Regions.US_WEST_2));
CognitoUserPool userPool = new CognitoUserPool(getApplicationContext(), "us-west-2_ghtcc6ho9", "4t0mk45hNso69dp2j4jvel5ghm", "1jmq0lhhq721oif9k6nug31c29i760vihua8hvrgu5umfr2a1vd7", identityProviderClient);
cogUser = userPool.getUser();
authenticationHandler = new AuthenticationHandler() {



        @Override
        public void onSuccess(CognitoUserSession userSession, CognitoDevice newDevice) {
            String ids = userSession.getIdToken().getJWTToken();
            Log.d("MyToken","session id___"+userSession.getIdToken().getExpiration()+"___"+userSession.getIdToken().getIssuedAt());
            Intent pubSub = new Intent(MainActivity.this, PubSubActivity.class);
            pubSub.putExtra("token",""+ids);
            startActivity(pubSub);
            //MainActivity.this.finish();

        }

        @Override
        public void getAuthenticationDetails(AuthenticationContinuation authenticationContinuation, String userId) {
            Log.d("MyToken","getAuthenticationDetails");
            AuthenticationDetails authenticationDetails = new AuthenticationDetails("shone", "172737", null);
            authenticationContinuation.setAuthenticationDetails(authenticationDetails);
            // Allow the sign-in to continue
            authenticationContinuation.continueTask();
        }

        @Override
        public void getMFACode(MultiFactorAuthenticationContinuation multiFactorAuthenticationContinuation) {
            Log.d("MyToken","getMFACode");
            multiFactorAuthenticationContinuation.continueTask();
        }

        @Override
        public void authenticationChallenge(ChallengeContinuation continuation) {
            Log.d("MyToken","authenticationChallenge"+continuation.getChallengeName());
            newPasswordContinuation.continueTask();
        }

        @Override
        public void onFailure(Exception exception) {
            exception.printStackTrace();
            Log.d("MyToken","onFailure");
        }
    };
     cogUser.getSessionInBackground(authenticationHandler); 

When It reaches 'OnSuccess' I am launching my connect activity and passing my session token along with the Intent. Moving to the next activity

private static final String COGNITO_POOL_ID = "us-west-2:a153a090-508c-44c0-a9dd-efd450298c4b";
private static final Regions MY_REGION = Regions.US_WEST_2;
AWSIotMqttManager mqttManager;
String clientId;
AWSCredentials awsCredentials;
CognitoCachingCredentialsProvider credentialsProvider;
 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Intent intent = getIntent();
if(null == intent){
    Toast.makeText(getApplicationContext(), "Token is null", Toast.LENGTH_SHORT).show();
}else {
    token = intent.getStringExtra("token");
}
 clientId = UUID.randomUUID().toString();
    credentialsProvider = new CognitoCachingCredentialsProvider(
            getApplicationContext(), 
            COGNITO_POOL_ID, 
            MY_REGION 
    );
mqttManager = new AWSIotMqttManager(clientId, CUSTOMER_SPECIFIC_ENDPOINT);
 Map loginsMap = new HashMap();
    loginsMap.put("cognito-idp.us-west-2.amazonaws.com/us-west-2_ghtcc6ho9", token);
    credentialsProvider.setLogins(loginsMap);
    Log.d("SESSION_ID", ""+token);
    new Thread(new Runnable() {
        @Override
        public void run() {
            credentialsProvider.refresh();
            awsCredentials = credentialsProvider.getCredentials();
            Log.d("SESSION_ID B: ", ""+awsCredentials.getAWSAccessKeyId());
            Log.d("SESSION_ID C: ", ""+awsCredentials.getAWSSecretKey());
        }
    }).start();
}

 View.OnClickListener connectClick = new View.OnClickListener() {
    @Override
    public void onClick(View v) {

        Log.d(LOG_TAG, "clientId = " + clientId);

        try {
            mqttManager.connect(credentialsProvider, new AWSIotMqttClientStatusCallback() {
                @Override
                public void onStatusChanged(final AWSIotMqttClientStatus status,
                        final Throwable throwable) {
                    Log.d(LOG_TAG, "Status = " + String.valueOf(status)+"______"+((null !=throwable)?throwable.getMessage():""));

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (status == AWSIotMqttClientStatus.Connecting) {
                                tvStatus.setText("Connecting...");

                            } else if (status == AWSIotMqttClientStatus.Connected) {
                                tvStatus.setText("Connected");

                            } else if (status == AWSIotMqttClientStatus.Reconnecting) {
                                if (throwable != null) {
                                    Log.e(LOG_TAG, "Connection error.", throwable);
                                }
                                tvStatus.setText("Reconnecting");
                            } else if (status == AWSIotMqttClientStatus.ConnectionLost) {
                                if (throwable != null) {
                                    Log.e(LOG_TAG, "Connection error.", throwable);
                                    throwable.printStackTrace();
                                }
                                tvStatus.setText("Disconnected");
                            } else {
                                tvStatus.setText("Disconnected");

                            }
                        }
                    });
                }
            });
        } catch (final Exception e) {
            Log.e(LOG_TAG, "Connection error.", e);
        }
    }
};

What is wrong in my code? Why it throws exception when the MQTT connect is being invoked? Any help would be appreciated.

like image 688
Shibin Francis Avatar asked May 29 '17 14:05

Shibin Francis


People also ask

Does AWS IoT use MQTT?

AWS IoT Core supports device connections that use the MQTT protocol and MQTT over WSS protocol and that are identified by a client ID. The AWS IoT Device SDKs support both protocols and are the recommended ways to connect devices to AWS IoT.


1 Answers

I beat my head up with this almost a week.

Full course of action -> After succesfull login you will have a jwt token

String idToken = cognitoUserSession.getIdToken().getJWTToken();

put it into a map

Map<String, String> logins = new HashMap<String, String>(); 
//fill it with Cognito User token
logins.put("cognito-idp.<REGION>.amazonaws.com/<COGNITO_USER_POOL_ID>", idToken);

then use it to set in two places (not stated in any documentation!)

CognitoCachingCredentialsProvider credentialsProvider = new 
CognitoCachingCredentialsProvider(context, IDENTITY_POOL_ID, REGION);
credentialsProvider.setLogins(logins);

and

AmazonCognitoIdentity cognitoIdentity = new AmazonCognitoIdentityClient(credentialsProvider);
GetIdRequest getIdReq = new GetIdRequest();
getIdReq.setLogins(logins); //or if you have already set provider logins just use credentialsProvider.getLogins()
getIdReq.setIdentityPoolId(COGNITO_POOL_ID);
GetIdResult getIdRes = cognitoIdentity.getId(getIdReq);

after that you still nedd to make some call

AttachPrincipalPolicyRequest attachPolicyReq = new AttachPrincipalPolicyRequest(); //in docs it called AttachPolicyRequest but it`s wrong
attachPolicyReq.setPolicyName("allAllowed"); //name of your IOTAWS policy
attachPolicyReq.setPrincipal(getIdRes.getIdentityId());
new AWSIotClient(credentialsProvider).attachPrincipalPolicy(attachPolicyReq);

and only after that you can enable connect button and continue like that

mqttManager.connect(credentialsProvider, new AWSIotMqttClientStatusCallback() {

Really for this small piece of code i spent a lot of time...

like image 75
Nick Link Avatar answered Sep 20 '22 13:09

Nick Link