A client for the SmartREST protocol from Cumulocity.

Dependencies:   SmartRest

Fork of MbedSmartRest by Vincent Wochnik

Committer:
vwochnik
Date:
Fri Apr 11 09:33:45 2014 +0000
Revision:
13:e76920d5e1ec
Parent:
12:788dd934f283
Child:
14:dc3f8dd5c02b
fix

Who changed what in which revision?

UserRevisionLine numberNew contents of line
vwochnik 3:ce2f116369bd 1 #include "MbedClient.h"
vwochnik 5:ab909221d22d 2 #include <stdlib.h>
vwochnik 9:3bbb83e7cbfd 3 #include <stdio.h>
vwochnik 13:e76920d5e1ec 4 #include <string.h>
vwochnik 13:e76920d5e1ec 5 #include "b64.h"
vwochnik 13:e76920d5e1ec 6 #include "mbed.h"
vwochnik 9:3bbb83e7cbfd 7
vwochnik 13:e76920d5e1ec 8 const char *cExpectedStatus = "HTTP/1.* 200 OK";
vwochnik 5:ab909221d22d 9
vwochnik 13:e76920d5e1ec 10 MbedClient::MbedClient(const char* host, uint16_t port, const char* username, const char* password)
vwochnik 13:e76920d5e1ec 11 : _host(host), _port(port), _username(username), _password(password), _source(_sock), _sink(_sock), _sock()
vwochnik 3:ce2f116369bd 12 {
vwochnik 13:e76920d5e1ec 13 _state = MBED_STATE_INIT;
vwochnik 5:ab909221d22d 14 }
vwochnik 5:ab909221d22d 15
vwochnik 5:ab909221d22d 16 MbedClient::~MbedClient()
vwochnik 5:ab909221d22d 17 {
vwochnik 3:ce2f116369bd 18 }
vwochnik 3:ce2f116369bd 19
vwochnik 3:ce2f116369bd 20 uint8_t MbedClient::beginRequest()
vwochnik 3:ce2f116369bd 21 {
vwochnik 13:e76920d5e1ec 22 if (_state != MBED_STATE_INIT)
vwochnik 5:ab909221d22d 23 return CLIENT_INTERNAL_ERROR;
vwochnik 13:e76920d5e1ec 24
vwochnik 13:e76920d5e1ec 25 if (_sock.connect(_host, _port) < 0) {
vwochnik 13:e76920d5e1ec 26 stop();
vwochnik 13:e76920d5e1ec 27 return CLIENT_CONNECTION_ERROR;
vwochnik 13:e76920d5e1ec 28 }
vwochnik 13:e76920d5e1ec 29
vwochnik 13:e76920d5e1ec 30 if ((!send("POST /s HTTP/1.0\r\n")) ||
vwochnik 13:e76920d5e1ec 31 (!send("Host: ")) ||
vwochnik 13:e76920d5e1ec 32 (!send(_host)) ||
vwochnik 13:e76920d5e1ec 33 (!send("\r\n")))
vwochnik 13:e76920d5e1ec 34 return CLIENT_CONNECTION_ERROR;
vwochnik 13:e76920d5e1ec 35
vwochnik 13:e76920d5e1ec 36 if (!sendBasicAuth())
vwochnik 13:e76920d5e1ec 37 return CLIENT_CONNECTION_ERROR;
vwochnik 13:e76920d5e1ec 38
vwochnik 13:e76920d5e1ec 39 _state = MBED_STATE_IN_REQUEST;
vwochnik 5:ab909221d22d 40 return CLIENT_OK;
vwochnik 3:ce2f116369bd 41 }
vwochnik 3:ce2f116369bd 42
vwochnik 5:ab909221d22d 43 uint8_t MbedClient::sendIdentifier(const char* identifier)
vwochnik 3:ce2f116369bd 44 {
vwochnik 13:e76920d5e1ec 45 if (_state != MBED_STATE_IN_REQUEST)
vwochnik 5:ab909221d22d 46 return CLIENT_INTERNAL_ERROR;
vwochnik 13:e76920d5e1ec 47
vwochnik 13:e76920d5e1ec 48 if ((!send("X-Id: ")) ||
vwochnik 13:e76920d5e1ec 49 (!send(identifier)) ||
vwochnik 13:e76920d5e1ec 50 (!send("\r\n")))
vwochnik 13:e76920d5e1ec 51 return CLIENT_CONNECTION_ERROR;
vwochnik 13:e76920d5e1ec 52
vwochnik 13:e76920d5e1ec 53 _state = MBED_STATE_SENT_ID;
vwochnik 5:ab909221d22d 54 return CLIENT_OK;
vwochnik 3:ce2f116369bd 55 }
vwochnik 3:ce2f116369bd 56
vwochnik 3:ce2f116369bd 57 uint8_t MbedClient::sendData(DataGenerator& generator)
vwochnik 3:ce2f116369bd 58 {
vwochnik 13:e76920d5e1ec 59 char len[8];
vwochnik 13:e76920d5e1ec 60
vwochnik 13:e76920d5e1ec 61 if ((_state != MBED_STATE_IN_REQUEST) && (_state != MBED_STATE_SENT_ID))
vwochnik 5:ab909221d22d 62 return CLIENT_INTERNAL_ERROR;
vwochnik 13:e76920d5e1ec 63
vwochnik 13:e76920d5e1ec 64 snprintf(len, 8, "%ld", generator.writtenLength());
vwochnik 13:e76920d5e1ec 65
vwochnik 13:e76920d5e1ec 66 if ((!send("Content-Length: ")) ||
vwochnik 13:e76920d5e1ec 67 (!send(len)) ||
vwochnik 13:e76920d5e1ec 68 (!send("\r\n\r\n")))
vwochnik 13:e76920d5e1ec 69 return CLIENT_CONNECTION_ERROR;
vwochnik 13:e76920d5e1ec 70
vwochnik 13:e76920d5e1ec 71 if (generator.writeTo(_sink) != generator.writtenLength()) {
vwochnik 13:e76920d5e1ec 72 stop();
vwochnik 13:e76920d5e1ec 73 return CLIENT_CONNECTION_ERROR;
vwochnik 13:e76920d5e1ec 74 }
vwochnik 13:e76920d5e1ec 75
vwochnik 13:e76920d5e1ec 76 _state = MBED_STATE_SENT_DATA;
vwochnik 5:ab909221d22d 77 return CLIENT_OK;
vwochnik 3:ce2f116369bd 78 }
vwochnik 3:ce2f116369bd 79
vwochnik 3:ce2f116369bd 80 uint8_t MbedClient::endRequest()
vwochnik 3:ce2f116369bd 81 {
vwochnik 13:e76920d5e1ec 82 if ((_state != MBED_STATE_IN_REQUEST) && (_state != MBED_STATE_SENT_ID) && (_state != MBED_STATE_SENT_DATA))
vwochnik 5:ab909221d22d 83 return CLIENT_INTERNAL_ERROR;
vwochnik 13:e76920d5e1ec 84
vwochnik 13:e76920d5e1ec 85 if (_state != MBED_STATE_SENT_DATA) {
vwochnik 13:e76920d5e1ec 86 // send end of headers
vwochnik 13:e76920d5e1ec 87 if (!send("\r\n"))
vwochnik 13:e76920d5e1ec 88 return CLIENT_CONNECTION_ERROR;
vwochnik 13:e76920d5e1ec 89 }
vwochnik 13:e76920d5e1ec 90
vwochnik 13:e76920d5e1ec 91 if (!_sink.flush()) {
vwochnik 13:e76920d5e1ec 92 stop();
vwochnik 13:e76920d5e1ec 93 return CLIENT_CONNECTION_ERROR;
vwochnik 13:e76920d5e1ec 94 }
vwochnik 13:e76920d5e1ec 95
vwochnik 13:e76920d5e1ec 96 _state = MBED_STATE_REQ_COMPLETE;
vwochnik 7:26524a6a04a1 97 return CLIENT_OK;
vwochnik 3:ce2f116369bd 98 }
vwochnik 3:ce2f116369bd 99
vwochnik 3:ce2f116369bd 100 uint8_t MbedClient::awaitResponse()
vwochnik 3:ce2f116369bd 101 {
vwochnik 13:e76920d5e1ec 102 int8_t state = 0; char c; size_t offset = 0;
vwochnik 5:ab909221d22d 103
vwochnik 13:e76920d5e1ec 104 if (_state != MBED_STATE_REQ_COMPLETE)
vwochnik 5:ab909221d22d 105 return CLIENT_INTERNAL_ERROR;
vwochnik 13:e76920d5e1ec 106
vwochnik 13:e76920d5e1ec 107 while ((state >= 0) && (state < 20) && (((c = _source.read()) > 0) || (_source.status() == DS_STATUS_OK))) {
vwochnik 13:e76920d5e1ec 108 switch (state) {
vwochnik 13:e76920d5e1ec 109 case 0: // read expected status line
vwochnik 13:e76920d5e1ec 110 if ((cExpectedStatus[offset] != c) && (cExpectedStatus[offset] != '*'))
vwochnik 13:e76920d5e1ec 111 state = -1;
vwochnik 13:e76920d5e1ec 112 offset++;
vwochnik 13:e76920d5e1ec 113 if (offset == strlen(cExpectedStatus))
vwochnik 13:e76920d5e1ec 114 state = 1;
vwochnik 13:e76920d5e1ec 115 break;
vwochnik 13:e76920d5e1ec 116 linebrk:
vwochnik 13:e76920d5e1ec 117 case 1:
vwochnik 13:e76920d5e1ec 118 if (c == '\n')
vwochnik 13:e76920d5e1ec 119 state = 2;
vwochnik 13:e76920d5e1ec 120 else if (c != '\r')
vwochnik 13:e76920d5e1ec 121 state = -1;
vwochnik 13:e76920d5e1ec 122 break;
vwochnik 13:e76920d5e1ec 123 case 2:
vwochnik 13:e76920d5e1ec 124 if (c == '\n') {
vwochnik 13:e76920d5e1ec 125 state = 20;
vwochnik 13:e76920d5e1ec 126 break;
vwochnik 13:e76920d5e1ec 127 } else if (c == '\r') {
vwochnik 13:e76920d5e1ec 128 break;
vwochnik 13:e76920d5e1ec 129 } else {
vwochnik 13:e76920d5e1ec 130 state = 3;
vwochnik 13:e76920d5e1ec 131 goto random;
vwochnik 13:e76920d5e1ec 132 }
vwochnik 13:e76920d5e1ec 133 random:
vwochnik 13:e76920d5e1ec 134 case 3:
vwochnik 13:e76920d5e1ec 135 if ((c == '\r') || (c == '\n')) {
vwochnik 13:e76920d5e1ec 136 state = 1;
vwochnik 13:e76920d5e1ec 137 goto linebrk;
vwochnik 13:e76920d5e1ec 138 }
vwochnik 13:e76920d5e1ec 139 }
vwochnik 13:e76920d5e1ec 140 }
vwochnik 13:e76920d5e1ec 141
vwochnik 13:e76920d5e1ec 142 if (state != 20) {
vwochnik 13:e76920d5e1ec 143 stop();
vwochnik 5:ab909221d22d 144 return CLIENT_CONNECTION_ERROR;
vwochnik 13:e76920d5e1ec 145 }
vwochnik 13:e76920d5e1ec 146
vwochnik 13:e76920d5e1ec 147 _state = MBED_STATE_RECVD_RESPONSE;
vwochnik 5:ab909221d22d 148 return CLIENT_OK;
vwochnik 3:ce2f116369bd 149 }
vwochnik 3:ce2f116369bd 150
vwochnik 3:ce2f116369bd 151 AbstractDataSource& MbedClient::receiveData()
vwochnik 3:ce2f116369bd 152 {
vwochnik 13:e76920d5e1ec 153 return _source;
vwochnik 3:ce2f116369bd 154 }
vwochnik 3:ce2f116369bd 155
vwochnik 3:ce2f116369bd 156 void MbedClient::stop()
vwochnik 3:ce2f116369bd 157 {
vwochnik 13:e76920d5e1ec 158 _sock.close();
vwochnik 13:e76920d5e1ec 159 _source.reset();
vwochnik 13:e76920d5e1ec 160 _sink.reset();
vwochnik 13:e76920d5e1ec 161 _state = MBED_STATE_INIT;
vwochnik 13:e76920d5e1ec 162 }
vwochnik 13:e76920d5e1ec 163
vwochnik 13:e76920d5e1ec 164 bool MbedClient::send(const char *str)
vwochnik 13:e76920d5e1ec 165 {
vwochnik 13:e76920d5e1ec 166 if (_sink.write(str) != strlen(str)) {
vwochnik 13:e76920d5e1ec 167 stop();
vwochnik 13:e76920d5e1ec 168 return false;
vwochnik 13:e76920d5e1ec 169 }
vwochnik 13:e76920d5e1ec 170 return true;
vwochnik 3:ce2f116369bd 171 }
vwochnik 13:e76920d5e1ec 172
vwochnik 13:e76920d5e1ec 173 bool MbedClient::sendBasicAuth()
vwochnik 13:e76920d5e1ec 174 {
vwochnik 13:e76920d5e1ec 175 size_t ul, pl; unsigned char input[3]; unsigned char output[5];
vwochnik 13:e76920d5e1ec 176 int inputOffset = 0;
vwochnik 13:e76920d5e1ec 177
vwochnik 13:e76920d5e1ec 178 if (!send("Authorization: Basic "))
vwochnik 13:e76920d5e1ec 179 return false;
vwochnik 13:e76920d5e1ec 180
vwochnik 13:e76920d5e1ec 181 ul = strlen(_username);
vwochnik 13:e76920d5e1ec 182 pl = strlen(_password);
vwochnik 13:e76920d5e1ec 183
vwochnik 13:e76920d5e1ec 184 for (int i = 0; i < (ul+1+pl); i++) {
vwochnik 13:e76920d5e1ec 185 if (i < ul)
vwochnik 13:e76920d5e1ec 186 input[inputOffset++] = _username[i];
vwochnik 13:e76920d5e1ec 187 else if (i == ul)
vwochnik 13:e76920d5e1ec 188 input[inputOffset++] = ':';
vwochnik 13:e76920d5e1ec 189 else
vwochnik 13:e76920d5e1ec 190 input[inputOffset++] = _password[i-(ul+1)];
vwochnik 13:e76920d5e1ec 191
vwochnik 13:e76920d5e1ec 192 if ((inputOffset == 3) || (i == ul+pl)) {
vwochnik 13:e76920d5e1ec 193 b64_encode(input, inputOffset, output, 4);
vwochnik 13:e76920d5e1ec 194 output[4] = '\0';
vwochnik 13:e76920d5e1ec 195 if (!send((char*)output))
vwochnik 13:e76920d5e1ec 196 return false;
vwochnik 13:e76920d5e1ec 197 inputOffset = 0;
vwochnik 13:e76920d5e1ec 198 }
vwochnik 13:e76920d5e1ec 199 }
vwochnik 13:e76920d5e1ec 200
vwochnik 13:e76920d5e1ec 201 if (!send("\r\n"))
vwochnik 13:e76920d5e1ec 202 return false;
vwochnik 13:e76920d5e1ec 203 return true;
vwochnik 13:e76920d5e1ec 204 }