a26857e162f8d0daa6d17064b8328cf92fc724fc
[apps/native/tizen-things-daemon.git] / daemon / src / ttd-http.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Flora License, Version 1.1 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <curl/curl.h>
18 #include <openssl/crypto.h>
19 #include <glib.h>
20 #include "ttd-log.h"
21 #include "ttd-url.h"
22
23 #define CERT_FILE_PATH "/opt/share/cert-svc/ca-certificate.crt"
24
25 static GMutex *mutex_a = NULL;
26 static int http_initialized = 0;
27 static char *urls[TTD_URL_TYPE_NUM] = { NULL, };
28
29 static void __locking_function(int mode, int n, const char *file, int line)
30 {
31         if (mode & CRYPTO_LOCK)
32                 g_mutex_lock(&mutex_a[n]);
33         else
34                 g_mutex_unlock(&mutex_a[n]);
35 }
36
37 static unsigned long __id_function(void)
38 {
39         return ((unsigned long)g_thread_self());
40 }
41
42 int __ssl_thread_mutex_setup(void)
43 {
44         int i;
45
46         mutex_a = g_try_malloc(CRYPTO_num_locks() * sizeof(GMutex));
47         if (!mutex_a)
48                 return -1;
49
50         for (i = 0; i < CRYPTO_num_locks(); i++)
51                 g_mutex_init(&mutex_a[i]);
52
53         CRYPTO_set_id_callback(__id_function);
54         CRYPTO_set_locking_callback(__locking_function);
55
56         return 0;
57 }
58
59 static int __ssl_thread_mutex_cleanup(void)
60 {
61         int i;
62
63         if (!mutex_a)
64                 return -1;
65
66         CRYPTO_set_id_callback(NULL);
67         CRYPTO_set_locking_callback(NULL);
68
69         for (i = 0; i < CRYPTO_num_locks(); i++)
70                 g_mutex_clear(&mutex_a[i]);
71
72         g_free(mutex_a);
73         mutex_a = NULL;
74
75         return 0;
76 }
77
78
79 int ttd_http_init(void)
80 {
81         int ret = 0;
82         curl_global_init(CURL_GLOBAL_DEFAULT);
83         ret = __ssl_thread_mutex_setup();
84         if (ret) {
85                 _E("failed to setup ssl thread mutex");
86                 return -1;
87         }
88
89         http_initialized = 1;
90
91         return 0;
92 }
93
94 int ttd_http_fini(void)
95 {
96         int i= 0;
97         __ssl_thread_mutex_cleanup();
98         curl_global_cleanup();
99
100         for (i = 0; i < TTD_URL_TYPE_NUM; i++) {
101                 g_free(urls[i]);
102                 urls[i] = NULL;
103         }
104
105         http_initialized = 0;
106
107         return 0;
108 }
109
110 static const char *__get_url_by_type(ttd_url_type_e type)
111 {
112         if (!urls[type])
113                 urls[type] = ttd_url_get_by_type(type);
114
115         return urls[type];
116 }
117
118 static size_t _response_write(void *ptr, size_t size, size_t nmemb, void *data)
119 {
120         size_t res_size = 0;
121         char **received = data;
122
123         res_size = size * nmemb;
124
125         if (received && res_size > 0) {
126                 if (*received) {
127                         char *temp = NULL;
128                         char *new = NULL;
129                         temp = g_strndup((const char *)ptr, res_size);
130                         new = g_strdup_printf("%s%s", *received, temp);
131                         g_free(temp);
132                         g_free(*received);
133                         *received = new;
134                 } else
135                         *received = g_strndup((const char *)ptr, res_size);
136         } else
137                 _E("fail to get response [res size : %d]", res_size);
138
139         return res_size;
140 }
141
142 int ttd_http_get(const char *url, char **response, long *res_code)
143 {
144         int ret = 0;
145         CURL *curl = NULL;
146         CURLcode res = CURLE_OK;
147         long r_code = 0;
148
149         retvm_if(!http_initialized, -1, "http is not initialized yet");
150         retvm_if(!response, -1, "response is null");
151         retvm_if(!url, -1, "url is null");
152
153         curl = curl_easy_init();
154
155         retvm_if(!curl, NULL, "failed to curl_easy_init()");
156
157         curl_easy_setopt(curl, CURLOPT_URL, url);
158         curl_easy_setopt(curl, CURLOPT_CAPATH, CERT_FILE_PATH);
159         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _response_write);
160         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)response);
161
162         res = curl_easy_perform(curl);
163         if (res != CURLE_OK) {
164                 _E("curl_easy_perform() failed: %s", curl_easy_strerror(res));
165                 ret = -1;
166         }
167         curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &r_code);
168         if (res_code)
169                 *res_code = r_code;
170
171         _D("received code[%ld]", r_code);
172         _D("response : %s", *response ? *response : "NULL");
173
174         curl_easy_cleanup(curl);
175
176         return ret;
177 }
178
179 int ttd_http_command_get(char **cmd_json, long *res_code)
180 {
181         const char *url = NULL;
182
183         retvm_if(!cmd_json, -1, "cmd_json is null");
184
185         url = __get_url_by_type(TTD_URL_CMD);
186         retvm_if(!url, -1, "failed to get url for command GET");
187
188         return ttd_http_get(url, cmd_json, res_code);
189 }
190
191 static int
192 __ttd_http_post(const char *url, const char *msg_body,
193         struct curl_slist *headers, long *res_code, char **res_msg)
194 {
195         int ret = 0;
196         CURL *curl = NULL;
197         CURLcode res = CURLE_OK;
198         long r_code = 0;
199         char *response = NULL;
200
201         retvm_if(!http_initialized, -1, "http is not initialized yet");
202         retvm_if(!url, -1, "url is null");
203         retvm_if(!msg_body, -1, "msg_body is null");
204
205         curl = curl_easy_init();
206
207         retvm_if(!curl, NULL, "failed to curl_easy_init()");
208
209         /* TODO : what should I do before post result */
210         if (headers)
211                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
212
213         curl_easy_setopt(curl, CURLOPT_URL, url);
214         curl_easy_setopt(curl, CURLOPT_CAPATH, CERT_FILE_PATH);
215         curl_easy_setopt(curl, CURLOPT_POST, 1L);
216         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg_body);
217         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _response_write);
218         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
219
220         res = curl_easy_perform(curl);
221         if (res != CURLE_OK) {
222                 _E("curl_easy_perform() failed: %s", curl_easy_strerror(res));
223                 ret = -1;
224         }
225
226         curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &r_code);
227         if (res_code)
228                 *res_code = r_code;
229
230         _D("response code - [%d]", r_code);
231         _D("response message - %s", response ? response : "NULL");
232         if (res_msg)
233                 *res_msg = response;
234         else
235                 g_free(response);
236
237         if (headers)
238                 curl_slist_free_all(headers);
239         curl_easy_cleanup(curl);
240
241         return ret;
242 }
243
244 static int
245 __ttd_http_form_post(const char *url, struct curl_httppost *formpost,
246         long *res_code, char **res_msg)
247 {
248         int ret = 0;
249         CURL *curl = NULL;
250         CURLcode res = CURLE_OK;
251         long r_code = 0;
252         char *response = NULL;
253
254         retvm_if(!http_initialized, -1, "http is not initialized yet");
255         retvm_if(!url, -1, "url is null");
256         retvm_if(!formpost, -1, "formpost is null");
257
258         curl = curl_easy_init();
259
260         retvm_if(!curl, NULL, "failed to curl_easy_init()");
261
262         curl_easy_setopt(curl, CURLOPT_URL, url);
263         curl_easy_setopt(curl, CURLOPT_CAPATH, CERT_FILE_PATH);
264         curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
265         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _response_write);
266         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
267
268         res = curl_easy_perform(curl);
269         if (res != CURLE_OK) {
270                 _E("curl_easy_perform() failed: %s", curl_easy_strerror(res));
271                 ret = -1;
272         }
273
274         curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &r_code);
275         if (res_code)
276                 *res_code = r_code;
277
278         _D("response code - [%d]", r_code);
279         _D("response message - %s", response ? response : "NULL");
280         if (res_msg)
281                 *res_msg = response;
282         else
283                 g_free(response);
284
285         curl_easy_cleanup(curl);
286         curl_formfree(formpost);
287
288         return ret;
289 }
290
291 int ttd_http_post(
292         const char *url, const char *post_body, long *res_code, char **res_msg)
293 {
294         retvm_if(!url, -1, "url is NULL");
295         retvm_if(!post_body, -1, "post_body is NULL");
296
297         return __ttd_http_post(url, post_body, NULL, res_code, res_msg);
298 }
299
300 int ttd_http_report_post(const char *result_json, long *res_code)
301 {
302         struct curl_slist *headers = NULL;
303         const char *url = NULL;
304
305         retvm_if(!result_json, -1, "result_json is NULL");
306
307         url = __get_url_by_type(TTD_URL_REPORT);
308         retvm_if(!url, -1, "failed to get url for command POST");
309
310         _D("report - %s", result_json);
311
312         headers = curl_slist_append(headers, "Accept: application/json");
313         headers = curl_slist_append(headers, "Content-Type: application/json");
314         /* add here http headers to set new one */
315
316         return __ttd_http_post(url, result_json, headers, res_code, NULL);
317 }
318
319 int ttd_http_appdata_post(
320         const char *project, const char *data_json, long *res_code)
321 {
322         struct curl_slist *headers = NULL;
323         const char *url = NULL;
324         char *p_url = NULL;
325         int ret = 0;
326
327         retvm_if(!project, -1, "project is NULL");
328         retvm_if(!data_json, -1, "data_json is NULL");
329
330         url = __get_url_by_type(TTD_URL_DATA);
331         retvm_if(!url, -1, "failed to get url for DATA");
332
333         p_url = g_strdup_printf("%s%s", url, project);
334         retvm_if(!p_url, -1, "failed to create url for project");
335
336         _D("[%s] : %s", project, data_json);
337
338         headers = curl_slist_append(headers, "Accept: application/json");
339         headers = curl_slist_append(headers, "Content-Type: application/json");
340         /* add here http headers to set new one */
341
342         ret = __ttd_http_post(p_url, data_json, headers, res_code, NULL);
343         g_free(p_url);
344
345         return ret;
346 }
347
348 int ttd_http_file_post(const char *url,
349         const char *filename, const char *postname, long *res_code, char **res_msg)
350 {
351         struct curl_httppost *formpost = NULL;
352         struct curl_httppost *lastptr = NULL;
353         char *basename = NULL;
354
355         retvm_if(!filename, -1, "filename is NULL");
356         retvm_if(!postname, -1, "postname is NULL");
357
358         basename = g_path_get_basename(filename);
359         retvm_if(!basename, -1, "failed to get basename from %s", filename);
360
361         curl_formadd(&formpost, &lastptr,
362                 CURLFORM_COPYNAME, "content-type:",
363                 CURLFORM_COPYCONTENTS, "multipart/form-data",
364                 CURLFORM_END);
365
366         curl_formadd(&formpost, &lastptr,
367                 CURLFORM_COPYNAME, postname,
368                 CURLFORM_FILE, filename,
369                 CURLFORM_END);
370
371         curl_formadd(&formpost, &lastptr,
372                 CURLFORM_COPYNAME, "filename",
373                 CURLFORM_COPYCONTENTS, basename,
374                 CURLFORM_END);
375
376         g_free(basename);
377
378         return __ttd_http_form_post(url, formpost, res_code, res_msg);
379 }
380
381 int ttd_http_data_post(const char *url,
382         const void *data, unsigned int data_len, const char *data_name,
383         const char *postname, long *res_code, char **res_msg)
384 {
385         struct curl_httppost *formpost = NULL;
386         struct curl_httppost *lastptr = NULL;
387
388         retvm_if(!data, -1, "data is NULL");
389         retvm_if(!data_len, -1, "data_len is 0");
390         retvm_if(!data_name, -1, "data_name is NULL");
391         retvm_if(!postname, -1, "postname is NULL");
392
393         curl_formadd(&formpost, &lastptr,
394                 CURLFORM_COPYNAME, "content-type:",
395                 CURLFORM_COPYCONTENTS, "multipart/form-data",
396                 CURLFORM_END);
397
398         curl_formadd(&formpost, &lastptr,
399                 CURLFORM_COPYNAME, postname,
400                 CURLFORM_BUFFER, data_name,
401                 CURLFORM_BUFFERPTR, data,
402                 CURLFORM_BUFFERLENGTH, data_len,
403                 CURLFORM_END);
404
405         return __ttd_http_form_post(url, formpost, res_code, res_msg);
406 }
407
408 int ttd_http_logfile_post(const char *filename, long *res_code, char **res_msg)
409 {
410         const char *url = NULL;
411
412         url = __get_url_by_type(TTD_URL_LOG);
413         retvm_if(!url, -1, "failed to get url for log");
414
415         return ttd_http_file_post(url, filename, "logFile", res_code, res_msg);
416 }