Own fork of MbedSmartRest

Dependents:   MbedSmartRestMain MbedSmartRestMain

Fork of MbedSmartRest by Cumulocity Official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MbedClient.cpp Source File

MbedClient.cpp

00001 /*
00002  * MbedClient.cpp
00003  *
00004  * Created on: Feb 1, 2013
00005  * * Authors: Vincent Wochnik <v.wochnik@gmail.com>
00006  *
00007  * Copyright (c) 2013 Cumulocity GmbH
00008  *
00009  * Permission is hereby granted, free of charge, to any person obtaining
00010  * a copy of this software and associated documentation files (the
00011  * "Software"), to deal in the Software without restriction, including
00012  * without limitation the rights to use, copy, modify, merge, publish,
00013  * distribute, sublicense, and/or sell copies of the Software, and to
00014  * permit persons to whom the Software is furnished to do so, subject to
00015  * the following conditions:
00016  *
00017  * The above copyright notice and this permission notice shall be
00018  * included in all copies or substantial portions of the Software.
00019  *
00020  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00021  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00022  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00023  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00024  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00025  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00026  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00027  */
00028 
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include "mbed.h"
00032 #include "rtos.h"
00033 
00034 #include "MbedClient.h"
00035 #include "SmartRestConf.h"
00036 #include "logging.h"
00037 
00038 #define STATE_INIT 0
00039 #define STATE_IN_REQUEST 1
00040 #define STATE_SENT_ID 2
00041 #define STATE_SENT_DATA 3
00042 #define STATE_REQ_COMPLETE 4
00043 #define STATE_RECVD_RESPONSE 5
00044 #define STATE_INTERNAL_ERROR 6
00045 
00046 #define MBCL_DBG(...) aDebug(__VA_ARGS__)
00047 
00048 #define DNS_ENTRY_DURATION 50
00049 
00050 MbedClient::MbedClient(uint8_t tries) :
00051     _tries(tries),
00052     _state(STATE_INIT),
00053     _isStreamRequest(false),
00054     _sock(),
00055     _source(_sock),
00056     _sink(_sock),
00057     _filter(_source),
00058     cachedIPValid(0)
00059 {
00060 }
00061 
00062 MbedClient::~MbedClient()
00063 {
00064 }
00065 
00066 uint8_t MbedClient::beginRequest()
00067 {
00068     if (_state != STATE_INIT)
00069         return internalError();
00070 
00071     MBCL_DBG("\033[32mMbed:\033[39m Begin SmartREST request.\n");
00072     _source.setTimeout(60000);
00073     if (!connect())
00074         return connectionError();
00075 
00076     if (!sendRequestHeader("/s"))
00077         return connectionError();
00078 
00079     _state = STATE_IN_REQUEST;
00080     return CLIENT_OK;
00081 }
00082 
00083 uint8_t MbedClient::beginStream(const char *uri)
00084 {
00085     if (_state != STATE_INIT)
00086         return internalError();
00087 
00088     // set stream request flag to later set the timeout right
00089     _isStreamRequest = true;
00090 
00091     MBCL_DBG("\033[32mMbed:\033[39m Begin SmartREST stream.\n");
00092     _source.setTimeout(60000);
00093     if (!connect())
00094         return connectionError();
00095 
00096     if (!sendRequestHeader(uri))
00097         return connectionError();
00098 
00099     _state = STATE_IN_REQUEST;
00100     return CLIENT_OK;
00101 }
00102 
00103 uint8_t MbedClient::sendIdentifier(const char* identifier)
00104 {
00105     MBCL_DBG("\033[32mMbed:\033[39m Send x-id.\n");
00106     if (_state != STATE_IN_REQUEST)
00107         return internalError();
00108 
00109     if ((identifier != NULL) && (strlen(identifier) != 0)) {
00110         if ((!send("X-Id: ")) ||
00111             (!send(identifier)) ||
00112             (!send("\r\n")))
00113             return connectionError();
00114     }
00115     _state = STATE_SENT_ID;
00116     return CLIENT_OK;
00117 }
00118 
00119 uint8_t MbedClient::sendData(const DataGenerator& generator)
00120 {
00121     MBCL_DBG("\033[32mMbed:\033[39m Send payload.\n");
00122     if (_state != STATE_IN_REQUEST && _state != STATE_SENT_ID)
00123         return internalError();
00124     
00125     size_t len = generator.writtenLength();
00126     if ((!send("Content-Length: ")) ||
00127         (_sink.write((unsigned long)len) == 0) ||
00128         (!send("\r\n\r\n")))
00129         return connectionError();
00130 
00131     if (generator.writeTo(_sink) != len)
00132         return connectionError();
00133     _state = STATE_SENT_DATA;
00134     return CLIENT_OK;
00135 }
00136 
00137 uint8_t MbedClient::endRequest()
00138 {
00139     MBCL_DBG("\033[32mMbed:\033[39m End request.\n");
00140     if ((_state != STATE_IN_REQUEST) &&
00141         (_state != STATE_SENT_ID) &&
00142         (_state != STATE_SENT_DATA)) {
00143         return internalError();
00144     }
00145     
00146     if (_state != STATE_SENT_DATA) {
00147         // send end of headers
00148         if (!send("\r\n")) {
00149             return connectionError();
00150         }
00151     }
00152     
00153     if (!_sink.flush()) {
00154         return connectionError();
00155     }
00156     
00157     _state = STATE_REQ_COMPLETE;
00158     return CLIENT_OK;
00159 }
00160 
00161 uint8_t MbedClient::awaitResponse()
00162 {
00163     if (_state != STATE_REQ_COMPLETE) {
00164         return internalError();
00165     }
00166     // set timeout to fifteen minutes if stream request flag set
00167     if (_isStreamRequest) {
00168         _source.setTimeout(300000);
00169     }
00170     
00171     uint8_t status = _filter.readStatus();
00172     if ((status != 200) || (!_filter.skipHeaders())) {
00173         return connectionError();
00174     }    
00175     
00176     _state = STATE_RECVD_RESPONSE;
00177     return CLIENT_OK;
00178 }
00179 
00180 AbstractDataSource& MbedClient::receiveData()
00181 {
00182     return _filter;
00183 }
00184 
00185 void MbedClient::stop()
00186 {
00187     _isStreamRequest = false;
00188     _sock.close();
00189     _source.reset();
00190     _sink.reset();
00191     _filter.reset();
00192     _state = STATE_INIT;
00193 }
00194 
00195 bool MbedClient::connect()
00196 {
00197     extern MDMRtos<MDMSerial> *pMdm;
00198     uint8_t tries = _tries;
00199     do {
00200         if (cachedIPValid == 0) {
00201             MDMParser::IP ip = pMdm->gethostbyname(srHost);
00202             if (ip == NOIP)
00203                 continue;
00204             const unsigned char *c = (const unsigned char*)&ip;
00205             snprintf(cachedIP, sizeof(cachedIP), "%u.%u.%u.%u", c[3], c[2], c[1], c[0]);
00206             aInfo("Connect to %s:%d (IP: %s)\n", srHost, ::srPort, cachedIP);
00207         } else {
00208             aDebug("Connect to %s:%d\n", cachedIP, ::srPort);
00209         }
00210         if (_sock.connect(cachedIP, ::srPort) >= 0)
00211             break;
00212         cachedIPValid = 0;
00213         _sock.close();
00214         aCritical("\033[32mThread %p:\033[39m Connect failed.\n", Thread::gettid());
00215     } while (--tries > 0);
00216 
00217     cachedIPValid = (cachedIPValid+1) % DNS_ENTRY_DURATION;
00218     return (tries > 0);
00219 }
00220 
00221 bool MbedClient::send(const char *str)
00222 {
00223     return (_sink.write(str) == strlen(str));
00224 }
00225 
00226 bool MbedClient::sendRequestHeader(const char *uri)
00227 {
00228     MBCL_DBG("\033[32mMbed:\033[39m Send header.\n");
00229     if ((!send("POST ")) ||
00230         (!send(uri)) ||
00231         (!send(" HTTP/1.0\r\n")) ||
00232         (!send("Host: ")) ||
00233         (!send(srHost)) ||
00234         (!send("\r\n")))
00235         return false;
00236     
00237     return sendBasicAuth();
00238 }
00239 
00240 bool MbedClient::sendBasicAuth()
00241 {
00242     // no need to send authorization if not specified
00243     const char* _username = srUsername;
00244     const char* _password = srPassword;
00245     if ((_username == NULL) || (strlen(_username) == 0) ||
00246         (_password == NULL) || (strlen(_password) == 0))
00247         return true;
00248 
00249     if (!send("Authorization: Basic "))
00250         return false;
00251 
00252     if (!send(srAuthStr))
00253         return false;
00254 
00255     if (!send("\r\n"))
00256         return false;
00257     return true;
00258 }
00259 
00260 uint8_t MbedClient::internalError()
00261 {
00262     aError("\033[32mMbed:\033[39m Internal error.\n");
00263     _state = STATE_INTERNAL_ERROR;
00264     return CLIENT_INTERNAL_ERROR;
00265 }
00266 
00267 uint8_t MbedClient::connectionError()
00268 {
00269     aError("\033[32mMbed:\033[39m Connect error.\n");
00270     _state = STATE_INTERNAL_ERROR;
00271     return CLIENT_CONNECTION_ERROR;
00272 }
00273