Own fork of MbedSmartRest

Dependents:   MbedSmartRestMain MbedSmartRestMain

Fork of MbedSmartRest by Cumulocity Official

Committer:
xinlei
Date:
Mon Apr 13 14:24:44 2015 +0000
Revision:
20:505d29d5bdfc
Parent:
19:81dfc04ce0bb
Child:
21:207549b3711e
v2.1rc1

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 17:b3a4b4bdfc59 45 #define MBCL_DBG(...) aDebug(__VA_ARGS__)
xinlei 17:b3a4b4bdfc59 46 //#define MBCL_DBG(fmt, ...)
xinlei 17:b3a4b4bdfc59 47 #define DNS_ENTRY_DURATION 50
Cumulocity 6:cd7ba1ddb664 48
xinlei 20:505d29d5bdfc 49 MbedClient::MbedClient(MDMSerial& mdm, uint8_t tries) :
Cumulocity 6:cd7ba1ddb664 50 _tries(tries),
Cumulocity 6:cd7ba1ddb664 51 _state(STATE_INIT),
Cumulocity 11:e1bee9a77652 52 _isStreamRequest(false),
xinlei 19:81dfc04ce0bb 53 _sock(),
Cumulocity 2:45a6e44a4fb4 54 _source(_sock),
Cumulocity 2:45a6e44a4fb4 55 _sink(_sock),
xinlei 19:81dfc04ce0bb 56 _filter(_source),
xinlei 17:b3a4b4bdfc59 57 _mdm(mdm),
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 20:505d29d5bdfc 71 MBCL_DBG("\033[32mMbedClient:\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 20:505d29d5bdfc 91 MBCL_DBG("\033[32mMbedClient:\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 20:505d29d5bdfc 105 MBCL_DBG("\033[32mMbedClient:\033[39m Send identifier.\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 20:505d29d5bdfc 121 MBCL_DBG("\033[32mMbedClient:\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 20:505d29d5bdfc 139 MBCL_DBG("\033[32mMbedClient:\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 20:505d29d5bdfc 163 aDebug("\033[32mThread %p:\033[39m Await response.\n", Thread::gettid());
xinlei 18:16192696c106 164 if (_state != STATE_REQ_COMPLETE) {
Cumulocity 6:cd7ba1ddb664 165 return internalError();
xinlei 18:16192696c106 166 }
xinlei 20:505d29d5bdfc 167 // set timeout to fifteen minutes if stream request flag set
xinlei 20:505d29d5bdfc 168 if (_isStreamRequest) {
xinlei 20:505d29d5bdfc 169 _source.setTimeout(300000);
xinlei 20:505d29d5bdfc 170 }
Cumulocity 0:099f76422485 171
xinlei 18:16192696c106 172 uint8_t status = _filter.readStatus();
xinlei 18:16192696c106 173 if ((status != 200) || (!_filter.skipHeaders())) {
Cumulocity 6:cd7ba1ddb664 174 return connectionError();
xinlei 20:505d29d5bdfc 175 }
Cumulocity 0:099f76422485 176
Cumulocity 6:cd7ba1ddb664 177 _state = STATE_RECVD_RESPONSE;
Cumulocity 0:099f76422485 178 return CLIENT_OK;
Cumulocity 0:099f76422485 179 }
Cumulocity 0:099f76422485 180
Cumulocity 0:099f76422485 181 AbstractDataSource& MbedClient::receiveData()
Cumulocity 0:099f76422485 182 {
Cumulocity 0:099f76422485 183 return _filter;
Cumulocity 0:099f76422485 184 }
Cumulocity 0:099f76422485 185
Cumulocity 0:099f76422485 186 void MbedClient::stop()
Cumulocity 0:099f76422485 187 {
xinlei 20:505d29d5bdfc 188 MBCL_DBG("\033[32mMbedClient:\033[39m Reset client, %zu bytes sent.\n", packetSize);
Cumulocity 11:e1bee9a77652 189 _isStreamRequest = false;
Cumulocity 0:099f76422485 190 _sock.close();
Cumulocity 0:099f76422485 191 _source.reset();
Cumulocity 0:099f76422485 192 _sink.reset();
Cumulocity 0:099f76422485 193 _filter.reset();
Cumulocity 6:cd7ba1ddb664 194 _state = STATE_INIT;
Cumulocity 0:099f76422485 195 }
Cumulocity 0:099f76422485 196
Cumulocity 11:e1bee9a77652 197 bool MbedClient::connect()
Cumulocity 11:e1bee9a77652 198 {
xinlei 20:505d29d5bdfc 199 uint8_t tries = _tries;
Cumulocity 11:e1bee9a77652 200 do {
xinlei 17:b3a4b4bdfc59 201 if (cachedIPValid == 0) {
xinlei 20:505d29d5bdfc 202 MDMParser::IP ip = _mdm.gethostbyname(getHost());
xinlei 20:505d29d5bdfc 203 if (ip == NOIP)
xinlei 17:b3a4b4bdfc59 204 continue;
xinlei 17:b3a4b4bdfc59 205 const unsigned char *c = (const unsigned char*)&ip;
xinlei 17:b3a4b4bdfc59 206 snprintf(cachedIP, sizeof(cachedIP), "%u.%u.%u.%u", c[3], c[2], c[1], c[0]);
xinlei 20:505d29d5bdfc 207 aInfo("\033[32mThread %p:\033[39m Connect to %s:%u (IP: %s)\n", Thread::gettid(), getHost(), getPort(), cachedIP);
xinlei 17:b3a4b4bdfc59 208 } else {
xinlei 20:505d29d5bdfc 209 aDebug("\033[32mMThread %p:\033[39m Connect to %s:%u\n", Thread::gettid(), cachedIP, getPort());
xinlei 17:b3a4b4bdfc59 210 }
xinlei 20:505d29d5bdfc 211 if (_sock.connect(cachedIP, getPort()) >= 0)
Cumulocity 11:e1bee9a77652 212 break;
xinlei 17:b3a4b4bdfc59 213 cachedIPValid = 0;
Cumulocity 11:e1bee9a77652 214 _sock.close();
xinlei 20:505d29d5bdfc 215 aCritical("\033[32mThread %p:\033[39m Connect failed.\n", Thread::gettid());
Cumulocity 11:e1bee9a77652 216 } while (--tries > 0);
Cumulocity 11:e1bee9a77652 217
xinlei 17:b3a4b4bdfc59 218 cachedIPValid = (cachedIPValid+1) % DNS_ENTRY_DURATION;
Cumulocity 11:e1bee9a77652 219 return (tries > 0);
Cumulocity 11:e1bee9a77652 220 }
Cumulocity 11:e1bee9a77652 221
Cumulocity 0:099f76422485 222 bool MbedClient::send(const char *str)
Cumulocity 0:099f76422485 223 {
Cumulocity 7:8159a2d12e4e 224 return (_sink.write(str) == strlen(str));
Cumulocity 0:099f76422485 225 }
Cumulocity 0:099f76422485 226
Cumulocity 11:e1bee9a77652 227 bool MbedClient::sendRequestHeader(const char *uri)
Cumulocity 11:e1bee9a77652 228 {
xinlei 20:505d29d5bdfc 229 MBCL_DBG("\033[32mMbedClient:\033[39m Send header.\n");
Cumulocity 11:e1bee9a77652 230 if ((!send("POST ")) ||
Cumulocity 11:e1bee9a77652 231 (!send(uri)) ||
Cumulocity 12:6634f9814235 232 (!send(" HTTP/1.0\r\n")) ||
Cumulocity 11:e1bee9a77652 233 (!send("Host: ")) ||
xinlei 20:505d29d5bdfc 234 (!send(getHost())) ||
Cumulocity 11:e1bee9a77652 235 (!send("\r\n")))
Cumulocity 11:e1bee9a77652 236 return false;
Cumulocity 11:e1bee9a77652 237
Cumulocity 11:e1bee9a77652 238 return sendBasicAuth();
Cumulocity 11:e1bee9a77652 239 }
Cumulocity 11:e1bee9a77652 240
Cumulocity 0:099f76422485 241 bool MbedClient::sendBasicAuth()
Cumulocity 0:099f76422485 242 {
Cumulocity 11:e1bee9a77652 243 // no need to send authorization if not specified
xinlei 20:505d29d5bdfc 244 const char* _username = getUsername();
xinlei 20:505d29d5bdfc 245 const char* _password = getPassword();
Cumulocity 11:e1bee9a77652 246 if ((_username == NULL) || (strlen(_username) == 0) ||
Cumulocity 11:e1bee9a77652 247 (_password == NULL) || (strlen(_password) == 0))
Cumulocity 11:e1bee9a77652 248 return true;
Cumulocity 11:e1bee9a77652 249
Cumulocity 0:099f76422485 250 if (!send("Authorization: Basic "))
Cumulocity 0:099f76422485 251 return false;
xinlei 20:505d29d5bdfc 252
xinlei 20:505d29d5bdfc 253 if (!send(getAuthStr()))
xinlei 20:505d29d5bdfc 254 return false;
Cumulocity 0:099f76422485 255
Cumulocity 0:099f76422485 256 if (!send("\r\n"))
Cumulocity 0:099f76422485 257 return false;
Cumulocity 0:099f76422485 258 return true;
Cumulocity 0:099f76422485 259 }
Cumulocity 6:cd7ba1ddb664 260
Cumulocity 6:cd7ba1ddb664 261 uint8_t MbedClient::internalError()
Cumulocity 6:cd7ba1ddb664 262 {
xinlei 20:505d29d5bdfc 263 aError("\033[32mMbedClient:\033[39m Internal error.\n");
Cumulocity 6:cd7ba1ddb664 264 _state = STATE_INTERNAL_ERROR;
Cumulocity 6:cd7ba1ddb664 265 return CLIENT_INTERNAL_ERROR;
Cumulocity 6:cd7ba1ddb664 266 }
Cumulocity 6:cd7ba1ddb664 267
Cumulocity 6:cd7ba1ddb664 268 uint8_t MbedClient::connectionError()
Cumulocity 6:cd7ba1ddb664 269 {
xinlei 20:505d29d5bdfc 270 aError("\033[32mMbedClient:\033[39m Connect error.\n");
Cumulocity 6:cd7ba1ddb664 271 _state = STATE_INTERNAL_ERROR;
Cumulocity 6:cd7ba1ddb664 272 return CLIENT_CONNECTION_ERROR;
Cumulocity 6:cd7ba1ddb664 273 }
Cumulocity 6:cd7ba1ddb664 274