Own fork of MbedSmartRest
Dependents: MbedSmartRestMain MbedSmartRestMain
Fork of MbedSmartRest by
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 <stdlib.h> 00030 #include <string.h> 00031 #include "mbed.h" 00032 #include "rtos.h" 00033 00034 #include "MbedClient.h" 00035 #include "SmartRestConf.h" 00036 #include "logging.h" 00037 00038 #define STATE_INIT 0 00039 #define STATE_IN_REQUEST 1 00040 #define STATE_SENT_ID 2 00041 #define STATE_SENT_DATA 3 00042 #define STATE_REQ_COMPLETE 4 00043 #define STATE_RECVD_RESPONSE 5 00044 #define STATE_INTERNAL_ERROR 6 00045 00046 #define MBCL_DBG(...) aDebug(__VA_ARGS__) 00047 00048 #define DNS_ENTRY_DURATION 50 00049 00050 MbedClient::MbedClient(uint8_t tries) : 00051 _tries(tries), 00052 _state(STATE_INIT), 00053 _isStreamRequest(false), 00054 _sock(), 00055 _source(_sock), 00056 _sink(_sock), 00057 _filter(_source), 00058 cachedIPValid(0) 00059 { 00060 } 00061 00062 MbedClient::~MbedClient() 00063 { 00064 } 00065 00066 uint8_t MbedClient::beginRequest() 00067 { 00068 if (_state != STATE_INIT) 00069 return internalError(); 00070 00071 MBCL_DBG("\033[32mMbed:\033[39m Begin SmartREST request.\n"); 00072 _source.setTimeout(60000); 00073 if (!connect()) 00074 return connectionError(); 00075 00076 if (!sendRequestHeader("/s")) 00077 return connectionError(); 00078 00079 _state = STATE_IN_REQUEST; 00080 return CLIENT_OK; 00081 } 00082 00083 uint8_t MbedClient::beginStream(const char *uri) 00084 { 00085 if (_state != STATE_INIT) 00086 return internalError(); 00087 00088 // set stream request flag to later set the timeout right 00089 _isStreamRequest = true; 00090 00091 MBCL_DBG("\033[32mMbed:\033[39m Begin SmartREST stream.\n"); 00092 _source.setTimeout(60000); 00093 if (!connect()) 00094 return connectionError(); 00095 00096 if (!sendRequestHeader(uri)) 00097 return connectionError(); 00098 00099 _state = STATE_IN_REQUEST; 00100 return CLIENT_OK; 00101 } 00102 00103 uint8_t MbedClient::sendIdentifier(const char* identifier) 00104 { 00105 MBCL_DBG("\033[32mMbed:\033[39m Send x-id.\n"); 00106 if (_state != STATE_IN_REQUEST) 00107 return internalError(); 00108 00109 if ((identifier != NULL) && (strlen(identifier) != 0)) { 00110 if ((!send("X-Id: ")) || 00111 (!send(identifier)) || 00112 (!send("\r\n"))) 00113 return connectionError(); 00114 } 00115 _state = STATE_SENT_ID; 00116 return CLIENT_OK; 00117 } 00118 00119 uint8_t MbedClient::sendData(const DataGenerator& generator) 00120 { 00121 MBCL_DBG("\033[32mMbed:\033[39m Send payload.\n"); 00122 if (_state != STATE_IN_REQUEST && _state != STATE_SENT_ID) 00123 return internalError(); 00124 00125 size_t len = generator.writtenLength(); 00126 if ((!send("Content-Length: ")) || 00127 (_sink.write((unsigned long)len) == 0) || 00128 (!send("\r\n\r\n"))) 00129 return connectionError(); 00130 00131 if (generator.writeTo(_sink) != len) 00132 return connectionError(); 00133 _state = STATE_SENT_DATA; 00134 return CLIENT_OK; 00135 } 00136 00137 uint8_t MbedClient::endRequest() 00138 { 00139 MBCL_DBG("\033[32mMbed:\033[39m End request.\n"); 00140 if ((_state != STATE_IN_REQUEST) && 00141 (_state != STATE_SENT_ID) && 00142 (_state != STATE_SENT_DATA)) { 00143 return internalError(); 00144 } 00145 00146 if (_state != STATE_SENT_DATA) { 00147 // send end of headers 00148 if (!send("\r\n")) { 00149 return connectionError(); 00150 } 00151 } 00152 00153 if (!_sink.flush()) { 00154 return connectionError(); 00155 } 00156 00157 _state = STATE_REQ_COMPLETE; 00158 return CLIENT_OK; 00159 } 00160 00161 uint8_t MbedClient::awaitResponse() 00162 { 00163 if (_state != STATE_REQ_COMPLETE) { 00164 return internalError(); 00165 } 00166 // set timeout to fifteen minutes if stream request flag set 00167 if (_isStreamRequest) { 00168 _source.setTimeout(300000); 00169 } 00170 00171 uint8_t status = _filter.readStatus(); 00172 if ((status != 200) || (!_filter.skipHeaders())) { 00173 return connectionError(); 00174 } 00175 00176 _state = STATE_RECVD_RESPONSE; 00177 return CLIENT_OK; 00178 } 00179 00180 AbstractDataSource& MbedClient::receiveData() 00181 { 00182 return _filter; 00183 } 00184 00185 void MbedClient::stop() 00186 { 00187 _isStreamRequest = false; 00188 _sock.close(); 00189 _source.reset(); 00190 _sink.reset(); 00191 _filter.reset(); 00192 _state = STATE_INIT; 00193 } 00194 00195 bool MbedClient::connect() 00196 { 00197 extern MDMRtos<MDMSerial> *pMdm; 00198 uint8_t tries = _tries; 00199 do { 00200 if (cachedIPValid == 0) { 00201 MDMParser::IP ip = pMdm->gethostbyname(srHost); 00202 if (ip == NOIP) 00203 continue; 00204 const unsigned char *c = (const unsigned char*)&ip; 00205 snprintf(cachedIP, sizeof(cachedIP), "%u.%u.%u.%u", c[3], c[2], c[1], c[0]); 00206 aInfo("Connect to %s:%d (IP: %s)\n", srHost, ::srPort, cachedIP); 00207 } else { 00208 aDebug("Connect to %s:%d\n", cachedIP, ::srPort); 00209 } 00210 if (_sock.connect(cachedIP, ::srPort) >= 0) 00211 break; 00212 cachedIPValid = 0; 00213 _sock.close(); 00214 aCritical("\033[32mThread %p:\033[39m Connect failed.\n", Thread::gettid()); 00215 } while (--tries > 0); 00216 00217 cachedIPValid = (cachedIPValid+1) % DNS_ENTRY_DURATION; 00218 return (tries > 0); 00219 } 00220 00221 bool MbedClient::send(const char *str) 00222 { 00223 return (_sink.write(str) == strlen(str)); 00224 } 00225 00226 bool MbedClient::sendRequestHeader(const char *uri) 00227 { 00228 MBCL_DBG("\033[32mMbed:\033[39m Send header.\n"); 00229 if ((!send("POST ")) || 00230 (!send(uri)) || 00231 (!send(" HTTP/1.0\r\n")) || 00232 (!send("Host: ")) || 00233 (!send(srHost)) || 00234 (!send("\r\n"))) 00235 return false; 00236 00237 return sendBasicAuth(); 00238 } 00239 00240 bool MbedClient::sendBasicAuth() 00241 { 00242 // no need to send authorization if not specified 00243 const char* _username = srUsername; 00244 const char* _password = srPassword; 00245 if ((_username == NULL) || (strlen(_username) == 0) || 00246 (_password == NULL) || (strlen(_password) == 0)) 00247 return true; 00248 00249 if (!send("Authorization: Basic ")) 00250 return false; 00251 00252 if (!send(srAuthStr)) 00253 return false; 00254 00255 if (!send("\r\n")) 00256 return false; 00257 return true; 00258 } 00259 00260 uint8_t MbedClient::internalError() 00261 { 00262 aError("\033[32mMbed:\033[39m Internal error.\n"); 00263 _state = STATE_INTERNAL_ERROR; 00264 return CLIENT_INTERNAL_ERROR; 00265 } 00266 00267 uint8_t MbedClient::connectionError() 00268 { 00269 aError("\033[32mMbed:\033[39m Connect error.\n"); 00270 _state = STATE_INTERNAL_ERROR; 00271 return CLIENT_CONNECTION_ERROR; 00272 } 00273
Generated on Tue Jul 12 2022 17:00:00 by 1.7.2