android: Add a simple HTTP(S) fetcher for CRLs
[strongswan.git] / src / frontends / android / app / src / main / jni / libandroidbridge / backend / android_fetcher.c
1 /*
2 * Copyright (C) 2017 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15 #include "android_fetcher.h"
16
17 #include "../android_jni.h"
18 #include "../charonservice.h"
19 #include <utils/debug.h>
20
21 typedef struct android_fetcher_t android_fetcher_t;
22
23 struct android_fetcher_t {
24
25 /**
26 * Public interface
27 */
28 fetcher_t public;
29
30 /**
31 * Callback function
32 */
33 fetcher_callback_t cb;
34 };
35
36 METHOD(fetcher_t, fetch, status_t,
37 android_fetcher_t *this, char *uri, void *userdata)
38 {
39 JNIEnv *env;
40 jmethodID method_id;
41 jobjectArray jdata;
42 jstring juri;
43 chunk_t data;
44 status_t status = FAILED;
45
46 if (this->cb == fetcher_default_callback)
47 {
48 *(chunk_t*)userdata = chunk_empty;
49 }
50
51 androidjni_attach_thread(&env);
52 /* can't use FindClass here as this is not called by the main thread */
53 method_id = (*env)->GetStaticMethodID(env, android_simple_fetcher_class,
54 "fetch", "(Ljava/lang/String;)[B");
55 if (!method_id)
56 {
57 goto failed;
58 }
59 juri = (*env)->NewStringUTF(env, uri);
60 if (!juri)
61 {
62 goto failed;
63 }
64 jdata = (*env)->CallStaticObjectMethod(env, android_simple_fetcher_class,
65 method_id, juri);
66 if (!jdata || androidjni_exception_occurred(env))
67 {
68 goto failed;
69 }
70 data = chunk_from_byte_array(env, jdata);
71 if (this->cb(userdata, data))
72 {
73 status = SUCCESS;
74 }
75 chunk_free(&data);
76 androidjni_detach_thread();
77 return status;
78
79 failed:
80 DBG1(DBG_LIB, "failed to fetch from '%s'", uri);
81 androidjni_exception_occurred(env);
82 androidjni_detach_thread();
83 return FAILED;
84 }
85
86 METHOD(fetcher_t, set_option, bool,
87 android_fetcher_t *this, fetcher_option_t option, ...)
88 {
89 bool supported = TRUE;
90 va_list args;
91
92 va_start(args, option);
93 switch (option)
94 {
95 case FETCH_CALLBACK:
96 {
97 this->cb = va_arg(args, fetcher_callback_t);
98 break;
99 }
100 default:
101 supported = FALSE;
102 break;
103 }
104 va_end(args);
105 return supported;
106 }
107
108 METHOD(fetcher_t, destroy, void,
109 android_fetcher_t *this)
110 {
111 free(this);
112 }
113
114 /*
115 * Described in header.
116 */
117 fetcher_t *android_fetcher_create()
118 {
119 android_fetcher_t *this;
120
121 INIT(this,
122 .public = {
123 .fetch = _fetch,
124 .set_option = _set_option,
125 .destroy = _destroy,
126 },
127 .cb = fetcher_default_callback,
128 );
129
130 return &this->public;
131 }