/* * * PACrunner - Proxy configuration daemon * * Copyright (C) 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include GMainLoop *main_loop = NULL; #define DBG(msg, ...) printf("%s():%d " msg "\n", __func__, __LINE__ , ## __VA_ARGS__ ) static void check_sockets(CURLM *multi, CURLMcode result, int handles) { CURLMsg *msg; CURL *easy; int msgs_left; char *str, *eff_url; DBG("result %d handles %d", result, handles); do { msg = curl_multi_info_read(multi, &msgs_left); if (msg == NULL) break; if (msg->msg != CURLMSG_DONE) continue; easy = msg->easy_handle; curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url); DBG("finished %s result %d", eff_url, msg->data.result); curl_multi_remove_handle(multi, easy); curl_easy_cleanup(easy); g_main_loop_quit(main_loop); } while (msgs_left > 0); } static guint timeout_source = 0; static gboolean event_callback(GIOChannel *channel, GIOCondition condition, gpointer user_data) { CURLM *multi = user_data; CURLMcode result; int sockfd, handles, action = 0; DBG("condition %d", condition); sockfd = g_io_channel_unix_get_fd(channel); if (condition & G_IO_IN) action |= CURL_CSELECT_IN; if (condition & G_IO_OUT) action |= CURL_CSELECT_OUT; result = curl_multi_socket_action(multi, sockfd, action, &handles); check_sockets(multi, result, handles); if (handles) return TRUE; if (timeout_source > 0) { g_source_remove(timeout_source); timeout_source = 0; } return FALSE; } static int socket_callback(CURL *easy, curl_socket_t sockfd, int what, void *user_data, void *socket_data) { CURLM *multi = user_data; guint source = GPOINTER_TO_UINT(socket_data); GIOChannel *channel; DBG("what %d source %d", what, source); if (source > 0) { g_source_remove(source); source = 0; } switch (what) { case CURL_POLL_NONE: DBG("poll none"); break; case CURL_POLL_IN: DBG("poll in"); channel = g_io_channel_unix_new(sockfd); source = g_io_add_watch(channel, G_IO_IN, event_callback, multi); g_io_channel_unref(channel); curl_multi_assign(multi, sockfd, GUINT_TO_POINTER(source)); break; case CURL_POLL_OUT: DBG("poll out"); channel = g_io_channel_unix_new(sockfd); source = g_io_add_watch(channel, G_IO_OUT, event_callback, multi); g_io_channel_unref(channel); curl_multi_assign(multi, sockfd, GUINT_TO_POINTER(source)); break; case CURL_POLL_INOUT: DBG("poll in/out"); channel = g_io_channel_unix_new(sockfd); source = g_io_add_watch(channel, G_IO_IN | G_IO_OUT, event_callback, multi); g_io_channel_unref(channel); curl_multi_assign(multi, sockfd, GUINT_TO_POINTER(source)); break; case CURL_POLL_REMOVE: DBG("poll remove"); break; } DBG("source %d", source); return 0; } static gboolean timeout_callback(gpointer user_data) { CURLM *multi = user_data; CURLMcode result; int handles; DBG(""); result = curl_multi_socket_all(multi, &handles); check_sockets(multi, result, handles); #ifdef WORKAROUND if (handles) return TRUE; #endif timeout_source = 0; return FALSE; } static int timer_callback(CURLM *multi, long timeout_ms, void *user_data) { guint interval = timeout_ms / 1000; DBG("interval %d", interval); if (timeout_source > 0) { g_source_remove(timeout_source); timeout_source = 0; } if (timeout_ms < 0) return 0; timeout_source = g_timeout_add_seconds(interval, timeout_callback, multi); return 0; } static CURLM *multi; static gboolean curl_download(gpointer user_data) { char *url = user_data; CURL *easy; CURLMcode result; DBG("url %s", url); easy = curl_easy_init(); curl_easy_setopt(easy, CURLOPT_URL, url); curl_easy_setopt(easy, CURLOPT_NOPROGRESS, 1); curl_easy_setopt(easy, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(easy, CURLOPT_NOPROXY, "*"); curl_easy_setopt(easy, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(easy, CURLOPT_CONNECTTIMEOUT, 30); curl_easy_setopt(easy, CURLOPT_USERAGENT, "pacrunner"); result = curl_multi_add_handle(multi, easy); return 0; } int main(int argc, char **argv) { DBG(""); multi = curl_multi_init(); curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, socket_callback); curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, multi); curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, timer_callback); curl_multi_setopt(multi, CURLMOPT_TIMERDATA, NULL); curl_multi_setopt(multi, CURLMOPT_PIPELINING, 1); main_loop = g_main_loop_new(NULL, FALSE); g_idle_add(curl_download, argv[1]); g_main_loop_run(main_loop); g_main_loop_unref(main_loop); return 0; }