aws / aws-iot-device-sdk-java

Java SDK for connecting to AWS IoT from a device.
https://aws.amazon.com/iot/sdk/
Apache License 2.0
210 stars 168 forks source link

Client keeps on disconnecting and reconnecting #28

Closed sunnymopada closed 7 years ago

sunnymopada commented 7 years ago

In paho sdk, in the below issue, user said client.reconnect() solved his problem when he got client keeps on disconnecting and reconnecting issue. https://github.com/eclipse/paho.mqtt.java/issues/258

I'm unable to find reconnect method in AWSIotMqttClient class

Can you guys look into that please?

fengsongAWS commented 7 years ago

Hi @SanyasiraoM , Can you elaborate your problem so that we can reproduce the issue? In theory, the paho handles the reconnect logic for you which should have the same logic as connect. AWS IoT Java SDK sets a maximum limit on reconnect retries and once it hits the limit, the iot client will quit and throw the error. In this case, we do not expose reconnect method in AWSIotMqttClient.

sunnymopada commented 7 years ago

@fengsongAWS Thanks for reply,

Below is the service I wrote. And I'm starting service every time when user opens the app.

public class MqttService extends Service {

    static final String TAG = "MqttService";
    private NetworkConnectionIntentReceiver networkConnectionMonitor;
    private AWSIotMqttClient client;
    ArrayList<AWSIotMessage> unPublishedMessages = new ArrayList<>();
    ArrayList<AWSIotMessage> messageStore = new ArrayList<>();
    boolean isGettingUnreadChannels = false, initializingConnection = false;

    public MqttService() {
        super();
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(final Intent intent, int flags, final int startId) {
        CommonMethods.setLogD(TAG, "onStartCommand");
        reconnectClient();
        registerBroadcastReceivers();
        return super.onStartCommand(intent, flags, startId);
    }

    /*Server activity communication by event bus start*/

    //Publishing events
    private void notifyConnectionStatus(String status) {
        initializingConnection = false;
    }

    private void notifyPublishCallback(String status, String awsIotMessage) {
        Intent intent = new Intent(this, MqttMethods.getClientServiceClass(this));
        intent.putExtra(Constants.AWS_IOT_CALL_BACK_MESSAGE, new Gson().toJson(new PublishCallbackEvent(status, awsIotMessage)));
        startService(intent);
    }

    private void handleNewEvent(AWSIotMessage awsIotMessage) {
        CommonMethods.setLogD(TAG, "New Event1 " + isGettingUnreadChannels + ":" + awsIotMessage.getStringPayload());
    }

   /*Server activity communication by event bus end*/

    private void initializeClient() {
        KeyStoreUtil.KeyStorePasswordPair pair = KeyStoreUtil.getKeyStorePasswordPair(MqttMethods.getCertificate(this), MqttMethods.getPrivateKey(this));
        if (pair != null) {
            client = new AWSIotMqttClient(MqttMethods.getClientEndPoint(), MqttMethods.getMqttClientId(this), pair.keyStore, pair.keyPassword) {
                @Override
                public void onConnectionSuccess() {
                    super.onConnectionSuccess();
                    CommonMethods.setLogD(TAG, client.getConnectionStatus().toString() + "");
                    notifyConnectionStatus(client.getConnectionStatus().toString());
                    try {
                        client.subscribe(new AWSIotTopic(MqttMethods.getSubscribeKey(MqttService.this)) {
                            @Override
                            public void onMessage(AWSIotMessage message) {
                                super.onMessage(message);
                                handleNewEvent(message);
                            }

                            @Override
                            public void onSuccess() {
                                super.onSuccess();
                            }

                            @Override
                            public void onFailure() {
                                super.onFailure();
                            }

                            @Override
                            public void onTimeout() {
                                super.onTimeout();
                            }
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConnectionClosed() {
                    super.onConnectionClosed();
                    CommonMethods.setLogD(TAG, client.getConnectionStatus().toString() + "");
                    notifyConnectionStatus(client.getConnectionStatus().toString());
                }

                @Override
                public void onConnectionFailure() {
                    super.onConnectionFailure();
                    CommonMethods.setLogD(TAG, client.getConnectionStatus().toString() + "");
                    notifyConnectionStatus(client.getConnectionStatus().toString());
                }
            };
            client.setKeepAliveInterval(60000);
        } else {
            stopSelf();
        }
    }

    public void connectAndSubscribe() {
        CommonMethods.setLogD(TAG, "Connect and subscribe");
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    client.connect();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    void reconnectClient() {
        CommonMethods.setLogD(TAG, "Reconnect to server" + ((client != null) ? client.getConnectionStatus() : ""));
        if (client != null && client.getConnectionStatus() == CONNECTED) {
            return;
        }
        if (!initializingConnection) {
            initializingConnection = true;
            initializeClient();
            connectAndSubscribe();
        }
    }

    public void subscribeClient(AWSIotTopic topic) {
        try {
            reconnectClient();
            client.subscribe(topic);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void publishMessage(AWSIotMessage message) {
        try {
            if (client != null && client.getConnectionStatus() == CONNECTED) {
                client.publish(message, getDefaultPublishTimeout());
            } else {
                unPublishedMessages.add(message);
                reconnectClient();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void unsubscribe(AWSIotTopic topic) {
        CommonMethods.setLogD(TAG, "unsubscribe to server");
        try {
            reconnectClient();
            client.unsubscribe(topic);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void disconnectClient() {
        CommonMethods.setLogD(TAG, "disconnect to server");
        try {
            if (client != null && client.getConnectionStatus() != DISCONNECTED) {
                client.disconnect();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("deprecation")
    private void registerBroadcastReceivers() {
        if (networkConnectionMonitor == null) {
            networkConnectionMonitor = new NetworkConnectionIntentReceiver();
            registerReceiver(networkConnectionMonitor, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
        }
    }

    private void unregisterBroadcastReceivers() {
        if (networkConnectionMonitor != null) {
            unregisterReceiver(networkConnectionMonitor);
            networkConnectionMonitor = null;
        }
    }

    /*
     * Called in response to a change in network connection - after losing a
     * connection to the server, this allows us to wait until we have a usable
     * data connection again
     */
    private class NetworkConnectionIntentReceiver extends BroadcastReceiver {

        @Override
        @SuppressLint("Wakelock")
        public void onReceive(Context context, Intent intent) {
            CommonMethods.setLogD(TAG, "Internal network status receive.");
            // we protect against the phone switching off
            // by requesting a wake lock - we request the minimum possible wake
            // lock - just enough to keep the CPU running until we've finished
            PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
            WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MQTT");
            wl.acquire();
            CommonMethods.setLogD(TAG, "Reconnect for Network recovery.");
            if (isOnline()) {
                CommonMethods.setLogD(TAG, "Online,reconnect.");
                reconnectClient();
            } else {

            }
            wl.release();
        }

    }

    /**
     * @return whether the android service can be regarded as online
     */
    public boolean isOnline() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = cm.getActiveNetworkInfo();
        //noinspection RedundantIfStatement
        if (networkInfo != null && networkInfo.isAvailable() && networkInfo.isConnected()) {
            return true;
        }

        return false;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "Destroy");
        disconnectClient();
        stopSelf();
        unregisterBroadcastReceivers();
        super.onDestroy();
    }
}

I was able to publish and receive messages but suddenly client keep on getting CONNECTED, DISCONNECTED continuously.And I'm sure that, no other client is using same client_id. And i'm testing with in single device. Even I tried changing the client_id but still the same issue. As mentioned in the question. The person is saying this issue is resolved when he do reconnect . But I could not find reconnect method in AwsIotMqttConnection class.

Below are the logs

06-10 13:05:44.549 4591-4591/com.example.awsiot D/MqttService: onStartCommand:
06-10 13:05:44.549 4591-4591/com.example.awsiot D/MqttService: Reconnect for Network recovery.:
06-10 13:05:44.549 4591-4591/com.example.awsiot D/MqttService: Online,reconnect.:
06-10 13:05:44.549 4591-4591/com.example.awsiot D/MqttService: Reconnect to server DISCONNECTED:
06-10 13:05:44.979 4591-4933/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:05:44.979 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:05:44.979 4591-4933/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:05:49.501 4591-4913/com.example.awsiot D/MqttService: publish message {"event_type":"ALIVE_MESSAGE","sender_id":"user1","source":"source"}:
06-10 13:05:50.521 4591-4933/com.example.awsiot D/MqttService: New Event1 false:{"event_type": "ALIVE_MESSAGE_ACK", "chat_room_id": "", "msg_id": "", "cli_event_id": "", "source": "source", "msg_ids": []}:
06-10 13:05:52.370 4591-4933/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:05:52.371 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:05:52.371 4591-4933/com.example.awsiot D/MqttService: DISCONNECTED:
06-10 13:05:54.524 4591-4913/com.example.awsiot D/MqttService: Reconnect to serverDISCONNECTED:
06-10 13:05:55.067 4591-4913/com.example.awsiot D/MqttService: Connect and subscribe:
06-10 13:05:55.372 4591-4933/com.example.awsiot I/AwsIotConnection: Connection is being retried
06-10 13:05:55.502 4591-5105/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:05:55.503 4591-5105/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:05:55.505 4591-5105/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:05:55.786 4591-4933/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:05:55.787 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:05:55.788 4591-4933/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:05:55.865 4591-5097/com.example.awsiot W/sIotMqttMessageListener: Request failed for topic topic/read/source/user1: Connection lost (32109) - java.io.EOFException
06-10 13:05:55.867 4591-5105/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:05:55.868 4591-5105/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:05:55.868 4591-5105/com.example.awsiot D/MqttService: DISCONNECTED:
06-10 13:05:58.868 4591-5105/com.example.awsiot I/AwsIotConnection: Connection is being retried
06-10 13:05:59.325 4591-5105/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:05:59.325 4591-5105/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:05:59.326 4591-5105/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:05:59.383 4591-4933/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:05:59.383 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:05:59.384 4591-4933/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:05:59.785 4591-5105/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:05:59.786 4591-5105/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:05:59.786 4591-5105/com.example.awsiot D/MqttService: DISCONNECTED:
06-10 13:06:02.384 4591-4933/com.example.awsiot I/AwsIotConnection: Connection is being retried
06-10 13:06:02.786 4591-5105/com.example.awsiot I/AwsIotConnection: Connection is being retried
06-10 13:06:02.909 4591-4933/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:06:02.909 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:06:02.910 4591-4933/com.example.awsiot D/MqttService: RECONNECTING:
06-10 13:06:03.253 4591-5105/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:06:03.254 4591-5105/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:06:03.255 4591-5105/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:06:03.312 4591-4933/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:06:03.312 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:06:03.312 4591-4933/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:06:06.312 4591-4933/com.example.awsiot I/AwsIotConnection: Connection is being retried
06-10 13:06:06.740 4591-4933/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:06:06.740 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:06:06.741 4591-4933/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:06:06.858 4591-4933/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:06:06.858 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:06:06.858 4591-4933/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:06:06.868 4591-5105/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:06:06.868 4591-5105/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:06:06.869 4591-5105/com.example.awsiot D/MqttService: DISCONNECTED:
06-10 13:06:09.524 4591-4913/com.example.awsiot D/MqttService: Reconnect to serverDISCONNECTED:
06-10 13:06:09.858 4591-4933/com.example.awsiot I/AwsIotConnection: Connection is being retried
06-10 13:06:09.869 4591-5105/com.example.awsiot I/AwsIotConnection: Connection is being retried
06-10 13:06:09.950 4591-4913/com.example.awsiot D/MqttService: Connect and subscribe:
06-10 13:06:10.322 4591-4933/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:06:10.322 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:06:10.323 4591-4933/com.example.awsiot D/MqttService: DISCONNECTED:
06-10 13:06:10.357 4591-5361/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:06:10.359 4591-5361/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:06:10.360 4591-5361/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:06:10.422 4591-4933/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:06:10.422 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:06:10.423 4591-4933/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:06:10.756 4591-5105/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:06:10.756 4591-5105/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:06:10.762 4591-5105/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:06:10.800 4591-5355/com.example.awsiot W/sIotMqttMessageListener: Request failed for topic topic/read/source/user1: Connection lost (32109) - java.io.EOFException
06-10 13:06:10.802 4591-5361/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:06:10.802 4591-5361/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:06:10.802 4591-5361/com.example.awsiot D/MqttService: DISCONNECTED:
06-10 13:06:13.423 4591-4933/com.example.awsiot I/AwsIotConnection: Connection is being retried
06-10 13:06:13.802 4591-5361/com.example.awsiot I/AwsIotConnection: Connection is being retried
06-10 13:06:14.224 4591-4933/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:06:14.225 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:06:14.225 4591-4933/com.example.awsiot D/MqttService: RECONNECTING:
06-10 13:06:14.287 4591-5105/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:06:14.287 4591-5105/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:06:14.287 4591-5105/com.example.awsiot D/MqttService: RECONNECTING:
06-10 13:06:14.494 4591-4913/com.example.awsiot D/BaseChatService: CurrentLiveStatus 1497080174494:
06-10 13:06:14.503 4591-4913/com.example.awsiot D/MqttService: Reconnect to serverRECONNECTING:
06-10 13:06:14.674 4591-5522/com.example.awsiot W/tMqttConnectionListener: Connect request failure
                                                                         Connection lost (32109) - java.io.EOFException
                                                                             at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:146)
                                                                             at java.lang.Thread.run(Thread.java:818)
                                                                          Caused by: java.io.EOFException
                                                                             at java.io.DataInputStream.readByte(DataInputStream.java:77)
                                                                             at org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream.readMqttWireMessage(MqttInputStream.java:65)
                                                                             at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:107)
                                                                             at java.lang.Thread.run(Thread.java:818) 
06-10 13:06:14.675 4591-5361/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:06:14.675 4591-5361/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:06:14.675 4591-5361/com.example.awsiot D/MqttService: DISCONNECTED:
06-10 13:06:14.880 4591-4913/com.example.awsiot D/MqttService: Connect and subscribe:
06-10 13:06:15.348 4591-5545/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:06:15.348 4591-5545/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:06:15.348 4591-5545/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:06:15.468 4591-4933/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:06:15.468 4591-4933/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:06:15.468 4591-4933/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:06:17.287 4591-5105/com.example.awsiot I/AwsIotConnection: Connection is being retried
06-10 13:06:17.822 4591-5105/com.example.awsiot I/AwsIotConnection: Connection successfully established
06-10 13:06:17.823 4591-5105/com.example.awsiot I/AbstractAwsIotClient: Client connection active: android-1
06-10 13:06:17.823 4591-5105/com.example.awsiot D/MqttService: CONNECTED:
06-10 13:06:17.896 4591-5537/com.example.awsiot W/sIotMqttMessageListener: Request failed for topic topic/read/source/user1: Connection lost (32109) - java.io.EOFException
06-10 13:06:17.898 4591-5545/com.example.awsiot I/AwsIotConnection: Connection temporarily lost
06-10 13:06:17.899 4591-5545/com.example.awsiot I/AbstractAwsIotClient: Client connection lost: android-1
06-10 13:06:17.899 4591-5545/com.example.awsiot D/MqttService: DISCONNECTED:
06-10 13:06:18.468 4591-4933/com.example.awsiot I/AwsIotConnection: Connection is being retried
sunnymopada commented 7 years ago

@fengsongAWS Any reply on this?

fengsongAWS commented 7 years ago

Is there any reason that you want IoT Java SDK running on Android devices? We have not fully tested AWS IoT Java SDK on Android devices yet and normally, we have aws android sdk for android developers. It provides iot core inside the sdk so you can also do pub/sub. https://github.com/aws/aws-sdk-android

sunnymopada commented 7 years ago

@fengsongAWS Thanks for reply,

As like you said we have two samples provided by aws for android

One is https://github.com/awslabs/aws-sdk-android-samples/tree/master/AndroidPubSub and It requires below configuration for connecting to server.

CUSTOMER_SPECIFIC_ENDPOINT = "<CHANGE_ME>";
COGNITO_POOL_ID = "<CHANGE_ME>";
AWS_IOT_POLICY_NAME = "CHANGE_ME";
MY_REGION = Regions.US_EAST_1;
KEYSTORE_NAME = "iot_keystore";
KEYSTORE_PASSWORD = "password";
CERTIFICATE_ID = "default";

Second is https://github.com/awslabs/aws-sdk-android-samples/tree/master/AndroidPubSubWebSocket and requires below configuration for connecting to server.

CUSTOMER_SPECIFIC_ENDPOINT = "<CHANGE_ME>";
COGNITO_POOL_ID = "<CHANGE_ME>";
MY_REGION = Regions.US_EAST_1;

We want to restrict users to publish and subscribe topic for every user. So we decided to go with different certificates for different users.

So java sdk https://github.com/aws/aws-iot-device-sdk-java is useful in our scenario as below configuration just needs certificates and does not need any cognito related credentials

String clientEndpoint = "<prefix>.iot.<region>.amazonaws.com";       // replace <prefix> and <region> with your own
String clientId = "<unique client id>";                              // replace with your own client ID. Use unique client IDs for concurrent connections.
String certificateFile = "<certificate file>";                       // X.509 based certificate file
String privateKeyFile = "<private key file>";                        // PKCS#1 or PKCS#8 PEM encoded private key file

Currently I'm using android compatible java sdk https://github.com/Hospes/aws-iot-device-sdk-android , mentioned at https://github.com/aws/aws-iot-device-sdk-java/issues/18

So do we have a sample or way to connect using android sdk using just certificates?. Thank you!

fengsongAWS commented 7 years ago

Hi, It is not a recommended way to put certs in a mobile device. That's why mobile developers usually choose to use Cognito to do authorization.

Based on your scenario, you can use Cognito to create different cognito pool associated with different IAM Policies. In the policy, you can restrict users under different pool with the operations you want. This is the typical way that mobile developers do. In addition to android web socket example, we have another android pub/sub sample which uses cognito to retrieve temporary IAM credentials and use that credentials call IoT to generate certificates and policies. https://github.com/awslabs/aws-sdk-android-samples/blob/master/AndroidPubSub/src/com/amazonaws/demo/androidpubsub/PubSubActivity.java

However, if you still want to put physical certs in mobile device and manually import the certs, you need to create a file reader to read from physical file and use AwsIoTKeystoreHelper to load certs and keys like what is shown here https://github.com/awslabs/aws-sdk-android-samples/blob/master/AndroidPubSub/src/com/amazonaws/demo/androidpubsub/PubSubActivity.java#L202.

sunnymopada commented 7 years ago

@fengsongAWS Thanks for reply,

In the https://github.com/awslabs/aws-sdk-android-samples/blob/master/AndroidPubSub/src/com/amazonaws/demo/androidpubsub/PubSubActivity.java#L202 link apart from certificates , we need to configure cognito as well right. So why both cognito and certificates?.

Can we achieve authentication as like in https://github.com/aws/aws-iot-device-sdk-java sample just by using certificates?

In our use case every user can subscribe to only one topic and publish to another one topic. And they are unique for all users. So can we achieve the same thing by what you are saying?

Sorry if any question is silly. Thank you!

fengsongAWS commented 7 years ago

Hi @SanyasiraoM ,

  1. For mobile developers, it is usually not recommended to put physical certs into device. If the device got compromised, it is in a bad situation. So, that's why AWS has Cognito services which provides developers a pool where you can retrieve temporary IAM credentials with limited IAM policy and users can use restricted policy to do the operation. If the credential expire, user can updated it as well. Cognito and IoT are two services. Cognito is just a service provides you with IAM credentials where you can use it to call a bunch of other AWS services. IoT is one of them. Certificates is the way of authentication and authorization in IoT service.

  2. Yes you can use android SDK to achieve that but I think you have to do some extra coding to parse the certs/key file in addition to the existing sample of android SDK as mentioned before.

  3. What do you mean they are unique for all users? Do all the users have the same permission where they can sub to the same topic and pub to another same topic? Or each user has different permission where each use can sub to one topic which is different than the others and so is pub? In both cases, you can easily do it by specifying the restriction in IAM policies using Cognito. Since clientId is a UUIID for each connection, you can pass ClientId as parameter to your IAM policy e.g.

        {
            "Effect": "Allow",
            "Action": [
                "iot:Publish"
            ],
            "Resource": [
                "arn:aws:iot:us-west-2:741837387995:topic/foo/bar/${iot:ClientId}"
            ]
        }

    Same thing for subscribe. For more information, you can refer to this link. http://docs.aws.amazon.com/iot/latest/developerguide/iam-policies.html

Thanks for your interest in AWS IoT Device SDK.

sunnymopada commented 7 years ago

@fengsongAWS Thanks for reply.

Regarding 3rd Point consider there is users with ids user1, user2, user3, etc.. now write/user1, read/user1 will be publish and subscribe topics for user1 respectively ; write/user2 and read/user2 will be publish and subscribe topics for user2; etc.. We want to achieve that topic authorization and restriction.

We want them to be unique for every user. Suppose if user1 logins in two devices, pubsub topics will be same but clientId will change.

So can I achieve our use case by the 3rd point you answered?

We are not keeping any physical certs in code. We are keeping content in the certs as strings in the app. Currently we are using unique certificate and private key each user and we will get them from backend we user login.

As like you said what if the device is compromised and they got cognito identity pool id? Won't it be same risk?

fengsongAWS commented 7 years ago

In your use case, basically you want to have unique cert/policy for each user. You can achieve this by using Cognito. This is exactly same as Android sample where you retrieve temporary IAM credentials and call IoT control plane to dynamically generate certs and policies.

However, it seems you have a backend service that manages user certs and those certs were pre-generated and attached with pre-configurted IoT Policies. You can stick to this pattern and skip the cognito part. As shown in https://github.com/awslabs/aws-sdk-android-samples/blob/master/AndroidPubSub/src/com/amazonaws/demo/androidpubsub/PubSubActivity.java#L202, you just need to pass in cert/key string.

Cognito provides a federated authenticated way of getting credentials from user pool. It is safer than put certs on device directly.

sunnymopada commented 7 years ago

HI @fengsongAWS ,

I tried to connect to server by commenting cognito part and giving certificates generated by our backend. But i'm unable to connect. But with the same certificates, I'm able to connect in https://github.com/aws/aws-iot-device-sdk-java sample.

You can see what I commented in https://bitbucket.org/snippets/SunnyiB/jqGXB,

Below is the log when tried to connect

06-21 12:56:28.152 1499-1499/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: clientId = f6376b28-8a01-4f36-b1e7-8c1a06437e5f
06-21 12:56:28.287 1499-1499/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Connecting
06-21 12:56:31.629 1499-10117/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Reconnecting
06-21 12:56:36.820 1499-10204/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Reconnecting
06-21 12:56:46.097 1499-10340/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Reconnecting
06-21 12:57:03.594 1499-10954/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Reconnecting
06-21 12:57:39.145 1499-11537/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Reconnecting
06-21 12:58:44.557 1499-12725/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Reconnecting
06-21 12:59:49.841 1499-13809/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Reconnecting
06-21 13:00:55.285 1499-15008/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Reconnecting
06-21 13:02:00.729 1499-16054/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Reconnecting
06-21 13:03:06.244 1499-17098/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = Reconnecting
06-21 13:05:10.430 1499-18601/com.amazonaws.demo.androidpubsub D/com.amazonaws.demo.androidpubsub.PubSubActivity: Status = ConnectionLost
rongsaws commented 7 years ago

For the AndroidPubSub sample, I think Cognito is used only for demonstrating temp credential retrieval for creating AWS IoT certs, if there's no cert & key existing in the key store file (named iot_keystore). If you have a way of getting pre-generated keystore file from your server backend, you don't have to use Cognito. Again, just to echo what fengsongAWS@ has said, it's important to note app users may be able to extract the keystore file using ADB or other means.

Android keystore file is prepared differently as the Java one, please follow the steps in the sample readme file for generating the keystore file. Make sure to use the same keystore password as used in your sample.

sunnymopada commented 7 years ago

Hi @rongsaws,

Can you check the previous answer, where I hardcoded certificate key and private key and commented cognito part. Can you check and let me know if something is wrong?

rongsaws commented 7 years ago

You don't really need to comment out the code to test. To test your own cert & key, you need to have a valid keystore file named "iot_keystore" under your app's data directory (see the adb portion in the readme file), then the Cognito part under this line won't get executed. If you previously created a keystore file, double check if it's valid.

sunnymopada commented 7 years ago

Hi @rongsaws

I'm not keeping keystore file Instead I'm keeping certificate and private key in https://github.com/awslabs/aws-sdk-android-samples/blob/master/AndroidPubSub/src/com/amazonaws/demo/androidpubsub/PubSubActivity.java#L202,L203, So instead of using cognito, it will use hardcoded certificates to create keystore.

Could you check https://bitbucket.org/snippets/SunnyiB/jqGXB once?

Thank you!

rongsaws commented 7 years ago

Did you debug the code and make sure that code path with hard-coded cert and key was executed? As said before, if you have previously created a keystore file, it'd be picked up and your modified code then won't get executed.

Another common mistake is using certs created in a different AWS region to connect, so double check your endpoint is correct. Also make sure you can ping your endpoint from your device.

sunnymopada commented 7 years ago

Thank you @fengsongAWS @rongsaws , Now i'm able connect.

Certs are created in different region.

Though my original issue in java is still exists. Now I can proceed with android.

nitinware commented 7 years ago

@SanyasiraoM - Was your issue resolved, I am seeing the same issue #31 When I startup the application, I am seeing a continuous logs are getting printed on console of connection lost, established, retired. Were you able to resolve this issue, any help is highly appreciated.

ravirajjak commented 6 years ago

I am getting the same issue every time I try to connect MQTT it gets connected then after few seconds again it goes in reconnecting state it happens in loop. Please suggest what to do..

sunnymopada commented 6 years ago

@nitinware @ravirajjak I Faced the issue while trying use this(java sdk) for android. I did not face any issues till now in android sdk - https://github.com/aws/aws-sdk-android/

lxwbr commented 6 years ago

I am having the same issue, but would like to use this device-sdk in order to communicate with the shadow and use an android tablet a thing.

manawardhana commented 6 years ago

Make sure no more than one client connected using the same certificate at the same time. Consider all possible clients: handsets, mock programs, IDE etc.

isha31 commented 6 years ago

Please help me! I am getting the same issue. Every time I attempt to connect to AWS MQTT Broker its always reconnecting, it gives the following log output :

`03-22 17:18:13.976 I/AWSIotMqttManager( 6911): attempting to reconnect to mqtt broker 03-22 17:18:18.096 W/AWSIotMqttManager( 6911): Reconnect failed Thread started: #4 03-22 17:18:18.096 I/AWSIotMqttManager( 6911): schedule Reconnect attempt 1 of 10 in 8 seconds. 03-22 17:18:26.099 I/AWSIotMqttManager( 6911): attempting to reconnect to mqtt broker 03-22 17:18:29.616 W/AWSIotMqttManager( 6911): Reconnect failed 03-22 17:18:29.616 I/AWSIotMqttManager( 6911): schedule Reconnect attempt 2 of 10 in 16 seconds.Thread started: #5

manawardhana commented 6 years ago

@isha31 I guess in your case you are not getting connected at all. Please check credentials and other connection parameters. Here we were referring to frequent occurrences of connecting and disconnecting events.

chenliuyun commented 6 years ago

I am having the same issue, use this device-sdk to update shadow(Topick:$aws/things/test/shadow/update).Other topics(not shadow) work well. Please suggest what to do..

nbsbhat commented 4 years ago

Using https://github.com/aws/aws-iot-device-sdk-js (nodeJS), the awsIot.device class was reconnecting and publishing the messages continuously. I forced an end connection to stop continuous publishing of messages:

        device
        .on('connect', function () {
          console.log('connected to aws endpoint..');

          device.publish(topic, JSON.stringify(msg), function (err) {
          if (err) {
            console.log('error publishing message:', err);
          }
          });
          device.end(callback => {
            console.log('closing connection', callback);
          });
        });
phanikrishnahari commented 4 years ago

@SanyasiraoM @fengsongAWS I'm using the AWS IoT SDK to connect to IoT and i have set my keep alive to 1200s, and i have also set a forced ping every 900s. thus the client should not disconnect technically forever. But, i notice that my client connects and disconnects every 5mins Below is a glimpse of the events:

Screen Shot 2020-08-05 at 5 21 53 PM

Any help is highly appreciated. Thanks in advance!

balaji-a-tfs commented 3 years ago

Hi, Kindly help me to understand the use of keep alive interval setting(i am using AWS IOT Client). When i set keep alive interval to 18hours before i hit the connect method and when i disconnect the internet where i have client created, the same client is getting disconnected automatically roughly after 16 to 17minutes. Is it the expected behavior of AWS java SDK's.

Also kindly help me to understand on weather we hav any call back methods on the client we create to get to understand on the connection status of MQTT client so that when it gets disconnected automatically for any reason we can have a own implementations to connect back.

Excepting for the reply at the earliest....Thanks in advance...

jmklix commented 3 years ago

IoT Docs

Connection inactivity (keep-alive interval) For MQTT (or MQTT over WebSocket) connections, a client can request a keep-alive interval between 30—1200 seconds as part of the MQTT CONNECT message. Amazon IoT Core starts the keep-alive timer for a client when sending CONNACK in response to the CONNECT message. This timer is reset whenever Amazon IoT receives a PUBLISH, SUBSCRIBE, PING, or PUBACK message from the client. Amazon IoT Core disconnects a client whose keep-alive timer has reached 1.5x the specified keep-alive interval (i.e., by a factor of 1.5). The default keep-alive interval is 1200 seconds. If a client requests a keep-alive interval of zero, the default keep-alive interval is used. If a client requests a keep-alive interval greater than 1200 seconds, the default keep-alive interval is used. If a client requests a keep-alive interval shorter than 30 seconds but greater than zero, the server treats the client as though it requested a keep-alive interval of 30 seconds. 1200 No

This might help with connection status: https://docs.aws.amazon.com/iot/latest/developerguide/life-cycle-events.html

balaji-a-tfs commented 3 years ago

Hi @jmklix, Thank you very much for your above inputs, have read somewhere that the keep alive interval is by default 18 hours and not 1200 Seconds, Can you please confirm if its 1200 seconds is the default if any value between 30 to 1200 is not set for the MQTT client created using web sockets.?