Had to fork with a different name, because of some incompatibility issues.
Diff: DeviceClient.cpp
- Revision:
- 5:ea9f483e0294
- Parent:
- 3:3d91bf839b49
- Child:
- 7:b14763b63562
--- a/DeviceClient.cpp Mon Mar 20 10:07:49 2017 +0000 +++ b/DeviceClient.cpp Tue May 30 06:24:06 2017 +0000 @@ -13,6 +13,8 @@ * Contributors: * Sathisumar Palaniappan - initial implementation * Sathisumar Palaniappan - added reconnect logic and isConnected() method + * Lokesh K Haralakatta - Port to mbed OS 5 support + * Lokesh K Haralakatta - Added SSL/TLS Support *******************************************************************************/ #include "MQTTClient.h" #include "DeviceClient.h" @@ -42,109 +44,126 @@ * This class allows device to publish events and receive commands to/from IBM IoT Foundation wtih simple function calls. */ DeviceClient::DeviceClient():org(NULL),deviceType(NULL),deviceId(NULL), - authMethod(NULL),authToken(NULL),mqttClient(ipstack),connected(false) + authMethod(NULL),authToken(NULL),mqttNetwork(NULL),mqttClient(NULL),connected(false),port(0) { - LOG("Constructor#1 called::\n"); + LOG("Constructor#1 called::\r\n"); } -DeviceClient::DeviceClient(char *orgId, char *typeId, char *id) - :org(orgId),deviceType(typeId),deviceId(id),authMethod(NULL), - authToken(NULL),mqttClient(ipstack),connected(false) +DeviceClient::DeviceClient(char *orgId, char *typeId, char *id, int port):org(orgId),deviceType(typeId), + deviceId(id),authMethod(NULL),authToken(NULL),connected(false), port(port) { - LOG("Constructor#2 called:: org=%s, type=%s, id=%s", (org==NULL)?"NULL":org, + LOG("Constructor#2 called:: org=%s, type=%s, id=%s\r\n", (org==NULL)?"NULL":org, (deviceType==NULL)?"NULL":deviceType, (deviceId==NULL)?"NULL":deviceId); - + if(strcmp(this->org, QUICKSTART) != 0) { - WARN("Registered flow must provide valid token"); + WARN("Registered flow must provide valid token\r\n"); } + + mqttNetwork = new MQTTNetwork(); + mqttClient = new MQTT::Client<MQTTNetwork, Countdown>(*mqttNetwork); + } -DeviceClient::DeviceClient(char *orgId, char *typeId, - char *id, char *method, char *token) - :org(orgId),deviceType(typeId),deviceId(id),authMethod(method), - authToken(token),mqttClient(ipstack),connected(false) +DeviceClient::DeviceClient(char *orgId, char *typeId,char *id, char *method, char *token, int port):org(orgId), + deviceType(typeId),deviceId(id),authMethod(method),authToken(token),connected(false), port(port) { // Don't print token for security reasons - LOG("Constructor#3 called:: org=%s, type=%s, id=%s", (org==NULL)?"NULL":org, + LOG("Constructor#3 called:: org=%s, type=%s, id=%s\r\n", (org==NULL)?"NULL":org, (deviceType==NULL)?"NULL":deviceType, (deviceId==NULL)?"NULL":deviceId); + + mqttNetwork = new MQTTNetwork(); + mqttClient = new MQTT::Client<MQTTNetwork, Countdown>(*mqttNetwork); } /** * Connect to the IBM Internet of Things Foundation - */ + */ bool DeviceClient::connect() -{ +{ char *organizationName, *typeId, *id; + bool rc = false; // Check if any organization is set - if(this->org == NULL || (strcmp("", this->org) == 0)) + if(this->org == NULL || (strcmp("", this->org) == 0)) { organizationName = QUICKSTART; } else { organizationName = this->org; } - + // Check if device type is already mentioned - if(this->deviceType == NULL || (strcmp("", this->deviceType) == 0)) + if(this->deviceType == NULL || (strcmp("", this->deviceType) == 0)) { typeId = "iotsample-mbed"; } else { typeId = this->deviceType; } - + char hostname[strlen(organizationName) + strlen(IBM_IOT_MESSAGING) + 1]; sprintf(hostname, "%s%s", organizationName, IBM_IOT_MESSAGING); - - EthernetInterface& eth = ipstack.getEth(); + + NetworkInterface* net = mqttNetwork->getEth(); + const char* ip = net->get_ip_address(); // Get devices MAC address if deviceId is not set already - if(this->deviceId == NULL || (strcmp("", this->deviceId) == 0)) + if(this->deviceId == NULL || (strcmp("", this->deviceId) == 0)) { char tmpBuf[50]; id = getMac(tmpBuf, sizeof(tmpBuf)); } else { id = this->deviceId; } - + // Construct clientId - d:org:type:id char clientId[strlen(organizationName) + strlen(typeId) + strlen(id) + 5]; sprintf(clientId, "d:%s:%s:%s", organizationName, typeId, id); - - logData(eth, hostname, clientId); - + // Initialize MQTT Connect MQTTPacket_connectData data = MQTTPacket_connectData_initializer; data.MQTTVersion = 4; data.clientID.cstring = clientId; - + int quickstartMode = (strcmp(organizationName, QUICKSTART) == 0); - - if (!quickstartMode) - { + + if (!quickstartMode) + { data.username.cstring = "use-token-auth"; data.password.cstring = this->authToken; - } - bool rc = tryConnect(hostname, data); - // By default subscribe to commands if we are in registered flow - if(rc == true && !quickstartMode) - { - subscribeToCommands(); + + //Check and initialize appropriate port + if(port == 1883) + port = MQTT_TLS_PORT; } - if(rc == true) - { - connected = true; + + logData(net, hostname, clientId); + + if(ip){ + rc = tryConnect(hostname, data); + // By default subscribe to commands if we are in registered flow + if(rc == true && !quickstartMode) + { + subscribeToCommands(); + } + if(rc == true) + { + connected = true; + LOG("Device Client Connected to %s:%d\r\n",hostname,port); + } } + else + LOG("No IP Assigned to Network Interface...\r\n"); + return rc; } /** * Reconnect when the connection is lost. This method disconnects the active connection if any - * and tries to initiate a fresh connection. + * and tries to initiate a fresh connection. * This method uses the Ethernet Link status wherever applicable while reconnecting. i.e, tries to * initiate the connection only when the Ethernet cable is plugged in. */ -bool DeviceClient::reConnect() +bool DeviceClient::reConnect() { - LOG("DeviceClient::reConnect() entry and connected = %s\n",(connected == true)?"true":"false"); + LOG("DeviceClient::reConnect() entry and connected = %s\r\n",(connected == true)?"true":"false"); if(connected == true) { disconnect(); @@ -152,13 +171,13 @@ if(linkStatus()) { - EthernetInterface& eth = ipstack.getEth(); - if(eth.connect() == 0) + NetworkInterface* net = mqttNetwork->getEth(); + if(net->connect() == 0) { bool status = connect(); - if(status == false) + if(status == false) { - eth.disconnect(); + net->disconnect(); } return status; } @@ -166,31 +185,31 @@ return false; } -bool DeviceClient::tryConnect(char *hostname, MQTTPacket_connectData &data) +bool DeviceClient::tryConnect(char *hostname, MQTTPacket_connectData &data) { int rc = -1; int retryAttempt = 0; - do { - rc = ipstack.connect(hostname, IBM_IOT_PORT, CONNECT_TIMEOUT); - if (rc != 0) + do { + rc = mqttNetwork->connect(hostname, port); + if (rc != 0) { - WARN("IP Stack connect returned: %d\n", rc); + WARN("mqttNetwork connect returned: %d\r\n", rc); } - // MQTT connect - if (rc == 0 && (rc = mqttClient.connect(data)) != 0) + // MQTT connect + if (rc == 0 && (rc = mqttClient->connect(data)) != 0) { - WARN("MQTT connect returned %d\n", rc); + WARN("MQTT connect returned %d\r\n", rc); if (rc == MQTT_NOT_AUTHORIZED || rc == MQTT_BAD_USERNAME_OR_PASSWORD) return false; // don't reattempt to connect if credentials are wrong } else if (rc == MQTT_CONNECTION_ACCEPTED) { return true; } - + int timeout = getConnTimeout(++retryAttempt); - - WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout); - + + WARN("Retry attempt number %d waiting %d\r\n", retryAttempt, timeout); + // enough retry is done - return to application if (retryAttempt == 5) return false; @@ -199,18 +218,19 @@ } while(true); } -void DeviceClient::logData(EthernetInterface& eth, char *hostname, char *clientId) +void DeviceClient::logData(NetworkInterface* net, char *hostname, char *clientId) { - // Network debug statements - LOG("=====================================\n"); - LOG("Connecting Ethernet.\n"); - LOG("IP ADDRESS: %s\n", eth.getIPAddress()); - LOG("MAC ADDRESS: %s\n", eth.getMACAddress()); - LOG("Gateway: %s\n", eth.getGateway()); - LOG("Network Mask: %s\n", eth.getNetworkMask()); - LOG("Server Hostname: %s\n", hostname); - LOG("Client ID: %s\n", clientId); - LOG("=====================================\n"); + // Network debug statements + LOG("=====================================\r\n"); + LOG("Connection Config Details:\r\n"); + LOG("IP ADDRESS: %s\r\n", net->get_ip_address()); + LOG("MAC ADDRESS: %s\r\n", net->get_mac_address()); + LOG("Gateway: %s\r\n", net->get_gateway()); + LOG("Network Mask: %s\r\n", net->get_netmask()); + LOG("Server Hostname: %s\r\n", hostname); + LOG("Server Port: %d\r\n", port); + LOG("Client ID: %s\r\n", clientId); + LOG("=====================================\r\n"); } int DeviceClient::getConnTimeout(int attemptNumber) @@ -223,22 +243,22 @@ * Returns the connection status, connected or disconnected. */ bool DeviceClient::isConnected() { - return mqttClient.isConnected(); + return mqttClient->isConnected(); } /** - * Publish data to the IBM Internet of Things Foundation. Note that data is published - * by default at Quality of Service (QoS) 0, which means that a successful send + * Publish data to the IBM Internet of Things Foundation. Note that data is published + * by default at Quality of Service (QoS) 0, which means that a successful send * does not guarantee receipt even if the publish has been successful. */ bool DeviceClient::publishEvent(char *eventName, char *data, MQTT::QoS qos) { - if(!mqttClient.isConnected()) + if(!mqttClient->isConnected()) { - WARN("Client is not connected \n"); + WARN("Client is not connected \r\n"); return false; } - + MQTT::Message message; /* Topic format must be iot-2/evt/<eventName>/fmt/json (let us stick to json format for now) * @@ -247,22 +267,22 @@ * /fmt/json = 9 * NULL char = 1 */ - + char topic[10 + strlen(eventName) + 9 + 1]; sprintf(topic, "%s%s%s", "iot-2/evt/", eventName, "/fmt/json"); - + message.qos = qos; message.retained = false; message.dup = false; message.payload = (void*)data; message.payloadlen = strlen(data); - - LOG("Publishing %s\n", data); - int rc = mqttClient.publish(topic, message); + + LOG("Publishing %s\r\n", data); + int rc = mqttClient->publish(topic, message); return rc == 0; } -void DeviceClient::setCommandCallback(CommandHandler callbackFunc) +void DeviceClient::setCommandCallback(CommandHandler callbackFunc) { handler = callbackFunc; } @@ -270,51 +290,51 @@ * Subscribe to commands from the application. This will be executed only for * registered flow (quickstart flow does not support command publish) */ -int DeviceClient::subscribeToCommands() +int DeviceClient::subscribeToCommands() { int rc = 0; // iot-2/cmd/+/fmt/+ - if ((rc = mqttClient.subscribe("iot-2/cmd/+/fmt/+", MQTT::QOS2, msgArrived)) != 0) - WARN("rc from MQTT subscribe is %d\n", rc); + if ((rc = mqttClient->subscribe("iot-2/cmd/+/fmt/+", MQTT::QOS2, msgArrived)) != 0) + WARN("rc from MQTT subscribe is %d\r\n", rc); return rc; } /** - * Callback method to be registered with MQTT::Client. MQTT::Client calls whenever + * Callback method to be registered with MQTT::Client. MQTT::Client calls whenever * any command is published to the topic subscribed earlier. */ void msgArrived(MQTT::MessageData& md) { // check whether callback is registered by the client code - if(handler == NULL) + if(handler == NULL) { return; } - + MQTT::Message &message = md.message; char topic[md.topicName.lenstring.len + 1]; - + sprintf(topic, "%.*s", md.topicName.lenstring.len, md.topicName.lenstring.data); - - LOG("Message arrived on topic %s: %.*s\n", topic, message.payloadlen, message.payload); - + + LOG("Message arrived on topic %s: %.*s\r\n", topic, message.payloadlen, message.payload); + // Command topic: iot-2/cmd/blink/fmt/json - cmd is the string between cmd/ and /fmt/ char* start = strstr(topic, "/cmd/") + 5; int len = strstr(topic, "/fmt/") - start; char name[len + 1]; - + memcpy(name, start, len); name[len] = NULL; - + start = strstr(topic, "/fmt/") + 5; - + char format[20]; // ToDO: need to find the length of the format strcpy(format, start); - + char payload[message.payloadlen + 1]; sprintf(payload, "%.*s", message.payloadlen, (char*)message.payload); - + IoTF::Command cmd(name, format, payload); (*handler)(cmd); } @@ -322,34 +342,34 @@ /** * Disconnects the connection in order. */ -bool DeviceClient::disconnect() +bool DeviceClient::disconnect() { int rc = 0; - if(mqttClient.isConnected()) + if(mqttClient->isConnected()) { - rc = mqttClient.disconnect(); + rc = mqttClient->disconnect(); } - - EthernetInterface& eth = ipstack.getEth(); - ipstack.disconnect(); - eth.disconnect(); + + NetworkInterface* net = mqttNetwork->getEth(); + mqttNetwork->disconnect(); + net->disconnect(); connected = false; return rc == 0; } // Yield to allow MQTT client to process the command -void DeviceClient::yield(int ms) +void DeviceClient::yield(int ms) { - if(mqttClient.isConnected()) + if(mqttClient->isConnected()) { - mqttClient.yield(ms); + mqttClient->yield(ms); } } // Obtain DeviceId address -char* DeviceClient::getDeviceId(char* buf, int buflen) -{ - if(this->deviceId == NULL || (strcmp("", this->deviceId) == 0)) +char* DeviceClient::getDeviceId(char* buf, int buflen) +{ + if(this->deviceId == NULL || (strcmp("", this->deviceId) == 0)) { return getMac(buf, buflen); } else { @@ -357,13 +377,13 @@ } } // Obtain MAC address -char* DeviceClient::getMac(char* buf, int buflen) -{ - EthernetInterface& eth = ipstack.getEth(); - strncpy(buf, eth.getMACAddress(), buflen); +char* DeviceClient::getMac(char* buf, int buflen) +{ + NetworkInterface* net = mqttNetwork->getEth(); + strncpy(buf, net->get_mac_address(), buflen); char* pos; // Remove colons from mac address while ((pos = strchr(buf, ':')) != NULL) memmove(pos, pos + 1, strlen(pos) + 1); return buf; -} \ No newline at end of file +}