Own fork of MbedSmartRest

Dependents:   MbedSmartRestMain MbedSmartRestMain

Fork of MbedSmartRest by Cumulocity Official

Committer:
xinlei
Date:
Mon Aug 10 10:39:53 2015 +0000
Revision:
26:9c36af176d91
Parent:
25:b8a080f5e578
removed traffic accounting

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Cumulocity 0:099f76422485 1 /*
Cumulocity 0:099f76422485 2 * MbedClient.cpp
Cumulocity 0:099f76422485 3 *
Cumulocity 0:099f76422485 4 * Created on: Feb 1, 2013
Cumulocity 0:099f76422485 5 * * Authors: Vincent Wochnik <v.wochnik@gmail.com>
Cumulocity 0:099f76422485 6 *
Cumulocity 0:099f76422485 7 * Copyright (c) 2013 Cumulocity GmbH
Cumulocity 0:099f76422485 8 *
Cumulocity 0:099f76422485 9 * Permission is hereby granted, free of charge, to any person obtaining
Cumulocity 0:099f76422485 10 * a copy of this software and associated documentation files (the
Cumulocity 0:099f76422485 11 * "Software"), to deal in the Software without restriction, including
Cumulocity 0:099f76422485 12 * without limitation the rights to use, copy, modify, merge, publish,
Cumulocity 0:099f76422485 13 * distribute, sublicense, and/or sell copies of the Software, and to
Cumulocity 0:099f76422485 14 * permit persons to whom the Software is furnished to do so, subject to
Cumulocity 0:099f76422485 15 * the following conditions:
Cumulocity 0:099f76422485 16 *
Cumulocity 0:099f76422485 17 * The above copyright notice and this permission notice shall be
Cumulocity 0:099f76422485 18 * included in all copies or substantial portions of the Software.
Cumulocity 0:099f76422485 19 *
Cumulocity 0:099f76422485 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Cumulocity 0:099f76422485 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Cumulocity 0:099f76422485 22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Cumulocity 0:099f76422485 23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
Cumulocity 0:099f76422485 24 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
Cumulocity 0:099f76422485 25 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Cumulocity 0:099f76422485 26 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Cumulocity 0:099f76422485 27 */
Cumulocity 0:099f76422485 28
Cumulocity 0:099f76422485 29 #include <stdlib.h>
Cumulocity 0:099f76422485 30 #include <string.h>
Cumulocity 0:099f76422485 31 #include "mbed.h"
xinlei 20:505d29d5bdfc 32 #include "rtos.h"
xinlei 20:505d29d5bdfc 33
xinlei 17:b3a4b4bdfc59 34 #include "MbedClient.h"
xinlei 20:505d29d5bdfc 35 #include "SmartRestConf.h"
xinlei 17:b3a4b4bdfc59 36 #include "logging.h"
Cumulocity 0:099f76422485 37
Cumulocity 6:cd7ba1ddb664 38 #define STATE_INIT 0
Cumulocity 6:cd7ba1ddb664 39 #define STATE_IN_REQUEST 1
Cumulocity 6:cd7ba1ddb664 40 #define STATE_SENT_ID 2
Cumulocity 6:cd7ba1ddb664 41 #define STATE_SENT_DATA 3
Cumulocity 6:cd7ba1ddb664 42 #define STATE_REQ_COMPLETE 4
Cumulocity 6:cd7ba1ddb664 43 #define STATE_RECVD_RESPONSE 5
Cumulocity 6:cd7ba1ddb664 44 #define STATE_INTERNAL_ERROR 6
xinlei 24:11fd6fd14c28 45
xinlei 17:b3a4b4bdfc59 46 #define MBCL_DBG(...) aDebug(__VA_ARGS__)
xinlei 24:11fd6fd14c28 47
xinlei 17:b3a4b4bdfc59 48 #define DNS_ENTRY_DURATION 50
Cumulocity 6:cd7ba1ddb664 49
xinlei 23:0529d6779ab1 50 MbedClient::MbedClient(uint8_t tries) :
Cumulocity 6:cd7ba1ddb664 51 _tries(tries),
Cumulocity 6:cd7ba1ddb664 52 _state(STATE_INIT),
Cumulocity 11:e1bee9a77652 53 _isStreamRequest(false),
xinlei 19:81dfc04ce0bb 54 _sock(),
Cumulocity 2:45a6e44a4fb4 55 _source(_sock),
Cumulocity 2:45a6e44a4fb4 56 _sink(_sock),
xinlei 19:81dfc04ce0bb 57 _filter(_source),
xinlei 17:b3a4b4bdfc59 58 cachedIPValid(0)
Cumulocity 0:099f76422485 59 {
Cumulocity 0:099f76422485 60 }
Cumulocity 0:099f76422485 61
Cumulocity 0:099f76422485 62 MbedClient::~MbedClient()
Cumulocity 0:099f76422485 63 {
Cumulocity 0:099f76422485 64 }
Cumulocity 0:099f76422485 65
Cumulocity 0:099f76422485 66 uint8_t MbedClient::beginRequest()
Cumulocity 0:099f76422485 67 {
Cumulocity 6:cd7ba1ddb664 68 if (_state != STATE_INIT)
Cumulocity 6:cd7ba1ddb664 69 return internalError();
Cumulocity 0:099f76422485 70
xinlei 25:b8a080f5e578 71 MBCL_DBG("\033[32mMbed:\033[39m Begin SmartREST request.\n");
Cumulocity 11:e1bee9a77652 72 _source.setTimeout(60000);
Cumulocity 11:e1bee9a77652 73 if (!connect())
Cumulocity 11:e1bee9a77652 74 return connectionError();
Cumulocity 6:cd7ba1ddb664 75
Cumulocity 11:e1bee9a77652 76 if (!sendRequestHeader("/s"))
Cumulocity 6:cd7ba1ddb664 77 return connectionError();
Cumulocity 0:099f76422485 78
Cumulocity 11:e1bee9a77652 79 _state = STATE_IN_REQUEST;
Cumulocity 11:e1bee9a77652 80 return CLIENT_OK;
Cumulocity 11:e1bee9a77652 81 }
Cumulocity 8:3a4dba260b71 82
Cumulocity 11:e1bee9a77652 83 uint8_t MbedClient::beginStream(const char *uri)
Cumulocity 11:e1bee9a77652 84 {
Cumulocity 11:e1bee9a77652 85 if (_state != STATE_INIT)
Cumulocity 11:e1bee9a77652 86 return internalError();
Cumulocity 11:e1bee9a77652 87
Cumulocity 11:e1bee9a77652 88 // set stream request flag to later set the timeout right
Cumulocity 11:e1bee9a77652 89 _isStreamRequest = true;
Cumulocity 11:e1bee9a77652 90
xinlei 25:b8a080f5e578 91 MBCL_DBG("\033[32mMbed:\033[39m Begin SmartREST stream.\n");
Cumulocity 11:e1bee9a77652 92 _source.setTimeout(60000);
Cumulocity 11:e1bee9a77652 93 if (!connect())
Cumulocity 6:cd7ba1ddb664 94 return connectionError();
Cumulocity 11:e1bee9a77652 95
Cumulocity 11:e1bee9a77652 96 if (!sendRequestHeader(uri))
Cumulocity 11:e1bee9a77652 97 return connectionError();
Cumulocity 0:099f76422485 98
Cumulocity 6:cd7ba1ddb664 99 _state = STATE_IN_REQUEST;
Cumulocity 0:099f76422485 100 return CLIENT_OK;
Cumulocity 0:099f76422485 101 }
Cumulocity 0:099f76422485 102
Cumulocity 0:099f76422485 103 uint8_t MbedClient::sendIdentifier(const char* identifier)
Cumulocity 0:099f76422485 104 {
xinlei 25:b8a080f5e578 105 MBCL_DBG("\033[32mMbed:\033[39m Send x-id.\n");
Cumulocity 6:cd7ba1ddb664 106 if (_state != STATE_IN_REQUEST)
Cumulocity 6:cd7ba1ddb664 107 return internalError();
Cumulocity 0:099f76422485 108
Cumulocity 0:099f76422485 109 if ((identifier != NULL) && (strlen(identifier) != 0)) {
Cumulocity 0:099f76422485 110 if ((!send("X-Id: ")) ||
Cumulocity 0:099f76422485 111 (!send(identifier)) ||
Cumulocity 0:099f76422485 112 (!send("\r\n")))
Cumulocity 6:cd7ba1ddb664 113 return connectionError();
Cumulocity 0:099f76422485 114 }
Cumulocity 6:cd7ba1ddb664 115 _state = STATE_SENT_ID;
Cumulocity 0:099f76422485 116 return CLIENT_OK;
Cumulocity 0:099f76422485 117 }
Cumulocity 0:099f76422485 118
Cumulocity 1:9a11a331e340 119 uint8_t MbedClient::sendData(const DataGenerator& generator)
Cumulocity 0:099f76422485 120 {
xinlei 25:b8a080f5e578 121 MBCL_DBG("\033[32mMbed:\033[39m Send payload.\n");
xinlei 20:505d29d5bdfc 122 if (_state != STATE_IN_REQUEST && _state != STATE_SENT_ID)
Cumulocity 6:cd7ba1ddb664 123 return internalError();
Cumulocity 0:099f76422485 124
xinlei 20:505d29d5bdfc 125 size_t len = generator.writtenLength();
Cumulocity 0:099f76422485 126 if ((!send("Content-Length: ")) ||
Cumulocity 7:8159a2d12e4e 127 (_sink.write((unsigned long)len) == 0) ||
Cumulocity 0:099f76422485 128 (!send("\r\n\r\n")))
Cumulocity 6:cd7ba1ddb664 129 return connectionError();
Cumulocity 0:099f76422485 130
Cumulocity 6:cd7ba1ddb664 131 if (generator.writeTo(_sink) != len)
Cumulocity 6:cd7ba1ddb664 132 return connectionError();
Cumulocity 6:cd7ba1ddb664 133 _state = STATE_SENT_DATA;
Cumulocity 0:099f76422485 134 return CLIENT_OK;
Cumulocity 0:099f76422485 135 }
Cumulocity 0:099f76422485 136
Cumulocity 0:099f76422485 137 uint8_t MbedClient::endRequest()
Cumulocity 0:099f76422485 138 {
xinlei 25:b8a080f5e578 139 MBCL_DBG("\033[32mMbed:\033[39m End request.\n");
Cumulocity 6:cd7ba1ddb664 140 if ((_state != STATE_IN_REQUEST) &&
Cumulocity 6:cd7ba1ddb664 141 (_state != STATE_SENT_ID) &&
xinlei 18:16192696c106 142 (_state != STATE_SENT_DATA)) {
Cumulocity 6:cd7ba1ddb664 143 return internalError();
xinlei 18:16192696c106 144 }
Cumulocity 0:099f76422485 145
Cumulocity 6:cd7ba1ddb664 146 if (_state != STATE_SENT_DATA) {
Cumulocity 0:099f76422485 147 // send end of headers
xinlei 18:16192696c106 148 if (!send("\r\n")) {
Cumulocity 6:cd7ba1ddb664 149 return connectionError();
xinlei 18:16192696c106 150 }
Cumulocity 0:099f76422485 151 }
Cumulocity 0:099f76422485 152
xinlei 18:16192696c106 153 if (!_sink.flush()) {
Cumulocity 6:cd7ba1ddb664 154 return connectionError();
xinlei 18:16192696c106 155 }
Cumulocity 0:099f76422485 156
Cumulocity 6:cd7ba1ddb664 157 _state = STATE_REQ_COMPLETE;
Cumulocity 0:099f76422485 158 return CLIENT_OK;
Cumulocity 0:099f76422485 159 }
Cumulocity 0:099f76422485 160
Cumulocity 0:099f76422485 161 uint8_t MbedClient::awaitResponse()
Cumulocity 0:099f76422485 162 {
xinlei 18:16192696c106 163 if (_state != STATE_REQ_COMPLETE) {
Cumulocity 6:cd7ba1ddb664 164 return internalError();
xinlei 18:16192696c106 165 }
xinlei 20:505d29d5bdfc 166 // set timeout to fifteen minutes if stream request flag set
xinlei 20:505d29d5bdfc 167 if (_isStreamRequest) {
xinlei 20:505d29d5bdfc 168 _source.setTimeout(300000);
xinlei 20:505d29d5bdfc 169 }
Cumulocity 0:099f76422485 170
xinlei 18:16192696c106 171 uint8_t status = _filter.readStatus();
xinlei 18:16192696c106 172 if ((status != 200) || (!_filter.skipHeaders())) {
Cumulocity 6:cd7ba1ddb664 173 return connectionError();
xinlei 20:505d29d5bdfc 174 }
Cumulocity 0:099f76422485 175
Cumulocity 6:cd7ba1ddb664 176 _state = STATE_RECVD_RESPONSE;
Cumulocity 0:099f76422485 177 return CLIENT_OK;
Cumulocity 0:099f76422485 178 }
Cumulocity 0:099f76422485 179
Cumulocity 0:099f76422485 180 AbstractDataSource& MbedClient::receiveData()
Cumulocity 0:099f76422485 181 {
Cumulocity 0:099f76422485 182 return _filter;
Cumulocity 0:099f76422485 183 }
Cumulocity 0:099f76422485 184
Cumulocity 0:099f76422485 185 void MbedClient::stop()
Cumulocity 0:099f76422485 186 {
Cumulocity 11:e1bee9a77652 187 _isStreamRequest = false;
Cumulocity 0:099f76422485 188 _sock.close();
Cumulocity 0:099f76422485 189 _source.reset();
Cumulocity 0:099f76422485 190 _sink.reset();
Cumulocity 0:099f76422485 191 _filter.reset();
Cumulocity 6:cd7ba1ddb664 192 _state = STATE_INIT;
Cumulocity 0:099f76422485 193 }
Cumulocity 0:099f76422485 194
Cumulocity 11:e1bee9a77652 195 bool MbedClient::connect()
Cumulocity 11:e1bee9a77652 196 {
xinlei 23:0529d6779ab1 197 extern MDMRtos<MDMSerial> *pMdm;
xinlei 20:505d29d5bdfc 198 uint8_t tries = _tries;
Cumulocity 11:e1bee9a77652 199 do {
xinlei 17:b3a4b4bdfc59 200 if (cachedIPValid == 0) {
xinlei 24:11fd6fd14c28 201 MDMParser::IP ip = pMdm->gethostbyname(srHost);
xinlei 20:505d29d5bdfc 202 if (ip == NOIP)
xinlei 17:b3a4b4bdfc59 203 continue;
xinlei 17:b3a4b4bdfc59 204 const unsigned char *c = (const unsigned char*)&ip;
xinlei 17:b3a4b4bdfc59 205 snprintf(cachedIP, sizeof(cachedIP), "%u.%u.%u.%u", c[3], c[2], c[1], c[0]);
xinlei 25:b8a080f5e578 206 aInfo("Connect to %s:%d (IP: %s)\n", srHost, ::srPort, cachedIP);
xinlei 17:b3a4b4bdfc59 207 } else {
xinlei 25:b8a080f5e578 208 aDebug("Connect to %s:%d\n", cachedIP, ::srPort);
xinlei 17:b3a4b4bdfc59 209 }
xinlei 24:11fd6fd14c28 210 if (_sock.connect(cachedIP, ::srPort) >= 0)
Cumulocity 11:e1bee9a77652 211 break;
xinlei 17:b3a4b4bdfc59 212 cachedIPValid = 0;
Cumulocity 11:e1bee9a77652 213 _sock.close();
xinlei 20:505d29d5bdfc 214 aCritical("\033[32mThread %p:\033[39m Connect failed.\n", Thread::gettid());
Cumulocity 11:e1bee9a77652 215 } while (--tries > 0);
Cumulocity 11:e1bee9a77652 216
xinlei 17:b3a4b4bdfc59 217 cachedIPValid = (cachedIPValid+1) % DNS_ENTRY_DURATION;
Cumulocity 11:e1bee9a77652 218 return (tries > 0);
Cumulocity 11:e1bee9a77652 219 }
Cumulocity 11:e1bee9a77652 220
Cumulocity 0:099f76422485 221 bool MbedClient::send(const char *str)
Cumulocity 0:099f76422485 222 {
Cumulocity 7:8159a2d12e4e 223 return (_sink.write(str) == strlen(str));
Cumulocity 0:099f76422485 224 }
Cumulocity 0:099f76422485 225
Cumulocity 11:e1bee9a77652 226 bool MbedClient::sendRequestHeader(const char *uri)
Cumulocity 11:e1bee9a77652 227 {
xinlei 25:b8a080f5e578 228 MBCL_DBG("\033[32mMbed:\033[39m Send header.\n");
Cumulocity 11:e1bee9a77652 229 if ((!send("POST ")) ||
Cumulocity 11:e1bee9a77652 230 (!send(uri)) ||
Cumulocity 12:6634f9814235 231 (!send(" HTTP/1.0\r\n")) ||
Cumulocity 11:e1bee9a77652 232 (!send("Host: ")) ||
xinlei 24:11fd6fd14c28 233 (!send(srHost)) ||
Cumulocity 11:e1bee9a77652 234 (!send("\r\n")))
Cumulocity 11:e1bee9a77652 235 return false;
Cumulocity 11:e1bee9a77652 236
Cumulocity 11:e1bee9a77652 237 return sendBasicAuth();
Cumulocity 11:e1bee9a77652 238 }
Cumulocity 11:e1bee9a77652 239
Cumulocity 0:099f76422485 240 bool MbedClient::sendBasicAuth()
Cumulocity 0:099f76422485 241 {
Cumulocity 11:e1bee9a77652 242 // no need to send authorization if not specified
xinlei 24:11fd6fd14c28 243 const char* _username = srUsername;
xinlei 24:11fd6fd14c28 244 const char* _password = srPassword;
Cumulocity 11:e1bee9a77652 245 if ((_username == NULL) || (strlen(_username) == 0) ||
Cumulocity 11:e1bee9a77652 246 (_password == NULL) || (strlen(_password) == 0))
Cumulocity 11:e1bee9a77652 247 return true;
Cumulocity 11:e1bee9a77652 248
Cumulocity 0:099f76422485 249 if (!send("Authorization: Basic "))
Cumulocity 0:099f76422485 250 return false;
xinlei 21:207549b3711e 251
xinlei 24:11fd6fd14c28 252 if (!send(srAuthStr))
xinlei 20:505d29d5bdfc 253 return false;
xinlei 21:207549b3711e 254
Cumulocity 0:099f76422485 255 if (!send("\r\n"))
Cumulocity 0:099f76422485 256 return false;
Cumulocity 0:099f76422485 257 return true;
Cumulocity 0:099f76422485 258 }
Cumulocity 6:cd7ba1ddb664 259
Cumulocity 6:cd7ba1ddb664 260 uint8_t MbedClient::internalError()
Cumulocity 6:cd7ba1ddb664 261 {
xinlei 25:b8a080f5e578 262 aError("\033[32mMbed:\033[39m Internal error.\n");
Cumulocity 6:cd7ba1ddb664 263 _state = STATE_INTERNAL_ERROR;
Cumulocity 6:cd7ba1ddb664 264 return CLIENT_INTERNAL_ERROR;
Cumulocity 6:cd7ba1ddb664 265 }
Cumulocity 6:cd7ba1ddb664 266
Cumulocity 6:cd7ba1ddb664 267 uint8_t MbedClient::connectionError()
Cumulocity 6:cd7ba1ddb664 268 {
xinlei 25:b8a080f5e578 269 aError("\033[32mMbed:\033[39m Connect error.\n");
Cumulocity 6:cd7ba1ddb664 270 _state = STATE_INTERNAL_ERROR;
Cumulocity 6:cd7ba1ddb664 271 return CLIENT_CONNECTION_ERROR;
Cumulocity 6:cd7ba1ddb664 272 }
Cumulocity 6:cd7ba1ddb664 273