├── .gitattributes ├── .gitignore ├── AWS ├── AWSClient.cpp ├── AWSClient.h ├── AWSClient2.cpp ├── AWSClient2.h ├── AWSFoundationalTypes.cpp ├── AWSFoundationalTypes.h ├── AmazonDynamoDBClient.cpp ├── AmazonDynamoDBClient.h ├── AmazonSNSClient.cpp ├── AmazonSNSClient.h ├── DeviceIndependentInterfaces.cpp ├── DeviceIndependentInterfaces.h ├── Esp8266AWSImplementations.cpp ├── Esp8266AWSImplementations.h ├── Utils.cpp ├── Utils.h ├── jsmn.c ├── jsmn.h ├── keys.c ├── keys.h ├── sha256.cpp └── sha256.h ├── AWS_Get-SetDemo └── AWS_Get-SetDemo.ino └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /AWS/AWSClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AWSClient.cpp 3 | * 4 | * See AWSClient.h for description. 5 | * 6 | * Created on: Jul 8, 2014 7 | * Author: hoffmaj 8 | */ 9 | 10 | #include "AWSClient.h" 11 | #include "Utils.h" 12 | #include "DeviceIndependentInterfaces.h" 13 | #include "AWSFoundationalTypes.h" 14 | #include "sha256.h" 15 | #include 16 | #include 17 | #include 18 | 19 | /* Constants string, formats, and lengths. */ 20 | static const char* CANONICAL_FORM_POST_LINE = "POST\n/\n\n"; 21 | static const int CANONICAL_FORM_POST_LINE_LEN = 8; 22 | static const char* HTTPS_REQUEST_POST_LINE = 23 | "POST https://%s.%s.%s/ HTTP/1.1\n"; 24 | static const int HTTPS_REQUEST_POST_LINE_LEN = 28; 25 | static const char* HTTP_REQUEST_POST_LINE = "POST http://%s.%s.%s/ HTTP/1.1\n"; 26 | static const int HTTP_REQUEST_POST_LINE_LEN = 27; 27 | static const char* CURL_START = "curl --silent -X POST "; 28 | static const int CURL_START_LEN = 22; 29 | static const char* HTTPS_CURL_END = "https://%s.%s.%s"; 30 | static const int HTTPS_CURL_END_LEN = 10; 31 | static const char* HTTP_CURL_END = "http://%s.%s.%s"; 32 | static const int HTTP_CURL_END_LEN = 9; 33 | static const char* TO_SIGN_TEMPLATE = 34 | "AWS4-HMAC-SHA256\n%sT%sZ\n%s/%s/%s/aws4_request\n%s"; 35 | static const int TO_SIGN_TEMPLATE_LEN = 36; 36 | static const char* CONTENT_LENGTH_HEADER = "content-length:%d"; 37 | static const int CONTENT_LENGTH_HEADER_LEN = 15; 38 | static const char* HOST_HEADER = "host:%s.%s.%s"; 39 | static const int HOST_HEADER_LEN = 7; 40 | static const char* CONNECTION_HEADER = "Connection:close"; 41 | static const int CONNECTION_HEADER_LEN = 16; 42 | static const char* CONTENT_TYPE_HEADER = "content-type:%s"; 43 | static const int CONTENT_TYPE_HEADER_LEN = 13; 44 | static const char* X_AMZ_DATE_HEADER = "x-amz-date:%sT%sZ"; 45 | static const int X_AMZ_DATE_HEADER_LEN = 13; 46 | static const char* X_AMZ_TARGET_HEADER = "x-amz-target:%s"; 47 | static const int X_AMZ_TARGET_HEADER_LEN = 13; 48 | static const char* AUTHORIZATION_HEADER = 49 | "Authorization: AWS4-HMAC-SHA256 Credential=%s/%s/%s/%s/aws4_request, SignedHeaders=%s, Signature=%s"; 50 | static const int AUTHORIZATION_HEADER_LEN = 87; 51 | static const char* SIGNED_HEADERS = 52 | "content-length;content-type;host;x-amz-date;x-amz-target"; 53 | static const int SIGNED_HEADERS_LEN = 56; 54 | 55 | AWSClient::AWSClient() { 56 | /* Null until set in init method. */ 57 | awsRegion = 0; 58 | awsEndpoint = 0; 59 | awsSecKey = 0; 60 | awsKeyID = 0; 61 | httpClient = 0; 62 | dateTimeProvider = 0; 63 | } 64 | 65 | void AWSClient::setAWSRegion(const char * awsRegion) { 66 | int len = strlen(awsRegion) + 1; 67 | this->awsRegion = new char[len](); 68 | strcpy(this->awsRegion, awsRegion); 69 | } 70 | void AWSClient::setAWSEndpoint(const char * awsEndpoint) { 71 | int len = strlen(awsEndpoint) + 1; 72 | this->awsEndpoint = new char[len](); 73 | strcpy(this->awsEndpoint, awsEndpoint); 74 | } 75 | void AWSClient::setAWSSecretKey(const char * awsSecKey) { 76 | int len = strlen(awsSecKey) + 1; 77 | this->awsSecKey = new char[len](); 78 | strcpy(this->awsSecKey, awsSecKey); 79 | } 80 | void AWSClient::setAWSKeyID(const char * awsKeyID) { 81 | int len = strlen(awsKeyID) + 1; 82 | this->awsKeyID = new char[len](); 83 | strcpy(this->awsKeyID, awsKeyID); 84 | } 85 | void AWSClient::setHttpClient(IHttpClient* httpClient) { 86 | this->httpClient = httpClient; 87 | } 88 | void AWSClient::setDateTimeProvider(IDateTimeProvider* dateTimeProvider) { 89 | this->dateTimeProvider = dateTimeProvider; 90 | } 91 | 92 | AWSClient::~AWSClient() { 93 | if (awsRegion != 0) 94 | delete[] awsRegion; 95 | if (awsEndpoint != 0) 96 | delete[] awsEndpoint; 97 | if (awsSecKey != 0) 98 | delete[] awsSecKey; 99 | if (awsKeyID != 0) 100 | delete[] awsKeyID; 101 | } 102 | 103 | void AWSClient::initSignedHeaders() { 104 | /* For each of the formats for unsigned headers, determine the size of the 105 | * formatted string, allocate that much space in the next available element 106 | * in the headers array, create the string, and add it's length to the 107 | * headerLens array. */ 108 | 109 | int contentLen = payload.length(); 110 | int len = CONTENT_LENGTH_HEADER_LEN + digitCount(contentLen); 111 | headers[headersCreated] = new char[len + 1](); 112 | sprintf(headers[headersCreated], CONTENT_LENGTH_HEADER, contentLen); 113 | headerLens[headersCreated++] = len; 114 | 115 | len = CONTENT_TYPE_HEADER_LEN + strlen(contentType); 116 | headers[headersCreated] = new char[len + 1](); 117 | sprintf(headers[headersCreated], CONTENT_TYPE_HEADER, contentType); 118 | headerLens[headersCreated++] = len; 119 | 120 | len = HOST_HEADER_LEN + strlen(awsService) + strlen(awsRegion) 121 | + strlen(awsEndpoint); 122 | headers[headersCreated] = new char[len + 1](); 123 | sprintf(headers[headersCreated], HOST_HEADER, awsService, awsRegion, 124 | awsEndpoint); 125 | headerLens[headersCreated++] = len; 126 | 127 | len = X_AMZ_DATE_HEADER_LEN + AWS_DATE_LEN + AWS_TIME_LEN; 128 | headers[headersCreated] = new char[len + 1](); 129 | sprintf(headers[headersCreated], X_AMZ_DATE_HEADER, awsDate, awsTime); 130 | headerLens[headersCreated++] = len; 131 | 132 | len = X_AMZ_TARGET_HEADER_LEN + strlen(target); 133 | headers[headersCreated] = new char[len + 1](); 134 | sprintf(headers[headersCreated], X_AMZ_TARGET_HEADER, target); 135 | headerLens[headersCreated++] = len; 136 | } 137 | 138 | char* AWSClient::createStringToSign(void) { 139 | SHA256* sha256 = new SHA256(); 140 | char* hashed; 141 | /* Calculate length of canonicalForm string. */ 142 | int canonicalFormLen = CANONICAL_FORM_POST_LINE_LEN; 143 | for (int i = 0; i < headersCreated; i++) { 144 | /* +1 for newlines */ 145 | canonicalFormLen += *(headerLens + i) + 1; 146 | } 147 | /* +2 for newlines. */ 148 | canonicalFormLen += SIGNED_HEADERS_LEN + HASH_HEX_LEN + 2; 149 | 150 | char* canonicalForm = new char[canonicalFormLen + 1](); 151 | 152 | /* Write the cannonicalForm string. */ 153 | int canonicalFormWritten = 0; 154 | canonicalFormWritten += strlen( 155 | strcpy(canonicalForm + canonicalFormWritten, 156 | CANONICAL_FORM_POST_LINE)); 157 | for (int i = 0; i < headersCreated; i++) { 158 | canonicalFormWritten += sprintf(canonicalForm + canonicalFormWritten, 159 | "%s\n", *(headers + i)); 160 | } 161 | canonicalFormWritten += sprintf(canonicalForm + canonicalFormWritten, 162 | "\n%s\n", SIGNED_HEADERS); 163 | hashed = (*sha256)(payload.getCStr(), payload.length()); 164 | strcpy(canonicalForm + canonicalFormWritten, hashed); 165 | delete[] hashed; 166 | canonicalFormWritten += HASH_HEX_LEN; 167 | 168 | /* Hash the canonicalForm string. */ 169 | hashed = (*sha256)(canonicalForm, canonicalFormWritten); 170 | delete sha256; 171 | 172 | delete[] canonicalForm; 173 | 174 | /* Determine the size to the string to sign. */ 175 | int toSignLen = TO_SIGN_TEMPLATE_LEN + 2 * AWS_DATE_LEN + AWS_TIME_LEN 176 | + strlen(awsRegion) + strlen(awsService) + HASH_HEX_LEN; 177 | 178 | /* Create and return the string to sign. */ 179 | char* toSign = new char[toSignLen + 1](); 180 | sprintf(toSign, TO_SIGN_TEMPLATE, awsDate, awsTime, awsDate, awsRegion, 181 | awsService, hashed); 182 | delete[] hashed; 183 | return toSign; 184 | 185 | } 186 | char* AWSClient::createSignature(const char* toSign) { 187 | 188 | /* Allocate memory for the signature */ 189 | char* signature = new char[HASH_HEX_LEN + 1](); 190 | 191 | /* Create the signature key */ 192 | /* + 4 for "AWS4" */ 193 | int keyLen = strlen(awsSecKey) + 4; 194 | char* key = new char[keyLen + 1](); 195 | sprintf(key, "AWS4%s", awsSecKey); 196 | 197 | /* repeatedly apply hmac with the appropriate values. See 198 | * http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html 199 | * for algorithm. */ 200 | char* k1 = hmacSha256(key, keyLen, awsDate, strlen(awsDate)); 201 | delete[] key; 202 | char* k2 = hmacSha256(k1, SHA256_DEC_HASH_LEN, awsRegion, 203 | strlen(awsRegion)); 204 | delete[] k1; 205 | char* k3 = hmacSha256(k2, SHA256_DEC_HASH_LEN, awsService, 206 | strlen(awsService)); 207 | delete[] k2; 208 | char* k4 = hmacSha256(k3, SHA256_DEC_HASH_LEN, "aws4_request", 12); 209 | delete[] k3; 210 | char* k5 = hmacSha256(k4, SHA256_DEC_HASH_LEN, toSign, strlen(toSign)); 211 | delete[] k4; 212 | 213 | /* Convert the chars in hash to hex for signature. */ 214 | for (int i = 0; i < SHA256_DEC_HASH_LEN; ++i) { 215 | sprintf(signature + 2 * i, "%02lx", 0xff & (unsigned long) k5[i]); 216 | } 217 | delete[] k5; 218 | return signature; 219 | } 220 | 221 | void AWSClient::initUnsignedHeaders(const char* signature) { 222 | int len = AUTHORIZATION_HEADER_LEN + strlen(awsKeyID) + AWS_DATE_LEN 223 | + strlen(awsRegion) + strlen(awsService) + SIGNED_HEADERS_LEN 224 | + HASH_HEX_LEN; 225 | headers[headersCreated] = new char[len + 1](); 226 | sprintf(headers[headersCreated], AUTHORIZATION_HEADER, awsKeyID, awsDate, 227 | awsRegion, awsService, SIGNED_HEADERS, signature); 228 | headerLens[headersCreated++] = len; 229 | 230 | len = CONNECTION_HEADER_LEN; 231 | headers[headersCreated] = new char[len + 1](); 232 | strcpy(headers[headersCreated], CONNECTION_HEADER); 233 | headerLens[headersCreated++] = len; 234 | } 235 | 236 | void AWSClient::getESPtime(char * espTime) { 237 | const char* dateTime = dateTimeProvider->getDateTime(); 238 | strcpy(espTime, dateTime); 239 | } 240 | 241 | void AWSClient::createRequestInit(MinimalString &reqPayload) { 242 | //initialize object-scoped variables 243 | const char* dateTime = dateTimeProvider->getDateTime(); 244 | 245 | strncpy(awsDate, dateTime,8); 246 | strncpy(awsTime, dateTime + 8,6); 247 | 248 | ////sprintf(awsDate, "%.8s", dateTime); 249 | ////sprintf(awsTime, "%.6s", dateTime + 8); 250 | payload = reqPayload; 251 | headersCreated = 0; 252 | 253 | //Create signature and headers 254 | initSignedHeaders(); 255 | char* toSign = createStringToSign(); 256 | char* signature = createSignature(toSign); 257 | delete[] toSign; 258 | initUnsignedHeaders(signature); 259 | delete[] signature; 260 | } 261 | 262 | void AWSClient::createRequestCleanup() { 263 | /* Free each header */ 264 | for (int i = 0; i < headersCreated; i++) { 265 | delete[] headers[i]; 266 | } 267 | } 268 | 269 | char* AWSClient::headersToRequest() { 270 | /* Determine whether to use https or http postLine values. */ 271 | int postLineLen = 272 | httpS ? HTTPS_REQUEST_POST_LINE_LEN : HTTP_REQUEST_POST_LINE_LEN; 273 | const char* postLine = 274 | httpS ? HTTPS_REQUEST_POST_LINE : HTTP_REQUEST_POST_LINE; 275 | 276 | /* Calculate length of httpRequest string. */ 277 | int httpRequestLen = postLineLen + strlen(awsService) + strlen(awsRegion) 278 | + strlen(awsEndpoint); 279 | for (int i = 0; i < headersCreated; i++) { 280 | /* +1 for newline. */ 281 | httpRequestLen += *(headerLens + i) + 1; 282 | } 283 | /* +1 for newline. */ 284 | httpRequestLen += payload.length() + 1; 285 | 286 | /* Create and write to the httpRequest string. */ 287 | char* httpRequest = new char[httpRequestLen + 1](); 288 | int httpRequestWritten = 0; 289 | httpRequestWritten += sprintf(httpRequest + httpRequestWritten, postLine, 290 | awsService, awsRegion, awsEndpoint); 291 | for (int i = 0; i < headersCreated; i++) { 292 | httpRequestWritten += sprintf(httpRequest + httpRequestWritten, "%s\n", 293 | *(headers + i)); 294 | } 295 | httpRequestWritten += sprintf(httpRequest + httpRequestWritten, "\n%s", 296 | payload.getCStr()); 297 | 298 | return httpRequest; 299 | } 300 | 301 | char* AWSClient::headersToCurlRequest() { 302 | /* Add backslashes before quotes in json string */ 303 | char* escapedPayload = escapeQuotes(payload.getCStr()); 304 | 305 | /* Determine whether to use https or http curlEnd values. */ 306 | int curlEndLen = httpS ? HTTPS_CURL_END_LEN : HTTP_CURL_END_LEN; 307 | const char* curlEnd = httpS ? HTTPS_CURL_END : HTTP_CURL_END; 308 | 309 | /* Calculate length of curl command. +6 for "-d", 2 spaces, 2 quotes. */ 310 | int httpRequestLen = CURL_START_LEN + curlEndLen + strlen(awsService) 311 | + strlen(awsRegion) + strlen(awsEndpoint) + strlen(escapedPayload) 312 | + 6; 313 | for (int i = 0; i < headersCreated; i++) { 314 | /* +6 for "-H", 2 spaces, 2 quotes */ 315 | httpRequestLen += *(headerLens + i) + 6; 316 | } 317 | 318 | /* Create and write to the httpRequest string. */ 319 | char* httpRequest = new char[httpRequestLen + 1](); 320 | int httpRequestWritten = 0; 321 | httpRequestWritten += strlen(strcpy(httpRequest, CURL_START)); 322 | for (int i = 0; i < headersCreated; i++) { 323 | httpRequestWritten += sprintf(httpRequest + httpRequestWritten, 324 | "-H \"%s\" ", *(headers + i)); 325 | } 326 | httpRequestWritten += sprintf(httpRequest + httpRequestWritten, 327 | "-d \"%s\" ", escapedPayload); 328 | delete[] escapedPayload; 329 | httpRequestWritten += sprintf(httpRequest + httpRequestWritten, curlEnd, 330 | awsService, awsRegion, awsEndpoint); 331 | 332 | return httpRequest; 333 | } 334 | 335 | char* AWSClient::createRequest(MinimalString &reqPayload) { 336 | /* Check that all values have been initialized. */ 337 | if (awsRegion == 0 || awsEndpoint == 0 || awsSecKey == 0 || awsKeyID == 0 338 | || httpClient == 0 || dateTimeProvider == 0) 339 | return 0; 340 | createRequestInit(reqPayload); 341 | char* request = headersToRequest(); 342 | createRequestCleanup(); 343 | return request; 344 | } 345 | 346 | char* AWSClient::createCurlRequest(MinimalString &reqPayload) { 347 | /* Check that all values have been initialized. */ 348 | if (awsRegion == 0 || awsEndpoint == 0 || awsSecKey == 0 || awsKeyID == 0 349 | || httpClient == 0 || dateTimeProvider == 0) 350 | return 0; 351 | createRequestInit(reqPayload); 352 | char* request = headersToCurlRequest(); 353 | createRequestCleanup(); 354 | return request; 355 | } 356 | 357 | char* AWSClient::sendData(const char* data) { 358 | char* server = new char[strlen(awsService) + strlen(awsRegion) 359 | + strlen(awsEndpoint) + 4](); 360 | sprintf(server, "%s.%s.%s", awsService, awsRegion, awsEndpoint); 361 | int port = httpS ? 443 : 80; 362 | char* response = httpClient->send(data, server, port); 363 | delete[] server; 364 | return response; 365 | } 366 | -------------------------------------------------------------------------------- /AWS/AWSClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * AWSClient.h 3 | * 4 | * Base classes for services to create an HTTP request. 5 | * 6 | * Created on: Jul 8, 2014 7 | * Author: hoffmaj 8 | */ 9 | 10 | #ifndef AWSCLIENT_H_ 11 | #define AWSCLIENT_H_ 12 | 13 | #include "DeviceIndependentInterfaces.h" 14 | #include "AWSFoundationalTypes.h" 15 | 16 | /* Total number of headers. */ 17 | static const int HEADER_COUNT = 7; 18 | /* Size of the awsDate string. */ 19 | static const int AWS_DATE_LEN = 8; 20 | /* Size of the awsTime string. */ 21 | static const int AWS_TIME_LEN = 6; 22 | /* Size of sha hashes and signatures in hexidecimal. */ 23 | static const int HASH_HEX_LEN = 64; 24 | 25 | /* Base class for an AWS Service Client. Creates http and https request in raw 26 | * http format or as a curl command. */ 27 | class AWSClient { 28 | /* Name of region, eg. "us-east-1" in "kinesis.us-east-1.amazonaws.com". */ 29 | char* awsRegion; 30 | /* Endpoint, eg. "amazonaws.com" in "kinesis.us-east-1.amazonaws.com". */ 31 | char* awsEndpoint; 32 | /* The user's AWS Secret Key for accessing the AWS Resource. */ 33 | char* awsSecKey; 34 | /* The user's AWS Access Key ID for accessing the AWS Resource. */ 35 | char* awsKeyID; 36 | /* GMT date in yyyyMMdd format. */ 37 | char awsDate[AWS_DATE_LEN + 1]; 38 | /* GMT time in HHmmss format. */ 39 | char awsTime[AWS_TIME_LEN + 1]; 40 | /* Number of headers created. */ 41 | int headersCreated; 42 | /* Array of the created http headers. */ 43 | char* headers[HEADER_COUNT]; 44 | /* Array of string lengths of the headers in the "headers" array. */ 45 | int headerLens[HEADER_COUNT]; 46 | /* The payload of the httprequest to be created */ 47 | MinimalString payload; 48 | 49 | /* Add the headers that will be signed to the headers array. Called before 50 | * createStringToSign. */ 51 | void initSignedHeaders(); 52 | /* Create the canonical request and the string to sign as described. Return 53 | * value must be deleted by caller. */ 54 | char* createStringToSign(void); 55 | /* Given the string to sign, create the signature (a 64-char cstring). 56 | * Return value must be deleted by caller. */ 57 | char* createSignature(const char* toSign); 58 | /* Add the headers that will not be signed to the headers array. Called 59 | * after createSignature. */ 60 | void initUnsignedHeaders(const char* signature); 61 | /* Contains all of the work to be done before headersToRequest or 62 | * headersToCurlRequest are called. Takes the payload to be sent and the 63 | * GMT date in yyyyMMddHHmmss format. */ 64 | void createRequestInit(MinimalString &reqPayload); 65 | /* Clean up after headersToRequest or headersToCurlRequest are called. */ 66 | void createRequestCleanup(); 67 | /* Using the headers array, create a raw http request. */ 68 | char* headersToRequest(void); 69 | /* Using the headers array, create a http request in curl command 70 | * format. */ 71 | char* headersToCurlRequest(void); 72 | 73 | protected: 74 | /* Used to keep track of time. */ 75 | IDateTimeProvider* dateTimeProvider; 76 | /* Used to send http to the server. */ 77 | IHttpClient* httpClient; 78 | /* true if https is to be used, false if http is to be used. */ 79 | bool httpS; 80 | /* Name of service, eg. "kinesis" in "kinesis.us-east-1.amazonaws.com". */ 81 | const char* awsService; 82 | /* Content type of payload, eg. "application/x-amz-json-1.1". */ 83 | const char* contentType; 84 | /* The request's target, i.e. "Kinesis_20131202.PutRecord". */ 85 | const char* target; 86 | /* Creates a raw http request, given the payload and current GMT date in 87 | * yyyyMMddHHmmss format. Should be exposed to user by extending class. 88 | * Returns 0 if client is unititialized. */ 89 | char* createRequest(MinimalString &payload); 90 | /* Creates a http request in curl format, given the payload and current GMT 91 | * date in yyyyMMddHHmmss format. Should be exposed to user by extending 92 | * class. Returns 0 if client is unititialized. */ 93 | char* createCurlRequest(MinimalString &payload); 94 | /* Sends http data. Returns http response, or null on error. */ 95 | char* sendData(const char* data); 96 | /* Empty constructor. Must also be initialized with init. */ 97 | AWSClient(); 98 | 99 | public: 100 | /* Setters for values used by createRequest and createCurlRequest. Must 101 | * be set or create[Curl]Request will return null. */ 102 | void getESPtime(char * espTime); 103 | void setAWSRegion(const char * awsRegion); 104 | void setAWSEndpoint(const char * awsEndpoint); 105 | void setAWSSecretKey(const char * awsSecKey); 106 | void setAWSKeyID(const char * awsKeyID); 107 | void setHttpClient(IHttpClient* httpClient); 108 | void setDateTimeProvider(IDateTimeProvider* dateTimeProvider); 109 | ~AWSClient(void); 110 | }; 111 | 112 | #endif /* AWSCLIENT_H_ */ 113 | -------------------------------------------------------------------------------- /AWS/AWSClient2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AWSClient.cpp 3 | * 4 | * See AWSClient.h for description. 5 | * 6 | */ 7 | 8 | #include "AWSClient2.h" 9 | #include "Utils.h" 10 | #include "DeviceIndependentInterfaces.h" 11 | #include "AWSFoundationalTypes.h" 12 | #include "sha256.h" 13 | #include 14 | #include 15 | #include 16 | 17 | /* Constants string, formats, and lengths. */ 18 | static const char* CANONICAL_FORM_POST_LINE = "POST\n/\n\n"; 19 | static const int CANONICAL_FORM_POST_LINE_LEN = 8; 20 | static const char* HTTPS_REQUEST_POST_LINE = 21 | "POST https://%s.%s.%s/ HTTP/1.1\n"; 22 | static const int HTTPS_REQUEST_POST_LINE_LEN = 28; 23 | static const char* HTTP_REQUEST_POST_LINE = "POST http://%s.%s.%s/ HTTP/1.1\n"; 24 | static const int HTTP_REQUEST_POST_LINE_LEN = 27; 25 | static const char* TO_SIGN_TEMPLATE = 26 | "AWS4-HMAC-SHA256\n%sT%sZ\n%s/%s/%s/aws4_request\n%s"; 27 | static const int TO_SIGN_TEMPLATE_LEN = 36; 28 | static const char* CONTENT_LENGTH_HEADER = "content-length:%d"; 29 | static const int CONTENT_LENGTH_HEADER_LEN = 15; 30 | static const char* HOST_HEADER = "host:%s.%s.%s"; 31 | static const int HOST_HEADER_LEN = 7; 32 | static const char* CONNECTION_HEADER = "Connection:close"; 33 | static const int CONNECTION_HEADER_LEN = 16; 34 | static const char* CONTENT_TYPE_HEADER = "content-type:%s"; 35 | static const int CONTENT_TYPE_HEADER_LEN = 13; 36 | static const char* X_AMZ_DATE_HEADER = "x-amz-date:%sT%sZ"; 37 | static const int X_AMZ_DATE_HEADER_LEN = 13; 38 | static const char* AUTHORIZATION_HEADER = 39 | "Authorization: AWS4-HMAC-SHA256 Credential=%s/%s/%s/%s/aws4_request, SignedHeaders=%s, Signature=%s"; 40 | static const int AUTHORIZATION_HEADER_LEN = 87; 41 | static const char* SIGNED_HEADERS = 42 | "content-length;content-type;host;x-amz-date"; 43 | static const int SIGNED_HEADERS_LEN = 43; 44 | 45 | AWSClient2::AWSClient2() { 46 | /* Null until set in init method. */ 47 | awsRegion = 0; 48 | awsEndpoint = 0; 49 | awsSecKey = 0; 50 | awsKeyID = 0; 51 | httpClient = 0; 52 | dateTimeProvider = 0; 53 | } 54 | 55 | void AWSClient2::setAWSRegion(const char * awsRegion) { 56 | int len = strlen(awsRegion) + 1; 57 | this->awsRegion = new char[len](); 58 | strcpy(this->awsRegion, awsRegion); 59 | } 60 | void AWSClient2::setAWSEndpoint(const char * awsEndpoint) { 61 | int len = strlen(awsEndpoint) + 1; 62 | this->awsEndpoint = new char[len](); 63 | strcpy(this->awsEndpoint, awsEndpoint); 64 | } 65 | void AWSClient2::setAWSSecretKey(const char * awsSecKey) { 66 | int len = strlen(awsSecKey) + 1; 67 | this->awsSecKey = new char[len](); 68 | strcpy(this->awsSecKey, awsSecKey); 69 | } 70 | void AWSClient2::setAWSKeyID(const char * awsKeyID) { 71 | int len = strlen(awsKeyID) + 1; 72 | this->awsKeyID = new char[len](); 73 | strcpy(this->awsKeyID, awsKeyID); 74 | } 75 | void AWSClient2::setHttpClient(IHttpClient* httpClient) { 76 | this->httpClient = httpClient; 77 | } 78 | void AWSClient2::setDateTimeProvider(IDateTimeProvider* dateTimeProvider) { 79 | this->dateTimeProvider = dateTimeProvider; 80 | } 81 | 82 | AWSClient2::~AWSClient2() { 83 | if (awsRegion != 0) 84 | delete[] awsRegion; 85 | if (awsEndpoint != 0) 86 | delete[] awsEndpoint; 87 | if (awsSecKey != 0) 88 | delete[] awsSecKey; 89 | if (awsKeyID != 0) 90 | delete[] awsKeyID; 91 | } 92 | 93 | void AWSClient2::initSignedHeaders() { 94 | /* For each of the formats for unsigned headers, determine the size of the 95 | * formatted string, allocate that much space in the next available element 96 | * in the headers array, create the string, and add it's length to the 97 | * headerLens array. */ 98 | 99 | int contentLen = payload.length(); 100 | int len = CONTENT_LENGTH_HEADER_LEN + digitCount(contentLen); 101 | headers[headersCreated] = new char[len + 1](); 102 | sprintf(headers[headersCreated], CONTENT_LENGTH_HEADER, contentLen); 103 | headerLens[headersCreated++] = len; 104 | 105 | len = CONTENT_TYPE_HEADER_LEN + strlen(contentType); 106 | headers[headersCreated] = new char[len + 1](); 107 | sprintf(headers[headersCreated], CONTENT_TYPE_HEADER, contentType); 108 | headerLens[headersCreated++] = len; 109 | 110 | len = HOST_HEADER_LEN + strlen(awsService) + strlen(awsRegion) 111 | + strlen(awsEndpoint); 112 | headers[headersCreated] = new char[len + 1](); 113 | sprintf(headers[headersCreated], HOST_HEADER, awsService, awsRegion, 114 | awsEndpoint); 115 | headerLens[headersCreated++] = len; 116 | 117 | len = X_AMZ_DATE_HEADER_LEN + AWS_DATE_LEN2 + AWS_TIME_LEN2; 118 | headers[headersCreated] = new char[len + 1](); 119 | sprintf(headers[headersCreated], X_AMZ_DATE_HEADER, awsDate, awsTime); 120 | headerLens[headersCreated++] = len; 121 | } 122 | 123 | char* AWSClient2::createStringToSign(void) { 124 | SHA256* sha256 = new SHA256(); 125 | char* hashed; 126 | /* Calculate length of canonicalForm string. */ 127 | int canonicalFormLen = CANONICAL_FORM_POST_LINE_LEN; 128 | for (int i = 0; i < headersCreated; i++) { 129 | /* +1 for newlines */ 130 | canonicalFormLen += *(headerLens + i) + 1; 131 | } 132 | /* +2 for newlines. */ 133 | canonicalFormLen += SIGNED_HEADERS_LEN + HASH_HEX_LEN2 + 2; 134 | 135 | char* canonicalForm = new char[canonicalFormLen + 1](); 136 | 137 | /* Write the cannonicalForm string. */ 138 | int canonicalFormWritten = 0; 139 | canonicalFormWritten += strlen( 140 | strcpy(canonicalForm + canonicalFormWritten, 141 | CANONICAL_FORM_POST_LINE)); 142 | for (int i = 0; i < headersCreated; i++) { 143 | canonicalFormWritten += sprintf(canonicalForm + canonicalFormWritten, 144 | "%s\n", *(headers + i)); 145 | } 146 | canonicalFormWritten += sprintf(canonicalForm + canonicalFormWritten, 147 | "\n%s\n", SIGNED_HEADERS); 148 | hashed = (*sha256)(payload.getCStr(), payload.length()); 149 | strcpy(canonicalForm + canonicalFormWritten, hashed); 150 | delete[] hashed; 151 | canonicalFormWritten += HASH_HEX_LEN2; 152 | 153 | /* Hash the canonicalForm string. */ 154 | hashed = (*sha256)(canonicalForm, canonicalFormWritten); 155 | delete sha256; 156 | 157 | delete[] canonicalForm; 158 | 159 | /* Determine the size to the string to sign. */ 160 | int toSignLen = TO_SIGN_TEMPLATE_LEN + 2 * AWS_DATE_LEN2 + AWS_TIME_LEN2 161 | + strlen(awsRegion) + strlen(awsService) + HASH_HEX_LEN2; 162 | 163 | /* Create and return the string to sign. */ 164 | char* toSign = new char[toSignLen + 1](); 165 | sprintf(toSign, TO_SIGN_TEMPLATE, awsDate, awsTime, awsDate, awsRegion, 166 | awsService, hashed); 167 | delete[] hashed; 168 | return toSign; 169 | 170 | } 171 | char* AWSClient2::createSignature(const char* toSign) { 172 | 173 | /* Allocate memory for the signature */ 174 | char* signature = new char[HASH_HEX_LEN2 + 1](); 175 | 176 | /* Create the signature key */ 177 | /* + 4 for "AWS4" */ 178 | int keyLen = strlen(awsSecKey) + 4; 179 | char* key = new char[keyLen + 1](); 180 | sprintf(key, "AWS4%s", awsSecKey); 181 | 182 | /* repeatedly apply hmac with the appropriate values. See 183 | * http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html 184 | * for algorithm. */ 185 | char* k1 = hmacSha256(key, keyLen, awsDate, strlen(awsDate)); 186 | delete[] key; 187 | char* k2 = hmacSha256(k1, SHA256_DEC_HASH_LEN, awsRegion, 188 | strlen(awsRegion)); 189 | delete[] k1; 190 | char* k3 = hmacSha256(k2, SHA256_DEC_HASH_LEN, awsService, 191 | strlen(awsService)); 192 | delete[] k2; 193 | char* k4 = hmacSha256(k3, SHA256_DEC_HASH_LEN, "aws4_request", 12); 194 | delete[] k3; 195 | char* k5 = hmacSha256(k4, SHA256_DEC_HASH_LEN, toSign, strlen(toSign)); 196 | delete[] k4; 197 | 198 | /* Convert the chars in hash to hex for signature. */ 199 | for (int i = 0; i < SHA256_DEC_HASH_LEN; ++i) { 200 | sprintf(signature + 2 * i, "%02lx", 0xff & (unsigned long) k5[i]); 201 | } 202 | delete[] k5; 203 | return signature; 204 | } 205 | 206 | void AWSClient2::initUnsignedHeaders(const char* signature) { 207 | int len = AUTHORIZATION_HEADER_LEN + strlen(awsKeyID) + AWS_DATE_LEN2 208 | + strlen(awsRegion) + strlen(awsService) + SIGNED_HEADERS_LEN 209 | + HASH_HEX_LEN2; 210 | headers[headersCreated] = new char[len + 1](); 211 | sprintf(headers[headersCreated], AUTHORIZATION_HEADER, awsKeyID, awsDate, 212 | awsRegion, awsService, SIGNED_HEADERS, signature); 213 | headerLens[headersCreated++] = len; 214 | /* 215 | len = CONNECTION_HEADER_LEN; 216 | headers[headersCreated] = new char[len + 1](); 217 | strcpy(headers[headersCreated], CONNECTION_HEADER); 218 | headerLens[headersCreated++] = len; 219 | */ 220 | } 221 | 222 | void AWSClient2::createRequestInit(MinimalString &reqPayload) { 223 | //initialize object-scoped variables 224 | const char* dateTime = dateTimeProvider->getDateTime(); 225 | 226 | strncpy(awsDate, dateTime,8); 227 | strncpy(awsTime, dateTime + 8,6); 228 | 229 | ////sprintf(awsDate, "%.8s", dateTime); 230 | ////sprintf(awsTime, "%.6s", dateTime + 8); 231 | payload = reqPayload; 232 | headersCreated = 0; 233 | 234 | //Create signature and headers 235 | initSignedHeaders(); 236 | char* toSign = createStringToSign(); 237 | char* signature = createSignature(toSign); 238 | delete[] toSign; 239 | initUnsignedHeaders(signature); 240 | delete[] signature; 241 | } 242 | 243 | void AWSClient2::createRequestCleanup() { 244 | /* Free each header */ 245 | for (int i = 0; i < headersCreated; i++) { 246 | delete[] headers[i]; 247 | } 248 | } 249 | 250 | char* AWSClient2::headersToRequest() { 251 | /* Determine whether to use https or http postLine values. */ 252 | int postLineLen = 253 | httpS ? HTTPS_REQUEST_POST_LINE_LEN : HTTP_REQUEST_POST_LINE_LEN; 254 | const char* postLine = 255 | httpS ? HTTPS_REQUEST_POST_LINE : HTTP_REQUEST_POST_LINE; 256 | 257 | /* Calculate length of httpRequest string. */ 258 | int httpRequestLen = postLineLen + strlen(awsService) + strlen(awsRegion) 259 | + strlen(awsEndpoint); 260 | for (int i = 0; i < headersCreated; i++) { 261 | /* +1 for newline. */ 262 | httpRequestLen += *(headerLens + i) + 1; 263 | } 264 | /* +1 for newline. */ 265 | httpRequestLen += payload.length() + 1; 266 | 267 | /* Create and write to the httpRequest string. */ 268 | char* httpRequest = new char[httpRequestLen + 1](); 269 | int httpRequestWritten = 0; 270 | httpRequestWritten += sprintf(httpRequest + httpRequestWritten, postLine, 271 | awsService, awsRegion, awsEndpoint); 272 | for (int i = 0; i < headersCreated; i++) { 273 | httpRequestWritten += sprintf(httpRequest + httpRequestWritten, "%s\n", 274 | *(headers + i)); 275 | } 276 | httpRequestWritten += sprintf(httpRequest + httpRequestWritten, "\n%s", 277 | payload.getCStr()); 278 | 279 | return httpRequest; 280 | } 281 | 282 | char* AWSClient2::createRequest(MinimalString &reqPayload) { 283 | /* Check that all values have been initialized. */ 284 | if (awsRegion == 0 || awsEndpoint == 0 || awsSecKey == 0 || awsKeyID == 0 285 | || httpClient == 0 || dateTimeProvider == 0) 286 | return 0; 287 | 288 | createRequestInit(reqPayload); 289 | char* request = headersToRequest(); 290 | createRequestCleanup(); 291 | return request; 292 | } 293 | 294 | char* AWSClient2::sendData(const char* data) { 295 | char* server = new char[strlen(awsService) + strlen(awsRegion) 296 | + strlen(awsEndpoint) + 4](); 297 | sprintf(server, "%s.%s.%s", awsService, awsRegion, awsEndpoint); 298 | int port = httpS ? 443 : 80; 299 | char* response = httpClient->send(data, server, port); 300 | delete[] server; 301 | return response; 302 | } 303 | -------------------------------------------------------------------------------- /AWS/AWSClient2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * AWSClient2.h 3 | * 4 | * Base classes for services to create an HTTP request. 5 | * 6 | */ 7 | 8 | #ifndef AWSCLIENT2_H_ 9 | #define AWSCLIENT2_H_ 10 | 11 | #include "DeviceIndependentInterfaces.h" 12 | #include "AWSFoundationalTypes.h" 13 | 14 | #include "AWSClient.h" 15 | 16 | /* Total number of headers. */ 17 | static const int HEADER_COUNT2 = 7; 18 | /* Size of the awsDate string. */ 19 | static const int AWS_DATE_LEN2 = 8; 20 | /* Size of the awsTime string. */ 21 | static const int AWS_TIME_LEN2 = 6; 22 | /* Size of sha hashes and signatures in hexidecimal. */ 23 | static const int HASH_HEX_LEN2 = 64; 24 | 25 | /* Base class for an AWS Service Client. Creates http and https request in raw 26 | * http format or as a curl command. */ 27 | class AWSClient2 { 28 | /* Name of region, eg. "us-east-1" in "kinesis.us-east-1.amazonaws.com". */ 29 | char* awsRegion; 30 | /* Endpoint, eg. "amazonaws.com" in "kinesis.us-east-1.amazonaws.com". */ 31 | char* awsEndpoint; 32 | /* The user's AWS Secret Key for accessing the AWS Resource. */ 33 | char* awsSecKey; 34 | /* The user's AWS Access Key ID for accessing the AWS Resource. */ 35 | char* awsKeyID; 36 | /* GMT date in yyyyMMdd format. */ 37 | char awsDate[AWS_DATE_LEN + 1]; 38 | /* GMT time in HHmmss format. */ 39 | char awsTime[AWS_TIME_LEN + 1]; 40 | /* Number of headers created. */ 41 | int headersCreated; 42 | /* Array of the created http headers. */ 43 | char* headers[HEADER_COUNT]; 44 | /* Array of string lengths of the headers in the "headers" array. */ 45 | int headerLens[HEADER_COUNT]; 46 | /* The payload of the httprequest to be created */ 47 | MinimalString payload; 48 | 49 | /* Add the headers that will be signed to the headers array. Called before 50 | * createStringToSign. */ 51 | void initSignedHeaders(); 52 | /* Create the canonical request and the string to sign as described. Return 53 | * value must be deleted by caller. */ 54 | char* createStringToSign(void); 55 | /* Given the string to sign, create the signature (a 64-char cstring). 56 | * Return value must be deleted by caller. */ 57 | char* createSignature(const char* toSign); 58 | /* Add the headers that will not be signed to the headers array. Called 59 | * after createSignature. */ 60 | void initUnsignedHeaders(const char* signature); 61 | /* Contains all of the work to be done before headersToRequest or 62 | * headersToCurlRequest are called. Takes the payload to be sent and the 63 | * GMT date in yyyyMMddHHmmss format. */ 64 | void createRequestInit(MinimalString &reqPayload); 65 | /* Clean up after headersToRequest or headersToCurlRequest are called. */ 66 | void createRequestCleanup(); 67 | /* Using the headers array, create a raw http request. */ 68 | char* headersToRequest(void); 69 | 70 | protected: 71 | /* Used to keep track of time. */ 72 | IDateTimeProvider* dateTimeProvider; 73 | /* Used to send http to the server. */ 74 | IHttpClient* httpClient; 75 | /* true if https is to be used, false if http is to be used. */ 76 | bool httpS; 77 | /* Name of service, eg. "kinesis" in "kinesis.us-east-1.amazonaws.com". */ 78 | const char* awsService; 79 | /* Content type of payload, eg. "application/x-amz-json-1.1". */ 80 | const char* contentType; 81 | /* Creates a raw http request, given the payload and current GMT date in 82 | * yyyyMMddHHmmss format. Should be exposed to user by extending class. 83 | * Returns 0 if client is unititialized. */ 84 | char* createRequest(MinimalString &payload); 85 | /* Sends http data. Returns http response, or null on error. */ 86 | char* sendData(const char* data); 87 | /* Empty constructor. Must also be initialized with init. */ 88 | AWSClient2(); 89 | 90 | public: 91 | /* Setters for values used by createRequest and createCurlRequest. Must 92 | * be set or create[Curl]Request will return null. */ 93 | void setAWSRegion(const char * awsRegion); 94 | void setAWSEndpoint(const char * awsEndpoint); 95 | void setAWSSecretKey(const char * awsSecKey); 96 | void setAWSKeyID(const char * awsKeyID); 97 | void setHttpClient(IHttpClient* httpClient); 98 | void setDateTimeProvider(IDateTimeProvider* dateTimeProvider); 99 | ~AWSClient2(void); 100 | }; 101 | 102 | #endif /* AWSCLIENT2_H_ */ 103 | -------------------------------------------------------------------------------- /AWS/AWSFoundationalTypes.cpp: -------------------------------------------------------------------------------- 1 | #include "AWSFoundationalTypes.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | static const char* FALSE_AS_JSON = "\"false\""; 8 | static const char* TRUE_AS_JSON = "\"true\""; 9 | static const int DOUBLE_STR_LEN = 10; 10 | static const int LONG_STR_LEN = 10; 11 | static const int INT_STR_LEN = 10; 12 | 13 | void MinimalString::innerCopy(const MinimalString &toCopy) { 14 | alreadySerialized = toCopy.getAlreadySerialized(); 15 | const char* toCopyCStr = toCopy.getCStr(); 16 | if (toCopyCStr == NULL) { 17 | cStr = NULL; 18 | } else { 19 | cStr = new char[strlen(toCopyCStr) + 1](); 20 | strcpy(cStr, toCopyCStr); 21 | } 22 | } 23 | 24 | void MinimalString::innerDelete() { 25 | if (cStr != NULL) { 26 | delete[] cStr; 27 | } 28 | } 29 | 30 | MinimalString::MinimalString(const char* cStr) { 31 | alreadySerialized = false; 32 | this->cStr = new char[strlen(cStr) + 1](); 33 | strcpy(this->cStr, cStr); 34 | } 35 | 36 | MinimalString::MinimalString(const char* cStr, int len) { 37 | alreadySerialized = false; 38 | this->cStr = new char[len + 1](); 39 | strncpy(this->cStr, cStr, len); 40 | } 41 | 42 | MinimalString::MinimalString() { 43 | alreadySerialized = false; 44 | this->cStr = NULL; 45 | } 46 | 47 | MinimalString::MinimalString(const MinimalString &toCopy) { 48 | innerCopy(toCopy); 49 | } 50 | 51 | const char* MinimalString::getCStr() const { 52 | return cStr; 53 | } 54 | 55 | MinimalString& MinimalString::operator=(const MinimalString &toCopy) { 56 | /* Make sure we are not leaking memory by overwriting a value. */ 57 | innerDelete(); 58 | innerCopy(toCopy); 59 | return *this; 60 | } 61 | 62 | void MinimalString::setAlreadySerialized(bool alreadySerialized) { 63 | this->alreadySerialized = alreadySerialized; 64 | } 65 | 66 | bool MinimalString::getAlreadySerialized() const { 67 | return alreadySerialized; 68 | } 69 | 70 | MinimalString MinimalString::jsonSerialize() const { 71 | if (alreadySerialized) { 72 | return *this; 73 | } 74 | if (cStr == NULL) { 75 | /* Empty quoted string. */ 76 | return MinimalString((char*) "\"\""); 77 | } else { 78 | /* +3 for the 2 quotes and the null termination character. */ 79 | char* json = new char[strlen(cStr) + 3](); 80 | sprintf(json, "\"%s\"", cStr); 81 | MinimalString jsonMinStr(json); 82 | delete json; 83 | return jsonMinStr; 84 | } 85 | } 86 | 87 | bool MinimalString::jsonDeserialize(MinimalString json) { 88 | innerDelete(); 89 | const char* jsonCStr = json.getCStr(); 90 | if (jsonCStr == NULL) { 91 | return false; 92 | } 93 | int jsonLen = json.length(); 94 | /* Only deserialize if the first and last characters are quotes. */ 95 | if ((jsonCStr[0] == '"') && (jsonCStr[jsonLen - 1] == '"')) { 96 | /* -2 for the removed quote, but +1 for the null termination 97 | * character. */ 98 | cStr = new char[jsonLen - 1](); 99 | /* Copy all but the first and last characters */ 100 | strncpy(cStr, jsonCStr + 1, jsonLen - 2); 101 | } else { 102 | return false; 103 | } 104 | return true; 105 | } 106 | 107 | int MinimalString::length() const { 108 | if (cStr == NULL) { 109 | return 0; 110 | } else { 111 | return strlen(cStr); 112 | } 113 | } 114 | 115 | MinimalString::~MinimalString() { 116 | innerDelete(); 117 | } 118 | 119 | SerializableDouble::SerializableDouble(double d) { 120 | this->d = d; 121 | } 122 | SerializableDouble::SerializableDouble() { 123 | } 124 | 125 | double SerializableDouble::getValue() const { 126 | return d; 127 | } 128 | 129 | MinimalString SerializableDouble::jsonSerialize() const { 130 | return jsonSerializeDouble(d); 131 | } 132 | 133 | bool SerializableDouble::jsonDeserialize(MinimalString json) { 134 | d = atof(json.getCStr()); 135 | /* No error checking for this deserialize method, always return success. */ 136 | return true; 137 | } 138 | 139 | MinimalString jsonCommaConcatenate(MinimalList list, 140 | char openChar, char closeChar) { 141 | int arrayLen = list.getLength(); 142 | const MinimalString* array = list.getArray(); 143 | MinimalString* jsonSerializationsArray = new MinimalString[arrayLen](); 144 | /* Count the length of the string to allocate and create array of 145 | * serialized char*s: 146 | * There are arrayLen - 1 separating commas and 1 openChar and 1 closeChar. 147 | * fullSerializationLen = arrayLen - 1 + 2 + (lengths of all 148 | * json-serialized elements) = arraylen + 1 + (lengths of all 149 | * json-serialized elements). */ 150 | int fullSerializationLen = arrayLen + 1; 151 | for (int i = 0; i < arrayLen; i++) { 152 | /* If quote, use teh jsonSerialized string, which simply puts quotes 153 | * around it. Otherwise use the string as is. */ 154 | jsonSerializationsArray[i] = array[i]; 155 | fullSerializationLen += jsonSerializationsArray[i].length(); 156 | } 157 | /* Create the array-syntax serialization of all inner serializations. */ 158 | char* fullSerialization = new char[fullSerializationLen + 1](); 159 | int fullSerializationWritten = 0; 160 | fullSerialization[fullSerializationWritten++] = openChar; 161 | for (int i = 0; i < arrayLen; i++) { 162 | /* Write the inner serialization to the full serialization and delete 163 | * the no longer needed inner serialization. */ 164 | fullSerializationWritten += sprintf( 165 | fullSerialization + fullSerializationWritten, "%s", 166 | jsonSerializationsArray[i].getCStr()); 167 | /* Comma after all but last element. */ 168 | if (i != arrayLen - 1) { 169 | fullSerialization[fullSerializationWritten++] = ','; 170 | } 171 | } 172 | delete[] jsonSerializationsArray; 173 | fullSerialization[fullSerializationWritten++] = closeChar; 174 | MinimalString jsonString(fullSerialization); 175 | delete[] fullSerialization; 176 | return jsonString; 177 | } 178 | 179 | MinimalList jsonCommaSeparate(MinimalString jsonList, 180 | char openChar, char closeChar) { 181 | /* Incemented for every opening bracket and decremented for every closing 182 | * bracket. */ 183 | int bracketLevel = 0; 184 | /* Incemented for every opening brace and decremented for every closing 185 | * brace. */ 186 | int braceLevel = 0; 187 | /* True when looking at characters within quotes. */ 188 | bool inQuotes = false; 189 | int jsonLen = jsonList.length(); 190 | 191 | if ((jsonLen <= 2) || (jsonList.getCStr()[0] != openChar) 192 | || (jsonList.getCStr()[jsonLen - 1] != closeChar)) { 193 | /* Missing open/close character or empty list, return empty list. */ 194 | MinimalList emptyList(0, 0); 195 | return emptyList; 196 | } 197 | 198 | /* Number of elements in the list, determined as the number of 199 | * unquoted/unbraced/unbracketed commas found plus one. */ 200 | int elementCount = 1; 201 | /* This for loop determines elementCount. */ 202 | for (int i = 1; i < jsonLen - 1; i++) { 203 | switch (jsonList.getCStr()[i]) { 204 | case '"': 205 | /* Toggle inQuotes. */ 206 | inQuotes = !inQuotes; 207 | break; 208 | /* increment and decrement for unquoted brackets and braces. */ 209 | case '[': 210 | if (!inQuotes) { 211 | bracketLevel++; 212 | } 213 | break; 214 | case ']': 215 | if (!inQuotes) { 216 | bracketLevel--; 217 | } 218 | break; 219 | case '{': 220 | if (!inQuotes) { 221 | braceLevel++; 222 | } 223 | break; 224 | case '}': 225 | if (!inQuotes) { 226 | braceLevel--; 227 | } 228 | break; 229 | case ',': 230 | /* If we are at the opening level, and unquoted, and have 231 | * encountered a comma, it is a element separator. */ 232 | if ((braceLevel == 0) && (bracketLevel == 0) && !inQuotes) { 233 | elementCount++; 234 | } 235 | } 236 | } 237 | /* Array of elements. */ 238 | MinimalString* elements = new MinimalString[elementCount](); 239 | /* Number of elements created / next index of elements array to write 240 | * to. */ 241 | int elementsCreated = 0; 242 | /* The start index for the current element being coppied. */ 243 | int elementStartIdx = 1; 244 | /* This for loop fills the elements array. */ 245 | for (int i = 1; i < jsonLen - 1; i++) { 246 | switch (jsonList.getCStr()[i]) { 247 | case '"': 248 | /* Toggle inQuotes. */ 249 | inQuotes = !inQuotes; 250 | break; 251 | /* increment and decrement for unquoted brackets and braces. */ 252 | case '[': 253 | if (!inQuotes) { 254 | bracketLevel++; 255 | } 256 | break; 257 | case ']': 258 | if (!inQuotes) { 259 | bracketLevel--; 260 | } 261 | break; 262 | case '{': 263 | if (!inQuotes) { 264 | braceLevel++; 265 | } 266 | break; 267 | case '}': 268 | if (!inQuotes) { 269 | braceLevel--; 270 | } 271 | break; 272 | case ',': 273 | /* If we are at the opening level, and unquoted, and have 274 | * encountered a comma, it is a element separator. */ 275 | if ((braceLevel == 0) && (bracketLevel == 0) && !inQuotes) { 276 | /* Copy over the string from the elementStartIdx (inclusive) to 277 | * i (exclusive). */ 278 | elements[elementsCreated] = MinimalString( 279 | jsonList.getCStr() + elementStartIdx, 280 | i - elementStartIdx); 281 | 282 | elementsCreated++; 283 | /* The start of the next element is the index after the index 284 | * of this comma. */ 285 | elementStartIdx = i + 1; 286 | } 287 | } 288 | } 289 | /* Copy over the last element, which does not end with a comma. */ 290 | elements[elementsCreated] = MinimalString( 291 | jsonList.getCStr() + elementStartIdx, 292 | (jsonList.length() - 1) - elementStartIdx); 293 | 294 | MinimalList elementsList(elements, elementCount); 295 | delete[] elements; 296 | return elementsList; 297 | } 298 | 299 | MinimalString jsonSerializeBool(bool b) { 300 | return b ? MinimalString(TRUE_AS_JSON) : MinimalString(FALSE_AS_JSON); 301 | } 302 | 303 | bool jsonDeserializeBool(MinimalString json) { 304 | return !strcmp("true", json.getCStr()); 305 | } 306 | 307 | int jsonDeserializeEnum(const char** enumLookup, int enumSize, 308 | MinimalString json) { 309 | MinimalString serialized = json.jsonSerialize(); 310 | const char* expected = serialized.getCStr(); 311 | for (int i = 0; i < enumSize; i++) { 312 | if (!strcmp(enumLookup[i], expected)) { 313 | return i; 314 | } 315 | } 316 | return -1; 317 | } 318 | 319 | MinimalString jsonSerializeDouble(double d) { 320 | char buffer[DOUBLE_STR_LEN + 1]; 321 | snprintf(buffer, DOUBLE_STR_LEN, "%f", d); 322 | return MinimalString(buffer); 323 | } 324 | 325 | MinimalString jsonSerializeLong(long l) { 326 | char buffer[LONG_STR_LEN + 1]; 327 | snprintf(buffer, LONG_STR_LEN, "%ld", l); 328 | return MinimalString(buffer); 329 | } 330 | 331 | MinimalString jsonSerializeInt(int i) { 332 | char buffer[INT_STR_LEN + 1]; 333 | snprintf(buffer, INT_STR_LEN, "%d", i); 334 | return MinimalString(buffer); 335 | } 336 | 337 | -------------------------------------------------------------------------------- /AWS/AWSFoundationalTypes.h: -------------------------------------------------------------------------------- 1 | /* Arduino compatible c++ does not have any built-in map or list types. It 2 | * does have a string type that is ONLY available on Arduino. The types in this 3 | * file are designed to be substitutes for map/list/string that function on 4 | * any device. They are simple and do not cover some edge conditions and should 5 | * be used carefully. Any types provided to the generics here should have deep 6 | * copying for their assignment operator and copy constructor, e.g. no 7 | * "char*". Many also require jsonSerialize and jsonDeserialize methods. */ 8 | 9 | #ifndef AWSFOUNDATIONALTYPES_H_ 10 | #define AWSFOUNDATIONALTYPES_H_ 11 | 12 | #include 13 | #include 14 | 15 | /* Common enum for AWS actions. Are set/returned by actions depending on the 16 | * action's success. */ 17 | enum ActionError { 18 | NONE_ACTIONERROR, 19 | RESPONSE_PARSING_ACTIONERROR, 20 | INVALID_REQUEST_ACTIONERROR, 21 | MISSING_REQUIRED_ARGS_ACTIONERROR, 22 | CONNECTION_ACTIONERROR 23 | }; 24 | 25 | /* A wrapper for c_strings that has a deep-copying equality operator and 26 | * constructor, as well as json serialization and deserialization 27 | * capabilities. */ 28 | class MinimalString { 29 | /* The wrapped c_string. */ 30 | char* cStr; 31 | /* True if this string represents an object that is already serialized and 32 | * therefore does not need to be enclosed in quotes when jsonSerialize() 33 | * is called. */ 34 | bool alreadySerialized; 35 | /* Copy the other MinimalString's c_string. */ 36 | void innerCopy(const MinimalString &toCopy); 37 | /* Delete the c_string if it exists. */ 38 | void innerDelete(); 39 | public: 40 | /* Copy the passed c_string. */ 41 | MinimalString(const char* cStr); 42 | /* Copy the passed c_string. */ 43 | MinimalString(const char* cStr, int len); 44 | /* Empty constructor, c_string is NULL. */ 45 | MinimalString(); 46 | /* Coppying constructor. */ 47 | MinimalString(const MinimalString &toCopy); 48 | /* c_string getter. */ 49 | const char* getCStr() const; 50 | /* Overload = for deep copying. */ 51 | MinimalString& operator=(const MinimalString &toCopy); 52 | void setAlreadySerialized(bool alreadySerialized); 53 | bool getAlreadySerialized() const; 54 | /* Returns a quoted copy of the string. */ 55 | MinimalString jsonSerialize() const; 56 | /* Unquotes the string if it has surrounding quotes. */ 57 | bool jsonDeserialize(MinimalString json); 58 | /* Calculate the length of the string. */ 59 | int length() const; 60 | ~MinimalString(); 61 | }; 62 | 63 | /* A wrapper for double objects that can has serialize/deserialize methods */ 64 | class SerializableDouble { 65 | /* The wrapped double. */ 66 | double d; 67 | public: 68 | SerializableDouble(double d); 69 | SerializableDouble(); 70 | /* c_string getter. */ 71 | double getValue() const; 72 | /* Returns the value's serialization. */ 73 | MinimalString jsonSerialize() const; 74 | /* Sets the value to the json's deserialization. */ 75 | bool jsonDeserialize(MinimalString json); 76 | }; 77 | 78 | /* Contains an array of elements and has a deep-copying equality operator and 79 | * constructor. Element_Type must also have a deep-copying equality operator 80 | * and constructor for this to work properly. Also has json serialization and 81 | * deserialization capabilities*/ 82 | template 83 | class MinimalList { 84 | /* The underylying array. */ 85 | Element_Type* array; 86 | /* Number of elements in the array. */ 87 | int length; 88 | /* Deep-copy an array and length. */ 89 | void copyArray(const Element_Type* array, int length); 90 | /* Delete the array is it exists. */ 91 | void innerDelete(); 92 | public: 93 | /* Getter for array. */ 94 | const Element_Type* getArray() const; 95 | /* Getter for length. */ 96 | int getLength() const; 97 | /* Constructor taking the array and length. */ 98 | MinimalList(const Element_Type* array, int length); 99 | /* Deep-copying constructor. */ 100 | MinimalList(const MinimalList& toCopy); 101 | /* Empty constructor with null array. */ 102 | MinimalList(); 103 | /* Deep-copying equality operator. */ 104 | MinimalList& operator=( 105 | const MinimalList& toCopy); 106 | /* Given a json syntax list of Element_Type, populate the MinimalList. 107 | * Element_Type must have a jsonDeserialize() method. */ 108 | bool jsonDeserialize(MinimalString json); 109 | /* Create a json syntax list of the elements. Element_Type must have a 110 | * jsonSerialize() method. */ 111 | MinimalString jsonSerialize() const; 112 | ~MinimalList(); 113 | }; 114 | 115 | /* Conatiner for a key-value pair, with json serialization/deserialization 116 | * capabilities. */ 117 | template 118 | class MinimalKeyValuePair { 119 | Key_Type key; 120 | Value_Type value; 121 | public: 122 | /* Given a string of the json form for a key-value pair (i.e. key:value), 123 | * set key and value. Key_Type and Value_Type must each have a 124 | * jsonDeserialize() method. */ 125 | bool jsonDeserialize(MinimalString json); 126 | /* Create a json key-value pair. Key_Type and Value_Type must each have a 127 | * jsonSerialize() method. */ 128 | MinimalString jsonSerialize() const; 129 | /* Get the key. */ 130 | Key_Type getKey() const; 131 | /* Get the value. */ 132 | Value_Type getValue() const; 133 | MinimalKeyValuePair(Key_Type key, Value_Type value); 134 | MinimalKeyValuePair(); 135 | }; 136 | 137 | /* A MinimalString to Value_Type map. This is designed to take a small amount 138 | * of code and memory, not to be fast. It is json 139 | * serializable/deserializable. */ 140 | template 141 | class MinimalMap { 142 | MinimalList > pairList; 143 | public: 144 | /* Json serialize a map. Value_Type MUST have a jsonSerialize() method. */ 145 | MinimalString jsonSerialize() const; 146 | /* Json deserialize a map. Value_Type MUST have a jsonDeserialize() method. */ 147 | bool jsonDeserialize(MinimalString json); 148 | /* Constructor taking a list of MinimalString, Value_Type pairs. */ 149 | MinimalMap( 150 | MinimalList > pairList); 151 | /* Constructor taking a array of MinimalString, Value_Type pairs and it's 152 | * length. */ 153 | MinimalMap(MinimalKeyValuePair* pairArray, 154 | int length); 155 | /* Return the underlying list of KeyValuePairs. */ 156 | MinimalList > getPairList() const; 157 | MinimalMap(); 158 | /* Get the value (passed by reference) for the given key (as a c_string 159 | * for usability purposes). */ 160 | bool get(const char* key, Value_Type &value); 161 | }; 162 | 163 | /* Takes an List of MinimalStrings, places a comma between each element and 164 | * surrounds all in brackets. */ 165 | MinimalString jsonCommaConcatenate(MinimalList list, 166 | char openChar, char closeChar); 167 | 168 | /* Create a list of strings for a string that starts openChar, ends with 169 | * closedChar, and has comma separated elements. */ 170 | MinimalList jsonCommaSeparate(MinimalString jsonList, 171 | char openChar, char closeChar); 172 | 173 | /* Get the json representation of a boolean */ 174 | MinimalString jsonSerializeBool(bool b); 175 | 176 | /* Get the json representation of a long */ 177 | MinimalString jsonSerializeLong(long l); 178 | 179 | /* Get the json representation of a int */ 180 | MinimalString jsonSerializeInt(int l); 181 | 182 | /* Get the json representation of a boolean */ 183 | bool jsonDeserializeBool(MinimalString json); 184 | 185 | /* Return the integer value of the enum deserialization of the passed json 186 | * string. enumLookup is an array of char* where each element is the json 187 | * serialization of a an enum, where the index of the lookup string is the same 188 | * as the integer value of the corresponding enum. */ 189 | int jsonDeserializeEnum(const char** enumLookup, int enumSize, 190 | MinimalString json); 191 | 192 | /* Get the json representation of a double */ 193 | MinimalString jsonSerializeDouble(double d); 194 | 195 | /* 196 | * 197 | * The following are the implementations for the template classes. Apparently 198 | * these are not allowed in the cpp file for templates. 199 | * 200 | */ 201 | 202 | template 203 | void MinimalList::copyArray(const Element_Type* array, 204 | int length) { 205 | this->length = length; 206 | this->array = new Element_Type[length](); 207 | for (int i = 0; i < length; i++) { 208 | this->array[i] = array[i]; 209 | } 210 | } 211 | 212 | template 213 | void MinimalList::innerDelete() { 214 | if (array != NULL) { 215 | delete[] array; 216 | } 217 | } 218 | 219 | template 220 | const Element_Type* MinimalList::getArray() const { 221 | return array; 222 | } 223 | 224 | template 225 | int MinimalList::getLength() const { 226 | return length; 227 | } 228 | 229 | template 230 | MinimalList::MinimalList(const Element_Type* array, int length) { 231 | copyArray(array, length); 232 | } 233 | 234 | template 235 | MinimalList::MinimalList( 236 | const MinimalList& toCopy) { 237 | copyArray(toCopy.getArray(), toCopy.getLength()); 238 | } 239 | 240 | template 241 | MinimalList::MinimalList() { 242 | this->array = NULL; 243 | this->length = 0; 244 | } 245 | 246 | template 247 | MinimalList& MinimalList::operator=( 248 | const MinimalList& toCopy) { 249 | innerDelete(); 250 | copyArray(toCopy.getArray(), toCopy.getLength()); 251 | return *this; 252 | } 253 | 254 | template 255 | bool MinimalList::jsonDeserialize(MinimalString json) { 256 | innerDelete(); 257 | /* Create a list of strings of the elements and get the underlying 258 | * array. */ 259 | MinimalList elementStrs = jsonCommaSeparate(json, '[', ']'); 260 | const MinimalString* elementStrsArray = elementStrs.getArray(); 261 | length = elementStrs.getLength(); 262 | /* Set this list's underlying array to be the same size as the length of 263 | * array of elementStings, and serialize each element with the 264 | * elementString of the same index. */ 265 | array = new Element_Type[length](); 266 | for (int i = 0; i < length; i++) { 267 | if (!array[i].jsonDeserialize(elementStrsArray[i])) { 268 | /* Propogate error. */ 269 | return false; 270 | } 271 | } 272 | return true; 273 | } 274 | 275 | template 276 | MinimalString MinimalList::jsonSerialize() const { 277 | /* Create a list where each element is the serialization of the 278 | * Element_Type. */ 279 | MinimalString* elementStrs = new MinimalString[length](); 280 | for (int i = 0; i < length; i++) { 281 | elementStrs[i] = array[i].jsonSerialize(); 282 | } 283 | MinimalList strList(elementStrs, length); 284 | delete[] elementStrs; 285 | /* Concatenate each string into a json-format list. */ 286 | return jsonCommaConcatenate(strList, '[', ']'); 287 | } 288 | 289 | template 290 | MinimalList::~MinimalList() { 291 | innerDelete(); 292 | } 293 | 294 | template 295 | bool MinimalKeyValuePair::jsonDeserialize( 296 | MinimalString json) { 297 | int jsonLen = json.length(); 298 | const char* jsonCStr = json.getCStr(); 299 | const char* colonLocation = strchr(jsonCStr, ':'); 300 | /* If not containing a colon, use empty constructor. */ 301 | if (colonLocation == NULL) { 302 | key = Key_Type(); 303 | value = Value_Type(); 304 | } 305 | int colonIdx = colonLocation - jsonCStr; 306 | /* Deserialize each substring on either side of the ':' in the json 307 | * string. */ 308 | if (!key.jsonDeserialize(MinimalString(jsonCStr, colonIdx)) 309 | || !value.jsonDeserialize( 310 | MinimalString(colonLocation + 1, jsonLen - colonIdx))) { 311 | /* Propogate error. */ 312 | return false; 313 | } 314 | return true; 315 | } 316 | 317 | template 318 | MinimalString MinimalKeyValuePair::jsonSerialize() const { 319 | MinimalString keyStr = key.jsonSerialize(); 320 | MinimalString valueStr = value.jsonSerialize(); 321 | /* +1 for the ':' between them. */ 322 | int serializedLen = keyStr.length() + valueStr.length() + 1; 323 | char* serialized = new char[serializedLen + 1](); 324 | sprintf(serialized, "%s:%s", keyStr.getCStr(), valueStr.getCStr()); 325 | MinimalString jsonString(serialized); 326 | delete[] serialized; 327 | return jsonString; 328 | } 329 | 330 | template 331 | Key_Type MinimalKeyValuePair::getKey() const { 332 | return key; 333 | } 334 | 335 | template 336 | Value_Type MinimalKeyValuePair::getValue() const { 337 | return value; 338 | } 339 | 340 | template 341 | MinimalKeyValuePair::MinimalKeyValuePair(Key_Type key, 342 | Value_Type value) { 343 | this->key = key; 344 | this->value = value; 345 | } 346 | 347 | template 348 | MinimalKeyValuePair::MinimalKeyValuePair() { 349 | } 350 | 351 | template 352 | MinimalString MinimalMap::jsonSerialize() const { 353 | const MinimalKeyValuePair* pairArray = 354 | pairList.getArray(); 355 | int arrayLen = pairList.getLength(); 356 | /* Create a string array and assign each element to the serialized form of 357 | * the element at the same index in pairArray. */ 358 | MinimalString* serializedPairsArray = new MinimalString[arrayLen](); 359 | for (int i = 0; i < arrayLen; i++) { 360 | serializedPairsArray[i] = pairArray[i].jsonSerialize(); 361 | } 362 | /* Create a list out of the serializedPairsArray, and create a braced, 363 | * comma-separated string out of the list. */ 364 | MinimalList serializedPairsList(serializedPairsArray, 365 | arrayLen); 366 | delete[] serializedPairsArray; 367 | return jsonCommaConcatenate(serializedPairsList, '{', '}'); 368 | } 369 | 370 | template 371 | bool MinimalMap::jsonDeserialize(MinimalString json) { 372 | /* Create the list of serialized pairs. */ 373 | MinimalList strList = jsonCommaSeparate(json, '{', '}'); 374 | const MinimalString* strArray = strList.getArray(); 375 | int arrayLen = strList.getLength(); 376 | /* Create a list of pairs the same size as the list of serialized pair 377 | * strings, then deserialize each element. */ 378 | MinimalKeyValuePair* deserializedPairsArray = 379 | new MinimalKeyValuePair [arrayLen](); 380 | for (int i = 0; i < arrayLen; i++) { 381 | if (!deserializedPairsArray[i].jsonDeserialize(strArray[i])) { 382 | delete[] deserializedPairsArray; 383 | /* Propogate error. */ 384 | return false; 385 | } 386 | } 387 | pairList = MinimalList >( 388 | deserializedPairsArray, arrayLen); 389 | delete[] deserializedPairsArray; 390 | return true; 391 | } 392 | 393 | template 394 | MinimalMap::MinimalMap( 395 | MinimalList > pairList) { 396 | this->pairList = pairList; 397 | } 398 | 399 | template 400 | MinimalMap::MinimalMap( 401 | MinimalKeyValuePair* pairArray, int length) { 402 | /* Create a MinimalList out of the array. */ 403 | this->pairList = 404 | MinimalList >( 405 | pairArray, length); 406 | } 407 | 408 | template 409 | MinimalList > MinimalMap< 410 | Value_Type>::getPairList() const { 411 | return pairList; 412 | } 413 | 414 | template 415 | MinimalMap::MinimalMap() { 416 | } 417 | 418 | template 419 | bool MinimalMap::get(const char* key, Value_Type &value) { 420 | /* Using a linear search, not hashing for this map. Program size and memory 421 | * usage are more important than speed on these microcontrollers. */ 422 | for (int i = 0; i < pairList.getLength(); i++) { 423 | if (!strcmp(key, pairList.getArray()[i].getKey().getCStr())) { 424 | value = pairList.getArray()[i].getValue(); 425 | return true; 426 | } 427 | } 428 | return false; 429 | } 430 | 431 | #endif /* AWSFOUNDATIONALTYPES_H_ */ 432 | -------------------------------------------------------------------------------- /AWS/AmazonDynamoDBClient.h: -------------------------------------------------------------------------------- 1 | #ifndef AMAZONDYNAMODBCLIENT_H_ 2 | #define AMAZONDYNAMODBCLIENT_H_ 3 | #include "AWSFoundationalTypes.h" 4 | #include "AWSClient.h" 5 | 6 | enum ReturnValue{ 7 | NONE_RETURNVALUE, 8 | ALL_OLD_RETURNVALUE, 9 | UPDATED_OLD_RETURNVALUE, 10 | ALL_NEW_RETURNVALUE, 11 | UPDATED_NEW_RETURNVALUE 12 | }; 13 | 14 | enum ConditionalOperator{ 15 | AND_CONDITIONALOPERATOR, 16 | OR_CONDITIONALOPERATOR 17 | }; 18 | 19 | enum TableStatus{ 20 | CREATING_TABLESTATUS, 21 | UPDATING_TABLESTATUS, 22 | DELETING_TABLESTATUS, 23 | ACTIVE_TABLESTATUS 24 | }; 25 | 26 | /*

If set to TOTAL, the response includes ConsumedCapacity data for tables and indexes. If set to INDEXES, the response includes ConsumedCapacity for indexes. If set to NONE (the default), ConsumedCapacity is not included in the response.

*/ 27 | enum ReturnConsumedCapacity{ 28 | INDEXES_RETURNCONSUMEDCAPACITY, 29 | TOTAL_RETURNCONSUMEDCAPACITY, 30 | NONE_RETURNCONSUMEDCAPACITY 31 | }; 32 | 33 | enum ProjectionType{ 34 | ALL_PROJECTIONTYPE, 35 | KEYS_ONLY_PROJECTIONTYPE, 36 | INCLUDE_PROJECTIONTYPE 37 | }; 38 | 39 | enum ComparisonOperator{ 40 | EQ_COMPARISONOPERATOR, 41 | NE_COMPARISONOPERATOR, 42 | IN_COMPARISONOPERATOR, 43 | LE_COMPARISONOPERATOR, 44 | LT_COMPARISONOPERATOR, 45 | GE_COMPARISONOPERATOR, 46 | GT_COMPARISONOPERATOR, 47 | BETWEEN_COMPARISONOPERATOR, 48 | NOT_NULL_COMPARISONOPERATOR, 49 | NULL_COMPARISONOPERATOR, 50 | CONTAINS_COMPARISONOPERATOR, 51 | NOT_CONTAINS_COMPARISONOPERATOR, 52 | BEGINS_WITH_COMPARISONOPERATOR 53 | }; 54 | 55 | enum ReturnItemCollectionMetrics{ 56 | SIZE_RETURNITEMCOLLECTIONMETRICS, 57 | NONE_RETURNITEMCOLLECTIONMETRICS 58 | }; 59 | 60 | enum ScalarAttributeType{ 61 | S_SCALARATTRIBUTETYPE, 62 | N_SCALARATTRIBUTETYPE, 63 | B_SCALARATTRIBUTETYPE 64 | }; 65 | 66 | enum IndexStatus{ 67 | CREATING_INDEXSTATUS, 68 | UPDATING_INDEXSTATUS, 69 | DELETING_INDEXSTATUS, 70 | ACTIVE_INDEXSTATUS 71 | }; 72 | 73 | enum Select{ 74 | ALL_ATTRIBUTES_SELECT, 75 | ALL_PROJECTED_ATTRIBUTES_SELECT, 76 | SPECIFIC_ATTRIBUTES_SELECT, 77 | COUNT_SELECT 78 | }; 79 | 80 | enum KeyType{ 81 | HASH_KEYTYPE, 82 | RANGE_KEYTYPE 83 | }; 84 | 85 | enum AttributeAction{ 86 | ADD_ATTRIBUTEACTION, 87 | PUT_ATTRIBUTEACTION, 88 | DELETE_ATTRIBUTEACTION 89 | }; 90 | 91 | /*

Represents a single element of a key schema. A key schema specifies the attributes that make up the primary key of a table, or the key attributes of an index.

A KeySchemaElement represents exactly one attribute of the primary key. For example, a hash type primary key would be represented by one KeySchemaElement. A hash-and-range type primary key would require one KeySchemaElement for the hash attribute, and another KeySchemaElement for the range attribute.

*/ 92 | class KeySchemaElement{ 93 | KeyType keyType; 94 | MinimalString attributeName; 95 | bool keyTypeBeenSet; 96 | bool attributeNameBeenSet; 97 | void reset(); 98 | public: 99 | KeySchemaElement(); 100 | bool jsonDeserialize(MinimalString json); 101 | MinimalString jsonSerialize() const; 102 | void setKeyType(KeyType keyType); 103 | void setAttributeName(MinimalString attributeName); 104 | KeyType getKeyType() const; 105 | MinimalString getAttributeName() const; 106 | }; 107 | 108 | /*

Represents attributes that are copied (projected) from the table into an index. These are in addition to the primary key attributes and index key attributes, which are automatically projected.

*/ 109 | class Projection{ 110 | ProjectionType projectionType; 111 | MinimalList nonKeyAttributes; 112 | bool projectionTypeBeenSet; 113 | bool nonKeyAttributesBeenSet; 114 | void reset(); 115 | public: 116 | Projection(); 117 | bool jsonDeserialize(MinimalString json); 118 | MinimalString jsonSerialize() const; 119 | void setProjectionType(ProjectionType projectionType); 120 | void setNonKeyAttributes(MinimalList nonKeyAttributes); 121 | ProjectionType getProjectionType() const; 122 | MinimalList getNonKeyAttributes() const; 123 | }; 124 | 125 | /*

Represents the provisioned throughput settings for the table, consisting of read and write capacity units, along with data about increases and decreases.

*/ 126 | class ProvisionedThroughputDescription{ 127 | long writeCapacityUnits; 128 | long numberOfDecreasesToday; 129 | MinimalString lastIncreaseDateTime; 130 | MinimalString lastDecreaseDateTime; 131 | long readCapacityUnits; 132 | bool writeCapacityUnitsBeenSet; 133 | bool numberOfDecreasesTodayBeenSet; 134 | bool lastIncreaseDateTimeBeenSet; 135 | bool lastDecreaseDateTimeBeenSet; 136 | bool readCapacityUnitsBeenSet; 137 | void reset(); 138 | public: 139 | ProvisionedThroughputDescription(); 140 | bool jsonDeserialize(MinimalString json); 141 | MinimalString jsonSerialize() const; 142 | void setWriteCapacityUnits(long writeCapacityUnits); 143 | void setNumberOfDecreasesToday(long numberOfDecreasesToday); 144 | void setLastIncreaseDateTime(MinimalString lastIncreaseDateTime); 145 | void setLastDecreaseDateTime(MinimalString lastDecreaseDateTime); 146 | void setReadCapacityUnits(long readCapacityUnits); 147 | long getWriteCapacityUnits() const; 148 | long getNumberOfDecreasesToday() const; 149 | MinimalString getLastIncreaseDateTime() const; 150 | MinimalString getLastDecreaseDateTime() const; 151 | long getReadCapacityUnits() const; 152 | }; 153 | 154 | /*

Represents the data for an attribute. You can set one, and only one, of the elements.

*/ 155 | class AttributeValue{ 156 | ////MinimalList SSS; 157 | MinimalList SS; 158 | MinimalList BS; 159 | MinimalString B; 160 | MinimalString S; 161 | MinimalList NS; 162 | MinimalString N; 163 | bool SSBeenSet; 164 | bool BSBeenSet; 165 | bool BBeenSet; 166 | bool SBeenSet; 167 | bool NSBeenSet; 168 | bool NBeenSet; 169 | void reset(); 170 | public: 171 | AttributeValue(); 172 | bool jsonDeserialize(MinimalString json); 173 | MinimalString jsonSerialize() const; 174 | ////void setSS(MinimalList SSS); 175 | void setSS(MinimalList SS); 176 | void setBS(MinimalList BS); 177 | void setB(MinimalString B); 178 | void setS(MinimalString S); 179 | void setNS(MinimalList NS); 180 | void setN(MinimalString N); 181 | MinimalList getSS() const; 182 | MinimalList getBS() const; 183 | MinimalString getB() const; 184 | MinimalString getS() const; 185 | MinimalList getNS() const; 186 | MinimalString getN() const; 187 | }; 188 | 189 | /*

Represents the provisioned throughput settings for a specified table or index. The settings can be modified using the UpdateTable operation.

For current minimum and maximum provisioned throughput values, see Limits in the Amazon DynamoDB Developer Guide.

*/ 190 | class ProvisionedThroughput{ 191 | long writeCapacityUnits; 192 | long readCapacityUnits; 193 | bool writeCapacityUnitsBeenSet; 194 | bool readCapacityUnitsBeenSet; 195 | void reset(); 196 | public: 197 | ProvisionedThroughput(); 198 | bool jsonDeserialize(MinimalString json); 199 | MinimalString jsonSerialize() const; 200 | void setWriteCapacityUnits(long writeCapacityUnits); 201 | void setReadCapacityUnits(long readCapacityUnits); 202 | long getWriteCapacityUnits() const; 203 | long getReadCapacityUnits() const; 204 | }; 205 | 206 | /*

Represents an attribute for describing the key schema for the table and indexes.

*/ 207 | class AttributeDefinition{ 208 | ScalarAttributeType attributeType; 209 | MinimalString attributeName; 210 | bool attributeTypeBeenSet; 211 | bool attributeNameBeenSet; 212 | void reset(); 213 | public: 214 | AttributeDefinition(); 215 | bool jsonDeserialize(MinimalString json); 216 | MinimalString jsonSerialize() const; 217 | void setAttributeType(ScalarAttributeType attributeType); 218 | void setAttributeName(MinimalString attributeName); 219 | ScalarAttributeType getAttributeType() const; 220 | MinimalString getAttributeName() const; 221 | }; 222 | 223 | /*

Represents the properties of a local secondary index.

*/ 224 | class LocalSecondaryIndexDescription{ 225 | Projection projection; 226 | long itemCount; 227 | long indexSizeBytes; 228 | MinimalList keySchema; 229 | MinimalString indexName; 230 | bool projectionBeenSet; 231 | bool itemCountBeenSet; 232 | bool indexSizeBytesBeenSet; 233 | bool keySchemaBeenSet; 234 | bool indexNameBeenSet; 235 | void reset(); 236 | public: 237 | LocalSecondaryIndexDescription(); 238 | bool jsonDeserialize(MinimalString json); 239 | MinimalString jsonSerialize() const; 240 | void setProjection(Projection projection); 241 | void setItemCount(long itemCount); 242 | void setIndexSizeBytes(long indexSizeBytes); 243 | void setKeySchema(MinimalList keySchema); 244 | void setIndexName(MinimalString indexName); 245 | Projection getProjection() const; 246 | long getItemCount() const; 247 | long getIndexSizeBytes() const; 248 | MinimalList getKeySchema() const; 249 | MinimalString getIndexName() const; 250 | }; 251 | 252 | /*

Represents the properties of a global secondary index.

*/ 253 | class GlobalSecondaryIndexDescription{ 254 | Projection projection; 255 | ProvisionedThroughputDescription provisionedThroughput; 256 | IndexStatus indexStatus; 257 | long itemCount; 258 | long indexSizeBytes; 259 | MinimalList keySchema; 260 | MinimalString indexName; 261 | bool projectionBeenSet; 262 | bool provisionedThroughputBeenSet; 263 | bool indexStatusBeenSet; 264 | bool itemCountBeenSet; 265 | bool indexSizeBytesBeenSet; 266 | bool keySchemaBeenSet; 267 | bool indexNameBeenSet; 268 | void reset(); 269 | public: 270 | GlobalSecondaryIndexDescription(); 271 | bool jsonDeserialize(MinimalString json); 272 | MinimalString jsonSerialize() const; 273 | void setProjection(Projection projection); 274 | void setProvisionedThroughput(ProvisionedThroughputDescription provisionedThroughput); 275 | void setIndexStatus(IndexStatus indexStatus); 276 | void setItemCount(long itemCount); 277 | void setIndexSizeBytes(long indexSizeBytes); 278 | void setKeySchema(MinimalList keySchema); 279 | void setIndexName(MinimalString indexName); 280 | Projection getProjection() const; 281 | ProvisionedThroughputDescription getProvisionedThroughput() const; 282 | IndexStatus getIndexStatus() const; 283 | long getItemCount() const; 284 | long getIndexSizeBytes() const; 285 | MinimalList getKeySchema() const; 286 | MinimalString getIndexName() const; 287 | }; 288 | 289 | /*

Represents the amount of provisioned throughput capacity consumed on a table or an index.

*/ 290 | class Capacity{ 291 | double capacityUnits; 292 | bool capacityUnitsBeenSet; 293 | void reset(); 294 | public: 295 | Capacity(); 296 | bool jsonDeserialize(MinimalString json); 297 | MinimalString jsonSerialize() const; 298 | void setCapacityUnits(double capacityUnits); 299 | double getCapacityUnits() const; 300 | }; 301 | 302 | /*

Represents a request to perform a PutItem operation on an item.

*/ 303 | class PutRequest{ 304 | MinimalMap item; 305 | bool itemBeenSet; 306 | void reset(); 307 | public: 308 | PutRequest(); 309 | bool jsonDeserialize(MinimalString json); 310 | MinimalString jsonSerialize() const; 311 | void setItem(MinimalMap item); 312 | MinimalMap getItem() const; 313 | }; 314 | 315 | /*

Represents a request to perform a DeleteItem operation on an item.

*/ 316 | class DeleteRequest{ 317 | MinimalMap key; 318 | bool keyBeenSet; 319 | void reset(); 320 | public: 321 | DeleteRequest(); 322 | bool jsonDeserialize(MinimalString json); 323 | MinimalString jsonSerialize() const; 324 | void setKey(MinimalMap key); 325 | MinimalMap getKey() const; 326 | }; 327 | 328 | /*

Represents the new provisioned throughput settings to be applied to a global secondary index.

*/ 329 | class UpdateGlobalSecondaryIndexAction{ 330 | ProvisionedThroughput provisionedThroughput; 331 | MinimalString indexName; 332 | bool provisionedThroughputBeenSet; 333 | bool indexNameBeenSet; 334 | void reset(); 335 | public: 336 | UpdateGlobalSecondaryIndexAction(); 337 | bool jsonDeserialize(MinimalString json); 338 | MinimalString jsonSerialize() const; 339 | void setProvisionedThroughput(ProvisionedThroughput provisionedThroughput); 340 | void setIndexName(MinimalString indexName); 341 | ProvisionedThroughput getProvisionedThroughput() const; 342 | MinimalString getIndexName() const; 343 | }; 344 | 345 | /*

Represents the properties of a table.

*/ 346 | class TableDescription{ 347 | ProvisionedThroughputDescription provisionedThroughput; 348 | MinimalString creationDateTime; 349 | long itemCount; 350 | MinimalList globalSecondaryIndexes; 351 | TableStatus tableStatus; 352 | MinimalString tableName; 353 | MinimalList localSecondaryIndexes; 354 | MinimalList keySchema; 355 | MinimalList attributeDefinitions; 356 | long tableSizeBytes; 357 | bool provisionedThroughputBeenSet; 358 | bool creationDateTimeBeenSet; 359 | bool itemCountBeenSet; 360 | bool globalSecondaryIndexesBeenSet; 361 | bool tableStatusBeenSet; 362 | bool tableNameBeenSet; 363 | bool localSecondaryIndexesBeenSet; 364 | bool keySchemaBeenSet; 365 | bool attributeDefinitionsBeenSet; 366 | bool tableSizeBytesBeenSet; 367 | void reset(); 368 | public: 369 | TableDescription(); 370 | bool jsonDeserialize(MinimalString json); 371 | MinimalString jsonSerialize() const; 372 | void setProvisionedThroughput(ProvisionedThroughputDescription provisionedThroughput); 373 | void setCreationDateTime(MinimalString creationDateTime); 374 | void setItemCount(long itemCount); 375 | void setGlobalSecondaryIndexes(MinimalList globalSecondaryIndexes); 376 | void setTableStatus(TableStatus tableStatus); 377 | void setTableName(MinimalString tableName); 378 | void setLocalSecondaryIndexes(MinimalList localSecondaryIndexes); 379 | void setKeySchema(MinimalList keySchema); 380 | void setAttributeDefinitions(MinimalList attributeDefinitions); 381 | void setTableSizeBytes(long tableSizeBytes); 382 | ProvisionedThroughputDescription getProvisionedThroughput() const; 383 | MinimalString getCreationDateTime() const; 384 | long getItemCount() const; 385 | MinimalList getGlobalSecondaryIndexes() const; 386 | TableStatus getTableStatus() const; 387 | MinimalString getTableName() const; 388 | MinimalList getLocalSecondaryIndexes() const; 389 | MinimalList getKeySchema() const; 390 | MinimalList getAttributeDefinitions() const; 391 | long getTableSizeBytes() const; 392 | }; 393 | 394 | /*

Represents the capacity units consumed by an operation. The data returned includes the total provisioned throughput consumed, along with statistics for the table and any indexes involved in the operation. ConsumedCapacity is only returned if it was asked for in the request. For more information, see Provisioned Throughput in the Amazon DynamoDB Developer Guide.

*/ 395 | class ConsumedCapacity{ 396 | double capacityUnits; 397 | MinimalMap globalSecondaryIndexes; 398 | MinimalString tableName; 399 | MinimalMap localSecondaryIndexes; 400 | Capacity table; 401 | bool capacityUnitsBeenSet; 402 | bool globalSecondaryIndexesBeenSet; 403 | bool tableNameBeenSet; 404 | bool localSecondaryIndexesBeenSet; 405 | bool tableBeenSet; 406 | void reset(); 407 | public: 408 | ConsumedCapacity(); 409 | bool jsonDeserialize(MinimalString json); 410 | MinimalString jsonSerialize() const; 411 | void setCapacityUnits(double capacityUnits); 412 | void setGlobalSecondaryIndexes(MinimalMap globalSecondaryIndexes); 413 | void setTableName(MinimalString tableName); 414 | void setLocalSecondaryIndexes(MinimalMap localSecondaryIndexes); 415 | void setTable(Capacity table); 416 | double getCapacityUnits() const; 417 | MinimalMap getGlobalSecondaryIndexes() const; 418 | MinimalString getTableName() const; 419 | MinimalMap getLocalSecondaryIndexes() const; 420 | Capacity getTable() const; 421 | }; 422 | 423 | /*

Information about item collections, if any, that were affected by the operation. ItemCollectionMetrics is only returned if it was asked for in the request. If the table does not have any local secondary indexes, this information is not returned in the response.

*/ 424 | class ItemCollectionMetrics{ 425 | MinimalList sizeEstimateRangeGB; 426 | MinimalMap itemCollectionKey; 427 | bool sizeEstimateRangeGBBeenSet; 428 | bool itemCollectionKeyBeenSet; 429 | void reset(); 430 | public: 431 | ItemCollectionMetrics(); 432 | bool jsonDeserialize(MinimalString json); 433 | MinimalString jsonSerialize() const; 434 | void setSizeEstimateRangeGB(MinimalList sizeEstimateRangeGB); 435 | void setItemCollectionKey(MinimalMap itemCollectionKey); 436 | MinimalList getSizeEstimateRangeGB() const; 437 | MinimalMap getItemCollectionKey() const; 438 | }; 439 | 440 | /*

Represents a condition to be compared with an attribute value. This condition can be used with DeleteItem, PutItem or UpdateItem operations; if the comparison evaluates to true, the operation succeeds; if not the operation fails. You can use ExpectedAttributeValue in one of two different ways:

  • Use AttributeValueList to specify one or more values to compare against an attribute. Use ComparisonOperator to specify how you want to perform the comparison. If the comparison evaluates to true, then the conditional operation succeeds.

  • Use Value to specify a value that DynamoDB will compare against an attribute. If the values match, then ExpectedAttributeValue evaluates to true and the conditional operation succeeds. Optionally, you can also set Exists to false, indicating that you do not expect to find the attribute value in the table. In this case, the conditional operation succeeds only if the comparison evaluates to false.

Value and Exists are incompatible with AttributeValueList and ComparisonOperator. If you attempt to use both sets of parameters at once, DynamoDB will throw a ValidationException.

The Value and Exists parameters are deprecated. Even though DynamoDB will continue to support these parameters, we recommend that you use AttributeValueList and ComparisonOperator instead. AttributeValueList and ComparisonOperator let you construct a much wider range of conditions than is possible with Value and Exists.

*/ 441 | class ExpectedAttributeValue{ 442 | AttributeValue value; 443 | bool exists; 444 | MinimalList attributeValueList; 445 | ComparisonOperator comparisonOperator; 446 | bool valueBeenSet; 447 | bool existsBeenSet; 448 | bool attributeValueListBeenSet; 449 | bool comparisonOperatorBeenSet; 450 | void reset(); 451 | public: 452 | ExpectedAttributeValue(); 453 | bool jsonDeserialize(MinimalString json); 454 | MinimalString jsonSerialize() const; 455 | void setValue(AttributeValue value); 456 | void setExists(bool exists); 457 | void setAttributeValueList(MinimalList attributeValueList); 458 | void setComparisonOperator(ComparisonOperator comparisonOperator); 459 | AttributeValue getValue() const; 460 | bool getExists() const; 461 | MinimalList getAttributeValueList() const; 462 | ComparisonOperator getComparisonOperator() const; 463 | }; 464 | 465 | /*

Represents the selection criteria for a Query or Scan operation:

  • For a Query operation, Condition is used for specifying the KeyConditions to use when querying a table or an index. For KeyConditions, only the following comparison operators are supported:

    EQ | LE | LT | GE | GT | BEGINS_WITH | BETWEEN

    Condition is also used in a QueryFilter, which evaluates the query results and returns only the desired values.

  • For a Scan operation, Condition is used in a ScanFilter, which evaluates the scan results and returns only the desired values.

*/ 466 | class Condition{ 467 | MinimalList attributeValueList; 468 | ComparisonOperator comparisonOperator; 469 | bool attributeValueListBeenSet; 470 | bool comparisonOperatorBeenSet; 471 | void reset(); 472 | public: 473 | Condition(); 474 | bool jsonDeserialize(MinimalString json); 475 | MinimalString jsonSerialize() const; 476 | void setAttributeValueList(MinimalList attributeValueList); 477 | void setComparisonOperator(ComparisonOperator comparisonOperator); 478 | MinimalList getAttributeValueList() const; 479 | ComparisonOperator getComparisonOperator() const; 480 | }; 481 | 482 | /*

Represents an operation to perform - either DeleteItem or PutItem. You can only specify one of these operations, not both, in a single WriteRequest. If you do need to perform both of these operations, you will need to specify two separate WriteRequest objects.

*/ 483 | class WriteRequest{ 484 | DeleteRequest deleteRequest; 485 | PutRequest putRequest; 486 | bool deleteRequestBeenSet; 487 | bool putRequestBeenSet; 488 | void reset(); 489 | public: 490 | WriteRequest(); 491 | bool jsonDeserialize(MinimalString json); 492 | MinimalString jsonSerialize() const; 493 | void setDeleteRequest(DeleteRequest deleteRequest); 494 | void setPutRequest(PutRequest putRequest); 495 | DeleteRequest getDeleteRequest() const; 496 | PutRequest getPutRequest() const; 497 | }; 498 | 499 | /*

Represents a set of primary keys and, for each key, the attributes to retrieve from the table.

For each primary key, you must provide all of the key attributes. For example, with a hash type primary key, you only need to specify the hash attribute. For a hash-and-range type primary key, you must specify both the hash attribute and the range attribute.

*/ 500 | class KeysAndAttributes{ 501 | bool consistentRead; 502 | MinimalList attributesToGet; 503 | MinimalList > keys; 504 | bool consistentReadBeenSet; 505 | bool attributesToGetBeenSet; 506 | bool keysBeenSet; 507 | void reset(); 508 | public: 509 | KeysAndAttributes(); 510 | bool jsonDeserialize(MinimalString json); 511 | MinimalString jsonSerialize() const; 512 | void setConsistentRead(bool consistentRead); 513 | void setAttributesToGet(MinimalList attributesToGet); 514 | void setKeys(MinimalList > keys); 515 | bool getConsistentRead() const; 516 | MinimalList getAttributesToGet() const; 517 | MinimalList > getKeys() const; 518 | }; 519 | 520 | /*

Represents a local secondary index.

*/ 521 | class LocalSecondaryIndex{ 522 | Projection projection; 523 | MinimalList keySchema; 524 | MinimalString indexName; 525 | bool projectionBeenSet; 526 | bool keySchemaBeenSet; 527 | bool indexNameBeenSet; 528 | void reset(); 529 | public: 530 | LocalSecondaryIndex(); 531 | bool jsonDeserialize(MinimalString json); 532 | MinimalString jsonSerialize() const; 533 | void setProjection(Projection projection); 534 | void setKeySchema(MinimalList keySchema); 535 | void setIndexName(MinimalString indexName); 536 | Projection getProjection() const; 537 | MinimalList getKeySchema() const; 538 | MinimalString getIndexName() const; 539 | }; 540 | 541 | /*

Represents a global secondary index.

*/ 542 | class GlobalSecondaryIndex{ 543 | Projection projection; 544 | ProvisionedThroughput provisionedThroughput; 545 | MinimalList keySchema; 546 | MinimalString indexName; 547 | bool projectionBeenSet; 548 | bool provisionedThroughputBeenSet; 549 | bool keySchemaBeenSet; 550 | bool indexNameBeenSet; 551 | void reset(); 552 | public: 553 | GlobalSecondaryIndex(); 554 | bool jsonDeserialize(MinimalString json); 555 | MinimalString jsonSerialize() const; 556 | void setProjection(Projection projection); 557 | void setProvisionedThroughput(ProvisionedThroughput provisionedThroughput); 558 | void setKeySchema(MinimalList keySchema); 559 | void setIndexName(MinimalString indexName); 560 | Projection getProjection() const; 561 | ProvisionedThroughput getProvisionedThroughput() const; 562 | MinimalList getKeySchema() const; 563 | MinimalString getIndexName() const; 564 | }; 565 | 566 | /*

For the UpdateItem operation, represents the attributes to be modified, the action to perform on each, and the new value for each.

Attribute values cannot be null; string and binary type attributes must have lengths greater than zero; and set type attributes must not be empty. Requests with empty values will be rejected with a ValidationException.

*/ 567 | class AttributeValueUpdate{ 568 | AttributeValue value; 569 | AttributeAction action; 570 | bool valueBeenSet; 571 | bool actionBeenSet; 572 | void reset(); 573 | public: 574 | AttributeValueUpdate(); 575 | bool jsonDeserialize(MinimalString json); 576 | MinimalString jsonSerialize() const; 577 | void setValue(AttributeValue value); 578 | void setAction(AttributeAction action); 579 | AttributeValue getValue() const; 580 | AttributeAction getAction() const; 581 | }; 582 | 583 | /*

Represents the new provisioned throughput settings to apply to a global secondary index.

*/ 584 | class GlobalSecondaryIndexUpdate{ 585 | UpdateGlobalSecondaryIndexAction update; 586 | bool updateBeenSet; 587 | void reset(); 588 | public: 589 | GlobalSecondaryIndexUpdate(); 590 | bool jsonDeserialize(MinimalString json); 591 | MinimalString jsonSerialize() const; 592 | void setUpdate(UpdateGlobalSecondaryIndexAction update); 593 | UpdateGlobalSecondaryIndexAction getUpdate() const; 594 | }; 595 | 596 | /*

Represents the output of a ListTables operation.

*/ 597 | class ListTablesOutput{ 598 | MinimalString lastEvaluatedTableName; 599 | MinimalList tableNames; 600 | bool lastEvaluatedTableNameBeenSet; 601 | bool tableNamesBeenSet; 602 | MinimalString errorType; 603 | MinimalString errorMessage; 604 | void reset(); 605 | public: 606 | ListTablesOutput(); 607 | bool jsonDeserialize(MinimalString json); 608 | MinimalString getErrorType() const; 609 | MinimalString getErrorMessage() const; 610 | void setLastEvaluatedTableName(MinimalString lastEvaluatedTableName); 611 | void setTableNames(MinimalList tableNames); 612 | MinimalString getLastEvaluatedTableName() const; 613 | MinimalList getTableNames() const; 614 | }; 615 | 616 | /*

Represents the output of an UpdateTable operation.

*/ 617 | class UpdateTableOutput{ 618 | TableDescription tableDescription; 619 | bool tableDescriptionBeenSet; 620 | MinimalString errorType; 621 | MinimalString errorMessage; 622 | void reset(); 623 | public: 624 | UpdateTableOutput(); 625 | bool jsonDeserialize(MinimalString json); 626 | MinimalString getErrorType() const; 627 | MinimalString getErrorMessage() const; 628 | void setTableDescription(TableDescription tableDescription); 629 | TableDescription getTableDescription() const; 630 | }; 631 | 632 | /*

Represents the output of an UpdateItem operation.

*/ 633 | class UpdateItemOutput{ 634 | MinimalMap attributes; 635 | ItemCollectionMetrics itemCollectionMetrics; 636 | ConsumedCapacity consumedCapacity; 637 | bool attributesBeenSet; 638 | bool itemCollectionMetricsBeenSet; 639 | bool consumedCapacityBeenSet; 640 | MinimalString errorType; 641 | MinimalString errorMessage; 642 | void reset(); 643 | public: 644 | UpdateItemOutput(); 645 | bool jsonDeserialize(MinimalString json); 646 | MinimalString getErrorType() const; 647 | MinimalString getErrorMessage() const; 648 | void setAttributes(MinimalMap attributes); 649 | void setItemCollectionMetrics(ItemCollectionMetrics itemCollectionMetrics); 650 | void setConsumedCapacity(ConsumedCapacity consumedCapacity); 651 | MinimalMap getAttributes() const; 652 | ItemCollectionMetrics getItemCollectionMetrics() const; 653 | ConsumedCapacity getConsumedCapacity() const; 654 | }; 655 | 656 | /*

Represents the input of a DeleteItem operation.

*/ 657 | class DeleteItemInput{ 658 | ReturnItemCollectionMetrics returnItemCollectionMetrics; 659 | ReturnValue returnValues; 660 | MinimalMap key; 661 | ConditionalOperator conditionalOperator; 662 | MinimalMap expected; 663 | MinimalString tableName; 664 | ReturnConsumedCapacity returnConsumedCapacity; 665 | bool returnItemCollectionMetricsBeenSet; 666 | bool returnValuesBeenSet; 667 | bool keyBeenSet; 668 | bool conditionalOperatorBeenSet; 669 | bool expectedBeenSet; 670 | bool tableNameBeenSet; 671 | bool returnConsumedCapacityBeenSet; 672 | void reset(); 673 | public: 674 | DeleteItemInput(); 675 | bool requiredAreSet() const; 676 | MinimalString jsonSerialize() const; 677 | void setReturnItemCollectionMetrics(ReturnItemCollectionMetrics returnItemCollectionMetrics); 678 | void setReturnValues(ReturnValue returnValues); 679 | void setKey(MinimalMap key); 680 | void setConditionalOperator(ConditionalOperator conditionalOperator); 681 | void setExpected(MinimalMap expected); 682 | void setTableName(MinimalString tableName); 683 | void setReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity); 684 | ReturnItemCollectionMetrics getReturnItemCollectionMetrics() const; 685 | ReturnValue getReturnValues() const; 686 | MinimalMap getKey() const; 687 | ConditionalOperator getConditionalOperator() const; 688 | MinimalMap getExpected() const; 689 | MinimalString getTableName() const; 690 | ReturnConsumedCapacity getReturnConsumedCapacity() const; 691 | }; 692 | 693 | /*

Represents the input of a Scan operation.

*/ 694 | class ScanInput{ 695 | MinimalMap scanFilter; 696 | Select select; 697 | int totalSegments; 698 | ConditionalOperator conditionalOperator; 699 | int segment; 700 | MinimalList attributesToGet; 701 | MinimalString tableName; 702 | ReturnConsumedCapacity returnConsumedCapacity; 703 | int limit; 704 | MinimalMap exclusiveStartKey; 705 | bool scanFilterBeenSet; 706 | bool selectBeenSet; 707 | bool totalSegmentsBeenSet; 708 | bool conditionalOperatorBeenSet; 709 | bool segmentBeenSet; 710 | bool attributesToGetBeenSet; 711 | bool tableNameBeenSet; 712 | bool returnConsumedCapacityBeenSet; 713 | bool limitBeenSet; 714 | bool exclusiveStartKeyBeenSet; 715 | void reset(); 716 | public: 717 | ScanInput(); 718 | bool requiredAreSet() const; 719 | MinimalString jsonSerialize() const; 720 | void setScanFilter(MinimalMap scanFilter); 721 | void setSelect(Select select); 722 | void setTotalSegments(int totalSegments); 723 | void setConditionalOperator(ConditionalOperator conditionalOperator); 724 | void setSegment(int segment); 725 | void setAttributesToGet(MinimalList attributesToGet); 726 | void setTableName(MinimalString tableName); 727 | void setReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity); 728 | void setLimit(int limit); 729 | void setExclusiveStartKey(MinimalMap exclusiveStartKey); 730 | MinimalMap getScanFilter() const; 731 | Select getSelect() const; 732 | int getTotalSegments() const; 733 | ConditionalOperator getConditionalOperator() const; 734 | int getSegment() const; 735 | MinimalList getAttributesToGet() const; 736 | MinimalString getTableName() const; 737 | ReturnConsumedCapacity getReturnConsumedCapacity() const; 738 | int getLimit() const; 739 | MinimalMap getExclusiveStartKey() const; 740 | }; 741 | 742 | /*

Represents the input of a ListTables operation.

*/ 743 | class ListTablesInput{ 744 | MinimalString exclusiveStartTableName; 745 | int limit; 746 | bool exclusiveStartTableNameBeenSet; 747 | bool limitBeenSet; 748 | void reset(); 749 | public: 750 | ListTablesInput(); 751 | bool requiredAreSet() const; 752 | MinimalString jsonSerialize() const; 753 | void setExclusiveStartTableName(MinimalString exclusiveStartTableName); 754 | void setLimit(int limit); 755 | MinimalString getExclusiveStartTableName() const; 756 | int getLimit() const; 757 | }; 758 | 759 | /*

Represents the output of a BatchWriteItem operation.

*/ 760 | class BatchWriteItemOutput{ 761 | MinimalMap > unprocessedItems; 762 | MinimalMap > itemCollectionMetrics; 763 | MinimalList consumedCapacity; 764 | bool unprocessedItemsBeenSet; 765 | bool itemCollectionMetricsBeenSet; 766 | bool consumedCapacityBeenSet; 767 | MinimalString errorType; 768 | MinimalString errorMessage; 769 | void reset(); 770 | public: 771 | BatchWriteItemOutput(); 772 | bool jsonDeserialize(MinimalString json); 773 | MinimalString getErrorType() const; 774 | MinimalString getErrorMessage() const; 775 | void setUnprocessedItems(MinimalMap > unprocessedItems); 776 | void setItemCollectionMetrics(MinimalMap > itemCollectionMetrics); 777 | void setConsumedCapacity(MinimalList consumedCapacity); 778 | MinimalMap > getUnprocessedItems() const; 779 | MinimalMap > getItemCollectionMetrics() const; 780 | MinimalList getConsumedCapacity() const; 781 | }; 782 | 783 | /*

Represents the input of a Query operation.

*/ 784 | class QueryInput{ 785 | bool scanIndexForward; 786 | Select select; 787 | bool consistentRead; 788 | ConditionalOperator conditionalOperator; 789 | MinimalMap queryFilter; 790 | MinimalList attributesToGet; 791 | MinimalMap keyConditions; 792 | MinimalString tableName; 793 | MinimalString indexName; 794 | ReturnConsumedCapacity returnConsumedCapacity; 795 | int limit; 796 | MinimalMap exclusiveStartKey; 797 | bool scanIndexForwardBeenSet; 798 | bool selectBeenSet; 799 | bool consistentReadBeenSet; 800 | bool conditionalOperatorBeenSet; 801 | bool queryFilterBeenSet; 802 | bool attributesToGetBeenSet; 803 | bool keyConditionsBeenSet; 804 | bool tableNameBeenSet; 805 | bool indexNameBeenSet; 806 | bool returnConsumedCapacityBeenSet; 807 | bool limitBeenSet; 808 | bool exclusiveStartKeyBeenSet; 809 | void reset(); 810 | public: 811 | QueryInput(); 812 | bool requiredAreSet() const; 813 | MinimalString jsonSerialize() const; 814 | void setScanIndexForward(bool scanIndexForward); 815 | void setSelect(Select select); 816 | void setConsistentRead(bool consistentRead); 817 | void setConditionalOperator(ConditionalOperator conditionalOperator); 818 | void setQueryFilter(MinimalMap queryFilter); 819 | void setAttributesToGet(MinimalList attributesToGet); 820 | void setKeyConditions(MinimalMap keyConditions); 821 | void setTableName(MinimalString tableName); 822 | void setIndexName(MinimalString indexName); 823 | void setReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity); 824 | void setLimit(int limit); 825 | void setExclusiveStartKey(MinimalMap exclusiveStartKey); 826 | bool getScanIndexForward() const; 827 | Select getSelect() const; 828 | bool getConsistentRead() const; 829 | ConditionalOperator getConditionalOperator() const; 830 | MinimalMap getQueryFilter() const; 831 | MinimalList getAttributesToGet() const; 832 | MinimalMap getKeyConditions() const; 833 | MinimalString getTableName() const; 834 | MinimalString getIndexName() const; 835 | ReturnConsumedCapacity getReturnConsumedCapacity() const; 836 | int getLimit() const; 837 | MinimalMap getExclusiveStartKey() const; 838 | }; 839 | 840 | /*

Represents the input of a BatchWriteItem operation.

*/ 841 | class BatchWriteItemInput{ 842 | ReturnItemCollectionMetrics returnItemCollectionMetrics; 843 | MinimalMap > requestItems; 844 | ReturnConsumedCapacity returnConsumedCapacity; 845 | bool returnItemCollectionMetricsBeenSet; 846 | bool requestItemsBeenSet; 847 | bool returnConsumedCapacityBeenSet; 848 | void reset(); 849 | public: 850 | BatchWriteItemInput(); 851 | bool requiredAreSet() const; 852 | MinimalString jsonSerialize() const; 853 | void setReturnItemCollectionMetrics(ReturnItemCollectionMetrics returnItemCollectionMetrics); 854 | void setRequestItems(MinimalMap > requestItems); 855 | void setReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity); 856 | ReturnItemCollectionMetrics getReturnItemCollectionMetrics() const; 857 | MinimalMap > getRequestItems() const; 858 | ReturnConsumedCapacity getReturnConsumedCapacity() const; 859 | }; 860 | 861 | /*

Represents the output of a Query operation.

*/ 862 | class QueryOutput{ 863 | MinimalMap lastEvaluatedKey; 864 | MinimalList > items; 865 | int count; 866 | int scannedCount; 867 | ConsumedCapacity consumedCapacity; 868 | bool lastEvaluatedKeyBeenSet; 869 | bool itemsBeenSet; 870 | bool countBeenSet; 871 | bool scannedCountBeenSet; 872 | bool consumedCapacityBeenSet; 873 | MinimalString errorType; 874 | MinimalString errorMessage; 875 | void reset(); 876 | public: 877 | QueryOutput(); 878 | bool jsonDeserialize(MinimalString json); 879 | MinimalString getErrorType() const; 880 | MinimalString getErrorMessage() const; 881 | void setLastEvaluatedKey(MinimalMap lastEvaluatedKey); 882 | void setItems(MinimalList > items); 883 | void setCount(int count); 884 | void setScannedCount(int scannedCount); 885 | void setConsumedCapacity(ConsumedCapacity consumedCapacity); 886 | MinimalMap getLastEvaluatedKey() const; 887 | MinimalList > getItems() const; 888 | int getCount() const; 889 | int getScannedCount() const; 890 | ConsumedCapacity getConsumedCapacity() const; 891 | }; 892 | 893 | /*

Represents the output of a DeleteItem operation.

*/ 894 | class DeleteItemOutput{ 895 | MinimalMap attributes; 896 | ItemCollectionMetrics itemCollectionMetrics; 897 | ConsumedCapacity consumedCapacity; 898 | bool attributesBeenSet; 899 | bool itemCollectionMetricsBeenSet; 900 | bool consumedCapacityBeenSet; 901 | MinimalString errorType; 902 | MinimalString errorMessage; 903 | void reset(); 904 | public: 905 | DeleteItemOutput(); 906 | bool jsonDeserialize(MinimalString json); 907 | MinimalString getErrorType() const; 908 | MinimalString getErrorMessage() const; 909 | void setAttributes(MinimalMap attributes); 910 | void setItemCollectionMetrics(ItemCollectionMetrics itemCollectionMetrics); 911 | void setConsumedCapacity(ConsumedCapacity consumedCapacity); 912 | MinimalMap getAttributes() const; 913 | ItemCollectionMetrics getItemCollectionMetrics() const; 914 | ConsumedCapacity getConsumedCapacity() const; 915 | }; 916 | 917 | /*

Represents the output of a BatchGetItem operation.

*/ 918 | class BatchGetItemOutput{ 919 | MinimalMap > > responses; 920 | MinimalMap unprocessedKeys; 921 | MinimalList consumedCapacity; 922 | bool responsesBeenSet; 923 | bool unprocessedKeysBeenSet; 924 | bool consumedCapacityBeenSet; 925 | MinimalString errorType; 926 | MinimalString errorMessage; 927 | void reset(); 928 | public: 929 | BatchGetItemOutput(); 930 | bool jsonDeserialize(MinimalString json); 931 | MinimalString getErrorType() const; 932 | MinimalString getErrorMessage() const; 933 | void setResponses(MinimalMap > > responses); 934 | void setUnprocessedKeys(MinimalMap unprocessedKeys); 935 | void setConsumedCapacity(MinimalList consumedCapacity); 936 | MinimalMap > > getResponses() const; 937 | MinimalMap getUnprocessedKeys() const; 938 | MinimalList getConsumedCapacity() const; 939 | }; 940 | 941 | /*

Represents the input of a CreateTable operation.

*/ 942 | class CreateTableInput{ 943 | ProvisionedThroughput provisionedThroughput; 944 | MinimalList globalSecondaryIndexes; 945 | MinimalString tableName; 946 | MinimalList localSecondaryIndexes; 947 | MinimalList keySchema; 948 | MinimalList attributeDefinitions; 949 | bool provisionedThroughputBeenSet; 950 | bool globalSecondaryIndexesBeenSet; 951 | bool tableNameBeenSet; 952 | bool localSecondaryIndexesBeenSet; 953 | bool keySchemaBeenSet; 954 | bool attributeDefinitionsBeenSet; 955 | void reset(); 956 | public: 957 | CreateTableInput(); 958 | bool requiredAreSet() const; 959 | MinimalString jsonSerialize() const; 960 | void setProvisionedThroughput(ProvisionedThroughput provisionedThroughput); 961 | void setGlobalSecondaryIndexes(MinimalList globalSecondaryIndexes); 962 | void setTableName(MinimalString tableName); 963 | void setLocalSecondaryIndexes(MinimalList localSecondaryIndexes); 964 | void setKeySchema(MinimalList keySchema); 965 | void setAttributeDefinitions(MinimalList attributeDefinitions); 966 | ProvisionedThroughput getProvisionedThroughput() const; 967 | MinimalList getGlobalSecondaryIndexes() const; 968 | MinimalString getTableName() const; 969 | MinimalList getLocalSecondaryIndexes() const; 970 | MinimalList getKeySchema() const; 971 | MinimalList getAttributeDefinitions() const; 972 | }; 973 | 974 | /*

Represents the input of a DescribeTable operation.

*/ 975 | class DescribeTableInput{ 976 | MinimalString tableName; 977 | bool tableNameBeenSet; 978 | void reset(); 979 | public: 980 | DescribeTableInput(); 981 | bool requiredAreSet() const; 982 | MinimalString jsonSerialize() const; 983 | void setTableName(MinimalString tableName); 984 | MinimalString getTableName() const; 985 | }; 986 | 987 | /*

Represents the input of a PutItem operation.

*/ 988 | class PutItemInput{ 989 | ReturnItemCollectionMetrics returnItemCollectionMetrics; 990 | ReturnValue returnValues; 991 | MinimalMap item; 992 | ConditionalOperator conditionalOperator; 993 | MinimalMap expected; 994 | MinimalString tableName; 995 | ReturnConsumedCapacity returnConsumedCapacity; 996 | bool returnItemCollectionMetricsBeenSet; 997 | bool returnValuesBeenSet; 998 | bool itemBeenSet; 999 | bool conditionalOperatorBeenSet; 1000 | bool expectedBeenSet; 1001 | bool tableNameBeenSet; 1002 | bool returnConsumedCapacityBeenSet; 1003 | void reset(); 1004 | public: 1005 | PutItemInput(); 1006 | bool requiredAreSet() const; 1007 | MinimalString jsonSerialize() const; 1008 | void setReturnItemCollectionMetrics(ReturnItemCollectionMetrics returnItemCollectionMetrics); 1009 | void setReturnValues(ReturnValue returnValues); 1010 | void setItem(MinimalMap item); 1011 | void setConditionalOperator(ConditionalOperator conditionalOperator); 1012 | void setExpected(MinimalMap expected); 1013 | void setTableName(MinimalString tableName); 1014 | void setReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity); 1015 | ReturnItemCollectionMetrics getReturnItemCollectionMetrics() const; 1016 | ReturnValue getReturnValues() const; 1017 | MinimalMap getItem() const; 1018 | ConditionalOperator getConditionalOperator() const; 1019 | MinimalMap getExpected() const; 1020 | MinimalString getTableName() const; 1021 | ReturnConsumedCapacity getReturnConsumedCapacity() const; 1022 | }; 1023 | 1024 | /*

Represents the output of a GetItem operation.

*/ 1025 | class GetItemOutput{ 1026 | MinimalMap item; 1027 | ConsumedCapacity consumedCapacity; 1028 | bool itemBeenSet; 1029 | bool consumedCapacityBeenSet; 1030 | MinimalString errorType; 1031 | MinimalString errorMessage; 1032 | void reset(); 1033 | public: 1034 | GetItemOutput(); 1035 | bool jsonDeserialize(MinimalString json); 1036 | MinimalString getErrorType() const; 1037 | MinimalString getErrorMessage() const; 1038 | void setItem(MinimalMap item); 1039 | void setConsumedCapacity(ConsumedCapacity consumedCapacity); 1040 | MinimalMap getItem() const; 1041 | ConsumedCapacity getConsumedCapacity() const; 1042 | }; 1043 | 1044 | /*

Represents the input of a DeleteTable operation.

*/ 1045 | class DeleteTableInput{ 1046 | MinimalString tableName; 1047 | bool tableNameBeenSet; 1048 | void reset(); 1049 | public: 1050 | DeleteTableInput(); 1051 | bool requiredAreSet() const; 1052 | MinimalString jsonSerialize() const; 1053 | void setTableName(MinimalString tableName); 1054 | MinimalString getTableName() const; 1055 | }; 1056 | 1057 | /*

Represents the output of a DescribeTable operation.

*/ 1058 | class DescribeTableOutput{ 1059 | TableDescription table; 1060 | bool tableBeenSet; 1061 | MinimalString errorType; 1062 | MinimalString errorMessage; 1063 | void reset(); 1064 | public: 1065 | DescribeTableOutput(); 1066 | bool jsonDeserialize(MinimalString json); 1067 | MinimalString getErrorType() const; 1068 | MinimalString getErrorMessage() const; 1069 | void setTable(TableDescription table); 1070 | TableDescription getTable() const; 1071 | }; 1072 | 1073 | /*

Represents the output of a Scan operation.

*/ 1074 | class ScanOutput{ 1075 | MinimalMap lastEvaluatedKey; 1076 | MinimalList > items; 1077 | int count; 1078 | int scannedCount; 1079 | ConsumedCapacity consumedCapacity; 1080 | bool lastEvaluatedKeyBeenSet; 1081 | bool itemsBeenSet; 1082 | bool countBeenSet; 1083 | bool scannedCountBeenSet; 1084 | bool consumedCapacityBeenSet; 1085 | MinimalString errorType; 1086 | MinimalString errorMessage; 1087 | void reset(); 1088 | public: 1089 | ScanOutput(); 1090 | bool jsonDeserialize(MinimalString json); 1091 | MinimalString getErrorType() const; 1092 | MinimalString getErrorMessage() const; 1093 | void setLastEvaluatedKey(MinimalMap lastEvaluatedKey); 1094 | void setItems(MinimalList > items); 1095 | void setCount(int count); 1096 | void setScannedCount(int scannedCount); 1097 | void setConsumedCapacity(ConsumedCapacity consumedCapacity); 1098 | MinimalMap getLastEvaluatedKey() const; 1099 | MinimalList > getItems() const; 1100 | int getCount() const; 1101 | int getScannedCount() const; 1102 | ConsumedCapacity getConsumedCapacity() const; 1103 | }; 1104 | 1105 | /*

Represents the input of a BatchGetItem operation.

*/ 1106 | class BatchGetItemInput{ 1107 | MinimalMap requestItems; 1108 | ReturnConsumedCapacity returnConsumedCapacity; 1109 | bool requestItemsBeenSet; 1110 | bool returnConsumedCapacityBeenSet; 1111 | void reset(); 1112 | public: 1113 | BatchGetItemInput(); 1114 | bool requiredAreSet() const; 1115 | MinimalString jsonSerialize() const; 1116 | void setRequestItems(MinimalMap requestItems); 1117 | void setReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity); 1118 | MinimalMap getRequestItems() const; 1119 | ReturnConsumedCapacity getReturnConsumedCapacity() const; 1120 | }; 1121 | 1122 | /*

Represents the input of an UpdateItem operation.

*/ 1123 | class UpdateItemInput{ 1124 | ReturnItemCollectionMetrics returnItemCollectionMetrics; 1125 | ReturnValue returnValues; 1126 | MinimalMap key; 1127 | ConditionalOperator conditionalOperator; 1128 | MinimalMap expected; 1129 | MinimalString tableName; 1130 | MinimalMap attributeUpdates; 1131 | ReturnConsumedCapacity returnConsumedCapacity; 1132 | bool returnItemCollectionMetricsBeenSet; 1133 | bool returnValuesBeenSet; 1134 | bool keyBeenSet; 1135 | bool conditionalOperatorBeenSet; 1136 | bool expectedBeenSet; 1137 | bool tableNameBeenSet; 1138 | bool attributeUpdatesBeenSet; 1139 | bool returnConsumedCapacityBeenSet; 1140 | void reset(); 1141 | public: 1142 | UpdateItemInput(); 1143 | bool requiredAreSet() const; 1144 | MinimalString jsonSerialize() const; 1145 | void setReturnItemCollectionMetrics(ReturnItemCollectionMetrics returnItemCollectionMetrics); 1146 | void setReturnValues(ReturnValue returnValues); 1147 | void setKey(MinimalMap key); 1148 | void setConditionalOperator(ConditionalOperator conditionalOperator); 1149 | void setExpected(MinimalMap expected); 1150 | void setTableName(MinimalString tableName); 1151 | void setAttributeUpdates(MinimalMap attributeUpdates); 1152 | void setReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity); 1153 | ReturnItemCollectionMetrics getReturnItemCollectionMetrics() const; 1154 | ReturnValue getReturnValues() const; 1155 | MinimalMap getKey() const; 1156 | ConditionalOperator getConditionalOperator() const; 1157 | MinimalMap getExpected() const; 1158 | MinimalString getTableName() const; 1159 | MinimalMap getAttributeUpdates() const; 1160 | ReturnConsumedCapacity getReturnConsumedCapacity() const; 1161 | }; 1162 | 1163 | /*

Represents the output of a CreateTable operation.

*/ 1164 | class CreateTableOutput{ 1165 | TableDescription tableDescription; 1166 | bool tableDescriptionBeenSet; 1167 | MinimalString errorType; 1168 | MinimalString errorMessage; 1169 | void reset(); 1170 | public: 1171 | CreateTableOutput(); 1172 | bool jsonDeserialize(MinimalString json); 1173 | MinimalString getErrorType() const; 1174 | MinimalString getErrorMessage() const; 1175 | void setTableDescription(TableDescription tableDescription); 1176 | TableDescription getTableDescription() const; 1177 | }; 1178 | 1179 | /*

Represents the input of an UpdateTable operation.

*/ 1180 | class UpdateTableInput{ 1181 | ProvisionedThroughput provisionedThroughput; 1182 | MinimalList globalSecondaryIndexUpdates; 1183 | MinimalString tableName; 1184 | bool provisionedThroughputBeenSet; 1185 | bool globalSecondaryIndexUpdatesBeenSet; 1186 | bool tableNameBeenSet; 1187 | void reset(); 1188 | public: 1189 | UpdateTableInput(); 1190 | bool requiredAreSet() const; 1191 | MinimalString jsonSerialize() const; 1192 | void setProvisionedThroughput(ProvisionedThroughput provisionedThroughput); 1193 | void setGlobalSecondaryIndexUpdates(MinimalList globalSecondaryIndexUpdates); 1194 | void setTableName(MinimalString tableName); 1195 | ProvisionedThroughput getProvisionedThroughput() const; 1196 | MinimalList getGlobalSecondaryIndexUpdates() const; 1197 | MinimalString getTableName() const; 1198 | }; 1199 | 1200 | /*

Represents the input of a GetItem operation.

*/ 1201 | class GetItemInput{ 1202 | MinimalMap key; 1203 | bool consistentRead; 1204 | MinimalList attributesToGet; 1205 | MinimalString tableName; 1206 | ReturnConsumedCapacity returnConsumedCapacity; 1207 | bool keyBeenSet; 1208 | bool consistentReadBeenSet; 1209 | bool attributesToGetBeenSet; 1210 | bool tableNameBeenSet; 1211 | bool returnConsumedCapacityBeenSet; 1212 | void reset(); 1213 | public: 1214 | GetItemInput(); 1215 | bool requiredAreSet() const; 1216 | MinimalString jsonSerialize() const; 1217 | void setKey(MinimalMap key); 1218 | void setConsistentRead(bool consistentRead); 1219 | void setAttributesToGet(MinimalList attributesToGet); 1220 | void setTableName(MinimalString tableName); 1221 | void setReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity); 1222 | MinimalMap getKey() const; 1223 | bool getConsistentRead() const; 1224 | MinimalList getAttributesToGet() const; 1225 | MinimalString getTableName() const; 1226 | ReturnConsumedCapacity getReturnConsumedCapacity() const; 1227 | }; 1228 | 1229 | /*

Represents the output of a DeleteTable operation.

*/ 1230 | class DeleteTableOutput{ 1231 | TableDescription tableDescription; 1232 | bool tableDescriptionBeenSet; 1233 | MinimalString errorType; 1234 | MinimalString errorMessage; 1235 | void reset(); 1236 | public: 1237 | DeleteTableOutput(); 1238 | bool jsonDeserialize(MinimalString json); 1239 | MinimalString getErrorType() const; 1240 | MinimalString getErrorMessage() const; 1241 | void setTableDescription(TableDescription tableDescription); 1242 | TableDescription getTableDescription() const; 1243 | }; 1244 | 1245 | /*

Represents the output of a PutItem operation.

*/ 1246 | class PutItemOutput{ 1247 | MinimalMap attributes; 1248 | ItemCollectionMetrics itemCollectionMetrics; 1249 | ConsumedCapacity consumedCapacity; 1250 | bool attributesBeenSet; 1251 | bool itemCollectionMetricsBeenSet; 1252 | bool consumedCapacityBeenSet; 1253 | MinimalString errorType; 1254 | MinimalString errorMessage; 1255 | void reset(); 1256 | public: 1257 | PutItemOutput(); 1258 | bool jsonDeserialize(MinimalString json); 1259 | MinimalString getErrorType() const; 1260 | MinimalString getErrorMessage() const; 1261 | void setAttributes(MinimalMap attributes); 1262 | void setItemCollectionMetrics(ItemCollectionMetrics itemCollectionMetrics); 1263 | void setConsumedCapacity(ConsumedCapacity consumedCapacity); 1264 | MinimalMap getAttributes() const; 1265 | ItemCollectionMetrics getItemCollectionMetrics() const; 1266 | ConsumedCapacity getConsumedCapacity() const; 1267 | }; 1268 | 1269 | class AmazonDynamoDBClient : public AWSClient { 1270 | public: 1271 | char szR[1024]; 1272 | char szResponse[1024]; 1273 | AmazonDynamoDBClient(); 1274 | /*

The BatchGetItem operation returns the attributes of one or more items from one or more tables. You identify requested items by primary key.

A single operation can retrieve up to 1 MB of data, which can contain as many as 100 items. BatchGetItem will return a partial result if the response size limit is exceeded, the table's provisioned throughput is exceeded, or an internal processing failure occurs. If a partial result is returned, the operation returns a value for UnprocessedKeys. You can use this value to retry the operation starting with the next item to get.

For example, if you ask to retrieve 100 items, but each individual item is 50 KB in size, the system returns 20 items (1 MB) and an appropriate UnprocessedKeys value so you can get the next page of results. If desired, your application can include its own logic to assemble the pages of results into one dataset.

If none of the items can be processed due to insufficient provisioned throughput on all of the tables in the request, then BatchGetItem will throw a ProvisionedThroughputExceededException. If at least one of the items is successfully processed, then BatchGetItem completes successfully, while returning the keys of the unread items in UnprocessedKeys.

If DynamoDB returns any unprocessed items, you should retry the batch operation on those items. However, we strongly recommend that you use an exponential backoff algorithm. If you retry the batch operation immediately, the underlying read or write requests can still fail due to throttling on the individual tables. If you delay the batch operation using exponential backoff, the individual requests in the batch are much more likely to succeed.

For more information, go to Batch Operations and Error Handling in the Amazon DynamoDB Developer Guide.

By default, BatchGetItem performs eventually consistent reads on every table in the request. If you want strongly consistent reads instead, you can set ConsistentRead to true for any or all tables.

In order to minimize response latency, BatchGetItem retrieves items in parallel.

When designing your application, keep in mind that DynamoDB does not return attributes in any particular order. To help parse the response by item, include the primary key values for the items in your request in the AttributesToGet parameter.

If a requested item does not exist, it is not returned in the result. Requests for nonexistent items consume the minimum read capacity units according to the type of read. For more information, see Capacity Units Calculations in the Amazon DynamoDB Developer Guide.

*/ 1275 | BatchGetItemOutput batchGetItem(BatchGetItemInput batchGetItemInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1276 | /*

The BatchWriteItem operation puts or deletes multiple items in one or more tables. A single call to BatchWriteItem can write up to 1 MB of data, which can comprise as many as 25 put or delete requests. Individual items to be written can be as large as 64 KB.

The individual PutItem and DeleteItem operations specified in BatchWriteItem are atomic; however BatchWriteItem as a whole is not. If any requested operations fail because the table's provisioned throughput is exceeded or an internal processing failure occurs, the failed operations are returned in the UnprocessedItems response parameter. You can investigate and optionally resend the requests. Typically, you would call BatchWriteItem in a loop. Each iteration would check for unprocessed items and submit a new BatchWriteItem request with those unprocessed items until all items have been processed.

Note that if none of the items can be processed due to insufficient provisioned throughput on all of the tables in the request, then BatchGetItem will throw a ProvisionedThroughputExceededException.

If DynamoDB returns any unprocessed items, you should retry the batch operation on those items. However, we strongly recommend that you use an exponential backoff algorithm. If you retry the batch operation immediately, the underlying read or write requests can still fail due to throttling on the individual tables. If you delay the batch operation using exponential backoff, the individual requests in the batch are much more likely to succeed.

For more information, go to Batch Operations and Error Handling in the Amazon DynamoDB Developer Guide.

With BatchWriteItem, you can efficiently write or delete large amounts of data, such as from Amazon Elastic MapReduce (EMR), or copy data from another database into DynamoDB. In order to improve performance with these large-scale operations, BatchWriteItem does not behave in the same way as individual PutItem and DeleteItem calls would For example, you cannot specify conditions on individual put and delete requests, and BatchWriteItem does not return deleted items in the response.

If you use a programming language that supports concurrency, such as Java, you can use threads to write items in parallel. Your application must include the necessary logic to manage the threads. With languages that don't support threading, such as PHP, you must update or delete the specified items one at a time. In both situations, BatchWriteItem provides an alternative where the API performs the specified put and delete operations in parallel, giving you the power of the thread pool approach without having to introduce complexity into your application.

Parallel processing reduces latency, but each specified put and delete request consumes the same number of write capacity units whether it is processed in parallel or not. Delete operations on nonexistent items consume one write capacity unit.

If one or more of the following is true, DynamoDB rejects the entire batch write operation:

  • One or more tables specified in the BatchWriteItem request does not exist.

  • Primary key attributes specified on an item in the request do not match those in the corresponding table's primary key schema.

  • You try to perform multiple operations on the same item in the same BatchWriteItem request. For example, you cannot put and delete the same item in the same BatchWriteItem request.

  • The total request size exceeds 1 MB.

  • Any individual item in a batch exceeds 64 KB.

*/ 1277 | BatchWriteItemOutput batchWriteItem(BatchWriteItemInput batchWriteItemInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1278 | /*

The CreateTable operation adds a new table to your account. In an AWS account, table names must be unique within each region. That is, you can have two tables with same name if you create the tables in different regions.

CreateTable is an asynchronous operation. Upon receiving a CreateTable request, DynamoDB immediately returns a response with a TableStatus of CREATING. After the table is created, DynamoDB sets the TableStatus to ACTIVE. You can perform read and write operations only on an ACTIVE table.

If you want to create multiple tables with secondary indexes on them, you must create them sequentially. Only one table with secondary indexes can be in the CREATING state at any given time.

You can use the DescribeTable API to check the table status.

*/ 1279 | CreateTableOutput createTable(CreateTableInput createTableInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1280 | /*

Deletes a single item in a table by primary key. You can perform a conditional delete operation that deletes the item if it exists, or if it has an expected attribute value.

In addition to deleting an item, you can also return the item's attribute values in the same operation, using the ReturnValues parameter.

Unless you specify conditions, the DeleteItem is an idempotent operation; running it multiple times on the same item or attribute does not result in an error response.

Conditional deletes are useful for only deleting items if specific conditions are met. If those conditions are met, DynamoDB performs the delete. Otherwise, the item is not deleted.

*/ 1281 | DeleteItemOutput deleteItem(DeleteItemInput deleteItemInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1282 | /*

The DeleteTable operation deletes a table and all of its items. After a DeleteTable request, the specified table is in the DELETING state until DynamoDB completes the deletion. If the table is in the ACTIVE state, you can delete it. If a table is in CREATING or UPDATING states, then DynamoDB returns a ResourceInUseException. If the specified table does not exist, DynamoDB returns a ResourceNotFoundException. If table is already in the DELETING state, no error is returned.

When you delete a table, any indexes on that table are also deleted.

Use the DescribeTable API to check the status of the table.

*/ 1283 | DeleteTableOutput deleteTable(DeleteTableInput deleteTableInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1284 | /*

Returns information about the table, including the current status of the table, when it was created, the primary key schema, and any indexes on the table.

*/ 1285 | DescribeTableOutput describeTable(DescribeTableInput describeTableInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1286 | /*

The GetItem operation returns a set of attributes for the item with the given primary key. If there is no matching item, GetItem does not return any data.

GetItem provides an eventually consistent read by default. If your application requires a strongly consistent read, set ConsistentRead to true. Although a strongly consistent read might take more time than an eventually consistent read, it always returns the last updated value.

*/ 1287 | GetItemOutput getItem(GetItemInput getItemInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1288 | /*

Returns an array of table names associated with the current account and endpoint. The output from ListTables is paginated, with each page returning a maximum of 100 table names.

*/ 1289 | ListTablesOutput listTables(ListTablesInput listTablesInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1290 | /*

Creates a new item, or replaces an old item with a new item. If an item already exists in the specified table with the same primary key, the new item completely replaces the existing item. You can perform a conditional put (insert a new item if one with the specified primary key doesn't exist), or replace an existing item if it has certain attribute values.

In addition to putting an item, you can also return the item's attribute values in the same operation, using the ReturnValues parameter.

When you add an item, the primary key attribute(s) are the only required attributes. Attribute values cannot be null. String and binary type attributes must have lengths greater than zero. Set type attributes cannot be empty. Requests with empty values will be rejected with a ValidationException.

You can request that PutItem return either a copy of the old item (before the update) or a copy of the new item (after the update). For more information, see the ReturnValues description.

For more information about using this API, see Working with Items in the Amazon DynamoDB Developer Guide.

*/ 1291 | PutItemOutput putItem(PutItemInput putItemInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1292 | /*

A Query operation directly accesses items from a table using the table primary key, or from an index using the index key. You must provide a specific hash key value. You can narrow the scope of the query by using comparison operators on the range key value, or on the index key. You can use the ScanIndexForward parameter to get results in forward or reverse order, by range key or by index key.

Queries that do not return results consume the minimum read capacity units according to the type of read.

If the total number of items meeting the query criteria exceeds the result set size limit of 1 MB, the query stops and results are returned to the user with a LastEvaluatedKey to continue the query in a subsequent operation. Unlike a Scan operation, a Query operation never returns an empty result set and a LastEvaluatedKey. The LastEvaluatedKey is only provided if the results exceed 1 MB, or if you have used Limit.

You can query a table, a local secondary index, or a global secondary index. For a query on a table or on a local secondary index, you can set ConsistentRead to true and obtain a strongly consistent result. Global secondary indexes support eventually consistent reads only, so do not specify ConsistentRead when querying a global secondary index.

*/ 1293 | QueryOutput query(QueryInput queryInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1294 | /*

The Scan operation returns one or more items and item attributes by accessing every item in the table. To have DynamoDB return fewer items, you can provide a ScanFilter.

If the total number of scanned items exceeds the maximum data set size limit of 1 MB, the scan stops and results are returned to the user with a LastEvaluatedKey to continue the scan in a subsequent operation. The results also include the number of items exceeding the limit. A scan can result in no table data meeting the filter criteria.

The result set is eventually consistent.

By default, Scan operations proceed sequentially; however, for faster performance on large tables, applications can request a parallel Scan by specifying the Segment and TotalSegments parameters. For more information, see Parallel Scan in the Amazon DynamoDB Developer Guide.

*/ 1295 | ScanOutput scan(ScanInput scanInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1296 | /*

Edits an existing item's attributes, or inserts a new item if it does not already exist. You can put, delete, or add attribute values. You can also perform a conditional update (insert a new attribute name-value pair if it doesn't exist, or replace an existing name-value pair if it has certain expected attribute values).

In addition to updating an item, you can also return the item's attribute values in the same operation, using the ReturnValues parameter.

*/ 1297 | UpdateItemOutput updateItem(UpdateItemInput updateItemInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1298 | /*

Updates the provisioned throughput for the given table. Setting the throughput for a table helps you manage performance and is part of the provisioned throughput feature of DynamoDB.

The provisioned throughput values can be upgraded or downgraded based on the maximums and minimums listed in the Limits section in the Amazon DynamoDB Developer Guide.

The table must be in the ACTIVE state for this operation to succeed. UpdateTable is an asynchronous operation; while executing the operation, the table is in the UPDATING state. While the table is in the UPDATING state, the table still has the provisioned throughput from before the call. The new provisioned throughput setting is in effect only when the table returns to the ACTIVE state after the UpdateTable operation.

You cannot add, modify or delete indexes using UpdateTable. Indexes can only be defined at table creation time.

*/ 1299 | UpdateTableOutput updateTable(UpdateTableInput updateTableInput, ActionError& actionError, bool retry = true, int* httpStatusCode = NULL); 1300 | }; 1301 | 1302 | #endif /* AMAZONDYNAMODBCLIENT_H_ */ 1303 | -------------------------------------------------------------------------------- /AWS/AmazonSNSClient.cpp: -------------------------------------------------------------------------------- 1 | #include "AmazonSNSClient.h" 2 | #include "AWSFoundationalTypes.h" 3 | #include 4 | #include "Utils.h" 5 | 6 | static const char* SERVICE = "sns"; 7 | static const char* FORM_TYPE = "application/x-www-form-urlencoded"; 8 | static const char* PAYLOAD_TEMPLATE = "Action=Publish&TargetArn=%s&Message=%s&Version=2010-03-31\n"; 9 | int PAYLOAD_TEMPLATE_LENGTH = 54; 10 | int MESSAGEID_BUFFER_LENGTH = 37; 11 | int EXTRACTED_TIMESTAMP_BUFFER_LENGTH = 17; 12 | int FORMATTED_TIMESTAMP_BUFFER_LENGTH = 15; 13 | 14 | PublishInput::PublishInput() { 15 | reset(); 16 | } 17 | 18 | void PublishInput::reset() { 19 | targetArnBeenSet = false; 20 | messageBeenSet = false; 21 | } 22 | 23 | bool PublishInput::requiredAreSet() const { 24 | return targetArnBeenSet && messageBeenSet; 25 | } 26 | 27 | void PublishInput::setTargetArn(MinimalString targetArn) { 28 | targetArnBeenSet = true; 29 | this->targetArn = targetArn; 30 | } 31 | 32 | void PublishInput::setMessage(MinimalString message) { 33 | messageBeenSet = true; 34 | this->message = message; 35 | } 36 | 37 | MinimalString PublishInput::getTargetArn() const { 38 | return this->targetArn; 39 | } 40 | 41 | MinimalString PublishInput::getMessage() const { 42 | return this->message; 43 | } 44 | 45 | MinimalString PublishInput::serialize() const { 46 | char* payload = new char[PAYLOAD_TEMPLATE_LENGTH + message.length() + targetArn.length() + 1](); 47 | 48 | sprintf(payload, PAYLOAD_TEMPLATE, targetArn.getCStr(), message.getCStr()); 49 | 50 | return MinimalString(payload); 51 | } 52 | 53 | PublishOutput::PublishOutput() { 54 | reset(); 55 | } 56 | 57 | void PublishOutput::reset() { 58 | messageIdBeenSet = false; 59 | 60 | errorType = MinimalString(); 61 | errorMessage = MinimalString(); 62 | } 63 | 64 | void PublishOutput::setMessageId(MinimalString messageId) { 65 | messageIdBeenSet = true; 66 | this->messageId = messageId; 67 | } 68 | 69 | MinimalString PublishOutput::getMessageId() const { 70 | return this->messageId; 71 | } 72 | 73 | MinimalString PublishOutput::getErrorType() const { 74 | return errorType; 75 | } 76 | 77 | MinimalString PublishOutput::getErrorMessage() const { 78 | return errorMessage; 79 | } 80 | 81 | AmazonSNSClient::AmazonSNSClient() : AWSClient2() { 82 | awsService = SERVICE; 83 | } 84 | 85 | PublishOutput AmazonSNSClient::publish(PublishInput publishInput, ActionError& actionError) { 86 | actionError = NONE_ACTIONERROR; 87 | 88 | PublishOutput publishOutput; 89 | 90 | if (!publishInput.requiredAreSet()) { 91 | actionError = MISSING_REQUIRED_ARGS_ACTIONERROR; 92 | return publishOutput; 93 | } 94 | 95 | contentType = FORM_TYPE; 96 | MinimalString payload = publishInput.serialize(); 97 | 98 | char* request = createRequest(payload); 99 | char* response = sendData(request); 100 | delete[] request; 101 | 102 | if (response == NULL) { 103 | actionError = CONNECTION_ACTIONERROR; 104 | return publishOutput; 105 | } 106 | 107 | int httpStatusCode = findHttpStatusCode(response); 108 | 109 | if (httpStatusCode == 200) { 110 | char* msgidIdx = strstr(response, ""); 111 | int msgidPos = msgidIdx - response; 112 | 113 | char* msgid = new char[MESSAGEID_BUFFER_LENGTH](); 114 | strncpy(msgid, response + msgidPos + 11, MESSAGEID_BUFFER_LENGTH - 1); 115 | msgid[37] = '\0'; 116 | 117 | publishOutput.setMessageId(msgid); 118 | return publishOutput; 119 | } 120 | 121 | if (httpStatusCode == 403) { 122 | char* ts = strstr(response, "earlier than "); 123 | int pos = ts - response; 124 | 125 | char* newts = new char[EXTRACTED_TIMESTAMP_BUFFER_LENGTH](); 126 | strncpy(newts, response + pos + 31, EXTRACTED_TIMESTAMP_BUFFER_LENGTH - 1); 127 | newts[16] = '\0'; 128 | 129 | char* time = new char[FORMATTED_TIMESTAMP_BUFFER_LENGTH](); 130 | sprintf(time, "%.8s%.6s", newts, newts + 9); 131 | dateTimeProvider->sync(time); 132 | } 133 | 134 | return publishOutput; 135 | } 136 | -------------------------------------------------------------------------------- /AWS/AmazonSNSClient.h: -------------------------------------------------------------------------------- 1 | #ifndef AMAZONSNSCLIENT_H_ 2 | #define AMAZONSNSCLIENT_H_ 3 | #include "AWSFoundationalTypes.h" 4 | #include "AWSClient2.h" 5 | 6 | class PublishInput { 7 | MinimalString targetArn; 8 | MinimalString message; 9 | bool targetArnBeenSet; 10 | bool messageBeenSet; 11 | void reset(); 12 | public: 13 | PublishInput(); 14 | bool requiredAreSet() const; 15 | void setMessage(MinimalString message); 16 | void setTargetArn(MinimalString targetArn); 17 | MinimalString getMessage() const; 18 | MinimalString getTargetArn() const; 19 | MinimalString serialize() const; 20 | }; 21 | 22 | class PublishOutput { 23 | MinimalString messageId; 24 | bool messageIdBeenSet; 25 | MinimalString errorType; 26 | MinimalString errorMessage; 27 | void reset(); 28 | public: 29 | PublishOutput(); 30 | MinimalString getErrorType() const; 31 | MinimalString getErrorMessage() const; 32 | void setMessageId(MinimalString messageId); 33 | MinimalString getMessageId() const; 34 | }; 35 | 36 | class AmazonSNSClient : public AWSClient2 { 37 | public: 38 | AmazonSNSClient(); 39 | PublishOutput publish(PublishInput input, ActionError& actionError); 40 | }; 41 | 42 | #endif /* AMAZONSNSCLIENT_H_ */ 43 | -------------------------------------------------------------------------------- /AWS/DeviceIndependentInterfaces.cpp: -------------------------------------------------------------------------------- 1 | #include "DeviceIndependentInterfaces.h" 2 | 3 | IHttpClient::~IHttpClient() { 4 | } 5 | IDateTimeProvider::~IDateTimeProvider() { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /AWS/DeviceIndependentInterfaces.h: -------------------------------------------------------------------------------- 1 | #ifndef AWSDEVICEINDEPENDENTINTERFACES_H_ 2 | #define AWSDEVICEINDEPENDENTINTERFACES_H_ 3 | 4 | /* HTTPClient Interface. Wraps the functionality of the existing TCPClient, and 5 | * EthernetClient for Spark Core and Intel Galileo Respectively. */ 6 | class IHttpClient { 7 | public: 8 | virtual ~IHttpClient(); 9 | /* Send http request and return the response. */ 10 | virtual char* send(const char *request, const char* serverUrl, 11 | int port) = 0; 12 | /* Returns true if the client uses a curl command, false if the client uses 13 | * raw http/https. */ 14 | virtual bool usesCurl(void) = 0; 15 | }; 16 | 17 | /* Interface for setting and retrieving the current time. Required for sigv4 18 | * signing. */ 19 | class IDateTimeProvider { 20 | public: 21 | virtual ~IDateTimeProvider(); 22 | /* Retrieve the current GMT date and time in yyyyMMddHHmmss format. */ 23 | virtual const char* getDateTime(void) = 0; 24 | /* Return true if the sync function requires the current time as in 25 | * argument. */ 26 | virtual bool syncTakesArg(void) = 0; 27 | /* Called if AWS Service reports in accurate time. Sets the provider to 28 | * current time. If syncTakesArg() returns true, this argument takes the 29 | * current GMT date and time in yyyyMMddHHmmss format. Else, the nput value 30 | * is ignored and may be null. */ 31 | virtual void sync(const char* dateTime) = 0; 32 | }; 33 | 34 | #endif /* AWSDEVICEINDEPENDENTINTERFACES_H_ */ 35 | -------------------------------------------------------------------------------- /AWS/Esp8266AWSImplementations.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | /* application.h is Esp8266's standard library. Defines the Arduino String 3 | * object, the Arduino delay() procedure, and the Esp8266 TCPClient. */ 4 | //#include 5 | #include "Esp8266AWSImplementations.h" 6 | #include "DeviceIndependentInterfaces.h" 7 | #include 8 | 9 | int delayTime = 500; 10 | char* updateCurTime(void); 11 | //char* updateCurTime2(WiFiClient client2); 12 | 13 | Esp8266HttpClient::Esp8266HttpClient() { 14 | } 15 | 16 | char* Esp8266HttpClient::send(const char* request, const char* serverUrl, 17 | int port) { 18 | /* Arduino String to build the response with. */ 19 | String responseBuilder = ""; 20 | if (client.connect(serverUrl, port)) { 21 | /* Send the requests */ 22 | client.println(request); 23 | client.println(); 24 | /* Read the request into responseBuilder. */ 25 | delay(delayTime); 26 | while (client.available()) { 27 | char c = client.read(); 28 | responseBuilder.concat(c); 29 | } 30 | client.stop(); 31 | } else { 32 | client.stop(); 33 | /* Error connecting. */ 34 | return 0; 35 | } 36 | /* Copy responseBuilder into char* */ 37 | int len = responseBuilder.length(); 38 | char* response = new char[len + 1](); 39 | responseBuilder.toCharArray(response, len + 1); 40 | return response; 41 | return 0; 42 | } 43 | 44 | bool Esp8266HttpClient::usesCurl() { 45 | /* Does not use curl command. */ 46 | return false; 47 | } 48 | 49 | Esp8266DateTimeProvider::Esp8266DateTimeProvider() { 50 | /* No need to sync, spark sychronizes time on startup. */ 51 | //strcpy(dateTime, updateCurTime2(client2)); 52 | } 53 | 54 | const char* Esp8266DateTimeProvider::getDateTime() { 55 | return updateCurTime(); 56 | } 57 | bool Esp8266DateTimeProvider::syncTakesArg(void) { 58 | return true; 59 | } 60 | 61 | void Esp8266DateTimeProvider::sync(const char* dateTime) { 62 | /* Use Esp8266's servers to synchronize current time. */ 63 | //Esp8266.syncTime(); 64 | ///dateTime = updateCurTime(); 65 | //strcpy(dateTime,tNow); 66 | } 67 | 68 | //////////////////////////////////// 69 | // convert month to digits 70 | //////////////////////////////////// 71 | String getMonth(String sM) { 72 | if(sM=="Jan") return "01"; 73 | if(sM=="Feb") return "02"; 74 | if(sM=="Mar") return "03"; 75 | if(sM=="Apr") return "04"; 76 | if(sM=="May") return "05"; 77 | if(sM=="Jun") return "06"; 78 | if(sM=="Jul") return "07"; 79 | if(sM=="Aug") return "08"; 80 | if(sM=="Sep") return "09"; 81 | if(sM=="Oct") return "10"; 82 | if(sM=="Nov") return "11"; 83 | if(sM=="Dec") return "12"; 84 | return "01"; 85 | } 86 | //////////////////////////////////// 87 | // Scrape UTC Time from server 88 | //////////////////////////////////// 89 | 90 | char* updateCurTime(void) { 91 | static int timeout_busy=0; 92 | int ipos; 93 | timeout_busy=0; //reset 94 | 95 | const char* timeServer = "developer.yahooapis.com"; 96 | const char* timeServerGet = "GET developer.yahooapis.com/TimeService/V1/getTime?appid=YahooDemo&output=json HTTP/1.1"; 97 | String utctime; 98 | String GmtDate; 99 | static char dateStamp[20]; 100 | static char chBuf[80]; 101 | char utctimeraw[80]; 102 | char* dpos; 103 | WiFiClient client2; 104 | if (client2.connect(timeServer, 80)) { 105 | //Send Request 106 | client2.println(timeServerGet); 107 | client2.println(); 108 | while((!client2.available())&&(timeout_busy++<5000)){ 109 | // Wait until the client sends some data 110 | delay(1); 111 | } 112 | //kill client if timeout 113 | if(timeout_busy>=5000) { 114 | client2.flush(); 115 | client2.stop(); 116 | //Serial.println("timeout receiving timeserver data\n"); 117 | return dateStamp; 118 | } 119 | //Read the http GET Response 120 | String req2 = client2.readString(); 121 | 122 | //Get the index of the Date String 123 | req2.toCharArray(chBuf, 80); 124 | //strcpy(dateStamp,chBuf); 125 | 126 | //Close connection 127 | delay(1); 128 | client2.flush(); 129 | client2.stop(); 130 | 131 | ipos = req2.indexOf("Date:"); 132 | if(ipos>0) { 133 | GmtDate = req2.substring(ipos,ipos+35); 134 | utctime = GmtDate.substring(18,22) + getMonth(GmtDate.substring(14,17)) + GmtDate.substring(11,13) + GmtDate.substring(23,25) + GmtDate.substring(26,28) + GmtDate.substring(29,31); 135 | utctime.substring(0,14).toCharArray(dateStamp, 20); 136 | } 137 | } 138 | else { 139 | //Serial.println("did not connect to timeserver\n"); 140 | } 141 | timeout_busy=0; //reset timeout 142 | return dateStamp; //Return latest or last good dateStamp 143 | } 144 | -------------------------------------------------------------------------------- /AWS/Esp8266AWSImplementations.h: -------------------------------------------------------------------------------- 1 | #ifndef AWSSPARKIMPLEMENTATIONS_H_ 2 | #define AWSSPARKIMPLEMENTATIONS_H_ 3 | #include "DeviceIndependentInterfaces.h" 4 | /* application.h is Esp8266's standard library. Define TCPClient. */ 5 | //#include 6 | #include 7 | 8 | /* HttpClient implementation to be used on the Esp8266 Core device. */ 9 | class Esp8266HttpClient: public IHttpClient { 10 | WiFiClient client; 11 | //TCPClient client; 12 | public: 13 | Esp8266HttpClient(); 14 | /* Send http request and return the response. */ 15 | char* send(const char *request, const char* serverUrl, int port); 16 | /* Returns false. Client uses raw http/https. */ 17 | bool usesCurl(void); 18 | }; 19 | 20 | class Esp8266DateTimeProvider: public IDateTimeProvider { 21 | /* The time as a cstring in yyyyMMddHHmmss format. Is written to within and 22 | * returned by getDateTime(). */ 23 | WiFiClient client2; 24 | //char dateTime[15]; 25 | public: 26 | char dateTime[15]; 27 | Esp8266DateTimeProvider(); 28 | /* Retrieve the current GMT date and time in yyyyMMddHHmmss format. */ 29 | const char* getDateTime(void); 30 | /* Returns false because Esp8266 has it's own mechanism for syncing that does 31 | * not require an argument. */ 32 | bool syncTakesArg(void); 33 | /* Synchronizes Esp8266's date and time with Esp8266's servers. The dateTime 34 | * argument is ignored. */ 35 | void sync(const char* dateTime); 36 | }; 37 | 38 | #endif /* AWSSPARKIMPLEMENTATIONS_H_ */ 39 | -------------------------------------------------------------------------------- /AWS/Utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Utils.cpp 3 | * 4 | * See Utils.h for description. 5 | * 6 | * Created on: Jun 30, 2014 7 | * Author: hoffmaj 8 | */ 9 | 10 | #include "Utils.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "jsmn.h" 16 | #include "sha256.h" 17 | 18 | /* Constants for base64Encode. */ 19 | static const char ENCODE_CHARS[] = 20 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 21 | static const char PAD_CHAR = '='; 22 | 23 | /* Constants for findHttpStatusCode. */ 24 | static const char HTTP_STATUS_CODE_PREFIX[] = "HTTP/1.1 "; 25 | static const int HTTP_STATUS_CODE_LEN = 3; 26 | 27 | /* Constants for hmacSha256. */ 28 | static const int BLOCK_SIZE = 64; 29 | static const char OPAD = 0x5c; 30 | static const char IPAD = 0x36; 31 | const int SHA256_DEC_HASH_LEN = 32; 32 | 33 | char *base64Encode(const char *toEncode) { 34 | int inLen = strlen(toEncode); 35 | /* For every three input chars there are 4 output chars, plus an extra 4 36 | * output chars for the possible 1 or 2 remaining input chars, plus an 37 | * extra byte for null termination. */ 38 | size_t encodedLen = (((inLen / 3) + (inLen % 3 > 0)) * 4) + 1; 39 | 40 | char *encoded = new char[encodedLen](); 41 | int chunkIdx; 42 | char inChar1; 43 | char inChar2; 44 | char inChar3; 45 | int outIdx1; 46 | int outIdx2; 47 | int outIdx3; 48 | int outIdx4; 49 | 50 | for (chunkIdx = 0; chunkIdx < inLen / 3; chunkIdx++) { 51 | /* This approach of treating each character individually instead of 52 | * containing all bits in a long type allows the encoding to work on 8, 53 | * 16, 32, and 64 bit systems. */ 54 | inChar1 = *toEncode++; 55 | inChar2 = *toEncode++; 56 | inChar3 = *toEncode++; 57 | 58 | outIdx1 = (inChar1 & 0xFC) >> 2; 59 | outIdx2 = ((inChar1 & 0x03) << 4) + ((inChar2 & 0xF0) >> 4); 60 | outIdx3 = ((inChar2 & 0x0F) << 2) + ((inChar3 & 0xC0) >> 6); 61 | outIdx4 = inChar3 & 0x3F; 62 | 63 | encoded[chunkIdx * 4] = ENCODE_CHARS[outIdx1]; 64 | encoded[chunkIdx * 4 + 1] = ENCODE_CHARS[outIdx2]; 65 | encoded[chunkIdx * 4 + 2] = ENCODE_CHARS[outIdx3]; 66 | encoded[chunkIdx * 4 + 3] = ENCODE_CHARS[outIdx4]; 67 | } 68 | 69 | switch (inLen % 3) { 70 | case 1: 71 | /* 1 extra input char -> 2 output chars and 2 padding chars. */ 72 | 73 | inChar1 = *toEncode++; 74 | 75 | outIdx1 = (inChar1 & 0xFC) >> 2; 76 | outIdx2 = (inChar1 & 0x03) << 4; 77 | 78 | encoded[chunkIdx * 4] = ENCODE_CHARS[outIdx1]; 79 | encoded[chunkIdx * 4 + 1] = ENCODE_CHARS[outIdx2]; 80 | encoded[chunkIdx * 4 + 2] = PAD_CHAR; 81 | encoded[chunkIdx * 4 + 3] = PAD_CHAR; 82 | chunkIdx++; 83 | break; 84 | case 2: 85 | /* 2 extra input chars -> 3 output chars and 1 padding char. */ 86 | 87 | inChar1 = *toEncode++; 88 | inChar2 = *toEncode++; 89 | outIdx1 = (inChar1 & 0xFC) >> 2; 90 | outIdx2 = ((inChar1 & 0x03) << 4) + ((inChar2 & 0xF0) >> 4); 91 | outIdx3 = ((inChar2 & 0x0F) << 2); 92 | encoded[chunkIdx * 4] = ENCODE_CHARS[outIdx1]; 93 | encoded[chunkIdx * 4 + 1] = ENCODE_CHARS[outIdx2]; 94 | encoded[chunkIdx * 4 + 2] = ENCODE_CHARS[outIdx3]; 95 | encoded[chunkIdx * 4 + 3] = PAD_CHAR; 96 | chunkIdx++; 97 | break; 98 | } 99 | /* Ensure null termination. */ 100 | encoded[chunkIdx * 4] = 0; 101 | 102 | return encoded; 103 | } 104 | 105 | int digitCount(int i) { 106 | int digits; 107 | for (digits = 0; i != 0; digits++) 108 | i /= 10; 109 | return digits; 110 | } 111 | 112 | char* escapeQuotes(const char* unescaped) { 113 | int unescapedLen = strlen(unescaped); 114 | 115 | /* Count quotes so that the amount of memory to be allocated can be 116 | * determined */ 117 | int quoteCount = 0; 118 | for (int i = 0; i < unescapedLen; i++) { 119 | if (unescaped[i] == '\"') { 120 | quoteCount++; 121 | } 122 | } 123 | 124 | /* Copy ever character over, including a backslash before every quote. */ 125 | char* escaped = new char[unescapedLen + quoteCount + 1](); 126 | int escapedWritten = 0; 127 | for (int i = 0; i < unescapedLen; i++) { 128 | if (unescaped[i] == '\"') { 129 | escaped[escapedWritten] = '\\'; 130 | escapedWritten++; 131 | } 132 | escaped[escapedWritten] = unescaped[i]; 133 | escapedWritten++; 134 | } 135 | return escaped; 136 | } 137 | 138 | bool findJsonStartEnd(const char* str, int* start, int* end) { 139 | /* Ignore everything before the first unquoted bracket and after the 140 | * unquoted bracket matching the first unquoted bracket, eg. headers and 141 | * newlines. */ 142 | int strLen = strlen(str); 143 | /* Incrememented for every unquoted '{' and decremented for every 144 | * unquoted '}' */ 145 | int braceBalance = 0; 146 | /* -1 is invalid start and end indices. */ 147 | int s = -1; 148 | int e = -1; 149 | bool inQuotes = false; 150 | for (int i = 0; i < strLen; i++) { 151 | /* Toggle inQuotes. */ 152 | if (str[i] == '\"') { 153 | inQuotes = !inQuotes; 154 | } 155 | /* Only consider brackets outside of quotes. */ 156 | if (!inQuotes) { 157 | if (str[i] == '{') { 158 | if (s == -1) { 159 | s = i; 160 | } 161 | braceBalance++; 162 | } else if (str[i] == '}') { 163 | braceBalance--; 164 | if (braceBalance == 0) { 165 | e = i; 166 | break; 167 | } 168 | } 169 | } 170 | } 171 | *start = s; 172 | *end = e; 173 | /* If not a full json string no success. */ 174 | if ((s == -1) || (e == -1)) { 175 | return false; 176 | } 177 | return true; 178 | } 179 | 180 | int findHttpStatusCode(const char* str) { 181 | /* If the input is null OR the input is not long enough to contain the 182 | * error code OR the first characters of the input are not 183 | * HTTP_STATUS_CODE_PREFIX, return 0; */ 184 | if (str == NULL 185 | || strlen(str) 186 | < strlen(HTTP_STATUS_CODE_PREFIX) + HTTP_STATUS_CODE_LEN 187 | || strncmp(HTTP_STATUS_CODE_PREFIX, str, 188 | strlen(HTTP_STATUS_CODE_PREFIX))) { 189 | return 0; 190 | } 191 | /* copy the error code string and convert it to an int. */ 192 | char errorCodeStr[HTTP_STATUS_CODE_LEN + 1]; 193 | strncpy(errorCodeStr, str + strlen(HTTP_STATUS_CODE_PREFIX), 194 | HTTP_STATUS_CODE_LEN); 195 | return atoi(errorCodeStr); 196 | } 197 | 198 | int jsonArraySize(const char* jsonArrayStr, int jsonArrayStrLen) { 199 | int elementCount = 0; 200 | bool inQuotes = false; 201 | if (jsonArrayStr[0] != '[' || jsonArrayStr[jsonArrayStrLen - 1] != ']') { 202 | /* Invalid syntax. */ 203 | return -1; 204 | } 205 | for (int i = 1; i < jsonArrayStrLen - 1; i++) { 206 | if (jsonArrayStr[i] == '"' && jsonArrayStr[i - 1] != '\\') { 207 | if (inQuotes) { 208 | elementCount++; 209 | } 210 | inQuotes = !inQuotes; 211 | } 212 | } 213 | return elementCount; 214 | } 215 | 216 | char** jsonArrayToStringArray(int numOfElements, const char* jsonArrayStr, 217 | int jsonArrayStrLen) { 218 | char** strArray = new char*[numOfElements](); 219 | int start = -1; 220 | int elementCount = 0; 221 | bool inQuotes = false; 222 | if (jsonArrayStr[0] != '[' || jsonArrayStr[jsonArrayStrLen - 1] != ']') { 223 | /* Invalid syntax. */ 224 | return 0; 225 | } 226 | for (int i = 1; i < jsonArrayStrLen - 1; i++) { 227 | if (jsonArrayStr[i] == '"' && jsonArrayStr[i - 1] != '\\') { 228 | if (inQuotes) { 229 | /* Delete values and return null if we find more elements than 230 | * expected. */ 231 | if (elementCount == numOfElements) { 232 | for (int j = 0; j < numOfElements; j++) { 233 | delete[] strArray[j]; 234 | } 235 | delete[] strArray; 236 | return 0; 237 | } 238 | 239 | char* str = new char[(i - start) + 1](); 240 | strncpy(str, jsonArrayStr + start, i - start); 241 | strArray[elementCount] = str; 242 | elementCount++; 243 | } else { 244 | start = i + 1; 245 | } 246 | inQuotes = !inQuotes; 247 | } 248 | } 249 | return strArray; 250 | } 251 | 252 | bool isKey(const char * json, int thisEnd, int nextStart) { 253 | /* Check the characters in between the two tokens. */ 254 | for (int i = thisEnd; i < nextStart; i++) { 255 | if (json[i] == ':') { 256 | /* A ':' means the token on the left is a key. */ 257 | return true; 258 | } else if (json[i] == ',') { 259 | /* A ',' means the token on the left is a value. */ 260 | return false; 261 | } 262 | } 263 | return false; 264 | } 265 | 266 | bool isOuterKey(const char * json, int thisEnd, int nextStart) { 267 | /* Check if token is a key at all before checking if it is an inner key. */ 268 | if (!isKey(json, thisEnd, nextStart)) { 269 | return false; 270 | } 271 | /* True when we are in a quoted section of a string. Ignore braces in a 272 | * quoted section. */ 273 | bool inQuote = false; 274 | /* The number of opening braces encountered minus the number of closing 275 | * braces encountered. braceLevel greater than 1 means we are looking at 276 | * inner keys. */ 277 | int braceLevel = 0; 278 | for (int i = 0; i < thisEnd; i++) { 279 | switch (json[i]) { 280 | case '"': 281 | /* Toggle inQuote. */ 282 | inQuote = !inQuote; 283 | break; 284 | case '{': 285 | /* If not in quotes, increase braceLevel. */ 286 | if (!inQuote) { 287 | braceLevel++; 288 | } 289 | break; 290 | case '}': 291 | /* If not in quotes, decrease braceLevel. */ 292 | if (!inQuote) { 293 | braceLevel--; 294 | } 295 | break; 296 | } 297 | } 298 | /* if we are at brace level 1 upon reaching, the key is in the outermost 299 | * json object */ 300 | return (braceLevel == 1); 301 | 302 | } 303 | 304 | char* jsmnGetVal(const char* key, const char* json, jsmntok_t* tokens, 305 | int tokenCount) { 306 | /* Look at all json tokens. */ 307 | for (int i = 0; i < tokenCount - 1; i++) { 308 | /* Check if token is an outer key. */ 309 | if (isOuterKey(json, tokens[i].end, tokens[i + 1].start)) { 310 | int currentKeyLen = tokens[i].end - tokens[i].start; 311 | int valueLen = tokens[i + 1].end - tokens[i + 1].start; 312 | /* Check if the key we are looking at is the key we are looking 313 | * for. */ 314 | if (((int) strlen(key) == currentKeyLen) 315 | && (strncmp(json + tokens[i].start, key, currentKeyLen) == 0)) { 316 | /* Copy and return the value */ 317 | char* value = new char[valueLen + 1](); 318 | strncpy(value, json + tokens[i + 1].start, valueLen); 319 | return value; 320 | } 321 | } 322 | } 323 | /* Key was not found. */ 324 | return NULL; 325 | } 326 | 327 | char* getTimeFromInvalidSignatureMessage(const char* message) { 328 | int messageLen = strlen(message); 329 | /* Iterate through each character in the string. */ 330 | for (int i = 0; i < messageLen; i++) { 331 | /* If an opening parenthesis is found, copy the following 15 332 | * characters, excluding the 9th character which is a 'T'.*/ 333 | if (message[i] == '(') { 334 | char* time = new char[15](); 335 | sprintf(time, "%.8s%.6s", message + i + 1, message + i + 10); 336 | return time; 337 | } 338 | } 339 | return 0; 340 | } 341 | 342 | char* hmacSha256(const char* key, int keyLen, const char* message, 343 | int messageLen) { 344 | SHA256* sha256 = new SHA256(); 345 | /* The corrected key should be BLOCK_SIZE long. */ 346 | char* correctedKey = new char[BLOCK_SIZE + 1](); 347 | /* If the key is greater than BLOCK_SIZE long, copy over its sha256 hash of 348 | * SHA256_DEC_HASH_LEN, leaving 0-padding to fill the entire BLOCK_SIZE. */ 349 | if ((int) keyLen > BLOCK_SIZE) { 350 | sha256->reset(); 351 | sha256->add(key, keyLen); 352 | char* hashedKey = sha256->getHashDec(); 353 | memcpy(correctedKey, hashedKey, SHA256_DEC_HASH_LEN); 354 | delete[] hashedKey; 355 | } 356 | /* if the key is less than BLOCK_SIZE long, simply copy it over, leaving 357 | * 0-padding to fill the entire BLOCK_SIZE. */ 358 | else { 359 | memcpy(correctedKey, key, keyLen); 360 | } 361 | 362 | /* Using an exclusive or with these OPAD and IPAD values to create the 363 | * iPadded and oPadded values specified by the HMAC algorithm. */ 364 | char* oPadded = new char[BLOCK_SIZE + 1](); 365 | char* iPadded = new char[BLOCK_SIZE + 1](); 366 | for (int i = 0; i < BLOCK_SIZE; i++) { 367 | oPadded[i] = correctedKey[i] ^ OPAD; 368 | iPadded[i] = correctedKey[i] ^ IPAD; 369 | } 370 | 371 | delete[] correctedKey; 372 | 373 | /* Create the inner hash with the concatenation of iPadded and message. */ 374 | sha256->reset(); 375 | sha256->add(iPadded, BLOCK_SIZE); 376 | delete[] iPadded; 377 | sha256->add(message, messageLen); 378 | char* innerHash = sha256->getHashDec(); 379 | 380 | /* Create the outer hash with the concatenation of oPadded and 381 | * innerhash. */ 382 | sha256->reset(); 383 | sha256->add(oPadded, BLOCK_SIZE); 384 | delete[] oPadded; 385 | sha256->add(innerHash, SHA256_DEC_HASH_LEN); 386 | delete[] innerHash; 387 | char* final = sha256->getHashDec(); 388 | delete sha256; 389 | return final; 390 | } 391 | 392 | -------------------------------------------------------------------------------- /AWS/Utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Utils.h 3 | * 4 | * Utility functions for the Arduino AWS SDK. 5 | * 6 | * Created on: Jun 30, 2014 7 | * Author: hoffmaj 8 | */ 9 | 10 | #ifndef UTILS_H_ 11 | #define UTILS_H_ 12 | 13 | #include 14 | #include "jsmn.h" 15 | 16 | extern const int SHA256_DEC_HASH_LEN; 17 | 18 | /* Base encode 64 an array of characters. Returned array must be deleted by 19 | * caller. */ 20 | char *base64Encode(const char *inputBuffer); 21 | 22 | /* Determine the number of digits in the base 10 representation a given 23 | * number. */ 24 | int digitCount(int i); 25 | 26 | /* Create a string identical to the given string except with backslashes before 27 | * quotes. Caller must delete the returned string. */ 28 | char* escapeQuotes(const char* unescaped); 29 | 30 | /* Determines the index of the opening and closing of a json string that is 31 | * surrounded by non-json, eg. http headers and newlines. Returns true if json 32 | * was found, false otherwise. */ 33 | bool findJsonStartEnd(const char* str, int* start, int* end); 34 | 35 | /* Find and return the status code of an http response. */ 36 | int findHttpStatusCode(const char* str); 37 | 38 | /* Given a char* of json array syntax ( e.g. ["a", "b", "c"]), count the number 39 | * of elements. */ 40 | int jsonArraySize(const char* jsonArrayStr, int jsonArrayStrLen); 41 | 42 | /* Given a char* of json array syntax ( e.g. ["a", "b", "c"]) and the number of 43 | * elements, create a matching array of char*'s. Caller must delete the created 44 | * array AND each element. */ 45 | char** jsonArrayToStringArray(int numOfElements, const char* jsonArrayStr, 46 | int jsonArrayStrLen); 47 | 48 | /* Determines whether a token is a json key, given the json string, the token's 49 | * end index, and the next token's start index. This includes keys of inner 50 | * json objects, i.e. both 'a' and 'b' would be a key in '{"a":{"b":1}}'. */ 51 | bool isKey(const char * json, int thisEnd, int nextStart); 52 | 53 | /* Determines whether a token is a json key, given the json string, the token's 54 | * end index, and the next token's start index. This does not include keys of 55 | * inner json objects, i.e. 'a' would be a key in '{"a":{"b":1}}', but 'b' 56 | * would not. */ 57 | bool isOuterKey(const char * json, int thisEnd, int nextStart); 58 | 59 | /* Given a json key, get a corresponding key. Takes the key, the json object 60 | * string, and the jsmn tokens. Returns 0 if key does not exist. If key does 61 | * exist, user must free the memory allocated to store the value. */ 62 | char* jsmnGetVal(const char* key, const char* json, jsmntok_t* tokens, 63 | int tokenCount); 64 | 65 | /* Very minimal implementation for finding the current time from the message 66 | * returned by a signature failure. This works with at least Kinesis and 67 | * DynamoDB, in which the time is located within the 15 characters following 68 | * the first opening parenthesis. (e.g. "...(20140721T184435Z ..." )*/ 69 | char* getTimeFromInvalidSignatureMessage(const char* message); 70 | 71 | /* Apply hmac to the key and message. */ 72 | char* hmacSha256(const char* key, int keyLen, const char* message, 73 | int messageLen); 74 | 75 | #endif /* UTILS_H_ */ 76 | -------------------------------------------------------------------------------- /AWS/jsmn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Serge A. Zaitsev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "jsmn.h" 26 | 27 | /** 28 | * Allocates a fresh unused token from the token pull. 29 | */ 30 | static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, 31 | size_t num_tokens) { 32 | jsmntok_t *tok; 33 | if (parser->toknext >= num_tokens) { 34 | return NULL; 35 | } 36 | tok = &tokens[parser->toknext++]; 37 | tok->start = tok->end = -1; 38 | tok->size = 0; 39 | #ifdef JSMN_PARENT_LINKS 40 | tok->parent = -1; 41 | #endif 42 | return tok; 43 | } 44 | 45 | /** 46 | * Fills token type and boundaries. 47 | */ 48 | static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, 49 | int end) { 50 | token->type = type; 51 | token->start = start; 52 | token->end = end; 53 | token->size = 0; 54 | } 55 | 56 | /** 57 | * Fills next available token with JSON primitive. 58 | */ 59 | static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, 60 | size_t len, jsmntok_t *tokens, size_t num_tokens) { 61 | jsmntok_t *token; 62 | int start; 63 | 64 | start = parser->pos; 65 | 66 | for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 67 | switch (js[parser->pos]) { 68 | #ifndef JSMN_STRICT 69 | /* In strict mode primitive must be followed by "," or "}" or "]" */ 70 | case ':': 71 | #endif 72 | case '\t': 73 | case '\r': 74 | case '\n': 75 | case ' ': 76 | case ',': 77 | case ']': 78 | case '}': 79 | goto found; 80 | } 81 | if (js[parser->pos] < 32 || js[parser->pos] >= 127) { 82 | parser->pos = start; 83 | return JSMN_ERROR_INVAL; 84 | } 85 | } 86 | #ifdef JSMN_STRICT 87 | /* In strict mode primitive must be followed by a comma/object/array */ 88 | parser->pos = start; 89 | return JSMN_ERROR_PART; 90 | #endif 91 | 92 | found: if (tokens == NULL) { 93 | parser->pos--; 94 | return (jsmnerr_t) 0; 95 | } 96 | token = jsmn_alloc_token(parser, tokens, num_tokens); 97 | if (token == NULL) { 98 | parser->pos = start; 99 | return JSMN_ERROR_NOMEM; 100 | } 101 | jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); 102 | #ifdef JSMN_PARENT_LINKS 103 | token->parent = parser->toksuper; 104 | #endif 105 | parser->pos--; 106 | return (jsmnerr_t) 0; 107 | } 108 | 109 | /** 110 | * Filsl next token with JSON string. 111 | */ 112 | static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, 113 | size_t len, jsmntok_t *tokens, size_t num_tokens) { 114 | jsmntok_t *token; 115 | 116 | int start = parser->pos; 117 | 118 | parser->pos++; 119 | 120 | /* Skip starting quote */ 121 | for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 122 | char c = js[parser->pos]; 123 | 124 | /* Quote: end of string */ 125 | if (c == '\"') { 126 | if (tokens == NULL) { 127 | return (jsmnerr_t) 0; 128 | } 129 | token = jsmn_alloc_token(parser, tokens, num_tokens); 130 | if (token == NULL) { 131 | parser->pos = start; 132 | return JSMN_ERROR_NOMEM; 133 | } 134 | jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); 135 | #ifdef JSMN_PARENT_LINKS 136 | token->parent = parser->toksuper; 137 | #endif 138 | return (jsmnerr_t) 0; 139 | } 140 | 141 | /* Backslash: Quoted symbol expected */ 142 | if (c == '\\') { 143 | parser->pos++; 144 | switch (js[parser->pos]) { 145 | /* Allowed escaped symbols */ 146 | case '\"': 147 | case '/': 148 | case '\\': 149 | case 'b': 150 | case 'f': 151 | case 'r': 152 | case 'n': 153 | case 't': 154 | break; 155 | /* Allows escaped symbol \uXXXX */ 156 | case 'u': 157 | parser->pos++; 158 | int i; 159 | for (i = 0; i < 4 && js[parser->pos] != '\0'; i++) { 160 | /* If it isn't a hex character we have an error */ 161 | if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ 162 | (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ 163 | (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ 164 | parser->pos = start; 165 | return JSMN_ERROR_INVAL; 166 | } 167 | parser->pos++; 168 | } 169 | parser->pos--; 170 | break; 171 | /* Unexpected symbol */ 172 | default: 173 | parser->pos = start; 174 | return JSMN_ERROR_INVAL; 175 | } 176 | } 177 | } 178 | parser->pos = start; 179 | return JSMN_ERROR_PART; 180 | } 181 | 182 | /** 183 | * Parse JSON string and fill tokens. 184 | */ 185 | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, 186 | jsmntok_t *tokens, unsigned int num_tokens) { 187 | jsmnerr_t r; 188 | int i; 189 | jsmntok_t *token; 190 | int count = 0; 191 | 192 | for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 193 | char c; 194 | jsmntype_t type; 195 | 196 | c = js[parser->pos]; 197 | switch (c) { 198 | case '{': 199 | case '[': 200 | count++; 201 | if (tokens == NULL) { 202 | break; 203 | } 204 | token = jsmn_alloc_token(parser, tokens, num_tokens); 205 | if (token == NULL) 206 | return JSMN_ERROR_NOMEM; 207 | if (parser->toksuper != -1) { 208 | tokens[parser->toksuper].size++; 209 | #ifdef JSMN_PARENT_LINKS 210 | token->parent = parser->toksuper; 211 | #endif 212 | } 213 | token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); 214 | token->start = parser->pos; 215 | parser->toksuper = parser->toknext - 1; 216 | break; 217 | case '}': 218 | case ']': 219 | if (tokens == NULL) 220 | break; 221 | type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); 222 | #ifdef JSMN_PARENT_LINKS 223 | if (parser->toknext < 1) { 224 | return JSMN_ERROR_INVAL; 225 | } 226 | token = &tokens[parser->toknext - 1]; 227 | for (;;) { 228 | if (token->start != -1 && token->end == -1) { 229 | if (token->type != type) { 230 | return JSMN_ERROR_INVAL; 231 | } 232 | token->end = parser->pos + 1; 233 | parser->toksuper = token->parent; 234 | break; 235 | } 236 | if (token->parent == -1) { 237 | break; 238 | } 239 | token = &tokens[token->parent]; 240 | } 241 | #else 242 | for (i = parser->toknext - 1; i >= 0; i--) { 243 | token = &tokens[i]; 244 | if (token->start != -1 && token->end == -1) { 245 | if (token->type != type) { 246 | return JSMN_ERROR_INVAL; 247 | } 248 | parser->toksuper = -1; 249 | token->end = parser->pos + 1; 250 | break; 251 | } 252 | } 253 | /* Error if unmatched closing bracket */ 254 | if (i == -1) 255 | return JSMN_ERROR_INVAL; 256 | for (; i >= 0; i--) { 257 | token = &tokens[i]; 258 | if (token->start != -1 && token->end == -1) { 259 | parser->toksuper = i; 260 | break; 261 | } 262 | } 263 | #endif 264 | break; 265 | case '\"': 266 | r = jsmn_parse_string(parser, js, len, tokens, num_tokens); 267 | if (r < 0) 268 | return r; 269 | count++; 270 | if (parser->toksuper != -1 && tokens != NULL) 271 | tokens[parser->toksuper].size++; 272 | break; 273 | case '\t': 274 | case '\r': 275 | case '\n': 276 | case ':': 277 | case ',': 278 | case ' ': 279 | break; 280 | #ifdef JSMN_STRICT 281 | /* In strict mode primitives are: numbers and booleans */ 282 | case '-': 283 | case '0': 284 | case '1': 285 | case '2': 286 | case '3': 287 | case '4': 288 | case '5': 289 | case '6': 290 | case '7': 291 | case '8': 292 | case '9': 293 | case 't': 294 | case 'f': 295 | case 'n': 296 | #else 297 | /* In non-strict mode every unquoted value is a primitive */ 298 | default: 299 | #endif 300 | r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); 301 | if (r < 0) 302 | return r; 303 | count++; 304 | if (parser->toksuper != -1 && tokens != NULL) 305 | tokens[parser->toksuper].size++; 306 | break; 307 | 308 | #ifdef JSMN_STRICT 309 | /* Unexpected char in strict mode */ 310 | default: 311 | return JSMN_ERROR_INVAL; 312 | #endif 313 | } 314 | } 315 | 316 | for (i = parser->toknext - 1; i >= 0; i--) { 317 | /* Unmatched opened object or array */ 318 | if (tokens[i].start != -1 && tokens[i].end == -1) { 319 | return JSMN_ERROR_PART; 320 | } 321 | } 322 | 323 | return (jsmnerr_t) count; 324 | } 325 | 326 | /** 327 | * Creates a new parser based over a given buffer with an array of tokens 328 | * available. 329 | */ 330 | void jsmn_init(jsmn_parser *parser) { 331 | parser->pos = 0; 332 | parser->toknext = 0; 333 | parser->toksuper = -1; 334 | } 335 | 336 | -------------------------------------------------------------------------------- /AWS/jsmn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Serge A. Zaitsev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef __JSMN_H_ 24 | #define __JSMN_H_ 25 | #include 26 | #define JSMN_STRICT 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | /** 32 | * JSON type identifier. Basic types are: 33 | * o Object 34 | * o Array 35 | * o String 36 | * o Other primitive: number, boolean (true/false) or null 37 | */ 38 | typedef enum { 39 | JSMN_PRIMITIVE = 0, JSMN_OBJECT = 1, JSMN_ARRAY = 2, JSMN_STRING = 3 40 | } jsmntype_t; 41 | 42 | typedef enum { 43 | /* Not enough tokens were provided */ 44 | JSMN_ERROR_NOMEM = -1, 45 | /* Invalid character inside JSON string */ 46 | JSMN_ERROR_INVAL = -2, 47 | /* The string is not a full JSON packet, more bytes expected */ 48 | JSMN_ERROR_PART = -3, 49 | } jsmnerr_t; 50 | 51 | /** 52 | * JSON token description. 53 | * @param type type (object, array, string etc.) 54 | * @param start start position in JSON data string 55 | * @param end end position in JSON data string 56 | */ 57 | typedef struct { 58 | jsmntype_t type; 59 | int start; 60 | int end; 61 | int size; 62 | #ifdef JSMN_PARENT_LINKS 63 | int parent; 64 | #endif 65 | } jsmntok_t; 66 | 67 | /** 68 | * JSON parser. Contains an array of token blocks available. Also stores 69 | * the string being parsed now and current position in that string 70 | */ 71 | typedef struct { 72 | unsigned int pos; /* offset in the JSON string */ 73 | unsigned int toknext; /* next token to allocate */ 74 | int toksuper; /* superior token node, e.g parent object or array */ 75 | } jsmn_parser; 76 | 77 | /** 78 | * Create JSON parser over an array of tokens 79 | */ 80 | void jsmn_init(jsmn_parser *parser); 81 | 82 | /** 83 | * Run JSON parser. It parses a JSON data string into and array of tokens, each describing 84 | * a single JSON object. 85 | */ 86 | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, 87 | jsmntok_t *tokens, unsigned int num_tokens); 88 | 89 | #ifdef __cplusplus 90 | } 91 | #endif 92 | 93 | #endif /* __JSMN_H_ */ 94 | -------------------------------------------------------------------------------- /AWS/keys.c: -------------------------------------------------------------------------------- 1 | // keys.cpp 2 | #include "keys.h" 3 | 4 | const char* awsKeyID = "KKKKKKKKKKKKKKKKKKKK"; //<<----Enter your awsKeyID 5 | const char* awsSecKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //<<----Enter your awsSecretKey -------------------------------------------------------------------------------- /AWS/keys.h: -------------------------------------------------------------------------------- 1 | // keys.h 2 | #ifndef KEYS_H_ 3 | #define KEYS_H_ 4 | 5 | extern const char* awsKeyID; // Declare these variables to 6 | extern const char* awsSecKey; // be accessible by the sketch 7 | 8 | #endif -------------------------------------------------------------------------------- /AWS/sha256.cpp: -------------------------------------------------------------------------------- 1 | // ////////////////////////////////////////////////////////// 2 | // sha256.cpp 3 | // Copyright (c) 2014 Stephan Brumme. All rights reserved. 4 | // see http://create.stephan-brumme.com/disclaimer.html 5 | // 6 | 7 | #include "sha256.h" 8 | 9 | /* These lines have been discarded from the original source code. endian.h is 10 | * not necessarilly included on the devices that will use this SDK. Little 11 | * Endian is assumed instead. */ 12 | // // big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN 13 | // #ifndef _MSC_VER 14 | // #include 15 | // #endif 16 | /// same as reset() 17 | SHA256::SHA256() { 18 | reset(); 19 | } 20 | 21 | /// restart 22 | void SHA256::reset() { 23 | m_numBytes = 0; 24 | m_bufferSize = 0; 25 | 26 | // according to RFC 1321 27 | m_hash[0] = 0x6a09e667; 28 | m_hash[1] = 0xbb67ae85; 29 | m_hash[2] = 0x3c6ef372; 30 | m_hash[3] = 0xa54ff53a; 31 | m_hash[4] = 0x510e527f; 32 | m_hash[5] = 0x9b05688c; 33 | m_hash[6] = 0x1f83d9ab; 34 | m_hash[7] = 0x5be0cd19; 35 | } 36 | 37 | namespace { 38 | inline uint32_t rotate(uint32_t a, uint32_t c) { 39 | return (a >> c) | (a << (32 - c)); 40 | } 41 | 42 | inline uint32_t swap(uint32_t x) { 43 | #if defined(__GNUC__) || defined(__clang__) 44 | return __builtin_bswap32(x); 45 | #endif 46 | #ifdef MSC_VER 47 | return _byteswap_ulong(x); 48 | #endif 49 | 50 | return (x >> 24) | ((x >> 8) & 0x0000FF00) | ((x << 8) & 0x00FF0000) 51 | | (x << 24); 52 | } 53 | 54 | // mix functions for processBlock() 55 | inline uint32_t f1(uint32_t e, uint32_t f, uint32_t g) { 56 | uint32_t term1 = rotate(e, 6) ^ rotate(e, 11) ^ rotate(e, 25); 57 | uint32_t term2 = (e & f) ^ (~e & g); //(g ^ (e & (f ^ g))) 58 | return term1 + term2; 59 | } 60 | 61 | inline uint32_t f2(uint32_t a, uint32_t b, uint32_t c) { 62 | uint32_t term1 = rotate(a, 2) ^ rotate(a, 13) ^ rotate(a, 22); 63 | uint32_t term2 = ((a | b) & c) | (a & b); //(a & (b ^ c)) ^ (b & c); 64 | return term1 + term2; 65 | } 66 | } 67 | 68 | /// process 64 bytes 69 | void SHA256::processBlock(const void* data) { 70 | // get last hash 71 | uint32_t a = m_hash[0]; 72 | uint32_t b = m_hash[1]; 73 | uint32_t c = m_hash[2]; 74 | uint32_t d = m_hash[3]; 75 | uint32_t e = m_hash[4]; 76 | uint32_t f = m_hash[5]; 77 | uint32_t g = m_hash[6]; 78 | uint32_t h = m_hash[7]; 79 | 80 | // data represented as 16x 32-bit words 81 | const uint32_t* input = (uint32_t*) data; 82 | // convert to big endian 83 | uint32_t words[64]; 84 | int i; 85 | for (i = 0; i < 16; i++) 86 | #if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) 87 | words[i] = input[i]; 88 | #else 89 | words[i] = swap(input[i]); 90 | #endif 91 | 92 | uint32_t x, y; // temporaries 93 | 94 | // first round 95 | x = h + f1(e, f, g) + 0x428a2f98 + words[0]; 96 | y = f2(a, b, c); 97 | d += x; 98 | h = x + y; 99 | x = g + f1(d, e, f) + 0x71374491 + words[1]; 100 | y = f2(h, a, b); 101 | c += x; 102 | g = x + y; 103 | x = f + f1(c, d, e) + 0xb5c0fbcf + words[2]; 104 | y = f2(g, h, a); 105 | b += x; 106 | f = x + y; 107 | x = e + f1(b, c, d) + 0xe9b5dba5 + words[3]; 108 | y = f2(f, g, h); 109 | a += x; 110 | e = x + y; 111 | x = d + f1(a, b, c) + 0x3956c25b + words[4]; 112 | y = f2(e, f, g); 113 | h += x; 114 | d = x + y; 115 | x = c + f1(h, a, b) + 0x59f111f1 + words[5]; 116 | y = f2(d, e, f); 117 | g += x; 118 | c = x + y; 119 | x = b + f1(g, h, a) + 0x923f82a4 + words[6]; 120 | y = f2(c, d, e); 121 | f += x; 122 | b = x + y; 123 | x = a + f1(f, g, h) + 0xab1c5ed5 + words[7]; 124 | y = f2(b, c, d); 125 | e += x; 126 | a = x + y; 127 | 128 | // secound round 129 | x = h + f1(e, f, g) + 0xd807aa98 + words[8]; 130 | y = f2(a, b, c); 131 | d += x; 132 | h = x + y; 133 | x = g + f1(d, e, f) + 0x12835b01 + words[9]; 134 | y = f2(h, a, b); 135 | c += x; 136 | g = x + y; 137 | x = f + f1(c, d, e) + 0x243185be + words[10]; 138 | y = f2(g, h, a); 139 | b += x; 140 | f = x + y; 141 | x = e + f1(b, c, d) + 0x550c7dc3 + words[11]; 142 | y = f2(f, g, h); 143 | a += x; 144 | e = x + y; 145 | x = d + f1(a, b, c) + 0x72be5d74 + words[12]; 146 | y = f2(e, f, g); 147 | h += x; 148 | d = x + y; 149 | x = c + f1(h, a, b) + 0x80deb1fe + words[13]; 150 | y = f2(d, e, f); 151 | g += x; 152 | c = x + y; 153 | x = b + f1(g, h, a) + 0x9bdc06a7 + words[14]; 154 | y = f2(c, d, e); 155 | f += x; 156 | b = x + y; 157 | x = a + f1(f, g, h) + 0xc19bf174 + words[15]; 158 | y = f2(b, c, d); 159 | e += x; 160 | a = x + y; 161 | 162 | // extend to 24 words 163 | for (; i < 24; i++) 164 | words[i] = words[i - 16] 165 | + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) 166 | ^ (words[i - 15] >> 3)) + words[i - 7] 167 | + (rotate(words[i - 2], 17) ^ rotate(words[i - 2], 19) 168 | ^ (words[i - 2] >> 10)); 169 | 170 | // third round 171 | x = h + f1(e, f, g) + 0xe49b69c1 + words[16]; 172 | y = f2(a, b, c); 173 | d += x; 174 | h = x + y; 175 | x = g + f1(d, e, f) + 0xefbe4786 + words[17]; 176 | y = f2(h, a, b); 177 | c += x; 178 | g = x + y; 179 | x = f + f1(c, d, e) + 0x0fc19dc6 + words[18]; 180 | y = f2(g, h, a); 181 | b += x; 182 | f = x + y; 183 | x = e + f1(b, c, d) + 0x240ca1cc + words[19]; 184 | y = f2(f, g, h); 185 | a += x; 186 | e = x + y; 187 | x = d + f1(a, b, c) + 0x2de92c6f + words[20]; 188 | y = f2(e, f, g); 189 | h += x; 190 | d = x + y; 191 | x = c + f1(h, a, b) + 0x4a7484aa + words[21]; 192 | y = f2(d, e, f); 193 | g += x; 194 | c = x + y; 195 | x = b + f1(g, h, a) + 0x5cb0a9dc + words[22]; 196 | y = f2(c, d, e); 197 | f += x; 198 | b = x + y; 199 | x = a + f1(f, g, h) + 0x76f988da + words[23]; 200 | y = f2(b, c, d); 201 | e += x; 202 | a = x + y; 203 | 204 | // extend to 32 words 205 | for (; i < 32; i++) 206 | words[i] = words[i - 16] 207 | + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) 208 | ^ (words[i - 15] >> 3)) + words[i - 7] 209 | + (rotate(words[i - 2], 17) ^ rotate(words[i - 2], 19) 210 | ^ (words[i - 2] >> 10)); 211 | 212 | // fourth round 213 | x = h + f1(e, f, g) + 0x983e5152 + words[24]; 214 | y = f2(a, b, c); 215 | d += x; 216 | h = x + y; 217 | x = g + f1(d, e, f) + 0xa831c66d + words[25]; 218 | y = f2(h, a, b); 219 | c += x; 220 | g = x + y; 221 | x = f + f1(c, d, e) + 0xb00327c8 + words[26]; 222 | y = f2(g, h, a); 223 | b += x; 224 | f = x + y; 225 | x = e + f1(b, c, d) + 0xbf597fc7 + words[27]; 226 | y = f2(f, g, h); 227 | a += x; 228 | e = x + y; 229 | x = d + f1(a, b, c) + 0xc6e00bf3 + words[28]; 230 | y = f2(e, f, g); 231 | h += x; 232 | d = x + y; 233 | x = c + f1(h, a, b) + 0xd5a79147 + words[29]; 234 | y = f2(d, e, f); 235 | g += x; 236 | c = x + y; 237 | x = b + f1(g, h, a) + 0x06ca6351 + words[30]; 238 | y = f2(c, d, e); 239 | f += x; 240 | b = x + y; 241 | x = a + f1(f, g, h) + 0x14292967 + words[31]; 242 | y = f2(b, c, d); 243 | e += x; 244 | a = x + y; 245 | 246 | // extend to 40 words 247 | for (; i < 40; i++) 248 | words[i] = words[i - 16] 249 | + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) 250 | ^ (words[i - 15] >> 3)) + words[i - 7] 251 | + (rotate(words[i - 2], 17) ^ rotate(words[i - 2], 19) 252 | ^ (words[i - 2] >> 10)); 253 | 254 | // fifth round 255 | x = h + f1(e, f, g) + 0x27b70a85 + words[32]; 256 | y = f2(a, b, c); 257 | d += x; 258 | h = x + y; 259 | x = g + f1(d, e, f) + 0x2e1b2138 + words[33]; 260 | y = f2(h, a, b); 261 | c += x; 262 | g = x + y; 263 | x = f + f1(c, d, e) + 0x4d2c6dfc + words[34]; 264 | y = f2(g, h, a); 265 | b += x; 266 | f = x + y; 267 | x = e + f1(b, c, d) + 0x53380d13 + words[35]; 268 | y = f2(f, g, h); 269 | a += x; 270 | e = x + y; 271 | x = d + f1(a, b, c) + 0x650a7354 + words[36]; 272 | y = f2(e, f, g); 273 | h += x; 274 | d = x + y; 275 | x = c + f1(h, a, b) + 0x766a0abb + words[37]; 276 | y = f2(d, e, f); 277 | g += x; 278 | c = x + y; 279 | x = b + f1(g, h, a) + 0x81c2c92e + words[38]; 280 | y = f2(c, d, e); 281 | f += x; 282 | b = x + y; 283 | x = a + f1(f, g, h) + 0x92722c85 + words[39]; 284 | y = f2(b, c, d); 285 | e += x; 286 | a = x + y; 287 | 288 | // extend to 48 words 289 | for (; i < 48; i++) 290 | words[i] = words[i - 16] 291 | + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) 292 | ^ (words[i - 15] >> 3)) + words[i - 7] 293 | + (rotate(words[i - 2], 17) ^ rotate(words[i - 2], 19) 294 | ^ (words[i - 2] >> 10)); 295 | 296 | // sixth round 297 | x = h + f1(e, f, g) + 0xa2bfe8a1 + words[40]; 298 | y = f2(a, b, c); 299 | d += x; 300 | h = x + y; 301 | x = g + f1(d, e, f) + 0xa81a664b + words[41]; 302 | y = f2(h, a, b); 303 | c += x; 304 | g = x + y; 305 | x = f + f1(c, d, e) + 0xc24b8b70 + words[42]; 306 | y = f2(g, h, a); 307 | b += x; 308 | f = x + y; 309 | x = e + f1(b, c, d) + 0xc76c51a3 + words[43]; 310 | y = f2(f, g, h); 311 | a += x; 312 | e = x + y; 313 | x = d + f1(a, b, c) + 0xd192e819 + words[44]; 314 | y = f2(e, f, g); 315 | h += x; 316 | d = x + y; 317 | x = c + f1(h, a, b) + 0xd6990624 + words[45]; 318 | y = f2(d, e, f); 319 | g += x; 320 | c = x + y; 321 | x = b + f1(g, h, a) + 0xf40e3585 + words[46]; 322 | y = f2(c, d, e); 323 | f += x; 324 | b = x + y; 325 | x = a + f1(f, g, h) + 0x106aa070 + words[47]; 326 | y = f2(b, c, d); 327 | e += x; 328 | a = x + y; 329 | 330 | // extend to 56 words 331 | for (; i < 56; i++) 332 | words[i] = words[i - 16] 333 | + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) 334 | ^ (words[i - 15] >> 3)) + words[i - 7] 335 | + (rotate(words[i - 2], 17) ^ rotate(words[i - 2], 19) 336 | ^ (words[i - 2] >> 10)); 337 | 338 | // seventh round 339 | x = h + f1(e, f, g) + 0x19a4c116 + words[48]; 340 | y = f2(a, b, c); 341 | d += x; 342 | h = x + y; 343 | x = g + f1(d, e, f) + 0x1e376c08 + words[49]; 344 | y = f2(h, a, b); 345 | c += x; 346 | g = x + y; 347 | x = f + f1(c, d, e) + 0x2748774c + words[50]; 348 | y = f2(g, h, a); 349 | b += x; 350 | f = x + y; 351 | x = e + f1(b, c, d) + 0x34b0bcb5 + words[51]; 352 | y = f2(f, g, h); 353 | a += x; 354 | e = x + y; 355 | x = d + f1(a, b, c) + 0x391c0cb3 + words[52]; 356 | y = f2(e, f, g); 357 | h += x; 358 | d = x + y; 359 | x = c + f1(h, a, b) + 0x4ed8aa4a + words[53]; 360 | y = f2(d, e, f); 361 | g += x; 362 | c = x + y; 363 | x = b + f1(g, h, a) + 0x5b9cca4f + words[54]; 364 | y = f2(c, d, e); 365 | f += x; 366 | b = x + y; 367 | x = a + f1(f, g, h) + 0x682e6ff3 + words[55]; 368 | y = f2(b, c, d); 369 | e += x; 370 | a = x + y; 371 | 372 | // extend to 64 words 373 | for (; i < 64; i++) 374 | words[i] = words[i - 16] 375 | + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) 376 | ^ (words[i - 15] >> 3)) + words[i - 7] 377 | + (rotate(words[i - 2], 17) ^ rotate(words[i - 2], 19) 378 | ^ (words[i - 2] >> 10)); 379 | 380 | // eigth round 381 | x = h + f1(e, f, g) + 0x748f82ee + words[56]; 382 | y = f2(a, b, c); 383 | d += x; 384 | h = x + y; 385 | x = g + f1(d, e, f) + 0x78a5636f + words[57]; 386 | y = f2(h, a, b); 387 | c += x; 388 | g = x + y; 389 | x = f + f1(c, d, e) + 0x84c87814 + words[58]; 390 | y = f2(g, h, a); 391 | b += x; 392 | f = x + y; 393 | x = e + f1(b, c, d) + 0x8cc70208 + words[59]; 394 | y = f2(f, g, h); 395 | a += x; 396 | e = x + y; 397 | x = d + f1(a, b, c) + 0x90befffa + words[60]; 398 | y = f2(e, f, g); 399 | h += x; 400 | d = x + y; 401 | x = c + f1(h, a, b) + 0xa4506ceb + words[61]; 402 | y = f2(d, e, f); 403 | g += x; 404 | c = x + y; 405 | x = b + f1(g, h, a) + 0xbef9a3f7 + words[62]; 406 | y = f2(c, d, e); 407 | f += x; 408 | b = x + y; 409 | x = a + f1(f, g, h) + 0xc67178f2 + words[63]; 410 | y = f2(b, c, d); 411 | e += x; 412 | a = x + y; 413 | 414 | // update hash 415 | m_hash[0] += a; 416 | m_hash[1] += b; 417 | m_hash[2] += c; 418 | m_hash[3] += d; 419 | m_hash[4] += e; 420 | m_hash[5] += f; 421 | m_hash[6] += g; 422 | m_hash[7] += h; 423 | } 424 | 425 | /// add arbitrary number of bytes 426 | void SHA256::add(const void* data, size_t numBytes) { 427 | const uint8_t* current = (const uint8_t*) data; 428 | 429 | if (m_bufferSize > 0) { 430 | while (numBytes > 0 && m_bufferSize < BlockSize) { 431 | m_buffer[m_bufferSize++] = *current++; 432 | numBytes--; 433 | } 434 | } 435 | 436 | // full buffer 437 | if (m_bufferSize == BlockSize) { 438 | processBlock(m_buffer); 439 | m_numBytes += BlockSize; 440 | m_bufferSize = 0; 441 | } 442 | 443 | // no more data ? 444 | if (numBytes == 0) 445 | return; 446 | 447 | // process full blocks 448 | while (numBytes >= BlockSize) { 449 | processBlock(current); 450 | current += BlockSize; 451 | m_numBytes += BlockSize; 452 | numBytes -= BlockSize; 453 | } 454 | 455 | // keep remaining bytes in buffer 456 | while (numBytes > 0) { 457 | m_buffer[m_bufferSize++] = *current++; 458 | numBytes--; 459 | } 460 | } 461 | 462 | /// process final block, less than 64 bytes 463 | void SHA256::processBuffer() { 464 | // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte 465 | 466 | // - append "1" bit to message 467 | // - append "0" bits until message length in bit mod 512 is 448 468 | // - append length as 64 bit integer 469 | 470 | // number of bits 471 | size_t paddedLength = m_bufferSize * 8; 472 | 473 | // plus one bit set to 1 (always appended) 474 | paddedLength++; 475 | 476 | // number of bits must be (numBits % 512) = 448 477 | size_t lower11Bits = paddedLength & 511; 478 | if (lower11Bits <= 448) 479 | paddedLength += 448 - lower11Bits; 480 | else 481 | paddedLength += 512 + 448 - lower11Bits; 482 | // convert from bits to bytes 483 | paddedLength /= 8; 484 | 485 | // only needed if additional data flows over into a second block 486 | unsigned char extra[BlockSize]; 487 | 488 | // append a "1" bit, 128 => binary 10000000 489 | if (m_bufferSize < BlockSize) 490 | m_buffer[m_bufferSize] = 128; 491 | else 492 | extra[0] = 128; 493 | 494 | size_t i; 495 | for (i = m_bufferSize + 1; i < BlockSize; i++) 496 | m_buffer[i] = 0; 497 | for (; i < paddedLength; i++) 498 | extra[i - BlockSize] = 0; 499 | 500 | // add message length in bits as 64 bit number 501 | uint64_t msgBits = 8 * (m_numBytes + m_bufferSize); 502 | // find right position 503 | unsigned char* addLength; 504 | if (paddedLength < BlockSize) 505 | addLength = m_buffer + paddedLength; 506 | else 507 | addLength = extra + paddedLength - BlockSize; 508 | 509 | // must be big endian 510 | *addLength++ = (msgBits >> 56) & 0xFF; 511 | *addLength++ = (msgBits >> 48) & 0xFF; 512 | *addLength++ = (msgBits >> 40) & 0xFF; 513 | *addLength++ = (msgBits >> 32) & 0xFF; 514 | *addLength++ = (msgBits >> 24) & 0xFF; 515 | *addLength++ = (msgBits >> 16) & 0xFF; 516 | *addLength++ = (msgBits >> 8) & 0xFF; 517 | *addLength = msgBits & 0xFF; 518 | 519 | // process blocks 520 | processBlock(m_buffer); 521 | // flowed over into a second block ? 522 | if (paddedLength > BlockSize) 523 | processBlock(extra); 524 | } 525 | 526 | /// return latest hash as 16 hex characters 527 | /* Modified from original source code. Using char* instead of string. */ 528 | char* SHA256::getHash() { 529 | // convert hash to string 530 | static const char dec2hex[16 + 1] = "0123456789abcdef"; 531 | 532 | // save old hash if buffer is partially filled 533 | uint32_t oldHash[HashValues]; 534 | for (int i = 0; i < HashValues; i++) 535 | oldHash[i] = m_hash[i]; 536 | 537 | // process remaining bytes 538 | processBuffer(); 539 | 540 | // create hash string 541 | /* Modified from original source code. Creating char* instead of string. */ 542 | char* hashBuffer = new char[HashValues * 8 + 1](); 543 | size_t offset = 0; 544 | for (int i = 0; i < HashValues; i++) { 545 | hashBuffer[offset++] = dec2hex[(m_hash[i] >> 28) & 15]; 546 | hashBuffer[offset++] = dec2hex[(m_hash[i] >> 24) & 15]; 547 | hashBuffer[offset++] = dec2hex[(m_hash[i] >> 20) & 15]; 548 | hashBuffer[offset++] = dec2hex[(m_hash[i] >> 16) & 15]; 549 | hashBuffer[offset++] = dec2hex[(m_hash[i] >> 12) & 15]; 550 | hashBuffer[offset++] = dec2hex[(m_hash[i] >> 8) & 15]; 551 | hashBuffer[offset++] = dec2hex[(m_hash[i] >> 4) & 15]; 552 | hashBuffer[offset++] = dec2hex[m_hash[i] & 15]; 553 | 554 | // restore old hash 555 | m_hash[i] = oldHash[i]; 556 | } 557 | // zero-terminated string 558 | hashBuffer[offset] = 0; 559 | 560 | return hashBuffer; 561 | } 562 | 563 | /* This function added to original source. It is a modified version of 564 | * getHash() from above. */ 565 | /// return latest hash raw (not as hex) 566 | char* SHA256::getHashDec() { 567 | // save old hash if buffer is partially filled 568 | uint32_t oldHash[HashValues]; 569 | for (int i = 0; i < HashValues; i++) 570 | oldHash[i] = m_hash[i]; 571 | 572 | // process remaining bytes 573 | processBuffer(); 574 | 575 | // create hash string 576 | /* Modified from original source code. Creating char* instead of string. */ 577 | char* hashBuffer = new char[HashValues * 4 + 1](); 578 | size_t offset = 0; 579 | for (int i = 0; i < HashValues; i++) { 580 | hashBuffer[offset++] = (m_hash[i] >> 24) & 0xff; 581 | hashBuffer[offset++] = (m_hash[i] >> 16) & 0xff; 582 | hashBuffer[offset++] = (m_hash[i] >> 8) & 0xff; 583 | hashBuffer[offset++] = m_hash[i] & 0xff; 584 | // restore old hash 585 | m_hash[i] = oldHash[i]; 586 | } 587 | // zero-terminated string 588 | hashBuffer[offset] = 0; 589 | 590 | return hashBuffer; 591 | } 592 | 593 | /// compute SHA256 of a memory block 594 | /* Modified from original source code. Using char* instead of string. */ 595 | char* SHA256::operator()(const void* data, size_t numBytes) { 596 | reset(); 597 | add(data, numBytes); 598 | return getHash(); 599 | } 600 | 601 | /* These lines have been discarded from the original source code. std::string object 602 | * is not necessarilly included on the devices that will use this SDK.*/ 603 | ///// compute SHA256 of a string, excluding final zero 604 | //std::string SHA256::operator()(const std::string& text) 605 | //{ 606 | // reset(); 607 | // add(text.c_str(), text.size()); 608 | // return getHash(); 609 | //} 610 | -------------------------------------------------------------------------------- /AWS/sha256.h: -------------------------------------------------------------------------------- 1 | // ////////////////////////////////////////////////////////// 2 | // sha256.h 3 | // Copyright (c) 2014 Stephan Brumme. All rights reserved. 4 | // see http://create.stephan-brumme.com/disclaimer.html 5 | // 6 | 7 | #pragma once 8 | 9 | //#include "hash.h" 10 | 11 | /* This include statement has been discarded from the original source code. Not 12 | * using string object as it is not necessarilly included on the devices that 13 | * will use this SDK. */ 14 | //#include 15 | // define fixed size integer types 16 | #ifdef _MSC_VER 17 | // Windows 18 | typedef unsigned __int8 uint8_t; 19 | typedef unsigned __int32 uint32_t; 20 | typedef unsigned __int64 uint64_t; 21 | #else 22 | // GCC 23 | #include 24 | #endif 25 | // This line added to original source code. defines size_t. 26 | #include "stddef.h" 27 | 28 | /// compute SHA256 hash 29 | /** Usage: 30 | SHA256 sha256; 31 | std::string myHash = sha256("Hello World"); // std::string 32 | std::string myHash2 = sha256("How are you", 11); // arbitrary data, 11 bytes 33 | 34 | // or in a streaming fashion: 35 | 36 | SHA256 sha256; 37 | while (more data available) 38 | sha256.add(pointer to fresh data, number of new bytes); 39 | std::string myHash3 = sha256.getHash(); 40 | */ 41 | class SHA256 //: public Hash 42 | { 43 | public: 44 | /// same as reset() 45 | SHA256(); 46 | 47 | /// compute SHA256 of a memory block 48 | /* Modified from original source code. Using char* instead of string. */ 49 | char* operator()(const void* data, size_t numBytes); 50 | /// compute SHA256 of a string, excluding final zero 51 | /* Modified from original source code. Using char* instead of string. */ 52 | char* operator()(const char* text); 53 | 54 | /// add arbitrary number of bytes 55 | void add(const void* data, size_t numBytes); 56 | 57 | /// return latest hash as 16 hex characters 58 | /* Modified from original source code. Using char* instead of string. */ 59 | char* getHash(); 60 | 61 | /* This function added to original source. */ 62 | /// return latest hash raw (not as hex) 63 | char* getHashDec(); 64 | 65 | /// restart 66 | void reset(); 67 | 68 | private: 69 | /// process 64 bytes 70 | void processBlock(const void* data); 71 | /// process everything left in the internal buffer 72 | void processBuffer(); 73 | 74 | /// split into 64 byte blocks (=> 512 bits) 75 | enum { 76 | BlockSize = 512 / 8, HashValues = 8 77 | }; 78 | 79 | /// size of processed data in bytes 80 | uint64_t m_numBytes; 81 | /// valid bytes in m_buffer 82 | size_t m_bufferSize; 83 | /// bytes not processed yet 84 | uint8_t m_buffer[BlockSize]; 85 | /// hash, stored as integers 86 | uint32_t m_hash[8]; 87 | }; 88 | -------------------------------------------------------------------------------- /AWS_Get-SetDemo/AWS_Get-SetDemo.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "AmazonDynamoDBClient.h" 13 | #include "Esp8266AWSImplementations.h" 14 | #include "AWSFoundationalTypes.h" 15 | #include 16 | #include "keys.h" 17 | 18 | extern "C" { 19 | #include "user_interface.h" 20 | } 21 | 22 | /* 23 | * 24 | * This sample uses GetItem on a DynamoDB table to retrieve the RGB state 25 | * and SetItem to set the RGB state. 26 | * 27 | * For this demo to work you must have keys.h/.ccp files that contain your AWS 28 | * access keys and define "awsSecKey" and "awsKeyID", a DynamoDB table with the 29 | * name defined by the constant TABLE_NAME with hash and range keys as defined 30 | * by constants HASH_KEY_NAME/RANGE_KEY_NAME, and and item in that table with 31 | * attributes as defined by HASH_KEY_VALUE/RANGE_KEY_VALUE and number 32 | * attributes R G and B. 33 | * 34 | */ 35 | 36 | 37 | //GPIO pin assignments 38 | #define LED_IND 16 // LED used for initial code testing (not included in final hardware design) 39 | // If present, the LED is initially ON and is set OFF during the setup() function 40 | 41 | // Serial baud and server port (customize to your liking) 42 | #define SERBAUD 74880 43 | #define SVRPORT 9703 44 | 45 | /* Contants describing DynamoDB table and values being used. */ 46 | static const char* HASH_KEY_NAME = "DemoName"; 47 | static const char* HASH_KEY_VALUE = "Colors"; 48 | static const char* RANGE_KEY_NAME = "id"; 49 | static const char* RANGE_KEY_VALUE = "1"; 50 | static const char* TABLE_NAME = "AWSArduinoSDKDemo"; 51 | static const int KEY_SIZE = 2; 52 | /* Constants for connecting to DynamoDB. */ 53 | static const char* AWS_REGION = "us-west-2"; //<<---CHANGE IF NECESSARY 54 | static const char* AWS_ENDPOINT = "amazonaws.com"; 55 | 56 | ///////////////////////////////////////////////////////////////// 57 | //Network Parameters: You must customize for your network 58 | ///////////////////////////////////////////////////////////////// 59 | const char* ssid = "YOUR SSID"; //<<---CHANGE AS NECESSARY 60 | const char* password = "YOURWIFIPASSWORD"; //<<---CHANGE AS NECESSARY 61 | const IPAddress ipadd(192,168,0,174); //<<---CHANGE AS NECESSARY 62 | const IPAddress ipgat(192,168,0,1); //<<---CHANGE AS NECESSARY 63 | const IPAddress ipsub(255,255,255,0); 64 | 65 | char szInfo[80]; 66 | char szT[40]; 67 | 68 | /* Device independent implementations required for AmazonDynamoDBClient to 69 | * function. */ 70 | Esp8266HttpClient httpClient; 71 | Esp8266DateTimeProvider dateTimeProvider; 72 | 73 | AmazonDynamoDBClient ddbClient; 74 | 75 | PutItemInput putItemInput; //Put Item 76 | GetItemInput getItemInput; //Get Item 77 | AttributeValue hashKey; 78 | AttributeValue rangeKey; 79 | ActionError actionError; 80 | 81 | // Create an instance of the server 82 | // specify the port to listen on as an argument 83 | WiFiServer server(SVRPORT); 84 | WiFiClient client; 85 | WiFiClient client2; 86 | 87 | 88 | void startWIFI(void) { 89 | //set IP if not correct 90 | IPAddress ip = WiFi.localIP(); 91 | //if( (ip[0]!=ipadd[0]) || (ip[1]!=ipadd[1]) || (ip[2]!=ipadd[2]) || (ip[3]!=ipadd[3]) ) { 92 | if( ip!= ipadd) { 93 | WiFi.config(ipadd, ipgat, ipsub); 94 | Serial.println(); 95 | delay(10); 96 | Serial.print("ESP8266 IP:"); 97 | delay(10); 98 | Serial.println(ip); 99 | delay(10); 100 | Serial.print("Fixed IP:"); 101 | delay(10); 102 | Serial.println(ipadd); 103 | delay(10); 104 | Serial.print("IP now set to: "); 105 | delay(10); 106 | Serial.println(WiFi.localIP()); 107 | delay(10); 108 | } 109 | // Connect to WiFi network 110 | Serial.println(); 111 | delay(10); 112 | Serial.println(); 113 | delay(10); 114 | Serial.print("Connecting to "); 115 | delay(10); 116 | Serial.println(ssid); 117 | delay(10); 118 | WiFi.begin(ssid, password); 119 | 120 | while (WiFi.status() != WL_CONNECTED) { 121 | Serial.print("."); 122 | delay(500); 123 | } 124 | Serial.println(""); 125 | Serial.println("WiFi connected"); 126 | 127 | // Start the server 128 | server.begin(); 129 | Serial.println("Server started"); 130 | 131 | // Print the IP address 132 | Serial.print("ESP8266 IP: "); 133 | Serial.println(WiFi.localIP()); 134 | 135 | Serial.print("ESP8266 WebServer Port: "); 136 | Serial.println(SVRPORT); 137 | delay(300); 138 | 139 | } 140 | 141 | void setup() { 142 | /* Begin serial communication. */ 143 | Serial.begin(SERBAUD); 144 | Serial.println("Starting Setup"); 145 | 146 | startWIFI(); 147 | 148 | /* Initialize ddbClient. */ 149 | ddbClient.setAWSRegion(AWS_REGION); 150 | ddbClient.setAWSEndpoint(AWS_ENDPOINT); 151 | ddbClient.setAWSSecretKey(awsSecKey); 152 | ddbClient.setAWSKeyID(awsKeyID); 153 | ddbClient.setHttpClient(&httpClient); 154 | ddbClient.setDateTimeProvider(&dateTimeProvider); 155 | 156 | /* Use GPIO16 for LED Indicator */ 157 | pinMode(LED_IND , OUTPUT); 158 | digitalWrite(LED_IND, 0); //Turn LED OFF (Setup completed) 159 | } 160 | 161 | void yieldEspCPU(void) { 162 | delay(100); 163 | ESP.wdtFeed(); 164 | yield(); 165 | } 166 | 167 | void getColors(int *R, int *G, int *B, GetItemOutput getItemOutput) { 168 | char szC[6]; 169 | Serial.println("GetItem succeeded!"); 170 | yieldEspCPU(); 171 | 172 | /* Get the "item" from the getItem output. */ 173 | MinimalMap < AttributeValue > attributeMap = getItemOutput.getItem(); 174 | AttributeValue av; 175 | 176 | // Get the rgb values and set the led with them. // 177 | attributeMap.get("R", av); 178 | *R = atoi(av.getS().getCStr()); 179 | Serial.print("Red value read: "); 180 | Serial.println(*R); 181 | 182 | attributeMap.get("G", av); 183 | *G = atoi(av.getS().getCStr()); 184 | Serial.print("Green value read: "); 185 | Serial.println(*G); 186 | 187 | attributeMap.get("B", av); 188 | *B = atoi(av.getS().getCStr()); 189 | Serial.print("Blue value read: "); 190 | Serial.println(*B); 191 | 192 | delay(10); 193 | Serial.print("\n\n"); 194 | } 195 | 196 | void awsGetRGB(int *R, int *G, int *B) { 197 | 198 | // Set the string and number values for the range and hash Keys, respectively. 199 | hashKey.setS(HASH_KEY_VALUE); 200 | rangeKey.setN(RANGE_KEY_VALUE); 201 | 202 | ////////////////////////////////////////////////////////////////////////////////////////// 203 | // Create key-value pairs out of the hash and range keys, and create a map out off them, 204 | // which is the key. 205 | ////////////////////////////////////////////////////////////////////////////////////////// 206 | MinimalKeyValuePair < MinimalString, AttributeValue > pair1(HASH_KEY_NAME, hashKey); 207 | MinimalKeyValuePair < MinimalString, AttributeValue > pair2(RANGE_KEY_NAME, rangeKey); 208 | MinimalKeyValuePair keyArray[] = { pair1, pair2 }; 209 | getItemInput.setKey(MinimalMap < AttributeValue > (keyArray, KEY_SIZE)); 210 | 211 | // Looking to get the R G and B values 212 | MinimalString attributesToGet[] = { "R", "G", "B" }; 213 | getItemInput.setAttributesToGet(MinimalList < MinimalString > (attributesToGet, 3)); 214 | 215 | // Set Table Name 216 | getItemInput.setTableName(TABLE_NAME); 217 | 218 | // Perform getItem and check for errors. 219 | GetItemOutput getItemOutput = ddbClient.getItem(getItemInput, actionError); 220 | 221 | ////////////////////////////////////////////////////////// 222 | // AWS DynamoDB get/set serial message header 223 | ////////////////////////////////////////////////////////// 224 | 225 | ddbClient.getESPtime(szInfo); //debug getTime 226 | Serial.print("------------------------------------------\n"); 227 | Serial.print("Loop start time: "); 228 | Serial.print(szInfo); 229 | Serial.print(" GMT\n"); 230 | 231 | Serial.print("Current Free Heap:"); 232 | Serial.println(system_get_free_heap_size()); 233 | Serial.println("------------------------------------------\n"); 234 | 235 | ////////////////////////////////////////////////////////// 236 | // AWS HTTP Request/Response (uncomment for debug) 237 | ////////////////////////////////////////////////////////// 238 | /************************************************ 239 | Serial.println("AWS Request:\n--------------\n"); 240 | Serial.println(ddbClient.szR); //HTTP Request 241 | 242 | Serial.println("AWS Reply:\n--------------\n"); 243 | Serial.println(ddbClient.szResponse); //HTTP Response 244 | *************************************************/ 245 | 246 | switch (actionError) { 247 | case NONE_ACTIONERROR: 248 | getColors(R,G,B,getItemOutput); 249 | break; 250 | 251 | case INVALID_REQUEST_ACTIONERROR: 252 | Serial.print("ERROR: "); 253 | Serial.println(getItemOutput.getErrorMessage().getCStr()); 254 | break; 255 | case MISSING_REQUIRED_ARGS_ACTIONERROR: 256 | Serial.println("ERROR: Required arguments were not set for GetItemInput"); 257 | break; 258 | case RESPONSE_PARSING_ACTIONERROR: 259 | Serial.println("ERROR: Problem parsing http response of GetItem\n"); 260 | break; 261 | case CONNECTION_ACTIONERROR: 262 | Serial.println("ERROR: Connection problem"); 263 | break; 264 | } 265 | } 266 | 267 | void awsSetRGB(int *R, int *G, int *B) { 268 | //Now lets change the RGB color values and put them to DynamoDB 269 | // Create an Item. // 270 | AttributeValue deviceValue; 271 | deviceValue.setS(HASH_KEY_VALUE); 272 | AttributeValue rValue; 273 | AttributeValue gValue; 274 | AttributeValue bValue; 275 | //Increment and set color 276 | String(++*R).toCharArray(szT,10); 277 | rValue.setS(szT); 278 | String(++*G).toCharArray(szT,10); 279 | gValue.setS(szT); 280 | String(++*B).toCharArray(szT,10); 281 | bValue.setS(szT); 282 | 283 | MinimalKeyValuePair < MinimalString, AttributeValue > att1(HASH_KEY_NAME, hashKey); 284 | MinimalKeyValuePair < MinimalString, AttributeValue > att2(RANGE_KEY_NAME, rangeKey); 285 | MinimalKeyValuePair < MinimalString, AttributeValue > att3("R", rValue); 286 | MinimalKeyValuePair < MinimalString, AttributeValue > att4("G", gValue); 287 | MinimalKeyValuePair < MinimalString, AttributeValue > att5("B", bValue); 288 | MinimalKeyValuePair < MinimalString, AttributeValue > itemArray[] = { att1, att2, att3, att4, att5}; 289 | 290 | // Set values for putItemInput. // 291 | putItemInput.setItem(MinimalMap < AttributeValue > (itemArray, 5)); 292 | putItemInput.setTableName(TABLE_NAME); 293 | 294 | // perform putItem and check for errors. // 295 | PutItemOutput putItemOutput = ddbClient.putItem(putItemInput, actionError); 296 | switch (actionError) { 297 | case NONE_ACTIONERROR: 298 | Serial.println("PutItem succeeded!"); 299 | Serial.print("Red set to: "); 300 | Serial.println(*R); 301 | Serial.print("Green set to: "); 302 | Serial.println(*G); 303 | Serial.print("Blue set to: "); 304 | Serial.println(*B); 305 | Serial.print("\n"); 306 | break; 307 | case INVALID_REQUEST_ACTIONERROR: 308 | Serial.print("ERROR: "); 309 | Serial.println(putItemOutput.getErrorMessage().getCStr()); 310 | break; 311 | case MISSING_REQUIRED_ARGS_ACTIONERROR: 312 | Serial.println( 313 | "ERROR: Required arguments were not set for PutItemInput"); 314 | break; 315 | case RESPONSE_PARSING_ACTIONERROR: 316 | Serial.println("ERROR: Problem parsing http response of PutItem"); 317 | break; 318 | case CONNECTION_ACTIONERROR: 319 | Serial.println("ERROR: Connection problem"); 320 | break; 321 | } 322 | } 323 | ///////////////////////////////////////////////////////////////////////////////// 324 | // Sketch loop(): 325 | // 1. Gets current RGB values and output to serial port 326 | // 2. Sets RGB values (current value + 1) and output set value to serial port 327 | // 3. yieldEspCPU() prevents ESP timeout resets 328 | ///////////////////////////////////////////////////////////////////////////////// 329 | void loop() { 330 | static int R,G,B; 331 | yieldEspCPU(); 332 | awsGetRGB(&R,&G,&B); 333 | yieldEspCPU(); 334 | awsSetRGB(&R,&G,&B); 335 | yieldEspCPU(); 336 | } 337 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

AWS API for ESP8266 Development Software

2 | 3 | This project interface the ESP8266 with AWS DynamoDB using the Arduino IDE platform. 4 | 5 | Setup: 6 | 7 | 1. Copy the ASW folder to your Arduino "../libraries" folder. 8 | 2. Copy the AWS_Get-SetDemo folder to your Arduino IDE sketchbook folder. 9 | 10 | Operation: 11 | 12 | The ESP8266 sketch: 13 | 1. setup() - connects to your local Wifi and initializes an AWS database client. 14 | - a web server is also started, but is not used for this demo sketch 15 | 16 | 2. loop() - first gets the current RGB values from a dynamoDB table 17 | - then sets the dynamoDB table RGB values to an increment of the value from the 'get' 18 | 19 | The current settings (change if needed in the sketch to match your configuration): 20 | 21 | ESP8266 Static IP: 192.168.0.174 22 | ESP8266 Server Port: 9703 23 | Router IP: 192.168.0.1 24 | 25 | Serial port baud: 74880 bps (Use ESPlorer to monitor ESP8266 serial port) 26 | 27 | AWS Settings: 28 | 29 | The AWS Dynamodb used in this example was based on the following: 30 | 31 | https://github.com/awslabs/aws-sdk-arduino 32 | 33 | See section "Table used by SparkGetItemSample and GalileoSample:" 34 | 35 | 36 | The serial port output from this request will look similar to this: 37 | 38 | Loop start time: 20150810210943 GMT
39 | Current Free Heap:21864 40 | 41 | GetItem succeeded!
42 | Red value read: 125
43 | Green value read: 107
44 | Blue value read: 107
45 | 46 | 47 | PutItem succeeded!
48 | Red set to: 126
49 | Green set to: 108
50 | Blue set to: 108
51 | 52 | Loop start time: 20150810211000 GMT
53 | Current Free Heap:21864 54 | 55 | GetItem succeeded!
56 | Red value read: 126
57 | Green value read: 108
58 | Blue value read: 108
59 | 60 | 61 | PutItem succeeded!
62 | Red set to: 127
63 | Green set to: 109
64 | Blue set to: 109
65 | 66 | Two iterations of the loop() function are shown above. Each iteration has- 67 | 68 | 1. A header with the loop start time in the format: yyyymmddhhmmss GMT 69 | 2. The header also shows the free heap, for troubleshooting in case a memory leak is detected. 70 | 3. The get values are displayed 71 | 4. The get values are incremented and then written (put) to the database 72 | 73 | Note the lapse time between iterations is about 17 seconds. 74 | --------------------------------------------------------------------------------