mbed.org implementation of the abstract SmartREST library for the Cumulocity Platform SmartREST protocol.
Dependents: MbedSmartRestMain MbedSmartRestMain
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 "MbedClient.h" 00030 #include <stdlib.h> 00031 #include <string.h> 00032 #include "b64.h" 00033 #include "mbed.h" 00034 00035 #define STATE_INIT 0 00036 #define STATE_IN_REQUEST 1 00037 #define STATE_SENT_ID 2 00038 #define STATE_SENT_DATA 3 00039 #define STATE_REQ_COMPLETE 4 00040 #define STATE_RECVD_RESPONSE 5 00041 #define STATE_INTERNAL_ERROR 6 00042 00043 MbedClient::MbedClient(const char* host, uint16_t port, uint8_t tries) : 00044 _host(host), 00045 _username(NULL), 00046 _password(NULL), 00047 _port(port), 00048 _tries(tries), 00049 _state(STATE_INIT), 00050 _isStreamRequest(false), 00051 _filter(_source), 00052 _source(_sock), 00053 _sink(_sock), 00054 _sock() 00055 { 00056 } 00057 00058 MbedClient::~MbedClient() 00059 { 00060 } 00061 00062 uint8_t MbedClient::setAuthorization(const char* username, const char* password) 00063 { 00064 if (_state != STATE_INIT) 00065 return internalError(); 00066 00067 _username = username; 00068 _password = password; 00069 MBCL_DBG("Set authorization to %s:%s", username, password); 00070 return CLIENT_OK; 00071 } 00072 00073 uint8_t MbedClient::beginRequest() 00074 { 00075 if (_state != STATE_INIT) 00076 return internalError(); 00077 00078 MBCL_DBG("Beginning SmartREST request."); 00079 _source.setTimeout(60000); 00080 if (!connect()) 00081 return connectionError(); 00082 00083 if (!sendRequestHeader("/s")) 00084 return connectionError(); 00085 00086 _state = STATE_IN_REQUEST; 00087 return CLIENT_OK; 00088 } 00089 00090 uint8_t MbedClient::beginStream(const char *uri) 00091 { 00092 if (_state != STATE_INIT) 00093 return internalError(); 00094 00095 // set stream request flag to later set the timeout right 00096 _isStreamRequest = true; 00097 00098 MBCL_DBG("Beginning SmartREST request."); 00099 _source.setTimeout(60000); 00100 if (!connect()) 00101 return connectionError(); 00102 00103 if (!sendRequestHeader(uri)) 00104 return connectionError(); 00105 00106 _state = STATE_IN_REQUEST; 00107 return CLIENT_OK; 00108 } 00109 00110 uint8_t MbedClient::sendIdentifier(const char* identifier) 00111 { 00112 if (_state != STATE_IN_REQUEST) 00113 return internalError(); 00114 00115 MBCL_DBG("Sending template identifier."); 00116 if ((identifier != NULL) && (strlen(identifier) != 0)) { 00117 if ((!send("X-Id: ")) || 00118 (!send(identifier)) || 00119 (!send("\r\n"))) 00120 return connectionError(); 00121 } 00122 00123 _state = STATE_SENT_ID; 00124 return CLIENT_OK; 00125 } 00126 00127 uint8_t MbedClient::sendData(const DataGenerator& generator) 00128 { 00129 size_t len; 00130 00131 if ((_state != STATE_IN_REQUEST) && (_state != STATE_SENT_ID)) 00132 return internalError(); 00133 00134 MBCL_DBG("Sending request payload."); 00135 len = generator.writtenLength(); 00136 if ((!send("Content-Length: ")) || 00137 (_sink.write((unsigned long)len) == 0) || 00138 (!send("\r\n\r\n"))) 00139 return connectionError(); 00140 00141 if (generator.writeTo(_sink) != len) 00142 return connectionError(); 00143 00144 _state = STATE_SENT_DATA; 00145 return CLIENT_OK; 00146 } 00147 00148 uint8_t MbedClient::endRequest() 00149 { 00150 if ((_state != STATE_IN_REQUEST) && 00151 (_state != STATE_SENT_ID) && 00152 (_state != STATE_SENT_DATA)) 00153 return internalError(); 00154 00155 MBCL_DBG("Ending request."); 00156 00157 if (_state != STATE_SENT_DATA) { 00158 // send end of headers 00159 if (!send("\r\n")) 00160 return connectionError(); 00161 } 00162 00163 if (!_sink.flush()) 00164 return connectionError(); 00165 00166 _state = STATE_REQ_COMPLETE; 00167 return CLIENT_OK; 00168 } 00169 00170 uint8_t MbedClient::awaitResponse() 00171 { 00172 uint8_t status; 00173 00174 if (_state != STATE_REQ_COMPLETE) 00175 return internalError(); 00176 00177 MBCL_DBG("Awaiting response..."); 00178 00179 status = _filter.readStatus(); 00180 MBCL_DBG("Status code: %u", status); 00181 00182 if ((status != 200) || (!_filter.skipHeaders())) 00183 return connectionError(); 00184 00185 // set timeout to fifteen minutes if stream request flag set 00186 if (_isStreamRequest) 00187 _source.setTimeout(900000); 00188 00189 _state = STATE_RECVD_RESPONSE; 00190 return CLIENT_OK; 00191 } 00192 00193 AbstractDataSource& MbedClient::receiveData() 00194 { 00195 return _filter; 00196 } 00197 00198 void MbedClient::stop() 00199 { 00200 MBCL_DBG("Resetting client."); 00201 _isStreamRequest = false; 00202 _sock.close(); 00203 _source.reset(); 00204 _sink.reset(); 00205 _filter.reset(); 00206 _state = STATE_INIT; 00207 } 00208 00209 bool MbedClient::connect() 00210 { 00211 uint8_t tries; 00212 00213 tries = _tries; 00214 do { 00215 MBCL_DBG("Connecting to %s:%u", _host, _port); 00216 if (_sock.connect(_host, _port) >= 0) 00217 break; 00218 _sock.close(); 00219 MBCL_DBG("Connection atempt failed."); 00220 } while (--tries > 0); 00221 00222 return (tries > 0); 00223 } 00224 00225 bool MbedClient::send(const char *str) 00226 { 00227 return (_sink.write(str) == strlen(str)); 00228 } 00229 00230 bool MbedClient::sendRequestHeader(const char *uri) 00231 { 00232 MBCL_DBG("Sending request header."); 00233 if ((!send("POST ")) || 00234 (!send(uri)) || 00235 (!send(" HTTP/1.0\r\n")) || 00236 (!send("Host: ")) || 00237 (!send(_host)) || 00238 (!send("\r\n"))) 00239 return false; 00240 00241 return sendBasicAuth(); 00242 } 00243 00244 bool MbedClient::sendBasicAuth() 00245 { 00246 size_t ul, pl; unsigned char input[3]; unsigned char output[5]; 00247 int inputOffset = 0; 00248 00249 // no need to send authorization if not specified 00250 if ((_username == NULL) || (strlen(_username) == 0) || 00251 (_password == NULL) || (strlen(_password) == 0)) 00252 return true; 00253 00254 if (!send("Authorization: Basic ")) 00255 return false; 00256 00257 ul = strlen(_username); 00258 pl = strlen(_password); 00259 00260 for (int i = 0; i < (ul+1+pl); i++) { 00261 if (i < ul) 00262 input[inputOffset++] = _username[i]; 00263 else if (i == ul) 00264 input[inputOffset++] = ':'; 00265 else 00266 input[inputOffset++] = _password[i-(ul+1)]; 00267 00268 if ((inputOffset == 3) || (i == ul+pl)) { 00269 b64_encode(input, inputOffset, output, 4); 00270 output[4] = '\0'; 00271 if (!send((char*)output)) 00272 return false; 00273 inputOffset = 0; 00274 } 00275 } 00276 00277 if (!send("\r\n")) 00278 return false; 00279 return true; 00280 } 00281 00282 uint8_t MbedClient::internalError() 00283 { 00284 MBCL_DBG("Internal error occurred."); 00285 _state = STATE_INTERNAL_ERROR; 00286 return CLIENT_INTERNAL_ERROR; 00287 } 00288 00289 uint8_t MbedClient::connectionError() 00290 { 00291 MBCL_DBG("Connection error occurred."); 00292 _state = STATE_INTERNAL_ERROR; 00293 return CLIENT_CONNECTION_ERROR; 00294 } 00295
Generated on Tue Jul 12 2022 15:21:50 by 1.7.2