00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <global.h>
00036
00037 #ifndef WIN32
00038 #include <sys/types.h>
00039 #include <sys/socket.h>
00040 #include <netinet/in.h>
00041 #include <netdb.h>
00042 #include <arpa/inet.h>
00043
00044 #endif
00045
00046 #include <pthread.h>
00047 #include <metaserver2.h>
00048 #include <version.h>
00049
00050 #ifdef HAVE_CURL_CURL_H
00051 #include <curl/curl.h>
00052 #include <curl/types.h>
00053 #include <curl/easy.h>
00054 #endif
00055
00056 static int metafd = -1;
00057
00058 static struct sockaddr_in sock;
00059
00068 void metaserver_init(void) {
00069 #ifdef WIN32
00070 struct hostent *hostbn;
00071 int temp = 1;
00072 #endif
00073
00074 if (!settings.meta_on) {
00075 metafd = -1;
00076 return;
00077 }
00078
00079 if (isdigit(settings.meta_server[0]))
00080 sock.sin_addr.s_addr = inet_addr(settings.meta_server);
00081 else {
00082 struct hostent *hostbn = gethostbyname(settings.meta_server);
00083
00084 if (hostbn == NULL) {
00085 LOG(llevDebug, "metaserver_init: Unable to resolve hostname %s\n", settings.meta_server);
00086 return;
00087 }
00088 memcpy(&sock.sin_addr, hostbn->h_addr, hostbn->h_length);
00089 }
00090 #ifdef WIN32
00091 ioctlsocket(metafd, FIONBIO , &temp);
00092 #else
00093 fcntl(metafd, F_SETFL, O_NONBLOCK);
00094 #endif
00095 if ((metafd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
00096 LOG(llevDebug, "metaserver_init: Unable to create socket, err %d\n", errno);
00097 return;
00098 }
00099 sock.sin_family = AF_INET;
00100 sock.sin_port = htons(settings.meta_port);
00101
00102
00103 if (settings.meta_host[0] == 0) {
00104 char hostname[MAX_BUF], domain[MAX_BUF];
00105
00106 if (gethostname(hostname, MAX_BUF-1)) {
00107 LOG(llevDebug, "metaserver_init: gethostname failed - will not report hostname\n");
00108 return;
00109 }
00110
00111 #ifdef WIN32
00112 hostbn = gethostbyname(hostname);
00113 if (hostbn != (struct hostent *)NULL)
00114 memcpy(domain, hostbn->h_addr, hostbn->h_length);
00115
00116 if (hostbn == (struct hostent *)NULL) {
00117 #else
00118 if (getdomainname(domain, MAX_BUF-1)) {
00119 #endif
00120 LOG(llevDebug, "metaserver_init: getdomainname failed - will not report hostname\n");
00121 return;
00122 }
00123
00124 sprintf(settings.meta_host, "%s.%s", hostname, domain);
00125 }
00126 }
00127
00134 void metaserver_update(void) {
00135 char data[MAX_BUF], num_players = 0;
00136 player *pl;
00137
00138
00139
00140
00141
00142
00143
00144 for (pl = first_player; pl != NULL; pl = pl->next) {
00145 if (pl->ob->map == NULL)
00146 continue;
00147 if (pl->hidden)
00148 continue;
00149 if (QUERY_FLAG(pl->ob, FLAG_WIZ))
00150 continue;
00151 if (QUERY_FLAG(pl->ob, FLAG_AFK))
00152 continue;
00153 if (pl->state != ST_PLAYING && pl->state != ST_GET_PARTY_PASSWORD)
00154 continue;
00155 if (pl->socket.is_bot)
00156 continue;
00157 num_players++;
00158 }
00159
00160
00161 if (metafd != -1) {
00162 snprintf(data, sizeof(data), "%s|%d|%s|%s|%d|%d|%ld", settings.meta_host, num_players,
00163 FULL_VERSION,
00164 settings.meta_comment, cst_tot.ibytes, cst_tot.obytes,
00165 (long)time(NULL)-cst_tot.time_start);
00166 if (sendto(metafd, data, strlen(data), 0, (struct sockaddr *)&sock, sizeof(sock)) < 0) {
00167 LOG(llevDebug, "metaserver_update: sendto failed, err = %d\n", errno);
00168 }
00169 }
00170
00171
00172
00173
00174 pthread_mutex_lock(&ms2_info_mutex);
00175 metaserver2_updateinfo.num_players = num_players;
00176 metaserver2_updateinfo.in_bytes = cst_tot.ibytes;
00177 metaserver2_updateinfo.out_bytes = cst_tot.obytes;
00178 metaserver2_updateinfo.uptime = (long)time(NULL)-cst_tot.time_start;
00179 pthread_mutex_unlock(&ms2_info_mutex);
00180
00181 }
00182
00196 typedef struct _MetaServer2 {
00197 char *hostname;
00198 struct _MetaServer2 *next;
00199 } MetaServer2;
00200
00201 static MetaServer2 *metaserver2;
00202
00211 typedef struct _LocalMeta2Info {
00212 int notification;
00213 char *hostname;
00214 int portnumber;
00215 char *html_comment;
00216 char *text_comment;
00217 char *archbase;
00218 char *mapbase;
00219 char *codebase;
00220 char *flags;
00221 } LocalMeta2Info;
00222
00223 static LocalMeta2Info local_info;
00224
00225
00226 pthread_mutex_t ms2_info_mutex;
00227
00228 MetaServer2_UpdateInfo metaserver2_updateinfo;
00229
00236 static void free_metaserver2(MetaServer2 *ms) {
00237 free(ms->hostname);
00238 free(ms);
00239 }
00240
00255 int metaserver2_init(void) {
00256 static int has_init = 0;
00257 FILE *fp;
00258 char buf[MAX_BUF], *cp;
00259 MetaServer2 *ms2, *msnext;
00260 int comp;
00261 pthread_t thread_id;
00262
00263 #ifdef HAVE_CURL_CURL_H
00264 if (!has_init) {
00265 memset(&local_info, 0, sizeof(LocalMeta2Info));
00266 memset(&metaserver2_updateinfo, 0, sizeof(MetaServer2_UpdateInfo));
00267
00268 local_info.portnumber = settings.csport;
00269 metaserver2 = NULL;
00270 pthread_mutex_init(&ms2_info_mutex, NULL);
00271 curl_global_init(CURL_GLOBAL_ALL);
00272 } else {
00273 local_info.notification = 0;
00274 if (local_info.hostname)
00275 FREE_AND_CLEAR(local_info.hostname);
00276 if (local_info.html_comment)
00277 FREE_AND_CLEAR(local_info.html_comment);
00278 if (local_info.text_comment)
00279 FREE_AND_CLEAR(local_info.text_comment);
00280 if (local_info.archbase)
00281 FREE_AND_CLEAR(local_info.archbase);
00282 if (local_info.mapbase)
00283 FREE_AND_CLEAR(local_info.mapbase);
00284 if (local_info.codebase)
00285 FREE_AND_CLEAR(local_info.codebase);
00286 if (local_info.flags)
00287 FREE_AND_CLEAR(local_info.flags);
00288 for (ms2 = metaserver2; ms2; ms2 = msnext) {
00289 msnext = ms2->next;
00290 free_metaserver2(ms2);
00291 }
00292 metaserver2 = NULL;
00293 }
00294 #endif
00295
00296
00297 snprintf(buf, sizeof(buf), "%s/metaserver2", settings.confdir);
00298
00299 if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL) {
00300 LOG(llevError, "Warning: No metaserver2 file found\n");
00301 return 0;
00302 }
00303 while (fgets(buf, MAX_BUF-1, fp) != NULL) {
00304 if (buf[0] == '#')
00305 continue;
00306
00307 if ((cp = strrchr(buf, '\n')) != NULL)
00308 *cp = '\0';
00309
00310
00311 if (buf[0] == 0)
00312 continue;
00313
00314
00315
00316 if ((cp = strpbrk(buf, " \t")) != NULL) {
00317 while (isspace(*cp))
00318 *cp++ = 0;
00319 } else {
00320
00321
00322
00323 cp = "";
00324 }
00325
00326 if (!strcasecmp(buf, "metaserver2_notification")) {
00327 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00328 local_info.notification = TRUE;
00329 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00330 local_info.notification = FALSE;
00331 } else {
00332 LOG(llevError, "metaserver2: Unknown value for metaserver2_notification: %s\n", cp);
00333 }
00334 } else if (!strcasecmp(buf, "metaserver2_server")) {
00335 if (*cp != 0) {
00336 ms2 = calloc(1, sizeof(MetaServer2));
00337 ms2->hostname = strdup(cp);
00338 ms2->next = metaserver2;
00339 metaserver2 = ms2;
00340 } else {
00341 LOG(llevError, "metaserver2: metaserver2_server must have a value.\n");
00342 }
00343 } else if (!strcasecmp(buf, "localhostname")) {
00344 if (*cp != 0) {
00345 local_info.hostname = strdup_local(cp);
00346 } else {
00347 LOG(llevError, "metaserver2: localhostname must have a value.\n");
00348 }
00349 } else if (!strcasecmp(buf, "portnumber")) {
00350 if (*cp != 0) {
00351 local_info.portnumber = atoi(cp);
00352 } else {
00353 LOG(llevError, "metaserver2: portnumber must have a value.\n");
00354 }
00355
00356
00357
00358
00359 } else if (!strcasecmp(buf, "html_comment")) {
00360 local_info.html_comment = strdup(cp);
00361 } else if (!strcasecmp(buf, "text_comment")) {
00362 local_info.text_comment = strdup(cp);
00363 } else if (!strcasecmp(buf, "archbase")) {
00364 local_info.archbase = strdup(cp);
00365 } else if (!strcasecmp(buf, "mapbase")) {
00366 local_info.mapbase = strdup(cp);
00367 } else if (!strcasecmp(buf, "codebase")) {
00368 local_info.codebase = strdup(cp);
00369 } else if (!strcasecmp(buf, "flags")) {
00370 local_info.flags = strdup(cp);
00371 } else {
00372 LOG(llevError, "Unknown value in metaserver2 file: %s\n", buf);
00373 }
00374 }
00375 close_and_delete(fp, comp);
00376
00377
00378 if (!local_info.hostname)
00379 local_info.notification = 0;
00380
00381 #ifndef HAVE_CURL_CURL_H
00382 if (local_info.notification) {
00383 LOG(llevError, "metaserver2 file is set to do notification, but libcurl is not found.\n");
00384 LOG(llevError, "Either fix your compilation, or turn of metaserver2 notification in \n");
00385 LOG(llevError, "the %s/metaserver2 file.\n", settings.confdir);
00386 LOG(llevError, "Exiting program.\n");
00387 exit(1);
00388 }
00389 #endif
00390
00391 if (local_info.notification) {
00392
00393
00394
00395
00396
00397 if (!local_info.html_comment)
00398 local_info.html_comment = strdup("");
00399 if (!local_info.text_comment)
00400 local_info.text_comment = strdup("");
00401 if (!local_info.archbase)
00402 local_info.archbase = strdup("");
00403 if (!local_info.mapbase)
00404 local_info.mapbase = strdup("");
00405 if (!local_info.codebase)
00406 local_info.codebase = strdup("");
00407 if (!local_info.flags)
00408 local_info.flags = strdup("");
00409
00410 comp = pthread_create(&thread_id, NULL, metaserver2_thread, NULL);
00411 if (comp) {
00412 LOG(llevError, "metaserver2_init: return code from pthread_create() is %d\n", comp);
00413
00414
00415 local_info.notification = 0;
00416 }
00417 }
00418 return local_info.notification;
00419 }
00420
00427 static size_t metaserver2_writer(void *ptr, size_t size, size_t nmemb, void *data) {
00428 size_t realsize = size*nmemb;
00429
00430 LOG(llevDebug, "metaserver2_writer- Start of text:\n%s\n", (const char*)ptr);
00431 LOG(llevDebug, "metaserver2_writer- End of text:\n");
00432
00433 return realsize;
00434 }
00435
00436
00442 static void metaserver2_updates(void) {
00443 #ifdef HAVE_CURL_CURL_H
00444 MetaServer2 *ms2;
00445 struct curl_httppost *formpost = NULL;
00446 struct curl_httppost *lastptr = NULL;
00447 char buf[MAX_BUF];
00448
00449
00450
00451
00452
00453
00454
00455 curl_formadd(&formpost, &lastptr,
00456 CURLFORM_COPYNAME, "hostname",
00457 CURLFORM_COPYCONTENTS, local_info.hostname,
00458 CURLFORM_END);
00459
00460 snprintf(buf, MAX_BUF-1, "%d", local_info.portnumber);
00461 curl_formadd(&formpost, &lastptr,
00462 CURLFORM_COPYNAME, "port",
00463 CURLFORM_COPYCONTENTS, buf,
00464 CURLFORM_END);
00465
00466 curl_formadd(&formpost, &lastptr,
00467 CURLFORM_COPYNAME, "html_comment",
00468 CURLFORM_COPYCONTENTS, local_info.html_comment,
00469 CURLFORM_END);
00470
00471 curl_formadd(&formpost, &lastptr,
00472 CURLFORM_COPYNAME, "text_comment",
00473 CURLFORM_COPYCONTENTS, local_info.text_comment,
00474 CURLFORM_END);
00475
00476 curl_formadd(&formpost, &lastptr,
00477 CURLFORM_COPYNAME, "archbase",
00478 CURLFORM_COPYCONTENTS, local_info.archbase,
00479 CURLFORM_END);
00480
00481 curl_formadd(&formpost, &lastptr,
00482 CURLFORM_COPYNAME, "mapbase",
00483 CURLFORM_COPYCONTENTS, local_info.mapbase,
00484 CURLFORM_END);
00485
00486 curl_formadd(&formpost, &lastptr,
00487 CURLFORM_COPYNAME, "codebase",
00488 CURLFORM_COPYCONTENTS, local_info.codebase,
00489 CURLFORM_END);
00490
00491 curl_formadd(&formpost, &lastptr,
00492 CURLFORM_COPYNAME, "flags",
00493 CURLFORM_COPYCONTENTS, local_info.flags,
00494 CURLFORM_END);
00495
00496 pthread_mutex_lock(&ms2_info_mutex);
00497
00498 snprintf(buf, MAX_BUF-1, "%d", metaserver2_updateinfo.num_players);
00499 curl_formadd(&formpost, &lastptr,
00500 CURLFORM_COPYNAME, "num_players",
00501 CURLFORM_COPYCONTENTS, buf,
00502 CURLFORM_END);
00503
00504 snprintf(buf, MAX_BUF-1, "%d", metaserver2_updateinfo.in_bytes);
00505 curl_formadd(&formpost, &lastptr,
00506 CURLFORM_COPYNAME, "in_bytes",
00507 CURLFORM_COPYCONTENTS, buf,
00508 CURLFORM_END);
00509
00510 snprintf(buf, MAX_BUF-1, "%d", metaserver2_updateinfo.out_bytes);
00511 curl_formadd(&formpost, &lastptr,
00512 CURLFORM_COPYNAME, "out_bytes",
00513 CURLFORM_COPYCONTENTS, buf,
00514 CURLFORM_END);
00515
00516 snprintf(buf, MAX_BUF-1, "%ld", metaserver2_updateinfo.uptime);
00517 curl_formadd(&formpost, &lastptr,
00518 CURLFORM_COPYNAME, "uptime",
00519 CURLFORM_COPYCONTENTS, buf,
00520 CURLFORM_END);
00521
00522 pthread_mutex_unlock(&ms2_info_mutex);
00523
00524
00525
00526
00527 curl_formadd(&formpost, &lastptr,
00528 CURLFORM_COPYNAME, "version",
00529 CURLFORM_COPYCONTENTS, FULL_VERSION,
00530 CURLFORM_END);
00531
00532 snprintf(buf, MAX_BUF-1, "%d", VERSION_SC);
00533 curl_formadd(&formpost, &lastptr,
00534 CURLFORM_COPYNAME, "sc_version",
00535 CURLFORM_COPYCONTENTS, buf,
00536 CURLFORM_END);
00537
00538 snprintf(buf, MAX_BUF-1, "%d", VERSION_CS);
00539 curl_formadd(&formpost, &lastptr,
00540 CURLFORM_COPYNAME, "cs_version",
00541 CURLFORM_COPYCONTENTS, buf,
00542 CURLFORM_END);
00543
00544 for (ms2 = metaserver2; ms2; ms2 = ms2->next) {
00545 CURL *curl;
00546 CURLcode res;
00547
00548 curl = curl_easy_init();
00549 if (curl) {
00550
00551 curl_easy_setopt(curl, CURLOPT_URL, ms2->hostname);
00552 curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
00553
00554
00555
00556
00557
00558 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, metaserver2_writer);
00559 res = curl_easy_perform(curl);
00560
00561 if (res)
00562 fprintf(stderr, "easy_perform got error %d\n", res);
00563
00564
00565 curl_easy_cleanup(curl);
00566 }
00567 }
00568
00569 curl_formfree(formpost);
00570 #endif
00571 }
00572
00586 void *metaserver2_thread(void *junk) {
00587 while (1) {
00588 metaserver2_updates();
00589 sleep(60);
00590 }
00591 }