/*************************************************************************** * 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 "event.h" #include "netpkt.h" #include "configfile.h" #include "plugin.h" #include "scanner.h" #include "logging.h" #include "gamelist.h" static LIST_HEAD(tx_queue); static int scan_sock; int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size) { struct net_pkt *pkt = malloc(sizeof(struct net_pkt) + size); if (pkt == NULL) { log_print(LOG_WARN, "pkt_send(): out of memory"); return -1; } pkt->addr.sin_family = AF_INET; pkt->addr.sin_port = htons(dstport); pkt->addr.sin_addr.s_addr = (dstip ? dstip->s_addr : 0xFFFFFFFF); memcpy(pkt->buf, buf, size); pkt->size = size; list_add_tail(&pkt->list, &tx_queue); return 0; } static int scanner_transmit(void *privdata) { if (list_empty(&tx_queue)) return -1; struct net_pkt *pkt; pkt = list_entry(tx_queue.next, struct net_pkt, list); list_del(&pkt->list); int ret = sendto(scan_sock, pkt->buf, pkt->size, 0, (struct sockaddr *)&pkt->addr, sizeof(pkt->addr)); if (ret <= 0) log_print(LOG_WARN, "scanner_transmit(): sendto()"); return 0; } static int scanner_scan(void *privdata) { plugins_scan(); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 10000; event_add_timeout(&tv, scanner_transmit, NULL); return 0; } static int scanner_receive(int fd, void *privdata) { int recvsize; if (ioctl(fd, FIONREAD, &recvsize) == -1) { log_print(LOG_WARN, "scanner_receive(): ioctl(FIONREAD)"); return 0; } struct net_pkt *pkt = malloc(sizeof(struct net_pkt) + recvsize); if (pkt == NULL) { log_print(LOG_WARN, "scanner_receive(): out of memory"); return 0; } unsigned int i = sizeof(struct sockaddr_in); pkt->size = recvfrom(fd, pkt->buf, recvsize, 0, (struct sockaddr *)&pkt->addr, &i); if (pkt->size < 0) { log_print(LOG_WARN, "scanner_receive(): recvfrom()"); free(pkt); return 0; } switch (plugins_parse(pkt)) { case PARSE_REJECT: { char *pkt_str = pkt_print(pkt); log_print(LOG_INFO, "scanner_receive(): unknown packet: %s:%d size:%d\n%s", inet_ntoa(pkt->addr.sin_addr), ntohs(pkt->addr.sin_port), pkt->size, pkt_str); free(pkt_str); } case PARSE_ACCEPT: free(pkt); case PARSE_ACCEPT_FREED: break; } return 0; } int scanner_init() { scan_sock = socket(PF_INET, SOCK_DGRAM, 0); if (scan_sock < 0) { log_print(LOG_ERROR, "scan_init(): socket()"); return -1; } struct sockaddr_in src; char *addr = config_get_string("global", "scanner_src", "0.0.0.0:7130"); if (parse_saddr(addr, &src) != 0) { log_print(LOG_ERROR, "server_init(): invalid scanner_src '%s'", addr); return -1; } if (bind(scan_sock, (struct sockaddr *)&src, sizeof(src)) < 0) { log_print(LOG_ERROR, "scan_init(): bind()"); return -1; } int j = 1; if (setsockopt(scan_sock, SOL_SOCKET, SO_BROADCAST, &j, sizeof(j))) { log_print(LOG_ERROR, "scan_init(): setsockopt(SO_BROADCAST)"); return -1; } int rxsize = 1<<20; if (setsockopt(scan_sock, SOL_SOCKET, SO_RCVBUF, &rxsize, sizeof(rxsize))) { log_print(LOG_ERROR, "scan_init(): setsockopt(SO_RCVBUF)"); return -1; } event_add_readfd(scan_sock, scanner_receive, NULL); log_print(LOG_INFO, "scan socket initialized (%s:%d)", inet_ntoa(src.sin_addr), ntohs(src.sin_port)); struct timeval tv; tv.tv_sec = config_get_int("global", "scan_interval", 60); tv.tv_usec = 0; event_add_timeout(&tv, scanner_scan, NULL); scanner_scan(NULL); return 0; }