Own fork of MbedSmartRest
Dependents: MbedSmartRestMain MbedSmartRestMain
Fork of MbedSmartRest by
MbedClient.cpp
- Committer:
- xinlei
- Date:
- 2015-06-01
- Revision:
- 25:b8a080f5e578
- Parent:
- 24:11fd6fd14c28
- Child:
- 26:9c36af176d91
File content as of revision 25:b8a080f5e578:
/* * MbedClient.cpp * * Created on: Feb 1, 2013 * * Authors: Vincent Wochnik <v.wochnik@gmail.com> * * Copyright (c) 2013 Cumulocity GmbH * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include <stdlib.h> #include <string.h> #include "mbed.h" #include "rtos.h" #include "MbedClient.h" #include "SmartRestConf.h" #include "logging.h" #define STATE_INIT 0 #define STATE_IN_REQUEST 1 #define STATE_SENT_ID 2 #define STATE_SENT_DATA 3 #define STATE_REQ_COMPLETE 4 #define STATE_RECVD_RESPONSE 5 #define STATE_INTERNAL_ERROR 6 #define MBCL_DBG(...) aDebug(__VA_ARGS__) #define DNS_ENTRY_DURATION 50 MbedClient::MbedClient(uint8_t tries) : _tries(tries), _state(STATE_INIT), _isStreamRequest(false), _sock(), _source(_sock), _sink(_sock), _filter(_source), cachedIPValid(0) { } MbedClient::~MbedClient() { } uint8_t MbedClient::beginRequest() { if (_state != STATE_INIT) return internalError(); MBCL_DBG("\033[32mMbed:\033[39m Begin SmartREST request.\n"); _source.setTimeout(60000); if (!connect()) return connectionError(); if (!sendRequestHeader("/s")) return connectionError(); _state = STATE_IN_REQUEST; return CLIENT_OK; } uint8_t MbedClient::beginStream(const char *uri) { if (_state != STATE_INIT) return internalError(); // set stream request flag to later set the timeout right _isStreamRequest = true; MBCL_DBG("\033[32mMbed:\033[39m Begin SmartREST stream.\n"); _source.setTimeout(60000); if (!connect()) return connectionError(); if (!sendRequestHeader(uri)) return connectionError(); _state = STATE_IN_REQUEST; return CLIENT_OK; } uint8_t MbedClient::sendIdentifier(const char* identifier) { MBCL_DBG("\033[32mMbed:\033[39m Send x-id.\n"); if (_state != STATE_IN_REQUEST) return internalError(); if ((identifier != NULL) && (strlen(identifier) != 0)) { if ((!send("X-Id: ")) || (!send(identifier)) || (!send("\r\n"))) return connectionError(); } _state = STATE_SENT_ID; return CLIENT_OK; } uint8_t MbedClient::sendData(const DataGenerator& generator) { MBCL_DBG("\033[32mMbed:\033[39m Send payload.\n"); if (_state != STATE_IN_REQUEST && _state != STATE_SENT_ID) return internalError(); size_t len = generator.writtenLength(); if ((!send("Content-Length: ")) || (_sink.write((unsigned long)len) == 0) || (!send("\r\n\r\n"))) return connectionError(); if (generator.writeTo(_sink) != len) return connectionError(); _state = STATE_SENT_DATA; return CLIENT_OK; } uint8_t MbedClient::endRequest() { MBCL_DBG("\033[32mMbed:\033[39m End request.\n"); if ((_state != STATE_IN_REQUEST) && (_state != STATE_SENT_ID) && (_state != STATE_SENT_DATA)) { return internalError(); } if (_state != STATE_SENT_DATA) { // send end of headers if (!send("\r\n")) { return connectionError(); } } if (!_sink.flush()) { return connectionError(); } _state = STATE_REQ_COMPLETE; return CLIENT_OK; } uint8_t MbedClient::awaitResponse() { if (_state != STATE_REQ_COMPLETE) { return internalError(); } // set timeout to fifteen minutes if stream request flag set if (_isStreamRequest) { _source.setTimeout(300000); } uint8_t status = _filter.readStatus(); if ((status != 200) || (!_filter.skipHeaders())) { return connectionError(); } _state = STATE_RECVD_RESPONSE; return CLIENT_OK; } AbstractDataSource& MbedClient::receiveData() { return _filter; } void MbedClient::stop() { aInfo("\033[32mMbed:\033[39m %zu bytes sent.\n", packetSize); _isStreamRequest = false; _sock.close(); _source.reset(); _sink.reset(); _filter.reset(); _state = STATE_INIT; } bool MbedClient::connect() { extern MDMRtos<MDMSerial> *pMdm; uint8_t tries = _tries; do { if (cachedIPValid == 0) { MDMParser::IP ip = pMdm->gethostbyname(srHost); if (ip == NOIP) continue; const unsigned char *c = (const unsigned char*)&ip; snprintf(cachedIP, sizeof(cachedIP), "%u.%u.%u.%u", c[3], c[2], c[1], c[0]); aInfo("Connect to %s:%d (IP: %s)\n", srHost, ::srPort, cachedIP); } else { aDebug("Connect to %s:%d\n", cachedIP, ::srPort); } if (_sock.connect(cachedIP, ::srPort) >= 0) break; cachedIPValid = 0; _sock.close(); aCritical("\033[32mThread %p:\033[39m Connect failed.\n", Thread::gettid()); } while (--tries > 0); cachedIPValid = (cachedIPValid+1) % DNS_ENTRY_DURATION; return (tries > 0); } bool MbedClient::send(const char *str) { return (_sink.write(str) == strlen(str)); } bool MbedClient::sendRequestHeader(const char *uri) { MBCL_DBG("\033[32mMbed:\033[39m Send header.\n"); if ((!send("POST ")) || (!send(uri)) || (!send(" HTTP/1.0\r\n")) || (!send("Host: ")) || (!send(srHost)) || (!send("\r\n"))) return false; return sendBasicAuth(); } bool MbedClient::sendBasicAuth() { // no need to send authorization if not specified const char* _username = srUsername; const char* _password = srPassword; if ((_username == NULL) || (strlen(_username) == 0) || (_password == NULL) || (strlen(_password) == 0)) return true; if (!send("Authorization: Basic ")) return false; if (!send(srAuthStr)) return false; if (!send("\r\n")) return false; return true; } uint8_t MbedClient::internalError() { aError("\033[32mMbed:\033[39m Internal error.\n"); _state = STATE_INTERNAL_ERROR; return CLIENT_INTERNAL_ERROR; } uint8_t MbedClient::connectionError() { aError("\033[32mMbed:\033[39m Connect error.\n"); _state = STATE_INTERNAL_ERROR; return CLIENT_CONNECTION_ERROR; }