A client for the SmartREST protocol from Cumulocity.
Fork of MbedSmartRest by
MbedClient.cpp@13:e76920d5e1ec, 2014-04-11 (annotated)
- 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?
User | Revision | Line number | New 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 | } |