40a8c30b36bc1f963138b1c3ebee46106ff61a69
[platform/core/location/location-module.git] / modules / osm / osm-http.c
1 /*
2  * location-module
3  *
4  * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Youngae Kang <youngae.kang@samsung.com>, Yunhan Kim <yhan.kim@samsung.com>,
7  *          Genie Kim <daejins.kim@samsung.com>, Minjune Kim <sena06.kim@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #include <curl/curl.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <glib.h>
26 #include <pthread.h>
27 #include <unistd.h>
28 #include "log.h"
29 #include "location-osm-route.h"
30 #include "osm-http.h"
31
32 //http://www.yournavigation.org/api/1.0/gosmore.php?format=geojson&flat=52.215676&flon=5.963946&tlat=52.2573&tlon=6.1799&v=motorcar&fast=1&layer=mapnik
33
34
35 #define YOUR_NAVIGATION_SERVER  "http://www.yournavigation.org/api/1.0/gosmore.php?"
36 #define YOUR_NAVIGATION_FORMAT  "format="
37
38 #define KML_FORMAT "kml"
39 #define GEOJSON_FORMAT "geojson"
40
41 static CURLM *g_multi_handle;
42 static pthread_t g_http_thread;
43 static GHashTable *g_req_table;
44
45 pthread_mutex_t curl_mutex = PTHREAD_MUTEX_INITIALIZER;
46
47 typedef int (*curl_async_cb) (int req_id, int error, const char *result, int result_len, void *user_data);
48
49 typedef struct {
50          guint req_id;
51         CURL *ctx;
52         curl_async_cb cb;
53         void *user_data;
54
55         int result_len;
56         char *result;
57 } curl_item_t;
58
59 CURL*
60 curl_create_session (guint *req_id)
61 {
62         static guint session_id = 0;
63
64         CURL_MUTEX_LOCK(&curl_mutex);
65         if (!g_multi_handle)
66                 g_multi_handle = curl_multi_init();
67         CURL_MUTEX_UNLOCK(&curl_mutex);
68
69         CURL* ctx = curl_easy_init();
70         if (!ctx) {
71                 MOD_LOGW("Unable to initialize cURL interface\n");
72                 return NULL;
73         }
74
75         *req_id = ++session_id;
76
77         MOD_LOGW ("req_id [%d]", *req_id);
78
79         return ctx;
80 }
81
82 int
83 curl_destroy_session (CURL* ctx)
84 {
85         if (!ctx) return -1;
86
87         curl_easy_cleanup(ctx);
88
89         return 0;
90 }
91
92 static gboolean
93 _compare_ctx (gpointer key, gpointer value, gpointer userdata)
94 {
95         if (!key || !value || !userdata) return FALSE;
96
97         curl_item_t * item = (curl_item_t*) value;
98         CURL *ctx = (CURL*) userdata;
99
100         if (item->ctx == ctx) {
101                 return TRUE;
102         }
103
104         return FALSE;
105 }
106
107 static int
108 _send_resp (curl_item_t *item)
109 {
110         MOD_LOGW ("Send response [%p]", item);
111         if (!item) return -1;
112         MOD_LOGW("Result [%s]", item->result);
113
114         if (item->cb)
115                 item->cb (item->req_id, 0, item->result, item->result_len, item->user_data);
116
117         if (item->user_data) {
118                 g_free(item->user_data);
119                 item->user_data = NULL;
120         }
121
122         if (item->result) {
123                 g_free(item->result);
124                 item->result = NULL;
125         }
126
127         return 0;
128 }
129
130 static void *
131 _create_http_thread(void *data)
132 {
133         MOD_LOGW ("Create Thread");
134         CURLMsg *msg = NULL;
135         int msgs_left = 0;
136         int still_running = 1;
137         int rc = 0;
138         int ret = 0;
139         struct timeval timeout;
140
141         timeout.tv_sec = 10;
142         timeout.tv_usec = 0;
143
144         while(still_running) {
145                 fd_set fdread;
146                 fd_set fdwrite;
147                 fd_set fdexecp;
148                 int maxfd = -1;
149
150                 FD_ZERO(&fdread);
151                 FD_ZERO(&fdwrite);
152                 FD_ZERO(&fdexecp);
153
154                 if (g_req_table)
155                         curl_multi_fdset (g_multi_handle, &fdread, &fdwrite, &fdexecp, &maxfd);
156                 else {
157                         MOD_LOGW ("Hash table is NULL");
158                         break;
159                 }
160
161                 rc = select(maxfd+1, &fdread, &fdwrite, &fdexecp, &timeout);
162                 MOD_LOGW ("run loop [%d]", still_running);
163                 switch (rc) {
164                         case -1:
165                                 break;
166                         case 0:
167                         default:
168                                 /* Timeout or readable / writable sockets */
169                                 curl_multi_perform(g_multi_handle, &still_running);
170                                 if (ret != CURLM_OK) {
171                                         MOD_LOGW ("curl_multi_perform error [%d]", ret);
172                                         break;
173                                 }
174
175                                 msg = curl_multi_info_read(g_multi_handle, &msgs_left);
176                                 if (msg && msg->msg == CURLMSG_DONE) {
177                                         curl_item_t *item = g_hash_table_find (g_req_table, _compare_ctx, msg->easy_handle);
178                                         if (item) {
179                                                 MOD_LOGW ("Found Item ID[%d]", item->req_id);
180                                                 int ret = _send_resp(item);
181                                                 if (ret) {
182                                                         MOD_LOGW ("Fail to send response [%d]", ret);
183                                                         g_http_thread = 0;
184                                                         return NULL;
185                                                 }
186
187                                                 g_hash_table_remove (g_req_table, (gpointer) &item->req_id);
188
189                                                 curl_destroy_session(item->ctx);
190                                                 if (item) {
191                                                         g_free(item);
192                                                         item = NULL;
193                                                 }
194
195                                         }
196                                 }
197                                 else {
198                                         sleep(1);
199                                 }
200                                 break;
201                 }
202         }
203
204         CURL_MUTEX_LOCK (&curl_mutex);
205         if (g_multi_handle) {
206                 curl_multi_cleanup(g_multi_handle);
207                 g_multi_handle = NULL;
208         }
209         CURL_MUTEX_UNLOCK (&curl_mutex);
210
211         MOD_LOGW("End Thread");
212         g_http_thread = 0;
213
214         return NULL;
215 }
216
217 static size_t
218 _osm_route_cb (char *ptr, size_t size, size_t nmemb, void *userdata)
219 {
220         curl_item_t *item = (curl_item_t*)userdata;
221
222         MOD_LOGW("size[%d], nmemb [%d]", size, nmemb);
223         int reallo_len = size * nmemb;
224
225         item->result = realloc (item->result, item->result_len + reallo_len + 1);
226         if (item->result == NULL) {
227                 /* out of memory! */
228                 MOD_LOGW("not enough memory (realloc returned NULL)\n");
229                 return 0;
230         }
231
232         memcpy(&(item->result[item->result_len]), ptr, reallo_len);
233         item->result_len += reallo_len;
234         item->result[item->result_len] = 0;
235
236         return reallo_len;
237 }
238
239 static int
240 _route_cb (int req_id, int error, const char *result, int result_len, void *user_data)
241 {
242         GList *route = NULL;
243         char *error_code = NULL;
244         char *error_msg = NULL;
245
246         osm_data_t *ndata = (osm_data_t *) user_data;
247         if (result && result_len > 0) {
248                 // parsing
249         }
250
251         convert_data_to_location_service (result, result_len, ndata->origin, ndata->dest, &route);
252
253
254         ndata->route_cb(error, req_id, route, error_code, error_msg, ndata->user_data);
255
256         return 0;
257 }
258
259 int
260 curl_request_route_async(const char *url, osm_data_t *data, guint *req_id)
261 {
262         curl_item_t *item = g_new0(curl_item_t, 1);
263         if (!item) return -999;
264
265         int stillrunning = 0;
266
267
268         CURL *ctx = curl_create_session (req_id);
269         if (!ctx) {
270                 *req_id = -1;
271                 return -1;
272         }
273
274
275         CURLMcode err = 0;
276         int ret = 0;
277
278         item->req_id = *req_id;
279         item->user_data = data;
280         item->ctx = ctx;
281         item->cb = _route_cb;
282
283         curl_easy_setopt (ctx, CURLOPT_URL, url);
284 //      curl_easy_setopt (ctx, CURLOPT_NOPROGRESS , 0L);
285 //      curl_easy_setopt( ctx , CURLOPT_WRITEHEADER , stderr);
286         curl_easy_setopt( ctx, CURLOPT_WRITEFUNCTION, _osm_route_cb);
287         curl_easy_setopt( ctx , CURLOPT_WRITEDATA, item);
288
289         CURL_MUTEX_LOCK (&curl_mutex);
290         curl_multi_add_handle(g_multi_handle, ctx);
291
292         if (!g_req_table) {
293                 g_req_table = g_hash_table_new (g_int_hash, g_int_equal);
294         }
295
296         g_hash_table_insert(g_req_table, req_id, item);
297
298         MOD_LOGW ("ReqID: %u", *req_id);
299
300         err = curl_multi_perform(g_multi_handle, &stillrunning);
301         CURL_MUTEX_UNLOCK (&curl_mutex);
302         if (CURLM_OK != err) {
303                 MOD_LOGW ("curl_multi_perform error[%d]", err);
304                 if (item) {
305                         g_free(item);
306                         item = NULL;
307                 }
308
309                 curl_destroy_session(ctx);
310                 return -1;
311         }
312
313         if (!g_http_thread) {   //TODO
314                 ret = pthread_create(&g_http_thread, NULL, _create_http_thread, NULL);
315
316                 if (ret) {
317                         // return error
318                         MOD_LOGW ("Fail to create thread [%d", ret);
319                         if (item) {
320                                 g_free(item);
321                                 item = NULL;
322                         }
323
324                         curl_destroy_session(ctx);
325                         return -1;
326                 }
327                 MOD_LOGW ("End loop");
328                 pthread_detach(g_http_thread);
329         }
330         else {
331                 MOD_LOGW ("Thread is alive");
332         }
333
334         return 0;
335 }
336
337 int
338 curl_cancel_route_request (guint req_id)
339 {
340         curl_item_t* item = NULL;
341
342         if (!g_req_table) {
343                 return LOCATION_ERROR_NOT_FOUND;
344         }
345
346         item = (curl_item_t *)g_hash_table_lookup (g_req_table, (void* )&req_id);
347         if (!item) {
348                 return LOCATION_ERROR_NOT_FOUND;
349         }
350
351
352         if (g_multi_handle) {
353                 curl_multi_remove_handle (g_multi_handle, item->ctx);
354         }
355
356         if( item->user_data) {
357                 g_free (item->user_data);
358                 item->user_data = NULL;
359         }
360
361         if (item->result) {
362                 g_free (item->result);
363                 item->result = NULL;
364         }
365         if (item) {
366                 g_free (item);
367                 item = NULL;
368         }
369
370         gboolean ret = g_hash_table_remove(g_req_table, (void *)&req_id);
371         if (!ret) {
372                 return LOCATION_ERROR_NOT_FOUND;
373         }
374         if (g_hash_table_size(g_req_table) == 0) {
375                 MOD_LOGW ("Hash table is NULL");
376                 g_hash_table_destroy(g_req_table);
377                 g_req_table = NULL;
378         }
379
380         return LOCATION_ERROR_NONE;
381 }