2 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "http_private.h"
20 void _check_curl_multi_status(gpointer user_data)
22 __http_transaction_h *transaction = NULL;
23 __http_session_h *session = (__http_session_h *)user_data;
25 CURLMsg* message = NULL;
27 CURL* curl_easy = NULL;
29 CURLcode curl_code = CURLE_OK;
31 message = curl_multi_info_read(session->multi_handle, &count);
33 while (message != NULL) {
34 if (message->msg == CURLMSG_DONE) {
35 curl_easy = message->easy_handle;
36 curl_code = message->data.result;
37 curl_easy_getinfo(curl_easy, CURLINFO_PRIVATE, &transaction);
38 curl_easy_getinfo(curl_easy, CURLINFO_EFFECTIVE_URL, &url);
40 DBG("Completed -%s: result(%d)\n", url, curl_code);
44 if (transaction->completed_cb)
45 transaction->completed_cb(transaction, transaction->completed_user_data);
47 case CURLE_COULDNT_RESOLVE_HOST:
48 if (transaction->aborted_cb)
49 transaction->aborted_cb(transaction, HTTP_ERROR_COULDNT_RESOLVE_HOST, transaction->aborted_user_data);
51 case CURLE_COULDNT_CONNECT:
52 if (transaction->aborted_cb)
53 transaction->aborted_cb(transaction, HTTP_ERROR_COULDNT_CONNECT, transaction->aborted_user_data);
55 case CURLE_SSL_CONNECT_ERROR:
56 if (transaction->aborted_cb)
57 transaction->aborted_cb(transaction, HTTP_ERROR_SSL_CONNECT_ERROR, transaction->aborted_user_data);
59 case CURLE_OPERATION_TIMEDOUT:
60 if (transaction->aborted_cb)
61 transaction->aborted_cb(transaction, HTTP_ERROR_OPERATION_TIMEDOUT, transaction->aborted_user_data);
67 if (session->multi_handle != NULL && curl_easy != NULL) {
68 curl_multi_remove_handle(session->multi_handle, curl_easy);
71 message = curl_multi_info_read(session->multi_handle, &count);
75 int _generate_session_id(void)
82 gboolean timer_expired_callback(gpointer user_data)
84 __http_session_h* session = (__http_session_h *)user_data;
88 ret = curl_multi_socket_action(session->multi_handle, CURL_SOCKET_TIMEOUT, 0, &(session->still_running));
90 DBG("CURLM_OK - Called curl_multi_socket_action()\n");
92 print_curl_multi_errorCode(ret);
94 _check_curl_multi_status(session);
99 gboolean _handle_event(int fd, int action, gpointer user_data)
101 __http_session_h *session = (__http_session_h *)user_data;
103 int running_handles = -1;
105 CURLMcode ret = CURLM_OK;
107 ret = curl_multi_socket_action(session->multi_handle, fd, action, &running_handles);
109 DBG("CURLM_OK: Called curl_multi_socket_action(%d)\n", action);
111 print_curl_multi_errorCode(ret);
113 _check_curl_multi_status(session);
115 if (running_handles > 0) {
118 DBG("last transfer done, kill timeout\n");
119 if (session->timer_event) {
120 g_source_remove(session->timer_event);
121 session->timer_event = 0;
127 gboolean __handle_socket_received_event_cb(GIOChannel *channel, GIOCondition condition, gpointer user_data)
131 if (condition & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
134 fd = g_io_channel_unix_get_fd(channel);
136 /* CURL_CSELECT_IN : 1, CURL_CSELECT_OUT: 2 */
137 action = (condition & G_IO_IN ? CURL_CSELECT_IN : 0) | (condition & G_IO_OUT ? CURL_CSELECT_OUT : 0);
139 ret = _handle_event(fd, action, user_data);
146 /* Clean up the __http_socket_info_h structure */
147 static void _remove_socket_info(__http_socket_info_h *sock_info)
152 if (sock_info->event) {
153 g_source_remove(sock_info->event);
154 sock_info->event = 0;
156 if (sock_info->channel) {
157 g_io_channel_unref(sock_info->channel);
158 sock_info->channel = NULL;
164 /* Assign socket information to a __http_socket_info_h structure */
165 static void _set_socket_info(__http_socket_info_h *sock_info, curl_socket_t fd, CURL *curl_easy, int action, void *user_data)
167 __http_session_h *session = (__http_session_h *)user_data;
168 GIOCondition condition = (action & CURL_POLL_IN ? G_IO_IN : 0) | (action & CURL_POLL_OUT ? G_IO_OUT : 0);
170 sock_info->sockfd = fd;
171 sock_info->action = action;
172 sock_info->easy_handle = curl_easy;
173 if (sock_info->event) {
174 g_source_remove(sock_info->event);
175 sock_info->event = 0;
177 sock_info->event = g_io_add_watch(sock_info->channel, condition, __handle_socket_received_event_cb, session);
180 /* Initialize a new Socket Info structure */
181 static void _add_socket_info(curl_socket_t fd, CURL *curl_easy, int action, void *user_data)
183 __http_session_h *session = (__http_session_h *)user_data;
184 __http_socket_info_h *sock_info = (__http_socket_info_h *)malloc(sizeof(__http_socket_info_h));
186 sock_info->session = session;
187 sock_info->channel = g_io_channel_unix_new(fd);
188 sock_info->event = 0;
189 _set_socket_info(sock_info, fd, curl_easy, action, session);
190 curl_multi_assign(session->multi_handle, fd, sock_info);
193 int __handle_socket_cb(CURL *curl_easy, curl_socket_t fd, int action, void *user_data, void *socketp)
195 __http_session_h *session = (__http_session_h *)user_data;
196 __http_socket_info_h *sock_info = (__http_socket_info_h*) socketp;
198 static const char *actionstr[] = { "none", "IN", "OUT", "INOUT", "REMOVE"};
200 DBG("__handle_socket_cb: fd=%d easy_handle=%p action=%s ", fd, curl_easy, actionstr[action]);
201 if (action == CURL_POLL_REMOVE) {
202 DBG("CURL_POLL_REMOVE\n");
203 _remove_socket_info(sock_info);
206 DBG("Adding data: %s%s\n", action & CURL_POLL_IN ? "READ" : "", action & CURL_POLL_OUT ? "WRITE" : "");
207 _add_socket_info(fd, curl_easy, action, session);
209 DBG("Changing action from %d to %d\n", sock_info->action, action);
210 _set_socket_info(sock_info, fd, curl_easy, action, session);
217 int __handle_timer_cb(CURLM *curl_multi, long timeout_ms, void *user_data)
219 __http_session_h* session = (__http_session_h *)user_data;
221 session->timer_event = g_timeout_add(timeout_ms , timer_expired_callback , session);
226 API int http_session_create(http_session_mode_e mode, http_session_h *http_session)
228 _retvm_if(_http_is_init() == false, HTTP_ERROR_INVALID_OPERATION,
229 "http isn't initialized");
230 _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
231 "parameter(http_session) is NULL\n");
233 __http_session_h *session = NULL;
235 session = (__http_session_h *)malloc(sizeof(__http_session_h));
236 if (session == NULL) {
237 ERR("Fail to allocate session memory!!");
238 return HTTP_ERROR_OUT_OF_MEMORY;
241 session->multi_handle = curl_multi_init();
242 session->session_id = _generate_session_id();
243 session->active_transaction_count = 0;
244 session->session_mode = mode;
245 session->auto_redirect = FALSE;
247 curl_multi_setopt(session->multi_handle, CURLMOPT_SOCKETFUNCTION, __handle_socket_cb);
248 curl_multi_setopt(session->multi_handle, CURLMOPT_SOCKETDATA, session);
249 curl_multi_setopt(session->multi_handle, CURLMOPT_TIMERFUNCTION, __handle_timer_cb);
250 curl_multi_setopt(session->multi_handle, CURLMOPT_TIMERDATA, session);
252 if (mode == HTTP_SESSION_MODE_PIPELINING)
253 curl_multi_setopt(session->multi_handle, CURLMOPT_PIPELINING, 1L);
255 *http_session = (http_session_h)session;
257 return HTTP_ERROR_NONE;
260 API int http_session_destroy(http_session_h http_session)
262 _retvm_if(_http_is_init() == false, HTTP_ERROR_INVALID_OPERATION,
263 "http isn't initialized");
264 _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
265 "parameter(http_session) is NULL\n");
267 __http_session_h *session = (__http_session_h *)http_session;
270 if (session->multi_handle) {
271 curl_multi_cleanup(session->multi_handle);
272 session->multi_handle = NULL;
275 session->active_transaction_count = 0;
276 session->still_running = 0;
277 session->auto_redirect = FALSE;
279 if (session->timer_event) {
280 g_source_remove(session->timer_event);
281 session->timer_event = 0;
288 return HTTP_ERROR_NONE;
291 API int http_session_set_auto_redirection(http_session_h http_session, bool auto_redirection)
293 _retvm_if(_http_is_init() == false, HTTP_ERROR_INVALID_OPERATION,
294 "http isn't initialized");
295 _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
296 "parameter(http_session) is NULL\n");
298 __http_session_h *session = (__http_session_h *)http_session;
300 session->auto_redirect = auto_redirection;
302 return HTTP_ERROR_NONE;
305 API int http_session_get_auto_redirection(http_session_h http_session, bool *auto_redirect)
307 _retvm_if(_http_is_init() == false, HTTP_ERROR_INVALID_OPERATION, "http isn't initialized");
308 _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER, "parameter(http_session) is NULL\n");
309 _retvm_if(auto_redirect == NULL, HTTP_ERROR_INVALID_PARAMETER, "parameter(auto_redirect) is NULL\n");
311 __http_session_h *session = (__http_session_h *)http_session;
313 *auto_redirect = session->auto_redirect;
315 return HTTP_ERROR_NONE;
318 API int http_session_get_active_transaction_count(http_session_h http_session, int *active_transaction_count)
320 _retvm_if(_http_is_init() == false, HTTP_ERROR_INVALID_OPERATION,
321 "http isn't initialized");
322 _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
323 "parameter(http_session) is NULL\n");
324 _retvm_if(active_transaction_count == NULL, HTTP_ERROR_INVALID_PARAMETER,
325 "parameter(active_transaction_count) is NULL\n");
327 __http_session_h *session = (__http_session_h *)http_session;
329 *active_transaction_count = session->active_transaction_count;
331 return HTTP_ERROR_NONE;
334 API int http_session_get_max_transaction_count(http_session_h http_session, int *transaction_count)
336 _retvm_if(_http_is_init() == false, HTTP_ERROR_INVALID_OPERATION,
337 "http isn't initialized");
338 _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
339 "parameter(http_session) is NULL\n");
340 _retvm_if(transaction_count == NULL, HTTP_ERROR_INVALID_PARAMETER,
341 "parameter(transaction_count) is NULL\n");
343 __http_session_h *session = (__http_session_h *)http_session;
345 if (session->session_mode == HTTP_SESSION_MODE_NORMAL)
346 *transaction_count = _MAX_HTTP_TRANSACTIONS_PER_SESSION_NORMAL;
347 else if (session->session_mode == HTTP_SESSION_MODE_PIPELINING)
348 *transaction_count = _MAX_HTTP_TRANSACTIONS_PER_SESSION_PIPE;
350 *transaction_count = -1;
352 return HTTP_ERROR_NONE;