source: rtos_arduino/trunk/arduino_lib/libraries/Temboo/src/utility/TembooSession.cpp@ 136

Last change on this file since 136 was 136, checked in by ertl-honda, 8 years ago

ライブラリとOS及びベーシックなサンプルの追加.

File size: 7.7 KB
Line 
1/*
2###############################################################################
3#
4# Temboo Arduino library
5#
6# Copyright 2014, Temboo Inc.
7#
8# Licensed under the Apache License, Version 2.0 (the "License");
9# you may not use this file except in compliance with the License.
10# You may obtain a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing,
15# software distributed under the License is distributed on an
16# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17# either express or implied. See the License for the specific
18# language governing permissions and limitations under the License.
19#
20###############################################################################
21*/
22
23#include <string.h>
24#include <stdlib.h>
25#include <avr/pgmspace.h>
26#include "TembooSession.h"
27#include "tmbhmac.h"
28#include "DataFormatter.h"
29
30static const char EOL[] PROGMEM = "\r\n";
31static const char POST[] PROGMEM = "POST ";
32static const char POSTAMBLE[] PROGMEM = " HTTP/1.0"; // Prevent host from using chunked encoding in response.
33static const char HEADER_HOST[] PROGMEM = "Host: ";
34static const char HEADER_ACCEPT[] PROGMEM = "Accept: application/xml";
35static const char HEADER_ORG[] PROGMEM = "x-temboo-domain: /";
36static const char HEADER_DOM[] PROGMEM = "/master";
37static const char HEADER_CONTENT_LENGTH[] PROGMEM = "Content-Length: ";
38static const char HEADER_TIME[] PROGMEM = "x-temboo-time: ";
39static const char BASE_CHOREO_URI[] PROGMEM = "/arcturus-web/api-1.0/ar";
40static const char HEADER_AUTH[] PROGMEM = "x-temboo-authentication: ";
41static const char HEADER_CONTENT_TYPE[] PROGMEM = "Content-Type: text/plain";
42static const char TEMBOO_DOMAIN[] PROGMEM = ".temboolive.com";
43static const char SDK_ID[] PROGMEM = "?source_id=arduinoSDK1";
44
45unsigned long TembooSession::s_timeOffset = 0;
46
47TembooSession::TembooSession(Client& client,
48 IPAddress serverAddr,
49 uint16_t port) : m_client(client) {
50 m_addr = serverAddr;
51 m_port = port;
52 m_sendQueueDepth = 0;
53}
54
55
56void TembooSession::setTime(unsigned long currentTime) {
57 s_timeOffset = currentTime - (millis()/1000);
58}
59
60
61unsigned long TembooSession::getTime() {
62 return s_timeOffset + (millis()/1000);
63}
64
65
66
67int TembooSession::executeChoreo(
68 const char* accountName,
69 const char* appKeyName,
70 const char* appKeyValue,
71 const char* path,
72 const ChoreoInputSet& inputSet,
73 const ChoreoOutputSet& outputSet,
74 const ChoreoPreset& preset) {
75
76 DataFormatter fmt(&inputSet, &outputSet, &preset);
77 char auth[HMAC_HEX_SIZE_BYTES + 1];
78 char buffer[11];
79
80 // We use the current time-of-day as salt on the app key.
81 // We keep track of time-of-day by getting the current time
82 // from the server and applying an offset (the length of time
83 // we've been running.)
84 uint32toa((uint32_t)TembooSession::getTime(), buffer);
85
86 uint16_t contentLength = getAuth(fmt, appKeyValue, buffer, auth);
87
88 m_client.stop();
89 m_client.flush();
90
91 int connected = 0;
92 TEMBOO_TRACE("Connecting: ");
93
94 // reserve space for the "host" string sufficient to hold either the
95 // (dotted-quad) IP address + port, or the default <account>.temboolive.com
96 // host string.
97 int hostLen = (m_addr == INADDR_NONE ? (strlen_P(TEMBOO_DOMAIN) + strlen(accountName) + 1):21);
98 char host[hostLen];
99
100 // If no explicit IP address was specified (the normal case), construct
101 // the "host" string from the account name and the temboo domain name.
102 if (m_addr == INADDR_NONE) {
103 strcpy(host, accountName);
104 strcat_P(host, TEMBOO_DOMAIN);
105 TEMBOO_TRACELN(host);
106 connected = m_client.connect(host, m_port);
107 } else {
108
109 // If an IP address was explicitly specified (presumably for testing purposes),
110 // convert it to a dotted-quad text string.
111 host[0] = '\0';
112 for(int i = 0; i < 4; i++) {
113 uint16toa(m_addr[i], &host[strlen(host)]);
114 strcat(host, ".");
115 }
116
117 // replace the last '.' with ':'
118 host[strlen(host)-1] = ':';
119
120 // append the port number
121 uint16toa(m_port, &host[strlen(host)]);
122
123 TEMBOO_TRACELN(host);
124 connected = m_client.connect(m_addr, m_port);
125 }
126
127 if (connected) {
128
129 TEMBOO_TRACELN("OK. req:");
130 qsendProgmem(POST);
131 qsendProgmem(BASE_CHOREO_URI);
132 qsend(path);
133 qsendProgmem(SDK_ID);
134 qsendlnProgmem(POSTAMBLE);
135
136 // Send our custom authentication header
137 // (app-key-name:hmac)
138 qsendProgmem(HEADER_AUTH);
139 qsend(appKeyName);
140 qsend(":");
141 qsendln(auth);
142
143 // send the standard host header
144 qsendProgmem(HEADER_HOST);
145 qsendln(host);
146
147 // send the standard accept header
148 qsendlnProgmem(HEADER_ACCEPT);
149
150 // send our custom account name neader
151 qsendProgmem(HEADER_ORG);
152 qsend(accountName);
153 qsendlnProgmem(HEADER_DOM);
154
155 // send the standard content type header
156 qsendlnProgmem(HEADER_CONTENT_TYPE);
157
158 // send our custom client time header
159 qsendProgmem(HEADER_TIME);
160 qsendln(buffer);
161
162 // send the standard content length header
163 qsendProgmem(HEADER_CONTENT_LENGTH);
164 qsendln(uint16toa(contentLength, buffer));
165
166 qsendProgmem(EOL);
167
168 // Format and send the body of the request
169 fmt.reset();
170 while(fmt.hasNext()) {
171 qsend(fmt.next());
172 }
173
174 qsendProgmem(EOL);
175 qflush();
176 return 0;
177 } else {
178 TEMBOO_TRACELN("FAIL");
179 return 1;
180 }
181}
182
183
184uint16_t TembooSession::getAuth(DataFormatter& fmt, const char* appKeyValue, const char* salt, char* result) const {
185
186 // We need the length of the data for other things, and
187 // this method is a convenient place to calculate it.
188 uint16_t len = 0;
189
190 HMAC hmac;
191
192 //combine the salt and the key and give it to the HMAC calculator
193 size_t keyLength = strlen(appKeyValue) + strlen(salt);
194 char key[keyLength + 1];
195 strcpy(key, salt);
196 strcat(key, appKeyValue);
197 hmac.init((uint8_t*)key, keyLength);
198
199 // process the data a block at a time.
200 uint8_t buffer[HMAC_BLOCK_SIZE_BYTES];
201 int blockCount = 0;
202 fmt.reset();
203 while(fmt.hasNext()) {
204 uint8_t c = fmt.next();
205 len++;
206 buffer[blockCount++] = c;
207 if (blockCount == HMAC_BLOCK_SIZE_BYTES) {
208 hmac.process(buffer, blockCount);
209 blockCount = 0;
210 }
211 }
212 hmac.process(buffer, blockCount);
213
214 // Finalize the HMAC calculation and store the (ASCII HEX) value in *result.
215 hmac.finishHex(result);
216
217 // Return the number of characters processed.
218 return len;
219}
220
221
222void TembooSession::qsend(const char* s) {
223 char c = *s++;
224 while(c != '\0') {
225 qsend(c);
226 c = *s++;
227 }
228}
229
230
231void TembooSession::qsendProgmem(const char* s) {
232 char c = pgm_read_byte(s++);
233 while(c != '\0') {
234 qsend(c);
235 c = pgm_read_byte(s++);
236 }
237}
238
239
240void TembooSession::qsend(char c) {
241 m_sendQueue[m_sendQueueDepth++] = c;
242 if (m_sendQueueDepth >= TEMBOO_SEND_QUEUE_SIZE) {
243 qflush();
244 }
245}
246
247
248void TembooSession::qflush() {
249 m_client.write((const uint8_t*)m_sendQueue, m_sendQueueDepth);
250 TEMBOO_TRACE_BYTES(m_sendQueue, m_sendQueueDepth);
251 m_sendQueueDepth = 0;
252}
253
254
255void TembooSession::qsendln(const char* s) {
256 qsend(s);
257 qsendProgmem(EOL);
258}
259
260
261void TembooSession::qsendlnProgmem(const char* s) {
262 qsendProgmem(s);
263 qsendProgmem(EOL);
264}
265
266
Note: See TracBrowser for help on using the repository browser.