source: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/client.c@ 364

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

TINETとSocket APIなどを更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 29.2 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 gd->jsn_buf_pos = -1;
197
198 jsonsl_reset(jsn);
199 gd->start = get_device_id_state_start;
200 gd->end = get_device_id_state_end;
201
202 slist1 = NULL;
203 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
204
205 curl = curl_easy_init();
206
207 char *client_id = curl_easy_escape(curl, client_info->client_id, strnlen(client_info->client_id, sizeof(client_info->client_id)));
208 char *esc_scope = curl_easy_escape(curl, scope, strlen(scope));
209
210 len = sizeof("client_id=") + strlen(client_id) + sizeof("scope=") + strlen(esc_scope);
211 postdata = malloc(len);
212 snprintf(postdata, len, "client_id=%s&scope=%s", client_id, esc_scope);
213
214 curl_free(client_id);
215 curl_free(esc_scope);
216
217 curl_easy_setopt(curl, CURLOPT_URL, "https://accounts.google.com/o/oauth2/device/code");
218 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
219 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
220 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
221 curl_setopt_common(curl);
222
223 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
224 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
225
226 ret = curl_easy_perform(curl);
227
228 free(postdata);
229
230 curl_easy_cleanup(curl);
231 curl = NULL;
232 curl_slist_free_all(slist1);
233 slist1 = NULL;
234
235 return (int)ret;
236}
237
238void get_access_token_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
239{
240 switch (gd->state) {
241 case psRoot:
242 if (state->level != 2) {
243 break;
244 }
245 else if (strcmp(buf, "access_token") == 0) {
246 gd->state = psAccessToken;
247 }
248 else if (strcmp(buf, "expires_in") == 0) {
249 gd->state = psExpiresIn;
250 }
251 else if (strcmp(buf, "refresh_token") == 0) {
252 gd->state = psRefreshToken;
253 }
254 else if (strcmp(buf, "scope") == 0) {
255 gd->state = psScope;
256 }
257 else if (strcmp(buf, "token_type") == 0) {
258 gd->state = psTokenType;
259 }
260 else if (strcmp(buf, "error") == 0) {
261 gd->state = psError;
262 }
263 else if (strcmp(buf, "error_description") == 0) {
264 gd->state = psErrorDescription;
265 }
266 break;
267 case psAccessToken:
268 if (state->type == JSONSL_T_STRING) {
269 strlcpy(gd->credential.access_token, buf, sizeof(gd->credential.access_token));
270 gd->state = psRoot;
271 }
272 break;
273 case psExpiresIn:
274 if (state->type == JSONSL_T_SPECIAL) {
275 gd->credential.expires_in = atoi(buf);
276 gd->state = psRoot;
277 }
278 break;
279 case psRefreshToken:
280 if (state->type == JSONSL_T_STRING) {
281 strlcpy(gd->credential.refresh_token, buf, sizeof(gd->credential.refresh_token));
282 gd->state = psRoot;
283 }
284 break;
285 case psScope:
286 if (state->type == JSONSL_T_STRING) {
287 strlcpy(gd->credential.scope, buf, sizeof(gd->credential.scope));
288 gd->state = psRoot;
289 }
290 break;
291 case psTokenType:
292 if (state->type == JSONSL_T_STRING) {
293 strlcpy(gd->credential.token_type, buf, sizeof(gd->credential.token_type));
294 gd->state = psRoot;
295 }
296 break;
297 case psError:
298 if (state->type == JSONSL_T_STRING) {
299 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
300 gd->state = psRoot;
301 }
302 break;
303 case psErrorDescription:
304 if (state->type == JSONSL_T_STRING) {
305 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
306 gd->state = psRoot;
307 }
308 break;
309 }
310}
311
312void get_access_token_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
313{
314}
315
316int get_access_token(google_drive_t *gd)
317{
318 client_info_t *client_info = &gd->client_info;
319 credential_t *credential = &gd->credential;
320 CURLcode ret;
321 CURL *curl;
322 struct curl_slist *slist1;
323 size_t len;
324 char *postdata;
325 jsonsl_t jsn = gd->jsn;
326
327 gd->jsn_buf_pos = -1;
328
329 jsonsl_reset(jsn);
330 gd->start = get_access_token_state_start;
331 gd->end = get_access_token_state_end;
332
333 slist1 = NULL;
334 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
335
336 curl = curl_easy_init();
337
338 char *client_id = curl_easy_escape(curl, client_info->client_id, strnlen(client_info->client_id, sizeof(client_info->client_id)));
339 char *client_secret = curl_easy_escape(curl, client_info->client_secret, strnlen(client_info->client_secret, sizeof(client_info->client_secret)));
340 char *grant_type = curl_easy_escape(curl, GRANT_TYPE_DEVICE, strnlen(GRANT_TYPE_DEVICE, sizeof(GRANT_TYPE_DEVICE)));
341
342 len = sizeof("client_id=") + strlen(client_id) + sizeof("client_secret=") + strlen(client_secret)
343 + sizeof("code=") + strlen(credential->device_code) + sizeof("grant_type=") + strlen(grant_type);
344 postdata = malloc(len);
345 snprintf(postdata, len, "client_id=%s&client_secret=%s&code=%s&grant_type=%s",
346 client_id, client_secret, credential->device_code, grant_type);
347
348 curl_free(client_id);
349 curl_free(client_secret);
350 curl_free(grant_type);
351
352 curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
353 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
354 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
355 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
356 curl_setopt_common(curl);
357
358 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
359 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
360
361 ret = curl_easy_perform(curl);
362
363 free(postdata);
364
365 curl_easy_cleanup(curl);
366 curl = NULL;
367 curl_slist_free_all(slist1);
368 slist1 = NULL;
369
370 return (int)ret;
371}
372
373void update_access_token_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
374{
375 switch (gd->state) {
376 case psRoot:
377 if (state->level != 2) {
378 break;
379 }
380 else if (strcmp(buf, "access_token") == 0) {
381 gd->state = psAccessToken;
382 }
383 else if (strcmp(buf, "expires_in") == 0) {
384 gd->state = psExpiresIn;
385 }
386 else if (strcmp(buf, "scope") == 0) {
387 gd->state = psScope;
388 }
389 else if (strcmp(buf, "token_type") == 0) {
390 gd->state = psTokenType;
391 }
392 else if (strcmp(buf, "error") == 0) {
393 gd->state = psError;
394 }
395 else if (strcmp(buf, "error_description") == 0) {
396 gd->state = psErrorDescription;
397 }
398 break;
399 case psAccessToken:
400 if (state->type == JSONSL_T_STRING) {
401 strlcpy(gd->credential.access_token, buf, sizeof(gd->credential.access_token));
402 gd->state = psRoot;
403 }
404 break;
405 case psExpiresIn:
406 if (state->type == JSONSL_T_SPECIAL) {
407 gd->credential.expires_in = atoi(buf);
408 gd->state = psRoot;
409 }
410 break;
411 case psScope:
412 if (state->type == JSONSL_T_STRING) {
413 strlcpy(gd->credential.scope, buf, sizeof(gd->credential.scope));
414 gd->state = psRoot;
415 }
416 break;
417 case psTokenType:
418 if (state->type == JSONSL_T_STRING) {
419 strlcpy(gd->credential.token_type, buf, sizeof(gd->credential.token_type));
420 gd->state = psRoot;
421 }
422 break;
423 case psError:
424 if (state->type == JSONSL_T_STRING) {
425 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
426 gd->state = psRoot;
427 }
428 break;
429 case psErrorDescription:
430 if (state->type == JSONSL_T_STRING) {
431 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
432 gd->state = psRoot;
433 }
434 break;
435 }
436}
437
438void update_access_token_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
439{
440}
441
442int update_access_token(google_drive_t *gd)
443{
444 client_info_t *client_info = &gd->client_info;
445 credential_t *credential = &gd->credential;
446 CURLcode ret;
447 CURL *curl;
448 struct curl_slist *slist1;
449 size_t len;
450 char *postdata;
451 jsonsl_t jsn = gd->jsn;
452
453 gd->jsn_buf_pos = -1;
454
455 jsonsl_reset(jsn);
456 gd->start = update_access_token_state_start;
457 gd->end = update_access_token_state_end;
458
459 slist1 = NULL;
460 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
461
462 curl = curl_easy_init();
463
464 char *client_id = curl_easy_escape(curl, client_info->client_id, strnlen(client_info->client_id, sizeof(client_info->client_id)));
465 char *client_secret = curl_easy_escape(curl, client_info->client_secret, strnlen(client_info->client_secret, sizeof(client_info->client_secret)));
466
467 len = sizeof("client_id=") + strlen(client_id) + sizeof("client_secret=") + strlen(client_secret)
468 + sizeof("refresh_token=") + strlen(credential->refresh_token);
469 postdata = malloc(len);
470 snprintf(postdata, len, "client_id=%s&client_secret=%s&code=%s&grant_type=refresh_token",
471 client_id, client_secret, credential->refresh_token);
472
473 curl_free(client_id);
474 curl_free(client_secret);
475
476 curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
477 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
478 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
479 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
480 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
481 curl_setopt_common(curl);
482
483 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
484 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
485
486 ret = curl_easy_perform(curl);
487
488 free(postdata);
489
490 curl_easy_cleanup(curl);
491 curl = NULL;
492 curl_slist_free_all(slist1);
493 slist1 = NULL;
494
495 return (int)ret;
496}
497
498void revoke_device_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
499{
500}
501
502void revoke_device_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
503{
504}
505
506int revoke_device(google_drive_t *gd)
507{
508 client_info_t *client_info = &gd->client_info;
509 credential_t *credential = &gd->credential;
510 CURLcode ret;
511 CURL *curl;
512 size_t len;
513 struct curl_slist *slist1;
514 char *postdata;
515 jsonsl_t jsn = gd->jsn;
516
517 gd->jsn_buf_pos = -1;
518
519 jsonsl_reset(jsn);
520 gd->start = revoke_device_state_start;
521 gd->end = revoke_device_state_end;
522
523 slist1 = NULL;
524 slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
525
526 curl = curl_easy_init();
527
528 len = sizeof("token=") + strlen(credential->access_token);
529 postdata = malloc(len);
530 snprintf(postdata, len, "token=%s", credential->access_token);
531
532 curl_easy_setopt(curl, CURLOPT_URL, "https://accounts.google.com/o/oauth2/revoke");
533 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
534 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
535 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
536 curl_setopt_common(curl);
537
538 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
539 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
540
541 ret = curl_easy_perform(curl);
542
543 free(postdata);
544
545 curl_easy_cleanup(curl);
546 curl = NULL;
547 curl_slist_free_all(slist1);
548 slist1 = NULL;
549
550 return (int)ret;
551}
552
553void upload_file_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
554{
555 switch (gd->state) {
556 case psRoot:
557 if (state->level != 2) {
558 break;
559 }
560 else if (strcmp(buf, "kind") == 0) {
561 gd->state = psKind;
562 }
563 else if (strcmp(buf, "id") == 0) {
564 gd->state = psId;
565 }
566 else if (strcmp(buf, "name") == 0) {
567 gd->state = psName;
568 }
569 else if (strcmp(buf, "mimeType") == 0) {
570 gd->state = psMimeType;
571 }
572 else if (strcmp(buf, "error") == 0) {
573 gd->state = psError;
574 }
575 else if (strcmp(buf, "error_description") == 0) {
576 gd->state = psErrorDescription;
577 }
578 break;
579 case psKind:
580 if (state->type == JSONSL_T_STRING) {
581 strlcpy(gd->file.kind, buf, sizeof(gd->file.kind));
582 gd->state = psRoot;
583 }
584 break;
585 case psId:
586 if (state->type == JSONSL_T_STRING) {
587 strlcpy(gd->file.id, buf, sizeof(gd->file.id));
588 gd->state = psRoot;
589 }
590 break;
591 case psName:
592 if (state->type == JSONSL_T_STRING) {
593 strlcpy(gd->file.name, buf, sizeof(gd->file.name));
594 gd->state = psRoot;
595 }
596 break;
597 case psMimeType:
598 if (state->type == JSONSL_T_STRING) {
599 strlcpy(gd->file.mimeType, buf, sizeof(gd->file.mimeType));
600 gd->state = psRoot;
601 }
602 break;
603 case psError:
604 if (state->type == JSONSL_T_STRING) {
605 strlcpy(gd->error.error, buf, sizeof(gd->error.error));
606 gd->state = psRoot;
607 }
608 break;
609 case psErrorDescription:
610 if (state->type == JSONSL_T_STRING) {
611 strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
612 gd->state = psRoot;
613 }
614 break;
615 }
616}
617
618void upload_file_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
619{
620}
621
622size_t read_callback(char *buffer, size_t size, size_t nitems, void *arg)
623{
624 FIL *file = (FIL *)arg;
625 UINT ret = 0;
626 FRESULT res;
627
628 res = f_read(file, buffer, size * nitems, &ret);
629 if (res != FR_OK)
630 return 0;
631
632 int rest = ret;
633 int len;
634
635 while (rest > 0) {
636 len = rest;
637 if (len > (sizeof(response) - 1)) {
638 len = sizeof(response) - 1;
639 }
640
641 memcpy(response, buffer, len);
642
643 response[len] = '\0';
644
645 printf(response);
646
647 dly_tsk(100);
648
649 rest -= len;
650 buffer = (char *)buffer + len;
651 }
652
653 return ret;
654}
655
656int seek_callback(void *arg, curl_off_t offset, int origin)
657{
658 FIL *file = (FIL *)arg;
659 BYTE mode;
660 FRESULT ret;
661
662 switch (origin) {
663 case SEEK_SET:
664 mode = F_SEEK_SET;
665 break;
666 case SEEK_CUR:
667 mode = F_SEEK_CUR;
668 break;
669 case SEEK_END:
670 mode = F_SEEK_END;
671 break;
672 default:
673 return CURL_SEEKFUNC_FAIL;
674 }
675
676 ret = f_seek(file, offset, mode);
677 if (ret != F_OK)
678 return CURL_SEEKFUNC_FAIL;
679
680 return CURL_SEEKFUNC_OK;
681}
682
683int upload_file(google_drive_t *gd, const char *filename, const char *localfilepath)
684{
685 CURLcode ret;
686 CURL *curl;
687 curl_mime *mime;
688 curl_mimepart *part;
689 struct curl_slist *slist1;
690 size_t len;
691 char *postdata, *authorization;
692 static const char buf[] = "Expect:";
693 jsonsl_t jsn = gd->jsn;
694 FIL file;
695 FRESULT fret;
696
697 gd->jsn_buf_pos = -1;
698
699 jsonsl_reset(jsn);
700 gd->start = upload_file_state_start;
701 gd->end = upload_file_state_end;
702
703 fret = f_open(&file, localfilepath, FA_READ);
704 if (fret != FR_OK) {
705 printf("log file open error %d\n", fret);
706 return -1;
707 }
708
709 len = sizeof("{\"name\":\"\"}") + strlen(filename);
710 postdata = malloc(len);
711 snprintf(postdata, len, "{\"name\":\"%s\"}", filename);
712
713 curl = curl_easy_init();
714
715 mime = curl_mime_init(curl);
716 part = curl_mime_addpart(mime);
717 curl_mime_name(part, "metadata");
718 curl_mime_type(part, "application/json;charset=utf-8");
719 curl_mime_data(part, postdata, CURL_ZERO_TERMINATED);
720 free(postdata);
721
722 part = curl_mime_addpart(mime);
723 curl_mime_name(part, "file");
724 curl_mime_type(part, "application/json");
725 curl_mime_data_cb(part, file.fsize, read_callback, seek_callback, NULL, &file);
726
727 len = sizeof("Authorization: Bearer ") + strnlen(gd->credential.access_token, sizeof(gd->credential.access_token));
728 authorization = malloc(len);
729 snprintf(authorization, len, "Authorization: Bearer %s", gd->credential.access_token);
730 slist1 = NULL;
731 slist1 = curl_slist_append(slist1, authorization);
732 free(authorization);
733
734 slist1 = curl_slist_append(slist1, buf);
735
736 curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
737 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
738 curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
739 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
740 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
741 curl_setopt_common(curl);
742
743 curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
744 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
745
746 ret = curl_easy_perform(curl);
747
748 curl_easy_cleanup(curl);
749 curl = NULL;
750 curl_mime_free(mime);
751 mime = NULL;
752 curl_slist_free_all(slist1);
753 slist1 = NULL;
754
755 f_close(&file);
756
757 return (int)ret;
758}
759
760int google_drive_error_callback(jsonsl_t jsn, jsonsl_error_t err,
761 struct jsonsl_state_st *state, char *errat)
762{
763 return 0;
764}
765
766void google_drive_state_callback(jsonsl_t jsn, jsonsl_action_t action,
767 struct jsonsl_state_st *state, const char *buf)
768{
769 google_drive_t *gd = (google_drive_t *)jsn->data;
770
771 switch (action) {
772 case JSONSL_ACTION_PUSH:
773 switch (state->type) {
774 case JSONSL_T_SPECIAL:
775 gd->jsn_buf[0] = *buf;
776 gd->jsn_buf_pos = 1;
777 break;
778 case JSONSL_T_STRING:
779 case JSONSL_T_HKEY:
780 gd->jsn_buf_pos = 0;
781 break;
782 default:
783 gd->jsn_buf_pos = -1;
784 }
785 break;
786 case JSONSL_ACTION_POP:
787 switch (state->type) {
788 case JSONSL_T_SPECIAL:
789 case JSONSL_T_STRING:
790 case JSONSL_T_HKEY:
791 gd->jsn_buf_pos--;
792 if (gd->jsn_buf_pos < sizeof(gd->jsn_buf)) {
793 gd->jsn_buf[gd->jsn_buf_pos] = '\0';
794 }
795 gd->start(gd, state, gd->jsn_buf);
796 break;
797 default:
798 gd->jsn_buf[0] = '\0';
799 break;
800 }
801 gd->jsn_buf_pos = -1;
802 break;
803 default:
804 gd->jsn_buf_pos = -1;
805 break;
806 }
807}
808
809static void get_logfname(char *fname)
810{
811 // fname = "0:/log/2016010100000000.log"
812 time_t t;
813 struct tm tm;
814 int tmp1, tmp2;
815 char *pos = &fname[7];
816
817 time(&t);
818 gmtime_r(&t, &tm);
819
820 /* 年 */
821 tmp1 = 1900 + tm.tm_year;
822 tmp2 = tmp1 / 1000;
823 tmp1 -= tmp2 * 1000;
824 *pos++ = '0' + tmp2;
825 tmp2 = tmp1 / 100;
826 tmp1 -= tmp2 * 100;
827 *pos++ = '0' + tmp2;
828 tmp2 = tmp1 / 10;
829 tmp1 -= tmp2 * 10;
830 *pos++ = '0' + tmp2;
831 *pos++ = '0' + tmp1;
832 /* 月 */
833 tmp1 = tm.tm_mon + 1;
834 tmp2 = tmp1 / 10;
835 tmp1 -= tmp2 * 10;
836 *pos++ = '0' + tmp2;
837 *pos++ = '0' + tmp1;
838 /* 日 */
839 tmp1 = tm.tm_mday;
840 tmp2 = tmp1 / 10;
841 tmp1 -= tmp2 * 10;
842 *pos++ = '0' + tmp2;
843 *pos++ = '0' + tmp1;
844 /* 時 */
845 tmp1 = tm.tm_hour;
846 tmp2 = tmp1 / 10;
847 tmp1 -= tmp2 * 10;
848 *pos++ = '0' + tmp2;
849 *pos++ = '0' + tmp1;
850 /* 分 */
851 tmp1 = tm.tm_min;
852 tmp2 = tmp1 / 10;
853 tmp1 -= tmp2 * 10;
854 *pos++ = '0' + tmp2;
855 *pos++ = '0' + tmp1;
856 /* 秒 */
857 tmp1 = tm.tm_sec;
858 tmp2 = tmp1 / 10;
859 tmp1 -= tmp2 * 10;
860 *pos++ = '0' + tmp2;
861 *pos++ = '0' + tmp1;
862}
863
864static FRESULT write_log(char *fname)
865{
866 FIL file;
867 FRESULT ret;
868
869 ret = f_open(&file, fname, FA_CREATE_ALWAYS | FA_WRITE);
870 if (ret != FR_OK) {
871 printf("not open a upload file %d\n", ret);
872 return ret;
873 }
874
875 f_printf(&file, "{\"datetime\":\"");
876 for (int i = 7; i < 21; i++)
877 f_putc(fname[i], &file);
878 f_printf(&file, "\",");
879
880 for (int i = 0; i < 6; i++) {
881 struct watt_hour_meter_t *meter = &electric_energy_meter_data[i];
882 uint32_t *log;
883 int len;
884
885 f_printf(&file, "\"channel%d\":[", i + 1);
886
887 wai_sem(MAIN_SEMAPHORE);
888
889 len = 48 - meter->current_pos;
890 if (len > 0) {
891 log = &meter->integral_electric_energy_measurement_log[meter->current_pos];
892 for (int j = 1; j < len; j++) {
893 f_printf(&file, "%d,", *log);
894 }
895 f_printf(&file, "%d", *log);
896 }
897 len = 48 - len;
898 if (len > 0) {
899 f_putc(',', &file);
900
901 log = &meter->integral_electric_energy_measurement_log[0];
902 for (int j = 1; j < len; j++) {
903 f_printf(&file, "%d,", *log);
904 }
905 f_printf(&file, "%d", *log);
906 }
907
908 sig_sem(MAIN_SEMAPHORE);
909
910 f_putc(']', &file);
911 if (i != 5) {
912 f_putc(',', &file);
913 }
914 }
915
916 f_putc('}', &file);
917
918 f_close(&file);
919
920 return FR_OK;
921}
922
923void curl_setopt_common(CURL *curl)
924{
925 CURLcode res;
926
927 /* ask libcurl to show us the verbose output */
928 res = curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
929 if (res != CURLE_OK)
930 printf("CURLOPT_VERBOSE failed: %s\n",
931 curl_easy_strerror(res));
932
933 /* set the error buffer as empty before performing a request */
934 errbuf[0] = 0;
935
936 /* provide a buffer to store errors in */
937 res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
938 if (res != CURLE_OK)
939 printf("CURLOPT_ERRORBUFFER failed: %s\n",
940 curl_easy_strerror(res));
941
942#ifdef SKIP_PEER_VERIFICATION
943 /*
944 * If you want to connect to a site who isn't using a certificate that is
945 * signed by one of the certs in the CA bundle you have, you can skip the
946 * verification of the server's certificate. This makes the connection
947 * A LOT LESS SECURE.
948 *
949 * If you have a CA cert for the server stored someplace else than in the
950 * default bundle, then the CURLOPT_CAPATH option might come handy for
951 * you.
952 */
953 res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
954 if (res != CURLE_OK)
955 printf("CURLOPT_SSL_VERIFYPEER failed: %s\n",
956 curl_easy_strerror(res));
957#else
958 res = curl_easy_setopt(curl, CURLOPT_CAINFO, "0:/certs/ca-cert.pem");
959 if (res != CURLE_OK)
960 printf("CURLOPT_CAINFO failed: %s\n",
961 curl_easy_strerror(res));
962
963 res = curl_easy_setopt(curl, CURLOPT_SSLCERT, "0:/certs/client-cert.pem");
964 if (res != CURLE_OK)
965 printf("CURLOPT_SSLCERT failed: %s\n",
966 curl_easy_strerror(res));
967
968 res = curl_easy_setopt(curl, CURLOPT_SSLKEY, "0:/certs/client-key.pem");
969 if (res != CURLE_OK)
970 printf("CURLOPT_SSLKEY failed: %s\n",
971 curl_easy_strerror(res));
972#endif
973
974#ifdef SKIP_HOSTNAME_VERIFICATION
975 /*
976 * If the site you're connecting to uses a different host name that what
977 * they have mentioned in their server certificate's commonName (or
978 * subjectAltName) fields, libcurl will refuse to connect. You can skip
979 * this check, but this will make the connection less secure.
980 */
981 res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
982 if (res != CURLE_OK)
983 printf("CURLOPT_SSL_VERIFYHOST failed: %s\n",
984 curl_easy_strerror(res));
985#endif
986
987 /*res = curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy.example.com:8080");
988 if (res != CURLE_OK)
989 printf("CURLOPT_PROXY failed: %s\n",
990 curl_easy_strerror(res));*/
991
992 res = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
993 if (res != CURLE_OK)
994 printf("CURLOPT_NOPROGRESS failed: %s\n",
995 curl_easy_strerror(res));
996
997 res = curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
998 if (res != CURLE_OK)
999 printf("CURLOPT_MAXREDIRS failed: %s\n",
1000 curl_easy_strerror(res));
1001
1002 res = curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
1003 if (res != CURLE_OK)
1004 printf("CURLOPT_TCP_KEEPALIVE failed: %s\n",
1005 curl_easy_strerror(res));
1006}
1007
1008void client_set_client_id(const char *client_id)
1009{
1010 google_drive_t *gd = &google_drive;
1011
1012 strlcpy(gd->client_info.client_id, client_id, sizeof(gd->client_info.client_id));
1013}
1014
1015void client_set_client_secret(const char *client_secret)
1016{
1017 google_drive_t *gd = &google_drive;
1018
1019 strlcpy(gd->client_info.client_secret, client_secret, sizeof(gd->client_info.client_secret));
1020}
1021
1022int client_get_device_id(int argc, char **argv)
1023{
1024 google_drive_t *gd = &google_drive;
1025 int ret;
1026
1027 ret = get_device_id(gd, SCOPE_DRIVE_FILE);
1028 if (ret == 0) {
1029 printf("Device was registered. Enter the code at the following URL\n");
1030 printf("url: %s\n", gd->credential.verification_url);
1031 printf("code: %s\n", gd->credential.user_code);
1032 }
1033 else {
1034 printf("Device register failed! %d\n", ret);
1035 }
1036
1037 return ret;
1038}
1039
1040int client_get_access_token(int argc, char **argv)
1041{
1042 google_drive_t *gd = &google_drive;
1043 int ret;
1044
1045 ret = get_access_token(gd);
1046 if (ret == 0) {
1047 printf("Access token was give\n");
1048 printf("Refresh token: %s\n", gd->credential.refresh_token);
1049 printf("Access token: %s\n", gd->credential.access_token);
1050 }
1051 else {
1052 printf("Access token gain failed. %d\n", ret);
1053 }
1054
1055 return ret;
1056}
1057
1058int client_update_access_token(int argc, char **argv)
1059{
1060 google_drive_t *gd = &google_drive;
1061 int ret;
1062
1063 ret = update_access_token(gd);
1064 if (ret == 0) {
1065 printf("Access token was update\n");
1066 printf("Access token: %s\n", gd->credential.access_token);
1067 }
1068 else {
1069 printf("Access token update failed. %d\n", ret);
1070 }
1071
1072 return ret;
1073}
1074
1075int client_revoke(int argc, char **argv)
1076{
1077 google_drive_t *gd = &google_drive;
1078 int ret;
1079
1080 ret = revoke_device(gd);
1081 if (ret == 0) {
1082 printf("Device was revoked.\n");
1083 }
1084 else {
1085 printf("Device revoke failed. %d\n", ret);
1086 }
1087
1088 return ret;
1089}
1090
1091int client_upload_file(int argc, char **argv)
1092{
1093 google_drive_t *gd = &google_drive;
1094 int ret;
1095 FRESULT fret;
1096 char fname[] = { "1:/log/20160101000000.log" };
1097
1098 get_logfname(fname);
1099
1100 fret = write_log(fname);
1101 if (fret != FR_OK) {
1102 printf("log file write error %d\n", fret);
1103 return (int)fret;
1104 }
1105
1106 ret = upload_file(gd, &fname[7], fname);
1107 if (ret == 0) {
1108 printf("%s was uploaded.\n", &fname[7]);
1109 }
1110 else {
1111 printf("%s upload failed. %d\n", &fname[7], ret);
1112 }
1113
1114 return ret;
1115}
1116
1117void client_final(void)
1118{
1119 google_drive_t *gd = &google_drive;
1120 jsonsl_t jsn = gd->jsn;
1121
1122 curl_global_cleanup();
1123 jsonsl_destroy(jsn);
1124}
Note: See TracBrowser for help on using the repository browser.