Atrinik Server 2.5
socket/metaserver.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 
00030 #include <pthread.h>
00031 #include <global.h>
00032 #include <curl/curl.h>
00033 
00034 static void *metaserver_thread(void *junk);
00035 
00038 typedef struct ms_update_info
00039 {
00042     char num_players[MAX_BUF];
00043 
00046     char csport[MAX_BUF];
00047 
00050     char *players;
00051 } ms_update_info;
00052 
00055 pthread_mutex_t ms_info_mutex;
00056 
00059 ms_update_info metaserver_info;
00060 
00063 void metaserver_info_update()
00064 {
00065     player *pl;
00066     uint32 num_players = 0;
00067     StringBuffer *sb = stringbuffer_new();
00068 
00069     for (pl = first_player; pl; pl = pl->next)
00070     {
00071         if (pl->state != ST_PLAYING)
00072         {
00073             continue;
00074         }
00075 
00076         if (!pl->ms_privacy && !pl->dm_stealth)
00077         {
00078             if (sb->pos)
00079             {
00080                 stringbuffer_append_string(sb, ":");
00081             }
00082 
00083             stringbuffer_append_string(sb, pl->quick_name);
00084         }
00085 
00086         num_players++;
00087     }
00088 
00089     pthread_mutex_lock(&ms_info_mutex);
00090 
00091     if (metaserver_info.players)
00092     {
00093         free(metaserver_info.players);
00094     }
00095 
00096     snprintf(metaserver_info.num_players, sizeof(metaserver_info.num_players), "%u", num_players);
00097     metaserver_info.players = stringbuffer_finish(sb);
00098     pthread_mutex_unlock(&ms_info_mutex);
00099 }
00100 
00103 void metaserver_init()
00104 {
00105     int ret;
00106     pthread_t thread_id;
00107 
00108     if (!settings.meta_on)
00109     {
00110         return;
00111     }
00112 
00113     pthread_mutex_init(&ms_info_mutex, NULL);
00114 
00115     memset(&metaserver_info, 0, sizeof(metaserver_info));
00116     /* Store the port number. */
00117     snprintf(metaserver_info.csport, sizeof(metaserver_info.csport), "%d", settings.csport);
00118     metaserver_info_update();
00119 
00120     /* Init global cURL */
00121     curl_global_init(CURL_GLOBAL_ALL);
00122     ret = pthread_create(&thread_id, NULL, metaserver_thread, NULL);
00123 
00124     if (ret)
00125     {
00126         LOG(llevError, "metaserver_init(): Failed to create thread: %d.\n", ret);
00127     }
00128 }
00129 
00137 static size_t metaserver_writer(void *ptr, size_t size, size_t nmemb, void *data)
00138 {
00139     size_t realsize = size * nmemb;
00140 
00141     (void) data;
00142 
00143     LOG(llevDebug, "metaserver_writer(): Returned data:\n%s\n", (const char *) ptr);
00144 
00145     return realsize;
00146 }
00147 
00150 static void metaserver_update()
00151 {
00152     struct curl_httppost *formpost = NULL, *lastptr = NULL;
00153     CURL *curl;
00154     CURLcode res = 0;
00155 
00156     /* Hostname. */
00157     curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "hostname", CURLFORM_COPYCONTENTS, settings.meta_host, CURLFORM_END);
00158 
00159     /* Server version. */
00160     curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "version", CURLFORM_COPYCONTENTS, VERSION, CURLFORM_END);
00161 
00162     /* Server comment. */
00163     curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "text_comment", CURLFORM_COPYCONTENTS, settings.meta_comment, CURLFORM_END);
00164 
00165     /* Server name. */
00166     curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "name", CURLFORM_COPYCONTENTS, settings.meta_name, CURLFORM_END);
00167 
00168     pthread_mutex_lock(&ms_info_mutex);
00169     /* Number of players. */
00170     curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "num_players", CURLFORM_COPYCONTENTS, metaserver_info.num_players, CURLFORM_END);
00171 
00172     /* Player names. */
00173     curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "players", CURLFORM_COPYCONTENTS, metaserver_info.players, CURLFORM_END);
00174 
00175     /* Port number. */
00176     curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "port", CURLFORM_COPYCONTENTS, metaserver_info.csport, CURLFORM_END);
00177     pthread_mutex_unlock(&ms_info_mutex);
00178 
00179     /* Init "easy" cURL */
00180     curl = curl_easy_init();
00181 
00182     if (curl)
00183     {
00184         /* What URL that receives this POST */
00185         curl_easy_setopt(curl, CURLOPT_URL, settings.meta_server);
00186         curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
00187 
00188         /* Almost always, we will get HTTP data returned
00189          * to us - instead of it going to stderr,
00190          * we want to take care of it ourselves. */
00191         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, metaserver_writer);
00192         res = curl_easy_perform(curl);
00193 
00194         if (res)
00195         {
00196             LOG(llevDebug, "metaserver_update(): easy_perform got error %d (%s).\n", res, curl_easy_strerror(res));
00197         }
00198 
00199         /* Always cleanup */
00200         curl_easy_cleanup(curl);
00201     }
00202 
00203     /* Free the form */
00204     curl_formfree(formpost);
00205 
00206     /* Output info that the data was updated. */
00207     if (!res)
00208     {
00209         time_t now = time(NULL);
00210 
00211         LOG(llevDebug, "metaserver_update(): Sent data at %.19s.\n", ctime(&now));
00212     }
00213 }
00214 
00218 static void *metaserver_thread(void *junk)
00219 {
00220     while (1)
00221     {
00222         metaserver_update();
00223         sleep(300);
00224     }
00225 
00226     (void) junk;
00227     return NULL;
00228 }