Atrinik Client 2.5
client/curl.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00120 #include <global.h>
00121 
00123 static CURLSH *handle_share = NULL;
00125 static SDL_mutex *handle_share_mutex = NULL;
00126 
00135 static size_t curl_callback(void *ptr, size_t size, size_t nmemb, void *data)
00136 {
00137     size_t realsize = size * nmemb;
00138     curl_data *mem = (curl_data *) data;
00139 
00140     SDL_LockMutex(mem->mutex);
00141     mem->memory = realloc(mem->memory, mem->size + realsize + 1);
00142 
00143     if (mem->memory)
00144     {
00145         memcpy(&(mem->memory[mem->size]), ptr, realsize);
00146         mem->size += realsize;
00147         mem->memory[mem->size] = '\0';
00148     }
00149 
00150     SDL_UnlockMutex(mem->mutex);
00151 
00152     return realsize;
00153 }
00154 
00161 int curl_connect(void *c_data)
00162 {
00163     curl_data *data = (curl_data *) c_data;
00164     char user_agent[MAX_BUF], version[MAX_BUF];
00165     CURL *handle;
00166     CURLcode res;
00167     long http_code;
00168 
00169     package_get_version_full(version, sizeof(version));
00170 
00171     /* Store user agent for cURL, including if this is GNU/Linux build of client
00172      * or Windows one. */
00173 #if defined(LINUX)
00174     snprintf(user_agent, sizeof(user_agent), "Atrinik Client (GNU/Linux)/%s (%d)", version, SOCKET_VERSION);
00175 #elif defined(WIN32)
00176     snprintf(user_agent, sizeof(user_agent), "Atrinik Client (Win32)/%s (%d)", version, SOCKET_VERSION);
00177 #else
00178     snprintf(user_agent, sizeof(user_agent), "Atrinik Client (Unknown)/%s (%d)", version, SOCKET_VERSION);
00179 #endif
00180 
00181     /* Init "easy" cURL */
00182     handle = curl_easy_init();
00183 
00184     if (!handle)
00185     {
00186         SDL_LockMutex(data->mutex);
00187         data->status = -1;
00188         SDL_UnlockMutex(data->mutex);
00189         return -1;
00190     }
00191 
00192     /* Set connection timeout. */
00193     curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, CURL_TIMEOUT);
00194     /* Disable signals since we are in a thread. See
00195      * http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTNOSIGNAL
00196      * for details. */
00197     curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1);
00198 
00199     SDL_LockMutex(data->mutex);
00200     curl_easy_setopt(handle, CURLOPT_URL, data->url);
00201     curl_easy_setopt(handle, CURLOPT_REFERER, data->url);
00202     curl_easy_setopt(handle, CURLOPT_SHARE, handle_share);
00203     SDL_UnlockMutex(data->mutex);
00204 
00205     /* The callback function. */
00206     curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curl_callback);
00207     curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *) data);
00208 
00209     /* Set user agent. */
00210     curl_easy_setopt(handle, CURLOPT_USERAGENT, user_agent);
00211 
00212     /* Get the data. */
00213     res = curl_easy_perform(handle);
00214 
00215     if (res)
00216     {
00217         LOG(llevBug, "curl_thread(): curl_easy_perform() got error %d (%s).\n", res, curl_easy_strerror(res));
00218         curl_easy_cleanup(handle);
00219         SDL_LockMutex(data->mutex);
00220         data->status = -1;
00221         SDL_UnlockMutex(data->mutex);
00222         return -1;
00223     }
00224 
00225     curl_easy_getinfo(handle, CURLINFO_HTTP_CODE, &http_code);
00226 
00227     if (http_code != 200)
00228     {
00229         SDL_LockMutex(data->mutex);
00230         data->status = -1;
00231         SDL_UnlockMutex(data->mutex);
00232         return -1;
00233     }
00234 
00235     curl_easy_cleanup(handle);
00236 
00237     SDL_LockMutex(data->mutex);
00238     data->status = 1;
00239     SDL_UnlockMutex(data->mutex);
00240 
00241     return 1;
00242 }
00243 
00248 curl_data *curl_data_new(const char *url)
00249 {
00250     curl_data *data = malloc(sizeof(curl_data));
00251 
00252     /* Store the url. */
00253     data->url = strdup(url);
00254     data->memory = NULL;
00255     data->size = 0;
00256     data->status = 0;
00257     /* Create a mutex to protect the structure. */
00258     data->mutex = SDL_CreateMutex();
00259 
00260     return data;
00261 }
00262 
00271 curl_data *curl_download_start(const char *url)
00272 {
00273     curl_data *data = curl_data_new(url);
00274 
00275     /* Create a new thread. */
00276     data->thread = SDL_CreateThread(curl_connect, data);
00277 
00278     if (!data->thread)
00279     {
00280         LOG(llevError, "curl_download_start(): Thread creation failed.\n");
00281     }
00282 
00283     return data;
00284 }
00285 
00291 sint8 curl_download_finished(curl_data *data)
00292 {
00293     sint8 status;
00294 
00295     SDL_LockMutex(data->mutex);
00296     status = data->status;
00297     SDL_UnlockMutex(data->mutex);
00298 
00299     return status;
00300 }
00301 
00305 void curl_data_free(curl_data *data)
00306 {
00307     /* Still downloading? Kill the thread. */
00308     if (curl_download_finished(data) == 0)
00309     {
00310         SDL_KillThread(data->thread);
00311     }
00312 
00313     if (data->memory)
00314     {
00315         free(data->memory);
00316     }
00317 
00318     SDL_DestroyMutex(data->mutex);
00319     free(data->url);
00320     free(data);
00321 }
00322 
00325 static void curl_share_lock(CURL *handle, curl_lock_data data, curl_lock_access lock_access, void *userptr)
00326 {
00327     (void) handle;
00328     (void) data;
00329     (void) lock_access;
00330     SDL_LockMutex(userptr);
00331 }
00332 
00335 static void curl_share_unlock(CURL *handle, curl_lock_data data, void *userptr)
00336 {
00337     (void) handle;
00338     (void) data;
00339     SDL_UnlockMutex(userptr);
00340 }
00341 
00344 void curl_init()
00345 {
00346     curl_global_init(CURL_GLOBAL_ALL);
00347     handle_share_mutex = SDL_CreateMutex();
00348 
00349     handle_share = curl_share_init();
00350     curl_share_setopt(handle_share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
00351     curl_share_setopt(handle_share, CURLSHOPT_USERDATA, handle_share_mutex);
00352     curl_share_setopt(handle_share, CURLSHOPT_LOCKFUNC, curl_share_lock);
00353     curl_share_setopt(handle_share, CURLSHOPT_UNLOCKFUNC, curl_share_unlock);
00354 }
00355 
00358 void curl_deinit()
00359 {
00360     curl_share_cleanup(handle_share);
00361     SDL_DestroyMutex(handle_share_mutex);
00362     curl_global_cleanup();
00363 }