Own fork of MbedSmartRest
Dependents: MbedSmartRestMain MbedSmartRestMain
Fork of MbedSmartRest by
MbedClient.cpp
- Committer:
- Cumulocity
- Date:
- 2014-10-23
- Revision:
- 8:3a4dba260b71
- Parent:
- 7:8159a2d12e4e
- Child:
- 11:e1bee9a77652
File content as of revision 8:3a4dba260b71:
/* * 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 "MbedClient.h" #include <stdlib.h> #include <string.h> #include "b64.h" #include "mbed.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 MbedClient::MbedClient(const char* host, uint16_t port, uint8_t tries) : _host(host), _username(NULL), _password(NULL), _port(port), _tries(tries), _state(STATE_INIT), _filter(_source), _source(_sock), _sink(_sock), _sock() { } MbedClient::~MbedClient() { } uint8_t MbedClient::setAuthorization(const char* username, const char* password) { if (_state != STATE_INIT) return internalError(); _username = username; _password = password; MBCL_DBG("Set authorization to %s:%s", username, password); return CLIENT_OK; } uint8_t MbedClient::beginRequest() { uint8_t tries; if (_state != STATE_INIT) return internalError(); tries = _tries; do { MBCL_DBG("Connecting to %s:%u", _host, _port); if (_sock.connect(_host, _port) >= 0) break; _sock.close(); MBCL_DBG("Connection atempt failed."); } while (--tries > 0); if (tries == 0) return connectionError(); MBCL_DBG("Sending request header."); if ((!send("POST /s HTTP/1.0\r\n")) || (!send("Host: ")) || (!send(_host)) || (!send("\r\n"))) return connectionError(); if ((_username != NULL) && (strlen(_username) > 0) && (_password != NULL) && (strlen(_password) > 0)) { if (!sendBasicAuth()) return connectionError(); } _state = STATE_IN_REQUEST; return CLIENT_OK; } uint8_t MbedClient::sendIdentifier(const char* identifier) { if (_state != STATE_IN_REQUEST) return internalError(); MBCL_DBG("Sending template identifier."); 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) { size_t len; if ((_state != STATE_IN_REQUEST) && (_state != STATE_SENT_ID)) return internalError(); MBCL_DBG("Sending request payload."); 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() { if ((_state != STATE_IN_REQUEST) && (_state != STATE_SENT_ID) && (_state != STATE_SENT_DATA)) return internalError(); MBCL_DBG("Ending request. request."); 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() { uint8_t status; if (_state != STATE_REQ_COMPLETE) return internalError(); MBCL_DBG("Awaiting response..."); status = _filter.readStatus(); MBCL_DBG("Status code: %u", status); if ((status != 200) || (!_filter.skipHeaders())) return connectionError(); _state = STATE_RECVD_RESPONSE; return CLIENT_OK; } AbstractDataSource& MbedClient::receiveData() { return _filter; } void MbedClient::stop() { MBCL_DBG("Resetting client."); _sock.close(); _source.reset(); _sink.reset(); _filter.reset(); _state = STATE_INIT; } bool MbedClient::send(const char *str) { return (_sink.write(str) == strlen(str)); } bool MbedClient::sendBasicAuth() { size_t ul, pl; unsigned char input[3]; unsigned char output[5]; int inputOffset = 0; if (!send("Authorization: Basic ")) return false; ul = strlen(_username); pl = strlen(_password); for (int i = 0; i < (ul+1+pl); i++) { if (i < ul) input[inputOffset++] = _username[i]; else if (i == ul) input[inputOffset++] = ':'; else input[inputOffset++] = _password[i-(ul+1)]; if ((inputOffset == 3) || (i == ul+pl)) { b64_encode(input, inputOffset, output, 4); output[4] = '\0'; if (!send((char*)output)) return false; inputOffset = 0; } } if (!send("\r\n")) return false; return true; } uint8_t MbedClient::internalError() { MBCL_DBG("Internal error occurred."); _state = STATE_INTERNAL_ERROR; return CLIENT_INTERNAL_ERROR; } uint8_t MbedClient::connectionError() { MBCL_DBG("Connection error occurred."); _state = STATE_INTERNAL_ERROR; return CLIENT_CONNECTION_ERROR; }