Проблема подключения клиента MQTT к серверу MQTT в Android в изолированной сети - PullRequest
0 голосов
/ 29 мая 2019

У меня ядро ​​Greengrass (Jetson TX2), транслирующее изолированную точку доступа, чтобы разные устройства IoT могли общаться друг с другом.Точка доступа работает так, как мне удалось подключить одно устройство к ядру по протоколу OSC.

Сейчас я пытаюсь заставить свои умные часы (работающие на WearOS) взаимодействовать с AWS Greengrass MQTT.Для этого требуется соединение SSL вместе с групповым сертификатом, предоставленным ядром.Моя реализация работает, когда ядро ​​и умные часы подключаются к сети с активным интернет-соединением.Однако, когда я пытаюсь передать их через изолированную точку доступа, умные часы не могут связаться с ядром

. Я реализую связь через paho.mqtt.android с socketFactory для хранения моих ключей и сертификатов.Я не уверен, из-за чего мое приложение не может обмениваться данными с моим основным процессором

Я попытался изолировать проблему, и кажется, что умные часы подключились к точке доступа и получили и IP-адрес.Однако библиотека paho.mqtt.android не использует этот IP-адрес для инициирования MQTT-соединения

. Именно так я реализую клиент из часов

AWSMQTTService.kt

 // ... other code
 socketFactory = AWSIotSslUtility.getSocketFactory(
            applicationContext.resources.openRawResource(R.raw.groupca),
            applicationContext.resources.openRawResource(R.raw.fc7334298c_certificate),
            applicationContext.resources.openRawResource(R.raw.fc7334298c_private)
        )
        mqttClient = MqttAndroidClient(this, "ssl://${getEdgeEndpoint()}:8883", getDeviceName())
        val mqttOptions = MqttConnectOptions()
        mqttOptions.connectionTimeout = 5
        mqttOptions.isAutomaticReconnect = true
        mqttOptions.socketFactory = socketFactory
        mqttClient.connect(mqttOptions, null, object : IMqttActionListener {
            override fun onSuccess(asyncActionToken: IMqttToken?) {
                debugLog("success")
            }

            override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable) {
                debugLog("failure")
                Log.e("Jarvis/err", "Failure", exception)
            }

        })

AWSIotSslUtility.kt

/*
 * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.shelltechworks.jarviswear.lib.utils

import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.bouncycastle.openssl.PEMKeyPair
import org.bouncycastle.openssl.PEMParser
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter
import java.io.*
import java.security.cert.CertificateFactory
import java.security.cert.Certificate as Certificate
import java.security.*
import java.security.Security
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManagerFactory


/**
 * This is a helper class to facilitate reading of the configurations and
 * certificate from the resource files.
 */
object AWSIotSslUtility {
    @Throws(Exception::class)
    fun getSocketFactory(
        caCrtFile: InputStream,
        crtFile: InputStream, keyFile: InputStream
    ): SSLSocketFactory {
        Security.addProvider(BouncyCastleProvider())
        val cf = CertificateFactory.getInstance("X.509")

        val caCert = cf.generateCertificate(caCrtFile)

        val cert = cf.generateCertificate(crtFile)

        // load client private key
        val pemParser = PEMParser(InputStreamReader(keyFile))

        val pemRawValue = pemParser.readObject()
        val converter = JcaPEMKeyConverter()
            .setProvider("BC")
        val key: KeyPair
        key = converter.getKeyPair(pemRawValue as PEMKeyPair)
        pemParser.close()

        // CA certificate is used to authenticate server
        val caKs = KeyStore.getInstance(KeyStore.getDefaultType())
        caKs.load(null, null)
        caKs.setCertificateEntry("ca-certificate", caCert)
        val tmf = TrustManagerFactory.getInstance("X509")
        tmf.init(caKs)

        // client key and certificates are sent to server so it can authenticate
        // us
        val ks = KeyStore.getInstance(KeyStore.getDefaultType())
        ks.load(null, null)
        ks.setCertificateEntry("certificate", cert)
        ks.setKeyEntry(
            "private-key", key.private, "".toCharArray(),
            arrayOf(cert)
        )
        val kmf = KeyManagerFactory.getInstance(
            KeyManagerFactory.getDefaultAlgorithm()
        )
        kmf.init(ks, "".toCharArray())

        // finally, create SSL socket factory
        val context = SSLContext.getInstance("TLSv1.2")
        context.init(kmf.keyManagers, tmf.trustManagers, null)
        return context.socketFactory
    }
}

Я ожидаю, что это подключится и напечатает success в журнале отладки.Однако я получил эту ошибку

2019-05-29 16:18:31.259 13475-13475/com.shelltechworks.jarviswear D/Jarvis/AWSMQTTService: failure
2019-05-29 16:18:31.270 13475-13475/com.shelltechworks.jarviswear E/Jarvis/err: Failure
    MqttException (0) - java.net.SocketTimeoutException: failed to connect to /192.168.12.1 (port 8883) from /192.168.167.239 (port 41415) after 5000ms
        at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:38)
        at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:715)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: java.net.SocketTimeoutException: failed to connect to /192.168.12.1 (port 8883) from /192.168.167.239 (port 41415) after 5000ms
        at libcore.io.IoBridge.connectErrno(IoBridge.java:185)
        at libcore.io.IoBridge.connect(IoBridge.java:130)
        at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:129)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:356)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:356)
        at java.net.Socket.connect(Socket.java:616)
        at org.eclipse.paho.client.mqttv3.internal.TCPNetworkModule.start(TCPNetworkModule.java:80)
        at org.eclipse.paho.client.mqttv3.internal.SSLNetworkModule.start(SSLNetworkModule.java:103)
        at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:701)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) 
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
        at java.lang.Thread.run(Thread.java:764) 

...