123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734 |
- /* libq3.c: masterserver plugin for Quake3 servers. */
- /* Copyright (C) 2003 Andre' Schulz
- * This file is part of masterserver.
- *
- * masterserver is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * masterserver 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 masterserver; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * The author can be contacted at chickenman@exhale.de
- */
- /*
- * vim:sw=4:ts=4
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <pthread.h>
- #include <sys/socket.h> // for socket() etc.
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <math.h>
- #include "../masterserver.h"
- #define HEARTBEAT_TIMEOUT 300
- // message of the day
- #define Q3M_MOTD "Insert MOTD here."
- // for logging stuff
- #undef LOG_SUBNAME
- #define LOG_SUBNAME "libq3" // logging subcategory description
- // q3 packet stuff
- const char q3_pkt_header[] = "\xff\xff\xff\xff";
- const int q3_pkt_header_len = 4;
- const char q3_pkt_heartbeat[] = "heartbeat QuakeArena-1\n";
- const int q3_pkt_heartbeat_len= 23;
- const char q3_pkt_getinfo[] = "getinfo\n";
- const int q3_pkt_getinfo_len = 8;
- const char q3_pkt_inforsp[] = "infoResponse\n";
- const int q3_pkt_inforsp_len = 13;
- const char q3_pkt_getstatus[] = "getstatus ";
- const int q3_pkt_getstatus_len= 10;
- const char q3_pkt_statusrsp[] = "statusResponse\n";
- const int q3_pkt_statusrsp_len= 15;
- const char q3_pkt_getsrv[] = "getservers";
- const int q3_pkt_getsrv_len = 10;
- const char q3_pkt_getsrvrsp[] = "getserversResponse";
- const int q3_pkt_getsrvrsp_len= 18;
- const char q3_pkt_getmotd[] = "getmotd";
- const int q3_pkt_getmotd_len = 7;
- const char q3_pkt_motd[] = "\xff\xff\xff\xffmotd \"challenge\\%d\\motd\\%s\\\"";
- const int q3_pkt_motd_len = 28;
- const char q3_pkt_footer[] = "\\EOT";
- const int q3_pkt_footer_len = 4;
- const char q3m_plugin_version[] = "0.8";
- static port_t q3m_ports[] = { { IPPROTO_UDP, 27950 }, // master
- { IPPROTO_UDP, 27951 }, // motd
- // { IPPROTO_UDP, 27952 }, // auth
- };
- // player info
- typedef struct {
- int score;
- int ping;
- char *name;
- } q3m_player_data_t;
- // q3 plugin private data
- typedef struct {
- // statusResponse vars
- int challenge;
- int sv_punkbuster; // 0 | 1
- int g_maxGameClients;
- int capturelimit;
- int sv_maxclients; // max num of clients
- int timelimit;
- int fraglimit;
- int dmflags; // bit field
- int sv_maxPing;
- int sv_minPing;
- char *sv_hostname; // server name
- int sv_maxRate;
- int sv_floodProtect; // 0 | 1
- char *version; // self explanatory
- int g_gametype; // 0 - FFA | 1 - Tournament | 2 - Single Player | 3 - TDM | 4 - CTF
- int protocol; // q3 network protocol version
- char *mapname; // self explanatory
- int sv_privateClients; // # of passworded player slots
- int sv_allowDownload; // 0 | 1
- int bot_minplayers;
- char *gamename; // which mod
- int g_needpass; // 0 | 1
- q3m_player_data_t *_player; // player info
- // following is information not in packet
- int _players; // # of players
- int _challenge; // our challenge #
- } q3m_private_data_t;
- static void info(void); // print information about plugin
- static void free_privdata(void *);
- static int process(char *, int); // process packet and return a value
- static int process_getmotd(char *, int);
- static int process_getservers(char *);
- static int process_heartbeat(char *);
- static int send_getstatus();
- static int process_statusResponse(char *, int);
- static void cleanup(void);
- void init_plugin(void) __attribute__ ((constructor));
- static
- struct masterserver_plugin q3m
- = { "q3m",
- q3m_plugin_version,
- masterserver_version,
- q3m_ports,
- 2,
- HEARTBEAT_TIMEOUT,
- &info,
- &process,
- &free_privdata,
- &cleanup
- };
- static void
- info(void)
- {
- INFO("quake3 masterserver plugin v%s\n", q3m_plugin_version);
- INFO(" compiled for masterserver v%s\n", masterserver_version);
- }
- static void
- free_privdata(void *data)
- {
- int i;
- q3m_private_data_t *privdata = (q3m_private_data_t *) data;
- if (data == NULL) return;
- free(privdata->sv_hostname);
- free(privdata->version);
- free(privdata->mapname);
- free(privdata->gamename);
- for (i = 0; i < privdata->_players; i++)
- free(privdata->_player[i].name);
- free(privdata->_player);
- free(privdata);
- }
- static int
- process_heartbeat(char *packet)
- {
- int server_dup = 0;
- int time_diff, i;
- serverlist_t *backup_ptr;
- // first, check if server is already in our list
- for (i = 0; i < q3m.num_servers; i++) {
- if ((q3m.list[i].ip.s_addr == q3m.client.sin_addr.s_addr)
- && (q3m.list[i].port == q3m.client.sin_port)) {
- DEBUG("duplicate server detected! (%s:%d)\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port));
- server_dup = 1;
- break;
- }
- }
- INFO("heartbeat from %s:%d\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port));
- // if not, then add it to the list
- if (server_dup == 0) {
- // server is not in our list so add its ip, port and a timestamp
- q3m.list[q3m.num_servers].ip = q3m.client.sin_addr;
- q3m.list[q3m.num_servers].port = q3m.client.sin_port;
- q3m.list[q3m.num_servers].lastheartbeat = time(NULL);
- DEBUG("this is server no.: %d | lastheartbeat: %d\n",
- q3m.num_servers, q3m.list[q3m.num_servers].lastheartbeat);
- // allocate memory for private data
- q3m.list[q3m.num_servers].private_data = calloc(1, sizeof(q3m_private_data_t));
- q3m.num_servers++;
- DEBUG("reallocating server list (old size: %d -> new size: %d)\n",
- q3m.num_servers * sizeof(serverlist_t),
- (q3m.num_servers+1) * sizeof(serverlist_t));
- // back up the current list pointer in case realloc() fails
- backup_ptr = q3m.list;
- q3m.list = (serverlist_t *) realloc(q3m.list, ((q3m.num_servers+1)*sizeof(serverlist_t)));
- if (q3m.list == NULL) {
- WARNING("realloc() failed trying to get %d bytes!\n",
- (q3m.num_servers+1)*sizeof(serverlist_t));
- // since the pointer is overwritten with NULL
- // we'll recover by using the backup pointer
- q3m.list = backup_ptr;
- return -2;
- } else DEBUG("reallocation successful\n");
- } else {
- time_diff = time(NULL) - q3m.list[i].lastheartbeat;
- // if time_diff is 0 the server has shutdown (most likely)
- if (time_diff == 0) {
- INFO("server %s:%u is shutting down (time_diff %d)\n",
- inet_ntoa(q3m.list[i].ip), ntohs(q3m.list[i].port),
- time_diff);
- delete_server(&q3m, i);
- server_dup = 0;
- return 2; // return "server-shutdown" code
- } else {
- // server is in already in our list so we just update the timestamp
- q3m.list[i].lastheartbeat = time(NULL);
- server_dup = 0;
- }
- }
- // server added/updated
- return 1;
- }
- static int
- send_getstatus()
- {
- int challenge, i;
- // create challenge number
- challenge = rand();
- DEBUG("challenge: %d\n", challenge);
- // prepare q3m.msg_out
- q3m.num_msgs = 1;
- q3m.msg_out_length = calloc(1, sizeof(int));
- if (q3m.msg_out_length == NULL) {
- ERRORV("calloc() failed trying to get %d bytes!\n", sizeof(int));
- return -2; // TODO: define retval for errors
- }
- DEBUG("allocated %d bytes for msg_out_length[]\n", sizeof(int));
- // q3m.msg_out_length[0] = q3_pkt_header_len + q3_pkt_getstatus_len;
- q3m.msg_out_length[0] = q3_pkt_header_len
- + q3_pkt_getstatus_len + (int)(sizeof(int)*2.5);
- // allocate the memory for the outgoing packet
- q3m.msg_out = calloc(1, sizeof(char *));
- if (q3m.msg_out == NULL) {
- ERRORV("calloc() failed trying to get %d bytes!\n", sizeof(char *));
- return -2; // TODO: define retval for errors
- }
- q3m.msg_out[0] = calloc(q3m.msg_out_length[0]+1, 1);
- if (q3m.msg_out[0] == NULL) {
- ERRORV("calloc() failed trying to get %d bytes!\n",
- q3m.msg_out_length[0]);
- return -2; // TODO: define retval for errors
- }
- DEBUG("allocated %d bytes for msg_out[0]\n", q3m.msg_out_length[0]+1);
- memcpy(q3m.msg_out[0], q3_pkt_header, q3_pkt_header_len);
- memcpy(q3m.msg_out[0]+q3_pkt_header_len, q3_pkt_getstatus, q3_pkt_getstatus_len);
- sprintf(q3m.msg_out[0]+q3_pkt_header_len+q3_pkt_getstatus_len, "%d", challenge);
- // write challenge into serverlist
- for (i = 0; i < q3m.num_servers; i++) {
- if ((q3m.client.sin_addr.s_addr == q3m.list[i].ip.s_addr)
- && (q3m.client.sin_port == q3m.list[i].port)) {
- ((q3m_private_data_t *) q3m.list[i].private_data)->_challenge = challenge;
- break;
- }
- }
- return 1; // send "getstatus" packet
- }
- static int
- process_getservers(char *packet)
- {
- int i, j, pkt_offset; // temp vars
- int getsrv_protocol;
- char *temp;
- q3m_private_data_t *temp_priv_data;
- INFO("getservers from %s:%u\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port));
- // we need the protocol version from the packet so we parse it
- temp = packet+q3_pkt_header_len+q3_pkt_getsrv_len+1;
- getsrv_protocol = atoi(temp);
- DEBUG("requested protocol is %d\n", getsrv_protocol);
- // got the protocol version now we can assemble the outgoing packet(s)
- DEBUG("assembling server list packet\n");
- /*
- * packet assembler follows
- */
- // walk the server list
- for (i = j = 0; (j < q3m.num_servers) || (q3m.num_msgs == 0); i++) {
- q3m.num_msgs++;
- // allocate memory for the packets
- q3m.msg_out = realloc(q3m.msg_out, q3m.num_msgs*sizeof(char *));
- if (q3m.msg_out == NULL) {
- ERRORV("malloc() failed to get %d bytes!\n", q3m.num_msgs*sizeof(char *));
- return -2;
- }
- q3m.msg_out_length = realloc(q3m.msg_out_length, q3m.num_msgs*sizeof(int));
- if (q3m.msg_out_length == NULL) {
- ERRORV("malloc() failed to get %d bytes!\n", q3m.num_msgs*sizeof(int));
- return -2;
- }
- // get memory for header and command
- q3m.msg_out[i] = malloc(811);
- if (q3m.msg_out[i] == NULL) {
- ERROR("malloc() failed to get 811 bytes!\n");
- return -2;
- }
- // write header and command into packet
- memcpy(q3m.msg_out[i], q3_pkt_header, q3_pkt_header_len);
- pkt_offset = q3_pkt_header_len;
- memcpy(q3m.msg_out[i]+pkt_offset, q3_pkt_getsrvrsp, q3_pkt_getsrvrsp_len);
- pkt_offset += q3_pkt_getsrvrsp_len;
- for (; (j < q3m.num_servers) && (pkt_offset < 806); j++) {
- temp_priv_data = (q3m_private_data_t *) q3m.list[j].private_data;
- // if the protocol matches, write ip/port into the packet
- if (temp_priv_data->protocol == getsrv_protocol) {
- // copy data from server list into packet
- memcpy(q3m.msg_out[i]+pkt_offset, "\\", 1);
- pkt_offset++;
- memcpy(q3m.msg_out[i]+pkt_offset, &q3m.list[j].ip, 4);
- pkt_offset += 4;
- memcpy(q3m.msg_out[i]+pkt_offset, &q3m.list[j].port, 2);
- pkt_offset += 2;
- }
- } // for j < 112
- // write footer
- memcpy(q3m.msg_out[i]+pkt_offset, q3_pkt_footer, q3_pkt_footer_len);
- pkt_offset += q3_pkt_footer_len;
- q3m.msg_out[i][pkt_offset] = '\0';
- q3m.msg_out_length[i] = pkt_offset;
- DEBUG("q3m.msg_out_length[%d] = %d\n", i, pkt_offset);
- }
- // packet with server list is ready
- return 1;
- }
- static int
- process_statusResponse(char *packet, int packetlen)
- {
- char *varname = NULL, *value = NULL;
- char *score = NULL, *ping = NULL, *name = NULL;
- int i;
- int server_dup = 0, done = 0;
- char *packetend = packet+packetlen;
- q3m_private_data_t *private_data = calloc(1, sizeof(q3m_private_data_t));
- q3m_private_data_t *oldprivdata;
- // check if source address is known
- for (i = 0; i < q3m.num_servers; i++) {
- if ((q3m.client.sin_addr.s_addr == q3m.list[i].ip.s_addr)
- && (q3m.client.sin_port == q3m.list[i].port)) {
- server_dup = 1;
- break;
- }
- }
- // source address not known
- if (server_dup == 0) {
- WARNING("unexpected \"statusResponse\" from %s:%d ignored\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port));
- return -1;
- }
- oldprivdata = (q3m_private_data_t *)q3m.list[i].private_data;
- // go to 1st "\" which is after the command string
- packet = strpbrk(packet, "\\");
- if (packet == NULL) {
- WARNING("malformed statusResponse packet received from %s:%d!\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port));
- return -1;
- }
- DEBUG("begin parsing server info\n");
- while ((++packet < packetend) && !done)
- {
- // get variable name
- varname = packet;
- // go to next delimiter
- packet = strpbrk(packet, "\\");
- if (packet == NULL) {
- ERRORV("malformed statusResponse packet received from %s:%d!\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port));
- return -2;
- }
- // overwrite delimiter with \0
- *packet = '\0';
- // get value
- value = ++packet;
- // go to next delimiter
- packet = strpbrk(packet, "\\\n");
- if (packet == NULL) {
- ERRORV("malformed statusResponse packet received from %s:%d!\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port));
- return -2;
- }
- // check if we're at the end of the server info section
- if (*packet == '\n') done = 1;
- // overwrite delimiter with \0
- *packet = '\0';
- DEBUG("varname = \"%s\", value = \"%s\"\n", varname, value);
- // parse varname and assign the value to the struct
- if (strcmp(varname, "challenge") == 0) {
- private_data->challenge = atoi(value);
- } else if (strcmp(varname, "sv_punkbuster") == 0) {
- private_data->sv_punkbuster = atoi(value);
- } else if (strcmp(varname, "g_maxGameClients") == 0) {
- private_data->g_maxGameClients = atoi(value);
- } else if (strcmp(varname, "capturelimit") == 0) {
- private_data->capturelimit = atoi(value);
- } else if (strcmp(varname, "sv_maxclients") == 0) {
- private_data->sv_maxclients = atoi(value);
- } else if (strcmp(varname, "timelimit") == 0) {
- private_data->timelimit = atoi(value);
- } else if (strcmp(varname, "fraglimit") == 0) {
- private_data->fraglimit = atoi(value);
- } else if (strcmp(varname, "dmflags") == 0) {
- private_data->dmflags = atoi(value);
- } else if (strcmp(varname, "sv_maxPing") == 0) {
- private_data->sv_maxPing = atoi(value);
- } else if (strcmp(varname, "sv_minPing") == 0) {
- private_data->sv_minPing = atoi(value);
- } else if (strcmp(varname, "sv_hostname") == 0) {
- private_data->sv_hostname = strdup(value);
- if (private_data->sv_hostname == NULL) {
- ERRORV("strdup() failed to get %d bytes!\n", strlen(value)+1);
- return -2;
- }
- } else if (strcmp(varname, "sv_maxRate") == 0) {
- private_data->sv_maxRate = atoi(value);
- } else if (strcmp(varname, "sv_floodProtect") == 0) {
- private_data->sv_floodProtect = atoi(value);
- } else if (strcmp(varname, "version") == 0) {
- private_data->version = strdup(value);
- if (private_data->version == NULL) {
- ERRORV("strdup() failed to get %d bytes!\n", strlen(value)+1);
- return -2;
- }
- } else if (strcmp(varname, "g_gametype") == 0) {
- private_data->g_gametype = atoi(value);
- } else if (strcmp(varname, "protocol") == 0) {
- private_data->protocol = atoi(value);
- } else if (strcmp(varname, "mapname") == 0) {
- private_data->mapname = strdup(value);
- if (private_data->mapname == NULL) {
- ERRORV("strdup() failed to get %d bytes!\n", strlen(value)+1);
- return -2;
- }
- } else if (strcmp(varname, "sv_privateClients") == 0) {
- private_data->sv_privateClients = atoi(value);
- } else if (strcmp(varname, "sv_allowDownload") == 0) {
- private_data->sv_allowDownload = atoi(value);
- } else if (strcmp(varname, "bot_minplayers") == 0) {
- private_data->bot_minplayers = atoi(value);
- } else if (strcmp(varname, "gamename") == 0) {
- private_data->gamename = strdup(value);
- if (private_data->gamename == NULL) {
- ERRORV("calloc() failed to get %d bytes!\n", strlen(value)+1);
- return -2;
- }
- } else if (strcmp(varname, "g_needpass") == 0) {
- private_data->g_needpass = atoi(value);
- } //else {
- // WARNING("unknown option \"%s\" in statusResponse ignored\n", varname);
- //}
- }
- DEBUG("end parsing server info\n");
- // parse player info
- private_data->_players = 0;
- while (++packet < packetend) {
- // FIXME: recover from realloc() failure
- private_data->_player = (q3m_player_data_t *) realloc(private_data->_player,
- (private_data->_players+1)*sizeof(q3m_player_data_t));
- if (private_data->_player == NULL) {
- ERRORV("realloc() failed trying to get %d bytes!\n",
- private_data->_players*sizeof(q3m_player_data_t));
- return -2;
- }
- // get player score
- score = packet;
- // go to next delimiter
- if ((packet = strpbrk(packet, " ")) == NULL) {
- ERRORV("malformed statusResponse packet received from %s:%d!\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port));
- return -2;
- }
- // overwrite delimiter
- *packet = '\0';
- // parse player score
- private_data->_player[private_data->_players].score = atoi(score);
- // get player ping
- ping = ++packet;
- // go to next delimiter
- if ((packet = strpbrk(packet, " ")) == NULL) {
- ERRORV("malformed statusResponse packet received from %s:%d!\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port));
- return -2;
- }
- // overwrite delimiter
- *packet = '\0';
- // parse player ping
- private_data->_player[private_data->_players].ping = atoi(ping);
- // get player name
- name = ++packet;
- // go to next delimiter
- if ((packet = strpbrk(packet, "\n")) == NULL) {
- ERRORV("malformed statusResponse packet received from %s:%d!\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port));
- return -2;
- }
- // overwrite delimiter
- *packet = '\0';
- // parse player name
- private_data->_player[private_data->_players].name = strdup(name);
- if (private_data->_player[private_data->_players].name == NULL) {
- ERRORV("strdup() failed to get %d bytes!\n",
- strlen(name)+1);
- return -2;
- }
- DEBUG("player #%d name: \"%s\", ping: %d, score: %d\n",
- private_data->_players, private_data->_player[private_data->_players].name,
- private_data->_player[private_data->_players].ping,
- private_data->_player[private_data->_players].score);
- private_data->_players++;
- }
- // compare challenge to ours
- if (private_data->challenge != oldprivdata->_challenge) {
- WARNING("statusResponse challenge mismatch (%d != %d)\n",
- private_data->challenge, oldprivdata->_challenge);
- free_privdata(private_data);
- return -1;
- }
- // if we already have parsed server/player info we have to free it first
- if (q3m.list[i].private_data != NULL) free_privdata(q3m.list[i].private_data);
- q3m.list[i].private_data = private_data;
- return 0;
- }
- static int
- process_getmotd(char *packet, int packetlen)
- {
- char *version, *renderer, *challenge;
- char *varname = NULL, *value = NULL;
- char *packetend = packet+packetlen;
- packet += q3_pkt_header_len+q3_pkt_getmotd_len+2;
- while ((++packet < packetend) && (*packet != '\x0a')) {
- // save position as variable name
- varname = packet;
- // go to next delimiter
- packet = strpbrk(packet, "\\");
- if (packet == NULL) {
- WARNING("invalid \"getmotd\" from %s:%d received; ignored\n",
- inet_ntoa(q3m.client.sin_addr),
- ntohs(q3m.client.sin_port));
- return -1;
- }
- // overwrite delimiter with \0
- *packet = '\0';
- // save next position as value
- value = ++packet;
- // go to next delimiter
- packet = strpbrk(packet, "\\\"");
- if (packet == NULL) {
- WARNING("invalid \"getmotd\" from %s:%d received; ignored\n",
- inet_ntoa(q3m.client.sin_addr),
- ntohs(q3m.client.sin_port));
- return -1;
- }
- // overwrite delimiter with \0
- *packet = '\0';
- // parse
- if (strcmp(varname, "version") == 0) {
- version = strdup(value);
- if (version == NULL) {
- ERRORV("strdup() failed to get %d bytes!\n", strlen(value)+1);
- return -2;
- }
- } else if (strcmp(varname, "renderer") == 0) {
- renderer = strdup(value);
- if (renderer == NULL) {
- ERRORV("strdup() failed to get %d bytes!\n", strlen(value)+1);
- return -2;
- }
- } else if (strcmp(varname, "challenge") == 0) {
- challenge = strdup(value);
- if (challenge == NULL) {
- ERRORV("strdup() failed to get %d bytes!\n", strlen(value)+1);
- return -2;
- }
- } else {
- WARNING("unknown variable \"%s\" in \"getmotd\" packet ignored\n",
- varname);
- }
- }
- INFO("getmotd from %s:%d running \"%s\" with a \"%s\"\n",
- inet_ntoa(q3m.client.sin_addr), ntohs(q3m.client.sin_port),
- version, renderer);
- // we got all we need to assemble the motd packet
- q3m.msg_out = calloc(1, sizeof(char *));
- if (q3m.msg_out == NULL) {
- ERRORV("calloc() failed trying to get %d bytes!\n",
- sizeof(char *));
- return -2;
- }
- q3m.msg_out_length = calloc(1, sizeof(int));
- if (q3m.msg_out_length == NULL) {
- ERRORV("calloc() failed trying to get %d bytes!\n",
- sizeof(int));
- return -2;
- }
- q3m.msg_out_length[0] = q3_pkt_header_len+q3_pkt_motd_len
- + strlen(Q3M_MOTD)
- + (int)(sizeof(int)*2.5);
- q3m.msg_out[0] = calloc(q3m.msg_out_length[0]+1, 1);
- if (q3m.msg_out[0] == NULL) {
- ERRORV("calloc() failed trying to get %d bytes!\n",
- q3m.msg_out_length[0]);
- return -2;
- }
- q3m.num_msgs = 1;
- sprintf(q3m.msg_out[0], q3_pkt_motd, atoi(challenge), Q3M_MOTD);
- // clean up
- free(version);
- free(renderer);
- free(challenge);
- return 1;
- }
- static int
- process(char *packet, int packetlen)
- {
- int retval;
- // check if packet is q3a related
- if (strncmp(packet, q3_pkt_header, q3_pkt_header_len) == 0) {
- DEBUG("Q3A protocol marker detected!\n");
- // which packet did we receive?
- if (strcmp(packet+q3_pkt_header_len, q3_pkt_heartbeat) == 0) {
- retval = process_heartbeat(packet);
- if (retval == 1) {
- send_getstatus();
- return 1; // "send packet" code
- }
- return retval;
- } else if (strncmp(packet+q3_pkt_header_len, q3_pkt_getsrv, q3_pkt_getsrv_len) == 0) {
- return process_getservers(packet);
- } else if (strncmp(packet+q3_pkt_header_len, q3_pkt_statusrsp, q3_pkt_statusrsp_len) == 0) {
- return process_statusResponse(packet, packetlen);
- } else if (strncmp(packet+q3_pkt_header_len, q3_pkt_getmotd, q3_pkt_getmotd_len) == 0) {
- return process_getmotd(packet, packetlen);
- }
- WARNING("unknown packet received!\n");
- return -1;
- } // end if for 0xff 0xff 0xff 0xff marker
- WARNING("invalid packet received: Q3A protocol marker missing!\n");
- return -1; // invalid packet
- }
- static void
- cleanup(void)
- {
- int i;
- if (q3m.num_servers > 0) {
- for (i = 0; i < q3m.num_servers; i++) {
- free_privdata(q3m.list[i].private_data);
- }
- }
- }
- void
- init_plugin(void)
- {
- register_plugin(&q3m);
- }
|