Compare commits
15 Commits
Author | SHA1 | Date |
---|---|---|
Olaf Rempel | 521a911110 | |
Olaf Rempel | be2726a22f | |
Olaf Rempel | aee280ca5c | |
Olaf Rempel | ce59a8853e | |
Olaf Rempel | 2363f1de47 | |
Olaf Rempel | bfd2d35260 | |
Olaf Rempel | 464d0b352d | |
Olaf Rempel | 5c2fc7d1a6 | |
Olaf Rempel | 9b62806411 | |
Olaf Rempel | ddc42a0968 | |
Olaf Rempel | 90d33bffbf | |
Olaf Rempel | 861d41be08 | |
Olaf Rempel | 7f0b2fd78f | |
Olaf Rempel | 0d0650008f | |
Olaf Rempel | 5d10585d29 |
|
@ -0,0 +1,6 @@
|
|||
*.d
|
||||
*.o
|
||||
*.so
|
||||
masterquery
|
||||
hlswmaster
|
||||
hlswmaster.log
|
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
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
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,50 @@
|
|||
* Thu 22 Dec 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.64
|
||||
(after Northern LAN Convention Winter 2005, www.northcon.de)
|
||||
- added Quake4 support (d3engine)
|
||||
- added CoD2 support (q3engine)
|
||||
- added Rune support (gamespy1)
|
||||
|
||||
* Thu 08 Sep 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.63
|
||||
(after The Summit 5, www.the-summit.de)
|
||||
- added ut2k4 plugin (native scan)
|
||||
- added Battlefield2 support (gs2 query/host ports)
|
||||
- added Swat4 Support (gs2)
|
||||
- fix quake2 plugin
|
||||
|
||||
* Thu 25 Aug 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.62
|
||||
(after Multimadness Summer 2005, www.multimadness.de)
|
||||
- use c99 inttypes
|
||||
- added new Halflife scan (halflife)
|
||||
- added Battlefield2 support (gamespy2)
|
||||
|
||||
* Sun 05 Jun 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.61
|
||||
- reduce per thread stack from 8MB to 64kB (strange pthread_create() defaults..)
|
||||
|
||||
* Sun 15 May 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.60
|
||||
- added receive-queue
|
||||
- changed plugin_helper api from void* to uint offsets
|
||||
- gamespy1 multi-packet response support
|
||||
- q3engine plugin rewrite
|
||||
- added halflife plugin
|
||||
|
||||
* Tue 19 Apr 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.53
|
||||
- code cleanup
|
||||
- added doxygen file
|
||||
|
||||
* Thu 31 Mar 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.52
|
||||
- games added: avp2, bfv, igi2, jk2, jk3, rtcw, ut2k3, ut2k4
|
||||
- sendqueue removed (no need to do ratelimiting)
|
||||
- serverlist.c + scanner.c merged, removing one thread
|
||||
- daemonize & run-as-user support
|
||||
|
||||
* Sun 27 Mar 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.51
|
||||
- added configfile parser, added configfile support to subsystems
|
||||
- plugins: replaced con/destructor with dlsym() peeking
|
||||
|
||||
* Sat 26 Mar 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.50
|
||||
- supported games: bf1942, cod, cod:uo, d3, ef, et, halo, q2, q3, ut
|
||||
- added autoconf/automake/libtool support
|
||||
- plugins: replaced _init() / _fini() with ((constructor)) / ((destructor))
|
||||
|
||||
* Mon 14 Mar 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.10
|
||||
- initial version
|
35
Makefile
35
Makefile
|
@ -1,28 +1,29 @@
|
|||
# Toplevel Makefile
|
||||
VERSION := v2.00
|
||||
|
||||
MASTER_SRC := client.c daemon.c logging.c main.c plugin.c plugin_helper.c scanner.c serverlist.c
|
||||
PLUGIN_SRC := hlswproxy.c q3engine.c quake2.c gamespy1.c gamespy2.c ut.c doom3.c
|
||||
CFLAGS := -O2 -pipe -Wall -Iinclude -DVERSION='"$(VERSION)"'
|
||||
LDFLAGS := -ldl -rdynamic
|
||||
|
||||
CFLAGS := -Wall -I. -I./include -g
|
||||
# ############################
|
||||
OBJS := configfile.o event.o gamelist.o logging.o netpkt.o plugin.o \
|
||||
plugin_helper.o scanner.o server.o
|
||||
|
||||
all: $(PLUGIN_SRC:%.c=plugins/%.so) src/hlswmaster tools/masterquery
|
||||
all: hlswmaster masterquery
|
||||
make -C plugins all
|
||||
|
||||
src/hlswmaster: $(MASTER_SRC:%.c=src/%.o)
|
||||
$(CC) -ldl -lpthread -rdynamic $^ -o $@
|
||||
hlswmaster: $(OBJS) hlswmaster.o
|
||||
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
tools/masterquery: tools/masterquery.c
|
||||
$(CC) $(CFLAGS) $< -o $@
|
||||
masterquery: masterquery.o
|
||||
$(CC) $(CFLAGS) $^ -o $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%_sh.o: %.c
|
||||
$(CC) $(CFLAGS) -fPIC -o $@ -c $<
|
||||
|
||||
%.so: %_sh.o
|
||||
$(LD) -shared -o $@ $<
|
||||
%.d: %.c
|
||||
$(CC) $(CFLAGS) -MM -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf src/*.o plugins/*.so plugins/*.o src/hlswmaster tools/masterquery
|
||||
rm -f hlswmaster masterquery *.d *.o *.log
|
||||
make -C plugins clean
|
||||
|
||||
DEPS := $(wildcard *.c)
|
||||
-include $(DEPS:.c=.d)
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 06/2006 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "configfile.h"
|
||||
#include "list.h"
|
||||
#include "logging.h"
|
||||
|
||||
#define BUFSIZE 1024
|
||||
|
||||
struct conf_section {
|
||||
struct list_head list;
|
||||
struct list_head tupel_list;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct conf_tupel {
|
||||
struct list_head list;
|
||||
char *option;
|
||||
char *parameter;
|
||||
};
|
||||
|
||||
static LIST_HEAD(config_list);
|
||||
|
||||
static struct conf_section * config_add_section(const char *name)
|
||||
{
|
||||
struct conf_section *section;
|
||||
section = malloc(sizeof(struct conf_section) + strlen(name));
|
||||
if (section == NULL)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(§ion->list);
|
||||
INIT_LIST_HEAD(§ion->tupel_list);
|
||||
|
||||
section->name = strdup(name);
|
||||
if (section->name == NULL) {
|
||||
free(section);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_add_tail(§ion->list, &config_list);
|
||||
return section;
|
||||
}
|
||||
|
||||
static int config_add_tupel(struct conf_section *section, const char *option, const char *parameter)
|
||||
{
|
||||
struct conf_tupel *tupel = malloc(sizeof(struct conf_tupel));
|
||||
if (tupel == NULL)
|
||||
return -1;
|
||||
|
||||
INIT_LIST_HEAD(&tupel->list);
|
||||
tupel->option = strdup(option);
|
||||
tupel->parameter = strdup(parameter);
|
||||
|
||||
if (tupel->option == NULL || tupel->parameter == NULL) {
|
||||
free(tupel);
|
||||
return -1;
|
||||
}
|
||||
|
||||
list_add_tail(&tupel->list, §ion->tupel_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse(const char *config)
|
||||
{
|
||||
FILE *fz = fopen(config, "r");
|
||||
if (fz == NULL) {
|
||||
log_print(LOG_ERROR, "config_parse(): %s", config);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *line = malloc(BUFSIZE);
|
||||
if (line == NULL) {
|
||||
log_print(LOG_ERROR, "config_parse(): out of memory");
|
||||
fclose(fz);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int linenum = 0;
|
||||
struct conf_section *section = NULL;
|
||||
while (fgets(line, BUFSIZE, fz) != NULL) {
|
||||
linenum++;
|
||||
|
||||
if (line[0] == '#' || line[0] <= ' ') {
|
||||
continue;
|
||||
|
||||
} else if (line[0] == '[') {
|
||||
char *tok = strtok(line +1, " ]\n");
|
||||
|
||||
if (tok == NULL || (section = config_add_section(tok)) == NULL) {
|
||||
log_print(LOG_WARN, "config_parse(): invalid section in row %d", linenum);
|
||||
free(line);
|
||||
fclose(fz);
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
|
||||
} else if (section == NULL) {
|
||||
log_print(LOG_WARN, "config_parse(): missing section in row %d", linenum);
|
||||
free(line);
|
||||
fclose(fz);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *tok = strtok(line, " \n");
|
||||
if (tok != NULL) {
|
||||
char *tok2;
|
||||
while ((tok2 = strtok(NULL, " \n"))) {
|
||||
if (config_add_tupel(section, tok, tok2) != 0)
|
||||
log_print(LOG_WARN, "config_parse(): invalid row %d", linenum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fz);
|
||||
free(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct conf_section * config_get_section(const char *name)
|
||||
{
|
||||
struct conf_section *section;
|
||||
|
||||
list_for_each_entry(section, &config_list, list) {
|
||||
if (!strcmp(section->name, name))
|
||||
return section;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char * config_get_string(const char *section_str, const char *option, char *def)
|
||||
{
|
||||
struct conf_section *section = config_get_section(section_str);
|
||||
if (section != NULL) {
|
||||
struct conf_tupel *tupel;
|
||||
list_for_each_entry(tupel, §ion->tupel_list, list) {
|
||||
if (!strcmp(tupel->option, option))
|
||||
return tupel->parameter;
|
||||
}
|
||||
}
|
||||
|
||||
if (def != NULL)
|
||||
log_print(LOG_WARN, "config [%s:%s] not found, using default: '%s'",
|
||||
section_str, option, def);
|
||||
return def;
|
||||
}
|
||||
|
||||
int config_get_int(const char *section, const char *option, int def)
|
||||
{
|
||||
char *ret = config_get_string(section, option, NULL);
|
||||
if (ret == NULL) {
|
||||
log_print(LOG_WARN, "config [%s:%s] not found, using default: '%d'",
|
||||
section, option, def);
|
||||
return def;
|
||||
}
|
||||
return atoi(ret);
|
||||
}
|
||||
|
||||
int config_get_strings(const char *section_str, const char *option,
|
||||
int (*callback)(const char *value, void *privdata),
|
||||
void *privdata)
|
||||
{
|
||||
struct conf_section *section = config_get_section(section_str);
|
||||
if (section == NULL)
|
||||
return -1;
|
||||
|
||||
int cnt = 0;
|
||||
struct conf_tupel *tupel;
|
||||
list_for_each_entry(tupel, §ion->tupel_list, list) {
|
||||
if (!strcmp(tupel->option, option))
|
||||
if (callback(tupel->parameter, privdata) == 0)
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
// TODO: wrong place!
|
||||
int parse_saddr(const char *addr, struct sockaddr_in *sa)
|
||||
{
|
||||
char *addr_cpy = strdup(addr);
|
||||
if (addr_cpy == NULL) {
|
||||
log_print(LOG_WARN, "parse_saddr(): out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *tmp;
|
||||
char *ip = strtok_r(addr_cpy, ":", &tmp);
|
||||
if (ip == NULL) {
|
||||
free(addr_cpy);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *port = strtok_r(NULL, ":", &tmp);
|
||||
if (port == NULL) {
|
||||
free(addr_cpy);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sa->sin_family = AF_INET;
|
||||
sa->sin_port = htons(atoi(port));
|
||||
int ret = inet_aton(ip, &sa->sin_addr);
|
||||
|
||||
free(addr_cpy);
|
||||
return (ret != 0) ? 0 : -1;
|
||||
}
|
|
@ -0,0 +1,310 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 10/2006 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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "logging.h"
|
||||
|
||||
#include "event.h"
|
||||
|
||||
static LIST_HEAD(readfd_list);
|
||||
static LIST_HEAD(writefd_list);
|
||||
static LIST_HEAD(exceptfd_list);
|
||||
static LIST_HEAD(timeout_list);
|
||||
|
||||
struct fd_entry {
|
||||
struct list_head list;
|
||||
int fd;
|
||||
int type;
|
||||
int (*callback)(int fd, void *privdata);
|
||||
void *privdata;
|
||||
};
|
||||
|
||||
struct timeout_entry {
|
||||
struct list_head list;
|
||||
struct timeval timeout;
|
||||
struct timeval nextrun;
|
||||
int (*callback)(void *privdata);
|
||||
void *privdata;
|
||||
};
|
||||
|
||||
int event_add_fd(int fd, int type, int (*callback)(int fd, void *privdata), void *privdata)
|
||||
{
|
||||
if (fd < 0 || fd > FD_SETSIZE)
|
||||
return -1;
|
||||
|
||||
struct fd_entry *entry;
|
||||
entry = malloc(sizeof(struct fd_entry));
|
||||
if (entry == NULL) {
|
||||
log_print(LOG_ERROR, "event_add_fd(): out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
entry->fd = fd;
|
||||
entry->type = type;
|
||||
entry->callback = callback;
|
||||
entry->privdata = privdata;
|
||||
|
||||
switch (type) {
|
||||
case FD_READ:
|
||||
list_add_tail(&entry->list, &readfd_list);
|
||||
break;
|
||||
|
||||
case FD_WRITE:
|
||||
list_add_tail(&entry->list, &writefd_list);
|
||||
break;
|
||||
|
||||
case FD_EXCEPT:
|
||||
list_add_tail(&entry->list, &exceptfd_list);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_print(LOG_ERROR, "add_fd(): unknown type");
|
||||
free(entry);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_remove_fd(int fd)
|
||||
{
|
||||
struct fd_entry *entry, *tmp;
|
||||
list_for_each_entry_safe(entry, tmp, &readfd_list, list) {
|
||||
if (entry->fd == fd) {
|
||||
list_del(&entry->list);
|
||||
free(entry);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(entry, tmp, &writefd_list, list) {
|
||||
if (entry->fd == fd) {
|
||||
list_del(&entry->list);
|
||||
free(entry);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(entry, tmp, &exceptfd_list, list) {
|
||||
if (entry->fd == fd) {
|
||||
list_del(&entry->list);
|
||||
free(entry);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void calc_nextrun(struct timeval *timeout, struct timeval *nextrun)
|
||||
{
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
nextrun->tv_usec = now.tv_usec + timeout->tv_usec;
|
||||
nextrun->tv_sec = now.tv_sec + timeout->tv_sec;
|
||||
|
||||
if (nextrun->tv_usec >= 1000000) {
|
||||
nextrun->tv_usec -= 1000000;
|
||||
nextrun->tv_sec++;
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_timeout(struct timeval *timeout, struct timeval *nextrun)
|
||||
{
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
timeout->tv_usec = nextrun->tv_usec - now.tv_usec;
|
||||
timeout->tv_sec = nextrun->tv_sec - now.tv_sec;
|
||||
|
||||
if (timeout->tv_usec < 0) {
|
||||
timeout->tv_usec += 1000000;
|
||||
timeout->tv_sec--;
|
||||
}
|
||||
}
|
||||
|
||||
static void schedule_nextrun(struct timeout_entry *entry)
|
||||
{
|
||||
struct timeout_entry *search;
|
||||
|
||||
list_for_each_entry(search, &timeout_list, list) {
|
||||
if (search->nextrun.tv_sec > entry->nextrun.tv_sec) {
|
||||
list_add_tail(&entry->list, &search->list);
|
||||
return;
|
||||
|
||||
} else if (search->nextrun.tv_sec == entry->nextrun.tv_sec &&
|
||||
search->nextrun.tv_usec > entry->nextrun.tv_usec) {
|
||||
list_add_tail(&entry->list, &search->list);
|
||||
return;
|
||||
}
|
||||
}
|
||||
list_add_tail(&entry->list, &timeout_list);
|
||||
}
|
||||
|
||||
int event_add_timeout(struct timeval *timeout, int (*callback)(void *privdata), void *privdata)
|
||||
{
|
||||
struct timeout_entry *entry;
|
||||
entry = malloc(sizeof(struct timeout_entry));
|
||||
if (entry == NULL) {
|
||||
log_print(LOG_ERROR, "event_add_timeout(): out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&entry->timeout, timeout, sizeof(entry->timeout));
|
||||
entry->callback = callback;
|
||||
entry->privdata = privdata;
|
||||
|
||||
calc_nextrun(&entry->timeout, &entry->nextrun);
|
||||
schedule_nextrun(entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void event_loop(void)
|
||||
{
|
||||
while (1) {
|
||||
fd_set readfds, *readfds_p = NULL;
|
||||
fd_set writefds, *writefds_p = NULL;
|
||||
fd_set exceptfds, *exceptfds_p =NULL;
|
||||
struct timeval timeout, *timeout_p = NULL;
|
||||
|
||||
if (!list_empty(&readfd_list)) {
|
||||
struct fd_entry *entry;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
list_for_each_entry(entry, &readfd_list, list)
|
||||
FD_SET(entry->fd, &readfds);
|
||||
|
||||
readfds_p = &readfds;
|
||||
}
|
||||
|
||||
if (!list_empty(&writefd_list)) {
|
||||
struct fd_entry *entry;
|
||||
|
||||
FD_ZERO(&writefds);
|
||||
list_for_each_entry(entry, &writefd_list, list)
|
||||
FD_SET(entry->fd, &writefds);
|
||||
|
||||
writefds_p = &writefds;
|
||||
}
|
||||
|
||||
if (!list_empty(&exceptfd_list)) {
|
||||
struct fd_entry *entry;
|
||||
|
||||
FD_ZERO(&exceptfds);
|
||||
list_for_each_entry(entry, &exceptfd_list, list)
|
||||
FD_SET(entry->fd, &exceptfds);
|
||||
|
||||
exceptfds_p = &exceptfds;
|
||||
}
|
||||
|
||||
if (!list_empty(&timeout_list)) {
|
||||
struct timeout_entry *entry, *tmp;
|
||||
list_for_each_entry_safe(entry, tmp, &timeout_list, list) {
|
||||
|
||||
calc_timeout(&timeout, &entry->nextrun);
|
||||
if (timeout.tv_sec >= 0 && timeout.tv_usec > 0) {
|
||||
timeout_p = &timeout;
|
||||
break;
|
||||
}
|
||||
|
||||
// delayed timeout, exec NOW!
|
||||
list_del(&entry->list);
|
||||
int ret = entry->callback(entry->privdata);
|
||||
if (ret == 0) {
|
||||
calc_nextrun(&entry->timeout, &entry->nextrun);
|
||||
schedule_nextrun(entry);
|
||||
|
||||
} else {
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int i = select(FD_SETSIZE, readfds_p, writefds_p, exceptfds_p, timeout_p);
|
||||
if (i < 0) {
|
||||
/* On error, -1 is returned, and errno is set
|
||||
* appropriately; the sets and timeout become
|
||||
* undefined, so do not rely on their contents
|
||||
* after an error.
|
||||
*/
|
||||
continue;
|
||||
|
||||
} else if (i == 0 && !list_empty(&timeout_list)) {
|
||||
struct timeout_entry *entry;
|
||||
entry = list_entry(timeout_list.next, typeof(*entry), list);
|
||||
list_del(&entry->list);
|
||||
|
||||
int ret = entry->callback(entry->privdata);
|
||||
if (ret == 0) {
|
||||
calc_nextrun(&entry->timeout, &entry->nextrun);
|
||||
schedule_nextrun(entry);
|
||||
|
||||
} else {
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (readfds_p) {
|
||||
struct fd_entry *entry, *tmp;
|
||||
list_for_each_entry_safe(entry, tmp, &readfd_list, list) {
|
||||
if (!FD_ISSET(entry->fd, &readfds))
|
||||
continue;
|
||||
|
||||
if (entry->callback(entry->fd, entry->privdata) != 0) {
|
||||
list_del(&entry->list);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (writefds_p) {
|
||||
struct fd_entry *entry, *tmp;
|
||||
list_for_each_entry_safe(entry, tmp, &writefd_list, list) {
|
||||
if (FD_ISSET(entry->fd, &writefds))
|
||||
continue;
|
||||
|
||||
if (entry->callback(entry->fd, entry->privdata) != 0) {
|
||||
list_del(&entry->list);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exceptfds_p) {
|
||||
struct fd_entry *entry, *tmp;
|
||||
list_for_each_entry_safe(entry, tmp, &exceptfd_list, list) {
|
||||
if (FD_ISSET(entry->fd, &exceptfds))
|
||||
continue;
|
||||
|
||||
if (entry->callback(entry->fd, entry->privdata) != 0) {
|
||||
list_del(&entry->list);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "gamelist.h"
|
||||
#include "logging.h"
|
||||
|
||||
#define BUCKET_NUM 127
|
||||
|
||||
static struct list_head *bucket;
|
||||
|
||||
static unsigned int hash_entry(struct game_entry *entry)
|
||||
{
|
||||
unsigned int hash = 0x12345678;
|
||||
|
||||
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->ip >> 0) & 0xFF);
|
||||
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->ip >> 8) & 0xFF);
|
||||
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->ip >> 16) & 0xFF);
|
||||
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->ip >> 24) & 0xFF);
|
||||
|
||||
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->port1 >> 0) & 0xFF);
|
||||
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->port1 >> 8) & 0xFF);
|
||||
|
||||
return hash % BUCKET_NUM;
|
||||
}
|
||||
|
||||
static int compare_entry(struct game_entry *a, struct game_entry *b)
|
||||
{
|
||||
return (a->gameid == b->gameid && a->ip == b->ip &&
|
||||
a->port1 == b->port1 && a->port2 == b->port2);
|
||||
}
|
||||
|
||||
int gamelist_add(struct game_entry *entry)
|
||||
{
|
||||
unsigned int hash = hash_entry(entry);
|
||||
|
||||
struct game_entry *search;
|
||||
list_for_each_entry(search, &bucket[hash], list) {
|
||||
if (compare_entry(search, entry)) {
|
||||
search->modtime = time(NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
entry->modtime = time(NULL);
|
||||
list_add_tail(&entry->list, &bucket[hash]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gamelist_gc_and_dump(int (*callback)(struct game_entry *entry), int timeout)
|
||||
{
|
||||
long now = time(NULL);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUCKET_NUM; i++) {
|
||||
struct game_entry *entry, *tmp;
|
||||
list_for_each_entry_safe(entry, tmp, &bucket[i], list) {
|
||||
if (entry->modtime + timeout >= now) {
|
||||
callback(entry);
|
||||
|
||||
} else {
|
||||
list_del(&entry->list);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gamelist_init()
|
||||
{
|
||||
bucket = malloc(sizeof(struct list_head) * BUCKET_NUM);
|
||||
if (bucket == NULL) {
|
||||
log_print(LOG_ERROR, "scan_init(): out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < BUCKET_NUM; i++)
|
||||
INIT_LIST_HEAD(&bucket[i]);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -21,39 +21,49 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <getopt.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "hlswmaster.h"
|
||||
#include "configfile.h"
|
||||
#include "event.h"
|
||||
#include "logging.h"
|
||||
|
||||
#include "gamelist.h"
|
||||
#include "scanner.h"
|
||||
#include "server.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#define DEFAULT_CONFIG "hlswmaster.conf"
|
||||
#define DEFAULT_LOGFILE "hlswmaster.log"
|
||||
|
||||
static struct option opts[] = {
|
||||
{"config", 1, 0, 'c'},
|
||||
{"user", 1, 0, 'u'},
|
||||
{"debug", 1, 0, 'd'},
|
||||
{"no-daemon", 0, 0, 'f'},
|
||||
{"debug", 0, 0, 'd'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int arg = 0, code = 0;
|
||||
pthread_t thread1, thread2, thread3, thread4;
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int arg = 0, code = 0, debug = 0;
|
||||
char *config = DEFAULT_CONFIG, *user = NULL, *logfile;
|
||||
|
||||
while (code != -1) {
|
||||
code = getopt_long(argc, argv, "c:u:d:fh", opts, &arg);
|
||||
code = getopt_long(argc, argv, "c:u:dh", opts, &arg);
|
||||
|
||||
switch (code) {
|
||||
case 'c': /* config */
|
||||
config = optarg;
|
||||
break;
|
||||
|
||||
case 'u': /* user */
|
||||
user = optarg;
|
||||
break;
|
||||
|
||||
case 'd': /* debug */
|
||||
break;
|
||||
|
||||
case 'f': /* no-daemon */
|
||||
debug = 1;
|
||||
break;
|
||||
|
||||
case 'h': /* help */
|
||||
|
@ -61,8 +71,7 @@ int main(int argc, char *argv[]) {
|
|||
"Options: \n"
|
||||
" --config -c configfile use this configfile\n"
|
||||
" --user -u username change uid to username\n"
|
||||
" --debug -d debuglevel level: 0 - 7\n"
|
||||
" --no-daemon -f do not fork\n"
|
||||
" --debug -d do not fork and log to stderr\n"
|
||||
" --help -h this help\n"
|
||||
"\n");
|
||||
exit(0);
|
||||
|
@ -77,26 +86,54 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
/* userwechsel */
|
||||
if (user) {
|
||||
struct passwd *pwl;
|
||||
if (!(pwl = getpwnam(user))) {
|
||||
log_print(LOG_ERROR, "unknown user: %s", user);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
plugin_load("plugins/hlswproxy.so");
|
||||
plugin_load("plugins/q3engine.so");
|
||||
plugin_load("plugins/quake2.so");
|
||||
plugin_load("plugins/gamespy1.so");
|
||||
plugin_load("plugins/gamespy2.so");
|
||||
plugin_load("plugins/doom3.so");
|
||||
plugin_load("plugins/ut.so");
|
||||
if (setgid(pwl->pw_gid) || setuid(pwl->pw_uid)) {
|
||||
log_print(LOG_ERROR, "setgid/setuid");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
scan_init();
|
||||
/* parse config file */
|
||||
if (config_parse(config) == -1)
|
||||
exit(-1);
|
||||
|
||||
// scan_transmit();
|
||||
pthread_create(&thread1, NULL, (void *)&scan_transmit, NULL);
|
||||
pthread_create(&thread2, NULL, (void *)&scan_receive, NULL);
|
||||
pthread_create(&thread3, NULL, (void *)&server_collector, NULL);
|
||||
pthread_create(&thread4, NULL, (void *)&client_handler, NULL);
|
||||
/* check logfile */
|
||||
logfile = config_get_string("global", "logfile", DEFAULT_LOGFILE);
|
||||
if (logfile && !debug) {
|
||||
/* start logging */
|
||||
if (!log_init(logfile))
|
||||
exit(-1);
|
||||
|
||||
sleep(9999);
|
||||
/* zum daemon mutieren */
|
||||
daemon(-1, 0);
|
||||
}
|
||||
|
||||
scan_exit();
|
||||
log_print(LOG_INFO, "hlswmaster started (user: %s, pid: %d)", getpwuid(getuid())->pw_name, getpid());
|
||||
|
||||
/* init plugins */
|
||||
if (plugin_init() == -1)
|
||||
exit(-1);
|
||||
|
||||
/* init gamelist */
|
||||
if (gamelist_init() == -1)
|
||||
exit(-1);
|
||||
|
||||
/* init server */
|
||||
if (server_init() == -1)
|
||||
exit(-1);
|
||||
|
||||
/* init scanner */
|
||||
if (scanner_init() == -1)
|
||||
exit(-1);
|
||||
|
||||
event_loop();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
[global]
|
||||
## broadcast scan source IP & PORT (udp)
|
||||
scanner_src 0.0.0.0:7130
|
||||
|
||||
## broadcast scan every X seconds
|
||||
scan_interval 60
|
||||
|
||||
## serverlist rebuild every X seconds
|
||||
serverlist_refresh 5
|
||||
|
||||
## server timeout after X seconds
|
||||
serverlist_timeout 180
|
||||
|
||||
## master answers with this source IP
|
||||
master_src 0.0.0.0:7140
|
||||
|
||||
plugin_dir plugins
|
||||
plugin d3engine.so
|
||||
plugin gamespy1.so
|
||||
plugin gamespy2.so
|
||||
plugin halflife.so
|
||||
plugin hlswproxy.so
|
||||
plugin q3engine.so
|
||||
plugin quake2.so
|
||||
plugin ut2k4.so
|
||||
|
||||
## logging
|
||||
logfile hlswmaster.log
|
||||
|
||||
[gamespy1]
|
||||
## internal fragment-list timeout
|
||||
gc_timeout 90
|
||||
|
||||
[hlswproxy]
|
||||
## ask these hlswmasters
|
||||
#scan 10.10.0.1:7140
|
||||
#scan 10.10.0.2:7140
|
||||
|
||||
[halflife]
|
||||
## allow these nets
|
||||
valid_net 10.10.0.0/16
|
||||
valid_net 172.16.0.0/16
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
int config_parse(const char *config);
|
||||
|
||||
char * config_get_string(const char *section_str, const char *option, char *def);
|
||||
|
||||
int config_get_int(const char *section, const char *option, int def);
|
||||
|
||||
int config_get_strings(const char *section_str, const char *option,
|
||||
int (*callback)(const char *value, void *privdata),
|
||||
void *privdata);
|
||||
|
||||
int parse_saddr(const char *addr, struct sockaddr_in *sa);
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _EVENT_H_
|
||||
#define _EVENT_H_
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#define FD_READ 0x01
|
||||
#define FD_WRITE 0x02
|
||||
#define FD_EXCEPT 0x04
|
||||
|
||||
#define event_add_readfd(fd, callback, privdata) \
|
||||
event_add_fd(fd, FD_READ, callback, privdata)
|
||||
|
||||
#define event_add_writefd(fd, callback, privdata) \
|
||||
event_add_fd(fd, FD_WRITE, callback, privdata)
|
||||
|
||||
#define event_add_exceptfd(fd, callback, privdata) \
|
||||
event_add_fd(fd, FD_EXCEPT, callback, privdata)
|
||||
|
||||
int event_add_fd(int fd, int type, int (*callback)(int fd, void *privdata), void *privdata);
|
||||
int event_add_timeout(struct timeval *timeout, int (*callback)(void *privdata), void *privdata);
|
||||
|
||||
int event_remove_fd(int fd);
|
||||
|
||||
void event_loop(void);
|
||||
|
||||
#endif /* _EVENT_H_ */
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef _GAMELIST_H_
|
||||
#define _GAMELIST_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "list.h"
|
||||
|
||||
struct game_entry {
|
||||
struct list_head list;
|
||||
unsigned long modtime;
|
||||
|
||||
/* begin HLSW_ENTRY */
|
||||
uint16_t gameid;
|
||||
uint32_t ip;
|
||||
uint16_t port1;
|
||||
uint16_t port2;
|
||||
/* end HLSW_ENTRY */
|
||||
|
||||
} __attribute__ ((packed));
|
||||
|
||||
int gamelist_init();
|
||||
int gamelist_add(struct game_entry *entry);
|
||||
int gamelist_gc_and_dump(int (*callback)(struct game_entry *entry), int timeout);
|
||||
|
||||
#endif /* _GAMELIST_H_ */
|
|
@ -1,48 +0,0 @@
|
|||
#ifndef _HLSWMASTER_H
|
||||
#define _HLSWMASTER_H
|
||||
|
||||
#include "list.h"
|
||||
#include "netpkt.h"
|
||||
|
||||
struct game_server {
|
||||
struct list_head list;
|
||||
unsigned long modtime;
|
||||
|
||||
u_int16_t gameid;
|
||||
u_int32_t ip;
|
||||
u_int16_t port1;
|
||||
u_int16_t port2;
|
||||
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* daemon.c */
|
||||
void daemonize(char *pw_name);
|
||||
|
||||
/* logging.c */
|
||||
void log_open(char *logfile);
|
||||
void log_close();
|
||||
void log_print(const char *fmt, ... );
|
||||
|
||||
/* plugin.c */
|
||||
int plugin_load(char *name);
|
||||
int plugin_unload(char *name);
|
||||
int plugins_scan(void);
|
||||
int plugins_parse(struct net_pkt *pkt);
|
||||
int plugins_gc(unsigned long timeout);
|
||||
|
||||
/* scanner.c */
|
||||
void pkt_queue(struct net_pkt *pkt);
|
||||
int scan_init(void);
|
||||
void scan_exit(void);
|
||||
void scan_transmit(void);
|
||||
void scan_receive(void);
|
||||
|
||||
/* serverlist.c */
|
||||
void server_collector(void);
|
||||
|
||||
/* client.c */
|
||||
int client_pkt_add(struct game_server *server);
|
||||
int client_pkt_commit(void);
|
||||
void client_handler(void);
|
||||
|
||||
#endif
|
|
@ -1,15 +1,15 @@
|
|||
#ifndef _LIST_H
|
||||
#define _LIST_H
|
||||
#ifndef _LIST_H_
|
||||
#define _LIST_H_
|
||||
|
||||
/*
|
||||
** stolen from linux kernel (2.6.11)
|
||||
** linux/include/linux/stddef.h (offsetoff)
|
||||
** linux/include/linux/kernel.h (container_of)
|
||||
** linux/include/linux/list.h (*list*)
|
||||
** linux/include/linux/netfilter_ipv4/listhelp.h (LIST_FIND)
|
||||
**
|
||||
** modified by Olaf Rempel
|
||||
*/
|
||||
* stolen from linux kernel 2.6.11 (http://kernel.org/)
|
||||
* linux/include/linux/stddef.h (offsetoff)
|
||||
* linux/include/linux/kernel.h (container_of)
|
||||
* linux/include/linux/list.h (*list*)
|
||||
* linux/include/linux/netfilter_ipv4/listhelp.h (LIST_FIND)
|
||||
*
|
||||
* modified by Olaf Rempel <razzor@kopf-tisch.de>
|
||||
*/
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
|
@ -45,7 +45,7 @@ static inline void __list_add(struct list_head *new,
|
|||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
|
@ -58,7 +58,7 @@ static inline void list_add(struct list_head *new, struct list_head *head)
|
|||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
|
@ -71,7 +71,7 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
|||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
|
@ -84,7 +84,7 @@ static inline void __list_del(struct list_head * prev, struct list_head * next)
|
|||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is
|
||||
|
@ -97,9 +97,9 @@ static inline void list_del(struct list_head *entry)
|
|||
entry->prev = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
* entry: the element to delete from the list.
|
||||
*/
|
||||
static inline void list_del_init(struct list_head *entry)
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ static inline void list_del_init(struct list_head *entry)
|
|||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_move - delete from one list and add as another's head
|
||||
* @list: the entry to move
|
||||
* @head: the head that will precede our entry
|
||||
|
@ -118,7 +118,7 @@ static inline void list_move(struct list_head *list, struct list_head *head)
|
|||
list_add(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_move_tail - delete from one list and add as another's tail
|
||||
* @list: the entry to move
|
||||
* @head: the head that will follow our entry
|
||||
|
@ -130,7 +130,7 @@ static inline void list_move_tail(struct list_head *list,
|
|||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
|
@ -153,7 +153,7 @@ static inline void __list_splice(struct list_head *list,
|
|||
at->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
|
@ -164,7 +164,7 @@ static inline void list_splice(struct list_head *list, struct list_head *head)
|
|||
__list_splice(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
|
@ -180,7 +180,7 @@ static inline void list_splice_init(struct list_head *list,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
|
@ -189,7 +189,7 @@ static inline void list_splice_init(struct list_head *list,
|
|||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
|
@ -197,7 +197,7 @@ static inline void list_splice_init(struct list_head *list,
|
|||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_for_each_prev - iterate over a list backwards
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
|
@ -205,7 +205,7 @@ static inline void list_splice_init(struct list_head *list,
|
|||
#define list_for_each_prev(pos, head) \
|
||||
for (pos = (head)->prev; pos != (head); pos = pos->prev)
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
|
@ -215,7 +215,7 @@ static inline void list_splice_init(struct list_head *list,
|
|||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
|
@ -226,7 +226,7 @@ static inline void list_splice_init(struct list_head *list,
|
|||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
|
@ -237,7 +237,7 @@ static inline void list_splice_init(struct list_head *list,
|
|||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
/*
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @n: another type * to use as temporary storage
|
||||
|
@ -250,7 +250,6 @@ static inline void list_splice_init(struct list_head *list,
|
|||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
#endif
|
||||
|
||||
/* Return pointer to first true entry, if any, or NULL. A macro
|
||||
required to allow inlining of cmpfn. */
|
||||
|
@ -265,3 +264,5 @@ static inline void list_splice_init(struct list_head *list,
|
|||
} \
|
||||
(type)__j; \
|
||||
})
|
||||
|
||||
#endif /* _LIST_H_ */
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _LOGGING_H_
|
||||
#define _LOGGING_H_
|
||||
|
||||
#define LOG_DEBUG 5
|
||||
#define LOG_INFO 4
|
||||
#define LOG_NOTICE 3
|
||||
#define LOG_WARN 2
|
||||
#define LOG_ERROR 1
|
||||
#define LOG_CRIT 0
|
||||
|
||||
#define LOG_EVERYTIME 0
|
||||
|
||||
int log_init(char *logfile);
|
||||
void log_print(int prio, const char *fmt, ... );
|
||||
|
||||
#endif /* _LOGGING_H_ */
|
|
@ -9,10 +9,20 @@
|
|||
|
||||
struct net_pkt {
|
||||
struct list_head list;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
unsigned int size;
|
||||
unsigned char buf[0];
|
||||
};
|
||||
|
||||
#endif
|
||||
int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
|
||||
int pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
|
||||
struct net_pkt * pkt_merge(struct net_pkt *pkt1, struct net_pkt *pkt2);
|
||||
|
||||
char * pkt_ntoa(struct net_pkt *pkt);
|
||||
unsigned short pkt_getport(struct net_pkt *pkt);
|
||||
int pkt_sameaddr(struct net_pkt *pkt1, struct net_pkt *pkt2);
|
||||
int pkt_parse_int(struct net_pkt *pkt, unsigned int offset, int *val);
|
||||
int pkt_parse_ip(struct net_pkt *pkt, int offset, struct in_addr *ip);
|
||||
char * pkt_print(struct net_pkt *pkt);
|
||||
|
||||
#endif /* _NETPKT_H */
|
||||
|
|
|
@ -2,43 +2,30 @@
|
|||
#define _PLUGIN_H
|
||||
|
||||
#include "netpkt.h"
|
||||
#include "configfile.h"
|
||||
#include "list.h"
|
||||
|
||||
extern int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2);
|
||||
// paket nicht akzeptiert, free() muss noch aufgerufen werden
|
||||
#define PARSE_REJECT 0
|
||||
|
||||
struct scan_ports {
|
||||
unsigned short portlo;
|
||||
unsigned short porthi;
|
||||
unsigned short gameid;
|
||||
};
|
||||
// paket akzeptiert, free() muss noch aufgerufen werden
|
||||
#define PARSE_ACCEPT 1
|
||||
|
||||
extern int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size);
|
||||
extern int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size);
|
||||
|
||||
extern int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr);
|
||||
extern int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
|
||||
extern void * pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
|
||||
|
||||
extern int server_add_pkt(unsigned int gameid, struct net_pkt *pkt);
|
||||
|
||||
extern char * pkt_ntoa(struct net_pkt *pkt);
|
||||
extern unsigned short pkt_getport(struct net_pkt *pkt);
|
||||
extern int pkt_atoi(struct net_pkt *pkt, void *p);
|
||||
// paket akzeptiert, free() wurde schon, oder darf noch aufgerufen werden
|
||||
#define PARSE_ACCEPT_FREED 2
|
||||
|
||||
struct hlswmaster_plugin {
|
||||
/* must be first */
|
||||
struct list_head list;
|
||||
char name[32];
|
||||
|
||||
char name[32];
|
||||
|
||||
int (*init)(struct list_head *config);
|
||||
int (*init)(void);
|
||||
int (*fini)(void);
|
||||
int (*scan)(void);
|
||||
int (*parse)(struct net_pkt *pkt);
|
||||
int (*gc)(int timeout);
|
||||
};
|
||||
|
||||
extern void register_plugin(struct hlswmaster_plugin *me);
|
||||
extern void unregister_plugin(struct hlswmaster_plugin *me);
|
||||
int plugin_init();
|
||||
int plugins_scan();
|
||||
int plugins_parse(struct net_pkt *pkt);
|
||||
|
||||
#endif
|
||||
#endif /* _PLUGIN_H */
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef _PLUGIN_HELPER_H
|
||||
#define _PLUGIN_HELPER_H
|
||||
|
||||
struct scan_ports {
|
||||
unsigned short portlo;
|
||||
unsigned short porthi;
|
||||
unsigned short gameid;
|
||||
};
|
||||
|
||||
int server_add(uint16_t gameid, uint32_t ip, uint16_t port1, uint16_t port2);
|
||||
int server_add_pkt(unsigned int gameid, struct net_pkt *pkt);
|
||||
int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size);
|
||||
int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr);
|
||||
|
||||
#endif /* _PLUGIN_HELPER_H */
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _SCANNER_H_
|
||||
#define _SCANNER_H_
|
||||
|
||||
int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size);
|
||||
int scanner_init();
|
||||
|
||||
#endif /* _SCANNER_H_ */
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _SERVER_H_
|
||||
#define _SERVER_H_
|
||||
|
||||
int server_init();
|
||||
|
||||
#endif /* _SERVER_H_ */
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 03/2005 by Olaf Rempel *
|
||||
* Copyright (C) 06/2006 by Olaf Rempel *
|
||||
* razzor@kopf-tisch.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
@ -24,67 +24,80 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
static FILE *log_fd = NULL;
|
||||
#include "logging.h"
|
||||
|
||||
#define BUFSIZE 8192
|
||||
|
||||
static FILE *log_fd = NULL;
|
||||
static char *buffer = NULL;
|
||||
|
||||
void log_print(int prio, const char *fmt, ...)
|
||||
{
|
||||
va_list az;
|
||||
int len;
|
||||
|
||||
if (buffer == NULL) {
|
||||
buffer = malloc(BUFSIZE);
|
||||
if (buffer == NULL) {
|
||||
fprintf(stderr, "log_print: out of memory\nBailing out!\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
va_start(az, fmt);
|
||||
len = vsnprintf(buffer, BUFSIZE, fmt, az);
|
||||
va_end(az);
|
||||
|
||||
if (len < 0 || len >= BUFSIZE) {
|
||||
log_print(LOG_ERROR, "log_print: arguments too long");
|
||||
errno = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (errno) {
|
||||
strncpy(buffer + len, ": ", BUFSIZE - len);
|
||||
len += 2;
|
||||
strncpy(buffer + len, strerror(errno), BUFSIZE - len);
|
||||
}
|
||||
|
||||
if (log_fd) {
|
||||
char tbuf[64];
|
||||
time_t tzgr;
|
||||
|
||||
time(&tzgr);
|
||||
strftime(tbuf, sizeof(tbuf), "%b %d %H:%M:%S :", localtime(&tzgr));
|
||||
|
||||
fprintf(log_fd, "%s %s\n", tbuf, buffer);
|
||||
fflush(log_fd);
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "%s\n", buffer);
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
static void log_close(void)
|
||||
{
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
|
||||
/**
|
||||
* log_close()
|
||||
* schliesst das logfile
|
||||
*/
|
||||
void log_close() {
|
||||
fclose(log_fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* log_open()
|
||||
* oeffnet ein logfile
|
||||
* wenn der prozess sich beendet, wird das logfile auch wieder geschlossen
|
||||
*
|
||||
* @param char *logfile
|
||||
*/
|
||||
void log_open(char *logfile) {
|
||||
if ((log_fd = fopen(logfile, "a" )) == NULL) {
|
||||
fprintf(stderr, "log_open(\"%s\"): %s\n", logfile, strerror(errno));
|
||||
exit(-1);
|
||||
int log_init(char *logfile)
|
||||
{
|
||||
log_fd = fopen(logfile, "a");
|
||||
if (log_fd == NULL) {
|
||||
log_print(LOG_ERROR, "log_open('%s'): %s", logfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (atexit(log_close) != 0) {
|
||||
fprintf(stderr, "log_open(): atexit(): %s\n", strerror(errno));
|
||||
exit(-1);
|
||||
log_print(LOG_ERROR, "log_open(): atexit()");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* log_print()
|
||||
* schreibt eine Zeile ins Logfile oder auf stderr
|
||||
* wenn errno gesetzt ist, wird der error-string mit ausgegeben
|
||||
*
|
||||
* @param variable parameterlist
|
||||
*/
|
||||
void log_print(const char *fmt, ...) {
|
||||
va_list az;
|
||||
char buffer[256];
|
||||
|
||||
va_start(az, fmt);
|
||||
vsprintf(buffer, fmt, az);
|
||||
va_end(az);
|
||||
|
||||
if (log_fd) {
|
||||
time_t tzgr;
|
||||
char tbuf[64];
|
||||
time(&tzgr);
|
||||
strftime(tbuf, 64, "%b %d %H:%M:%S :", localtime(&tzgr));
|
||||
|
||||
if (errno) {
|
||||
fprintf(log_fd, "%s %s: %s\n", tbuf, buffer, strerror(errno));
|
||||
} else {
|
||||
fprintf(log_fd, "%s %s\n", tbuf, buffer);
|
||||
}
|
||||
} else {
|
||||
if (errno) {
|
||||
fprintf(stderr, "%s: %s\n", buffer, strerror(errno));
|
||||
} else {
|
||||
fprintf(stderr, "%s\n", buffer);
|
||||
}
|
||||
}
|
||||
errno = 0;
|
||||
fflush(log_fd);
|
||||
|
||||
log_print(LOG_EVERYTIME, "==========================");
|
||||
return 1;
|
||||
}
|
|
@ -10,23 +10,25 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
struct _entry {
|
||||
u_int16_t gameid;
|
||||
u_int32_t ip;
|
||||
u_int16_t port1;
|
||||
u_int16_t port2;
|
||||
uint16_t gameid;
|
||||
uint32_t ip;
|
||||
uint16_t port1;
|
||||
uint16_t port2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static char hlswheader[] = "\xFF\xFF\xFF\xFFHLSWLANSEARCH";
|
||||
|
||||
#define id2name_count (sizeof(id2name) / sizeof(char *) -1)
|
||||
static char *id2name[] = {
|
||||
"Unknown", // 0
|
||||
"Unknown", // 0
|
||||
"Halflife",
|
||||
"Quake 1",
|
||||
"Quake 2",
|
||||
"Q3Comp",
|
||||
"Unreal Tournament",
|
||||
"Unreal Tournament", // 5
|
||||
"Quake 3 Arena",
|
||||
"Elite Force",
|
||||
"Return to Castle Wolfenstein",
|
||||
|
@ -36,7 +38,7 @@ static char *id2name[] = {
|
|||
"Jedi Knight 2",
|
||||
"Soldier of Fortune",
|
||||
"Unreal Tournament 2003",
|
||||
"America's Army: Operations",
|
||||
"America's Army: Operations", // 15
|
||||
"Battlefield 1942",
|
||||
"Alien vs. Predator 2",
|
||||
"Rune",
|
||||
|
@ -46,36 +48,39 @@ static char *id2name[] = {
|
|||
"Operation Flashpoint",
|
||||
"Operation Flashpoint Resistance",
|
||||
"Devastation",
|
||||
"Wolfenstein - Enemy Territory",
|
||||
"Wolfenstein - Enemy Territory", //25
|
||||
"Elite Force 2",
|
||||
"Jedi Knight 3",
|
||||
"Medal of Honor: Allied Assault Breakthrough",
|
||||
"Tribes 2",
|
||||
"Halo", // 30
|
||||
"Call of Duty",
|
||||
"Call of Duty",
|
||||
"Savage: The Battle for Newerth",
|
||||
"Unreal Tournament 2004",
|
||||
"HLSteam",
|
||||
"Battlefield Vietnam",
|
||||
"Battlefield Vietnam", // 35
|
||||
"GS2Prot",
|
||||
"Pain Killer",
|
||||
"Doom 3",
|
||||
"OGPProt",
|
||||
"Halflife 2", // 40
|
||||
"Tribes Vengeance",
|
||||
"Call of Duty: United Offensive"
|
||||
"Call of Duty: United Offensive",
|
||||
"Starwars: Battlefront (?)",
|
||||
"SWAT 4",
|
||||
"Battlefield 2", // 45
|
||||
"unknown",
|
||||
"Quake 4",
|
||||
"Call of Duty 2",
|
||||
"unknown",
|
||||
"FEAR", // 50
|
||||
"Warsow(?)"
|
||||
};
|
||||
|
||||
static struct option opts[] = {
|
||||
{"destination", 1, 0, 'd'},
|
||||
{"intervall", 1, 0, 'i'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
static int sock, verbose = 0;
|
||||
|
||||
static int sock;
|
||||
|
||||
static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size) {
|
||||
static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size)
|
||||
{
|
||||
struct _entry *server;
|
||||
struct in_addr tmp;
|
||||
|
||||
|
@ -84,37 +89,43 @@ static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size) {
|
|||
inet_ntoa(src->sin_addr), ntohs(src->sin_port), size);
|
||||
|
||||
} else {
|
||||
printf("received hlsw packet from: %15s:%-5d size=%d\n",
|
||||
inet_ntoa(src->sin_addr), ntohs(src->sin_port), size);
|
||||
|
||||
server = pkt + sizeof(hlswheader);
|
||||
while ((void *)server < pkt + size) {
|
||||
tmp.s_addr = server->ip;
|
||||
printf(" ip=%15s port1=%5d port2=%5d gameid=%2d (%s)\n",
|
||||
inet_ntoa(tmp), server->port1, server->port2,
|
||||
server->gameid, id2name[server->gameid]);
|
||||
server++;
|
||||
printf("received hlsw packet from: %15s:%-5d size=%d count=%d\n",
|
||||
inet_ntoa(src->sin_addr), ntohs(src->sin_port), size,
|
||||
((size > sizeof(hlswheader)) ? (size - sizeof(hlswheader)) / sizeof(struct _entry) : 0));
|
||||
|
||||
if (verbose) {
|
||||
server = pkt + sizeof(hlswheader);
|
||||
while ((void *)server < pkt + size) {
|
||||
tmp.s_addr = server->ip;
|
||||
|
||||
printf(" ip=%15s port1=%5d port2=%5d gameid=%2d (%s)\n",
|
||||
inet_ntoa(tmp), server->port1, server->port2,
|
||||
server->gameid, server->gameid <= id2name_count ? id2name[server->gameid] : "unknown");
|
||||
server++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int scan_init() {
|
||||
int i = 1;
|
||||
|
||||
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
static int scan_init()
|
||||
{
|
||||
sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("socket()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int i = 1;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i))) {
|
||||
perror("setsockopt()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scan_transmit(struct sockaddr_in *dst) {
|
||||
static int scan_transmit(struct sockaddr_in *dst)
|
||||
{
|
||||
if (sendto(sock, hlswheader, sizeof(hlswheader), 0, (struct sockaddr *)dst, sizeof(struct sockaddr_in)) < 0) {
|
||||
perror("sendto()");
|
||||
return -1;
|
||||
|
@ -123,7 +134,8 @@ static int scan_transmit(struct sockaddr_in *dst) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int scan_receive() {
|
||||
static int scan_receive()
|
||||
{
|
||||
struct sockaddr_in src;
|
||||
struct timeval tv;
|
||||
fd_set fdsel;
|
||||
|
@ -132,26 +144,24 @@ static int scan_receive() {
|
|||
|
||||
FD_ZERO(&fdsel);
|
||||
FD_SET(sock, &fdsel);
|
||||
|
||||
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
while (1) {
|
||||
|
||||
/* timeout */
|
||||
while (tv.tv_sec > 0 || tv.tv_usec > 0) {
|
||||
|
||||
if (select(FD_SETSIZE, &fdsel, NULL, NULL, &tv) < 0) {
|
||||
perror("select");
|
||||
perror("select()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* timeout: our exit */
|
||||
if (tv.tv_sec == 0 && tv.tv_usec == 0)
|
||||
break;
|
||||
|
||||
/* get packetsize */
|
||||
if (ioctl(sock, FIONREAD, &recvsize) == -1) {
|
||||
perror("ioctl");
|
||||
perror("ioctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (recvsize > 0) {
|
||||
if (!(pkt = malloc(recvsize))) {
|
||||
perror("malloc()");
|
||||
|
@ -166,11 +176,19 @@ static int scan_receive() {
|
|||
free(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
static struct option opts[] = {
|
||||
{"destination", 1, 0, 'd'},
|
||||
{"intervall", 1, 0, 'i'},
|
||||
{"verbose", 0, 0, 'v'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct sockaddr_in dst;
|
||||
int arg = 0, code = 0;
|
||||
int freq = -1;
|
||||
|
@ -180,7 +198,7 @@ int main(int argc, char *argv[]) {
|
|||
inet_aton("255.255.255.255", &dst.sin_addr);
|
||||
|
||||
while (code != -1) {
|
||||
code = getopt_long(argc, argv, "d:i:h", opts, &arg);
|
||||
code = getopt_long(argc, argv, "d:i:vh", opts, &arg);
|
||||
|
||||
switch (code) {
|
||||
case 'd': /* destination */
|
||||
|
@ -189,7 +207,7 @@ int main(int argc, char *argv[]) {
|
|||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'i': /* intervall */
|
||||
freq = atoi(optarg);
|
||||
if (freq < 1) {
|
||||
|
@ -198,11 +216,16 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
break;
|
||||
|
||||
case 'v': /* verbose */
|
||||
verbose = 1;
|
||||
break;
|
||||
|
||||
case 'h': /* help */
|
||||
printf("Usage: masterquery [options]\n"
|
||||
"Options: \n"
|
||||
" --destination -d scan destination <ip>\n"
|
||||
" --intervall -i scan intervall in seconds\n"
|
||||
" --verbose -v verbose: show packet content\n"
|
||||
" --help -h this help\n"
|
||||
"\n");
|
||||
exit(0);
|
||||
|
@ -220,18 +243,14 @@ int main(int argc, char *argv[]) {
|
|||
if (scan_init())
|
||||
exit(-1);
|
||||
|
||||
while (1) {
|
||||
do {
|
||||
if (scan_transmit(&dst))
|
||||
exit(-1);
|
||||
|
||||
if (scan_receive())
|
||||
exit(-1);
|
||||
|
||||
if (freq < 0)
|
||||
break;
|
||||
|
||||
sleep(freq -1);
|
||||
}
|
||||
} while (freq >= 1 && !sleep(freq -1));
|
||||
|
||||
close(sock);
|
||||
return 0;
|
|
@ -0,0 +1,143 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define __USE_GNU
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "netpkt.h"
|
||||
|
||||
int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size)
|
||||
{
|
||||
|
||||
if (offset >= pkt->size)
|
||||
return 1;
|
||||
|
||||
/* nicht ueber das paket hinaus vergleichen */
|
||||
if (offset + size >= pkt->size)
|
||||
size = pkt->size - offset;
|
||||
|
||||
return memcmp(pkt->buf + offset, search, size);
|
||||
}
|
||||
|
||||
int pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size)
|
||||
{
|
||||
void *found;
|
||||
|
||||
if (offset >= pkt->size)
|
||||
return -1;
|
||||
|
||||
found = memmem(pkt->buf + offset, pkt->size, search, size);
|
||||
|
||||
return (found == NULL) ? -1 : (found - (void *)pkt->buf);
|
||||
}
|
||||
|
||||
struct net_pkt * pkt_merge(struct net_pkt *pkt1, struct net_pkt *pkt2)
|
||||
{
|
||||
struct net_pkt *ret;
|
||||
ret = malloc(sizeof(struct net_pkt) + pkt1->size + pkt2->size);
|
||||
|
||||
memcpy(&ret->addr, &pkt1->addr, sizeof(ret->addr));
|
||||
ret->size = pkt1->size + pkt2->size;
|
||||
|
||||
memcpy(ret->buf, pkt1->buf, pkt1->size);
|
||||
memcpy(ret->buf + pkt1->size, pkt2->buf, pkt2->size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char * pkt_ntoa(struct net_pkt *pkt)
|
||||
{
|
||||
return inet_ntoa(pkt->addr.sin_addr);
|
||||
}
|
||||
|
||||
unsigned short pkt_getport(struct net_pkt *pkt)
|
||||
{
|
||||
return ntohs(pkt->addr.sin_port);
|
||||
}
|
||||
|
||||
int pkt_sameaddr(struct net_pkt *pkt1, struct net_pkt *pkt2)
|
||||
{
|
||||
return (pkt1->addr.sin_addr.s_addr == pkt2->addr.sin_addr.s_addr) &&
|
||||
(pkt1->addr.sin_port == pkt2->addr.sin_port);
|
||||
}
|
||||
|
||||
int pkt_parse_int(struct net_pkt *pkt, unsigned int offset, int *val)
|
||||
{
|
||||
unsigned char *max = pkt->buf + pkt->size;
|
||||
unsigned char *c = pkt->buf + offset;
|
||||
|
||||
/* untere grenze abtesten */
|
||||
if (pkt->buf > c || c > max)
|
||||
return -1;
|
||||
|
||||
*val = 0;
|
||||
|
||||
/* ziffern einlesen */
|
||||
while (isdigit(*c) && c < max)
|
||||
*val = (*val * 10) + (*c++ - 0x30);
|
||||
|
||||
return (c - (pkt->buf + offset));
|
||||
}
|
||||
|
||||
int pkt_parse_ip(struct net_pkt *pkt, int offset, struct in_addr *ip)
|
||||
{
|
||||
int i, tmp, count, pos = offset;
|
||||
ip->s_addr = 0;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
count = pkt_parse_int(pkt, pos, &tmp);
|
||||
pos += count;
|
||||
if (count == 0 || tmp < 0 || tmp > 255)
|
||||
return 0;
|
||||
|
||||
ip->s_addr = ip->s_addr>>8 | tmp<<24;
|
||||
|
||||
if (i != 3 && pkt->buf[pos++] != '.')
|
||||
return 0;
|
||||
}
|
||||
return pos - offset;
|
||||
}
|
||||
|
||||
char * pkt_print(struct net_pkt *pkt)
|
||||
{
|
||||
int pos = 0, i = 0, j;
|
||||
char *buf = malloc(pkt->size * 4 + 64);
|
||||
|
||||
while (pos < pkt->size) {
|
||||
i += sprintf(buf + i, "%04X: ", pos);
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (pos + j < pkt->size)
|
||||
i += sprintf(buf + i, "%02X", pkt->buf[pos + j]);
|
||||
else
|
||||
i += sprintf(buf + i, " ");
|
||||
|
||||
if (j % 2)
|
||||
buf[i++] = ' ';
|
||||
}
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (pos + j < pkt->size) {
|
||||
unsigned char val = pkt->buf[pos + j];
|
||||
if (val >= 0x20 && val < 0x80)
|
||||
buf[i++] = val;
|
||||
else
|
||||
buf[i++] = '.';
|
||||
} else {
|
||||
buf[i++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
pos += 16;
|
||||
buf[i++] = '\r';
|
||||
buf[i++] = '\n';
|
||||
}
|
||||
buf[i] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
/***************************************************************************
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "plugin.h"
|
||||
#include "configfile.h"
|
||||
#include "logging.h"
|
||||
#include "netpkt.h"
|
||||
#include "list.h"
|
||||
#include "event.h"
|
||||
|
||||
#define BUFSIZE 512
|
||||
|
||||
static LIST_HEAD(plugin_list);
|
||||
|
||||
static int plugin_load(const char *filename, void *privdata)
|
||||
{
|
||||
char *plugin_dir = (char *)privdata;
|
||||
|
||||
char *fullname = malloc(BUFSIZE);
|
||||
if (fullname == NULL) {
|
||||
log_print(LOG_ERROR, "plugin_load: out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int len = snprintf(fullname, BUFSIZE, "%s/%s", plugin_dir, filename);
|
||||
if (len < 0 || len >= BUFSIZE) {
|
||||
log_print(LOG_ERROR, "plugin_load: file name too long: %s/%s", plugin_dir, filename);
|
||||
free(fullname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dlerror();
|
||||
void *dlref = dlopen(fullname, RTLD_NOW);
|
||||
if (dlref == NULL) {
|
||||
log_print(LOG_WARN, "plugin_load: %s", dlerror());
|
||||
free(fullname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct hlswmaster_plugin *plugin = dlsym(dlref, "plugin");
|
||||
if (plugin == NULL) {
|
||||
log_print(LOG_WARN, "plugin_load: invalid plugin '%s'", fullname);
|
||||
dlclose(dlref);
|
||||
free(fullname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_print(LOG_INFO, "loading plugin '%s'", plugin->name);
|
||||
|
||||
if (plugin->init == NULL || (plugin->init() == 0)) {
|
||||
list_add_tail(&plugin->list, &plugin_list);
|
||||
free(fullname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_print(LOG_WARN, "plugin_load: failed to load '%s'", plugin->name);
|
||||
dlclose(dlref);
|
||||
free(fullname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int plugins_scan(void)
|
||||
{
|
||||
struct hlswmaster_plugin *plugin;
|
||||
list_for_each_entry(plugin, &plugin_list, list)
|
||||
if (plugin->scan && !plugin->scan())
|
||||
log_print(LOG_WARN, "plugin %s: scan error", plugin->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plugins_parse(struct net_pkt *pkt)
|
||||
{
|
||||
int retval;
|
||||
|
||||
struct hlswmaster_plugin *plugin;
|
||||
list_for_each_entry(plugin, &plugin_list, list)
|
||||
if (plugin->parse && (retval = plugin->parse(pkt)))
|
||||
return retval;
|
||||
|
||||
return PARSE_REJECT;
|
||||
}
|
||||
|
||||
int plugin_init(void)
|
||||
{
|
||||
char *dir = config_get_string("global", "plugin_dir", ".");
|
||||
int cnt = config_get_strings("global", "plugin", plugin_load, (void *)dir);
|
||||
|
||||
log_print(LOG_INFO, "%d plugins loaded", cnt);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,79 +1,78 @@
|
|||
/***************************************************************************
|
||||
* 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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "hlswmaster.h"
|
||||
|
||||
/**
|
||||
* daemonize()
|
||||
* macht den Prozess zu einen Daemon
|
||||
* und fuehrt ihn unterem user aus
|
||||
*
|
||||
* @param char *pw_name
|
||||
*
|
||||
* TODO: hier schon logging benutzen? stderr? wann exit/return?
|
||||
*/
|
||||
void daemonize(char *pw_name) {
|
||||
int fail = 0;
|
||||
pid_t pid;
|
||||
struct passwd *pwl;
|
||||
|
||||
if ((pid = fork()) < 0) {
|
||||
log_print("daemonize(): fork()");
|
||||
exit(-1);
|
||||
|
||||
} else if (pid != 0) {
|
||||
/* Elternprozess beenden */
|
||||
exit(0);
|
||||
|
||||
} else {
|
||||
/* Kindprozess weiterlaufen lassen */
|
||||
if (setsid() == -1) {
|
||||
log_print("daemonize: setsid()");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
umask(0) ;
|
||||
|
||||
if (pw_name != NULL) {
|
||||
if((pwl = getpwnam(pw_name)) == NULL) {
|
||||
log_print("mkdaemon(): getpwnam(\"%s\")", pw_name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (setgid(pwl->pw_gid) != 0) {
|
||||
log_print("mkdaemon(): setgid()");
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
if (setuid(pwl->pw_uid) != 0) {
|
||||
log_print("mkdaemon(): setuid()");
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
if (fail == 0) {
|
||||
log_print("user changed to: %s, pid: %d", pw_name, getpid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/***************************************************************************
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gamelist.h"
|
||||
#include "logging.h"
|
||||
#include "netpkt.h"
|
||||
#include "plugin_helper.h"
|
||||
#include "scanner.h"
|
||||
|
||||
int server_add(uint16_t gameid, uint32_t ip, uint16_t port1, uint16_t port2)
|
||||
{
|
||||
struct game_entry *entry = malloc(sizeof(struct game_entry));
|
||||
if (entry == NULL) {
|
||||
log_print(LOG_WARN, "server_add(): out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
entry->gameid = gameid;
|
||||
entry->ip = ip;
|
||||
entry->port1 = port1;
|
||||
entry->port2 = port2;
|
||||
|
||||
return gamelist_add(entry);
|
||||
}
|
||||
|
||||
int server_add_pkt(unsigned int gameid, struct net_pkt *pkt)
|
||||
{
|
||||
return server_add(gameid, pkt->addr.sin_addr.s_addr, ntohs(pkt->addr.sin_port), 0);
|
||||
}
|
||||
|
||||
int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size)
|
||||
{
|
||||
unsigned short port;
|
||||
int ret = 0;
|
||||
|
||||
while (portarr && portarr->portlo) {
|
||||
for (port = portarr->portlo; port <= portarr->porthi; port++)
|
||||
if (pkt_send(dstip, port, buf, size) < 0)
|
||||
ret = -1;
|
||||
|
||||
portarr++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr)
|
||||
{
|
||||
unsigned short port;
|
||||
while (portarr && portarr->portlo) {
|
||||
for (port = portarr->portlo; port <= portarr->porthi; port++)
|
||||
if (port == ntohs(pkt->addr.sin_port))
|
||||
return portarr->gameid;
|
||||
|
||||
portarr++;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
*.so
|
||||
*.d
|
|
@ -0,0 +1,22 @@
|
|||
PLUGINS := $(wildcard *.c)
|
||||
CFLAGS := -O2 -pipe -Wall -I../include
|
||||
|
||||
all: $(PLUGINS:.c=.so)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.so: %_sh.o
|
||||
$(LD) -shared -o $@ $<
|
||||
|
||||
%_sh.o: %.c
|
||||
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||
|
||||
%.d: %.c
|
||||
$(CC) $(CFLAGS) -MM -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.so *.d *.o
|
||||
|
||||
DEPS := $(wildcard *.c)
|
||||
-include $(DEPS:.c=.d)
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 03/2005 by Olaf Rempel *
|
||||
* Copyright (C) 12/2005 by Olaf Rempel *
|
||||
* razzor@kopf-tisch.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
@ -18,44 +18,41 @@
|
|||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <string.h>
|
||||
#include "netpkt.h"
|
||||
#include "plugin.h"
|
||||
#include "plugin_helper.h"
|
||||
|
||||
struct scan_ports port_arr[] = {
|
||||
static struct scan_ports port_arr[] = {
|
||||
{ 27666, 27673, 38 }, /* Doom 3 */
|
||||
{ 28004, 28008, 47 }, /* Quake 4 */
|
||||
{ 0,0,0 }
|
||||
};
|
||||
|
||||
static char scanmsg[] = "\xff\xffgetInfo";
|
||||
static char replymsg[] = "\xff\xffinfoResponse";
|
||||
|
||||
int scan(void) {
|
||||
static int scan(void)
|
||||
{
|
||||
pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse(struct net_pkt *pkt) {
|
||||
static int parse(struct net_pkt *pkt)
|
||||
{
|
||||
int gameid;
|
||||
|
||||
if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg)))
|
||||
return 0;
|
||||
|
||||
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
|
||||
return 0;
|
||||
return PARSE_REJECT;
|
||||
|
||||
if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg)))
|
||||
return PARSE_REJECT;
|
||||
|
||||
server_add_pkt(gameid, pkt);
|
||||
return 1;
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
|
||||
static struct hlswmaster_plugin plugin = {
|
||||
.name = "doom3",
|
||||
struct hlswmaster_plugin plugin = {
|
||||
.name = "d3engine",
|
||||
.scan = &scan,
|
||||
.parse = &parse,
|
||||
};
|
||||
|
||||
void _init(void) {
|
||||
register_plugin(&plugin);
|
||||
}
|
||||
|
||||
void _fini(void) {
|
||||
unregister_plugin(&plugin);
|
||||
}
|
|
@ -17,61 +17,285 @@
|
|||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "plugin.h"
|
||||
#include <time.h>
|
||||
|
||||
struct scan_ports port_arr[] = {
|
||||
{ 22000, 22010, 16 }, /* Battlefield 1942 */
|
||||
{ 0, 0, 0 }
|
||||
#include "logging.h"
|
||||
#include "event.h"
|
||||
#include "netpkt.h"
|
||||
#include "plugin.h"
|
||||
#include "plugin_helper.h"
|
||||
|
||||
static struct scan_ports port_arr[] = {
|
||||
{ 7777, 7788, 5 }, /* ut(5), ut2k3(14), rune(18), ut2k4(33), aao(15) */
|
||||
{ 22000, 22010, 16 }, /* bf1942(16) */
|
||||
{ 23000, 23010, 35 }, /* bfv(35) */
|
||||
{ 26001, 26011, 19 }, /* igi2(19) */
|
||||
{ 27888, 27888, 17 }, /* avp2(17) (nur der standart-port..) */
|
||||
{ 44400, 44400, 51 },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
static char scanmsg[] = "\\info\\";
|
||||
static char bf1942_reply[] = "\\gameId\\BF1942\\";
|
||||
static char hostport_search[] = "\\hostport\\";
|
||||
struct gs1_part {
|
||||
struct list_head list;
|
||||
unsigned long timeout;
|
||||
unsigned int queryid;
|
||||
unsigned int subid;
|
||||
struct net_pkt *pkt;
|
||||
};
|
||||
|
||||
int scan(void) {
|
||||
static LIST_HEAD(gs1_partlist);
|
||||
|
||||
static char scanmsg[] = "\\status\\";
|
||||
|
||||
static char search_queryid[] = "\\queryid\\";
|
||||
static char search_final[] = "\\final\\";
|
||||
static char search_hostport[] = "\\hostport\\";
|
||||
static char search_gamename[] = "\\gamename\\";
|
||||
static char search_gameid[] = "\\game_id\\";
|
||||
|
||||
static char reply_ut[] = "ut\\";
|
||||
static char reply_ut2k3[] = "ut2\\";
|
||||
static char reply_ut2k4[] = "ut2004\\";
|
||||
static char reply_bf1942[] = "bfield1942\\";
|
||||
static char reply_bfv1[] = "bfvietnam\\";
|
||||
static char reply_bfv2[] = "BFVIETNAM\\";
|
||||
static char reply_poe[] = "poe\\";
|
||||
static char reply_opk[] = "opk\\";
|
||||
static char reply_avp2[] = "avp2\\";
|
||||
static char reply_igi2[] = "projectigi2r\\";
|
||||
static char reply_aao[] = "armygame\\";
|
||||
static char reply_rune[] = "rune\\";
|
||||
static char reply_postal2[] ="postal2\\";
|
||||
|
||||
static int scan(void)
|
||||
{
|
||||
pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse(struct net_pkt *pkt) {
|
||||
int gameid, port;
|
||||
void *p;
|
||||
|
||||
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
|
||||
return 0;
|
||||
static struct net_pkt * gs1_pkt_merge(struct net_pkt *pkt, unsigned int queryid, unsigned int subid)
|
||||
{
|
||||
struct net_pkt *retpkt = NULL;
|
||||
struct gs1_part *part, *tmp;
|
||||
unsigned int i = 1, found = 0, notfound = 0;
|
||||
|
||||
switch (gameid) {
|
||||
case 16: /* battlefield 1942 */
|
||||
if (!pkt_memmem(pkt, 0, bf1942_reply, strlen(bf1942_reply)))
|
||||
return 0;
|
||||
// wenn paket non-final ist, in liste speichern
|
||||
// NULL zurueckgeben
|
||||
if (pkt_memmem(pkt, 0, search_final, strlen(search_final)) == -1) {
|
||||
part = malloc(sizeof(struct gs1_part));
|
||||
part->timeout = time(NULL);
|
||||
part->queryid = queryid;
|
||||
part->subid = subid;
|
||||
part->pkt = pkt;
|
||||
|
||||
p = pkt_memmem(pkt, 0, hostport_search, strlen(hostport_search));
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
port = pkt_atoi(pkt, p + strlen(hostport_search));
|
||||
server_add(gameid, pkt->addr.sin_addr.s_addr, port, ntohs(pkt->addr.sin_port));
|
||||
break;
|
||||
|
||||
default:
|
||||
server_add_pkt(gameid, pkt);
|
||||
break;
|
||||
// in liste packen
|
||||
list_add_tail(&part->list, &gs1_partlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
// wenn paket final ist, dann mit evtl. non-final paketen mergen
|
||||
// komplettes Paket zurueckgeben
|
||||
while (i < subid && notfound <= subid) {
|
||||
found = 0;
|
||||
list_for_each_entry_safe(part, tmp, &gs1_partlist, list) {
|
||||
if (pkt_sameaddr(part->pkt, pkt) && (part->queryid == queryid) && part->subid == i) {
|
||||
if (retpkt != NULL) {
|
||||
struct net_pkt *retpkt2 = retpkt;
|
||||
retpkt = pkt_merge(retpkt, part->pkt);
|
||||
free(retpkt2);
|
||||
free(part->pkt);
|
||||
} else {
|
||||
retpkt = part->pkt;
|
||||
}
|
||||
list_del(&part->list);
|
||||
free(part);
|
||||
found = 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (found == 0)
|
||||
notfound++;
|
||||
}
|
||||
|
||||
/* merge error, eat last paket, cleanup */
|
||||
if (i != subid || notfound > subid) {
|
||||
log_print(LOG_INFO, "gs1: merging error!");
|
||||
free(pkt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (retpkt != NULL) ? pkt_merge(retpkt, pkt) : pkt;
|
||||
}
|
||||
|
||||
static struct hlswmaster_plugin plugin = {
|
||||
static int parse_real(struct net_pkt *pkt, int gameid)
|
||||
{
|
||||
int port, offset, pos1, pos2;
|
||||
|
||||
pos1 = pkt_memmem(pkt, 0, search_gamename, strlen(search_gamename));
|
||||
pos1 += strlen(search_gamename);
|
||||
pos2 = pkt_memmem(pkt, 0, search_gameid, strlen(search_gameid));
|
||||
pos2 += strlen(search_gameid);
|
||||
|
||||
switch (gameid) {
|
||||
case 5:/* unreal tournament */
|
||||
if (!pkt_memcmp(pkt, pos1, reply_ut, strlen(reply_ut)))
|
||||
gameid = 5;
|
||||
|
||||
/* unreal tournament 2k3 */
|
||||
else if (!pkt_memcmp(pkt, pos1, reply_ut2k3, strlen(reply_ut2k4)))
|
||||
gameid = 14;
|
||||
|
||||
/* unreal tournament 2k4 */
|
||||
else if (!pkt_memcmp(pkt, pos1, reply_ut2k4, strlen(reply_ut2k4)))
|
||||
gameid = 33;
|
||||
|
||||
/* americas army operations */
|
||||
else if (!pkt_memcmp(pkt, pos1, reply_aao, strlen(reply_aao)))
|
||||
gameid = 15;
|
||||
|
||||
/* postal2 */
|
||||
else if (!pkt_memcmp(pkt, pos1, reply_postal2, strlen(reply_postal2)))
|
||||
gameid = 9;
|
||||
|
||||
else
|
||||
return PARSE_REJECT;
|
||||
break;
|
||||
|
||||
case 16:/* battlefield 1942 */
|
||||
case 35:/* battlefield vietnam */
|
||||
if (!pkt_memcmp(pkt, pos1, reply_bf1942, strlen(reply_bf1942)))
|
||||
gameid = 16;
|
||||
|
||||
else if (!pkt_memcmp(pkt, pos2, reply_bfv1, strlen(reply_bfv1)))
|
||||
gameid = 35;
|
||||
|
||||
else if (!pkt_memcmp(pkt, pos2, reply_bfv2, strlen(reply_bfv2)))
|
||||
gameid = 35;
|
||||
|
||||
else if (!pkt_memcmp(pkt, pos2, reply_poe, strlen(reply_poe)))
|
||||
gameid = 35;
|
||||
|
||||
else if (!pkt_memcmp(pkt, pos2, reply_opk, strlen(reply_opk)))
|
||||
gameid = 35;
|
||||
else
|
||||
return PARSE_REJECT;
|
||||
break;
|
||||
|
||||
case 17:/* alien vs. predator 2 */
|
||||
if (!pkt_memcmp(pkt, pos1, reply_avp2, strlen(reply_avp2)))
|
||||
gameid = 17;
|
||||
else
|
||||
return PARSE_REJECT;
|
||||
break;
|
||||
|
||||
case 18:/* rune */
|
||||
if (!pkt_memcmp(pkt, pos1, reply_rune, strlen(reply_rune)))
|
||||
gameid = 18;
|
||||
else
|
||||
return PARSE_REJECT;
|
||||
break;
|
||||
|
||||
case 19:/* project igi2 covert strike */
|
||||
if (!pkt_memcmp(pkt, pos1, reply_igi2, strlen(reply_igi2)))
|
||||
gameid = 19;
|
||||
else
|
||||
return PARSE_REJECT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return PARSE_REJECT;
|
||||
}
|
||||
|
||||
/* hostport angabe suchen */
|
||||
offset = pkt_memmem(pkt, 0, search_hostport, strlen(search_hostport));
|
||||
if (offset != -1)
|
||||
pkt_parse_int(pkt, offset + strlen(search_hostport), &port);
|
||||
|
||||
/*
|
||||
* wenn ein hostport angegeben wurde, und das nicht der src port ist
|
||||
* beide ports in die serverliste uebernehmen
|
||||
*/
|
||||
if ((offset != -1) && (port != ntohs(pkt->addr.sin_port))) {
|
||||
server_add(gameid, pkt->addr.sin_addr.s_addr, port, ntohs(pkt->addr.sin_port));
|
||||
} else {
|
||||
server_add_pkt(gameid, pkt);
|
||||
}
|
||||
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
|
||||
static int parse(struct net_pkt *pkt)
|
||||
{
|
||||
struct net_pkt *pkt2;
|
||||
int gameid, pos, offset, queryid, subid, retval;
|
||||
|
||||
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
|
||||
return PARSE_REJECT;
|
||||
|
||||
/* eat ut connection attemps */
|
||||
if (gameid == 5 && pkt->size <= 6)
|
||||
return PARSE_ACCEPT;
|
||||
|
||||
if ((offset = pkt_memmem(pkt, 0, search_queryid, strlen(search_queryid))) == -1)
|
||||
return PARSE_REJECT;
|
||||
|
||||
pos = offset + strlen(search_queryid);
|
||||
if ((offset = pkt_parse_int(pkt, pos, &queryid)) == 0)
|
||||
return PARSE_REJECT;
|
||||
|
||||
pos += offset +1;
|
||||
if ((offset = pkt_parse_int(pkt, pos, &subid)) == 0)
|
||||
return PARSE_REJECT;
|
||||
|
||||
/* multipaket antworten zusammenfassen
|
||||
* wenn paket non-final, dann einfach annehmen
|
||||
*/
|
||||
if ((pkt2 = gs1_pkt_merge(pkt, queryid, subid)) == NULL)
|
||||
return PARSE_ACCEPT_FREED;
|
||||
|
||||
retval = parse_real(pkt2, gameid);
|
||||
|
||||
/* free merged packet */
|
||||
if (pkt != pkt2)
|
||||
free(pkt2);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int gc(void *privdata) {
|
||||
|
||||
unsigned int timeout = (int)privdata;
|
||||
unsigned long now = time(NULL);
|
||||
|
||||
struct gs1_part *part, *tmp;
|
||||
list_for_each_entry_safe(part, tmp, &gs1_partlist, list) {
|
||||
if (part->timeout + timeout < now) {
|
||||
log_print(LOG_INFO, "gs1: removing dead fragment");
|
||||
list_del(&part->list);
|
||||
free(part->pkt);
|
||||
free(part);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init(void)
|
||||
{
|
||||
int timeout = config_get_int("gamespy1", "gc_timeout", 90);
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
event_add_timeout(&tv, gc, (void *)timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hlswmaster_plugin plugin = {
|
||||
.name = "gamespy1",
|
||||
.scan = &scan,
|
||||
.parse = &parse,
|
||||
.init = &init,
|
||||
};
|
||||
|
||||
void _init(void) {
|
||||
register_plugin(&plugin);
|
||||
}
|
||||
|
||||
void _fini(void) {
|
||||
unregister_plugin(&plugin);
|
||||
}
|
||||
|
|
|
@ -18,44 +18,90 @@
|
|||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <string.h>
|
||||
#include "netpkt.h"
|
||||
#include "plugin.h"
|
||||
#include "plugin_helper.h"
|
||||
|
||||
struct scan_ports port_arr[] = {
|
||||
{ 2302, 2302, 30 }, /* halo */
|
||||
{ 0,0,0 }
|
||||
static struct scan_ports port_arr[] = {
|
||||
{ 2302, 2302, 30 }, /* halo(30) */
|
||||
{ 3455, 3455, 37 }, /* painkiller(34) */
|
||||
{ 10481, 10482, 44 }, /* swat4 (44) */
|
||||
{ 29900, 29910, 45 }, /* battlefield2 (45) */
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
static char scanmsg[] = { 0xFE, 0xFD, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00 };
|
||||
static char scanmsg[] = { 0xFE, 0xFD, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0x00, 0x00 };
|
||||
static char replymsg[] = { 0x00, 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
|
||||
int scan(void) {
|
||||
static char search_hostport[] = "hostport";
|
||||
static char search_gamename[] = "gamename";
|
||||
|
||||
static char reply_bf2[] = "battlefield2";
|
||||
|
||||
static int scan(void)
|
||||
{
|
||||
pkt_send_portarr(NULL, port_arr, scanmsg, sizeof(scanmsg));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse(struct net_pkt *pkt) {
|
||||
int gameid;
|
||||
static int parse(struct net_pkt *pkt)
|
||||
{
|
||||
int gameid, pos1, pos3, port;
|
||||
|
||||
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
|
||||
return 0;
|
||||
|
||||
if (pkt_memcmp(pkt, 0, replymsg, sizeof(replymsg)))
|
||||
return 0;
|
||||
return PARSE_REJECT;
|
||||
|
||||
server_add_pkt(gameid, pkt);
|
||||
return 1;
|
||||
if (pkt_memcmp(pkt, 0, replymsg, sizeof(replymsg)))
|
||||
return PARSE_REJECT;
|
||||
|
||||
pos1 = pkt_memmem(pkt, 0, search_gamename, strlen(search_gamename));
|
||||
pos1 += strlen(search_gamename) +1;
|
||||
|
||||
/* hostport angabe suchen */
|
||||
pos3 = pkt_memmem(pkt, 0, search_hostport, strlen(search_hostport));
|
||||
if (pos3 != -1)
|
||||
pkt_parse_int(pkt, pos3 + strlen(search_hostport) +1, &port);
|
||||
|
||||
switch (gameid) {
|
||||
case 30:/* halo */
|
||||
case 37:/* painkiller */
|
||||
break;
|
||||
|
||||
case 44:/* swat4 */
|
||||
if (pos3 != -1)
|
||||
gameid = 44;
|
||||
else
|
||||
return PARSE_REJECT;
|
||||
break;
|
||||
|
||||
case 45:/* battlefield 2 */
|
||||
// todo: pos3 check noetig?
|
||||
if (!pkt_memcmp(pkt, pos1, reply_bf2, strlen(reply_bf2)) && pos3 != -1)
|
||||
gameid = 45;
|
||||
else
|
||||
return PARSE_REJECT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return PARSE_REJECT;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* wenn ein hostport angegeben wurde, und das nicht der src port ist
|
||||
* beide ports in die serverliste uebernehmen
|
||||
*/
|
||||
if ((pos3 != -1) && (port != ntohs(pkt->addr.sin_port))) {
|
||||
server_add(gameid, pkt->addr.sin_addr.s_addr, port, ntohs(pkt->addr.sin_port));
|
||||
} else {
|
||||
server_add_pkt(gameid, pkt);
|
||||
}
|
||||
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
|
||||
static struct hlswmaster_plugin plugin = {
|
||||
struct hlswmaster_plugin plugin = {
|
||||
.name = "gamespy2",
|
||||
.scan = &scan,
|
||||
.parse = &parse,
|
||||
};
|
||||
|
||||
void _init(void) {
|
||||
register_plugin(&plugin);
|
||||
}
|
||||
|
||||
void _fini(void) {
|
||||
unregister_plugin(&plugin);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 04/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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "netpkt.h"
|
||||
#include "plugin.h"
|
||||
#include "plugin_helper.h"
|
||||
#include "logging.h"
|
||||
|
||||
struct validnet_entry {
|
||||
struct list_head list;
|
||||
struct in_addr ip;
|
||||
struct in_addr netmask;
|
||||
};
|
||||
|
||||
static LIST_HEAD(validnet_list);
|
||||
|
||||
static struct scan_ports port_arr[] = {
|
||||
{ 27015, 27024, 1 }, /* cs/hl */
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
static char scanmsg1[] = "\xff\xff\xff\xff" "details";
|
||||
static char scanmsg2[] = "\xff\xff\xff\xff\x54";
|
||||
static char scanmsg3[] = "\xff\xff\xff\xff" "TSource Engine Query";
|
||||
|
||||
static int scan(void)
|
||||
{
|
||||
pkt_send_portarr(NULL, port_arr, scanmsg1, strlen(scanmsg1));
|
||||
pkt_send_portarr(NULL, port_arr, scanmsg2, strlen(scanmsg2));
|
||||
pkt_send_portarr(NULL, port_arr, scanmsg3, strlen(scanmsg3));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int parse(struct net_pkt *pkt)
|
||||
{
|
||||
struct in_addr tmp;
|
||||
int port, count, pos;
|
||||
|
||||
if (!pkt_check_portarr(pkt, port_arr))
|
||||
return PARSE_REJECT;
|
||||
|
||||
// check 0xFF 0xFF 0xFF 0xFF
|
||||
if (pkt_memcmp(pkt, 0, scanmsg1, 4))
|
||||
return PARSE_REJECT;
|
||||
|
||||
/* check for short answer without ip/port */
|
||||
if (pkt->size >= 5 && pkt->buf[4] == 'm' && pkt->buf[5] == 0x00) {
|
||||
server_add_pkt(1, pkt);
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
|
||||
/* second query?! */
|
||||
if (pkt->size >= 5 && pkt->buf[4] == 'I' && pkt->buf[5] == 0x07) {
|
||||
server_add_pkt(40, pkt);
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
|
||||
/* parse server IP */
|
||||
pos = 5;
|
||||
if ((count = pkt_parse_ip(pkt, pos, &tmp)) == 0)
|
||||
return PARSE_REJECT;
|
||||
|
||||
/* parse server port */
|
||||
pos += count +1;
|
||||
if ((count = pkt_parse_int(pkt, pos, &port)) == 0)
|
||||
return PARSE_REJECT;
|
||||
|
||||
/* check server IP */
|
||||
struct validnet_entry *entry;
|
||||
list_for_each_entry(entry, &validnet_list, list) {
|
||||
if (((entry->ip.s_addr ^ tmp.s_addr) & entry->netmask.s_addr) == 0) {
|
||||
server_add(1, tmp.s_addr, port, 0);
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
}
|
||||
|
||||
server_add(1, pkt->addr.sin_addr.s_addr, port, 0);
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
|
||||
// TODO: wrong place
|
||||
int parse_ipmask(const char *value, struct in_addr *ip, struct in_addr *netmask)
|
||||
{
|
||||
|
||||
char *buf = strdup(value);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
int retval = -1;
|
||||
char *p = strchr(buf, '/');
|
||||
|
||||
/* valid_net x.x.x.x */
|
||||
if (p == NULL) {
|
||||
/* single ip */
|
||||
if (inet_pton(AF_INET, buf, ip) > 0) {
|
||||
netmask->s_addr = 0xFFFFFFFF;
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
/* valid_net x.x.x.x/x.x.x.x or x.x.x.x/xx */
|
||||
} else {
|
||||
*p = 0x00;
|
||||
|
||||
/* ip */
|
||||
if (inet_pton(AF_INET, buf, &ip) > 0) {
|
||||
|
||||
/* x.x.x.x/x.x.x.x */
|
||||
if (inet_pton(AF_INET, p+1, netmask) > 0) {
|
||||
retval = 0;
|
||||
|
||||
/* x.x.x.x/xx */
|
||||
} else {
|
||||
int mask = atoi(p+1);
|
||||
|
||||
if (mask >= 0 && mask <= 32) {
|
||||
netmask->s_addr = htonl(0xFFFFFFFF << (32 - mask));
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int init_callback(const char *value, void *privdata)
|
||||
{
|
||||
struct validnet_entry *entry = malloc(sizeof(struct validnet_entry));
|
||||
if (entry == NULL) {
|
||||
log_print(LOG_ERROR, "halflife_init(): out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parse_ipmask(value, &entry->ip, &entry->netmask) != 0) {
|
||||
log_print(LOG_WARN, " invalid dst: %s", value);
|
||||
free(entry);
|
||||
return -1;
|
||||
}
|
||||
|
||||
list_add(&entry->list, &validnet_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init(void)
|
||||
{
|
||||
config_get_strings("halflife", "valid_net", init_callback, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hlswmaster_plugin plugin = {
|
||||
.name = "halflife",
|
||||
.scan = &scan,
|
||||
.parse = &parse,
|
||||
.init = &init,
|
||||
};
|
|
@ -17,48 +17,94 @@
|
|||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "netpkt.h"
|
||||
#include "plugin.h"
|
||||
#include "plugin_helper.h"
|
||||
#include "logging.h"
|
||||
#include "scanner.h"
|
||||
|
||||
struct game_entry {
|
||||
uint16_t gameid;
|
||||
uint32_t ip;
|
||||
uint16_t port1;
|
||||
uint16_t port2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct master_entry {
|
||||
struct list_head list;
|
||||
struct sockaddr_in addr;
|
||||
};
|
||||
|
||||
static LIST_HEAD(master_list);
|
||||
|
||||
static char scanmsg[] = "\xff\xff\xff\xffHLSWLANSEARCH";
|
||||
|
||||
struct _entry {
|
||||
u_int16_t gameid;
|
||||
u_int32_t ip;
|
||||
u_int16_t port1;
|
||||
u_int16_t port2;
|
||||
} __attribute__ ((packed));
|
||||
static int scan(void)
|
||||
{
|
||||
struct master_entry *entry;
|
||||
list_for_each_entry(entry, &master_list, list)
|
||||
pkt_send(&entry->addr.sin_addr, ntohs(entry->addr.sin_port), scanmsg, sizeof(scanmsg));
|
||||
|
||||
int scan(void) {
|
||||
pkt_send(NULL, 7140, scanmsg, sizeof(scanmsg));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse(struct net_pkt *pkt) {
|
||||
struct _entry *server;
|
||||
static int parse(struct net_pkt *pkt)
|
||||
{
|
||||
// TODO: check against master_list
|
||||
if (pkt_getport(pkt) != 7140)
|
||||
return 0;
|
||||
return PARSE_REJECT;
|
||||
|
||||
server = (void *)pkt->buf + sizeof(scanmsg);
|
||||
struct game_entry *game = (void *)pkt->buf + sizeof(scanmsg);
|
||||
|
||||
while ((void *)server < ((void *)pkt->buf + pkt->size)) {
|
||||
server_add(server->gameid, server->ip, server->port1, server->port2);
|
||||
server++;
|
||||
while ((void *)game < ((void *)pkt->buf + pkt->size)) {
|
||||
server_add(game->gameid, game->ip, game->port1, game->port2);
|
||||
game++;
|
||||
}
|
||||
return 1;
|
||||
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
|
||||
static struct hlswmaster_plugin plugin = {
|
||||
static int init_callback(const char *value, void *privdata)
|
||||
{
|
||||
struct master_entry *entry = malloc(sizeof(struct master_entry));
|
||||
if (entry == NULL) {
|
||||
log_print(LOG_ERROR, "hlswproxy_init(): out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parse_saddr(value, &entry->addr) != 0) {
|
||||
log_print(LOG_WARN, " invalid dst: %s", value);
|
||||
free(entry);
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_print(LOG_INFO, " adding remote master %s:%d",
|
||||
inet_ntoa(entry->addr.sin_addr), ntohs(entry->addr.sin_port));
|
||||
|
||||
list_add(&entry->list, &master_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init(void)
|
||||
{
|
||||
if (config_get_strings("hlswproxy", "scan", init_callback, NULL) <= 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hlswmaster_plugin plugin = {
|
||||
.name = "hlswproxy",
|
||||
.scan = &scan,
|
||||
.parse = &parse,
|
||||
.init = &init,
|
||||
};
|
||||
|
||||
void _init(void) {
|
||||
register_plugin(&plugin);
|
||||
}
|
||||
|
||||
void _fini(void) {
|
||||
unregister_plugin(&plugin);
|
||||
}
|
||||
|
|
|
@ -18,80 +18,93 @@
|
|||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <string.h>
|
||||
#include "netpkt.h"
|
||||
#include "plugin.h"
|
||||
#include "plugin_helper.h"
|
||||
|
||||
struct scan_ports port_arr[] = {
|
||||
{ 27960, 27969, 6 }, /* Quake3(6), Elite Force(7), Enemy Territory(25) */
|
||||
{ 28960, 28963, 31 }, /* Call of Duty(31), Call of Duty: United Offensive (42) */
|
||||
static struct scan_ports port_arr[] = {
|
||||
{ 27960, 27969, 6 }, /* q3(6), ef(7), et25), rtcw(8) */
|
||||
{ 28070, 28070, 12 }, /* jk2(12) */
|
||||
{ 28960, 28963, 31 }, /* cod(31), cod:uo(42), cod2(48) */
|
||||
{ 29070, 29070, 27 }, /* jk3(27) */
|
||||
{ 0,0,0 }
|
||||
};
|
||||
|
||||
static char scanmsg[] = "\xff\xff\xff\xffgetStatus";
|
||||
static char replymsg[] = "\xff\xff\xff\xffstatusResponse";
|
||||
static char search_version[] = "\\version\\";
|
||||
static char search_gamename[] = "\\gamename\\";
|
||||
static char reply_q3[] = "Q3 ";
|
||||
static char reply_ef[] = "ST:V HM ";
|
||||
static char reply_rtcw[] = "Wolf ";
|
||||
static char reply_et[] = "ET";
|
||||
static char reply_jk2[] = "JK2MP";
|
||||
static char reply_jk3[] = "JAmp";
|
||||
static char reply_cod[] = "Call of Duty\\";
|
||||
static char reply_coduo[] = "CoD:United Offensive\\";
|
||||
static char reply_cod2[] = "Call of Duty 2\\";
|
||||
|
||||
static char q3_reply[] = "\\version\\Q3 ";
|
||||
static char ef_reply[] = "\\version\\ST:V ";
|
||||
static char et_reply[] = "\\version\\ET ";
|
||||
static char cod_reply[] = "\\gamename\\Call of Duty\\";
|
||||
static char coduo_reply[] = "\\gamename\\CoD:United Offensive\\";
|
||||
|
||||
int scan(void) {
|
||||
static int scan(void)
|
||||
{
|
||||
pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse(struct net_pkt *pkt) {
|
||||
int gameid;
|
||||
static int parse(struct net_pkt *pkt)
|
||||
{
|
||||
int gameid = 0, pos1, pos2;
|
||||
|
||||
if (!pkt_check_portarr(pkt, port_arr))
|
||||
return PARSE_REJECT;
|
||||
|
||||
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
|
||||
return 0;
|
||||
|
||||
if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg)))
|
||||
return 0;
|
||||
return PARSE_REJECT;
|
||||
|
||||
switch (gameid) {
|
||||
case 6: /* q3, ef, et */
|
||||
if (pkt_memmem(pkt, 0, q3_reply, strlen(q3_reply))) {
|
||||
pos1 = pkt_memmem(pkt, 0, search_version, strlen(search_version));
|
||||
pos2 = pkt_memmem(pkt, 0, search_gamename, strlen(search_gamename));
|
||||
|
||||
if (pos1 != -1) {
|
||||
pos1 += strlen(search_version);
|
||||
if (!pkt_memcmp(pkt, pos1, reply_q3, strlen(reply_q3)))
|
||||
gameid = 6;
|
||||
|
||||
} else if (pkt_memmem(pkt, 0, ef_reply, strlen(ef_reply))) {
|
||||
else if (!pkt_memcmp(pkt, pos1, reply_ef, strlen(reply_ef)))
|
||||
gameid = 7;
|
||||
|
||||
} else if (pkt_memmem(pkt, 0, et_reply, strlen(et_reply))) {
|
||||
|
||||
else if (!pkt_memcmp(pkt, pos1, reply_rtcw, strlen(reply_rtcw)))
|
||||
gameid = 8;
|
||||
|
||||
else if (!pkt_memcmp(pkt, pos1, reply_et, strlen(reply_et)))
|
||||
gameid = 25;
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 31: /* cod, cod:uo */
|
||||
if (pkt_memmem(pkt, 0, cod_reply, strlen(cod_reply))) {
|
||||
gameid = 31;
|
||||
else if (!pkt_memcmp(pkt, pos1, reply_jk2, strlen(reply_jk2)))
|
||||
gameid = 12;
|
||||
|
||||
} else if (pkt_memmem(pkt, 0, coduo_reply, strlen(coduo_reply))) {
|
||||
gameid = 42;
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
else if (!pkt_memcmp(pkt, pos1, reply_jk3, strlen(reply_jk3)))
|
||||
gameid = 27;
|
||||
}
|
||||
|
||||
if (gameid == 0 && pos2 != -1) {
|
||||
pos2 += strlen(search_gamename);
|
||||
if (!pkt_memcmp(pkt, pos2, reply_cod, strlen(reply_cod)))
|
||||
gameid = 31;
|
||||
|
||||
else if (!pkt_memcmp(pkt, pos2, reply_coduo, strlen(reply_coduo)))
|
||||
gameid = 42;
|
||||
|
||||
else if (!pkt_memcmp(pkt, pos2, reply_cod2, strlen(reply_cod2)))
|
||||
gameid = 48;
|
||||
}
|
||||
|
||||
if (gameid == 0)
|
||||
return PARSE_REJECT;
|
||||
|
||||
server_add_pkt(gameid, pkt);
|
||||
return 1;
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
|
||||
static struct hlswmaster_plugin plugin = {
|
||||
struct hlswmaster_plugin plugin = {
|
||||
.name = "q3engine",
|
||||
.scan = &scan,
|
||||
.parse = &parse,
|
||||
};
|
||||
|
||||
void _init(void) {
|
||||
register_plugin(&plugin);
|
||||
}
|
||||
|
||||
void _fini(void) {
|
||||
unregister_plugin(&plugin);
|
||||
}
|
||||
|
|
|
@ -18,37 +18,34 @@
|
|||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <string.h>
|
||||
#include "netpkt.h"
|
||||
#include "plugin.h"
|
||||
#include "plugin_helper.h"
|
||||
#include "scanner.h"
|
||||
|
||||
static char scanmsg[] = "\xff\xff\xff\xffinfo 34";
|
||||
static char scanmsg[] = "\xff\xff\xff\xffinfo 34"; /* q2(3) */
|
||||
static char replymsg[] = "\xff\xff\xff\xffinfo";
|
||||
|
||||
int scan(void) {
|
||||
static int scan(void)
|
||||
{
|
||||
pkt_send(NULL, 27910, scanmsg, strlen(scanmsg));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* TODO: src port checken */
|
||||
int parse(struct net_pkt *pkt) {
|
||||
static int parse(struct net_pkt *pkt)
|
||||
{
|
||||
if (pkt_getport(pkt) != 27910)
|
||||
return 0;
|
||||
|
||||
if (pkt_memcmp(pkt, 0, scanmsg, strlen(scanmsg)))
|
||||
return 0;
|
||||
return PARSE_REJECT;
|
||||
|
||||
if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg)))
|
||||
return PARSE_REJECT;
|
||||
|
||||
server_add_pkt(3, pkt);
|
||||
return 1;
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
|
||||
static struct hlswmaster_plugin plugin = {
|
||||
struct hlswmaster_plugin plugin = {
|
||||
.name = "quake2",
|
||||
.scan = &scan,
|
||||
.parse = &parse,
|
||||
};
|
||||
|
||||
void _init(void) {
|
||||
register_plugin(&plugin);
|
||||
}
|
||||
|
||||
void _fini(void) {
|
||||
unregister_plugin(&plugin);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 03/2005 by Olaf Rempel *
|
||||
* Copyright (C) 09/2005 by Olaf Rempel *
|
||||
* razzor@kopf-tisch.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
@ -18,59 +18,36 @@
|
|||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <string.h>
|
||||
#include "netpkt.h"
|
||||
#include "scanner.h"
|
||||
#include "plugin.h"
|
||||
#include "plugin_helper.h"
|
||||
|
||||
struct scan_ports port_arr[] = {
|
||||
{ 8777, 8786, 5 }, /* Unreal Tournament (5), Ravenshield (-) */
|
||||
{ 0,0,0 }
|
||||
};
|
||||
static char scanmsg1[] = "\x80\x00\x00\x00\x00";
|
||||
|
||||
static char scanmsg[] = "REPORTQUERY";
|
||||
static char ut_reply[] = "ut ";
|
||||
static char rvs_reply[] = "rvnshld 0";
|
||||
|
||||
int scan(void) {
|
||||
pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg));
|
||||
static int scan(void)
|
||||
{
|
||||
pkt_send(NULL, 10777, scanmsg1, 5);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse(struct net_pkt *pkt) {
|
||||
int gameid, port;
|
||||
void *p;
|
||||
static int parse(struct net_pkt *pkt)
|
||||
{
|
||||
unsigned short *port;
|
||||
|
||||
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
|
||||
return 0;
|
||||
|
||||
switch (gameid) {
|
||||
case 5: /* ut, rvs */
|
||||
if ((p = pkt_memmem(pkt, 0, ut_reply, strlen(ut_reply)))) {
|
||||
port = pkt_atoi(pkt, p + strlen(ut_reply));
|
||||
server_add(gameid, pkt->addr.sin_addr.s_addr, port -1, port);
|
||||
|
||||
} else if ((p = pkt_memmem(pkt, 0, rvs_reply, strlen(rvs_reply)))) {
|
||||
server_add_pkt(0, pkt);
|
||||
if (pkt_memcmp(pkt, 0, scanmsg1, 5))
|
||||
return PARSE_REJECT;
|
||||
|
||||
}
|
||||
break;
|
||||
if (pkt->size < 12)
|
||||
return PARSE_REJECT;
|
||||
|
||||
default:
|
||||
server_add_pkt(gameid, pkt);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
port = (unsigned short *)&(pkt->buf[10]);
|
||||
server_add(33, pkt->addr.sin_addr.s_addr, *port, ntohs(pkt->addr.sin_port));
|
||||
return PARSE_ACCEPT;
|
||||
}
|
||||
|
||||
static struct hlswmaster_plugin plugin = {
|
||||
.name = "ut",
|
||||
struct hlswmaster_plugin plugin = {
|
||||
.name = "ut2k4",
|
||||
.scan = &scan,
|
||||
.parse = &parse,
|
||||
};
|
||||
|
||||
void _init(void) {
|
||||
register_plugin(&plugin);
|
||||
}
|
||||
|
||||
void _fini(void) {
|
||||
unregister_plugin(&plugin);
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/***************************************************************************
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 11/2006 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "configfile.h"
|
||||
#include "list.h"
|
||||
#include "event.h"
|
||||
#include "scanner.h"
|
||||
#include "logging.h"
|
||||
#include "netpkt.h"
|
||||
#include "gamelist.h"
|
||||
|
||||
#define HLSW_HEADER "\xFF\xFF\xFF\xFFHLSWLANSEARCH"
|
||||
#define HLSW_HEADER_LEN 0x11
|
||||
#define HLSW_ENTRY_LEN 10
|
||||
#define MAX_PKT_LEN (HLSW_HEADER_LEN + HLSW_ENTRY_LEN * 140)
|
||||
|
||||
static LIST_HEAD(master_pkt_list);
|
||||
|
||||
static int serverlist_add_game(struct game_entry *entry)
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
struct net_pkt *pkt;
|
||||
list_for_each_entry(pkt, &master_pkt_list, list) {
|
||||
if (pkt->size <= (MAX_PKT_LEN - HLSW_ENTRY_LEN)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
pkt = malloc(sizeof(struct net_pkt) + MAX_PKT_LEN);
|
||||
if (pkt == NULL) {
|
||||
log_print(LOG_WARN, "serverlist_add_game(): out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(pkt->buf, HLSW_HEADER, HLSW_HEADER_LEN);
|
||||
pkt->size = HLSW_HEADER_LEN;
|
||||
list_add(&pkt->list, &master_pkt_list);
|
||||
}
|
||||
|
||||
memcpy((void *)&pkt->buf + pkt->size, &entry->gameid, HLSW_ENTRY_LEN);
|
||||
pkt->size += HLSW_ENTRY_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serverlist_refresh(void *privdata)
|
||||
{
|
||||
int timeout = (int)privdata;
|
||||
|
||||
struct net_pkt *pkt, *tmp;
|
||||
list_for_each_entry_safe(pkt, tmp, &master_pkt_list, list) {
|
||||
list_del(&pkt->list);
|
||||
free(pkt);
|
||||
}
|
||||
|
||||
gamelist_gc_and_dump(serverlist_add_game, timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int server_handler(int fd, void *privdata)
|
||||
{
|
||||
struct sockaddr_in client;
|
||||
unsigned char buf[32];
|
||||
|
||||
unsigned int i = sizeof(client);
|
||||
int ret = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&client, &i);
|
||||
if (ret <= 0) {
|
||||
log_print(LOG_WARN, "server_handler(): recvfrom()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (memcmp(buf, HLSW_HEADER, HLSW_HEADER_LEN))
|
||||
return 0;
|
||||
|
||||
struct net_pkt *pkt;
|
||||
list_for_each_entry(pkt, &master_pkt_list, list)
|
||||
sendto(fd, pkt->buf, pkt->size, 0, (struct sockaddr *)&client, sizeof(client));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int server_init()
|
||||
{
|
||||
int sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
log_print(LOG_ERROR, "server_init(): socket()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_in src;
|
||||
char *addr = config_get_string("global", "master_src", "0.0.0.0:7140");
|
||||
if (parse_saddr(addr, &src) != 0) {
|
||||
log_print(LOG_ERROR, "server_init(): invalid master_src '%s'", addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&src, sizeof(src)) < 0) {
|
||||
log_print(LOG_ERROR, "server_init(): bind()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
event_add_readfd(sock, server_handler, NULL);
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = config_get_int("global", "serverlist_refresh", 5);
|
||||
tv.tv_usec = 0;
|
||||
|
||||
int timeout = config_get_int("global", "serverlist_timeout", 180);
|
||||
event_add_timeout(&tv, serverlist_refresh, (void *)timeout);
|
||||
return 0;
|
||||
}
|
184
src/client.c
184
src/client.c
|
@ -1,184 +0,0 @@
|
|||
/***************************************************************************
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "hlswmaster.h"
|
||||
#include "plugin.h"
|
||||
#include "list.h"
|
||||
|
||||
#define HLSW_HEADER "\xFF\xFF\xFF\xFFHLSWLANSEARCH\x00"
|
||||
#define HLSW_HEADER_LEN 0x12
|
||||
#define HLSW_ENTRY_LEN 10
|
||||
#define MAX_PKT_LEN (HLSW_HEADER_LEN + HLSW_ENTRY_LEN * 140)
|
||||
|
||||
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 cpkt_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);
|
||||
|
||||
/* kopier den hlsw header in das client paket */
|
||||
memcpy(new->buf, HLSW_HEADER, HLSW_HEADER_LEN);
|
||||
new->size = 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)
|
||||
*/
|
||||
int client_pkt_add(struct game_server *server) {
|
||||
struct client_pkt *cpkt;
|
||||
|
||||
cpkt = LIST_FIND(&client_pkt_prepare, cpkt_not_full, struct client_pkt *, NULL);
|
||||
if (!cpkt && !(cpkt = client_pkt_add_real(&client_pkt_prepare)))
|
||||
return 0;
|
||||
|
||||
/* kopiert den server eintrag in das client paket */
|
||||
memcpy((void *)&cpkt->buf + cpkt->size, &server->gameid, HLSW_ENTRY_LEN);
|
||||
cpkt->size += HLSW_ENTRY_LEN;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
156
src/plugin.c
156
src/plugin.c
|
@ -1,156 +0,0 @@
|
|||
/***************************************************************************
|
||||
* 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 <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "hlswmaster.h"
|
||||
#include "plugin.h"
|
||||
#include "netpkt.h"
|
||||
#include "list.h"
|
||||
|
||||
/* liste der geladenen plugins */
|
||||
LIST_HEAD(plugin_list);
|
||||
|
||||
/* sichert die plugin list UND die plugins ab */
|
||||
static pthread_mutex_t plugin_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/**
|
||||
* plugin_load()
|
||||
* laedt ein plugin
|
||||
*
|
||||
* @param char *name
|
||||
* @return false on error
|
||||
*
|
||||
* TODO: pfadname als parameter (config-file?)
|
||||
* TODO: referenz speichern? wo? wie?
|
||||
*/
|
||||
int plugin_load(char *name) {
|
||||
void *tmp;
|
||||
|
||||
if (!(tmp = dlopen(name, RTLD_NOW)))
|
||||
log_print("unable to load plugin '%s'", name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* plugin_unload()
|
||||
* entfernt ein plugin
|
||||
*
|
||||
* @param char *name
|
||||
* @return false on error
|
||||
*
|
||||
* TODO: implementieren? oder lieber nicht?
|
||||
*/
|
||||
int plugin_unload(char *name) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* plugins_scan()
|
||||
* ruft die scan() Funktionen der Plugins auf (wenn vorhanden)
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
int plugins_scan(void) {
|
||||
struct hlswmaster_plugin *plugin;
|
||||
|
||||
pthread_mutex_lock(&plugin_lock);
|
||||
list_for_each_entry(plugin, &plugin_list, list)
|
||||
if (plugin->scan && !plugin->scan())
|
||||
log_print("plugin %s: scan error", plugin->name);
|
||||
|
||||
pthread_mutex_unlock(&plugin_lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* plugins_parse()
|
||||
* ruft die parse() Funktionen der Plugins auf (wenn vorhanden)
|
||||
* bis ein Plugin das Paket annimmt
|
||||
*
|
||||
* @param struct net_pkt *pkt
|
||||
* @return false wenn kein Plugin das Paket angenommen hat
|
||||
*/
|
||||
int plugins_parse(struct net_pkt *pkt) {
|
||||
struct hlswmaster_plugin *plugin;
|
||||
|
||||
pthread_mutex_lock(&plugin_lock);
|
||||
list_for_each_entry(plugin, &plugin_list, list) {
|
||||
if (plugin->parse && plugin->parse(pkt)) {
|
||||
pthread_mutex_unlock(&plugin_lock);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&plugin_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* plugins_gc()
|
||||
* ruft die gc() Funktionen der Plugins auf (wenn vorhanden)
|
||||
*
|
||||
* @param unsigned long timeout
|
||||
* @return true
|
||||
*
|
||||
* TODO: wird noch nicht benutzt
|
||||
*/
|
||||
int plugins_gc(unsigned long timeout) {
|
||||
struct hlswmaster_plugin *plugin;
|
||||
|
||||
pthread_mutex_lock(&plugin_lock);
|
||||
list_for_each_entry(plugin, &plugin_list, list)
|
||||
if (plugin->gc)
|
||||
plugin->gc(timeout);
|
||||
|
||||
pthread_mutex_unlock(&plugin_lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* register_plugin()
|
||||
* wird von den Plugins beim laden (durch _init())aufgerufen
|
||||
*
|
||||
* @param struct hlswmaster_plugin *me
|
||||
*/
|
||||
void register_plugin(struct hlswmaster_plugin *me) {
|
||||
if (!me->init || (me->init(NULL))) {
|
||||
pthread_mutex_lock(&plugin_lock);
|
||||
list_add_tail((struct list_head *)me, &plugin_list);
|
||||
pthread_mutex_unlock(&plugin_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* register_plugin()
|
||||
* wird von den Plugins beim entfernen (durch fini) aufgerufen
|
||||
*
|
||||
* @param struct hlswmaster_plugin *me
|
||||
*/
|
||||
void unregister_plugin(struct hlswmaster_plugin *me) {
|
||||
pthread_mutex_lock(&plugin_lock);
|
||||
list_del((struct list_head *)me);
|
||||
pthread_mutex_unlock(&plugin_lock);
|
||||
|
||||
if (me->fini)
|
||||
me->fini();
|
||||
}
|
|
@ -1,201 +0,0 @@
|
|||
/***************************************************************************
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define __USE_GNU
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "hlswmaster.h"
|
||||
#include "plugin.h"
|
||||
#include "netpkt.h"
|
||||
|
||||
/**
|
||||
* pkt_queue()
|
||||
* erzeugt ein net_pkt aus den parametern und legt es in die send queue
|
||||
*
|
||||
* @param struct in_addr *dstip - pointer auf eine IP, wenn NULL wird broadcast angenommen
|
||||
* @param unsigned int dstport - destination port
|
||||
* @param char *buf - pointer auf den zu sendenen speicherbereich
|
||||
* @param unsigned int size - groesse des speicherbereichs
|
||||
* @return false bei fehler
|
||||
*/
|
||||
int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size) {
|
||||
struct net_pkt *pkt;
|
||||
|
||||
if (!(pkt = malloc(sizeof(struct net_pkt) + size)))
|
||||
return 0;
|
||||
|
||||
INIT_LIST_HEAD(&pkt->list);
|
||||
|
||||
pkt->addr.sin_family = AF_INET;
|
||||
pkt->addr.sin_port = htons(dstport);
|
||||
pkt->addr.sin_addr.s_addr = (dstip ? dstip->s_addr : 0xFFFFFFFF);
|
||||
|
||||
pkt->size = size;
|
||||
memcpy(pkt->buf, buf, size);
|
||||
|
||||
pkt_queue(pkt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* pkt_queue_portarr()
|
||||
* erzeugt ein net_pkt aus den parametern und legt es in die send queue
|
||||
*
|
||||
* @param char *dstip - pointer auf eine IP, wenn NULL wird broadcast angenommen
|
||||
* @param struct scan_ports *port_arr
|
||||
* @param char *buf - pointer auf den zu sendenen speicherbereich
|
||||
* @param unsigned int size - groesse des speicherbereichs
|
||||
* @return false bei fehler
|
||||
*/
|
||||
int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size) {
|
||||
unsigned short port;
|
||||
while (portarr && portarr->portlo) {
|
||||
for (port = portarr->portlo; port <= portarr->porthi; port++)
|
||||
pkt_send(dstip, port, buf, size);
|
||||
|
||||
portarr++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* pkt_check_portarr()
|
||||
* prueft ob der src-port des pakets in der portliste vorhanden ist
|
||||
*
|
||||
* @param struct net_pkt *pkt
|
||||
* @param struct scan_ports *port_arr
|
||||
* @return die gameid der portrange oder 0 wenn nicht vorhanden
|
||||
*/
|
||||
int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr) {
|
||||
unsigned short port;
|
||||
while (portarr && portarr->portlo) {
|
||||
for (port = portarr->portlo; port <= portarr->porthi; port++)
|
||||
if (port == ntohs(pkt->addr.sin_port))
|
||||
return portarr->gameid;
|
||||
|
||||
portarr++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pkt_memcmp()
|
||||
* vergleicht das Paket mit einem Speicherbereich
|
||||
*
|
||||
* @param struct net_pkt *pkt
|
||||
* @param unsigned int offset
|
||||
* @param char *search
|
||||
* @param unsigned int size
|
||||
* @return true wenn gleich
|
||||
*/
|
||||
int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size) {
|
||||
|
||||
if (offset >= pkt->size)
|
||||
return 1;
|
||||
|
||||
if (offset + size >= pkt->size)
|
||||
size = pkt->size - offset;
|
||||
|
||||
return memcmp(pkt->buf + offset, search, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* pkt_memmem()
|
||||
* sucht einen Speicherbereich in dem Paket
|
||||
*
|
||||
* @param struct net_pkt *pkt
|
||||
* @param unsigned int offset
|
||||
* @param char *search
|
||||
* @param unsigned int size
|
||||
* @return pointer auf den string im Paket
|
||||
*/
|
||||
void * pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size) {
|
||||
if (offset >= pkt->size)
|
||||
return NULL;
|
||||
|
||||
return memmem(pkt->buf + offset, pkt->size, search, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* server_add_pkt()
|
||||
* fuegt der serverliste einen server hinzu
|
||||
*
|
||||
* @param unsigned int gameid
|
||||
* @param struct net_pkt *pkt
|
||||
* @return false bei fehler
|
||||
*/
|
||||
int server_add_pkt(unsigned int gameid, struct net_pkt *pkt) {
|
||||
return server_add(gameid, pkt->addr.sin_addr.s_addr, ntohs(pkt->addr.sin_port), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* pkt_ntoa()
|
||||
* gibt die IP des Pakets als String zurueck
|
||||
*
|
||||
* @param struct net_pkt *pkt
|
||||
* @return pointer auf String
|
||||
*/
|
||||
char * pkt_ntoa(struct net_pkt *pkt) {
|
||||
return inet_ntoa(pkt->addr.sin_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* pkt_getport()
|
||||
* gibt den Port des Pakets als short zurueck
|
||||
*
|
||||
* @param struct net_pkt *pkt
|
||||
* @return portnr
|
||||
*/
|
||||
unsigned short pkt_getport(struct net_pkt *pkt) {
|
||||
return ntohs(pkt->addr.sin_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* pkt_atoi()
|
||||
* gibt den integer in dem paket ab der position zurueck
|
||||
*
|
||||
* @param struct net_pkt *pkt
|
||||
* @return int
|
||||
*/
|
||||
int pkt_atoi(struct net_pkt *pkt, void *p) {
|
||||
int val = 0;
|
||||
void *max = ((void *)pkt->buf + pkt->size);
|
||||
char *c = p;
|
||||
|
||||
/* check lower bounds */
|
||||
if ((void *)pkt->buf > p || p > max)
|
||||
return 0;
|
||||
|
||||
while (isdigit(*c) && (void *)c < max)
|
||||
val = (val * 10) + (*c++ - 0x30);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
154
src/scanner.c
154
src/scanner.c
|
@ -1,154 +0,0 @@
|
|||
/***************************************************************************
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "netpkt.h"
|
||||
#include "hlswmaster.h"
|
||||
|
||||
LIST_HEAD(send_queue);
|
||||
|
||||
static int scan_sock;
|
||||
|
||||
/**
|
||||
* _pkt_queue()
|
||||
* packt ein paket in die sender queue
|
||||
* @param struct net_pkt *pkt
|
||||
*/
|
||||
void pkt_queue(struct net_pkt *pkt) {
|
||||
list_add_tail(&pkt->list, &send_queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* scan_transmit()
|
||||
* triggert den scan der plugins
|
||||
* arbeitet die sender queue ab
|
||||
*
|
||||
* TODO: ratelimiting
|
||||
* TODO: interval als parameter (config file?)
|
||||
*/
|
||||
void scan_transmit(void) {
|
||||
struct net_pkt *pkt, *tmp;
|
||||
|
||||
while (1) {
|
||||
plugins_scan();
|
||||
|
||||
list_for_each_entry_safe(pkt, tmp, &send_queue, list) {
|
||||
if (sendto(scan_sock, pkt->buf, pkt->size, 0, (struct sockaddr *)&pkt->addr, sizeof(pkt->addr)) < 0)
|
||||
log_print("scan_transmit(): sendto()");
|
||||
|
||||
list_del(&pkt->list);
|
||||
free(pkt);
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
sleep(30);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* scan_receive()
|
||||
* wartet auf serverantworten und uebergibt die pakete den
|
||||
* plugins zur auswertung
|
||||
*/
|
||||
void scan_receive(void) {
|
||||
struct net_pkt *pkt;
|
||||
fd_set fdsel, fdcpy;
|
||||
int recvsize, i;
|
||||
|
||||
FD_ZERO(&fdsel);
|
||||
FD_SET(scan_sock, &fdsel);
|
||||
|
||||
while (1) {
|
||||
memcpy(&fdcpy, &fdsel, sizeof(fdsel));
|
||||
select(FD_SETSIZE, &fdcpy, NULL, NULL, NULL);
|
||||
|
||||
ioctl(scan_sock, FIONREAD, &recvsize);
|
||||
|
||||
if (recvsize <= 0) {
|
||||
log_print("scan_receive(): drop short packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(pkt = malloc(sizeof(struct net_pkt) + recvsize))) {
|
||||
log_print("scan_receive(): malloc()");
|
||||
continue;
|
||||
}
|
||||
|
||||
i = sizeof(struct sockaddr_in);
|
||||
pkt->size = recvfrom(scan_sock, pkt->buf, recvsize, 0, (struct sockaddr *)&pkt->addr, &i);
|
||||
|
||||
if (!plugins_parse(pkt)) {
|
||||
log_print("scan_receive(): unknown packet: %s:%d size:%d",
|
||||
inet_ntoa(pkt->addr.sin_addr), ntohs(pkt->addr.sin_port), pkt->size);
|
||||
}
|
||||
|
||||
free(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* scan_init()
|
||||
* initialisiert den socket fuer den server scan
|
||||
* @return false on error
|
||||
*
|
||||
* TODO: src ip als parameter (config-file?)
|
||||
*/
|
||||
int scan_init() {
|
||||
struct sockaddr_in dst;
|
||||
int i = 1;
|
||||
|
||||
if ((scan_sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
log_print("scan_init(): socket()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dst.sin_family = AF_INET;
|
||||
dst.sin_port = htons(7130);
|
||||
inet_aton("0.0.0.0", &dst.sin_addr);
|
||||
|
||||
if (bind(scan_sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) {
|
||||
log_print("scan_init(): bind()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (setsockopt(scan_sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i))) {
|
||||
log_print("scan_init(): setsockopt()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* schliesst den server scan socket
|
||||
*/
|
||||
void scan_exit() {
|
||||
close(scan_sock);
|
||||
}
|
140
src/serverlist.c
140
src/serverlist.c
|
@ -1,140 +0,0 @@
|
|||
/***************************************************************************
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "hlswmaster.h"
|
||||
#include "plugin.h"
|
||||
#include "list.h"
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
LIST_HEAD(server_list);
|
||||
|
||||
/* sichert die server liste */
|
||||
static pthread_mutex_t server_list_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/**
|
||||
* server_cmp()
|
||||
* LIST_FIND helper
|
||||
*
|
||||
* @param struct game_server *a
|
||||
* @param struct game_server *b
|
||||
* @return true wenn es sich um den selben server handelt
|
||||
*/
|
||||
static inline int server_cmp(const struct game_server *a, struct game_server *b) {
|
||||
return (a->gameid == b->gameid && a->ip == b->ip &&
|
||||
a->port1 == b->port1 && a->port2 == b->port2);
|
||||
}
|
||||
|
||||
/**
|
||||
* server_add()
|
||||
* fuegt der internen serverliste einen server hinzu
|
||||
* wenn dieser server schon in der liste vorhanden ist, wird nur
|
||||
* die modtime angepasst
|
||||
*
|
||||
* @param unsigned int gameid
|
||||
* @param struct in_addr ip
|
||||
* @param u_int16_t port1
|
||||
* @param u_int16_t port2
|
||||
* @return false bei fehler
|
||||
*/
|
||||
int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2) {
|
||||
struct game_server server, *nserver;
|
||||
|
||||
server.gameid = gameid;
|
||||
server.ip = ip;
|
||||
server.port1 = port1;
|
||||
server.port2 = port2;
|
||||
|
||||
pthread_mutex_lock(&server_list_lock);
|
||||
|
||||
/* diesen server in der liste suchen */
|
||||
nserver = LIST_FIND(&server_list, server_cmp, struct game_server *, &server);
|
||||
if (!nserver) {
|
||||
/* neuen eintrag anlegen */
|
||||
if (!(nserver = malloc(sizeof(struct game_server)))) {
|
||||
pthread_mutex_unlock(&server_list_lock);
|
||||
return 0;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
{
|
||||
struct in_addr tmp;
|
||||
tmp.s_addr = server.ip;
|
||||
printf("server_add_new: gameid=%2d ip=%15s port1=%5d port2=%5d\n",
|
||||
server.gameid, inet_ntoa(tmp), server.port1, server.port2);
|
||||
}
|
||||
#endif
|
||||
memcpy(nserver, &server, sizeof(struct game_server));
|
||||
list_add_tail(&nserver->list, &server_list);
|
||||
}
|
||||
/* modtime anpassen */
|
||||
nserver->modtime = time(NULL);
|
||||
|
||||
pthread_mutex_unlock(&server_list_lock);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* server_collector()
|
||||
* loescht alte server aus der liste
|
||||
* baut aus den verbleibenden die client_liste auf
|
||||
*
|
||||
* TODO: timeout und intervall als config parameter (config file?)
|
||||
*/
|
||||
void server_collector(void) {
|
||||
struct game_server *server, *tmp;
|
||||
unsigned long now, timeout = 60;
|
||||
|
||||
while (1) {
|
||||
sleep(5);
|
||||
|
||||
now = time(NULL);
|
||||
pthread_mutex_lock(&server_list_lock);
|
||||
list_for_each_entry_safe(server, tmp, &server_list, list) {
|
||||
if ((server->modtime + timeout) < now) {
|
||||
#ifdef DEBUG
|
||||
{
|
||||
struct in_addr tmp2;
|
||||
tmp2.s_addr = server->ip;
|
||||
printf("server timeout: gameid=%2d ip=%15s port1=%5d port2=%5d\n",
|
||||
server->gameid, inet_ntoa(tmp2), server->port1, server->port2);
|
||||
}
|
||||
#endif
|
||||
list_del(&server->list);
|
||||
free(server);
|
||||
continue;
|
||||
}
|
||||
client_pkt_add(server);
|
||||
}
|
||||
pthread_mutex_unlock(&server_list_lock);
|
||||
|
||||
client_pkt_commit();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue