/*************************************************************************** * Copyright (C) 03/2005 by Olaf Rempel * * razzor@kopf-tisch.de * * * * This program 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. * * * * 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., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include "hlswmaster.h" #include "plugin.h" #include "list.h" #define HLSW_HEADER "\xFF\xFF\xFF\xFFHLSWLANSEARCH\x00" #define HLSW_HEADER_LEN 0x12 #define MAX_PKT_LEN (HLSW_HEADER_LEN + 1400) struct client_pkt { struct list_head list; unsigned int size; unsigned char buf[0]; }; /* real und prepare list. enthalten die client-antworten */ LIST_HEAD(client_pkt_list); LIST_HEAD(client_pkt_prepare); /* sichert die real list ab */ static pthread_mutex_t pkt_list_lock = PTHREAD_MUTEX_INITIALIZER; /** * pkt_not_full() * LIST_FIND helper * * @param struct client_pkt *a * @param void *b * @return true wenn das paket noch nicht voll ist */ static inline int pkt_not_full(const struct client_pkt *a, void *b) { return (a->size < MAX_PKT_LEN); } /** * client_pkt_add_real() * erzeugt eine neues client_pkt und fuegt es einer liste hinzu * gibt einen pointer auf das neue client_pkt zurueck * * @param struct list_head *list * @return struct client_pkt * or NULL on error */ static struct client_pkt * client_pkt_add_real(struct list_head *list) { struct client_pkt *new; if (!(new = malloc(sizeof(struct client_pkt) + MAX_PKT_LEN))) return NULL; INIT_LIST_HEAD(&new->list); new->size = HLSW_HEADER_LEN; memcpy(new->buf, HLSW_HEADER, HLSW_HEADER_LEN); list_add_tail(&new->list, list); return new; } /** * client_pkt_add() * fuegt dem freien client_pkt der prepare-liste ein Spiel hinzu * wenn kein platz vorhanden ist, wird ein neues paket erzeugt * * @param struct game_server *server * @return false bei fehler (malloc) * * TODO: memcpy() durch pointer ops ersetzen? */ int client_pkt_add(struct game_server *server) { struct client_pkt *pkt; char *src, *dst; pkt = LIST_FIND(&client_pkt_prepare, pkt_not_full, struct client_pkt *, NULL); if (!pkt && !(pkt = client_pkt_add_real(&client_pkt_prepare))) return 0; dst = (char *)&pkt->buf + pkt->size; src = (char *)&server->gameid; memcpy(dst, src, 2); src = (char *)&server->ip; memcpy(dst +2, src, 4); src = (char *)&server->port1; memcpy(dst +6, src, 4); src = (char *)&server->port2; memcpy(dst +8, src, 4); pkt->size += 10; return 1; } /** * client_pkt_commit() * * die prepare liste die echte liste und alle pakete der * alten liste werden entfernt * * @return true */ int client_pkt_commit() { struct list_head old_list, *pkt, *tmp; pthread_mutex_lock(&pkt_list_lock); /* old_list wird head der real list */ list_add(&old_list, &client_pkt_list); list_del(&client_pkt_list); /* client_pkt_list wird head der prepare list */ list_add(&client_pkt_list, &client_pkt_prepare); list_del_init(&client_pkt_prepare); pthread_mutex_unlock(&pkt_list_lock); /* alle alten pakete entfernen */ list_for_each_safe(pkt, tmp, &old_list) { list_del(pkt); free(pkt); } return 1; } /** * client_handler() * empfaengt und beantwortet die HLSW Anfragen * * TODO: src-ip configurierbar machen (config file?) */ void client_handler(void) { struct client_pkt *pkt; struct sockaddr_in dst; int sock, i; unsigned char buf[32]; if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { log_print("client_handler(): socket()"); return; } dst.sin_family = AF_INET; dst.sin_port = htons(7140); inet_aton("0.0.0.0", &dst.sin_addr); if (bind(sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) { log_print("client_handler(): bind()"); return; } while (1) { /* auf clientanfrage warten */ i = sizeof(struct sockaddr_in); recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&dst, &i); /* testen ob es sich um ein HLSW anforderung handelt */ if (memcmp(buf, HLSW_HEADER, HLSW_HEADER_LEN)) continue; pthread_mutex_lock(&pkt_list_lock); /* pakete aus der real list senden */ list_for_each_entry(pkt, &client_pkt_list, list) sendto(sock, pkt->buf, pkt->size, 0, (struct sockaddr *)&dst, sizeof(dst)); pthread_mutex_unlock(&pkt_list_lock); } }