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

Last change on this file was 400, 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: 33.9 KB
Line 
1/*
2 * TOPPERS PROJECT Home Network Working Group Software
3 *
4 * Copyright (C) 2016-2019 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 <stdio.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
64int read_client_info(google_drive_t *gd, const char *fname);
65void curl_setopt_common(CURL *curl);
66int google_drive_error_callback(jsonsl_t jsn, jsonsl_error_t err,
67 struct jsonsl_state_st *state, char *errat);
68void google_drive_state_callback(jsonsl_t jsn, jsonsl_action_t action,
69 struct jsonsl_state_st *state, const char *buf);
70
71void client_init(void)
72{
73 google_drive_t *gd = &google_drive;
74
75 memset(gd, 0, sizeof(google_drive_t));
76 memcpy(gd->fname, "1:/log/20160101000000.log", sizeof(gd->fname));
77
78 read_client_info(gd, "1:/client_secret.json");
79
80 curl_global_init(CURL_GLOBAL_DEFAULT);
81}
82
83size_t write_callback(void *buffer, size_t size, size_t nmemb, void *arg)
84{
85 google_drive_t *gd = (google_drive_t *)arg;
86 jsonsl_t jsn = gd->jsn;
87 size_t len = size * nmemb, pos;
88 jsonsl_char_t data;
89
90 for (pos = 0; pos < len; pos++) {
91 data = *((jsonsl_char_t *)&((uint8_t *)buffer)[pos]);
92
93 if ((gd->jsn_buf_pos >= 0) && (gd->jsn_buf_pos < sizeof(gd->jsn_buf)))
94 gd->jsn_buf[gd->jsn_buf_pos++] = data;
95 jsonsl_feed(jsn, &data, 1);
96 }
97
98 return len;
99}
100
101void client_info_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
102{
103 switch (gd->state) {
104 case psRoot:
105 if (state->level != 2) {
106 break;
107 }
108 else if (strcmp(buf, "installed") == 0) {
109 gd->state = psInstalled;
110 }
111 break;
112 case psInstalled:
113 if (state->level == 2) {
114 gd->state = psRoot;
115 break;
116 }
117 if (state->level != 3) {
118 break;
119 }
120 else if (strcmp(buf, "client_id") == 0) {
121 gd->state = psClientId;
122 }
123 else if (strcmp(buf, "project_id") == 0) {
124 gd->state = psProjectId;
125 }
126 else if (strcmp(buf, "auth_uri") == 0) {
127 gd->state = psAuthUri;
128 }
129 else if (strcmp(buf, "token_uri") == 0) {
130 gd->state = psTokenUri;
131 }
132 else if (strcmp(buf, "auth_provider_x509_cert_url") == 0) {
133 gd->state = psAuthProviderX509CertUrl;
134 }
135 else if (strcmp(buf, "client_secret") == 0) {
136 gd->state = psClientSecret;
137 }
138 else if (strcmp(buf, "redirect_uris") == 0) {
139 gd->state = psRedirectUris;
140 gd->index = 0;
141 }
142 break;
143 case psClientId:
144 if (state->type == JSONSL_T_STRING) {
145 strlcpy(gd->client_info.client_id, buf, sizeof(gd->client_info.client_id));
146 gd->state = psInstalled;
147 }
148 break;
149 case psProjectId:
150 if (state->type == JSONSL_T_STRING) {
151 //strlcpy(gd->client_info.project_id, buf, sizeof(gd->client_info.project_id));
152 gd->state = psInstalled;
153 }
154 break;
155 case psAuthUri:
156 if (state->type == JSONSL_T_STRING) {
157 //strlcpy(gd->client_info.auth_uri, buf, sizeof(gd->client_info.auth_uri));
158 gd->state = psInstalled;
159 }
160 break;
161 case psTokenUri:
162 if (state->type == JSONSL_T_STRING) {
163 //strlcpy(gd->client_info.token_uri, buf, sizeof(gd->client_info.token_uri));
164 gd->state = psInstalled;
165 }
166 break;
167 case psAuthProviderX509CertUrl:
168 if (state->type == JSONSL_T_STRING) {
169 //strlcpy(gd->client_info.auth_provider_x509_cert_url, buf, sizeof(gd->client_info.auth_provider_x509_cert_url));
170 gd->state = psInstalled;
171 }
172 break;
173 case psClientSecret:
174 if (state->type == JSONSL_T_STRING) {
175 strlcpy(gd->client_info.client_secret, buf, sizeof(gd->client_info.client_secret));
176 gd->state = psInstalled;
177 }
178 break;
179 case psRedirectUris:
180 if (state->type == JSONSL_T_STRING) {
181 //strlcpy(gd->client_info.redirect_uris[gd->index], buf, sizeof(gd->client_info.redirect_uris[0]));
182 gd->index++;
183 if (gd->index == 2) {
184 gd->state = psInstalled;
185 }
186 }
187 break;
188 }
189}
190
191void client_info_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
192{
193}
194
195int read_client_info(google_drive_t *gd, const char *fname)
196{
197 FIL file;
198 FRESULT ret;
199 jsonsl_t jsn = gd->jsn = jsonsl_new(5);
200 char buffer[16];
201 size_t len, pos;
202 jsonsl_char_t data;
203
204 jsn->data = gd;
205 jsn->error_callback = google_drive_error_callback;
206 jsn->action_callback = google_drive_state_callback;
207 jsonsl_enable_all_callbacks(jsn);
208
209 gd->jsn_buf_pos = -1;
210 gd->start = client_info_state_start;
211 gd->end = client_info_state_end;
212 gd->state = psRoot;
213
214 ret = f_open(&file, fname, FA_READ);
215 if (ret != FR_OK) {
216 printf("not open %s file %d\n", fname, ret);
217 ret = -1;
218 goto error;
219 }
220
221 for (;;) {
222 len = 0;
223 ret = f_read(&file, buffer, sizeof(buffer), &len);
224 if ((ret != FR_OK) || (len <= 0))
225 break;
226
227 for (pos = 0; pos < len; pos++) {
228 data = *((jsonsl_char_t *)&((uint8_t *)buffer)[pos]);
229
230 if ((gd->jsn_buf_pos >= 0) && (gd->jsn_buf_pos < sizeof(gd->jsn_buf)))
231 gd->jsn_buf[gd->jsn_buf_pos++] = data;
232 jsonsl_feed(jsn, &data, 1);
233 }
234 }
235
236 f_close(&file);
237
238 ret = 0;
239error:
240 gd->jsn = NULL;
241 jsonsl_destroy(jsn);
242
243 return ret;
244}
245
246void get_device_id_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
247{
248 switch (gd->state) {
249 case psRoot:
250 if (state->level != 2) {
251 break;
252 }
253 else if (strcmp(buf, "device_code") == 0) {
254 gd->state = psDeviceCode;
255 }
256 else if (strcmp(buf, "user_code") == 0) {
257 gd->state = psUserCode;
258 }
259 else if (strcmp(buf, "expires_in") == 0) {
260 gd->state = psExpiresIn;
261 }
262 else if (strcmp(buf, "interval") == 0) {
263 gd->state = psInterval;
264 }
265 else if (strcmp(buf, "verification_url") == 0) {
266 gd->state = psVerificationUrl;
267 }
268 else if (strcmp(buf, "error") == 0) {
269 gd->state = psError;
270 }
271 else if (strcmp(buf, "error_description") == 0) {
272 gd->state = psErrorDescription;
273 }
274 break;
275 case psDeviceCode:
276 if (state->type == JSONSL_T_STRING) {
277 strlcpy(gd->credential.device_code, buf, sizeof(gd->credential.device_code));
278 gd->state = psRoot;
279 }
280 break;
281 case psUserCode:
282 if (state->type == JSONSL_T_STRING) {
283 strlcpy(gd->credential.user_code, buf, sizeof(gd->credential.user_code));
284 gd->state = psRoot;
285 }
286 break;
287 case psExpiresIn:
288 if (state->type == JSONSL_T_SPECIAL) {
289 gd->credential.expires_in = atoi(buf);
290 gd->state = psRoot;
291 }
292 break;
293 case psInterval:
294 if (state->type == JSONSL_T_SPECIAL) {
295 gd->credential.interval = atoi(buf);
296 gd->state = psRoot;
297 }
298 break;
299 case psVerificationUrl:
300 if (state->type == JSONSL_T_STRING) {
301 strlcpy(gd->credential.verification_url, buf, sizeof(gd->credential.verification_url));
302 gd->state = psRoot;
303 }
304 break;
305 case psError:
306 if (state->type == JSONSL_T_STRING) {
307 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
308 gd->state = psRoot;
309 }
310 break;
311 case psErrorDescription:
312 if (state->type == JSONSL_T_STRING) {
313 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
314 gd->state = psRoot;
315 }
316 break;
317 }
318}
319
320void get_device_id_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
321{
322}
323
324int get_device_id(google_drive_t *gd, const char *scope)
325{
326 client_info_t *client_info = &gd->client_info;
327 credential_t *credential = &gd->credential;
328 CURLcode ret;
329 CURL *curl;
330 struct curl_slist *slist1;
331 size_t len;
332 char *postdata;
333
334 len = strnlen(client_info->client_id, sizeof(client_info->client_id));
335 if (len == 0)
336 return -1;
337
338 jsonsl_t jsn = gd->jsn = jsonsl_new(3);
339 jsn->data = gd;
340 jsn->error_callback = google_drive_error_callback;
341 jsn->action_callback = google_drive_state_callback;
342 jsonsl_enable_all_callbacks(jsn);
343
344 gd->jsn_buf_pos = -1;
345 gd->start = get_device_id_state_start;
346 gd->end = get_device_id_state_end;
347 gd->state = psRoot;
348
349 slist1 = NULL;
350 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
351
352 curl = curl_easy_init();
353
354 char *client_id = curl_easy_escape(curl, client_info->client_id, len);
355 char *esc_scope = curl_easy_escape(curl, scope, strlen(scope));
356
357 len = sizeof("client_id=") + strlen(client_id) + sizeof("scope=") + strlen(esc_scope);
358 postdata = malloc(len);
359 snprintf(postdata, len, "client_id=%s&scope=%s", client_id, esc_scope);
360
361 curl_free(client_id);
362 curl_free(esc_scope);
363
364 curl_easy_setopt(curl, CURLOPT_URL, "https://accounts.google.com/o/oauth2/device/code");
365 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
366 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
367 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
368 curl_setopt_common(curl);
369
370 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
371 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
372
373 ret = curl_easy_perform(curl);
374
375 free(postdata);
376
377 curl_easy_cleanup(curl);
378 curl = NULL;
379 curl_slist_free_all(slist1);
380 slist1 = NULL;
381
382 gd->jsn = NULL;
383 jsonsl_destroy(jsn);
384
385 return (int)ret;
386}
387
388void get_access_token_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
389{
390 switch (gd->state) {
391 case psRoot:
392 if (state->level != 2) {
393 break;
394 }
395 else if (strcmp(buf, "access_token") == 0) {
396 gd->state = psAccessToken;
397 }
398 else if (strcmp(buf, "expires_in") == 0) {
399 gd->state = psExpiresIn;
400 }
401 else if (strcmp(buf, "refresh_token") == 0) {
402 gd->state = psRefreshToken;
403 }
404 else if (strcmp(buf, "scope") == 0) {
405 gd->state = psScope;
406 }
407 else if (strcmp(buf, "token_type") == 0) {
408 gd->state = psTokenType;
409 }
410 else if (strcmp(buf, "error") == 0) {
411 gd->state = psError;
412 }
413 else if (strcmp(buf, "error_description") == 0) {
414 gd->state = psErrorDescription;
415 }
416 break;
417 case psAccessToken:
418 if (state->type == JSONSL_T_STRING) {
419 strlcpy(gd->credential.access_token, buf, sizeof(gd->credential.access_token));
420 gd->state = psRoot;
421 }
422 break;
423 case psExpiresIn:
424 if (state->type == JSONSL_T_SPECIAL) {
425 gd->credential.expires_in = atoi(buf);
426 gd->state = psRoot;
427 }
428 break;
429 case psRefreshToken:
430 if (state->type == JSONSL_T_STRING) {
431 strlcpy(gd->credential.refresh_token, buf, sizeof(gd->credential.refresh_token));
432 gd->state = psRoot;
433 }
434 break;
435 case psScope:
436 if (state->type == JSONSL_T_STRING) {
437 strlcpy(gd->credential.scope, buf, sizeof(gd->credential.scope));
438 gd->state = psRoot;
439 }
440 break;
441 case psTokenType:
442 if (state->type == JSONSL_T_STRING) {
443 strlcpy(gd->credential.token_type, buf, sizeof(gd->credential.token_type));
444 gd->state = psRoot;
445 }
446 break;
447 case psError:
448 if (state->type == JSONSL_T_STRING) {
449 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
450 gd->state = psRoot;
451 }
452 break;
453 case psErrorDescription:
454 if (state->type == JSONSL_T_STRING) {
455 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
456 gd->state = psRoot;
457 }
458 break;
459 }
460}
461
462void get_access_token_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
463{
464}
465
466int get_access_token(google_drive_t *gd)
467{
468 client_info_t *client_info = &gd->client_info;
469 credential_t *credential = &gd->credential;
470 CURLcode ret;
471 CURL *curl;
472 struct curl_slist *slist1;
473 size_t len;
474 char *postdata;
475
476 len = strlen(credential->device_code);
477 if (len == 0)
478 return -1;
479
480 jsonsl_t jsn = gd->jsn = jsonsl_new(3);
481 jsn->data = gd;
482 jsn->error_callback = google_drive_error_callback;
483 jsn->action_callback = google_drive_state_callback;
484 jsonsl_enable_all_callbacks(jsn);
485
486 gd->jsn_buf_pos = -1;
487 gd->start = get_access_token_state_start;
488 gd->end = get_access_token_state_end;
489 gd->state = psRoot;
490
491 slist1 = NULL;
492 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
493
494 curl = curl_easy_init();
495
496 char *client_id = curl_easy_escape(curl, client_info->client_id, strnlen(client_info->client_id, sizeof(client_info->client_id)));
497 char *client_secret = curl_easy_escape(curl, client_info->client_secret, strnlen(client_info->client_secret, sizeof(client_info->client_secret)));
498 char *grant_type = curl_easy_escape(curl, GRANT_TYPE_DEVICE, strnlen(GRANT_TYPE_DEVICE, sizeof(GRANT_TYPE_DEVICE)));
499
500 len = sizeof("client_id=") + strlen(client_id) + sizeof("client_secret=") + strlen(client_secret)
501 + sizeof("code=") + strlen(credential->device_code) + sizeof("grant_type=") + strlen(grant_type);
502 postdata = malloc(len);
503 snprintf(postdata, len, "client_id=%s&client_secret=%s&code=%s&grant_type=%s",
504 client_id, client_secret, credential->device_code, grant_type);
505
506 curl_free(client_id);
507 curl_free(client_secret);
508 curl_free(grant_type);
509
510 curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
511 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
512 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
513 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
514 curl_setopt_common(curl);
515
516 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
517 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
518
519 ret = curl_easy_perform(curl);
520
521 free(postdata);
522
523 curl_easy_cleanup(curl);
524 curl = NULL;
525 curl_slist_free_all(slist1);
526 slist1 = NULL;
527
528 gd->jsn = NULL;
529 jsonsl_destroy(jsn);
530
531 return (int)ret;
532}
533
534void update_access_token_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
535{
536 switch (gd->state) {
537 case psRoot:
538 if (state->level != 2) {
539 break;
540 }
541 else if (strcmp(buf, "access_token") == 0) {
542 gd->state = psAccessToken;
543 }
544 else if (strcmp(buf, "expires_in") == 0) {
545 gd->state = psExpiresIn;
546 }
547 else if (strcmp(buf, "scope") == 0) {
548 gd->state = psScope;
549 }
550 else if (strcmp(buf, "token_type") == 0) {
551 gd->state = psTokenType;
552 }
553 else if (strcmp(buf, "error") == 0) {
554 gd->state = psError;
555 }
556 else if (strcmp(buf, "error_description") == 0) {
557 gd->state = psErrorDescription;
558 }
559 break;
560 case psAccessToken:
561 if (state->type == JSONSL_T_STRING) {
562 strlcpy(gd->credential.access_token, buf, sizeof(gd->credential.access_token));
563 gd->state = psRoot;
564 }
565 break;
566 case psExpiresIn:
567 if (state->type == JSONSL_T_SPECIAL) {
568 gd->credential.expires_in = atoi(buf);
569 gd->state = psRoot;
570 }
571 break;
572 case psScope:
573 if (state->type == JSONSL_T_STRING) {
574 strlcpy(gd->credential.scope, buf, sizeof(gd->credential.scope));
575 gd->state = psRoot;
576 }
577 break;
578 case psTokenType:
579 if (state->type == JSONSL_T_STRING) {
580 strlcpy(gd->credential.token_type, buf, sizeof(gd->credential.token_type));
581 gd->state = psRoot;
582 }
583 break;
584 case psError:
585 if (state->type == JSONSL_T_STRING) {
586 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
587 gd->state = psRoot;
588 }
589 break;
590 case psErrorDescription:
591 if (state->type == JSONSL_T_STRING) {
592 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
593 gd->state = psRoot;
594 }
595 break;
596 }
597}
598
599void update_access_token_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
600{
601}
602
603int update_access_token(google_drive_t *gd)
604{
605 client_info_t *client_info = &gd->client_info;
606 credential_t *credential = &gd->credential;
607 CURLcode ret;
608 CURL *curl;
609 struct curl_slist *slist1;
610 size_t len;
611 char *postdata;
612
613 len = strlen(credential->refresh_token);
614 if (len == 0)
615 return -1;
616
617 jsonsl_t jsn = gd->jsn = jsonsl_new(3);
618 jsn->data = gd;
619 jsn->error_callback = google_drive_error_callback;
620 jsn->action_callback = google_drive_state_callback;
621 jsonsl_enable_all_callbacks(jsn);
622
623 gd->jsn_buf_pos = -1;
624 gd->start = update_access_token_state_start;
625 gd->end = update_access_token_state_end;
626 gd->state = psRoot;
627
628 slist1 = NULL;
629 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
630
631 curl = curl_easy_init();
632
633 char *client_id = curl_easy_escape(curl, client_info->client_id, strnlen(client_info->client_id, sizeof(client_info->client_id)));
634 char *client_secret = curl_easy_escape(curl, client_info->client_secret, strnlen(client_info->client_secret, sizeof(client_info->client_secret)));
635
636 len = sizeof("client_id=") + strlen(client_id) + sizeof("client_secret=") + strlen(client_secret)
637 + sizeof("refresh_token=") + strlen(credential->refresh_token);
638 postdata = malloc(len);
639 snprintf(postdata, len, "client_id=%s&client_secret=%s&code=%s&grant_type=refresh_token",
640 client_id, client_secret, credential->refresh_token);
641
642 curl_free(client_id);
643 curl_free(client_secret);
644
645 curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
646 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
647 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
648 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
649 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
650 curl_setopt_common(curl);
651
652 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
653 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
654
655 ret = curl_easy_perform(curl);
656
657 free(postdata);
658
659 curl_easy_cleanup(curl);
660 curl = NULL;
661 curl_slist_free_all(slist1);
662 slist1 = NULL;
663
664 gd->jsn = NULL;
665 jsonsl_destroy(jsn);
666
667 return (int)ret;
668}
669
670void revoke_device_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
671{
672}
673
674void revoke_device_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
675{
676}
677
678int revoke_device(google_drive_t *gd)
679{
680 client_info_t *client_info = &gd->client_info;
681 credential_t *credential = &gd->credential;
682 CURLcode ret;
683 CURL *curl;
684 size_t len;
685 struct curl_slist *slist1;
686 char *postdata;
687
688 len = strlen(credential->access_token);
689 if (len == 0)
690 return -1;
691
692 jsonsl_t jsn = gd->jsn = jsonsl_new(3);
693 jsn->data = gd;
694 jsn->error_callback = google_drive_error_callback;
695 jsn->action_callback = google_drive_state_callback;
696 jsonsl_enable_all_callbacks(jsn);
697
698 gd->jsn_buf_pos = -1;
699 gd->start = revoke_device_state_start;
700 gd->end = revoke_device_state_end;
701 gd->state = psRoot;
702
703 slist1 = NULL;
704 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
705
706 curl = curl_easy_init();
707
708 len = sizeof("token=") + strlen(credential->access_token);
709 postdata = malloc(len);
710 snprintf(postdata, len, "token=%s", credential->access_token);
711
712 curl_easy_setopt(curl, CURLOPT_URL, "https://accounts.google.com/o/oauth2/revoke");
713 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
714 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
715 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
716 curl_setopt_common(curl);
717
718 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
719 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
720
721 ret = curl_easy_perform(curl);
722
723 free(postdata);
724
725 curl_easy_cleanup(curl);
726 curl = NULL;
727 curl_slist_free_all(slist1);
728 slist1 = NULL;
729
730 gd->jsn = NULL;
731 jsonsl_destroy(jsn);
732
733 memset(credential, 0, sizeof(*credential));
734
735 return (int)ret;
736}
737
738void upload_file_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
739{
740 switch (gd->state) {
741 case psRoot:
742 if (state->level != 2) {
743 break;
744 }
745 else if (strcmp(buf, "kind") == 0) {
746 gd->state = psKind;
747 }
748 else if (strcmp(buf, "id") == 0) {
749 gd->state = psId;
750 }
751 else if (strcmp(buf, "name") == 0) {
752 gd->state = psName;
753 }
754 else if (strcmp(buf, "mimeType") == 0) {
755 gd->state = psMimeType;
756 }
757 else if (strcmp(buf, "error") == 0) {
758 gd->state = psError;
759 }
760 else if (strcmp(buf, "error_description") == 0) {
761 gd->state = psErrorDescription;
762 }
763 break;
764 case psKind:
765 if (state->type == JSONSL_T_STRING) {
766 strlcpy(gd->file.kind, buf, sizeof(gd->file.kind));
767 gd->state = psRoot;
768 }
769 break;
770 case psId:
771 if (state->type == JSONSL_T_STRING) {
772 strlcpy(gd->file.id, buf, sizeof(gd->file.id));
773 gd->state = psRoot;
774 }
775 break;
776 case psName:
777 if (state->type == JSONSL_T_STRING) {
778 strlcpy(gd->file.name, buf, sizeof(gd->file.name));
779 gd->state = psRoot;
780 }
781 break;
782 case psMimeType:
783 if (state->type == JSONSL_T_STRING) {
784 strlcpy(gd->file.mimeType, buf, sizeof(gd->file.mimeType));
785 gd->state = psRoot;
786 }
787 break;
788 case psError:
789 if (state->type == JSONSL_T_STRING) {
790 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
791 gd->state = psRoot;
792 }
793 break;
794 case psErrorDescription:
795 if (state->type == JSONSL_T_STRING) {
796 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
797 gd->state = psRoot;
798 }
799 break;
800 }
801}
802
803void upload_file_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
804{
805}
806
807size_t read_callback(char *buffer, size_t size, size_t nitems, void *arg)
808{
809 FIL *file = (FIL *)arg;
810 UINT ret = 0;
811 FRESULT res;
812
813 res = f_read(file, buffer, size * nitems, &ret);
814 if (res != FR_OK)
815 return 0;
816
817 int rest = ret;
818 int len;
819
820 while (rest > 0) {
821 len = rest;
822 if (len > (sizeof(response) - 1)) {
823 len = sizeof(response) - 1;
824 }
825
826 memcpy(response, buffer, len);
827
828 response[len] = '\0';
829
830 printf(response);
831
832 dly_tsk(100);
833
834 rest -= len;
835 buffer = (char *)buffer + len;
836 }
837
838 return ret;
839}
840
841int seek_callback(void *arg, curl_off_t offset, int origin)
842{
843 FIL *file = (FIL *)arg;
844 BYTE mode;
845 FRESULT ret;
846
847 switch (origin) {
848 case SEEK_SET:
849 mode = F_SEEK_SET;
850 break;
851 case SEEK_CUR:
852 mode = F_SEEK_CUR;
853 break;
854 case SEEK_END:
855 mode = F_SEEK_END;
856 break;
857 default:
858 return CURL_SEEKFUNC_FAIL;
859 }
860
861 ret = f_seek(file, offset, mode);
862 if (ret != F_OK)
863 return CURL_SEEKFUNC_FAIL;
864
865 return CURL_SEEKFUNC_OK;
866}
867
868int upload_file(google_drive_t *gd, const char *filename, const char *localfilepath)
869{
870 CURLcode ret;
871 CURL *curl;
872 curl_mime *mime;
873 curl_mimepart *part;
874 struct curl_slist *slist1;
875 size_t len;
876 char *postdata, *authorization;
877 static const char buf[] = "Expect:";
878 FIL file;
879 FRESULT fret;
880
881 len = strnlen(gd->credential.access_token, sizeof(gd->credential.access_token));
882 if (len <= 0)
883 return -1;
884
885 jsonsl_t jsn = gd->jsn = jsonsl_new(3);
886 jsn->data = gd;
887 jsn->error_callback = google_drive_error_callback;
888 jsn->action_callback = google_drive_state_callback;
889 jsonsl_enable_all_callbacks(jsn);
890
891 gd->jsn_buf_pos = -1;
892 gd->start = upload_file_state_start;
893 gd->end = upload_file_state_end;
894 gd->state = psRoot;
895
896 fret = f_open(&file, localfilepath, FA_READ);
897 if (fret != FR_OK) {
898 printf("log file open error %d\n", fret);
899 ret = -1;
900 goto error;
901 }
902
903 len = sizeof("{\"name\":\"\"}") + strlen(filename);
904 postdata = malloc(len);
905 snprintf(postdata, len, "{\"name\":\"%s\"}", filename);
906
907 curl = curl_easy_init();
908
909 mime = curl_mime_init(curl);
910 part = curl_mime_addpart(mime);
911 curl_mime_name(part, "metadata");
912 curl_mime_type(part, "application/json;charset=utf-8");
913 curl_mime_data(part, postdata, CURL_ZERO_TERMINATED);
914 free(postdata);
915
916 part = curl_mime_addpart(mime);
917 curl_mime_name(part, "file");
918 curl_mime_type(part, "application/json");
919 curl_mime_data_cb(part, file.fsize, read_callback, seek_callback, NULL, &file);
920
921 len = sizeof("Authorization: Bearer ") + strnlen(gd->credential.access_token, sizeof(gd->credential.access_token));
922 authorization = malloc(len);
923 snprintf(authorization, len, "Authorization: Bearer %s", gd->credential.access_token);
924 slist1 = NULL;
925 slist1 = curl_slist_append(slist1, authorization);
926 free(authorization);
927
928 slist1 = curl_slist_append(slist1, buf);
929
930 curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
931 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
932 curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
933 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
934 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
935 curl_setopt_common(curl);
936
937 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
938 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
939
940 ret = curl_easy_perform(curl);
941
942 curl_easy_cleanup(curl);
943 curl = NULL;
944 curl_mime_free(mime);
945 mime = NULL;
946 curl_slist_free_all(slist1);
947 slist1 = NULL;
948
949 f_close(&file);
950
951error:
952 gd->jsn = NULL;
953 jsonsl_destroy(jsn);
954
955 return (int)ret;
956}
957
958int google_drive_error_callback(jsonsl_t jsn, jsonsl_error_t err,
959 struct jsonsl_state_st *state, char *errat)
960{
961 return 0;
962}
963
964void google_drive_state_callback(jsonsl_t jsn, jsonsl_action_t action,
965 struct jsonsl_state_st *state, const char *buf)
966{
967 google_drive_t *gd = (google_drive_t *)jsn->data;
968
969 switch (action) {
970 case JSONSL_ACTION_PUSH:
971 switch (state->type) {
972 case JSONSL_T_SPECIAL:
973 gd->jsn_buf[0] = *buf;
974 gd->jsn_buf_pos = 1;
975 break;
976 case JSONSL_T_STRING:
977 case JSONSL_T_HKEY:
978 gd->jsn_buf_pos = 0;
979 break;
980 default:
981 gd->jsn_buf_pos = -1;
982 }
983 break;
984 case JSONSL_ACTION_POP:
985 switch (state->type) {
986 case JSONSL_T_SPECIAL:
987 case JSONSL_T_STRING:
988 case JSONSL_T_HKEY:
989 gd->jsn_buf_pos--;
990 if (gd->jsn_buf_pos < sizeof(gd->jsn_buf)) {
991 gd->jsn_buf[gd->jsn_buf_pos] = '\0';
992 }
993 gd->start(gd, state, gd->jsn_buf);
994 break;
995 default:
996 gd->jsn_buf[0] = '\0';
997 break;
998 }
999 gd->jsn_buf_pos = -1;
1000 break;
1001 default:
1002 gd->jsn_buf_pos = -1;
1003 break;
1004 }
1005}
1006
1007static void get_logfname(char *fname)
1008{
1009 // fname = "0:/log/2016010100000000.log"
1010 time_t t;
1011 struct tm tm;
1012 int tmp1, tmp2;
1013 char *pos = &fname[7];
1014
1015 time(&t);
1016 gmtime_r(&t, &tm);
1017
1018 /* 年 */
1019 tmp1 = 1900 + tm.tm_year;
1020 tmp2 = tmp1 / 1000;
1021 tmp1 -= tmp2 * 1000;
1022 *pos++ = '0' + tmp2;
1023 tmp2 = tmp1 / 100;
1024 tmp1 -= tmp2 * 100;
1025 *pos++ = '0' + tmp2;
1026 tmp2 = tmp1 / 10;
1027 tmp1 -= tmp2 * 10;
1028 *pos++ = '0' + tmp2;
1029 *pos++ = '0' + tmp1;
1030 /* 月 */
1031 tmp1 = tm.tm_mon + 1;
1032 tmp2 = tmp1 / 10;
1033 tmp1 -= tmp2 * 10;
1034 *pos++ = '0' + tmp2;
1035 *pos++ = '0' + tmp1;
1036 /* 日 */
1037 tmp1 = tm.tm_mday;
1038 tmp2 = tmp1 / 10;
1039 tmp1 -= tmp2 * 10;
1040 *pos++ = '0' + tmp2;
1041 *pos++ = '0' + tmp1;
1042 /* 時 */
1043 tmp1 = tm.tm_hour;
1044 tmp2 = tmp1 / 10;
1045 tmp1 -= tmp2 * 10;
1046 *pos++ = '0' + tmp2;
1047 *pos++ = '0' + tmp1;
1048 /* 分 */
1049 tmp1 = tm.tm_min;
1050 tmp2 = tmp1 / 10;
1051 tmp1 -= tmp2 * 10;
1052 *pos++ = '0' + tmp2;
1053 *pos++ = '0' + tmp1;
1054 /* 秒 */
1055 tmp1 = tm.tm_sec;
1056 tmp2 = tmp1 / 10;
1057 tmp1 -= tmp2 * 10;
1058 *pos++ = '0' + tmp2;
1059 *pos++ = '0' + tmp1;
1060}
1061
1062static FRESULT write_log(char *fname)
1063{
1064 FIL file;
1065 FRESULT ret;
1066
1067 ret = f_open(&file, fname, FA_CREATE_ALWAYS | FA_WRITE);
1068 if (ret != FR_OK) {
1069 printf("not open a upload file %d\n", ret);
1070 return ret;
1071 }
1072
1073 f_printf(&file, "{\"datetime\":\"");
1074 for (int i = 7; i < 21; i++)
1075 f_putc(fname[i], &file);
1076 f_printf(&file, "\",");
1077
1078 for (int i = 0; i < 6; i++) {
1079 struct watt_hour_meter_t *meter = &electric_energy_meter_data[i];
1080 uint32_t *log;
1081 int len;
1082
1083 f_printf(&file, "\"channel%d\":[", i + 1);
1084
1085 wai_sem(MAIN_SEMAPHORE);
1086
1087 len = 48 - meter->current_pos;
1088 if (len > 0) {
1089 log = &meter->integral_electric_energy_measurement_log[meter->current_pos];
1090 for (int j = 1; j < len; j++) {
1091 f_printf(&file, "%d,", *log);
1092 }
1093 f_printf(&file, "%d", *log);
1094 }
1095 len = 48 - len;
1096 if (len > 0) {
1097 f_putc(',', &file);
1098
1099 log = &meter->integral_electric_energy_measurement_log[0];
1100 for (int j = 1; j < len; j++) {
1101 f_printf(&file, "%d,", *log);
1102 }
1103 f_printf(&file, "%d", *log);
1104 }
1105
1106 sig_sem(MAIN_SEMAPHORE);
1107
1108 f_putc(']', &file);
1109 if (i != 5) {
1110 f_putc(',', &file);
1111 }
1112 }
1113
1114 f_putc('}', &file);
1115
1116 f_close(&file);
1117
1118 return FR_OK;
1119}
1120
1121void curl_setopt_common(CURL *curl)
1122{
1123 CURLcode res;
1124
1125 /* ask libcurl to show us the verbose output */
1126 res = curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
1127 if (res != CURLE_OK)
1128 printf("CURLOPT_VERBOSE failed: %s\n",
1129 curl_easy_strerror(res));
1130
1131 /* set the error buffer as empty before performing a request */
1132 errbuf[0] = 0;
1133
1134 /* provide a buffer to store errors in */
1135 res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
1136 if (res != CURLE_OK)
1137 printf("CURLOPT_ERRORBUFFER failed: %s\n",
1138 curl_easy_strerror(res));
1139
1140#ifdef SKIP_PEER_VERIFICATION
1141 /*
1142 * If you want to connect to a site who isn't using a certificate that is
1143 * signed by one of the certs in the CA bundle you have, you can skip the
1144 * verification of the server's certificate. This makes the connection
1145 * A LOT LESS SECURE.
1146 *
1147 * If you have a CA cert for the server stored someplace else than in the
1148 * default bundle, then the CURLOPT_CAPATH option might come handy for
1149 * you.
1150 */
1151 res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
1152 if (res != CURLE_OK)
1153 printf("CURLOPT_SSL_VERIFYPEER failed: %s\n",
1154 curl_easy_strerror(res));
1155#else
1156 res = curl_easy_setopt(curl, CURLOPT_CAINFO, "0:/certs/ca-cert.pem");
1157 if (res != CURLE_OK)
1158 printf("CURLOPT_CAINFO failed: %s\n",
1159 curl_easy_strerror(res));
1160
1161 res = curl_easy_setopt(curl, CURLOPT_SSLCERT, "0:/certs/client-cert.pem");
1162 if (res != CURLE_OK)
1163 printf("CURLOPT_SSLCERT failed: %s\n",
1164 curl_easy_strerror(res));
1165
1166 res = curl_easy_setopt(curl, CURLOPT_SSLKEY, "0:/certs/client-key.pem");
1167 if (res != CURLE_OK)
1168 printf("CURLOPT_SSLKEY failed: %s\n",
1169 curl_easy_strerror(res));
1170#endif
1171
1172#ifdef SKIP_HOSTNAME_VERIFICATION
1173 /*
1174 * If the site you're connecting to uses a different host name that what
1175 * they have mentioned in their server certificate's commonName (or
1176 * subjectAltName) fields, libcurl will refuse to connect. You can skip
1177 * this check, but this will make the connection less secure.
1178 */
1179 res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
1180 if (res != CURLE_OK)
1181 printf("CURLOPT_SSL_VERIFYHOST failed: %s\n",
1182 curl_easy_strerror(res));
1183#endif
1184
1185 /*res = curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy.example.com:8080");
1186 if (res != CURLE_OK)
1187 printf("CURLOPT_PROXY failed: %s\n",
1188 curl_easy_strerror(res));*/
1189
1190 res = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
1191 if (res != CURLE_OK)
1192 printf("CURLOPT_NOPROGRESS failed: %s\n",
1193 curl_easy_strerror(res));
1194
1195 res = curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
1196 if (res != CURLE_OK)
1197 printf("CURLOPT_MAXREDIRS failed: %s\n",
1198 curl_easy_strerror(res));
1199
1200 res = curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
1201 if (res != CURLE_OK)
1202 printf("CURLOPT_TCP_KEEPALIVE failed: %s\n",
1203 curl_easy_strerror(res));
1204}
1205
1206void client_set_client_id(const char *client_id)
1207{
1208 google_drive_t *gd = &google_drive;
1209
1210 strlcpy(gd->client_info.client_id, client_id, sizeof(gd->client_info.client_id));
1211}
1212
1213void client_set_client_secret(const char *client_secret)
1214{
1215 google_drive_t *gd = &google_drive;
1216
1217 strlcpy(gd->client_info.client_secret, client_secret, sizeof(gd->client_info.client_secret));
1218}
1219
1220int client_get_device_id(int argc, char **argv)
1221{
1222 google_drive_t *gd = &google_drive;
1223 int ret;
1224
1225 ret = get_device_id(gd, SCOPE_DRIVE_FILE);
1226 if (ret == 0) {
1227 printf("Device was registered. Enter the code at the following URL\n");
1228 printf("url: %s\n", gd->credential.verification_url);
1229 printf("code: %s\n", gd->credential.user_code);
1230 }
1231 else {
1232 printf("Device register failed! %d\n", ret);
1233 }
1234
1235 return ret;
1236}
1237
1238int client_get_access_token(int argc, char **argv)
1239{
1240 google_drive_t *gd = &google_drive;
1241 int ret;
1242
1243 ret = get_access_token(gd);
1244 if (ret == 0) {
1245 printf("Access token was give\n");
1246 printf("Refresh token: %s\n", gd->credential.refresh_token);
1247 printf("Access token: %s\n", gd->credential.access_token);
1248 }
1249 else {
1250 printf("Access token gain failed. %d\n", ret);
1251 }
1252
1253 return ret;
1254}
1255
1256int client_update_access_token(int argc, char **argv)
1257{
1258 google_drive_t *gd = &google_drive;
1259 int ret;
1260
1261 ret = update_access_token(gd);
1262 if (ret == 0) {
1263 printf("Access token was update\n");
1264 printf("Access token: %s\n", gd->credential.access_token);
1265 }
1266 else {
1267 printf("Access token update failed. %d\n", ret);
1268 }
1269
1270 return ret;
1271}
1272
1273int client_revoke(int argc, char **argv)
1274{
1275 google_drive_t *gd = &google_drive;
1276 int ret;
1277
1278 ret = revoke_device(gd);
1279 if (ret == 0) {
1280 printf("Device was revoked.\n");
1281 }
1282 else {
1283 printf("Device revoke failed. %d\n", ret);
1284 }
1285
1286 return ret;
1287}
1288
1289int client_upload_file(int argc, char **argv)
1290{
1291 google_drive_t *gd = &google_drive;
1292 int ret;
1293 FRESULT fret;
1294 char fname[] = { "1:/log/20160101000000.log" };
1295
1296 get_logfname(fname);
1297
1298 fret = write_log(fname);
1299 if (fret != FR_OK) {
1300 printf("log file write error %d\n", fret);
1301 return (int)fret;
1302 }
1303
1304 ret = upload_file(gd, &fname[7], fname);
1305 if (ret == 0) {
1306 printf("%s was uploaded.\n", &fname[7]);
1307 }
1308 else {
1309 printf("%s upload failed. %d\n", &fname[7], ret);
1310 }
1311
1312 return ret;
1313}
1314
1315void client_final(void)
1316{
1317 curl_global_cleanup();
1318}
Note: See TracBrowser for help on using the repository browser.