source: asp3_tinet_ecnl_rx/trunk/app1_usb_watt_meter/src/client.c@ 368

Last change on this file since 368 was 368, checked in by coas-nagasima, 5 years ago

必要な情報がない場合はエラーとするよう更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 29.4 KB
Line 
1/*
2 * TOPPERS ECHONET Lite Communication Middleware
3 *
4 * Copyright (C) 2016 Cores Co., Ltd. Japan
5 *
6 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
7 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
8 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
9 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
10 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
11 * スコード中に含まれていること.
12 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
13 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
14 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
15 * の無保証規定を掲載すること.
16 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
17 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
18 * と.
19 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
20 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
21 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
22 * 報告すること.
23 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
24 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
25 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
26 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
27 * 免責すること.
28 *
29 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
30 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
31 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
32 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
33 * の責任を負わない.
34 *
35 * @(#) $Id$
36 */
37#include <lib/curl_config.h>
38#include <lib/curl_setup.h>
39#include <curl/curl.h>
40#include <wolfssl/wolfcrypt/wc_port.h>
41//#include <wolfssl/ssl.h>
42//#include <sys/socket.h>
43#include <string.h>
44#include <kernel.h>
45#include <t_syslog.h>
46#include "echonet_main.h"
47#include "kernel_cfg.h"
48#include "ff.h"
49#include "util/ntstdio.h"
50#include "client.h"
51#include "jsonsl.h"
52
53#define SKIP_PEER_VERIFICATION
54//#define SKIP_HOSTNAME_VERIFICATION
55
56const char SCOPE_DRIVE_FILE[] = "https://www.googleapis.com/auth/drive.file";
57const char GRANT_TYPE_DEVICE[] = "http://oauth.net/grant_type/device/1.0";
58
59char response[80];
60char errbuf[CURL_ERROR_SIZE];
61
62google_drive_t google_drive;
63
64void curl_setopt_common(CURL *curl);
65int google_drive_error_callback(jsonsl_t jsn, jsonsl_error_t err,
66 struct jsonsl_state_st *state, char *errat);
67void google_drive_state_callback(jsonsl_t jsn, jsonsl_action_t action,
68 struct jsonsl_state_st *state, const char *buf);
69
70void client_init(void)
71{
72 google_drive_t *gd = &google_drive;
73 jsonsl_t jsn;
74
75 memset(gd, 0, sizeof(google_drive_t));
76 memcpy(gd->fname, "1:/log/20160101000000.log", sizeof(gd->fname));
77
78 jsn = gd->jsn = jsonsl_new(3);
79 jsn->data = gd;
80 jsn->error_callback = google_drive_error_callback;
81 jsn->action_callback = google_drive_state_callback;
82 jsonsl_enable_all_callbacks(jsn);
83
84 //uITRON4_minit(ITRON_POOL_SIZE);
85
86 curl_global_init(CURL_GLOBAL_DEFAULT);
87}
88
89size_t write_callback(void *buffer, size_t size, size_t nmemb, void *arg)
90{
91 google_drive_t *gd = (google_drive_t *)arg;
92 jsonsl_t jsn = gd->jsn;
93 size_t len = size * nmemb, pos;
94 jsonsl_char_t data;
95
96 for (pos = 0; pos < len; pos++) {
97 data = *((jsonsl_char_t *)&((uint8_t *)buffer)[pos]);
98
99 if ((gd->jsn_buf_pos >= 0) && (gd->jsn_buf_pos < sizeof(gd->jsn_buf)))
100 gd->jsn_buf[gd->jsn_buf_pos++] = data;
101 jsonsl_feed(jsn, &data, 1);
102 }
103
104 return len;
105}
106
107void get_device_id_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
108{
109 switch (gd->state) {
110 case psRoot:
111 if (state->level != 2) {
112 break;
113 }
114 else if (strcmp(buf, "device_code") == 0) {
115 gd->state = psDeviceCode;
116 }
117 else if (strcmp(buf, "user_code") == 0) {
118 gd->state = psUserCode;
119 }
120 else if (strcmp(buf, "expires_in") == 0) {
121 gd->state = psExpiresIn;
122 }
123 else if (strcmp(buf, "interval") == 0) {
124 gd->state = psInterval;
125 }
126 else if (strcmp(buf, "verification_url") == 0) {
127 gd->state = psVerificationUrl;
128 }
129 else if (strcmp(buf, "error") == 0) {
130 gd->state = psError;
131 }
132 else if (strcmp(buf, "error_description") == 0) {
133 gd->state = psErrorDescription;
134 }
135 break;
136 case psDeviceCode:
137 if (state->type == JSONSL_T_STRING) {
138 strlcpy(gd->credential.device_code, buf, sizeof(gd->credential.device_code));
139 gd->state = psRoot;
140 }
141 break;
142 case psUserCode:
143 if (state->type == JSONSL_T_STRING) {
144 strlcpy(gd->credential.user_code, buf, sizeof(gd->credential.user_code));
145 gd->state = psRoot;
146 }
147 break;
148 case psExpiresIn:
149 if (state->type == JSONSL_T_SPECIAL) {
150 gd->credential.expires_in = atoi(buf);
151 gd->state = psRoot;
152 }
153 break;
154 case psInterval:
155 if (state->type == JSONSL_T_SPECIAL) {
156 gd->credential.interval = atoi(buf);
157 gd->state = psRoot;
158 }
159 break;
160 case psVerificationUrl:
161 if (state->type == JSONSL_T_STRING) {
162 strlcpy(gd->credential.verification_url, buf, sizeof(gd->credential.verification_url));
163 gd->state = psRoot;
164 }
165 break;
166 case psError:
167 if (state->type == JSONSL_T_STRING) {
168 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
169 gd->state = psRoot;
170 }
171 break;
172 case psErrorDescription:
173 if (state->type == JSONSL_T_STRING) {
174 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
175 gd->state = psRoot;
176 }
177 break;
178 }
179}
180
181void get_device_id_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
182{
183}
184
185int get_device_id(google_drive_t *gd, const char *scope)
186{
187 client_info_t *client_info = &gd->client_info;
188 credential_t *credential = &gd->credential;
189 CURLcode ret;
190 CURL *curl;
191 struct curl_slist *slist1;
192 size_t len;
193 char *postdata;
194 jsonsl_t jsn = gd->jsn;
195
196 len = strnlen(client_info->client_id, sizeof(client_info->client_id));
197 if (len == 0)
198 return -1;
199
200 gd->jsn_buf_pos = -1;
201
202 jsonsl_reset(jsn);
203 gd->start = get_device_id_state_start;
204 gd->end = get_device_id_state_end;
205
206 slist1 = NULL;
207 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
208
209 curl = curl_easy_init();
210
211 char *client_id = curl_easy_escape(curl, client_info->client_id, len);
212 char *esc_scope = curl_easy_escape(curl, scope, strlen(scope));
213
214 len = sizeof("client_id=") + strlen(client_id) + sizeof("scope=") + strlen(esc_scope);
215 postdata = malloc(len);
216 snprintf(postdata, len, "client_id=%s&scope=%s", client_id, esc_scope);
217
218 curl_free(client_id);
219 curl_free(esc_scope);
220
221 curl_easy_setopt(curl, CURLOPT_URL, "https://accounts.google.com/o/oauth2/device/code");
222 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
223 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
224 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
225 curl_setopt_common(curl);
226
227 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
228 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
229
230 ret = curl_easy_perform(curl);
231
232 free(postdata);
233
234 curl_easy_cleanup(curl);
235 curl = NULL;
236 curl_slist_free_all(slist1);
237 slist1 = NULL;
238
239 return (int)ret;
240}
241
242void get_access_token_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
243{
244 switch (gd->state) {
245 case psRoot:
246 if (state->level != 2) {
247 break;
248 }
249 else if (strcmp(buf, "access_token") == 0) {
250 gd->state = psAccessToken;
251 }
252 else if (strcmp(buf, "expires_in") == 0) {
253 gd->state = psExpiresIn;
254 }
255 else if (strcmp(buf, "refresh_token") == 0) {
256 gd->state = psRefreshToken;
257 }
258 else if (strcmp(buf, "scope") == 0) {
259 gd->state = psScope;
260 }
261 else if (strcmp(buf, "token_type") == 0) {
262 gd->state = psTokenType;
263 }
264 else if (strcmp(buf, "error") == 0) {
265 gd->state = psError;
266 }
267 else if (strcmp(buf, "error_description") == 0) {
268 gd->state = psErrorDescription;
269 }
270 break;
271 case psAccessToken:
272 if (state->type == JSONSL_T_STRING) {
273 strlcpy(gd->credential.access_token, buf, sizeof(gd->credential.access_token));
274 gd->state = psRoot;
275 }
276 break;
277 case psExpiresIn:
278 if (state->type == JSONSL_T_SPECIAL) {
279 gd->credential.expires_in = atoi(buf);
280 gd->state = psRoot;
281 }
282 break;
283 case psRefreshToken:
284 if (state->type == JSONSL_T_STRING) {
285 strlcpy(gd->credential.refresh_token, buf, sizeof(gd->credential.refresh_token));
286 gd->state = psRoot;
287 }
288 break;
289 case psScope:
290 if (state->type == JSONSL_T_STRING) {
291 strlcpy(gd->credential.scope, buf, sizeof(gd->credential.scope));
292 gd->state = psRoot;
293 }
294 break;
295 case psTokenType:
296 if (state->type == JSONSL_T_STRING) {
297 strlcpy(gd->credential.token_type, buf, sizeof(gd->credential.token_type));
298 gd->state = psRoot;
299 }
300 break;
301 case psError:
302 if (state->type == JSONSL_T_STRING) {
303 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
304 gd->state = psRoot;
305 }
306 break;
307 case psErrorDescription:
308 if (state->type == JSONSL_T_STRING) {
309 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
310 gd->state = psRoot;
311 }
312 break;
313 }
314}
315
316void get_access_token_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
317{
318}
319
320int get_access_token(google_drive_t *gd)
321{
322 client_info_t *client_info = &gd->client_info;
323 credential_t *credential = &gd->credential;
324 CURLcode ret;
325 CURL *curl;
326 struct curl_slist *slist1;
327 size_t len;
328 char *postdata;
329 jsonsl_t jsn = gd->jsn;
330
331 len = strlen(credential->device_code);
332 if (len == 0)
333 return -1;
334
335 gd->jsn_buf_pos = -1;
336
337 jsonsl_reset(jsn);
338 gd->start = get_access_token_state_start;
339 gd->end = get_access_token_state_end;
340
341 slist1 = NULL;
342 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
343
344 curl = curl_easy_init();
345
346 char *client_id = curl_easy_escape(curl, client_info->client_id, strnlen(client_info->client_id, sizeof(client_info->client_id)));
347 char *client_secret = curl_easy_escape(curl, client_info->client_secret, strnlen(client_info->client_secret, sizeof(client_info->client_secret)));
348 char *grant_type = curl_easy_escape(curl, GRANT_TYPE_DEVICE, strnlen(GRANT_TYPE_DEVICE, sizeof(GRANT_TYPE_DEVICE)));
349
350 len = sizeof("client_id=") + strlen(client_id) + sizeof("client_secret=") + strlen(client_secret)
351 + sizeof("code=") + strlen(credential->device_code) + sizeof("grant_type=") + strlen(grant_type);
352 postdata = malloc(len);
353 snprintf(postdata, len, "client_id=%s&client_secret=%s&code=%s&grant_type=%s",
354 client_id, client_secret, credential->device_code, grant_type);
355
356 curl_free(client_id);
357 curl_free(client_secret);
358 curl_free(grant_type);
359
360 curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
361 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
362 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
363 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
364 curl_setopt_common(curl);
365
366 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
367 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
368
369 ret = curl_easy_perform(curl);
370
371 free(postdata);
372
373 curl_easy_cleanup(curl);
374 curl = NULL;
375 curl_slist_free_all(slist1);
376 slist1 = NULL;
377
378 return (int)ret;
379}
380
381void update_access_token_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
382{
383 switch (gd->state) {
384 case psRoot:
385 if (state->level != 2) {
386 break;
387 }
388 else if (strcmp(buf, "access_token") == 0) {
389 gd->state = psAccessToken;
390 }
391 else if (strcmp(buf, "expires_in") == 0) {
392 gd->state = psExpiresIn;
393 }
394 else if (strcmp(buf, "scope") == 0) {
395 gd->state = psScope;
396 }
397 else if (strcmp(buf, "token_type") == 0) {
398 gd->state = psTokenType;
399 }
400 else if (strcmp(buf, "error") == 0) {
401 gd->state = psError;
402 }
403 else if (strcmp(buf, "error_description") == 0) {
404 gd->state = psErrorDescription;
405 }
406 break;
407 case psAccessToken:
408 if (state->type == JSONSL_T_STRING) {
409 strlcpy(gd->credential.access_token, buf, sizeof(gd->credential.access_token));
410 gd->state = psRoot;
411 }
412 break;
413 case psExpiresIn:
414 if (state->type == JSONSL_T_SPECIAL) {
415 gd->credential.expires_in = atoi(buf);
416 gd->state = psRoot;
417 }
418 break;
419 case psScope:
420 if (state->type == JSONSL_T_STRING) {
421 strlcpy(gd->credential.scope, buf, sizeof(gd->credential.scope));
422 gd->state = psRoot;
423 }
424 break;
425 case psTokenType:
426 if (state->type == JSONSL_T_STRING) {
427 strlcpy(gd->credential.token_type, buf, sizeof(gd->credential.token_type));
428 gd->state = psRoot;
429 }
430 break;
431 case psError:
432 if (state->type == JSONSL_T_STRING) {
433 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
434 gd->state = psRoot;
435 }
436 break;
437 case psErrorDescription:
438 if (state->type == JSONSL_T_STRING) {
439 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
440 gd->state = psRoot;
441 }
442 break;
443 }
444}
445
446void update_access_token_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
447{
448}
449
450int update_access_token(google_drive_t *gd)
451{
452 client_info_t *client_info = &gd->client_info;
453 credential_t *credential = &gd->credential;
454 CURLcode ret;
455 CURL *curl;
456 struct curl_slist *slist1;
457 size_t len;
458 char *postdata;
459 jsonsl_t jsn = gd->jsn;
460
461 len = strlen(credential->refresh_token);
462 if (len == 0)
463 return -1;
464
465 gd->jsn_buf_pos = -1;
466
467 jsonsl_reset(jsn);
468 gd->start = update_access_token_state_start;
469 gd->end = update_access_token_state_end;
470
471 slist1 = NULL;
472 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
473
474 curl = curl_easy_init();
475
476 char *client_id = curl_easy_escape(curl, client_info->client_id, strnlen(client_info->client_id, sizeof(client_info->client_id)));
477 char *client_secret = curl_easy_escape(curl, client_info->client_secret, strnlen(client_info->client_secret, sizeof(client_info->client_secret)));
478
479 len = sizeof("client_id=") + strlen(client_id) + sizeof("client_secret=") + strlen(client_secret)
480 + sizeof("refresh_token=") + strlen(credential->refresh_token);
481 postdata = malloc(len);
482 snprintf(postdata, len, "client_id=%s&client_secret=%s&code=%s&grant_type=refresh_token",
483 client_id, client_secret, credential->refresh_token);
484
485 curl_free(client_id);
486 curl_free(client_secret);
487
488 curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
489 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
490 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
491 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
492 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
493 curl_setopt_common(curl);
494
495 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
496 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
497
498 ret = curl_easy_perform(curl);
499
500 free(postdata);
501
502 curl_easy_cleanup(curl);
503 curl = NULL;
504 curl_slist_free_all(slist1);
505 slist1 = NULL;
506
507 return (int)ret;
508}
509
510void revoke_device_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
511{
512}
513
514void revoke_device_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
515{
516}
517
518int revoke_device(google_drive_t *gd)
519{
520 client_info_t *client_info = &gd->client_info;
521 credential_t *credential = &gd->credential;
522 CURLcode ret;
523 CURL *curl;
524 size_t len;
525 struct curl_slist *slist1;
526 char *postdata;
527 jsonsl_t jsn = gd->jsn;
528
529 len = strlen(credential->access_token);
530 if (len == 0)
531 return -1;
532
533 gd->jsn_buf_pos = -1;
534
535 jsonsl_reset(jsn);
536 gd->start = revoke_device_state_start;
537 gd->end = revoke_device_state_end;
538
539 slist1 = NULL;
540 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
541
542 curl = curl_easy_init();
543
544 len = sizeof("token=") + strlen(credential->access_token);
545 postdata = malloc(len);
546 snprintf(postdata, len, "token=%s", credential->access_token);
547
548 curl_easy_setopt(curl, CURLOPT_URL, "https://accounts.google.com/o/oauth2/revoke");
549 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
550 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
551 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
552 curl_setopt_common(curl);
553
554 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
555 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
556
557 ret = curl_easy_perform(curl);
558
559 free(postdata);
560
561 curl_easy_cleanup(curl);
562 curl = NULL;
563 curl_slist_free_all(slist1);
564 slist1 = NULL;
565
566 return (int)ret;
567}
568
569void upload_file_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
570{
571 switch (gd->state) {
572 case psRoot:
573 if (state->level != 2) {
574 break;
575 }
576 else if (strcmp(buf, "kind") == 0) {
577 gd->state = psKind;
578 }
579 else if (strcmp(buf, "id") == 0) {
580 gd->state = psId;
581 }
582 else if (strcmp(buf, "name") == 0) {
583 gd->state = psName;
584 }
585 else if (strcmp(buf, "mimeType") == 0) {
586 gd->state = psMimeType;
587 }
588 else if (strcmp(buf, "error") == 0) {
589 gd->state = psError;
590 }
591 else if (strcmp(buf, "error_description") == 0) {
592 gd->state = psErrorDescription;
593 }
594 break;
595 case psKind:
596 if (state->type == JSONSL_T_STRING) {
597 strlcpy(gd->file.kind, buf, sizeof(gd->file.kind));
598 gd->state = psRoot;
599 }
600 break;
601 case psId:
602 if (state->type == JSONSL_T_STRING) {
603 strlcpy(gd->file.id, buf, sizeof(gd->file.id));
604 gd->state = psRoot;
605 }
606 break;
607 case psName:
608 if (state->type == JSONSL_T_STRING) {
609 strlcpy(gd->file.name, buf, sizeof(gd->file.name));
610 gd->state = psRoot;
611 }
612 break;
613 case psMimeType:
614 if (state->type == JSONSL_T_STRING) {
615 strlcpy(gd->file.mimeType, buf, sizeof(gd->file.mimeType));
616 gd->state = psRoot;
617 }
618 break;
619 case psError:
620 if (state->type == JSONSL_T_STRING) {
621 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
622 gd->state = psRoot;
623 }
624 break;
625 case psErrorDescription:
626 if (state->type == JSONSL_T_STRING) {
627 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
628 gd->state = psRoot;
629 }
630 break;
631 }
632}
633
634void upload_file_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
635{
636}
637
638size_t read_callback(char *buffer, size_t size, size_t nitems, void *arg)
639{
640 FIL *file = (FIL *)arg;
641 UINT ret = 0;
642 FRESULT res;
643
644 res = f_read(file, buffer, size * nitems, &ret);
645 if (res != FR_OK)
646 return 0;
647
648 int rest = ret;
649 int len;
650
651 while (rest > 0) {
652 len = rest;
653 if (len > (sizeof(response) - 1)) {
654 len = sizeof(response) - 1;
655 }
656
657 memcpy(response, buffer, len);
658
659 response[len] = '\0';
660
661 printf(response);
662
663 dly_tsk(100);
664
665 rest -= len;
666 buffer = (char *)buffer + len;
667 }
668
669 return ret;
670}
671
672int seek_callback(void *arg, curl_off_t offset, int origin)
673{
674 FIL *file = (FIL *)arg;
675 BYTE mode;
676 FRESULT ret;
677
678 switch (origin) {
679 case SEEK_SET:
680 mode = F_SEEK_SET;
681 break;
682 case SEEK_CUR:
683 mode = F_SEEK_CUR;
684 break;
685 case SEEK_END:
686 mode = F_SEEK_END;
687 break;
688 default:
689 return CURL_SEEKFUNC_FAIL;
690 }
691
692 ret = f_seek(file, offset, mode);
693 if (ret != F_OK)
694 return CURL_SEEKFUNC_FAIL;
695
696 return CURL_SEEKFUNC_OK;
697}
698
699int upload_file(google_drive_t *gd, const char *filename, const char *localfilepath)
700{
701 CURLcode ret;
702 CURL *curl;
703 curl_mime *mime;
704 curl_mimepart *part;
705 struct curl_slist *slist1;
706 size_t len;
707 char *postdata, *authorization;
708 static const char buf[] = "Expect:";
709 jsonsl_t jsn = gd->jsn;
710 FIL file;
711 FRESULT fret;
712
713 gd->jsn_buf_pos = -1;
714
715 jsonsl_reset(jsn);
716 gd->start = upload_file_state_start;
717 gd->end = upload_file_state_end;
718
719 fret = f_open(&file, localfilepath, FA_READ);
720 if (fret != FR_OK) {
721 printf("log file open error %d\n", fret);
722 return -1;
723 }
724
725 len = sizeof("{\"name\":\"\"}") + strlen(filename);
726 postdata = malloc(len);
727 snprintf(postdata, len, "{\"name\":\"%s\"}", filename);
728
729 curl = curl_easy_init();
730
731 mime = curl_mime_init(curl);
732 part = curl_mime_addpart(mime);
733 curl_mime_name(part, "metadata");
734 curl_mime_type(part, "application/json;charset=utf-8");
735 curl_mime_data(part, postdata, CURL_ZERO_TERMINATED);
736 free(postdata);
737
738 part = curl_mime_addpart(mime);
739 curl_mime_name(part, "file");
740 curl_mime_type(part, "application/json");
741 curl_mime_data_cb(part, file.fsize, read_callback, seek_callback, NULL, &file);
742
743 len = sizeof("Authorization: Bearer ") + strnlen(gd->credential.access_token, sizeof(gd->credential.access_token));
744 authorization = malloc(len);
745 snprintf(authorization, len, "Authorization: Bearer %s", gd->credential.access_token);
746 slist1 = NULL;
747 slist1 = curl_slist_append(slist1, authorization);
748 free(authorization);
749
750 slist1 = curl_slist_append(slist1, buf);
751
752 curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
753 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
754 curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
755 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
756 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
757 curl_setopt_common(curl);
758
759 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
760 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
761
762 ret = curl_easy_perform(curl);
763
764 curl_easy_cleanup(curl);
765 curl = NULL;
766 curl_mime_free(mime);
767 mime = NULL;
768 curl_slist_free_all(slist1);
769 slist1 = NULL;
770
771 f_close(&file);
772
773 return (int)ret;
774}
775
776int google_drive_error_callback(jsonsl_t jsn, jsonsl_error_t err,
777 struct jsonsl_state_st *state, char *errat)
778{
779 return 0;
780}
781
782void google_drive_state_callback(jsonsl_t jsn, jsonsl_action_t action,
783 struct jsonsl_state_st *state, const char *buf)
784{
785 google_drive_t *gd = (google_drive_t *)jsn->data;
786
787 switch (action) {
788 case JSONSL_ACTION_PUSH:
789 switch (state->type) {
790 case JSONSL_T_SPECIAL:
791 gd->jsn_buf[0] = *buf;
792 gd->jsn_buf_pos = 1;
793 break;
794 case JSONSL_T_STRING:
795 case JSONSL_T_HKEY:
796 gd->jsn_buf_pos = 0;
797 break;
798 default:
799 gd->jsn_buf_pos = -1;
800 }
801 break;
802 case JSONSL_ACTION_POP:
803 switch (state->type) {
804 case JSONSL_T_SPECIAL:
805 case JSONSL_T_STRING:
806 case JSONSL_T_HKEY:
807 gd->jsn_buf_pos--;
808 if (gd->jsn_buf_pos < sizeof(gd->jsn_buf)) {
809 gd->jsn_buf[gd->jsn_buf_pos] = '\0';
810 }
811 gd->start(gd, state, gd->jsn_buf);
812 break;
813 default:
814 gd->jsn_buf[0] = '\0';
815 break;
816 }
817 gd->jsn_buf_pos = -1;
818 break;
819 default:
820 gd->jsn_buf_pos = -1;
821 break;
822 }
823}
824
825static void get_logfname(char *fname)
826{
827 // fname = "0:/log/2016010100000000.log"
828 time_t t;
829 struct tm tm;
830 int tmp1, tmp2;
831 char *pos = &fname[7];
832
833 time(&t);
834 gmtime_r(&t, &tm);
835
836 /* 年 */
837 tmp1 = 1900 + tm.tm_year;
838 tmp2 = tmp1 / 1000;
839 tmp1 -= tmp2 * 1000;
840 *pos++ = '0' + tmp2;
841 tmp2 = tmp1 / 100;
842 tmp1 -= tmp2 * 100;
843 *pos++ = '0' + tmp2;
844 tmp2 = tmp1 / 10;
845 tmp1 -= tmp2 * 10;
846 *pos++ = '0' + tmp2;
847 *pos++ = '0' + tmp1;
848 /* 月 */
849 tmp1 = tm.tm_mon + 1;
850 tmp2 = tmp1 / 10;
851 tmp1 -= tmp2 * 10;
852 *pos++ = '0' + tmp2;
853 *pos++ = '0' + tmp1;
854 /* 日 */
855 tmp1 = tm.tm_mday;
856 tmp2 = tmp1 / 10;
857 tmp1 -= tmp2 * 10;
858 *pos++ = '0' + tmp2;
859 *pos++ = '0' + tmp1;
860 /* 時 */
861 tmp1 = tm.tm_hour;
862 tmp2 = tmp1 / 10;
863 tmp1 -= tmp2 * 10;
864 *pos++ = '0' + tmp2;
865 *pos++ = '0' + tmp1;
866 /* 分 */
867 tmp1 = tm.tm_min;
868 tmp2 = tmp1 / 10;
869 tmp1 -= tmp2 * 10;
870 *pos++ = '0' + tmp2;
871 *pos++ = '0' + tmp1;
872 /* 秒 */
873 tmp1 = tm.tm_sec;
874 tmp2 = tmp1 / 10;
875 tmp1 -= tmp2 * 10;
876 *pos++ = '0' + tmp2;
877 *pos++ = '0' + tmp1;
878}
879
880static FRESULT write_log(char *fname)
881{
882 FIL file;
883 FRESULT ret;
884
885 ret = f_open(&file, fname, FA_CREATE_ALWAYS | FA_WRITE);
886 if (ret != FR_OK) {
887 printf("not open a upload file %d\n", ret);
888 return ret;
889 }
890
891 f_printf(&file, "{\"datetime\":\"");
892 for (int i = 7; i < 21; i++)
893 f_putc(fname[i], &file);
894 f_printf(&file, "\",");
895
896 for (int i = 0; i < 6; i++) {
897 struct watt_hour_meter_t *meter = &electric_energy_meter_data[i];
898 uint32_t *log;
899 int len;
900
901 f_printf(&file, "\"channel%d\":[", i + 1);
902
903 wai_sem(MAIN_SEMAPHORE);
904
905 len = 48 - meter->current_pos;
906 if (len > 0) {
907 log = &meter->integral_electric_energy_measurement_log[meter->current_pos];
908 for (int j = 1; j < len; j++) {
909 f_printf(&file, "%d,", *log);
910 }
911 f_printf(&file, "%d", *log);
912 }
913 len = 48 - len;
914 if (len > 0) {
915 f_putc(',', &file);
916
917 log = &meter->integral_electric_energy_measurement_log[0];
918 for (int j = 1; j < len; j++) {
919 f_printf(&file, "%d,", *log);
920 }
921 f_printf(&file, "%d", *log);
922 }
923
924 sig_sem(MAIN_SEMAPHORE);
925
926 f_putc(']', &file);
927 if (i != 5) {
928 f_putc(',', &file);
929 }
930 }
931
932 f_putc('}', &file);
933
934 f_close(&file);
935
936 return FR_OK;
937}
938
939void curl_setopt_common(CURL *curl)
940{
941 CURLcode res;
942
943 /* ask libcurl to show us the verbose output */
944 res = curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
945 if (res != CURLE_OK)
946 printf("CURLOPT_VERBOSE failed: %s\n",
947 curl_easy_strerror(res));
948
949 /* set the error buffer as empty before performing a request */
950 errbuf[0] = 0;
951
952 /* provide a buffer to store errors in */
953 res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
954 if (res != CURLE_OK)
955 printf("CURLOPT_ERRORBUFFER failed: %s\n",
956 curl_easy_strerror(res));
957
958#ifdef SKIP_PEER_VERIFICATION
959 /*
960 * If you want to connect to a site who isn't using a certificate that is
961 * signed by one of the certs in the CA bundle you have, you can skip the
962 * verification of the server's certificate. This makes the connection
963 * A LOT LESS SECURE.
964 *
965 * If you have a CA cert for the server stored someplace else than in the
966 * default bundle, then the CURLOPT_CAPATH option might come handy for
967 * you.
968 */
969 res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
970 if (res != CURLE_OK)
971 printf("CURLOPT_SSL_VERIFYPEER failed: %s\n",
972 curl_easy_strerror(res));
973#else
974 res = curl_easy_setopt(curl, CURLOPT_CAINFO, "0:/certs/ca-cert.pem");
975 if (res != CURLE_OK)
976 printf("CURLOPT_CAINFO failed: %s\n",
977 curl_easy_strerror(res));
978
979 res = curl_easy_setopt(curl, CURLOPT_SSLCERT, "0:/certs/client-cert.pem");
980 if (res != CURLE_OK)
981 printf("CURLOPT_SSLCERT failed: %s\n",
982 curl_easy_strerror(res));
983
984 res = curl_easy_setopt(curl, CURLOPT_SSLKEY, "0:/certs/client-key.pem");
985 if (res != CURLE_OK)
986 printf("CURLOPT_SSLKEY failed: %s\n",
987 curl_easy_strerror(res));
988#endif
989
990#ifdef SKIP_HOSTNAME_VERIFICATION
991 /*
992 * If the site you're connecting to uses a different host name that what
993 * they have mentioned in their server certificate's commonName (or
994 * subjectAltName) fields, libcurl will refuse to connect. You can skip
995 * this check, but this will make the connection less secure.
996 */
997 res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
998 if (res != CURLE_OK)
999 printf("CURLOPT_SSL_VERIFYHOST failed: %s\n",
1000 curl_easy_strerror(res));
1001#endif
1002
1003 /*res = curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy.example.com:8080");
1004 if (res != CURLE_OK)
1005 printf("CURLOPT_PROXY failed: %s\n",
1006 curl_easy_strerror(res));*/
1007
1008 res = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
1009 if (res != CURLE_OK)
1010 printf("CURLOPT_NOPROGRESS failed: %s\n",
1011 curl_easy_strerror(res));
1012
1013 res = curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
1014 if (res != CURLE_OK)
1015 printf("CURLOPT_MAXREDIRS failed: %s\n",
1016 curl_easy_strerror(res));
1017
1018 res = curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
1019 if (res != CURLE_OK)
1020 printf("CURLOPT_TCP_KEEPALIVE failed: %s\n",
1021 curl_easy_strerror(res));
1022}
1023
1024void client_set_client_id(const char *client_id)
1025{
1026 google_drive_t *gd = &google_drive;
1027
1028 strlcpy(gd->client_info.client_id, client_id, sizeof(gd->client_info.client_id));
1029}
1030
1031void client_set_client_secret(const char *client_secret)
1032{
1033 google_drive_t *gd = &google_drive;
1034
1035 strlcpy(gd->client_info.client_secret, client_secret, sizeof(gd->client_info.client_secret));
1036}
1037
1038int client_get_device_id(int argc, char **argv)
1039{
1040 google_drive_t *gd = &google_drive;
1041 int ret;
1042
1043 ret = get_device_id(gd, SCOPE_DRIVE_FILE);
1044 if (ret == 0) {
1045 printf("Device was registered. Enter the code at the following URL\n");
1046 printf("url: %s\n", gd->credential.verification_url);
1047 printf("code: %s\n", gd->credential.user_code);
1048 }
1049 else {
1050 printf("Device register failed! %d\n", ret);
1051 }
1052
1053 return ret;
1054}
1055
1056int client_get_access_token(int argc, char **argv)
1057{
1058 google_drive_t *gd = &google_drive;
1059 int ret;
1060
1061 ret = get_access_token(gd);
1062 if (ret == 0) {
1063 printf("Access token was give\n");
1064 printf("Refresh token: %s\n", gd->credential.refresh_token);
1065 printf("Access token: %s\n", gd->credential.access_token);
1066 }
1067 else {
1068 printf("Access token gain failed. %d\n", ret);
1069 }
1070
1071 return ret;
1072}
1073
1074int client_update_access_token(int argc, char **argv)
1075{
1076 google_drive_t *gd = &google_drive;
1077 int ret;
1078
1079 ret = update_access_token(gd);
1080 if (ret == 0) {
1081 printf("Access token was update\n");
1082 printf("Access token: %s\n", gd->credential.access_token);
1083 }
1084 else {
1085 printf("Access token update failed. %d\n", ret);
1086 }
1087
1088 return ret;
1089}
1090
1091int client_revoke(int argc, char **argv)
1092{
1093 google_drive_t *gd = &google_drive;
1094 int ret;
1095
1096 ret = revoke_device(gd);
1097 if (ret == 0) {
1098 printf("Device was revoked.\n");
1099 }
1100 else {
1101 printf("Device revoke failed. %d\n", ret);
1102 }
1103
1104 return ret;
1105}
1106
1107int client_upload_file(int argc, char **argv)
1108{
1109 google_drive_t *gd = &google_drive;
1110 int ret;
1111 FRESULT fret;
1112 char fname[] = { "1:/log/20160101000000.log" };
1113
1114 get_logfname(fname);
1115
1116 fret = write_log(fname);
1117 if (fret != FR_OK) {
1118 printf("log file write error %d\n", fret);
1119 return (int)fret;
1120 }
1121
1122 ret = upload_file(gd, &fname[7], fname);
1123 if (ret == 0) {
1124 printf("%s was uploaded.\n", &fname[7]);
1125 }
1126 else {
1127 printf("%s upload failed. %d\n", &fname[7], ret);
1128 }
1129
1130 return ret;
1131}
1132
1133void client_final(void)
1134{
1135 google_drive_t *gd = &google_drive;
1136 jsonsl_t jsn = gd->jsn;
1137
1138 curl_global_cleanup();
1139 jsonsl_destroy(jsn);
1140}
Note: See TracBrowser for help on using the repository browser.